diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index c2acecfcb..d44c54afd 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -6,6 +6,9 @@ This file documents all notable changes to https://github.com/devonfw/IDEasy[IDE
Release with new features and bugfixes:
+* https://github.com/devonfw/IDEasy/issues/692[#692]: "Latest" version of Docker causes installation problems
+
+
The full list of changes for this release can be found in https://github.com/devonfw/IDEasy/milestone/24?closed=1[milestone 2025.03.002].
== 2025.03.001
diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/repository/AbstractToolRepository.java b/cli/src/main/java/com/devonfw/tools/ide/tool/repository/AbstractToolRepository.java
index 086ed9681..bb9b679dd 100644
--- a/cli/src/main/java/com/devonfw/tools/ide/tool/repository/AbstractToolRepository.java
+++ b/cli/src/main/java/com/devonfw/tools/ide/tool/repository/AbstractToolRepository.java
@@ -27,7 +27,7 @@
public abstract class AbstractToolRepository implements ToolRepository {
private static final int MAX_TEMP_DOWNLOADS = 9;
-
+
/** The owning {@link IdeContext}. */
protected final IdeContext context;
@@ -135,7 +135,11 @@ protected String createDownloadFilename(String tool, String edition, VersionIden
StringBuilder sb = new StringBuilder(32);
sb.append(tool);
sb.append("-");
- sb.append(version);
+ if (VersionIdentifier.LATEST.equals(version)) {
+ sb.append("latest");
+ } else {
+ sb.append(version);
+ }
if (!edition.equals(tool)) {
sb.append("-");
sb.append(edition);
diff --git a/cli/src/main/java/com/devonfw/tools/ide/url/model/folder/AbstractUrlFolder.java b/cli/src/main/java/com/devonfw/tools/ide/url/model/folder/AbstractUrlFolder.java
index 2daa4f1c8..fed985b67 100644
--- a/cli/src/main/java/com/devonfw/tools/ide/url/model/folder/AbstractUrlFolder.java
+++ b/cli/src/main/java/com/devonfw/tools/ide/url/model/folder/AbstractUrlFolder.java
@@ -58,6 +58,9 @@ public int getChildCount() {
public C getChild(String name) {
load(false);
+ if ("*".equals(name)) {
+ return this.childMap.get("latest");
+ }
return this.childMap.get(name);
}
diff --git a/url-updater/src/main/java/com/devonfw/tools/ide/url/tool/docker/DockerDesktopUrlUpdater.java b/url-updater/src/main/java/com/devonfw/tools/ide/url/tool/docker/DockerDesktopUrlUpdater.java
index 924a21deb..6000fcbcc 100644
--- a/url-updater/src/main/java/com/devonfw/tools/ide/url/tool/docker/DockerDesktopUrlUpdater.java
+++ b/url-updater/src/main/java/com/devonfw/tools/ide/url/tool/docker/DockerDesktopUrlUpdater.java
@@ -1,5 +1,7 @@
package com.devonfw.tools.ide.url.tool.docker;
+import static java.lang.String.format;
+
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -17,6 +19,21 @@ public class DockerDesktopUrlUpdater extends WebsiteUrlUpdater {
VersionIdentifier.of("4.4.3"), VersionIdentifier.of("4.4.4"), VersionIdentifier.of("4.17.1"),
VersionIdentifier.of("4.5.1"));
+ private final static String DOCKER_RELEASE_NOTES_URL = "https://docs.docker.com/desktop/release-notes/";
+
+ private final static String REGEX_FOR_DOCKER_VERSION =
+ "href=#%s" // Find the href with the readable version - %s provided by urlVersion
+ + ".{0,300}" // We have to look in close range for the next part (docker lists a summary at top. If this range is to big
+ // we'll find the latest listed version with download links that doesn't match the version we are looking for
+ + "href=https://desktop\\.docker\\.com" // Start of download link
+ + ".*?" // We don't care if its windows or mac - match as least as possible characters
+ + "(\\d{5,6})"; // Associated docker-version to readable version we are looking for
+ private final static String REGEX_FOR_DOWNLOAD_URLS = "https://desktop.docker.com/%s/main/%s/%s/";
+ private final static String WIN_VERSION = "win";
+ private final static String MAC_VERSION = "mac";
+ private final static String AMD_ARCH_TYPE = "amd64";
+ private final static String ARM_ARCH_TYPE = "arm64";
+
@Override
protected String getTool() {
@@ -29,31 +46,79 @@ protected void addVersion(UrlVersion urlVersion) {
VersionIdentifier vid = VersionIdentifier.of(urlVersion.getName());
String version = urlVersion.getName().replaceAll("\\.", "");
// get Code for version
- String body = doGetResponseBodyAsString("https://docs.docker.com/desktop/release-notes/");
- String regex = "href=#" + version
- // .......1.........................................................2.................
- + ".{8,12}(\r\n|\r|\n).{0,350}href=https://desktop\\.docker\\.com.*?(\\d{5,6}).*\\.exe";
- Pattern pattern = Pattern.compile(regex, Pattern.DOTALL);
- Matcher matcher = pattern.matcher(body);
+ String body = doGetResponseBodyAsString(DOCKER_RELEASE_NOTES_URL);
+ String regexForDockerVersion = format(REGEX_FOR_DOCKER_VERSION, version);
+ Pattern patternForDockerVersion = Pattern.compile(regexForDockerVersion, Pattern.DOTALL);
+ Matcher matcherForDockerVersion = patternForDockerVersion.matcher(body);
String code;
- if (matcher.find()) {
- code = matcher.group(2);
- boolean success = doAddVersion(urlVersion,
- "https://desktop.docker.com/win/main/amd64/" + code + "/Docker%20Desktop%20Installer.exe", WINDOWS);
- if (!success) {
- return;
- }
+ if (matcherForDockerVersion.find()) {
+ code = matcherForDockerVersion.group(1);
+ addVersionsForWindows(urlVersion, code, body);
if (!WINDOWS_ONLY_VERSIONS.stream().anyMatch(i -> vid.compareVersion(i).isEqual())) {
- doAddVersion(urlVersion, "https://desktop.docker.com/mac/main/amd64/" + code + "/Docker.dmg", MAC, X64);
- doAddVersion(urlVersion, "https://desktop.docker.com/mac/main/arm64/" + code + "/Docker.dmg", MAC, ARM64);
+ addVersionsForMac(urlVersion, code, body);
}
}
}
+ /**
+ * Adds the windows versions for docker if they exist
+ *
+ * @param urlVersion the readable version e.g. 4332 (4.33.2)
+ * @param dockerVersion the associated docker version to readable version e.g. 179689
+ * @param body the html body to search in
+ */
+ private void addVersionsForWindows(UrlVersion urlVersion, String dockerVersion, String body) {
+ boolean versionExists = checkIfVersionExists(dockerVersion, body, WIN_VERSION, AMD_ARCH_TYPE);
+ if (versionExists) {
+ doAddVersion(urlVersion, "https://desktop.docker.com/win/main/amd64/" + dockerVersion + "/Docker%20Desktop%20Installer.exe", WINDOWS, X64);
+ }
+ versionExists = checkIfVersionExists(dockerVersion, body, WIN_VERSION, ARM_ARCH_TYPE);
+ if (versionExists) {
+ doAddVersion(urlVersion, "https://desktop.docker.com/win/main/arm64/" + dockerVersion + "/Docker%20Desktop%20Installer.exe", WINDOWS, ARM64);
+ }
+ }
+
+ /**
+ * Adds the mac versions for docker if they exist
+ *
+ * @param urlVersion the readable version e.g. 4332 (4.33.2)
+ * @param dockerVersion the associated docker version to readable version e.g. 179689
+ * @param body the html body to search in
+ */
+ private void addVersionsForMac(UrlVersion urlVersion, String dockerVersion, String body) {
+ boolean versionExists = checkIfVersionExists(dockerVersion, body, MAC_VERSION, AMD_ARCH_TYPE);
+ if (versionExists) {
+ doAddVersion(urlVersion, "https://desktop.docker.com/mac/main/amd64/" + dockerVersion + "/Docker.dmg", MAC, X64);
+ }
+ versionExists = checkIfVersionExists(dockerVersion, body, MAC_VERSION, ARM_ARCH_TYPE);
+ if (versionExists) {
+ doAddVersion(urlVersion, "https://desktop.docker.com/mac/main/arm64/" + dockerVersion + "/Docker.dmg", MAC, ARM64);
+ }
+ }
+
+ /**
+ * As docker is very inconsistent by releasing versions we have to check every single one if the download link exists to prevent failing downloads
+ * (403-errors) E.g. for only amd64 windows download link provided- 4.24.1 E.g. for no
+ * download links provided - 4.24.2 E.g. for only mac download links provided - 4.36.1
+ *
+ * @param dockerVersion the associated docker version to readable version e.g. 179689 (4.33.2)
+ * @param body the html body to search in
+ * @param osVersion the os versions - win or mac
+ * @param archType the archType - amd64 or arm64
+ * @return true if the version exists - false if not
+ */
+ private boolean checkIfVersionExists(String dockerVersion, String body, String osVersion, String archType) {
+ String regexForDownloadUrlS = format(REGEX_FOR_DOWNLOAD_URLS, osVersion, archType, dockerVersion);
+ Pattern patternForDownloadUrls = Pattern.compile(regexForDownloadUrlS, Pattern.DOTALL);
+ Matcher matcherForDownloadUrls = patternForDownloadUrls.matcher(body);
+ return matcherForDownloadUrls.find();
+ }
+
@Override
protected String getVersionUrl() {
- return "https://docs.docker.com/desktop/release-notes/";
+ return DOCKER_RELEASE_NOTES_URL;
}
@Override
diff --git a/url-updater/src/test/java/com/devonfw/tools/ide/url/tool/UrlUpdaterMockSingle.java b/url-updater/src/test/java/com/devonfw/tools/ide/url/tool/UrlUpdaterMockSingle.java
index 3ca4b4407..e0697f668 100644
--- a/url-updater/src/test/java/com/devonfw/tools/ide/url/tool/UrlUpdaterMockSingle.java
+++ b/url-updater/src/test/java/com/devonfw/tools/ide/url/tool/UrlUpdaterMockSingle.java
@@ -13,7 +13,7 @@
*/
public class UrlUpdaterMockSingle extends UrlUpdaterMock {
- private static final Set versions = new HashSet<>(List.of("1.0"));
+ private static Set versions = new HashSet<>(List.of("1.0"));
/**
* The constructor
@@ -30,6 +30,15 @@ protected Set getVersions() {
return versions;
}
+ /**
+ * Enables the possibility to change the version which should be tested.
+ *
+ * @param newVersion the new Version to be set.
+ */
+ protected void setVersion(final String newVersion) {
+ versions = Set.of(newVersion);
+ }
+
@Override
protected void addVersion(UrlVersion urlVersion) {
doAddVersion(urlVersion, wmRuntimeInfo.getHttpBaseUrl() + "/os/windows_x64_url.tgz", WINDOWS, X64, "123");
diff --git a/url-updater/src/test/java/com/devonfw/tools/ide/url/tool/UrlUpdaterTest.java b/url-updater/src/test/java/com/devonfw/tools/ide/url/tool/UrlUpdaterTest.java
index e6abb0db0..9692fe5fd 100644
--- a/url-updater/src/test/java/com/devonfw/tools/ide/url/tool/UrlUpdaterTest.java
+++ b/url-updater/src/test/java/com/devonfw/tools/ide/url/tool/UrlUpdaterTest.java
@@ -280,4 +280,26 @@ public void testUrlUpdaterWithTextContentTypeWillNotCreateStatusJson(@TempDir Pa
}
+ /**
+ * Tests if the {@link com.devonfw.tools.ide.url.updater.UrlUpdater} will handle the literally latest version of a tool correctly
+ *
+ * @param tempDir Temporary directory
+ * @param wmRuntimeInfo wireMock server on a random port
+ */
+ @Test
+ public void testUrlUpdaterWithOnlyLatestVersion(@TempDir Path tempDir, WireMockRuntimeInfo wmRuntimeInfo) {
+ //given
+ stubFor(any(urlMatching("/os/.*")).willReturn(aResponse().withStatus(200).withBody("aBody")));
+ UrlRepository urlRepository = UrlRepository.load(tempDir);
+ UrlUpdaterMockSingle updater = new UrlUpdaterMockSingle(wmRuntimeInfo);
+ updater.setVersion("latest");
+
+ // when
+ updater.update(urlRepository);
+
+ // then
+ Path versionsPath = tempDir.resolve("mocked").resolve("mocked").resolve("latest");
+ assertThat(versionsPath.resolve("status.json")).exists();
+ }
+
}