From d8b40b60930bd92e244088421e525ceb2ee52aa2 Mon Sep 17 00:00:00 2001 From: fnowakowski Date: Mon, 28 Oct 2024 15:42:47 +0100 Subject: [PATCH] DCA11Y-1145: refactor: use shell only if node version manager requires shell --- .../node-version-manager/invoker.properties | 3 +- .../plugins/frontend/lib/ProcessExecutor.java | 12 +- ...hellExecutor.java => CommandExecutor.java} | 104 +++++++++--------- .../version/manager/client/AsdfClient.java | 79 +++++++++---- .../lib/version/manager/client/FnmClient.java | 92 ++++++++-------- .../version/manager/client/MiseClient.java | 57 +++++++--- .../lib/version/manager/client/NvmClient.java | 73 +++++++++--- .../lib/version/manager/client/NvsClient.java | 66 ++++++++--- .../manager/client/VersionManagerFactory.java | 16 +-- 9 files changed, 329 insertions(+), 173 deletions(-) rename frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/{ShellExecutor.java => CommandExecutor.java} (57%) diff --git a/frontend-maven-plugin/src/it/node-version-manager/invoker.properties b/frontend-maven-plugin/src/it/node-version-manager/invoker.properties index 2263026c..72a572b9 100644 --- a/frontend-maven-plugin/src/it/node-version-manager/invoker.properties +++ b/frontend-maven-plugin/src/it/node-version-manager/invoker.properties @@ -1,3 +1,4 @@ # ignoring windows for now invoker.os.family=!windows,unix,mac -invoker.environmentVariables.SHELL=bash \ No newline at end of file +invoker.environmentVariables.SHELL=bash +invoker.environmentVariables.FNM_DIR=$HOME \ No newline at end of file diff --git a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/ProcessExecutor.java b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/ProcessExecutor.java index d4ef7707..5bbfaedc 100644 --- a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/ProcessExecutor.java +++ b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/ProcessExecutor.java @@ -4,6 +4,7 @@ import java.io.File; import java.io.IOException; import java.io.OutputStream; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -22,15 +23,17 @@ public final class ProcessExecutor { private final static String PATH_ENV_VAR = "PATH"; - private final Map environment; + private Map environment; private CommandLine commandLine; private final Executor executor; + private final Platform platform; public ProcessExecutor(File workingDirectory, List paths, List command, Platform platform, Map additionalEnvironment){ this(workingDirectory, paths, command, platform, additionalEnvironment, 0); } public ProcessExecutor(File workingDirectory, List paths, List command, Platform platform, Map additionalEnvironment, long timeoutInSeconds) { + this.platform = platform; this.environment = createEnvironment(paths, platform, additionalEnvironment); this.commandLine = createCommandLine(command); this.executor = createExecutor(workingDirectory, timeoutInSeconds); @@ -53,6 +56,13 @@ public int executeAndRedirectOutput(final Logger logger) throws ProcessExecution return execute(logger, stdout, stdout); } + public int execute(List command, List paths, final Logger logger, final OutputStream stdout, final OutputStream stderr) + throws ProcessExecutionException { + this.commandLine = createCommandLine(command); + this.environment = createEnvironment(paths, platform, Collections.emptyMap()); + return execute(logger, stdout, stderr); + } + public int execute(final Logger logger, final OutputStream stdout, final OutputStream stderr) throws ProcessExecutionException { logger.debug("Executing command line {}", commandLine); diff --git a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/ShellExecutor.java b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/CommandExecutor.java similarity index 57% rename from frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/ShellExecutor.java rename to frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/CommandExecutor.java index 5ff1389f..f15b3960 100644 --- a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/ShellExecutor.java +++ b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/CommandExecutor.java @@ -12,24 +12,30 @@ import java.util.Collections; import java.util.List; -public class ShellExecutor { +public class CommandExecutor { private final Logger logger = LoggerFactory.getLogger(getClass()); private final InstallConfig config; private String shell; + private ProcessExecutor executor; - public ShellExecutor(InstallConfig config) { + private String fileToSource; + private String pathToInclude; + + public CommandExecutor(InstallConfig config) { this.config = config; } - public String executeAndCatchErrors(List command, List paths) { + public String executeAndCatchErrors(List command) { ByteArrayOutputStream stdout = new ByteArrayOutputStream(); ByteArrayOutputStream stderr = new ByteArrayOutputStream(); - List profiledShellCommand = getShellCommand(command); + if (shell != null) { + command = getShellCommand(command); + } try { - int exitValue = execute(profiledShellCommand, stdout, stderr, paths); + int exitValue = execute(command, Collections.singletonList(pathToInclude), stdout, stderr); if (exitValue != 0) { logger.debug("Command finished with an error exit code {}", exitValue); } @@ -42,18 +48,16 @@ public String executeAndCatchErrors(List command, List paths) { return output; } - public String executeAndCatchErrors(List command) { - return executeAndCatchErrors(command, Collections.emptyList()); - } - - public String executeOrFail(List command, List paths) { + public String executeOrFail(List command) { ByteArrayOutputStream stdout = new ByteArrayOutputStream(); ByteArrayOutputStream stderr = new ByteArrayOutputStream(); - List profiledShellCommand = getShellCommand(command); + if (shell != null) { + command = getShellCommand(command); + } boolean hasExecutionFailed = false; try { - int exitValue = execute(profiledShellCommand, stdout, stderr, paths); + int exitValue = execute(command, Collections.singletonList(pathToInclude), stdout, stderr); if (exitValue != 0) { hasExecutionFailed = true; } @@ -62,7 +66,7 @@ public String executeOrFail(List command, List paths) { } if (hasExecutionFailed) { - String commandText = String.join(" ", profiledShellCommand); + String commandText = String.join(" ", command); throw new RuntimeException(String.format("Execution of `%s` has failed" + "\nstdout: `%s`" + "\nstderr: `%s`", commandText, parseOutput(stdout), parseOutput(stderr))); @@ -73,68 +77,67 @@ public String executeOrFail(List command, List paths) { } } - public String executeOrFail(List command) { - return executeOrFail(command, Collections.emptyList()); + public CommandExecutor withShell() { + setCurrentUnixShell(); + return this; } - private int execute(List command, ByteArrayOutputStream stdout, ByteArrayOutputStream stderr, List paths) throws ProcessExecutionException { - ProcessExecutor executor = new ProcessExecutor( - config.getWorkingDirectory(), - paths, - command, - config.getPlatform(), - Collections.emptyMap()); - - return executor.execute(logger, stdout, stderr); + public CommandExecutor withSourced(String file) { + fileToSource = file; + return this; } - private List getShellCommand(List command) { - List profiledShellCommand = new ArrayList<>(); + public CommandExecutor withPath(String path) { + pathToInclude = path; + return this; + } - // FIXME - if (config.getPlatform().isWindows() || true) { - logger.warn("Windows is currently not supported"); - profiledShellCommand.addAll(command); - } else { - String shell = getCurrentUnixShell(); - profiledShellCommand.add(shell); - profiledShellCommand.add("-c"); - profiledShellCommand.add(getCommandWithSourcedProfile(shell, command)); + public void initializeProcessExecutor(List paths) { + if (executor == null) { + executor = new ProcessExecutor( + config.getWorkingDirectory(), + paths, + Arrays.asList("echo", "running empty command..."), + config.getPlatform(), + Collections.emptyMap()); } + } - return profiledShellCommand; + private int execute(List command, List paths, ByteArrayOutputStream stdout, ByteArrayOutputStream stderr) throws ProcessExecutionException { + initializeProcessExecutor(Collections.emptyList()); + return executor.execute(command, paths, logger, stdout, stderr); } private String parseOutput(ByteArrayOutputStream stream) { return stream.toString().trim(); } - private String getCommandWithSourcedProfile(String shell, List commandParts) { - String flagCommand = String.join(" ", commandParts); - String sourceProfile = ""; + private List getShellCommand(List commandParts) { + String flatCommand = String.join(" ", commandParts); + + List commandWithSourcedProfile = new ArrayList<>(); + commandWithSourcedProfile.add(shell); + commandWithSourcedProfile.add("-c"); - if (shell.endsWith("zsh")) { - sourceProfile = "source ~/.zshrc"; - } else if (shell.endsWith("bash")) { - sourceProfile = "source ~/.bashrc"; - } else if (shell.endsWith("fish")) { - sourceProfile = "source ~/.config/fish/config.fish"; + if (fileToSource != null) { + String sourceCommand = String.format(". %s", fileToSource); + commandWithSourcedProfile.add(String.format("%s; %s", sourceCommand, flatCommand)); } else { - sourceProfile = "source ~/.profile"; + commandWithSourcedProfile.add(flatCommand); } - return String.format("%s; %s", sourceProfile, flagCommand); + return commandWithSourcedProfile; } - private String getCurrentUnixShell() { - if (shell != null) return shell; + private void setCurrentUnixShell() { + if (shell != null) return; String shellFromEV = System.getenv("SHELL"); if (shellFromEV == null || shellFromEV.isEmpty()) { logger.debug("SHELL variable couldn't be found. Falling back on reading the variable from /bin/sh."); ByteArrayOutputStream stdout = new ByteArrayOutputStream(); try { - execute(Arrays.asList("/bin/sh", "-c", "echo $SHELL"), stdout, stdout, Collections.emptyList()); + execute(Arrays.asList("/bin/sh", "-c", "echo $SHELL"), Collections.emptyList(), stdout, stdout); String shellFromSh = parseOutput(stdout); logger.debug("SHELL from /bin/sh: {}", shellFromSh); @@ -149,6 +152,5 @@ private String getCurrentUnixShell() { } else { shell = shellFromEV; } - return shell; } } diff --git a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/AsdfClient.java b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/AsdfClient.java index 5d125d49..02b53066 100644 --- a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/AsdfClient.java +++ b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/AsdfClient.java @@ -1,48 +1,57 @@ package com.github.eirslett.maven.plugins.frontend.lib.version.manager.client; -import com.github.eirslett.maven.plugins.frontend.lib.version.manager.ShellExecutor; +import com.github.eirslett.maven.plugins.frontend.lib.version.manager.CommandExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; public class AsdfClient implements VersionManagerClient { final Logger logger = LoggerFactory.getLogger(getClass()); - final ShellExecutor shellExecutor; + final CommandExecutor commandExecutor; private static final String EXECUTABLE = "asdf"; - public AsdfClient(ShellExecutor shellExecutor) { - this.shellExecutor = shellExecutor; + public AsdfClient(CommandExecutor commandExecutor) { + this.commandExecutor = commandExecutor; } @Override public boolean isInstalled() { - String version = shellExecutor.executeAndCatchErrors(Arrays.asList( - EXECUTABLE, "--version" - )); - - return version.matches("v\\d+\\.\\d+\\.\\d+-[0-9a-z]+"); + String asdfDir = getAsdfDir(); + logger.debug("Checking if ASDF installation directory exists: {}", asdfDir); + return asdfDir != null; } @Override public void installNode() { - - shellExecutor.executeOrFail(Arrays.asList( - EXECUTABLE, "plugin", "add", "nodejs" - )); - shellExecutor.executeOrFail(Arrays.asList( - EXECUTABLE, "install", "nodejs" - )); + commandExecutor + .withShell() + .withSourced(getAsdfScript()) + .executeOrFail(Arrays.asList( + EXECUTABLE, "plugin", "add", "nodejs" + )); + commandExecutor + .withShell() + .withSourced(getAsdfScript()) + .executeOrFail(Arrays.asList( + EXECUTABLE, "install", "nodejs" + )); } @Override public File getNodeExecutable() { - return new File(shellExecutor.executeOrFail(Arrays.asList( - EXECUTABLE, "which", "node" - ))); + String nodePath = commandExecutor + .withShell() + .withSourced(getAsdfScript()) + .executeOrFail(Arrays.asList( + EXECUTABLE, "which", "node" + )); + return new File(nodePath); } @Override @@ -50,4 +59,36 @@ public File getNpmExecutable() { File nodeExec = getNodeExecutable(); return Paths.get(nodeExec.getParent(), "npm").toFile(); } + + private String getAsdfScript() { + String asdfDir = getAsdfDir(); + String asdfScript = Paths.get(asdfDir, "asdf.sh").toString(); + + return asdfScript; + } + + private String getAsdfDir() { + String asdfDir = System.getenv("ASDF_DIR"); + if (asdfDir != null) { + Path path = Paths.get(asdfDir); + if (Files.exists(path)) { + return path.toString(); + } + } + + String home = System.getenv("HOME"); + if (home != null) { + Path path = Paths.get(home, ".asdf"); + if (Files.exists(path)) { + return path.toString(); + } + + path = Paths.get(home, ".local", "share", "asdf"); + if (Files.exists(path)) { + return path.toString(); + } + } + + return null; + } } diff --git a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/FnmClient.java b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/FnmClient.java index 6d4787e3..02ccfeee 100644 --- a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/FnmClient.java +++ b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/FnmClient.java @@ -1,57 +1,45 @@ package com.github.eirslett.maven.plugins.frontend.lib.version.manager.client; -import com.github.eirslett.maven.plugins.frontend.lib.version.manager.ShellExecutor; +import com.github.eirslett.maven.plugins.frontend.lib.version.manager.CommandExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; -import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; -import java.util.Collections; import java.util.stream.Collectors; public class FnmClient implements VersionManagerClient { final Logger logger = LoggerFactory.getLogger(getClass()); - final ShellExecutor shellExecutor; + final CommandExecutor commandExecutor; - private static final String EXECUTABLE = "fnm"; - - public FnmClient(ShellExecutor shellExecutor) { - this.shellExecutor = shellExecutor; + public FnmClient(CommandExecutor commandExecutor) { + this.commandExecutor = commandExecutor; } @Override public boolean isInstalled() { String fnmDir = getFnmDir(); - if (fnmDir == null) return false; - - // FIXME just return true if fnm dir exists - String version = cleanOutput(shellExecutor.executeAndCatchErrors(Arrays.asList( - EXECUTABLE, "--version" - ), Collections.singletonList(fnmDir))); + logger.debug("Checking if FNM installation directory exists: {}", fnmDir); - return version.matches("fnm \\d+\\.\\d+\\.\\d+"); + return fnmDir != null; } @Override public void installNode() { - shellExecutor.executeOrFail(Arrays.asList( - EXECUTABLE, "use", "--install-if-missing" - ), Collections.singletonList(getFnmDir())); - - // FIXME verify node installed - shellExecutor.executeAndCatchErrors(Arrays.asList( - "node", "--version" - ), Collections.singletonList(getFnmDir())); + commandExecutor + .withPath(getFnmDir()) + .executeOrFail(Arrays.asList(getExecutable(), "use", "--install-if-missing")); } @Override public File getNodeExecutable() { - String currentNodeVersion = cleanOutput(shellExecutor.executeOrFail( - Arrays.asList(EXECUTABLE, "current"), Collections.singletonList(getFnmDir()))); + String output = commandExecutor + .withPath(getFnmDir()) + .executeOrFail(Arrays.asList(getExecutable(), "current")); + String currentNodeVersion = cleanOutput(output); String fnmDir = getFnmDir(); return Paths.get(fnmDir, "node-versions", currentNodeVersion, "installation", "bin", "node").toFile(); @@ -71,33 +59,43 @@ private String cleanOutput(String output) { .collect(Collectors.joining(System.lineSeparator())); } - private String getFnmDir() { - String $fnmDir = System.getenv("FNM_DIR"); - Path path = Paths.get($fnmDir); - if (Files.exists(path)) { - return path.toString(); - } - - String $home = System.getenv("HOME"); - path = Paths.get($home, ".fnm"); - if (Files.exists(path)) { - return path.toString(); - } + private String getExecutable() { + return Paths.get(getFnmDir(), "fnm").toString(); + } - String $xdgDataHome = System.getenv("XDG_DATA_HOME"); - path = Paths.get($xdgDataHome, "fnm"); - if (Files.exists(path)) { - return path.toString(); + private String getFnmDir() { + String fnmDir = System.getenv("FNM_DIR"); + if (fnmDir != null) { + Path path = Paths.get(fnmDir); + if (Files.exists(path)) { + return path.toString(); + } } - path = Paths.get($home, "Library", "Application Support", "fnm"); - if (Files.exists(path)) { - return path.toString(); + String home = System.getenv("HOME"); + if (home != null) { + Path path = Paths.get(home, ".fnm"); + if (Files.exists(path)) { + return path.toString(); + } + + path = Paths.get(home, "Library", "Application Support", "fnm"); + if (Files.exists(path)) { + return path.toString(); + } + + path = Paths.get(home, ".local", "share", "fnm"); + if (Files.exists(path)) { + return path.toString(); + } } - path = Paths.get($home, ".local", "share", "fnm"); - if (Files.exists(path)) { - return path.toString(); + String xdgDataHome = System.getenv("XDG_DATA_HOME"); + if (xdgDataHome != null ) { + Path path = Paths.get(xdgDataHome, "fnm"); + if (Files.exists(path)) { + return path.toString(); + } } return null; diff --git a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/MiseClient.java b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/MiseClient.java index d23c3460..fc0d1ee1 100644 --- a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/MiseClient.java +++ b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/MiseClient.java @@ -1,44 +1,45 @@ package com.github.eirslett.maven.plugins.frontend.lib.version.manager.client; -import com.github.eirslett.maven.plugins.frontend.lib.version.manager.ShellExecutor; +import com.github.eirslett.maven.plugins.frontend.lib.version.manager.CommandExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; public class MiseClient implements VersionManagerClient { final Logger logger = LoggerFactory.getLogger(getClass()); - final ShellExecutor shellExecutor; + final CommandExecutor commandExecutor; - private static final String EXECUTABLE = "mise"; - - public MiseClient(ShellExecutor shellExecutor) { - this.shellExecutor = shellExecutor; + public MiseClient(CommandExecutor commandExecutor) { + this.commandExecutor = commandExecutor; } @Override public boolean isInstalled() { - String version = shellExecutor.executeAndCatchErrors(Arrays.asList( - EXECUTABLE, "--version" - )); + String miseBinDir = getMiseBinDir(); + logger.debug("Checking if MISE installation directory exists: {}", miseBinDir); - return version.matches("\\d+\\.\\d+\\.\\d+ .*"); + return miseBinDir != null; } @Override public void installNode() { - shellExecutor.executeOrFail(Arrays.asList( - EXECUTABLE, "install", "node" - )); + commandExecutor + .withPath(getMiseBinDir()) + .executeOrFail(Arrays.asList(getExecutable(), "install", "node")); } @Override public File getNodeExecutable() { - return new File(shellExecutor.executeOrFail(Arrays.asList( - EXECUTABLE, "which", "node" - ))); + String nodePath = commandExecutor + .withPath(getMiseBinDir()) + .executeOrFail(Arrays.asList(getExecutable(), "which", "node")); + + return new File(nodePath); } @Override @@ -46,4 +47,28 @@ public File getNpmExecutable() { File nodeExec = getNodeExecutable(); return Paths.get(nodeExec.getParentFile().getParent(), "/lib/node_modules/npm/bin/npm-cli.js").toFile(); } + + private String getExecutable() { + return Paths.get(getMiseBinDir(), "mise").toString(); + } + + private String getMiseBinDir() { + String miseInstallPath = System.getenv("MISE_INSTALL_PATH"); + if (miseInstallPath != null) { + Path path = Paths.get(miseInstallPath); + if (Files.exists(path)) { + return path.getParent().toString(); + } + } + + String home = System.getenv("HOME"); + if (home != null) { + Path path = Paths.get(home, ".local", "bin", "mise"); + if (Files.exists(path)) { + return path.getParent().toString(); + } + } + + return null; + } } diff --git a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/NvmClient.java b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/NvmClient.java index ac20ac9c..a81fc099 100644 --- a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/NvmClient.java +++ b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/NvmClient.java @@ -1,43 +1,51 @@ package com.github.eirslett.maven.plugins.frontend.lib.version.manager.client; -import com.github.eirslett.maven.plugins.frontend.lib.version.manager.ShellExecutor; +import com.github.eirslett.maven.plugins.frontend.lib.version.manager.CommandExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Arrays; public class NvmClient implements VersionManagerClient { final Logger logger = LoggerFactory.getLogger(getClass()); - final ShellExecutor shellExecutor; + final CommandExecutor commandExecutor; private static final String EXECUTABLE = "nvm"; - public NvmClient(ShellExecutor shellExecutor) { - this.shellExecutor = shellExecutor; + public NvmClient(CommandExecutor commandExecutor) { + this.commandExecutor = commandExecutor; } @Override public boolean isInstalled() { - String version = shellExecutor.executeAndCatchErrors(Arrays.asList( - EXECUTABLE, "--version" - )); - - return version.matches("\\d+\\.\\d+\\.\\d+"); + String nvmDir = getNvmDir(); + logger.debug("Checking if NVM installation directory exists: {}", nvmDir); + return nvmDir != null; } @Override public void installNode() { - shellExecutor.executeOrFail(Arrays.asList( - EXECUTABLE, "install" - )); + commandExecutor + .withShell() + .withSourced(getNvmScript()) + .executeOrFail(Arrays.asList( + EXECUTABLE, "install" + )); } @Override public File getNodeExecutable() { - return new File(shellExecutor.executeOrFail(Arrays.asList( - EXECUTABLE, "which", "node" - ))); + String nodePath = commandExecutor + .withShell() + .withSourced(getNvmScript()) + .executeOrFail(Arrays.asList( + EXECUTABLE, "which", "node" + )); + return new File(nodePath); } @Override @@ -45,4 +53,39 @@ public File getNpmExecutable() { File nodeExec = getNodeExecutable(); return new File(nodeExec.getParent(), "npm"); } + + private String getNvmScript() { + String nvmDir = getNvmDir(); + String nvmScript = Paths.get(nvmDir, "nvm.sh").toString(); + + return nvmScript; + } + + private String getNvmDir() { + String nvmDir = System.getenv("NVM_DIR"); + if (nvmDir != null) { + Path path = Paths.get(nvmDir); + if (Files.exists(path)) { + return path.toString(); + } + } + + String home = System.getenv("HOME"); + if (home != null) { + Path path = Paths.get(home, ".nvm"); + if (Files.exists(path)) { + return path.toString(); + } + } + + String xdgConfigHome = System.getenv("XDG_CONFIG_HOME"); + if (xdgConfigHome != null) { + Path path = Paths.get(xdgConfigHome, "nvm"); + if (Files.exists(path)) { + return path.toString(); + } + } + + return null; + } } diff --git a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/NvsClient.java b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/NvsClient.java index 5b89f102..b7468b71 100644 --- a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/NvsClient.java +++ b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/NvsClient.java @@ -1,43 +1,51 @@ package com.github.eirslett.maven.plugins.frontend.lib.version.manager.client; -import com.github.eirslett.maven.plugins.frontend.lib.version.manager.ShellExecutor; +import com.github.eirslett.maven.plugins.frontend.lib.version.manager.CommandExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Arrays; public class NvsClient implements VersionManagerClient { final Logger logger = LoggerFactory.getLogger(getClass()); - final ShellExecutor shellExecutor; + final CommandExecutor commandExecutor; private static final String EXECUTABLE = "nvs"; - public NvsClient(ShellExecutor shellExecutor) { - this.shellExecutor = shellExecutor; + public NvsClient(CommandExecutor commandExecutor) { + this.commandExecutor = commandExecutor; } @Override public boolean isInstalled() { - String version = shellExecutor.executeAndCatchErrors(Arrays.asList( - EXECUTABLE, "--version" - )); - - return version.matches("\\d+\\.\\d+\\.\\d+"); + String nvsDir = getNvsDir(); + logger.debug("Checking if NVS installation directory exists: {}", nvsDir); + return nvsDir != null; } @Override public void installNode() { - shellExecutor.executeOrFail(Arrays.asList( - EXECUTABLE, "add" - )); + commandExecutor + .withShell() + .withSourced(getNvsScript()) + .executeOrFail(Arrays.asList( + EXECUTABLE, "add" + )); } @Override public File getNodeExecutable() { - return new File(shellExecutor.executeOrFail(Arrays.asList( - EXECUTABLE, "which", "node" - ))); + String nodePath = commandExecutor + .withShell() + .withSourced(getNvsScript()) + .executeOrFail(Arrays.asList( + EXECUTABLE, "which", "node" + )); + return new File(nodePath); } @Override @@ -45,4 +53,32 @@ public File getNpmExecutable() { File nodeExec = getNodeExecutable(); return new File(nodeExec.getParent(), "npm"); } + + + private String getNvsScript() { + String nvsDir = getNvsDir(); + String nvsScript = Paths.get(nvsDir, "nvs.sh").toString(); + + return nvsScript; + } + + private String getNvsDir() { + String nvsDir = System.getenv("NVS_DIR"); + if (nvsDir != null) { + Path path = Paths.get(nvsDir); + if (Files.exists(path)) { + return path.toString(); + } + } + + String home = System.getenv("HOME"); + if (home != null) { + Path path = Paths.get(home, ".nvs"); + if (Files.exists(path)) { + return path.toString(); + } + } + + return null; + } } diff --git a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/VersionManagerFactory.java b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/VersionManagerFactory.java index 07f39125..ccb78e76 100644 --- a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/VersionManagerFactory.java +++ b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/version/manager/client/VersionManagerFactory.java @@ -1,28 +1,28 @@ package com.github.eirslett.maven.plugins.frontend.lib.version.manager.client; import com.github.eirslett.maven.plugins.frontend.lib.InstallConfig; -import com.github.eirslett.maven.plugins.frontend.lib.version.manager.ShellExecutor; +import com.github.eirslett.maven.plugins.frontend.lib.version.manager.CommandExecutor; import com.github.eirslett.maven.plugins.frontend.lib.version.manager.VersionManagerType; public class VersionManagerFactory { - final ShellExecutor shellExecutor; + final CommandExecutor commandExecutor; public VersionManagerFactory(InstallConfig installConfig) { - this.shellExecutor = new ShellExecutor(installConfig); + this.commandExecutor = new CommandExecutor(installConfig); } public VersionManagerClient getClient(VersionManagerType type) { if (type == VersionManagerType.FNM) { - return new FnmClient(shellExecutor); + return new FnmClient(commandExecutor); } else if (type == VersionManagerType.NVM) { - return new NvmClient(shellExecutor); + return new NvmClient(commandExecutor); } else if (type == VersionManagerType.NVS) { - return new NvsClient(shellExecutor); + return new NvsClient(commandExecutor); } else if (type == VersionManagerType.MISE) { - return new MiseClient(shellExecutor); + return new MiseClient(commandExecutor); } else if (type == VersionManagerType.ASDF) { - return new AsdfClient(shellExecutor); + return new AsdfClient(commandExecutor); } throw new RuntimeException(String.format("Version manager (%s) type is not implemented", type));