diff --git a/cli/src/main/java/com/devonfw/tools/ide/repo/DefaultToolRepository.java b/cli/src/main/java/com/devonfw/tools/ide/repo/DefaultToolRepository.java index c15f44761c..222eb2d9b3 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/repo/DefaultToolRepository.java +++ b/cli/src/main/java/com/devonfw/tools/ide/repo/DefaultToolRepository.java @@ -33,7 +33,7 @@ public String getId() { public VersionIdentifier resolveVersion(String tool, String edition, VersionIdentifier version) { UrlMetadata metadata = this.context.getUrls(); - UrlVersion urlVersion = metadata.getVersionFolder(tool, edition, version); + UrlVersion urlVersion = metadata.getResolvedVersion(tool, edition, version); return urlVersion.getVersionIdentifier(); } @@ -41,7 +41,7 @@ public VersionIdentifier resolveVersion(String tool, String edition, VersionIden protected UrlDownloadFileMetadata getMetadata(String tool, String edition, VersionIdentifier version) { UrlMetadata metadata = this.context.getUrls(); - UrlVersion urlVersion = metadata.getVersionFolder(tool, edition, version); + UrlVersion urlVersion = metadata.getResolvedVersion(tool, edition, version); SystemInfo sys = this.context.getSystemInfo(); UrlDownloadFile urls = urlVersion.getMatchingUrls(sys.getOs(), sys.getArchitecture()); return urls; 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 14db1f0079..c49a1c19b2 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 @@ -9,6 +9,7 @@ import java.util.Set; import com.devonfw.tools.ide.common.Tag; +import com.devonfw.tools.ide.context.AbstractIdeContext; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.io.FileAccess; import com.devonfw.tools.ide.io.FileCopyMode; @@ -73,16 +74,17 @@ protected boolean doInstall(boolean silent) { VersionIdentifier installedVersion = getInstalledVersion(); Step step = this.context.newStep(silent, "Install " + this.tool, configuredVersion); try { - // 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 resolvedVersion = installation.resolvedVersion(); - if (resolvedVersion.equals(installedVersion) && !installation.newInstallation()) { + ToolRepository repository = this.context.getDefaultToolRepository(); + String edition = getConfiguredEdition(); + VersionIdentifier resolvedVersion = repository.resolveVersion(this.tool, edition, configuredVersion); + if (resolvedVersion.equals(installedVersion)) { IdeLogLevel level = silent ? IdeLogLevel.DEBUG : IdeLogLevel.INFO; this.context.level(level).log("Version {} of tool {} is already installed", installedVersion, getToolWithEdition()); step.success(); return false; } + // install configured version of our tool in the software repository if not already installed + ToolInstallation installation = installInRepo(resolvedVersion, edition, repository); // we need to link the version or update the link. Path toolPath = getToolPath(); FileAccess fileAccess = this.context.getFileAccess(); @@ -158,17 +160,20 @@ public ToolInstallation installInRepo(VersionIdentifier version, String edition, FileAccess fileAccess = this.context.getFileAccess(); if (Files.isDirectory(toolPath)) { if (Files.exists(toolVersionFile)) { - if (this.context.isForceMode()) { - fileAccess.delete(toolPath); - } else { - this.context.debug("Version {} of tool {} is already installed at {}", resolvedVersion, getToolWithEdition(this.tool, edition), toolPath); - return createToolInstallation(toolPath, resolvedVersion, toolVersionFile); - } + this.context.debug("Version {} of tool {} is already installed at {}", resolvedVersion, getToolWithEdition(this.tool, edition), toolPath); + return createToolInstallation(toolPath, resolvedVersion, toolVersionFile); } else { - this.context.warning("Deleting corrupted installation at {}", toolPath); - fileAccess.delete(toolPath); + this.context.warning("Archiving corrupted installation at {}", toolPath); + fileAccess.backup(toolPath); } } + + if (Files.exists(this.dependency.getDependencyJsonPath(getConfiguredEdition()))) { + installDependencies(resolvedVersion); + } else { + this.context.trace("No Dependencies file found"); + } + Path target = toolRepository.download(this.tool, edition, resolvedVersion); fileAccess.mkdirs(toolPath.getParent()); boolean extract = isExtract(); @@ -291,13 +296,39 @@ private ToolInstallation createToolInstallation(Path rootDir, VersionIdentifier if (Files.isDirectory(binFolder)) { binDir = binFolder; } - if (linkDir != rootDir) { + if (newInstallation && (linkDir != rootDir)) { assert (!linkDir.equals(rootDir)); this.context.getFileAccess().copy(toolVersionFile, linkDir, FileCopyMode.COPY_FILE_OVERRIDE); + if (this.context.getSystemInfo().isMac() && !((AbstractIdeContext) this.context).isTest()) { + Path macApp = findMacApp(linkDir); + if (macApp != null) { + ProcessContext pc = this.context.newProcess(); + pc.executable("sudo").addArgs("xattr", "-d", "com.apple.quarantine", macApp); + pc.run(); + } + } } return new ToolInstallation(rootDir, linkDir, binDir, resolvedVersion, newInstallation); } + private Path findMacApp(Path path) { + + while (path != null) { + Path fileName = path.getFileName(); + if (fileName == null) { + return null; + } + String filename = fileName.toString(); + if (filename.endsWith(".app")) { + return path; + } else if (filename.equals(IdeContext.FOLDER_CONTENTS)) { + return path.getParent(); + } + path = path.getParent(); + } + return null; + } + private ToolInstallation createToolInstallation(Path rootDir, VersionIdentifier resolvedVersion, Path toolVersionFile) { return createToolInstallation(rootDir, resolvedVersion, toolVersionFile, 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 ce403baac1..bbd5f2e50b 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 @@ -278,22 +278,21 @@ public void setVersion(String version) { public void setVersion(VersionIdentifier version, boolean hint) { String edition = getConfiguredEdition(); - this.context.getUrls() - .getVersionFolder(this.tool, edition, version); // CliException is thrown if the version is not existing EnvironmentVariables variables = this.context.getVariables(); EnvironmentVariables settingsVariables = variables.getByType(EnvironmentVariablesType.SETTINGS); - String name = EnvironmentVariables.getToolVersionVariable(this.tool); - VersionIdentifier resolvedVersion = this.context.getUrls().getVersion(this.tool, edition, version); + String versionVariableName = EnvironmentVariables.getToolVersionVariable(this.tool); + VersionIdentifier resolvedVersion = this.context.getUrls().getResolvedVersion(this.tool, edition, version).getVersionIdentifier(); if (version.isPattern()) { this.context.debug("Resolved version {} to {} for tool {}/{}", version, resolvedVersion, this.tool, edition); } - settingsVariables.set(name, resolvedVersion.toString(), false); + settingsVariables.set(versionVariableName, version.toString(), false); settingsVariables.save(); - this.context.info("{}={} has been set in {}", name, version, settingsVariables.getSource()); - EnvironmentVariables declaringVariables = variables.findVariable(name); + this.context.info("{}={} has been set in {}", versionVariableName, version, settingsVariables.getSource()); + EnvironmentVariables declaringVariables = variables.findVariable(versionVariableName); 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, + this.context.warning("The variable {} is overridden in {}. Please remove the overridden declaration in order to make the change affect.", + versionVariableName, declaringVariables.getSource()); } if (hint) { 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 b521860766..a23989fa03 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 @@ -214,7 +214,7 @@ private Set findVariables(String content) { @Override public void installPlugin(PluginDescriptor plugin) { - Path mavenPlugin = this.getToolPath().resolve("lib/ext/" + plugin.getName() + ".jar"); + Path mavenPlugin = getToolPath().resolve("lib/ext/" + plugin.getName() + ".jar"); this.context.getFileAccess().download(plugin.getUrl(), mavenPlugin); if (Files.exists(mavenPlugin)) { this.context.success("Successfully added {} to {}", plugin.getName(), mavenPlugin.toString()); diff --git a/cli/src/main/java/com/devonfw/tools/ide/url/model/UrlMetadata.java b/cli/src/main/java/com/devonfw/tools/ide/url/model/UrlMetadata.java index 2fcad237ae..c7cfd553b2 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/url/model/UrlMetadata.java +++ b/cli/src/main/java/com/devonfw/tools/ide/url/model/UrlMetadata.java @@ -46,8 +46,14 @@ public UrlMetadata(IdeContext context) { */ public UrlEdition getEdition(String tool, String edition) { - UrlTool urlTool = this.repository.getOrCreateChild(tool); - UrlEdition urlEdition = urlTool.getOrCreateChild(edition); + UrlTool urlTool = this.repository.getChild(tool); + if (urlTool == null) { + throw new CliException("Could not find tool '" + tool + "' in ide-urls metadata!"); + } + UrlEdition urlEdition = urlTool.getChild(edition); + if (urlEdition == null) { + throw new CliException("Could not find edition '" + edition + "' for tool '" + tool + "' in ide-urls metadata!"); + } return urlEdition; } @@ -101,14 +107,25 @@ private List computeSortedVersions(String tool, String editio * latest version. * @return the latest matching {@link VersionIdentifier} for the given {@code tool} and {@code edition}. */ - public VersionIdentifier getVersion(String tool, String edition, VersionIdentifier version) { + public UrlVersion getResolvedVersion(String tool, String edition, VersionIdentifier version) { if (version == null) { version = VersionIdentifier.LATEST; } - if (!version.isPattern()) { - return version; + UrlEdition urlEdition = getEdition(tool, edition); + VersionIdentifier resolvedVersion = version; + if (version.isPattern()) { + resolvedVersion = resolveVersion(tool, edition, version); } + UrlVersion urlVersion = urlEdition.getChild(resolvedVersion.toString()); + if (urlVersion == null) { + throw new CliException("Version " + version + " for tool " + tool + " does not exist in edition " + edition + "."); + } + return urlVersion; + } + + private VersionIdentifier resolveVersion(String tool, String edition, VersionIdentifier version) { + List versions = getSortedVersions(tool, edition); for (VersionIdentifier vi : versions) { if (version.matches(vi)) { @@ -116,26 +133,10 @@ public VersionIdentifier getVersion(String tool, String edition, VersionIdentifi return vi; } } + // TODO properly consider edition (needs list-versions commandlet enhancement to also support edition) throw new CliException( "Could not find any version matching '" + version + "' for tool '" + tool + "' - potentially there are " + versions.size() + " version(s) available in " - + getEdition(tool, edition).getPath() + " but none matched!"); - } - - /** - * @param tool the name of the {@link UrlTool}. - * @param edition the name of the {@link UrlEdition}. - * @param version the {@link VersionIdentifier} to match. May be a {@link VersionIdentifier#isPattern() pattern}, a specific version or {@code null} for the - * latest version. - * @return the latest matching {@link UrlVersion} for the given {@code tool} and {@code edition}. - */ - public UrlVersion getVersionFolder(String tool, String edition, VersionIdentifier version) { - - VersionIdentifier resolvedVersion = getVersion(tool, edition, version); - UrlVersion urlVersion = getEdition(tool, edition).getChild(resolvedVersion.toString()); - if (urlVersion == null) { - throw new CliException("Version " + version + " for tool " + tool + " does not exist in edition " + edition + "."); - } - return urlVersion; + + getEdition(tool, edition).getPath() + " but none matched! You can get the list of available versions with the following command:\nide list-versions " + tool); } } diff --git a/cli/src/test/java/com/devonfw/tools/ide/commandlet/EditionSetCommandletTest.java b/cli/src/test/java/com/devonfw/tools/ide/commandlet/EditionSetCommandletTest.java index d373efb97e..1723b61827 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/commandlet/EditionSetCommandletTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/commandlet/EditionSetCommandletTest.java @@ -6,7 +6,6 @@ import org.junit.jupiter.api.Test; import com.devonfw.tools.ide.context.AbstractIdeContextTest; -import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.context.IdeTestContext; import com.devonfw.tools.ide.log.IdeLogLevel; @@ -18,17 +17,18 @@ public class EditionSetCommandletTest extends AbstractIdeContextTest { public void testEditionSetCommandletRun() { // arrange - IdeContext context = newContext(PROJECT_BASIC); + IdeTestContext context = newContext(PROJECT_BASIC); EditionSetCommandlet editionSet = context.getCommandletManager().getCommandlet(EditionSetCommandlet.class); - editionSet.tool.setValueAsString("mvn", context); - editionSet.edition.setValueAsString("setEdition", context); + editionSet.tool.setValueAsString("docker", context); + editionSet.edition.setValueAsString("rancher", context); + assertThat(context.getVariables().getToolEdition("docker")).isEqualTo("docker"); // act editionSet.run(); // assert - List logs = ((IdeTestContext) context).level(IdeLogLevel.WARNING).getMessages(); - assertThat(logs).containsExactly("Edition setEdition seems to be invalid"); + assertThat(context.getVariables().getToolEdition("docker")).isEqualTo("rancher"); + assertLogMessage(context, IdeLogLevel.INFO, "DOCKER_EDITION=rancher has been set in SETTINGS@", true); Path settingsIdeProperties = context.getSettingsPath().resolve("ide.properties"); assertThat(settingsIdeProperties).hasContent(""" #******************************************************************************** @@ -49,6 +49,6 @@ public void testEditionSetCommandletRun() { TEST_ARGS9=settings9 TEST_ARGSb=${TEST_ARGS10} settingsb ${TEST_ARGSa} ${TEST_ARGSb} TEST_ARGSc=${TEST_ARGSc} settingsc - MVN_EDITION=setEdition"""); + DOCKER_EDITION=rancher"""); } } diff --git a/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/docker/latest/mac_arm64.urls b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/docker/latest/mac_arm64.urls new file mode 100644 index 0000000000..f67fd2cb57 --- /dev/null +++ b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/docker/latest/mac_arm64.urls @@ -0,0 +1 @@ +https://desktop.docker.com/mac/main/arm64/Docker.dmg diff --git a/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/docker/latest/mac_x64.urls b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/docker/latest/mac_x64.urls new file mode 100644 index 0000000000..ddc76f03ea --- /dev/null +++ b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/docker/latest/mac_x64.urls @@ -0,0 +1 @@ +https://desktop.docker.com/mac/main/amd64/Docker.dmg diff --git a/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/docker/latest/windows_x64.urls b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/docker/latest/windows_x64.urls new file mode 100644 index 0000000000..a91514e91b --- /dev/null +++ b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/docker/latest/windows_x64.urls @@ -0,0 +1 @@ +https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe diff --git a/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/linux_x64.urls b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/linux_x64.urls new file mode 100644 index 0000000000..3745edf9cc --- /dev/null +++ b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/linux_x64.urls @@ -0,0 +1 @@ +https://github.com/rancher-sandbox/rancher-desktop/releases/download/v1.14.2/rancher-desktop-linux-v1.14.2.zip diff --git a/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/linux_x64.urls.sha256 b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/linux_x64.urls.sha256 new file mode 100644 index 0000000000..8410df2f88 --- /dev/null +++ b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/linux_x64.urls.sha256 @@ -0,0 +1 @@ +2d304d3fe0dbf5efe987c2d583feeb607ce9ef507753fcf0a6b1a6b9b2128d1e diff --git a/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/mac_arm64.urls b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/mac_arm64.urls new file mode 100644 index 0000000000..e3511f6835 --- /dev/null +++ b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/mac_arm64.urls @@ -0,0 +1 @@ +https://github.com/rancher-sandbox/rancher-desktop/releases/download/v1.14.2/Rancher.Desktop-1.14.2-mac.aarch64.zip diff --git a/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/mac_arm64.urls.sha256 b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/mac_arm64.urls.sha256 new file mode 100644 index 0000000000..92ed70df7f --- /dev/null +++ b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/mac_arm64.urls.sha256 @@ -0,0 +1 @@ +0ce7cf58fecbf4ea99541f51401f95ba70053b390b51ae98b16265d1a450a517 diff --git a/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/mac_x64.urls b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/mac_x64.urls new file mode 100644 index 0000000000..e370458885 --- /dev/null +++ b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/mac_x64.urls @@ -0,0 +1 @@ +https://github.com/rancher-sandbox/rancher-desktop/releases/download/v1.14.2/Rancher.Desktop-1.14.2.x86_64.dmg diff --git a/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/mac_x64.urls.sha256 b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/mac_x64.urls.sha256 new file mode 100644 index 0000000000..cf87a9ec60 --- /dev/null +++ b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/mac_x64.urls.sha256 @@ -0,0 +1 @@ +e764e335d1475f8bceb3fb6d1d1892b09d3c2bee3f34355ddab8a7e157c87452 diff --git a/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/windows_x64.urls b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/windows_x64.urls new file mode 100644 index 0000000000..cf9728f8a4 --- /dev/null +++ b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/windows_x64.urls @@ -0,0 +1 @@ +https://github.com/rancher-sandbox/rancher-desktop/releases/download/v1.14.2/Rancher.Desktop.Setup.1.14.2.msi diff --git a/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/windows_x64.urls.sha256 b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/windows_x64.urls.sha256 new file mode 100644 index 0000000000..f22248aa2d --- /dev/null +++ b/cli/src/test/resources/ide-projects/basic/_ide/urls/docker/rancher/1.14.2/windows_x64.urls.sha256 @@ -0,0 +1 @@ +01f52b7a1ebcddeda01b6979ce3505b895fdcde2c5b57f18e4f8c4a593618f3f