Skip to content
2 changes: 2 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
25 changes: 25 additions & 0 deletions cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down
83 changes: 79 additions & 4 deletions cli/src/main/java/com/devonfw/tools/ide/tool/docker/Docker.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
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;
import com.devonfw.tools.ide.os.SystemArchitecture;
import com.devonfw.tools.ide.os.WindowsHelper;
import com.devonfw.tools.ide.os.WindowsHelperImpl;
import com.devonfw.tools.ide.tool.GlobalToolCommandlet;
import com.devonfw.tools.ide.tool.NativePackageManager;
import com.devonfw.tools.ide.tool.PackageManagerCommand;
Expand All @@ -23,6 +26,11 @@ 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_LINUX_VERSION_PATTERN = Pattern.compile("^([0-9]+(?:\\.[0-9]+){1,2})");

/**
* The constructor.
*
Expand All @@ -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;
Expand All @@ -48,10 +64,6 @@ private String detectContainerRuntime() {
}
}

private boolean isCommandAvailable(String command) {
return this.context.getPath().hasBinaryOnPath(command);
}

@Override
public boolean isExtract() {

Expand Down Expand Up @@ -82,6 +94,69 @@ protected List<PackageManagerCommand> 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 registryPath = "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Docker Desktop";

WindowsHelper windowsHelper = ((com.devonfw.tools.ide.context.AbstractIdeContext) this.context).getWindowsHelper();
String version = windowsHelper.getRegistryValue(registryPath, "DisplayVersion");

return VersionIdentifier.of(version);
}

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() {

Expand Down
17 changes: 17 additions & 0 deletions cli/src/main/java/com/devonfw/tools/ide/tool/kubectl/KubeCtl.java
Original file line number Diff line number Diff line change
@@ -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 <a href="https://kubernetes.io/de/docs/tasks/tools/install-kubectl/">Kubectl</a>.
*/
public class KubeCtl extends DelegatingToolCommandlet {

private static final Pattern KUBECTL_VERSION_PATTERN = Pattern.compile("Client Version: \\s*v([\\d.]+)");

/**
* The constructor.
Expand All @@ -22,4 +26,17 @@ 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<String> outputs = this.context.newProcess().runAndGetOutput(this.tool, "version", "--client");
String singleLineOutput = String.join("\n", outputs);
return resolveVersionWithPattern(singleLineOutput, KUBECTL_VERSION_PATTERN);
}

}
Loading