From 74ef1e3151866b845d8652686d1628d8d8cbe666 Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Thu, 19 Oct 2023 20:36:13 +0200 Subject: [PATCH 01/22] first changes --- .../tools/ide/tool/GlobalToolCommandlet.java | 20 + .../tools/ide/tool/LocalToolCommandlet.java | 493 ++++++++++++++++++ 2 files changed, 513 insertions(+) create mode 100644 cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java create mode 100644 cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java new file mode 100644 index 000000000..b11926b0f --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java @@ -0,0 +1,20 @@ +package com.devonfw.tools.ide.tool; + +import com.devonfw.tools.ide.context.IdeContext; + +import java.util.Set; + +public class GlobalToolCommandlet extends ToolCommandlet { + /** + * The constructor. + * + * @param context the {@link IdeContext}. + * @param tool the {@link #getName() tool name}. + * @param tags the {@link #getTags() tags} classifying the tool. Should be created via {@link Set#of(Object) Set.of} + * method. + */ + public GlobalToolCommandlet(IdeContext context, String tool, Set tags) { + + super(context, tool, tags); + } +} diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java new file mode 100644 index 000000000..1aff6a72e --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java @@ -0,0 +1,493 @@ +package com.devonfw.tools.ide.tool; + +import com.devonfw.tools.ide.commandlet.Commandlet; +import com.devonfw.tools.ide.common.Tags; +import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.environment.EnvironmentVariables; +import com.devonfw.tools.ide.environment.EnvironmentVariablesType; +import com.devonfw.tools.ide.io.FileAccess; +import com.devonfw.tools.ide.io.FileCopyMode; +import com.devonfw.tools.ide.io.TarCompression; +import com.devonfw.tools.ide.log.IdeLogLevel; +import com.devonfw.tools.ide.os.MacOsHelper; +import com.devonfw.tools.ide.process.ProcessContext; +import com.devonfw.tools.ide.process.ProcessErrorHandling; +import com.devonfw.tools.ide.property.StringListProperty; +import com.devonfw.tools.ide.repo.ToolRepository; +import com.devonfw.tools.ide.util.FilenameUtil; +import com.devonfw.tools.ide.version.VersionIdentifier; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.List; +import java.util.Set; + +public class LocalToolCommandlet extends ToolCommandlet { + /** + * The constructor. + * + * @param context the {@link IdeContext}. + * @param tool the {@link #getName() tool name}. + * @param tags the {@link #getTags() tags} classifying the tool. Should be created via {@link Set#of(Object) Set.of} + * method. + */ + public LocalToolCommandlet(IdeContext context, String tool, Set tags) { + + super(context, tool, tags); + } + + @Override + public void run() { + + runTool(null, this.arguments.asArray()); + } + + /** + * Ensures the tool is installed and then runs this tool with the given arguments. + * + * @param toolVersion the explicit version (pattern) to run. Typically {@code null} to ensure the configured version + * is installed and use that one. Otherwise the specified version will be installed in the software repository + * without touching and IDE installation and used to run. + * @param args the commandline arguments to run the tool. + */ + public void runTool(VersionIdentifier toolVersion, String... args) { + + Path binary; + if (toolVersion == null) { + install(true); + binary = getToolBinary(); + } else { + throw new UnsupportedOperationException("Not yet implemented!"); + } + ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.WARNING).executable(binary) + .addArgs(args); + pc.run(); + } + + /** + * @return the {@link Path} where the main executable file of this tool is installed. + */ + public Path getToolBinary() { + + Path binPath = getToolBinPath(); + Path binary = this.context.getFileAccess().findFirst(binPath, this::isBinary, false); + if (binary == null) { + throw new IllegalStateException("Could not find executable binary for " + getName() + " in " + binPath); + } + return binary; + } + + protected boolean isBinary(Path path) { + + String filename = path.getFileName().toString(); + String binaryName = getBinaryName(); + if (filename.equals(binaryName)) { + return true; + } else if (filename.startsWith(binaryName)) { + String suffix = filename.substring(binaryName.length()); + return this.context.getSystemInfo().getOs().isExecutable(suffix); + } + return false; + } + + protected String getBinaryName() { + + return this.tool; + } + + /** + * @return the {@link EnvironmentVariables#getToolEdition(String) tool edition}. + */ + protected String getEdition() { + + return this.context.getVariables().getToolEdition(getName()); + } + + + /** + * @return the {@link Path} where the tool is located (installed). + */ + public Path getToolPath() { + + return this.context.getSoftwarePath().resolve(getName()); + } + + /** + * @return the {@link Path} where the executables of the tool can be found. Typically a "bin" folder inside + * {@link #getToolPath() tool path}. + */ + public Path getToolBinPath() { + + Path toolPath = getToolPath(); + Path binPath = this.context.getFileAccess().findFirst(toolPath, path -> path.getFileName().toString().equals("bin"), + false); + if ((binPath != null) && Files.isDirectory(binPath)) { + return binPath; + } + return toolPath; + } + + /** + * @return the {@link EnvironmentVariables#getToolVersion(String) tool version}. + */ + public VersionIdentifier getConfiguredVersion() { + + return this.context.getVariables().getToolVersion(getName()); + } + + /** + * @return the currently installed {@link VersionIdentifier version} of this tool or {@code null} if not installed. + */ + public VersionIdentifier getInstalledVersion() { + + Path toolPath = getToolPath(); + if (!Files.isDirectory(toolPath)) { + this.context.trace("Tool {} not installed in {}", getName(), toolPath); + return null; + } + Path toolVersionFile = toolPath.resolve(IdeContext.FILE_SOFTWARE_VERSION); + if (!Files.exists(toolVersionFile)) { + Path legacyToolVersionFile = toolPath.resolve(IdeContext.FILE_LEGACY_SOFTWARE_VERSION); + if (Files.exists(legacyToolVersionFile)) { + toolVersionFile = legacyToolVersionFile; + } else { + this.context.warning("Tool {} is missing version file in {}", getName(), toolVersionFile); + return null; + } + } + try { + String version = Files.readString(toolVersionFile).trim(); + return VersionIdentifier.of(version); + } catch (IOException e) { + throw new IllegalStateException("Failed to read file " + toolVersionFile, e); + } + + } + + /** + * Method to be called for {@link #install(boolean)} from dependent {@link Commandlet}s. + * + * @return {@code true} if the tool was newly installed, {@code false} if the tool was already installed before and + * nothing has changed. + */ + public boolean install() { + + return install(true); + } + + /** + * Performs the installation of the {@link #getName() tool} managed by this {@link Commandlet}. + * + * @param silent - {@code true} if called recursively to suppress verbose logging, {@code false} otherwise. + * @return {@code true} if the tool was newly installed, {@code false} if the tool was already installed before and + * nothing has changed. + */ + public boolean install(boolean silent) { + + return doInstall(silent); + } + + /** + * Installs or updates the managed {@link #getName() tool}. + * + * @param silent - {@code true} if called recursively to suppress verbose logging, {@code false} otherwise. + * @return {@code true} if the tool was newly installed, {@code false} if the tool was already installed before and + * nothing has changed. + */ + protected boolean doInstall(boolean silent) { + + VersionIdentifier configuredVersion = getConfiguredVersion(); + // install configured version of our tool in the software repository if not already installed + ToolInstallation installation = installInRepo(configuredVersion); + + // check if we already have this version installed (linked) locally in IDE_HOME/software + VersionIdentifier installedVersion = getInstalledVersion(); + VersionIdentifier resolvedVersion = installation.resolvedVersion(); + if (isInstalledVersion(resolvedVersion, installedVersion, silent)) { + return false; + } + // we need to link the version or update the link. + Path toolPath = getToolPath(); + FileAccess fileAccess = this.context.getFileAccess(); + if (Files.exists(toolPath)) { + fileAccess.backup(toolPath); + } + fileAccess.symlink(installation.linkDir(), toolPath); + this.context.getPath().setPath(this.tool, installation.binDir()); + if (installedVersion == null) { + this.context.success("Successfully installed {} in version {}", this.tool, resolvedVersion); + } else { + this.context.success("Successfully installed {} in version {} replacing previous version {]", this.tool, + resolvedVersion, installedVersion); + } + postInstall(); + return true; + } + + /** + * This method is called after the tool has been newly installed or updated to a new version. Override it to add + * custom post intallation logic. + */ + protected void postInstall() { + + // nothing to do by default + } + + /** + * Performs the installation of the {@link #getName() tool} managed by this {@link Commandlet} only in the central + * software repository without touching the IDE installation. + * + * @param version the {@link VersionIdentifier} requested to be installed. May also be a + * {@link VersionIdentifier#isPattern() version pattern}. + * @return the {@link ToolInstallation} in the central software repository matching the given {@code version}. + */ + public ToolInstallation installInRepo(VersionIdentifier version) { + + return installInRepo(version, getEdition()); + } + + /** + * Performs the installation of the {@link #getName() tool} managed by this {@link Commandlet} only in the central + * software repository without touching the IDE installation. + * + * @param version the {@link VersionIdentifier} requested to be installed. May also be a + * {@link VersionIdentifier#isPattern() version pattern}. + * @param edition the specific edition to install. + * @return the {@link ToolInstallation} in the central software repository matching the given {@code version}. + */ + public ToolInstallation installInRepo(VersionIdentifier version, String edition) { + + return installInRepo(version, edition, this.context.getDefaultToolRepository()); + } + + /** + * Performs the installation of the {@link #getName() tool} managed by this {@link Commandlet} only in the central + * software repository without touching the IDE installation. + * + * @param version the {@link VersionIdentifier} requested to be installed. May also be a + * {@link VersionIdentifier#isPattern() version pattern}. + * @param edition the specific edition to install. + * @param toolRepository the {@link ToolRepository} to use. + * @return the {@link ToolInstallation} in the central software repository matching the given {@code version}. + */ + public ToolInstallation installInRepo(VersionIdentifier version, String edition, ToolRepository toolRepository) { + + VersionIdentifier resolvedVersion = toolRepository.resolveVersion(this.tool, edition, version); + Path toolPath = this.context.getSoftwareRepositoryPath().resolve(toolRepository.getId()).resolve(this.tool) + .resolve(edition).resolve(resolvedVersion.toString()); + Path toolVersionFile = toolPath.resolve(IdeContext.FILE_SOFTWARE_VERSION); + FileAccess fileAccess = this.context.getFileAccess(); + if (Files.isDirectory(toolPath)) { + if (Files.exists(toolVersionFile)) { + this.context.debug("Version {} of tool {} is already installed at {}", resolvedVersion, + getToolWithEdition(this.tool, edition), toolPath); + return createToolInstallation(toolPath, resolvedVersion, toolVersionFile); + } + this.context.warning("Deleting corrupted installation at {}", toolPath); + fileAccess.delete(toolPath); + } + Path target = toolRepository.download(this.tool, edition, resolvedVersion); + fileAccess.mkdirs(toolPath.getParent()); + extract(target, toolPath); + try { + Files.writeString(toolVersionFile, resolvedVersion.toString(), StandardOpenOption.CREATE_NEW); + } catch (IOException e) { + throw new IllegalStateException("Failed to write version file " + toolVersionFile, e); + } + return createToolInstallation(toolPath, resolvedVersion, toolVersionFile); + } + + private ToolInstallation createToolInstallation(Path rootDir, VersionIdentifier resolvedVersion, + Path toolVersionFile) { + + Path linkDir = getMacOsHelper().findLinkDir(rootDir); + Path binDir = linkDir; + Path binFolder = binDir.resolve(IdeContext.FOLDER_BIN); + if (Files.isDirectory(binFolder)) { + binDir = binFolder; + } + if (linkDir != rootDir) { + assert (!linkDir.equals(rootDir)); + this.context.getFileAccess().copy(toolVersionFile, linkDir, FileCopyMode.COPY_FILE_OVERRIDE); + } + return new ToolInstallation(rootDir, linkDir, binDir, resolvedVersion); + } + + private MacOsHelper getMacOsHelper() { + + if (this.macOsHelper == null) { + this.macOsHelper = new MacOsHelper(this.context); + } + return this.macOsHelper; + } + + /** + * @return {@code true} to extract (unpack) the downloaded binary file, {@code false} otherwise. + */ + protected boolean isExtract() { + + return true; + } + + /** + * @return the currently installed tool version or {@code null} if not found (tool not installed). + */ + protected String getInstalledToolVersion() { + + Path toolPath = getToolPath(); + if (!Files.isDirectory(toolPath)) { + this.context.debug("Tool {} not installed in {}", getName(), toolPath); + return null; + } + Path toolVersionFile = toolPath.resolve(IdeContext.FILE_SOFTWARE_VERSION); + if (!Files.exists(toolVersionFile)) { + Path legacyToolVersionFile = toolPath.resolve(IdeContext.FILE_LEGACY_SOFTWARE_VERSION); + if (Files.exists(legacyToolVersionFile)) { + toolVersionFile = legacyToolVersionFile; + } else { + this.context.warning("Tool {} is missing version file in {}", getName(), toolVersionFile); + return null; + } + } + try { + return Files.readString(toolVersionFile).trim(); + } catch (IOException e) { + throw new IllegalStateException("Failed to read file " + toolVersionFile, e); + } + } + + private boolean isInstalledVersion(VersionIdentifier expectedVersion, VersionIdentifier installedVersion, + boolean silent) { + + if (expectedVersion.equals(installedVersion)) { + IdeLogLevel level = IdeLogLevel.INFO; + if (silent) { + level = IdeLogLevel.DEBUG; + } + this.context.level(level).log("Version {} of tool {} is already installed", installedVersion, + getToolWithEdition()); + return true; + } + return false; + } + + /** + * @param file the {@link Path} to the file to extract. + * @param targetDir the {@link Path} to the directory where to extract (or copy) the file. + */ + protected void extract(Path file, Path targetDir) { + + FileAccess fileAccess = this.context.getFileAccess(); + if (isExtract()) { + this.context.trace("Trying to extract the downloaded file {} to {}.", file, targetDir); + String extension = FilenameUtil.getExtension(file.getFileName().toString()); + this.context.trace("Determined file extension {}", extension); + TarCompression tarCompression = TarCompression.of(extension); + if (tarCompression != null) { + fileAccess.untar(file, targetDir, tarCompression); + } else if ("zip".equals(extension) || "jar".equals(extension)) { + fileAccess.unzip(file, targetDir); + } else if ("dmg".equals(extension)) { + assert this.context.getSystemInfo().isMac(); + Path mountPath = this.context.getIdeHome().resolve(IdeContext.FOLDER_UPDATES).resolve(IdeContext.FOLDER_VOLUME); + fileAccess.mkdirs(mountPath); + ProcessContext pc = this.context.newProcess(); + pc.executable("hdiutil"); + pc.addArgs("attach", "-quiet", "-nobrowse", "-mountpoint", mountPath, file); + pc.run(); + Path appPath = fileAccess.findFirst(mountPath, p -> p.getFileName().toString().endsWith(".app"), false); + if (appPath == null) { + throw new IllegalStateException("Failed to unpack DMG as no MacOS *.app was found in file " + file); + } + fileAccess.copy(appPath, targetDir); + pc.addArgs("detach", "-force", mountPath); + pc.run(); + // if [ -e "${target_dir}/Applications" ] + // then + // rm "${target_dir}/Applications" + // fi + } else if ("msi".equals(extension)) { + this.context.newProcess().executable("msiexec").addArgs("/a", file, "/qn", "TARGETDIR=" + targetDir).run(); + // msiexec also creates a copy of the MSI + Path msiCopy = targetDir.resolve(file.getFileName()); + fileAccess.delete(msiCopy); + } else if ("pkg".equals(extension)) { + + Path tmpDir = fileAccess.createTempDir("ide-pkg-"); + ProcessContext pc = this.context.newProcess(); + // we might also be able to use cpio from commons-compression instead of external xar... + pc.executable("xar").addArgs("-C", tmpDir, "-xf", file).run(); + Path contentPath = fileAccess.findFirst(tmpDir, p -> p.getFileName().toString().equals("Payload"), true); + fileAccess.untar(contentPath, targetDir, TarCompression.GZ); + fileAccess.delete(tmpDir); + } else { + throw new IllegalStateException("Unknown archive format " + extension + ". Can not extract " + file); + } + } else { + this.context.trace("Extraction is disabled for '{}' hence just moving the downloaded file {}.", getName(), file); + fileAccess.move(file, targetDir); + } + } + + /** + * List the available versions of this tool. + */ + public void listVersions() { + + List versions = this.context.getUrls().getSortedVersions(getName(), getEdition()); + for (VersionIdentifier vi : versions) { + this.context.info(vi.toString()); + } + } + + /** + * Sets the tool version in the environment variable configuration file. + * + * @param version the version (pattern) to set. + */ + public void setVersion(String version) { + + if ((version == null) || version.isBlank()) { + throw new IllegalStateException("Version has to be specified!"); + } + VersionIdentifier configuredVersion = VersionIdentifier.of(version); + if (!configuredVersion.isPattern() && !configuredVersion.isValid()) { + this.context.warning("Version {} seems to be invalid", version); + } + setVersion(configuredVersion, true); + } + + /** + * Sets the tool version in the environment variable configuration file. + * + * @param version the version to set. May also be a {@link VersionIdentifier#isPattern() version pattern}. + * @param hint - {@code true} to print the installation hint, {@code false} otherwise. + */ + public void setVersion(VersionIdentifier version, boolean hint) { + + EnvironmentVariables variables = this.context.getVariables(); + EnvironmentVariables settingsVariables = variables.getByType(EnvironmentVariablesType.SETTINGS); + String edition = getEdition(); + String name = EnvironmentVariables.getToolVersionVariable(this.tool); + VersionIdentifier resolvedVersion = this.context.getUrls().getVersion(this.tool, edition, version); + if (version.isPattern()) { + this.context.debug("Resolved version {} to {} for tool {}/{}", version, resolvedVersion, this.tool, edition); + } + settingsVariables.set(name, resolvedVersion.toString(), false); + settingsVariables.save(); + this.context.info("{}={} has been set in {}", name, version, settingsVariables.getSource()); + EnvironmentVariables declaringVariables = variables.findVariable(name); + if ((declaringVariables != null) && (declaringVariables != settingsVariables)) { + this.context.warning( + "The variable {} is overridden in {}. Please remove the overridden declaration in order to make the change affect.", + name, declaringVariables.getSource()); + } + if (hint) { + this.context.info("To install that version call the following command:"); + this.context.info("ide install {}", this.tool); + } + } + +} From baed11e77cf36d7d2fa845732b4c95bfb7226243 Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Tue, 24 Oct 2023 04:50:45 +0200 Subject: [PATCH 02/22] changes --- .../tools/ide/tool/GlobalToolCommandlet.java | 63 +++- .../tools/ide/tool/LocalToolCommandlet.java | 181 +---------- .../tools/ide/tool/ToolCommandlet.java | 280 +----------------- .../tools/ide/tool/ide/IdeToolCommandlet.java | 3 +- 4 files changed, 75 insertions(+), 452 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java index b11926b0f..6dd7b4133 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java @@ -1,10 +1,18 @@ package com.devonfw.tools.ide.tool; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.process.ProcessContext; +import com.devonfw.tools.ide.process.ProcessErrorHandling; +import com.devonfw.tools.ide.repo.ToolRepository; +import com.devonfw.tools.ide.version.VersionIdentifier; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Set; -public class GlobalToolCommandlet extends ToolCommandlet { +public abstract class GlobalToolCommandlet extends ToolCommandlet { /** * The constructor. * @@ -17,4 +25,57 @@ public GlobalToolCommandlet(IdeContext context, String tool, Set tags) { super(context, tool, tags); } + + + /** + * @return the {@link Path} where the main executable file of this tool is installed. + */ + @Override + public Path getToolBinary() { + + String path = System.getenv("PATH"); + String[] pathDirs = path.split(File.pathSeparator); + for (String dir : pathDirs) { + Path toolPath = Paths.get(dir, getName()); + if (Files.isExecutable(toolPath)) { + return toolPath; + } + } + return null; + } + + public Path getToolPath() { + + return getToolBinary(); + } + + /** + * Installs or updates the managed {@link #getName() tool}. + * + * @param silent - {@code true} if called recursively to suppress verbose logging, {@code false} otherwise. + * @return {@code true} if the tool was newly installed, {@code false} if the tool was already installed before and + * nothing has changed. + */ + @Override + protected boolean doInstall(boolean silent) { + + String edition = getEdition(); + ToolRepository toolRepository = this.context.getDefaultToolRepository(); + VersionIdentifier configuredVersion = getConfiguredVersion(); + VersionIdentifier resolvedVersion = toolRepository.resolveVersion(this.tool, edition, configuredVersion); + Path binaryPath = getToolBinary(); + if (Files.exists(binaryPath)) { + //TODO: check whether resolvedVersion is different than installedVersion, if so update the tool? + return false; + } + // download and install the global tool + Path target = toolRepository.download(this.tool, edition, resolvedVersion); + ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.WARNING).executable(target); + pc.run(); + this.context.success("Successfully installed {} in version {}", this.tool, resolvedVersion); + //TODO: create a toolVersionFile? If so, in binDir or rootDir? + postInstall(); + return true; + } + } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java index 1aff6a72e..e38fc180c 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java @@ -1,18 +1,13 @@ package com.devonfw.tools.ide.tool; import com.devonfw.tools.ide.commandlet.Commandlet; -import com.devonfw.tools.ide.common.Tags; import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.environment.EnvironmentVariables; -import com.devonfw.tools.ide.environment.EnvironmentVariablesType; import com.devonfw.tools.ide.io.FileAccess; import com.devonfw.tools.ide.io.FileCopyMode; import com.devonfw.tools.ide.io.TarCompression; import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.os.MacOsHelper; import com.devonfw.tools.ide.process.ProcessContext; -import com.devonfw.tools.ide.process.ProcessErrorHandling; -import com.devonfw.tools.ide.property.StringListProperty; import com.devonfw.tools.ide.repo.ToolRepository; import com.devonfw.tools.ide.util.FilenameUtil; import com.devonfw.tools.ide.version.VersionIdentifier; @@ -21,10 +16,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; -import java.util.List; import java.util.Set; -public class LocalToolCommandlet extends ToolCommandlet { +public abstract class LocalToolCommandlet extends ToolCommandlet { /** * The constructor. * @@ -38,37 +32,12 @@ public LocalToolCommandlet(IdeContext context, String tool, Set tags) { super(context, tool, tags); } - @Override - public void run() { - - runTool(null, this.arguments.asArray()); - } - - /** - * Ensures the tool is installed and then runs this tool with the given arguments. - * - * @param toolVersion the explicit version (pattern) to run. Typically {@code null} to ensure the configured version - * is installed and use that one. Otherwise the specified version will be installed in the software repository - * without touching and IDE installation and used to run. - * @param args the commandline arguments to run the tool. - */ - public void runTool(VersionIdentifier toolVersion, String... args) { - - Path binary; - if (toolVersion == null) { - install(true); - binary = getToolBinary(); - } else { - throw new UnsupportedOperationException("Not yet implemented!"); - } - ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.WARNING).executable(binary) - .addArgs(args); - pc.run(); - } /** * @return the {@link Path} where the main executable file of this tool is installed. */ + + @Override public Path getToolBinary() { Path binPath = getToolBinPath(); @@ -82,7 +51,7 @@ public Path getToolBinary() { protected boolean isBinary(Path path) { String filename = path.getFileName().toString(); - String binaryName = getBinaryName(); + String binaryName = super.getName(); if (filename.equals(binaryName)) { return true; } else if (filename.startsWith(binaryName)) { @@ -92,20 +61,6 @@ protected boolean isBinary(Path path) { return false; } - protected String getBinaryName() { - - return this.tool; - } - - /** - * @return the {@link EnvironmentVariables#getToolEdition(String) tool edition}. - */ - protected String getEdition() { - - return this.context.getVariables().getToolEdition(getName()); - } - - /** * @return the {@link Path} where the tool is located (installed). */ @@ -129,65 +84,7 @@ public Path getToolBinPath() { return toolPath; } - /** - * @return the {@link EnvironmentVariables#getToolVersion(String) tool version}. - */ - public VersionIdentifier getConfiguredVersion() { - return this.context.getVariables().getToolVersion(getName()); - } - - /** - * @return the currently installed {@link VersionIdentifier version} of this tool or {@code null} if not installed. - */ - public VersionIdentifier getInstalledVersion() { - - Path toolPath = getToolPath(); - if (!Files.isDirectory(toolPath)) { - this.context.trace("Tool {} not installed in {}", getName(), toolPath); - return null; - } - Path toolVersionFile = toolPath.resolve(IdeContext.FILE_SOFTWARE_VERSION); - if (!Files.exists(toolVersionFile)) { - Path legacyToolVersionFile = toolPath.resolve(IdeContext.FILE_LEGACY_SOFTWARE_VERSION); - if (Files.exists(legacyToolVersionFile)) { - toolVersionFile = legacyToolVersionFile; - } else { - this.context.warning("Tool {} is missing version file in {}", getName(), toolVersionFile); - return null; - } - } - try { - String version = Files.readString(toolVersionFile).trim(); - return VersionIdentifier.of(version); - } catch (IOException e) { - throw new IllegalStateException("Failed to read file " + toolVersionFile, e); - } - - } - - /** - * Method to be called for {@link #install(boolean)} from dependent {@link Commandlet}s. - * - * @return {@code true} if the tool was newly installed, {@code false} if the tool was already installed before and - * nothing has changed. - */ - public boolean install() { - - return install(true); - } - - /** - * Performs the installation of the {@link #getName() tool} managed by this {@link Commandlet}. - * - * @param silent - {@code true} if called recursively to suppress verbose logging, {@code false} otherwise. - * @return {@code true} if the tool was newly installed, {@code false} if the tool was already installed before and - * nothing has changed. - */ - public boolean install(boolean silent) { - - return doInstall(silent); - } /** * Installs or updates the managed {@link #getName() tool}. @@ -196,6 +93,8 @@ public boolean install(boolean silent) { * @return {@code true} if the tool was newly installed, {@code false} if the tool was already installed before and * nothing has changed. */ + + @Override protected boolean doInstall(boolean silent) { VersionIdentifier configuredVersion = getConfiguredVersion(); @@ -226,15 +125,6 @@ protected boolean doInstall(boolean silent) { return true; } - /** - * This method is called after the tool has been newly installed or updated to a new version. Override it to add - * custom post intallation logic. - */ - protected void postInstall() { - - // nothing to do by default - } - /** * Performs the installation of the {@link #getName() tool} managed by this {@link Commandlet} only in the central * software repository without touching the IDE installation. @@ -431,63 +321,4 @@ protected void extract(Path file, Path targetDir) { } } - /** - * List the available versions of this tool. - */ - public void listVersions() { - - List versions = this.context.getUrls().getSortedVersions(getName(), getEdition()); - for (VersionIdentifier vi : versions) { - this.context.info(vi.toString()); - } - } - - /** - * Sets the tool version in the environment variable configuration file. - * - * @param version the version (pattern) to set. - */ - public void setVersion(String version) { - - if ((version == null) || version.isBlank()) { - throw new IllegalStateException("Version has to be specified!"); - } - VersionIdentifier configuredVersion = VersionIdentifier.of(version); - if (!configuredVersion.isPattern() && !configuredVersion.isValid()) { - this.context.warning("Version {} seems to be invalid", version); - } - setVersion(configuredVersion, true); - } - - /** - * Sets the tool version in the environment variable configuration file. - * - * @param version the version to set. May also be a {@link VersionIdentifier#isPattern() version pattern}. - * @param hint - {@code true} to print the installation hint, {@code false} otherwise. - */ - public void setVersion(VersionIdentifier version, boolean hint) { - - EnvironmentVariables variables = this.context.getVariables(); - EnvironmentVariables settingsVariables = variables.getByType(EnvironmentVariablesType.SETTINGS); - String edition = getEdition(); - String name = EnvironmentVariables.getToolVersionVariable(this.tool); - VersionIdentifier resolvedVersion = this.context.getUrls().getVersion(this.tool, edition, version); - if (version.isPattern()) { - this.context.debug("Resolved version {} to {} for tool {}/{}", version, resolvedVersion, this.tool, edition); - } - settingsVariables.set(name, resolvedVersion.toString(), false); - settingsVariables.save(); - this.context.info("{}={} has been set in {}", name, version, settingsVariables.getSource()); - EnvironmentVariables declaringVariables = variables.findVariable(name); - if ((declaringVariables != null) && (declaringVariables != settingsVariables)) { - this.context.warning( - "The variable {} is overridden in {}. Please remove the overridden declaration in order to make the change affect.", - name, declaringVariables.getSource()); - } - if (hint) { - this.context.info("To install that version call the following command:"); - this.context.info("ide install {}", this.tool); - } - } - } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java index e34d3a558..4d2eea9c3 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java @@ -37,7 +37,7 @@ public abstract class ToolCommandlet extends Commandlet implements Tags { /** The commandline arguments to pass to the tool. */ public final StringListProperty arguments; - private MacOsHelper macOsHelper; + protected MacOsHelper macOsHelper; /** * The constructor. @@ -102,33 +102,10 @@ public void runTool(VersionIdentifier toolVersion, String... args) { /** * @return the {@link Path} where the main executable file of this tool is installed. */ - public Path getToolBinary() { + public abstract Path getToolBinary(); - Path binPath = getToolBinPath(); - Path binary = this.context.getFileAccess().findFirst(binPath, this::isBinary, false); - if (binary == null) { - throw new IllegalStateException("Could not find executable binary for " + getName() + " in " + binPath); - } - return binary; - } + public abstract Path getToolPath(); - protected boolean isBinary(Path path) { - - String filename = path.getFileName().toString(); - String binaryName = getBinaryName(); - if (filename.equals(binaryName)) { - return true; - } else if (filename.startsWith(binaryName)) { - String suffix = filename.substring(binaryName.length()); - return this.context.getSystemInfo().getOs().isExecutable(suffix); - } - return false; - } - - protected String getBinaryName() { - - return this.tool; - } /** * @return the {@link EnvironmentVariables#getToolEdition(String) tool edition}. @@ -162,29 +139,6 @@ protected final static String getToolWithEdition(String tool, String edition) { return tool + "/" + edition; } - /** - * @return the {@link Path} where the tool is located (installed). - */ - public Path getToolPath() { - - return this.context.getSoftwarePath().resolve(getName()); - } - - /** - * @return the {@link Path} where the executables of the tool can be found. Typically a "bin" folder inside - * {@link #getToolPath() tool path}. - */ - public Path getToolBinPath() { - - Path toolPath = getToolPath(); - Path binPath = this.context.getFileAccess().findFirst(toolPath, path -> path.getFileName().toString().equals("bin"), - false); - if ((binPath != null) && Files.isDirectory(binPath)) { - return binPath; - } - return toolPath; - } - /** * @return the {@link EnvironmentVariables#getToolVersion(String) tool version}. */ @@ -252,35 +206,7 @@ public boolean install(boolean silent) { * @return {@code true} if the tool was newly installed, {@code false} if the tool was already installed before and * nothing has changed. */ - protected boolean doInstall(boolean silent) { - - VersionIdentifier configuredVersion = getConfiguredVersion(); - // install configured version of our tool in the software repository if not already installed - ToolInstallation installation = installInRepo(configuredVersion); - - // check if we already have this version installed (linked) locally in IDE_HOME/software - VersionIdentifier installedVersion = getInstalledVersion(); - VersionIdentifier resolvedVersion = installation.resolvedVersion(); - if (isInstalledVersion(resolvedVersion, installedVersion, silent)) { - return false; - } - // we need to link the version or update the link. - Path toolPath = getToolPath(); - FileAccess fileAccess = this.context.getFileAccess(); - if (Files.exists(toolPath)) { - fileAccess.backup(toolPath); - } - fileAccess.symlink(installation.linkDir(), toolPath); - this.context.getPath().setPath(this.tool, installation.binDir()); - if (installedVersion == null) { - this.context.success("Successfully installed {} in version {}", this.tool, resolvedVersion); - } else { - this.context.success("Successfully installed {} in version {} replacing previous version {]", this.tool, - resolvedVersion, installedVersion); - } - postInstall(); - return true; - } + protected abstract boolean doInstall(boolean silent); /** * This method is called after the tool has been newly installed or updated to a new version. Override it to add @@ -291,202 +217,6 @@ protected void postInstall() { // nothing to do by default } - /** - * Performs the installation of the {@link #getName() tool} managed by this {@link Commandlet} only in the central - * software repository without touching the IDE installation. - * - * @param version the {@link VersionIdentifier} requested to be installed. May also be a - * {@link VersionIdentifier#isPattern() version pattern}. - * @return the {@link ToolInstallation} in the central software repository matching the given {@code version}. - */ - public ToolInstallation installInRepo(VersionIdentifier version) { - - return installInRepo(version, getEdition()); - } - - /** - * Performs the installation of the {@link #getName() tool} managed by this {@link Commandlet} only in the central - * software repository without touching the IDE installation. - * - * @param version the {@link VersionIdentifier} requested to be installed. May also be a - * {@link VersionIdentifier#isPattern() version pattern}. - * @param edition the specific edition to install. - * @return the {@link ToolInstallation} in the central software repository matching the given {@code version}. - */ - public ToolInstallation installInRepo(VersionIdentifier version, String edition) { - - return installInRepo(version, edition, this.context.getDefaultToolRepository()); - } - - /** - * Performs the installation of the {@link #getName() tool} managed by this {@link Commandlet} only in the central - * software repository without touching the IDE installation. - * - * @param version the {@link VersionIdentifier} requested to be installed. May also be a - * {@link VersionIdentifier#isPattern() version pattern}. - * @param edition the specific edition to install. - * @param toolRepository the {@link ToolRepository} to use. - * @return the {@link ToolInstallation} in the central software repository matching the given {@code version}. - */ - public ToolInstallation installInRepo(VersionIdentifier version, String edition, ToolRepository toolRepository) { - - VersionIdentifier resolvedVersion = toolRepository.resolveVersion(this.tool, edition, version); - Path toolPath = this.context.getSoftwareRepositoryPath().resolve(toolRepository.getId()).resolve(this.tool) - .resolve(edition).resolve(resolvedVersion.toString()); - Path toolVersionFile = toolPath.resolve(IdeContext.FILE_SOFTWARE_VERSION); - FileAccess fileAccess = this.context.getFileAccess(); - if (Files.isDirectory(toolPath)) { - if (Files.exists(toolVersionFile)) { - this.context.debug("Version {} of tool {} is already installed at {}", resolvedVersion, - getToolWithEdition(this.tool, edition), toolPath); - return createToolInstallation(toolPath, resolvedVersion, toolVersionFile); - } - this.context.warning("Deleting corrupted installation at {}", toolPath); - fileAccess.delete(toolPath); - } - Path target = toolRepository.download(this.tool, edition, resolvedVersion); - fileAccess.mkdirs(toolPath.getParent()); - extract(target, toolPath); - try { - Files.writeString(toolVersionFile, resolvedVersion.toString(), StandardOpenOption.CREATE_NEW); - } catch (IOException e) { - throw new IllegalStateException("Failed to write version file " + toolVersionFile, e); - } - return createToolInstallation(toolPath, resolvedVersion, toolVersionFile); - } - - private ToolInstallation createToolInstallation(Path rootDir, VersionIdentifier resolvedVersion, - Path toolVersionFile) { - - Path linkDir = getMacOsHelper().findLinkDir(rootDir); - Path binDir = linkDir; - Path binFolder = binDir.resolve(IdeContext.FOLDER_BIN); - if (Files.isDirectory(binFolder)) { - binDir = binFolder; - } - if (linkDir != rootDir) { - assert (!linkDir.equals(rootDir)); - this.context.getFileAccess().copy(toolVersionFile, linkDir, FileCopyMode.COPY_FILE_OVERRIDE); - } - return new ToolInstallation(rootDir, linkDir, binDir, resolvedVersion); - } - - private MacOsHelper getMacOsHelper() { - - if (this.macOsHelper == null) { - this.macOsHelper = new MacOsHelper(this.context); - } - return this.macOsHelper; - } - - /** - * @return {@code true} to extract (unpack) the downloaded binary file, {@code false} otherwise. - */ - protected boolean isExtract() { - - return true; - } - - /** - * @return the currently installed tool version or {@code null} if not found (tool not installed). - */ - protected String getInstalledToolVersion() { - - Path toolPath = getToolPath(); - if (!Files.isDirectory(toolPath)) { - this.context.debug("Tool {} not installed in {}", getName(), toolPath); - return null; - } - Path toolVersionFile = toolPath.resolve(IdeContext.FILE_SOFTWARE_VERSION); - if (!Files.exists(toolVersionFile)) { - Path legacyToolVersionFile = toolPath.resolve(IdeContext.FILE_LEGACY_SOFTWARE_VERSION); - if (Files.exists(legacyToolVersionFile)) { - toolVersionFile = legacyToolVersionFile; - } else { - this.context.warning("Tool {} is missing version file in {}", getName(), toolVersionFile); - return null; - } - } - try { - return Files.readString(toolVersionFile).trim(); - } catch (IOException e) { - throw new IllegalStateException("Failed to read file " + toolVersionFile, e); - } - } - - private boolean isInstalledVersion(VersionIdentifier expectedVersion, VersionIdentifier installedVersion, - boolean silent) { - - if (expectedVersion.equals(installedVersion)) { - IdeLogLevel level = IdeLogLevel.INFO; - if (silent) { - level = IdeLogLevel.DEBUG; - } - this.context.level(level).log("Version {} of tool {} is already installed", installedVersion, - getToolWithEdition()); - return true; - } - return false; - } - - /** - * @param file the {@link Path} to the file to extract. - * @param targetDir the {@link Path} to the directory where to extract (or copy) the file. - */ - protected void extract(Path file, Path targetDir) { - - FileAccess fileAccess = this.context.getFileAccess(); - if (isExtract()) { - this.context.trace("Trying to extract the downloaded file {} to {}.", file, targetDir); - String extension = FilenameUtil.getExtension(file.getFileName().toString()); - this.context.trace("Determined file extension {}", extension); - TarCompression tarCompression = TarCompression.of(extension); - if (tarCompression != null) { - fileAccess.untar(file, targetDir, tarCompression); - } else if ("zip".equals(extension) || "jar".equals(extension)) { - fileAccess.unzip(file, targetDir); - } else if ("dmg".equals(extension)) { - assert this.context.getSystemInfo().isMac(); - Path mountPath = this.context.getIdeHome().resolve(IdeContext.FOLDER_UPDATES).resolve(IdeContext.FOLDER_VOLUME); - fileAccess.mkdirs(mountPath); - ProcessContext pc = this.context.newProcess(); - pc.executable("hdiutil"); - pc.addArgs("attach", "-quiet", "-nobrowse", "-mountpoint", mountPath, file); - pc.run(); - Path appPath = fileAccess.findFirst(mountPath, p -> p.getFileName().toString().endsWith(".app"), false); - if (appPath == null) { - throw new IllegalStateException("Failed to unpack DMG as no MacOS *.app was found in file " + file); - } - fileAccess.copy(appPath, targetDir); - pc.addArgs("detach", "-force", mountPath); - pc.run(); - // if [ -e "${target_dir}/Applications" ] - // then - // rm "${target_dir}/Applications" - // fi - } else if ("msi".equals(extension)) { - this.context.newProcess().executable("msiexec").addArgs("/a", file, "/qn", "TARGETDIR=" + targetDir).run(); - // msiexec also creates a copy of the MSI - Path msiCopy = targetDir.resolve(file.getFileName()); - fileAccess.delete(msiCopy); - } else if ("pkg".equals(extension)) { - - Path tmpDir = fileAccess.createTempDir("ide-pkg-"); - ProcessContext pc = this.context.newProcess(); - // we might also be able to use cpio from commons-compression instead of external xar... - pc.executable("xar").addArgs("-C", tmpDir, "-xf", file).run(); - Path contentPath = fileAccess.findFirst(tmpDir, p -> p.getFileName().toString().equals("Payload"), true); - fileAccess.untar(contentPath, targetDir, TarCompression.GZ); - fileAccess.delete(tmpDir); - } else { - throw new IllegalStateException("Unknown archive format " + extension + ". Can not extract " + file); - } - } else { - this.context.trace("Extraction is disabled for '{}' hence just moving the downloaded file {}.", getName(), file); - fileAccess.move(file, targetDir); - } - } - /** * List the available versions of this tool. */ @@ -546,4 +276,4 @@ public void setVersion(VersionIdentifier version, boolean hint) { } } -} +} \ No newline at end of file diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeToolCommandlet.java index 36431b5fc..c517a51f4 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeToolCommandlet.java @@ -14,12 +14,13 @@ import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.io.FileAccess; +import com.devonfw.tools.ide.tool.LocalToolCommandlet; import com.devonfw.tools.ide.tool.ToolCommandlet; /** * {@link ToolCommandlet} for an IDE (integrated development environment). */ -public abstract class IdeToolCommandlet extends ToolCommandlet { +public abstract class IdeToolCommandlet extends LocalToolCommandlet { private Map pluginsMap; From 6bf0f178bb9cb8a4d7095d5e534caf2e5fd074f2 Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Tue, 24 Oct 2023 10:10:45 +0200 Subject: [PATCH 03/22] tools extend LocalToolCommandlet, globalToolCommand not yet fully implemented --- .../com/devonfw/tools/ide/tool/GlobalToolCommandlet.java | 4 ++-- cli/src/main/java/com/devonfw/tools/ide/tool/gh/Gh.java | 3 ++- .../main/java/com/devonfw/tools/ide/tool/gradle/Gradle.java | 3 ++- cli/src/main/java/com/devonfw/tools/ide/tool/helm/Helm.java | 3 ++- cli/src/main/java/com/devonfw/tools/ide/tool/java/Java.java | 3 ++- .../java/com/devonfw/tools/ide/tool/kotlinc/Kotlinc.java | 3 ++- .../com/devonfw/tools/ide/tool/kotlinc/KotlincNative.java | 3 ++- cli/src/main/java/com/devonfw/tools/ide/tool/mvn/Mvn.java | 3 ++- cli/src/main/java/com/devonfw/tools/ide/tool/node/Node.java | 3 ++- cli/src/main/java/com/devonfw/tools/ide/tool/oc/Oc.java | 3 ++- .../java/com/devonfw/tools/ide/tool/quarkus/Quarkus.java | 3 ++- .../java/com/devonfw/tools/ide/tool/terraform/Terraform.java | 3 ++- .../main/java/com/devonfw/tools/ide/tool/vscode/Vscode.java | 5 +++-- 13 files changed, 27 insertions(+), 15 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java index 6dd7b4133..3fc544208 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java @@ -45,8 +45,8 @@ public Path getToolBinary() { } public Path getToolPath() { - - return getToolBinary(); + //TODO: get rootDir of global tool? is RootDir accessible from BinDir (getToolBinary())? + return null; } /** diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/gh/Gh.java b/cli/src/main/java/com/devonfw/tools/ide/tool/gh/Gh.java index bf83c1653..65383ed92 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/gh/Gh.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/gh/Gh.java @@ -3,12 +3,13 @@ import java.util.Set; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.tool.LocalToolCommandlet; import com.devonfw.tools.ide.tool.ToolCommandlet; /** * {@link ToolCommandlet} for github CLI (gh). */ -public class Gh extends ToolCommandlet { +public class Gh extends LocalToolCommandlet { /** * The constructor. diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/gradle/Gradle.java b/cli/src/main/java/com/devonfw/tools/ide/tool/gradle/Gradle.java index 8329e0182..f0405ce14 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/gradle/Gradle.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/gradle/Gradle.java @@ -3,13 +3,14 @@ import java.util.Set; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.tool.LocalToolCommandlet; import com.devonfw.tools.ide.tool.ToolCommandlet; import com.devonfw.tools.ide.tool.java.Java; /** * {@link ToolCommandlet} for gradle. */ -public class Gradle extends ToolCommandlet { +public class Gradle extends LocalToolCommandlet { /** * The constructor. diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/helm/Helm.java b/cli/src/main/java/com/devonfw/tools/ide/tool/helm/Helm.java index 83d233d0f..1f4a2a41b 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/helm/Helm.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/helm/Helm.java @@ -1,6 +1,7 @@ package com.devonfw.tools.ide.tool.helm; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.tool.LocalToolCommandlet; import com.devonfw.tools.ide.tool.ToolCommandlet; import java.util.Set; @@ -8,7 +9,7 @@ /** * {@link ToolCommandlet} for Helm, the package manager for Kubernetes. */ -public class Helm extends ToolCommandlet { +public class Helm extends LocalToolCommandlet { /** * The constructor. * diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/java/Java.java b/cli/src/main/java/com/devonfw/tools/ide/tool/java/Java.java index a2add484b..e26c7308a 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/java/Java.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/java/Java.java @@ -3,12 +3,13 @@ import java.util.Set; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.tool.LocalToolCommandlet; import com.devonfw.tools.ide.tool.ToolCommandlet; /** * {@link ToolCommandlet} for Java (Java Virtual Machine and Java Development Kit). */ -public class Java extends ToolCommandlet { +public class Java extends LocalToolCommandlet { /** * The constructor. diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/kotlinc/Kotlinc.java b/cli/src/main/java/com/devonfw/tools/ide/tool/kotlinc/Kotlinc.java index 8eb8b6ee2..744d051f0 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/kotlinc/Kotlinc.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/kotlinc/Kotlinc.java @@ -3,12 +3,13 @@ import java.util.Set; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.tool.LocalToolCommandlet; import com.devonfw.tools.ide.tool.ToolCommandlet; /** * {@link ToolCommandlet} for Kotlin command-line compiler (kotlinc). */ -public class Kotlinc extends ToolCommandlet { +public class Kotlinc extends LocalToolCommandlet { /** * The constructor. diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/kotlinc/KotlincNative.java b/cli/src/main/java/com/devonfw/tools/ide/tool/kotlinc/KotlincNative.java index 00cbbdf41..b8ed74b58 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/kotlinc/KotlincNative.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/kotlinc/KotlincNative.java @@ -3,12 +3,13 @@ import java.util.Set; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.tool.LocalToolCommandlet; import com.devonfw.tools.ide.tool.ToolCommandlet; /** * {@link ToolCommandlet} for Kotlin Native (kotlincnative). */ -public class KotlincNative extends ToolCommandlet { +public class KotlincNative extends LocalToolCommandlet { /** * The constructor. diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/mvn/Mvn.java b/cli/src/main/java/com/devonfw/tools/ide/tool/mvn/Mvn.java index b394bd3db..5ef339f7c 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/mvn/Mvn.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/mvn/Mvn.java @@ -3,13 +3,14 @@ import java.util.Set; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.tool.LocalToolCommandlet; import com.devonfw.tools.ide.tool.ToolCommandlet; import com.devonfw.tools.ide.tool.java.Java; /** * {@link ToolCommandlet} for maven. */ -public class Mvn extends ToolCommandlet { +public class Mvn extends LocalToolCommandlet { /** * The constructor. diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/node/Node.java b/cli/src/main/java/com/devonfw/tools/ide/tool/node/Node.java index fdd408d38..a3f9c976e 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/node/Node.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/node/Node.java @@ -3,12 +3,13 @@ import java.util.Set; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.tool.LocalToolCommandlet; import com.devonfw.tools.ide.tool.ToolCommandlet; /** * {@link ToolCommandlet} for node. */ -public class Node extends ToolCommandlet { +public class Node extends LocalToolCommandlet { /** * The constructor. diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/oc/Oc.java b/cli/src/main/java/com/devonfw/tools/ide/tool/oc/Oc.java index f65f1ea54..31a7f1b9f 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/oc/Oc.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/oc/Oc.java @@ -1,6 +1,7 @@ package com.devonfw.tools.ide.tool.oc; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.tool.LocalToolCommandlet; import com.devonfw.tools.ide.tool.ToolCommandlet; import java.util.Set; @@ -8,7 +9,7 @@ /** * {@link ToolCommandlet} for Openshift CLI. */ -public class Oc extends ToolCommandlet { +public class Oc extends LocalToolCommandlet { /** * The constructor. diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/quarkus/Quarkus.java b/cli/src/main/java/com/devonfw/tools/ide/tool/quarkus/Quarkus.java index d35528415..d135d9abc 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/quarkus/Quarkus.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/quarkus/Quarkus.java @@ -1,6 +1,7 @@ package com.devonfw.tools.ide.tool.quarkus; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.tool.LocalToolCommandlet; import com.devonfw.tools.ide.tool.ToolCommandlet; import java.util.Set; @@ -8,7 +9,7 @@ /** * {@link ToolCommandlet} for Quarkus. */ -public class Quarkus extends ToolCommandlet { +public class Quarkus extends LocalToolCommandlet { /** * The constructor * diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/terraform/Terraform.java b/cli/src/main/java/com/devonfw/tools/ide/tool/terraform/Terraform.java index 3ef684178..56174c0c7 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/terraform/Terraform.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/terraform/Terraform.java @@ -3,12 +3,13 @@ import java.util.Set; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.tool.LocalToolCommandlet; import com.devonfw.tools.ide.tool.ToolCommandlet; /** * {@link ToolCommandlet} for terraform CLI (terraform). */ -public class Terraform extends ToolCommandlet { +public class Terraform extends LocalToolCommandlet { /** * The constructor. diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/vscode/Vscode.java b/cli/src/main/java/com/devonfw/tools/ide/tool/vscode/Vscode.java index 7963df6fb..5a94dbf88 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/vscode/Vscode.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/vscode/Vscode.java @@ -3,12 +3,13 @@ import java.util.Set; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.tool.LocalToolCommandlet; import com.devonfw.tools.ide.tool.ToolCommandlet; /** * {@link ToolCommandlet} for vscode. */ -public class Vscode extends ToolCommandlet { +public class Vscode extends LocalToolCommandlet { /** * The constructor. @@ -21,7 +22,7 @@ public Vscode (IdeContext context) { } @Override - protected String getBinaryName() { + public String getName() { return "code"; } From c74381339634d18a86db8c3501302ef0df2e5a1e Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Tue, 24 Oct 2023 10:26:58 +0200 Subject: [PATCH 04/22] corrected coding style --- .../tools/ide/tool/GlobalToolCommandlet.java | 88 ++++++++++--------- .../tools/ide/tool/ToolCommandlet.java | 4 + 2 files changed, 50 insertions(+), 42 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java index 3fc544208..36b5e729e 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java @@ -19,63 +19,67 @@ public abstract class GlobalToolCommandlet extends ToolCommandlet { * @param context the {@link IdeContext}. * @param tool the {@link #getName() tool name}. * @param tags the {@link #getTags() tags} classifying the tool. Should be created via {@link Set#of(Object) Set.of} - * method. + * method. */ public GlobalToolCommandlet(IdeContext context, String tool, Set tags) { super(context, tool, tags); } + /** + * @return the {@link Path} where the main executable file of this tool is installed. + */ + @Override + public Path getToolBinary() { - /** - * @return the {@link Path} where the main executable file of this tool is installed. - */ - @Override - public Path getToolBinary() { - - String path = System.getenv("PATH"); - String[] pathDirs = path.split(File.pathSeparator); - for (String dir : pathDirs) { - Path toolPath = Paths.get(dir, getName()); - if (Files.isExecutable(toolPath)) { - return toolPath; - } + String path = System.getenv("PATH"); + String[] pathDirs = path.split(File.pathSeparator); + for (String dir : pathDirs) { + Path toolPath = Paths.get(dir, getName()); + if (Files.isExecutable(toolPath)) { + return toolPath; } - return null; } + return null; + } + /** + * @return the {@link Path} where the tool is located (installed). + */ + @Override public Path getToolPath() { - //TODO: get rootDir of global tool? is RootDir accessible from BinDir (getToolBinary())? + + // TODO: get rootDir of global tool? is RootDir accessible from BinDir (getToolBinary())? return null; } - /** - * Installs or updates the managed {@link #getName() tool}. - * - * @param silent - {@code true} if called recursively to suppress verbose logging, {@code false} otherwise. - * @return {@code true} if the tool was newly installed, {@code false} if the tool was already installed before and - * nothing has changed. - */ - @Override - protected boolean doInstall(boolean silent) { + /** + * Installs or updates the managed {@link #getName() tool}. + * + * @param silent - {@code true} if called recursively to suppress verbose logging, {@code false} otherwise. + * @return {@code true} if the tool was newly installed, {@code false} if the tool was already installed before and + * nothing has changed. + */ + @Override + protected boolean doInstall(boolean silent) { - String edition = getEdition(); - ToolRepository toolRepository = this.context.getDefaultToolRepository(); - VersionIdentifier configuredVersion = getConfiguredVersion(); - VersionIdentifier resolvedVersion = toolRepository.resolveVersion(this.tool, edition, configuredVersion); - Path binaryPath = getToolBinary(); - if (Files.exists(binaryPath)) { - //TODO: check whether resolvedVersion is different than installedVersion, if so update the tool? - return false; - } - // download and install the global tool - Path target = toolRepository.download(this.tool, edition, resolvedVersion); - ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.WARNING).executable(target); - pc.run(); - this.context.success("Successfully installed {} in version {}", this.tool, resolvedVersion); - //TODO: create a toolVersionFile? If so, in binDir or rootDir? - postInstall(); - return true; + String edition = getEdition(); + ToolRepository toolRepository = this.context.getDefaultToolRepository(); + VersionIdentifier configuredVersion = getConfiguredVersion(); + VersionIdentifier resolvedVersion = toolRepository.resolveVersion(this.tool, edition, configuredVersion); + Path binaryPath = getToolBinary(); + if (Files.exists(binaryPath)) { + // TODO: check whether resolvedVersion is different than installedVersion, if so update the tool? + return false; } + // download and install the global tool + Path target = toolRepository.download(this.tool, edition, resolvedVersion); + ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.WARNING).executable(target); + pc.run(); + this.context.success("Successfully installed {} in version {}", this.tool, resolvedVersion); + // TODO: create a toolVersionFile? If so, in binDir or rootDir? + postInstall(); + return true; + } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java index 4d2eea9c3..c1c2b2781 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java @@ -104,6 +104,9 @@ public void runTool(VersionIdentifier toolVersion, String... args) { */ public abstract Path getToolBinary(); + /** + * @return the {@link Path} where the tool is located (installed). + */ public abstract Path getToolPath(); @@ -125,6 +128,7 @@ protected final String getToolWithEdition() { return getToolWithEdition(getName(), getEdition()); } + /** * @param tool the tool name. * @param edition the edition. From fe286c45bf3844698f477c1f16ab67c4065bd799 Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Tue, 24 Oct 2023 10:33:00 +0200 Subject: [PATCH 05/22] corrected coding style --- .../tools/ide/tool/LocalToolCommandlet.java | 489 +++++++++--------- 1 file changed, 243 insertions(+), 246 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java index e38fc180c..4458a902b 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java @@ -25,300 +25,297 @@ public abstract class LocalToolCommandlet extends ToolCommandlet { * @param context the {@link IdeContext}. * @param tool the {@link #getName() tool name}. * @param tags the {@link #getTags() tags} classifying the tool. Should be created via {@link Set#of(Object) Set.of} - * method. + * method. */ public LocalToolCommandlet(IdeContext context, String tool, Set tags) { super(context, tool, tags); } + /** + * @return the {@link Path} where the main executable file of this tool is installed. + */ - /** - * @return the {@link Path} where the main executable file of this tool is installed. - */ - - @Override - public Path getToolBinary() { + @Override + public Path getToolBinary() { - Path binPath = getToolBinPath(); - Path binary = this.context.getFileAccess().findFirst(binPath, this::isBinary, false); - if (binary == null) { - throw new IllegalStateException("Could not find executable binary for " + getName() + " in " + binPath); - } - return binary; + Path binPath = getToolBinPath(); + Path binary = this.context.getFileAccess().findFirst(binPath, this::isBinary, false); + if (binary == null) { + throw new IllegalStateException("Could not find executable binary for " + getName() + " in " + binPath); } + return binary; + } - protected boolean isBinary(Path path) { + protected boolean isBinary(Path path) { - String filename = path.getFileName().toString(); - String binaryName = super.getName(); - if (filename.equals(binaryName)) { - return true; - } else if (filename.startsWith(binaryName)) { - String suffix = filename.substring(binaryName.length()); - return this.context.getSystemInfo().getOs().isExecutable(suffix); - } - return false; + String filename = path.getFileName().toString(); + String binaryName = super.getName(); + if (filename.equals(binaryName)) { + return true; + } else if (filename.startsWith(binaryName)) { + String suffix = filename.substring(binaryName.length()); + return this.context.getSystemInfo().getOs().isExecutable(suffix); } + return false; + } - /** - * @return the {@link Path} where the tool is located (installed). - */ - public Path getToolPath() { + /** + * @return the {@link Path} where the tool is located (installed). + */ + public Path getToolPath() { - return this.context.getSoftwarePath().resolve(getName()); - } + return this.context.getSoftwarePath().resolve(getName()); + } - /** - * @return the {@link Path} where the executables of the tool can be found. Typically a "bin" folder inside - * {@link #getToolPath() tool path}. - */ - public Path getToolBinPath() { - - Path toolPath = getToolPath(); - Path binPath = this.context.getFileAccess().findFirst(toolPath, path -> path.getFileName().toString().equals("bin"), - false); - if ((binPath != null) && Files.isDirectory(binPath)) { - return binPath; - } - return toolPath; + /** + * @return the {@link Path} where the executables of the tool can be found. Typically a "bin" folder inside + * {@link #getToolPath() tool path}. + */ + public Path getToolBinPath() { + + Path toolPath = getToolPath(); + Path binPath = this.context.getFileAccess().findFirst(toolPath, path -> path.getFileName().toString().equals("bin"), + false); + if ((binPath != null) && Files.isDirectory(binPath)) { + return binPath; } + return toolPath; + } + /** + * Installs or updates the managed {@link #getName() tool}. + * + * @param silent - {@code true} if called recursively to suppress verbose logging, {@code false} otherwise. + * @return {@code true} if the tool was newly installed, {@code false} if the tool was already installed before and + * nothing has changed. + */ + @Override + protected boolean doInstall(boolean silent) { - /** - * Installs or updates the managed {@link #getName() tool}. - * - * @param silent - {@code true} if called recursively to suppress verbose logging, {@code false} otherwise. - * @return {@code true} if the tool was newly installed, {@code false} if the tool was already installed before and - * nothing has changed. - */ + VersionIdentifier configuredVersion = getConfiguredVersion(); + // install configured version of our tool in the software repository if not already installed + ToolInstallation installation = installInRepo(configuredVersion); - @Override - protected boolean doInstall(boolean silent) { + // check if we already have this version installed (linked) locally in IDE_HOME/software + VersionIdentifier installedVersion = getInstalledVersion(); + VersionIdentifier resolvedVersion = installation.resolvedVersion(); + if (isInstalledVersion(resolvedVersion, installedVersion, silent)) { + return false; + } + // we need to link the version or update the link. + Path toolPath = getToolPath(); + FileAccess fileAccess = this.context.getFileAccess(); + if (Files.exists(toolPath)) { + fileAccess.backup(toolPath); + } + fileAccess.symlink(installation.linkDir(), toolPath); + this.context.getPath().setPath(this.tool, installation.binDir()); + if (installedVersion == null) { + this.context.success("Successfully installed {} in version {}", this.tool, resolvedVersion); + } else { + this.context.success("Successfully installed {} in version {} replacing previous version {]", this.tool, + resolvedVersion, installedVersion); + } + postInstall(); + return true; + } - VersionIdentifier configuredVersion = getConfiguredVersion(); - // install configured version of our tool in the software repository if not already installed - ToolInstallation installation = installInRepo(configuredVersion); + /** + * Performs the installation of the {@link #getName() tool} managed by this {@link Commandlet} only in the central + * software repository without touching the IDE installation. + * + * @param version the {@link VersionIdentifier} requested to be installed. May also be a + * {@link VersionIdentifier#isPattern() version pattern}. + * @return the {@link ToolInstallation} in the central software repository matching the given {@code version}. + */ + public ToolInstallation installInRepo(VersionIdentifier version) { - // check if we already have this version installed (linked) locally in IDE_HOME/software - VersionIdentifier installedVersion = getInstalledVersion(); - VersionIdentifier resolvedVersion = installation.resolvedVersion(); - if (isInstalledVersion(resolvedVersion, installedVersion, silent)) { - return false; - } - // we need to link the version or update the link. - Path toolPath = getToolPath(); - FileAccess fileAccess = this.context.getFileAccess(); - if (Files.exists(toolPath)) { - fileAccess.backup(toolPath); - } - fileAccess.symlink(installation.linkDir(), toolPath); - this.context.getPath().setPath(this.tool, installation.binDir()); - if (installedVersion == null) { - this.context.success("Successfully installed {} in version {}", this.tool, resolvedVersion); - } else { - this.context.success("Successfully installed {} in version {} replacing previous version {]", this.tool, - resolvedVersion, installedVersion); - } - postInstall(); - return true; - } + return installInRepo(version, getEdition()); + } - /** - * Performs the installation of the {@link #getName() tool} managed by this {@link Commandlet} only in the central - * software repository without touching the IDE installation. - * - * @param version the {@link VersionIdentifier} requested to be installed. May also be a - * {@link VersionIdentifier#isPattern() version pattern}. - * @return the {@link ToolInstallation} in the central software repository matching the given {@code version}. - */ - public ToolInstallation installInRepo(VersionIdentifier version) { - - return installInRepo(version, getEdition()); - } + /** + * Performs the installation of the {@link #getName() tool} managed by this {@link Commandlet} only in the central + * software repository without touching the IDE installation. + * + * @param version the {@link VersionIdentifier} requested to be installed. May also be a + * {@link VersionIdentifier#isPattern() version pattern}. + * @param edition the specific edition to install. + * @return the {@link ToolInstallation} in the central software repository matching the given {@code version}. + */ + public ToolInstallation installInRepo(VersionIdentifier version, String edition) { - /** - * Performs the installation of the {@link #getName() tool} managed by this {@link Commandlet} only in the central - * software repository without touching the IDE installation. - * - * @param version the {@link VersionIdentifier} requested to be installed. May also be a - * {@link VersionIdentifier#isPattern() version pattern}. - * @param edition the specific edition to install. - * @return the {@link ToolInstallation} in the central software repository matching the given {@code version}. - */ - public ToolInstallation installInRepo(VersionIdentifier version, String edition) { - - return installInRepo(version, edition, this.context.getDefaultToolRepository()); - } + return installInRepo(version, edition, this.context.getDefaultToolRepository()); + } - /** - * Performs the installation of the {@link #getName() tool} managed by this {@link Commandlet} only in the central - * software repository without touching the IDE installation. - * - * @param version the {@link VersionIdentifier} requested to be installed. May also be a - * {@link VersionIdentifier#isPattern() version pattern}. - * @param edition the specific edition to install. - * @param toolRepository the {@link ToolRepository} to use. - * @return the {@link ToolInstallation} in the central software repository matching the given {@code version}. - */ - public ToolInstallation installInRepo(VersionIdentifier version, String edition, ToolRepository toolRepository) { - - VersionIdentifier resolvedVersion = toolRepository.resolveVersion(this.tool, edition, version); - Path toolPath = this.context.getSoftwareRepositoryPath().resolve(toolRepository.getId()).resolve(this.tool) - .resolve(edition).resolve(resolvedVersion.toString()); - Path toolVersionFile = toolPath.resolve(IdeContext.FILE_SOFTWARE_VERSION); - FileAccess fileAccess = this.context.getFileAccess(); - if (Files.isDirectory(toolPath)) { - if (Files.exists(toolVersionFile)) { - this.context.debug("Version {} of tool {} is already installed at {}", resolvedVersion, - getToolWithEdition(this.tool, edition), toolPath); - return createToolInstallation(toolPath, resolvedVersion, toolVersionFile); - } - this.context.warning("Deleting corrupted installation at {}", toolPath); - fileAccess.delete(toolPath); - } - Path target = toolRepository.download(this.tool, edition, resolvedVersion); - fileAccess.mkdirs(toolPath.getParent()); - extract(target, toolPath); - try { - Files.writeString(toolVersionFile, resolvedVersion.toString(), StandardOpenOption.CREATE_NEW); - } catch (IOException e) { - throw new IllegalStateException("Failed to write version file " + toolVersionFile, e); + /** + * Performs the installation of the {@link #getName() tool} managed by this {@link Commandlet} only in the central + * software repository without touching the IDE installation. + * + * @param version the {@link VersionIdentifier} requested to be installed. May also be a + * {@link VersionIdentifier#isPattern() version pattern}. + * @param edition the specific edition to install. + * @param toolRepository the {@link ToolRepository} to use. + * @return the {@link ToolInstallation} in the central software repository matching the given {@code version}. + */ + public ToolInstallation installInRepo(VersionIdentifier version, String edition, ToolRepository toolRepository) { + + VersionIdentifier resolvedVersion = toolRepository.resolveVersion(this.tool, edition, version); + Path toolPath = this.context.getSoftwareRepositoryPath().resolve(toolRepository.getId()).resolve(this.tool) + .resolve(edition).resolve(resolvedVersion.toString()); + Path toolVersionFile = toolPath.resolve(IdeContext.FILE_SOFTWARE_VERSION); + FileAccess fileAccess = this.context.getFileAccess(); + if (Files.isDirectory(toolPath)) { + if (Files.exists(toolVersionFile)) { + this.context.debug("Version {} of tool {} is already installed at {}", resolvedVersion, + getToolWithEdition(this.tool, edition), toolPath); + return createToolInstallation(toolPath, resolvedVersion, toolVersionFile); } - return createToolInstallation(toolPath, resolvedVersion, toolVersionFile); + this.context.warning("Deleting corrupted installation at {}", toolPath); + fileAccess.delete(toolPath); + } + Path target = toolRepository.download(this.tool, edition, resolvedVersion); + fileAccess.mkdirs(toolPath.getParent()); + extract(target, toolPath); + try { + Files.writeString(toolVersionFile, resolvedVersion.toString(), StandardOpenOption.CREATE_NEW); + } catch (IOException e) { + throw new IllegalStateException("Failed to write version file " + toolVersionFile, e); } + return createToolInstallation(toolPath, resolvedVersion, toolVersionFile); + } - private ToolInstallation createToolInstallation(Path rootDir, VersionIdentifier resolvedVersion, - Path toolVersionFile) { + private ToolInstallation createToolInstallation(Path rootDir, VersionIdentifier resolvedVersion, + Path toolVersionFile) { - Path linkDir = getMacOsHelper().findLinkDir(rootDir); - Path binDir = linkDir; - Path binFolder = binDir.resolve(IdeContext.FOLDER_BIN); - if (Files.isDirectory(binFolder)) { - binDir = binFolder; - } - if (linkDir != rootDir) { - assert (!linkDir.equals(rootDir)); - this.context.getFileAccess().copy(toolVersionFile, linkDir, FileCopyMode.COPY_FILE_OVERRIDE); - } - return new ToolInstallation(rootDir, linkDir, binDir, resolvedVersion); + Path linkDir = getMacOsHelper().findLinkDir(rootDir); + Path binDir = linkDir; + Path binFolder = binDir.resolve(IdeContext.FOLDER_BIN); + if (Files.isDirectory(binFolder)) { + binDir = binFolder; } + if (linkDir != rootDir) { + assert (!linkDir.equals(rootDir)); + this.context.getFileAccess().copy(toolVersionFile, linkDir, FileCopyMode.COPY_FILE_OVERRIDE); + } + return new ToolInstallation(rootDir, linkDir, binDir, resolvedVersion); + } - private MacOsHelper getMacOsHelper() { + private MacOsHelper getMacOsHelper() { - if (this.macOsHelper == null) { - this.macOsHelper = new MacOsHelper(this.context); - } - return this.macOsHelper; + if (this.macOsHelper == null) { + this.macOsHelper = new MacOsHelper(this.context); } + return this.macOsHelper; + } - /** - * @return {@code true} to extract (unpack) the downloaded binary file, {@code false} otherwise. - */ - protected boolean isExtract() { + /** + * @return {@code true} to extract (unpack) the downloaded binary file, {@code false} otherwise. + */ + protected boolean isExtract() { - return true; - } + return true; + } - /** - * @return the currently installed tool version or {@code null} if not found (tool not installed). - */ - protected String getInstalledToolVersion() { + /** + * @return the currently installed tool version or {@code null} if not found (tool not installed). + */ + protected String getInstalledToolVersion() { - Path toolPath = getToolPath(); - if (!Files.isDirectory(toolPath)) { - this.context.debug("Tool {} not installed in {}", getName(), toolPath); + Path toolPath = getToolPath(); + if (!Files.isDirectory(toolPath)) { + this.context.debug("Tool {} not installed in {}", getName(), toolPath); + return null; + } + Path toolVersionFile = toolPath.resolve(IdeContext.FILE_SOFTWARE_VERSION); + if (!Files.exists(toolVersionFile)) { + Path legacyToolVersionFile = toolPath.resolve(IdeContext.FILE_LEGACY_SOFTWARE_VERSION); + if (Files.exists(legacyToolVersionFile)) { + toolVersionFile = legacyToolVersionFile; + } else { + this.context.warning("Tool {} is missing version file in {}", getName(), toolVersionFile); return null; } - Path toolVersionFile = toolPath.resolve(IdeContext.FILE_SOFTWARE_VERSION); - if (!Files.exists(toolVersionFile)) { - Path legacyToolVersionFile = toolPath.resolve(IdeContext.FILE_LEGACY_SOFTWARE_VERSION); - if (Files.exists(legacyToolVersionFile)) { - toolVersionFile = legacyToolVersionFile; - } else { - this.context.warning("Tool {} is missing version file in {}", getName(), toolVersionFile); - return null; - } - } - try { - return Files.readString(toolVersionFile).trim(); - } catch (IOException e) { - throw new IllegalStateException("Failed to read file " + toolVersionFile, e); - } } + try { + return Files.readString(toolVersionFile).trim(); + } catch (IOException e) { + throw new IllegalStateException("Failed to read file " + toolVersionFile, e); + } + } - private boolean isInstalledVersion(VersionIdentifier expectedVersion, VersionIdentifier installedVersion, - boolean silent) { + private boolean isInstalledVersion(VersionIdentifier expectedVersion, VersionIdentifier installedVersion, + boolean silent) { - if (expectedVersion.equals(installedVersion)) { - IdeLogLevel level = IdeLogLevel.INFO; - if (silent) { - level = IdeLogLevel.DEBUG; - } - this.context.level(level).log("Version {} of tool {} is already installed", installedVersion, - getToolWithEdition()); - return true; + if (expectedVersion.equals(installedVersion)) { + IdeLogLevel level = IdeLogLevel.INFO; + if (silent) { + level = IdeLogLevel.DEBUG; } - return false; + this.context.level(level).log("Version {} of tool {} is already installed", installedVersion, + getToolWithEdition()); + return true; } + return false; + } - /** - * @param file the {@link Path} to the file to extract. - * @param targetDir the {@link Path} to the directory where to extract (or copy) the file. - */ - protected void extract(Path file, Path targetDir) { - - FileAccess fileAccess = this.context.getFileAccess(); - if (isExtract()) { - this.context.trace("Trying to extract the downloaded file {} to {}.", file, targetDir); - String extension = FilenameUtil.getExtension(file.getFileName().toString()); - this.context.trace("Determined file extension {}", extension); - TarCompression tarCompression = TarCompression.of(extension); - if (tarCompression != null) { - fileAccess.untar(file, targetDir, tarCompression); - } else if ("zip".equals(extension) || "jar".equals(extension)) { - fileAccess.unzip(file, targetDir); - } else if ("dmg".equals(extension)) { - assert this.context.getSystemInfo().isMac(); - Path mountPath = this.context.getIdeHome().resolve(IdeContext.FOLDER_UPDATES).resolve(IdeContext.FOLDER_VOLUME); - fileAccess.mkdirs(mountPath); - ProcessContext pc = this.context.newProcess(); - pc.executable("hdiutil"); - pc.addArgs("attach", "-quiet", "-nobrowse", "-mountpoint", mountPath, file); - pc.run(); - Path appPath = fileAccess.findFirst(mountPath, p -> p.getFileName().toString().endsWith(".app"), false); - if (appPath == null) { - throw new IllegalStateException("Failed to unpack DMG as no MacOS *.app was found in file " + file); - } - fileAccess.copy(appPath, targetDir); - pc.addArgs("detach", "-force", mountPath); - pc.run(); - // if [ -e "${target_dir}/Applications" ] - // then - // rm "${target_dir}/Applications" - // fi - } else if ("msi".equals(extension)) { - this.context.newProcess().executable("msiexec").addArgs("/a", file, "/qn", "TARGETDIR=" + targetDir).run(); - // msiexec also creates a copy of the MSI - Path msiCopy = targetDir.resolve(file.getFileName()); - fileAccess.delete(msiCopy); - } else if ("pkg".equals(extension)) { - - Path tmpDir = fileAccess.createTempDir("ide-pkg-"); - ProcessContext pc = this.context.newProcess(); - // we might also be able to use cpio from commons-compression instead of external xar... - pc.executable("xar").addArgs("-C", tmpDir, "-xf", file).run(); - Path contentPath = fileAccess.findFirst(tmpDir, p -> p.getFileName().toString().equals("Payload"), true); - fileAccess.untar(contentPath, targetDir, TarCompression.GZ); - fileAccess.delete(tmpDir); - } else { - throw new IllegalStateException("Unknown archive format " + extension + ". Can not extract " + file); + /** + * @param file the {@link Path} to the file to extract. + * @param targetDir the {@link Path} to the directory where to extract (or copy) the file. + */ + protected void extract(Path file, Path targetDir) { + + FileAccess fileAccess = this.context.getFileAccess(); + if (isExtract()) { + this.context.trace("Trying to extract the downloaded file {} to {}.", file, targetDir); + String extension = FilenameUtil.getExtension(file.getFileName().toString()); + this.context.trace("Determined file extension {}", extension); + TarCompression tarCompression = TarCompression.of(extension); + if (tarCompression != null) { + fileAccess.untar(file, targetDir, tarCompression); + } else if ("zip".equals(extension) || "jar".equals(extension)) { + fileAccess.unzip(file, targetDir); + } else if ("dmg".equals(extension)) { + assert this.context.getSystemInfo().isMac(); + Path mountPath = this.context.getIdeHome().resolve(IdeContext.FOLDER_UPDATES).resolve(IdeContext.FOLDER_VOLUME); + fileAccess.mkdirs(mountPath); + ProcessContext pc = this.context.newProcess(); + pc.executable("hdiutil"); + pc.addArgs("attach", "-quiet", "-nobrowse", "-mountpoint", mountPath, file); + pc.run(); + Path appPath = fileAccess.findFirst(mountPath, p -> p.getFileName().toString().endsWith(".app"), false); + if (appPath == null) { + throw new IllegalStateException("Failed to unpack DMG as no MacOS *.app was found in file " + file); } + fileAccess.copy(appPath, targetDir); + pc.addArgs("detach", "-force", mountPath); + pc.run(); + // if [ -e "${target_dir}/Applications" ] + // then + // rm "${target_dir}/Applications" + // fi + } else if ("msi".equals(extension)) { + this.context.newProcess().executable("msiexec").addArgs("/a", file, "/qn", "TARGETDIR=" + targetDir).run(); + // msiexec also creates a copy of the MSI + Path msiCopy = targetDir.resolve(file.getFileName()); + fileAccess.delete(msiCopy); + } else if ("pkg".equals(extension)) { + + Path tmpDir = fileAccess.createTempDir("ide-pkg-"); + ProcessContext pc = this.context.newProcess(); + // we might also be able to use cpio from commons-compression instead of external xar... + pc.executable("xar").addArgs("-C", tmpDir, "-xf", file).run(); + Path contentPath = fileAccess.findFirst(tmpDir, p -> p.getFileName().toString().equals("Payload"), true); + fileAccess.untar(contentPath, targetDir, TarCompression.GZ); + fileAccess.delete(tmpDir); } else { - this.context.trace("Extraction is disabled for '{}' hence just moving the downloaded file {}.", getName(), file); - fileAccess.move(file, targetDir); + throw new IllegalStateException("Unknown archive format " + extension + ". Can not extract " + file); } + } else { + this.context.trace("Extraction is disabled for '{}' hence just moving the downloaded file {}.", getName(), file); + fileAccess.move(file, targetDir); } + } } From 171ba7ce5643cde0399474ec81a42ec4c2de2369 Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Tue, 24 Oct 2023 10:38:06 +0200 Subject: [PATCH 06/22] updated TODOs --- .../java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java index 36b5e729e..3c98920b1 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java @@ -77,7 +77,7 @@ protected boolean doInstall(boolean silent) { ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.WARNING).executable(target); pc.run(); this.context.success("Successfully installed {} in version {}", this.tool, resolvedVersion); - // TODO: create a toolVersionFile? If so, in binDir or rootDir? + //TODO: create a toolVersionFile? If so, in binDir or rootDir? If so, in binDir or rootDir? if not, how do we retrieve the version so that getInstalledVersion works? postInstall(); return true; } From f1b4f1d25adc74af99f62b92224028b1bfe22652 Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Tue, 24 Oct 2023 10:39:56 +0200 Subject: [PATCH 07/22] updated TODOs --- .../java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java index 3c98920b1..909990681 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java @@ -77,7 +77,7 @@ protected boolean doInstall(boolean silent) { ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.WARNING).executable(target); pc.run(); this.context.success("Successfully installed {} in version {}", this.tool, resolvedVersion); - //TODO: create a toolVersionFile? If so, in binDir or rootDir? If so, in binDir or rootDir? if not, how do we retrieve the version so that getInstalledVersion works? + //TODO: create a toolVersionFile? If so, in binDir or rootDir? if not, how do we retrieve the version so that getInstalledVersion works? postInstall(); return true; } From 74461da9fda7cb78e2510df74eb7adac9824443e Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Tue, 24 Oct 2023 10:44:43 +0200 Subject: [PATCH 08/22] updated branch --- cli/src/main/java/com/devonfw/tools/ide/tool/az/Azure.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/az/Azure.java b/cli/src/main/java/com/devonfw/tools/ide/tool/az/Azure.java index 772296a59..12937026a 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/az/Azure.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/az/Azure.java @@ -6,13 +6,14 @@ import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.environment.EnvironmentVariables; import com.devonfw.tools.ide.environment.EnvironmentVariablesType; +import com.devonfw.tools.ide.tool.LocalToolCommandlet; import com.devonfw.tools.ide.tool.ToolCommandlet; /** * {@link ToolCommandlet} for azure CLI (azure). */ -public class Azure extends ToolCommandlet { +public class Azure extends LocalToolCommandlet { /** * The constructor. From 27fc1b898a06c3935c050226e3383d86722e71b7 Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Fri, 27 Oct 2023 02:23:17 +0200 Subject: [PATCH 09/22] added -f option --- .../tools/ide/tool/GlobalToolCommandlet.java | 35 +++++++-- .../tools/ide/tool/LocalToolCommandlet.java | 75 ------------------ .../tools/ide/tool/ToolCommandlet.java | 76 ++++++++++++++++++- 3 files changed, 102 insertions(+), 84 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java index 909990681..9e1ecb7f3 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java @@ -7,9 +7,11 @@ import com.devonfw.tools.ide.version.VersionIdentifier; 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.nio.file.StandardOpenOption; import java.util.Set; public abstract class GlobalToolCommandlet extends ToolCommandlet { @@ -53,6 +55,16 @@ public Path getToolPath() { return null; } + + /** + * @return {@code true} to extract (unpack) the downloaded binary file, {@code false} otherwise. + */ + @Override + protected boolean isExtract() { + + return false; + } + /** * Installs or updates the managed {@link #getName() tool}. * @@ -63,23 +75,30 @@ public Path getToolPath() { @Override protected boolean doInstall(boolean silent) { + Path binaryPath = getToolBinary(); + if (Files.exists(binaryPath) && !this.context.isForceMode()) { + // tool already installed + this.context.debug("{} is already installed at {}", this.tool, binaryPath); + return false; + } String edition = getEdition(); ToolRepository toolRepository = this.context.getDefaultToolRepository(); VersionIdentifier configuredVersion = getConfiguredVersion(); VersionIdentifier resolvedVersion = toolRepository.resolveVersion(this.tool, edition, configuredVersion); - Path binaryPath = getToolBinary(); - if (Files.exists(binaryPath)) { - // TODO: check whether resolvedVersion is different than installedVersion, if so update the tool? - return false; - } // download and install the global tool Path target = toolRepository.download(this.tool, edition, resolvedVersion); + ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.WARNING).executable(target); - pc.run(); - this.context.success("Successfully installed {} in version {}", this.tool, resolvedVersion); - //TODO: create a toolVersionFile? If so, in binDir or rootDir? if not, how do we retrieve the version so that getInstalledVersion works? + if (pc.run() == 0) { + this.context.success("Successfully installed {} in version {}", this.tool, resolvedVersion); + } else { + this.context.warning("{} in version {} was not successfully installed", this.tool, resolvedVersion); + return false; + } postInstall(); return true; } + + } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java index 4458a902b..23a8aabce 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java @@ -6,7 +6,6 @@ import com.devonfw.tools.ide.io.FileCopyMode; import com.devonfw.tools.ide.io.TarCompression; import com.devonfw.tools.ide.log.IdeLogLevel; -import com.devonfw.tools.ide.os.MacOsHelper; import com.devonfw.tools.ide.process.ProcessContext; import com.devonfw.tools.ide.repo.ToolRepository; import com.devonfw.tools.ide.util.FilenameUtil; @@ -202,22 +201,6 @@ private ToolInstallation createToolInstallation(Path rootDir, VersionIdentifier return new ToolInstallation(rootDir, linkDir, binDir, resolvedVersion); } - private MacOsHelper getMacOsHelper() { - - if (this.macOsHelper == null) { - this.macOsHelper = new MacOsHelper(this.context); - } - return this.macOsHelper; - } - - /** - * @return {@code true} to extract (unpack) the downloaded binary file, {@code false} otherwise. - */ - protected boolean isExtract() { - - return true; - } - /** * @return the currently installed tool version or {@code null} if not found (tool not installed). */ @@ -260,62 +243,4 @@ private boolean isInstalledVersion(VersionIdentifier expectedVersion, VersionIde return false; } - /** - * @param file the {@link Path} to the file to extract. - * @param targetDir the {@link Path} to the directory where to extract (or copy) the file. - */ - protected void extract(Path file, Path targetDir) { - - FileAccess fileAccess = this.context.getFileAccess(); - if (isExtract()) { - this.context.trace("Trying to extract the downloaded file {} to {}.", file, targetDir); - String extension = FilenameUtil.getExtension(file.getFileName().toString()); - this.context.trace("Determined file extension {}", extension); - TarCompression tarCompression = TarCompression.of(extension); - if (tarCompression != null) { - fileAccess.untar(file, targetDir, tarCompression); - } else if ("zip".equals(extension) || "jar".equals(extension)) { - fileAccess.unzip(file, targetDir); - } else if ("dmg".equals(extension)) { - assert this.context.getSystemInfo().isMac(); - Path mountPath = this.context.getIdeHome().resolve(IdeContext.FOLDER_UPDATES).resolve(IdeContext.FOLDER_VOLUME); - fileAccess.mkdirs(mountPath); - ProcessContext pc = this.context.newProcess(); - pc.executable("hdiutil"); - pc.addArgs("attach", "-quiet", "-nobrowse", "-mountpoint", mountPath, file); - pc.run(); - Path appPath = fileAccess.findFirst(mountPath, p -> p.getFileName().toString().endsWith(".app"), false); - if (appPath == null) { - throw new IllegalStateException("Failed to unpack DMG as no MacOS *.app was found in file " + file); - } - fileAccess.copy(appPath, targetDir); - pc.addArgs("detach", "-force", mountPath); - pc.run(); - // if [ -e "${target_dir}/Applications" ] - // then - // rm "${target_dir}/Applications" - // fi - } else if ("msi".equals(extension)) { - this.context.newProcess().executable("msiexec").addArgs("/a", file, "/qn", "TARGETDIR=" + targetDir).run(); - // msiexec also creates a copy of the MSI - Path msiCopy = targetDir.resolve(file.getFileName()); - fileAccess.delete(msiCopy); - } else if ("pkg".equals(extension)) { - - Path tmpDir = fileAccess.createTempDir("ide-pkg-"); - ProcessContext pc = this.context.newProcess(); - // we might also be able to use cpio from commons-compression instead of external xar... - pc.executable("xar").addArgs("-C", tmpDir, "-xf", file).run(); - Path contentPath = fileAccess.findFirst(tmpDir, p -> p.getFileName().toString().equals("Payload"), true); - fileAccess.untar(contentPath, targetDir, TarCompression.GZ); - fileAccess.delete(tmpDir); - } else { - throw new IllegalStateException("Unknown archive format " + extension + ". Can not extract " + file); - } - } else { - this.context.trace("Extraction is disabled for '{}' hence just moving the downloaded file {}.", getName(), file); - fileAccess.move(file, targetDir); - } - } - } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java index c1c2b2781..dc968e4a6 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java @@ -37,7 +37,7 @@ public abstract class ToolCommandlet extends Commandlet implements Tags { /** The commandline arguments to pass to the tool. */ public final StringListProperty arguments; - protected MacOsHelper macOsHelper; + private MacOsHelper macOsHelper; /** * The constructor. @@ -221,6 +221,80 @@ protected void postInstall() { // nothing to do by default } + /** + * @return {@code true} to extract (unpack) the downloaded binary file, {@code false} otherwise. + */ + protected boolean isExtract() { + + return true; + } + + /** + * @param file the {@link Path} to the file to extract. + * @param targetDir the {@link Path} to the directory where to extract (or copy) the file. + */ + protected void extract(Path file, Path targetDir) { + + FileAccess fileAccess = this.context.getFileAccess(); + if (isExtract()) { + this.context.trace("Trying to extract the downloaded file {} to {}.", file, targetDir); + String extension = FilenameUtil.getExtension(file.getFileName().toString()); + this.context.trace("Determined file extension {}", extension); + TarCompression tarCompression = TarCompression.of(extension); + if (tarCompression != null) { + fileAccess.untar(file, targetDir, tarCompression); + } else if ("zip".equals(extension) || "jar".equals(extension)) { + fileAccess.unzip(file, targetDir); + } else if ("dmg".equals(extension)) { + assert this.context.getSystemInfo().isMac(); + Path mountPath = this.context.getIdeHome().resolve(IdeContext.FOLDER_UPDATES).resolve(IdeContext.FOLDER_VOLUME); + fileAccess.mkdirs(mountPath); + ProcessContext pc = this.context.newProcess(); + pc.executable("hdiutil"); + pc.addArgs("attach", "-quiet", "-nobrowse", "-mountpoint", mountPath, file); + pc.run(); + Path appPath = fileAccess.findFirst(mountPath, p -> p.getFileName().toString().endsWith(".app"), false); + if (appPath == null) { + throw new IllegalStateException("Failed to unpack DMG as no MacOS *.app was found in file " + file); + } + fileAccess.copy(appPath, targetDir); + pc.addArgs("detach", "-force", mountPath); + pc.run(); + // if [ -e "${target_dir}/Applications" ] + // then + // rm "${target_dir}/Applications" + // fi + } else if ("msi".equals(extension)) { + this.context.newProcess().executable("msiexec").addArgs("/a", file, "/qn", "TARGETDIR=" + targetDir).run(); + // msiexec also creates a copy of the MSI + Path msiCopy = targetDir.resolve(file.getFileName()); + fileAccess.delete(msiCopy); + } else if ("pkg".equals(extension)) { + + Path tmpDir = fileAccess.createTempDir("ide-pkg-"); + ProcessContext pc = this.context.newProcess(); + // we might also be able to use cpio from commons-compression instead of external xar... + pc.executable("xar").addArgs("-C", tmpDir, "-xf", file).run(); + Path contentPath = fileAccess.findFirst(tmpDir, p -> p.getFileName().toString().equals("Payload"), true); + fileAccess.untar(contentPath, targetDir, TarCompression.GZ); + fileAccess.delete(tmpDir); + } else { + throw new IllegalStateException("Unknown archive format " + extension + ". Can not extract " + file); + } + } else { + this.context.trace("Extraction is disabled for '{}' hence just moving the downloaded file {}.", getName(), file); + fileAccess.move(file, targetDir); + } + } + + protected MacOsHelper getMacOsHelper() { + + if (this.macOsHelper == null) { + this.macOsHelper = new MacOsHelper(this.context); + } + return this.macOsHelper; + } + /** * List the available versions of this tool. */ From 1580a68bbcc3c4abae40fc8064fec41a39b18262 Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Fri, 27 Oct 2023 02:56:31 +0200 Subject: [PATCH 10/22] removed unecessary imports --- .../main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java index 4e8eccafc..71e496a07 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java @@ -3,7 +3,6 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.StandardOpenOption; import java.util.List; import java.util.Set; import java.util.stream.Stream; @@ -15,14 +14,12 @@ import com.devonfw.tools.ide.environment.EnvironmentVariables; import com.devonfw.tools.ide.environment.EnvironmentVariablesType; import com.devonfw.tools.ide.io.FileAccess; -import com.devonfw.tools.ide.io.FileCopyMode; import com.devonfw.tools.ide.io.TarCompression; import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.os.MacOsHelper; import com.devonfw.tools.ide.process.ProcessContext; import com.devonfw.tools.ide.process.ProcessErrorHandling; import com.devonfw.tools.ide.property.StringListProperty; -import com.devonfw.tools.ide.repo.ToolRepository; import com.devonfw.tools.ide.util.FilenameUtil; import com.devonfw.tools.ide.version.VersionIdentifier; From f90d5c97ef8bd139e8548dc4239fe0396e54ff4b Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Fri, 27 Oct 2023 03:43:15 +0200 Subject: [PATCH 11/22] updated TODOs and JavaDoc --- .../com/devonfw/tools/ide/tool/GlobalToolCommandlet.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java index 9e1ecb7f3..8046bbefc 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java @@ -7,11 +7,9 @@ import com.devonfw.tools.ide.version.VersionIdentifier; 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.nio.file.StandardOpenOption; import java.util.Set; public abstract class GlobalToolCommandlet extends ToolCommandlet { @@ -51,7 +49,6 @@ public Path getToolBinary() { @Override public Path getToolPath() { - // TODO: get rootDir of global tool? is RootDir accessible from BinDir (getToolBinary())? return null; } @@ -66,7 +63,7 @@ protected boolean isExtract() { } /** - * Installs or updates the managed {@link #getName() tool}. + * Installs {@link #getName() tool}, if force mode is enabled it proceeds with the installation. * * @param silent - {@code true} if called recursively to suppress verbose logging, {@code false} otherwise. * @return {@code true} if the tool was newly installed, {@code false} if the tool was already installed before and @@ -87,7 +84,7 @@ protected boolean doInstall(boolean silent) { VersionIdentifier resolvedVersion = toolRepository.resolveVersion(this.tool, edition, configuredVersion); // download and install the global tool Path target = toolRepository.download(this.tool, edition, resolvedVersion); - + //TODO: (Eventually) extract the file -> where? ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.WARNING).executable(target); if (pc.run() == 0) { this.context.success("Successfully installed {} in version {}", this.tool, resolvedVersion); From ecd1a13581c8a011891919e9983fe40f8fd09d5f Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Fri, 27 Oct 2023 03:49:07 +0200 Subject: [PATCH 12/22] updated javaDoc --- .../java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java | 1 + 1 file changed, 1 insertion(+) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java index 8046bbefc..b0a5b8a0a 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java @@ -54,6 +54,7 @@ public Path getToolPath() { /** + * Override this if the global tool comes with a zip file. * @return {@code true} to extract (unpack) the downloaded binary file, {@code false} otherwise. */ @Override From 886e8452e8bc8cdd48c7913a0569949003b59b6f Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Sat, 28 Oct 2023 03:39:58 +0200 Subject: [PATCH 13/22] merged other PR --- .../java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java index c7ca038d5..92d0793b4 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java @@ -75,9 +75,7 @@ protected boolean doInstall(boolean silent) { Path binaryPath = getToolBinary(); if (Files.exists(binaryPath) && !this.context.isForceMode()) { - if (silent) { - this.context.debug("{} is already installed at {}", this.tool, binaryPath); - } + this.context.debug("{} is already installed at {}", this.tool, binaryPath); return false; } String edition = getEdition(); From 50373eb25f6a9876fcbced9875b4d3066a4b3137 Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Mon, 30 Oct 2023 00:21:01 +0100 Subject: [PATCH 14/22] removed package-lock.json --- .../com/devonfw/tools/ide/tool/GlobalToolCommandlet.java | 6 +----- package-lock.json | 6 ------ 2 files changed, 1 insertion(+), 11 deletions(-) delete mode 100644 package-lock.json diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java index 92d0793b4..e5c4aaa78 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java @@ -84,11 +84,7 @@ protected boolean doInstall(boolean silent) { VersionIdentifier resolvedVersion = toolRepository.resolveVersion(this.tool, edition, configuredVersion); // download and install the global tool Path target = toolRepository.download(this.tool, edition, resolvedVersion); - if (isExtract()) { - Path extracted = this.context.getTempPath(); - extract(target, extracted); - target = extracted; - } + extract(target, null); ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.WARNING).executable(target); if (pc.run() == 0) { this.context.success("Successfully installed {} in version {}", this.tool, resolvedVersion); diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 1dbaba1b1..000000000 --- a/package-lock.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "IDEasy", - "lockfileVersion": 3, - "requires": true, - "packages": {} -} From ae58363fbc52f44eb4efdd0d3042276560af385a Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Mon, 30 Oct 2023 04:10:25 +0100 Subject: [PATCH 15/22] rearranged local and global TC --- .../ide/commandlet/VersionGetCommandlet.java | 7 +- .../tools/ide/tool/GlobalToolCommandlet.java | 35 +++-- .../tools/ide/tool/LocalToolCommandlet.java | 56 ++++---- .../tools/ide/tool/ToolCommandlet.java | 122 ++---------------- .../tools/ide/tool/eclipse/Eclipse.java | 2 +- .../com/devonfw/tools/ide/tool/helm/Helm.java | 3 +- 6 files changed, 64 insertions(+), 161 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionGetCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionGetCommandlet.java index bfbebee1c..9087116ae 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionGetCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionGetCommandlet.java @@ -3,6 +3,8 @@ import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.property.ToolProperty; +import com.devonfw.tools.ide.tool.GlobalToolCommandlet; +import com.devonfw.tools.ide.tool.LocalToolCommandlet; import com.devonfw.tools.ide.tool.ToolCommandlet; import com.devonfw.tools.ide.version.VersionIdentifier; @@ -38,7 +40,10 @@ public String getName() { public void run() { ToolCommandlet commandlet = this.tool.getValue(); - VersionIdentifier installedVersion = commandlet.getInstalledVersion(); + if (commandlet instanceof GlobalToolCommandlet) { + throw new UnsupportedOperationException("Not yet implemented!"); + } + VersionIdentifier installedVersion = ((LocalToolCommandlet)commandlet).getInstalledVersion(); if (installedVersion == null) { throw new CliException("Tool " + commandlet.getName() + " is not installed!", 4); } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java index e5c4aaa78..6ed69c92f 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java @@ -1,6 +1,7 @@ package com.devonfw.tools.ide.tool; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.io.FileAccess; import com.devonfw.tools.ide.process.ProcessContext; import com.devonfw.tools.ide.process.ProcessErrorHandling; import com.devonfw.tools.ide.repo.ToolRepository; @@ -29,7 +30,6 @@ public GlobalToolCommandlet(IdeContext context, String tool, Set tags) { /** * @return the {@link Path} where the main executable file of this tool is installed. */ - @Override public Path getToolBinary() { String path = System.getenv("PATH"); @@ -44,23 +44,13 @@ public Path getToolBinary() { } /** - * @return the {@link Path} where the tool is located (installed). - */ - @Override - public Path getToolPath() { - - return null; - } - - - /** - * Override this if the global tool comes with a zip file. + * Override this if the global tool comes with a file that has to be extracted. * @return {@code true} to extract (unpack) the downloaded binary file, {@code false} otherwise. */ @Override protected boolean isExtract() { - return false; + return true; } /** @@ -74,7 +64,7 @@ protected boolean isExtract() { protected boolean doInstall(boolean silent) { Path binaryPath = getToolBinary(); - if (Files.exists(binaryPath) && !this.context.isForceMode()) { + if (binaryPath != null && Files.exists(binaryPath) && !this.context.isForceMode()) { this.context.debug("{} is already installed at {}", this.tool, binaryPath); return false; } @@ -83,10 +73,19 @@ protected boolean doInstall(boolean silent) { VersionIdentifier configuredVersion = getConfiguredVersion(); VersionIdentifier resolvedVersion = toolRepository.resolveVersion(this.tool, edition, configuredVersion); // download and install the global tool - Path target = toolRepository.download(this.tool, edition, resolvedVersion); - extract(target, null); - ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.WARNING).executable(target); - if (pc.run() == 0) { + FileAccess fileAccess = this.context.getFileAccess(); + Path target = Path.of("C:\\Users\\saboucha\\Downloads\\devonfw-ide\\terraform-1.6.2-windows.zip"); + //Path target = toolRepository.download(this.tool, edition, resolvedVersion); + //Path tmpPath = this.context.getTempDownloadPath().resolve(target.getFileName()); + //Path tmpPath = fileAccess.createTempDir(target.getFileName().toString()); + //this.context.getFileAccess().delete(tmpPath); + //extract(target, tmpPath); + Path tmpPath = this.context.getTempPath().resolve(target.getFileName()); + extract(target, tmpPath); + ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.WARNING).executable(tmpPath); + int exitCode = pc.run(); + fileAccess.delete(tmpPath); + if (exitCode == 0) { this.context.success("Successfully installed {} in version {}", this.tool, resolvedVersion); } else { this.context.warning("{} in version {} was not successfully installed", this.tool, resolvedVersion); diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java index 23a8aabce..7a6859b1e 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java @@ -31,33 +31,6 @@ public LocalToolCommandlet(IdeContext context, String tool, Set tags) { super(context, tool, tags); } - /** - * @return the {@link Path} where the main executable file of this tool is installed. - */ - - @Override - public Path getToolBinary() { - - Path binPath = getToolBinPath(); - Path binary = this.context.getFileAccess().findFirst(binPath, this::isBinary, false); - if (binary == null) { - throw new IllegalStateException("Could not find executable binary for " + getName() + " in " + binPath); - } - return binary; - } - - protected boolean isBinary(Path path) { - - String filename = path.getFileName().toString(); - String binaryName = super.getName(); - if (filename.equals(binaryName)) { - return true; - } else if (filename.startsWith(binaryName)) { - String suffix = filename.substring(binaryName.length()); - return this.context.getSystemInfo().getOs().isExecutable(suffix); - } - return false; - } /** * @return the {@link Path} where the tool is located (installed). @@ -201,6 +174,35 @@ private ToolInstallation createToolInstallation(Path rootDir, VersionIdentifier return new ToolInstallation(rootDir, linkDir, binDir, resolvedVersion); } + /** + * @return the currently installed {@link VersionIdentifier version} of this tool or {@code null} if not installed. + */ + public VersionIdentifier getInstalledVersion() { + + Path toolPath = getToolPath(); + if (!Files.isDirectory(toolPath)) { + this.context.trace("Tool {} not installed in {}", getName(), toolPath); + return null; + } + Path toolVersionFile = toolPath.resolve(IdeContext.FILE_SOFTWARE_VERSION); + if (!Files.exists(toolVersionFile)) { + Path legacyToolVersionFile = toolPath.resolve(IdeContext.FILE_LEGACY_SOFTWARE_VERSION); + if (Files.exists(legacyToolVersionFile)) { + toolVersionFile = legacyToolVersionFile; + } else { + this.context.warning("Tool {} is missing version file in {}", getName(), toolVersionFile); + return null; + } + } + try { + String version = Files.readString(toolVersionFile).trim(); + return VersionIdentifier.of(version); + } catch (IOException e) { + throw new IllegalStateException("Failed to read file " + toolVersionFile, e); + } + + } + /** * @return the currently installed tool version or {@code null} if not found (tool not installed). */ diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java index 81d4f4cc0..bb3d671aa 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java @@ -100,16 +100,6 @@ public void runTool(VersionIdentifier toolVersion, String... args) { pc.run(); } - /** - * @return the {@link Path} where the main executable file of this tool is installed. - */ - public abstract Path getToolBinary(); - - /** - * @return the {@link Path} where the tool is located (installed). - */ - - /** * @return the {@link EnvironmentVariables#getToolEdition(String) tool edition}. */ @@ -142,29 +132,6 @@ protected final static String getToolWithEdition(String tool, String edition) { return tool + "/" + edition; } - /** - * @return the {@link Path} where the tool is located (installed). - */ - public Path getToolPath() { - - return this.context.getSoftwarePath().resolve(getName()); - } - - /** - * @return the {@link Path} where the executables of the tool can be found. Typically a "bin" folder inside - * {@link #getToolPath() tool path}. - */ - public Path getToolBinPath() { - - Path toolPath = getToolPath(); - Path binPath = this.context.getFileAccess().findFirst(toolPath, path -> path.getFileName().toString().equals("bin"), - false); - if ((binPath != null) && Files.isDirectory(binPath)) { - return binPath; - } - return toolPath; - } - /** * @return the {@link EnvironmentVariables#getToolVersion(String) tool version}. */ @@ -173,35 +140,6 @@ public VersionIdentifier getConfiguredVersion() { return this.context.getVariables().getToolVersion(getName()); } - /** - * @return the currently installed {@link VersionIdentifier version} of this tool or {@code null} if not installed. - */ - public VersionIdentifier getInstalledVersion() { - - Path toolPath = getToolPath(); - if (!Files.isDirectory(toolPath)) { - this.context.trace("Tool {} not installed in {}", getName(), toolPath); - return null; - } - Path toolVersionFile = toolPath.resolve(IdeContext.FILE_SOFTWARE_VERSION); - if (!Files.exists(toolVersionFile)) { - Path legacyToolVersionFile = toolPath.resolve(IdeContext.FILE_LEGACY_SOFTWARE_VERSION); - if (Files.exists(legacyToolVersionFile)) { - toolVersionFile = legacyToolVersionFile; - } else { - this.context.warning("Tool {} is missing version file in {}", getName(), toolVersionFile); - return null; - } - } - try { - String version = Files.readString(toolVersionFile).trim(); - return VersionIdentifier.of(version); - } catch (IOException e) { - throw new IllegalStateException("Failed to read file " + toolVersionFile, e); - } - - } - /** * Method to be called for {@link #install(boolean)} from dependent {@link Commandlet}s. * @@ -243,56 +181,6 @@ protected void postInstall() { // nothing to do by default } - /** - * @return {@code true} to extract (unpack) the downloaded binary file, {@code false} otherwise. - */ - protected boolean isExtract() { - - return true; - } - - /** - * @return the currently installed tool version or {@code null} if not found (tool not installed). - */ - protected String getInstalledToolVersion() { - - Path toolPath = getToolPath(); - if (!Files.isDirectory(toolPath)) { - this.context.debug("Tool {} not installed in {}", getName(), toolPath); - return null; - } - Path toolVersionFile = toolPath.resolve(IdeContext.FILE_SOFTWARE_VERSION); - if (!Files.exists(toolVersionFile)) { - Path legacyToolVersionFile = toolPath.resolve(IdeContext.FILE_LEGACY_SOFTWARE_VERSION); - if (Files.exists(legacyToolVersionFile)) { - toolVersionFile = legacyToolVersionFile; - } else { - this.context.warning("Tool {} is missing version file in {}", getName(), toolVersionFile); - return null; - } - } - try { - return Files.readString(toolVersionFile).trim(); - } catch (IOException e) { - throw new IllegalStateException("Failed to read file " + toolVersionFile, e); - } - } - - private boolean isInstalledVersion(VersionIdentifier expectedVersion, VersionIdentifier installedVersion, - boolean silent) { - - if (expectedVersion.equals(installedVersion)) { - IdeLogLevel level = IdeLogLevel.INFO; - if (silent) { - level = IdeLogLevel.DEBUG; - } - this.context.level(level).log("Version {} of tool {} is already installed", installedVersion, - getToolWithEdition()); - return true; - } - return false; - } - /** * @param path the {@link Path} to start the recursive search from. * @return the deepest subdir {@code s} of the passed path such that all directories between {@code s} and the passed @@ -325,9 +213,9 @@ private Path getProperInstallationSubDirOf(Path path) { */ protected void extract(Path file, Path targetDir) { - Path tmpDir = this.context.getFileAccess().createTempDir("extract-" + file.getFileName()); FileAccess fileAccess = this.context.getFileAccess(); if (isExtract()) { + Path tmpDir = this.context.getFileAccess().createTempDir("extract-" + file.getFileName()); this.context.trace("Trying to extract the downloaded file {} to {} and move it to {}.", file, tmpDir, targetDir); String extension = FilenameUtil.getExtension(file.getFileName().toString()); this.context.trace("Determined file extension {}", extension); @@ -380,6 +268,14 @@ protected void extract(Path file, Path targetDir) { } } + /** + * @return {@code true} to extract (unpack) the downloaded binary file, {@code false} otherwise. + */ + protected boolean isExtract() { + + return true; + } + protected MacOsHelper getMacOsHelper() { if (this.macOsHelper == null) { diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/eclipse/Eclipse.java b/cli/src/main/java/com/devonfw/tools/ide/tool/eclipse/Eclipse.java index 1d0adf78c..5b8dccedd 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/eclipse/Eclipse.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/eclipse/Eclipse.java @@ -53,7 +53,7 @@ public boolean install(boolean silent) { */ protected ProcessResult runEclipse(boolean log, String... args) { - Path toolPath = Paths.get(getBinaryName()); + Path toolPath = Paths.get(getName()); ProcessContext pc = this.context.newProcess(); if (log) { pc.errorHandling(ProcessErrorHandling.ERROR); diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/helm/Helm.java b/cli/src/main/java/com/devonfw/tools/ide/tool/helm/Helm.java index 1f4a2a41b..0ecfbf4d5 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/helm/Helm.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/helm/Helm.java @@ -1,6 +1,7 @@ package com.devonfw.tools.ide.tool.helm; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.tool.GlobalToolCommandlet; import com.devonfw.tools.ide.tool.LocalToolCommandlet; import com.devonfw.tools.ide.tool.ToolCommandlet; @@ -9,7 +10,7 @@ /** * {@link ToolCommandlet} for Helm, the package manager for Kubernetes. */ -public class Helm extends LocalToolCommandlet { +public class Helm extends GlobalToolCommandlet { /** * The constructor. * From e9517f856c2da86be513e5acbae4ac9be5ce38d3 Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Mon, 30 Oct 2023 18:48:28 +0100 Subject: [PATCH 16/22] Update GlobalToolCommandlet.java --- .../com/devonfw/tools/ide/tool/GlobalToolCommandlet.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java index 6ed69c92f..8b6a87946 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java @@ -76,12 +76,12 @@ protected boolean doInstall(boolean silent) { FileAccess fileAccess = this.context.getFileAccess(); Path target = Path.of("C:\\Users\\saboucha\\Downloads\\devonfw-ide\\terraform-1.6.2-windows.zip"); //Path target = toolRepository.download(this.tool, edition, resolvedVersion); - //Path tmpPath = this.context.getTempDownloadPath().resolve(target.getFileName()); - //Path tmpPath = fileAccess.createTempDir(target.getFileName().toString()); - //this.context.getFileAccess().delete(tmpPath); - //extract(target, tmpPath); Path tmpPath = this.context.getTempPath().resolve(target.getFileName()); extract(target, tmpPath); + if (isExtract()) { + //TODO: look for .exe inside tmpPath + tmpPath = null; + } ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.WARNING).executable(tmpPath); int exitCode = pc.run(); fileAccess.delete(tmpPath); From 9a8e2f374c9366823c5f0346a6b7f616b18d43b9 Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Mon, 30 Oct 2023 19:10:53 +0100 Subject: [PATCH 17/22] removed getToolBinary --- .../tools/ide/tool/GlobalToolCommandlet.java | 18 +----------------- .../devonfw/tools/ide/tool/ToolCommandlet.java | 7 ++++++- .../tools/ide/tool/eclipse/Eclipse.java | 2 +- .../com/devonfw/tools/ide/tool/helm/Helm.java | 3 +-- .../devonfw/tools/ide/tool/vscode/Vscode.java | 3 ++- 5 files changed, 11 insertions(+), 22 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java index 8b6a87946..60707694b 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java @@ -27,22 +27,6 @@ public GlobalToolCommandlet(IdeContext context, String tool, Set tags) { super(context, tool, tags); } - /** - * @return the {@link Path} where the main executable file of this tool is installed. - */ - public Path getToolBinary() { - - String path = System.getenv("PATH"); - String[] pathDirs = path.split(File.pathSeparator); - for (String dir : pathDirs) { - Path toolPath = Paths.get(dir, getName()); - if (Files.isExecutable(toolPath)) { - return toolPath; - } - } - return null; - } - /** * Override this if the global tool comes with a file that has to be extracted. * @return {@code true} to extract (unpack) the downloaded binary file, {@code false} otherwise. @@ -63,7 +47,7 @@ protected boolean isExtract() { @Override protected boolean doInstall(boolean silent) { - Path binaryPath = getToolBinary(); + Path binaryPath = this.context.getPath().findBinary(Path.of(getBinaryName())); if (binaryPath != null && Files.exists(binaryPath) && !this.context.isForceMode()) { this.context.debug("{} is already installed at {}", this.tool, binaryPath); return false; diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java index bb3d671aa..a1c648f89 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java @@ -65,6 +65,11 @@ public String getName() { return this.tool; } + protected String getBinaryName() { + + return this.tool; + } + @Override public final Set getTags() { @@ -88,7 +93,7 @@ public void run() { public void runTool(VersionIdentifier toolVersion, String... args) { Path binaryPath; - Path toolPath = Paths.get(getName()); + Path toolPath = Paths.get(getBinaryName()); if (toolVersion == null) { install(true); binaryPath = toolPath; diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/eclipse/Eclipse.java b/cli/src/main/java/com/devonfw/tools/ide/tool/eclipse/Eclipse.java index 5b8dccedd..1d0adf78c 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/eclipse/Eclipse.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/eclipse/Eclipse.java @@ -53,7 +53,7 @@ public boolean install(boolean silent) { */ protected ProcessResult runEclipse(boolean log, String... args) { - Path toolPath = Paths.get(getName()); + Path toolPath = Paths.get(getBinaryName()); ProcessContext pc = this.context.newProcess(); if (log) { pc.errorHandling(ProcessErrorHandling.ERROR); diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/helm/Helm.java b/cli/src/main/java/com/devonfw/tools/ide/tool/helm/Helm.java index 0ecfbf4d5..1f4a2a41b 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/helm/Helm.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/helm/Helm.java @@ -1,7 +1,6 @@ package com.devonfw.tools.ide.tool.helm; import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.tool.GlobalToolCommandlet; import com.devonfw.tools.ide.tool.LocalToolCommandlet; import com.devonfw.tools.ide.tool.ToolCommandlet; @@ -10,7 +9,7 @@ /** * {@link ToolCommandlet} for Helm, the package manager for Kubernetes. */ -public class Helm extends GlobalToolCommandlet { +public class Helm extends LocalToolCommandlet { /** * The constructor. * diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/vscode/Vscode.java b/cli/src/main/java/com/devonfw/tools/ide/tool/vscode/Vscode.java index 5a94dbf88..a7e85da00 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/vscode/Vscode.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/vscode/Vscode.java @@ -22,7 +22,8 @@ public Vscode (IdeContext context) { } @Override - public String getName() { + protected String getBinaryName() { + return "code"; } From bbd224b6a2a5b64c6c536dfb07e1a8a6215d5c26 Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Mon, 30 Oct 2023 19:13:04 +0100 Subject: [PATCH 18/22] updated doInstall --- .../java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java index 60707694b..3a1bc74ba 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java @@ -58,13 +58,11 @@ protected boolean doInstall(boolean silent) { VersionIdentifier resolvedVersion = toolRepository.resolveVersion(this.tool, edition, configuredVersion); // download and install the global tool FileAccess fileAccess = this.context.getFileAccess(); - Path target = Path.of("C:\\Users\\saboucha\\Downloads\\devonfw-ide\\terraform-1.6.2-windows.zip"); - //Path target = toolRepository.download(this.tool, edition, resolvedVersion); + Path target = toolRepository.download(this.tool, edition, resolvedVersion); Path tmpPath = this.context.getTempPath().resolve(target.getFileName()); extract(target, tmpPath); if (isExtract()) { //TODO: look for .exe inside tmpPath - tmpPath = null; } ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.WARNING).executable(tmpPath); int exitCode = pc.run(); From 6cf468255170d3497cc8ac0642f5b808170644e9 Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Mon, 30 Oct 2023 20:28:58 +0100 Subject: [PATCH 19/22] doInstall in GTC implemented --- .../ide/commandlet/VersionGetCommandlet.java | 7 +--- .../tools/ide/tool/GlobalToolCommandlet.java | 32 ++++++++++++++----- .../tools/ide/tool/LocalToolCommandlet.java | 3 -- .../tools/ide/tool/ToolCommandlet.java | 13 ++++++-- 4 files changed, 36 insertions(+), 19 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionGetCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionGetCommandlet.java index 9087116ae..bfbebee1c 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionGetCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionGetCommandlet.java @@ -3,8 +3,6 @@ import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.property.ToolProperty; -import com.devonfw.tools.ide.tool.GlobalToolCommandlet; -import com.devonfw.tools.ide.tool.LocalToolCommandlet; import com.devonfw.tools.ide.tool.ToolCommandlet; import com.devonfw.tools.ide.version.VersionIdentifier; @@ -40,10 +38,7 @@ public String getName() { public void run() { ToolCommandlet commandlet = this.tool.getValue(); - if (commandlet instanceof GlobalToolCommandlet) { - throw new UnsupportedOperationException("Not yet implemented!"); - } - VersionIdentifier installedVersion = ((LocalToolCommandlet)commandlet).getInstalledVersion(); + VersionIdentifier installedVersion = commandlet.getInstalledVersion(); if (installedVersion == null) { throw new CliException("Tool " + commandlet.getName() + " is not installed!", 4); } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java index 3a1bc74ba..0ad564204 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java @@ -7,10 +7,8 @@ import com.devonfw.tools.ide.repo.ToolRepository; import com.devonfw.tools.ide.version.VersionIdentifier; -import java.io.File; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Set; public abstract class GlobalToolCommandlet extends ToolCommandlet { @@ -34,7 +32,7 @@ public GlobalToolCommandlet(IdeContext context, String tool, Set tags) { @Override protected boolean isExtract() { - return true; + return false; } /** @@ -50,7 +48,7 @@ protected boolean doInstall(boolean silent) { Path binaryPath = this.context.getPath().findBinary(Path.of(getBinaryName())); if (binaryPath != null && Files.exists(binaryPath) && !this.context.isForceMode()) { this.context.debug("{} is already installed at {}", this.tool, binaryPath); - return false; + //return false; } String edition = getEdition(); ToolRepository toolRepository = this.context.getDefaultToolRepository(); @@ -59,14 +57,16 @@ protected boolean doInstall(boolean silent) { // download and install the global tool FileAccess fileAccess = this.context.getFileAccess(); Path target = toolRepository.download(this.tool, edition, resolvedVersion); - Path tmpPath = this.context.getTempPath().resolve(target.getFileName()); - extract(target, tmpPath); + Path tmpPath = fileAccess.createTempDir(getName()); + Path downloadBinaryPath = tmpPath.resolve(target.getFileName()); + extract(target, downloadBinaryPath); if (isExtract()) { - //TODO: look for .exe inside tmpPath + downloadBinaryPath = fileAccess.findFirst(downloadBinaryPath, Files::isExecutable, false); } - ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.WARNING).executable(tmpPath); + ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.WARNING).executable(downloadBinaryPath); int exitCode = pc.run(); fileAccess.delete(tmpPath); + fileAccess.delete(target); if (exitCode == 0) { this.context.success("Successfully installed {} in version {}", this.tool, resolvedVersion); } else { @@ -77,6 +77,22 @@ protected boolean doInstall(boolean silent) { return true; } + /** + * @return the currently installed {@link VersionIdentifier version} of this tool or {@code null} if not installed. + */ + @Override + public VersionIdentifier getInstalledVersion() { + return null; + } + + /** + * @return the currently installed tool version or {@code null} if not found (tool not installed). + */ + @Override + protected String getInstalledToolVersion() { + return null; + } + } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java index 7a6859b1e..0c31acc6f 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java @@ -4,11 +4,8 @@ import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.io.FileAccess; import com.devonfw.tools.ide.io.FileCopyMode; -import com.devonfw.tools.ide.io.TarCompression; import com.devonfw.tools.ide.log.IdeLogLevel; -import com.devonfw.tools.ide.process.ProcessContext; import com.devonfw.tools.ide.repo.ToolRepository; -import com.devonfw.tools.ide.util.FilenameUtil; import com.devonfw.tools.ide.version.VersionIdentifier; import java.io.IOException; diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java index a1c648f89..e779fb799 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java @@ -16,7 +16,6 @@ import com.devonfw.tools.ide.environment.EnvironmentVariablesType; import com.devonfw.tools.ide.io.FileAccess; import com.devonfw.tools.ide.io.TarCompression; -import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.os.MacOsHelper; import com.devonfw.tools.ide.process.ProcessContext; import com.devonfw.tools.ide.process.ProcessErrorHandling; @@ -179,7 +178,7 @@ public boolean install(boolean silent) { /** * This method is called after the tool has been newly installed or updated to a new version. Override it to add - * custom post intallation logic. + * custom post installation logic. */ protected void postInstall() { @@ -289,6 +288,16 @@ protected MacOsHelper getMacOsHelper() { return this.macOsHelper; } + /** + * @return the currently installed {@link VersionIdentifier version} of this tool or {@code null} if not installed. + */ + public abstract VersionIdentifier getInstalledVersion(); + + /** + * @return the currently installed tool version or {@code null} if not found (tool not installed). + */ + protected abstract String getInstalledToolVersion(); + /** * List the available versions of this tool. */ From 2b31f10c13a0fe709428af490f30928ef2ed649a Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Mon, 30 Oct 2023 21:00:24 +0100 Subject: [PATCH 20/22] JavaDocs --- .../java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java | 3 +++ .../java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java index 0ad564204..1fbac8d4e 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java @@ -11,6 +11,9 @@ import java.nio.file.Path; import java.util.Set; +/** + * {@link ToolCommandlet} that are installed globally. + */ public abstract class GlobalToolCommandlet extends ToolCommandlet { /** * The constructor. diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java index 0c31acc6f..1f3cfdb6f 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java @@ -14,6 +14,9 @@ import java.nio.file.StandardOpenOption; import java.util.Set; +/** + * {@link ToolCommandlet} that are installed locally. + */ public abstract class LocalToolCommandlet extends ToolCommandlet { /** * The constructor. From 830e6d3fa49d4616c64b27b1c44fb39acc00f36b Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Tue, 31 Oct 2023 14:58:33 +0100 Subject: [PATCH 21/22] updated doInstall --- .../java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java index 1fbac8d4e..cb0665e03 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java @@ -51,7 +51,7 @@ protected boolean doInstall(boolean silent) { Path binaryPath = this.context.getPath().findBinary(Path.of(getBinaryName())); if (binaryPath != null && Files.exists(binaryPath) && !this.context.isForceMode()) { this.context.debug("{} is already installed at {}", this.tool, binaryPath); - //return false; + return false; } String edition = getEdition(); ToolRepository toolRepository = this.context.getDefaultToolRepository(); From 0fa34f354fc6d4b27ed09214eee9da37a3c0f334 Mon Sep 17 00:00:00 2001 From: salimbouch <145128725+salimbouch@users.noreply.github.com> Date: Mon, 6 Nov 2023 01:59:46 +0100 Subject: [PATCH 22/22] reviewed changes --- .../tools/ide/tool/GlobalToolCommandlet.java | 41 ++---------- .../tools/ide/tool/LocalToolCommandlet.java | 67 +------------------ .../tools/ide/tool/ToolCommandlet.java | 38 +++++++++-- 3 files changed, 42 insertions(+), 104 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java index cb0665e03..8c83a16a1 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java @@ -12,9 +12,10 @@ import java.util.Set; /** - * {@link ToolCommandlet} that are installed globally. + * {@link ToolCommandlet} that is installed globally. */ public abstract class GlobalToolCommandlet extends ToolCommandlet { + /** * The constructor. * @@ -28,27 +29,17 @@ public GlobalToolCommandlet(IdeContext context, String tool, Set tags) { super(context, tool, tags); } - /** - * Override this if the global tool comes with a file that has to be extracted. - * @return {@code true} to extract (unpack) the downloaded binary file, {@code false} otherwise. - */ @Override protected boolean isExtract() { - + // for global tools we usually download installers and do not want to extract them (e.g. installer.msi file shall not be extracted) return false; } - /** - * Installs {@link #getName() tool}, if force mode is enabled it proceeds with the installation even if the tool - * is already installed - * @param silent - {@code true} if called recursively to suppress verbose logging, {@code false} otherwise. - * @return {@code true} if the tool was newly installed, {@code false} if the tool was already installed before and - * nothing has changed. - */ @Override protected boolean doInstall(boolean silent) { Path binaryPath = this.context.getPath().findBinary(Path.of(getBinaryName())); + //if force mode is enabled, go through with the installation even if the tool is already installed if (binaryPath != null && Files.exists(binaryPath) && !this.context.isForceMode()) { this.context.debug("{} is already installed at {}", this.tool, binaryPath); return false; @@ -60,15 +51,15 @@ protected boolean doInstall(boolean silent) { // download and install the global tool FileAccess fileAccess = this.context.getFileAccess(); Path target = toolRepository.download(this.tool, edition, resolvedVersion); - Path tmpPath = fileAccess.createTempDir(getName()); - Path downloadBinaryPath = tmpPath.resolve(target.getFileName()); + Path tmpDir = fileAccess.createTempDir(getName()); + Path downloadBinaryPath = tmpDir.resolve(target.getFileName()); extract(target, downloadBinaryPath); if (isExtract()) { downloadBinaryPath = fileAccess.findFirst(downloadBinaryPath, Files::isExecutable, false); } ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.WARNING).executable(downloadBinaryPath); int exitCode = pc.run(); - fileAccess.delete(tmpPath); + fileAccess.delete(tmpDir); fileAccess.delete(target); if (exitCode == 0) { this.context.success("Successfully installed {} in version {}", this.tool, resolvedVersion); @@ -80,22 +71,4 @@ protected boolean doInstall(boolean silent) { return true; } - /** - * @return the currently installed {@link VersionIdentifier version} of this tool or {@code null} if not installed. - */ - @Override - public VersionIdentifier getInstalledVersion() { - return null; - } - - /** - * @return the currently installed tool version or {@code null} if not found (tool not installed). - */ - @Override - protected String getInstalledToolVersion() { - return null; - } - - - } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java index 1f3cfdb6f..8505dead7 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java @@ -15,9 +15,10 @@ import java.util.Set; /** - * {@link ToolCommandlet} that are installed locally. + * {@link ToolCommandlet} that is installed locally into the IDE. */ public abstract class LocalToolCommandlet extends ToolCommandlet { + /** * The constructor. * @@ -55,14 +56,6 @@ public Path getToolBinPath() { return toolPath; } - /** - * Installs or updates the managed {@link #getName() tool}. - * - * @param silent - {@code true} if called recursively to suppress verbose logging, {@code false} otherwise. - * @return {@code true} if the tool was newly installed, {@code false} if the tool was already installed before and - * nothing has changed. - */ - @Override protected boolean doInstall(boolean silent) { @@ -174,62 +167,6 @@ private ToolInstallation createToolInstallation(Path rootDir, VersionIdentifier return new ToolInstallation(rootDir, linkDir, binDir, resolvedVersion); } - /** - * @return the currently installed {@link VersionIdentifier version} of this tool or {@code null} if not installed. - */ - public VersionIdentifier getInstalledVersion() { - - Path toolPath = getToolPath(); - if (!Files.isDirectory(toolPath)) { - this.context.trace("Tool {} not installed in {}", getName(), toolPath); - return null; - } - Path toolVersionFile = toolPath.resolve(IdeContext.FILE_SOFTWARE_VERSION); - if (!Files.exists(toolVersionFile)) { - Path legacyToolVersionFile = toolPath.resolve(IdeContext.FILE_LEGACY_SOFTWARE_VERSION); - if (Files.exists(legacyToolVersionFile)) { - toolVersionFile = legacyToolVersionFile; - } else { - this.context.warning("Tool {} is missing version file in {}", getName(), toolVersionFile); - return null; - } - } - try { - String version = Files.readString(toolVersionFile).trim(); - return VersionIdentifier.of(version); - } catch (IOException e) { - throw new IllegalStateException("Failed to read file " + toolVersionFile, e); - } - - } - - /** - * @return the currently installed tool version or {@code null} if not found (tool not installed). - */ - protected String getInstalledToolVersion() { - - Path toolPath = getToolPath(); - if (!Files.isDirectory(toolPath)) { - this.context.debug("Tool {} not installed in {}", getName(), toolPath); - return null; - } - Path toolVersionFile = toolPath.resolve(IdeContext.FILE_SOFTWARE_VERSION); - if (!Files.exists(toolVersionFile)) { - Path legacyToolVersionFile = toolPath.resolve(IdeContext.FILE_LEGACY_SOFTWARE_VERSION); - if (Files.exists(legacyToolVersionFile)) { - toolVersionFile = legacyToolVersionFile; - } else { - this.context.warning("Tool {} is missing version file in {}", getName(), toolVersionFile); - return null; - } - } - try { - return Files.readString(toolVersionFile).trim(); - } catch (IOException e) { - throw new IllegalStateException("Failed to read file " + toolVersionFile, e); - } - } - private boolean isInstalledVersion(VersionIdentifier expectedVersion, VersionIdentifier installedVersion, boolean silent) { diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java index e779fb799..c25a7d5bb 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java @@ -64,6 +64,10 @@ public String getName() { return this.tool; } + /** + * + * @return the name of the binary + */ protected String getBinaryName() { return this.tool; @@ -177,8 +181,7 @@ public boolean install(boolean silent) { protected abstract boolean doInstall(boolean silent); /** - * This method is called after the tool has been newly installed or updated to a new version. Override it to add - * custom post installation logic. + * This method is called after the tool has been newly installed or updated to a new version. */ protected void postInstall() { @@ -291,12 +294,37 @@ protected MacOsHelper getMacOsHelper() { /** * @return the currently installed {@link VersionIdentifier version} of this tool or {@code null} if not installed. */ - public abstract VersionIdentifier getInstalledVersion(); + public VersionIdentifier getInstalledVersion() { + + return getInstalledVersion(this.context.getSoftwarePath().resolve(getName())); + } /** - * @return the currently installed tool version or {@code null} if not found (tool not installed). + * @return the currently installed {@link VersionIdentifier version} of this tool or {@code null} if not installed. */ - protected abstract String getInstalledToolVersion(); + protected VersionIdentifier getInstalledVersion(Path toolPath) { + + if (!Files.isDirectory(toolPath)) { + this.context.debug("Tool {} not installed in {}", getName(), toolPath); + return null; + } + Path toolVersionFile = toolPath.resolve(IdeContext.FILE_SOFTWARE_VERSION); + if (!Files.exists(toolVersionFile)) { + Path legacyToolVersionFile = toolPath.resolve(IdeContext.FILE_LEGACY_SOFTWARE_VERSION); + if (Files.exists(legacyToolVersionFile)) { + toolVersionFile = legacyToolVersionFile; + } else { + this.context.warning("Tool {} is missing version file in {}", getName(), toolVersionFile); + return null; + } + } + try { + String version = Files.readString(toolVersionFile).trim(); + return VersionIdentifier.of(version); + } catch (IOException e) { + throw new IllegalStateException("Failed to read file " + toolVersionFile, e); + } + } /** * List the available versions of this tool.