Skip to content
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
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
82 changes: 78 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,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;
Expand All @@ -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.
*
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,68 @@ 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 dockerDesktopVersionWindowsCommand = "reg query \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Docker Desktop\" /v DisplayVersion";

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

Expand Down
19 changes: 19 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,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<String> outputs = this.context.newProcess().runAndGetOutput(this.tool, "version", "--client");
String singleLineOutput = String.join("\n", outputs);

return super.resolveVersionWithPattern(singleLineOutput, KUBECTL_VERSION_PATTERN);

}

}