Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#692 : UrlUpdater fetches every defined version for Docker and latest version is now accepted as well #1117

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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() {

Expand All @@ -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- <a href="https://docs.docker.com/desktop/release-notes/#4241">4.24.1</a> E.g. for no
* download links provided - <a href="https://docs.docker.com/desktop/release-notes/#4242">4.24.2</a> E.g. for only mac download links provided - <a
* href="https://docs.docker.com/desktop/release-notes/#4361">4.36.1</a>
*
* @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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*/
public class UrlUpdaterMockSingle extends UrlUpdaterMock {

private static final Set<String> versions = new HashSet<>(List.of("1.0"));
private static Set<String> versions = new HashSet<>(List.of("1.0"));

/**
* The constructor
Expand All @@ -30,6 +30,15 @@ protected Set<String> 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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

}