diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index b60f424883..78ef67e4ba 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -6,6 +6,8 @@ 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/1653[#1653]: Implementation of getEdition and getVersion for Docker + The full list of changes for this release can be found in https://github.com/devonfw/IDEasy/milestone/39?closed=1[milestone 2026.01.001]. == 2025.12.001 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 fc1455fd11..203a7c98fa 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 @@ -7,6 +7,8 @@ import java.util.List; import java.util.Objects; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import com.devonfw.tools.ide.commandlet.Commandlet; import com.devonfw.tools.ide.common.Tag; @@ -939,6 +941,29 @@ public void reset() { this.executionDirectory = null; } + /** + * @param command the binary that will be searched in the PATH e.g. docker + * @return true if the command is available to use + */ + protected boolean isCommandAvailable(String command) { + return this.context.getPath().hasBinaryOnPath(command); + } + + /** + * @param output the raw output string from executed command e.g. 'docker version' + * @param pattern Regular Expression pattern that filters out the unnecessary texts. + * @return version that has been processed. + */ + protected VersionIdentifier resolveVersionWithPattern(String output, Pattern pattern) { + Matcher matcher = pattern.matcher(output); + + if (matcher.find()) { + return VersionIdentifier.of(matcher.group(1)); + } else { + return null; + } + } + /** * @param step the {@link Step} to get {@link Step#asSuccess() success logger} from. May be {@code null}. * @return the {@link IdeSubLogger} from {@link Step#asSuccess()} or {@link IdeContext#success()} as fallback. diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/docker/Docker.java b/cli/src/main/java/com/devonfw/tools/ide/tool/docker/Docker.java index 9a57adf4c4..b3ff1063f6 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/docker/Docker.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/docker/Docker.java @@ -4,6 +4,7 @@ import java.util.Arrays; import java.util.List; import java.util.Set; +import java.util.regex.Pattern; import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; @@ -23,6 +24,13 @@ public class Docker extends GlobalToolCommandlet { private static final String PODMAN = "podman"; + + private static final Pattern RDCTL_CLIENT_VERSION_PATTERN = Pattern.compile("client version:\\s*v([\\d.]+)", Pattern.CASE_INSENSITIVE); + + private static final Pattern DOCKER_DESKTOP_WINDOWS_VERSION_PATTERN = Pattern.compile("DisplayVersion\\s+REG_SZ\\s+([0-9]+(?:\\.[0-9]+){2})"); + + private static final Pattern DOCKER_DESKTOP_LINUX_VERSION_PATTERN = Pattern.compile("^([0-9]+(?:\\.[0-9]+){1,2})"); + /** * The constructor. * @@ -38,6 +46,14 @@ public String getBinaryName() { return detectContainerRuntime(); } + private boolean isDockerInstalled() { + return isCommandAvailable("docker"); + } + + private boolean isRancherDesktopInstalled() { + return isCommandAvailable("rdctl"); + } + private String detectContainerRuntime() { if (isCommandAvailable(this.tool)) { return this.tool; @@ -48,10 +64,6 @@ private String detectContainerRuntime() { } } - private boolean isCommandAvailable(String command) { - return this.context.getPath().hasBinaryOnPath(command); - } - @Override public boolean isExtract() { @@ -82,6 +94,68 @@ protected List getInstallPackageManagerCommands() { String.format("sudo apt install -y --allow-downgrades rancher-desktop=%s*", resolvedVersion)))); } + @Override + public VersionIdentifier getInstalledVersion() { + + if (!isDockerInstalled()) { + this.context.error("Couldn't get installed version of " + this.getName()); + return null; + } + + if (isRancherDesktopInstalled()) { + return getRancherDesktopClientVersion(); + } else { + VersionIdentifier parsedVersion = switch (this.context.getSystemInfo().getOs()) { + case WINDOWS -> getDockerDesktopVersionWindows(); + case LINUX -> getDockerDesktopVersionLinux(); + default -> null; + }; + + if (parsedVersion == null) { + this.context.error("Couldn't get installed version of " + this.getName()); + } + + return parsedVersion; + } + } + + private VersionIdentifier getDockerDesktopVersionWindows() { + + String dockerDesktopVersionWindowsCommand = "reg query \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Docker Desktop\" /v DisplayVersion"; + + List outputs = this.context.newProcess().runAndGetOutput("cmd.exe", "/c", dockerDesktopVersionWindowsCommand); + String singleLineOutput = String.join(" ", outputs); + return super.resolveVersionWithPattern(singleLineOutput, DOCKER_DESKTOP_WINDOWS_VERSION_PATTERN); + } + + private VersionIdentifier getDockerDesktopVersionLinux() { + + String dockerDesktopVersionLinuxCommand = "apt list --installed | grep docker-desktop | awk '{print $2}'"; + String output = this.context.newProcess().runAndGetSingleOutput("bash", "-lc", dockerDesktopVersionLinuxCommand); + return super.resolveVersionWithPattern(output, DOCKER_DESKTOP_LINUX_VERSION_PATTERN); + } + + private VersionIdentifier getRancherDesktopClientVersion() { + + String output = this.context.newProcess().runAndGetSingleOutput("rdctl", "version"); + return super.resolveVersionWithPattern(output, RDCTL_CLIENT_VERSION_PATTERN); + } + + @Override + public String getInstalledEdition() { + + if (!isDockerInstalled()) { + this.context.error("Couldn't get installed edition of " + this.getName()); + return null; + } + + if (isRancherDesktopInstalled()) { + return "rancher"; + } else { + return "desktop"; + } + } + @Override public void uninstall() { diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/kubectl/KubeCtl.java b/cli/src/main/java/com/devonfw/tools/ide/tool/kubectl/KubeCtl.java index c976413ee6..d3cd0c25b2 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/kubectl/KubeCtl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/kubectl/KubeCtl.java @@ -1,17 +1,21 @@ package com.devonfw.tools.ide.tool.kubectl; +import java.util.List; import java.util.Set; +import java.util.regex.Pattern; import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.tool.DelegatingToolCommandlet; import com.devonfw.tools.ide.tool.docker.Docker; +import com.devonfw.tools.ide.version.VersionIdentifier; /** * {@link DelegatingToolCommandlet} for Kubectl. */ public class KubeCtl extends DelegatingToolCommandlet { + private static final Pattern KUBECTL_VERSION_PATTERN = Pattern.compile("Client Version: \\s*v([\\d.]+)"); /** * The constructor. @@ -22,4 +26,19 @@ public KubeCtl(IdeContext context) { super(context, "kubectl", Set.of(Tag.KUBERNETES), Docker.class); } + + @Override + public VersionIdentifier getInstalledVersion() { + + if (!isCommandAvailable(this.tool)) { + return super.getInstalledVersion(); + } + + List outputs = this.context.newProcess().runAndGetOutput(this.tool, "version", "--client"); + String singleLineOutput = String.join("\n", outputs); + + return super.resolveVersionWithPattern(singleLineOutput, KUBECTL_VERSION_PATTERN); + + } + }