• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

devonfw / IDEasy / 29005438306

09 Jul 2026 08:38AM UTC coverage: 72.104% (-0.08%) from 72.18%
29005438306

Pull #2085

github

web-flow
Merge 334faba15 into 8ed88cfeb
Pull Request #2085: #854: Fix Rancher Desktop path

4879 of 7474 branches covered (65.28%)

Branch coverage included in aggregate %.

12571 of 16727 relevant lines covered (75.15%)

3.18 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

4.63
cli/src/main/java/com/devonfw/tools/ide/tool/docker/Docker.java
1
package com.devonfw.tools.ide.tool.docker;
2

3
import java.nio.file.Files;
4
import java.nio.file.Path;
5
import java.util.ArrayList;
6
import java.util.List;
7
import java.util.Set;
8
import java.util.regex.Pattern;
9

10
import org.slf4j.Logger;
11
import org.slf4j.LoggerFactory;
12

13
import com.devonfw.tools.ide.cli.CliException;
14
import com.devonfw.tools.ide.common.Tag;
15
import com.devonfw.tools.ide.context.IdeContext;
16
import com.devonfw.tools.ide.os.SystemArchitecture;
17
import com.devonfw.tools.ide.os.WindowsHelper;
18
import com.devonfw.tools.ide.tool.GlobalToolCommandlet;
19
import com.devonfw.tools.ide.tool.NativePackageManager;
20
import com.devonfw.tools.ide.tool.PackageManagerCommand;
21
import com.devonfw.tools.ide.tool.ToolInstallRequest;
22
import com.devonfw.tools.ide.tool.ToolInstallation;
23
import com.devonfw.tools.ide.tool.repository.ToolRepository;
24
import com.devonfw.tools.ide.version.VersionIdentifier;
25

26
/**
27
 * {@link GlobalToolCommandlet} for <a href="https://www.docker.com/">docker</a> either as
28
 * <a href="https://rancherdesktop.io/">Rancher Desktop</a> or as
29
 * <a href="https://www.docker.com/products/docker-desktop/">Docker Desktop</a>.
30
 */
31
public class Docker extends GlobalToolCommandlet {
32

33
  private static final Logger LOG = LoggerFactory.getLogger(Docker.class);
3✔
34

35
  private static final String PODMAN = "podman";
36

37
  private static final Pattern RDCTL_CLIENT_VERSION_PATTERN = Pattern.compile("client version:\\s*v?([\\d.]+)", Pattern.CASE_INSENSITIVE);
4✔
38

39
  private static final Pattern DOCKER_DESKTOP_LINUX_VERSION_PATTERN = Pattern.compile("^([0-9]+(?:\\.[0-9]+){1,2})");
4✔
40

41
  /**
42
   * The constructor.
43
   *
44
   * @param context the {@link IdeContext}.
45
   */
46
  public Docker(IdeContext context) {
47

48
    super(context, "docker", Set.of(Tag.DOCKER));
6✔
49
  }
1✔
50

51
  @Override
52
  public String getBinaryName() {
53
    return detectContainerRuntime();
×
54
  }
55

56
  private boolean isDockerInstalled() {
57
    return resolveRancherDesktopCommand("docker") != null;
×
58
  }
59

60
  private boolean isRancherDesktopInstalled() {
61
    return resolveRancherDesktopCommand("rdctl") != null;
×
62
  }
63

64
  private String detectContainerRuntime() {
65
    String docker = resolveRancherDesktopCommand(this.tool);
×
66
    if (docker != null) {
×
67
      return docker;
×
68
    } else if (isCommandAvailable(PODMAN)) {
×
69
      return PODMAN;
×
70
    } else {
71
      return this.tool;
×
72
    }
73
  }
74

75
  /**
76
   * Rancher Desktop links its CLI tools (docker, kubectl, rdctl) into the fixed {@code ~/.rd/bin} directory, which it creates on its first launch.
77
   * Depending on the user's path management strategy this directory may not be on the PATH, so we look it up there explicitly as a fallback.
78
   *
79
   * @param command the name of the Rancher Desktop CLI to resolve.
80
   * @return the {@code command} unchanged if available on PATH, otherwise its absolute path inside {@code ~/.rd/bin} or {@code null} if not found.
81
   */
82
  private String resolveRancherDesktopCommand(String command) {
83
    if (isCommandAvailable(command)) {
×
84
      return command;
×
85
    }
86
    Path rancherDesktopBinary = getRancherDesktopBinDir().resolve(command);
×
87
    if (Files.exists(rancherDesktopBinary)) {
×
88
      return rancherDesktopBinary.toString();
×
89
    }
90
    return null;
×
91
  }
92

93
  private Path getRancherDesktopBinDir() {
94
    return this.context.getUserHome().resolve(".rd").resolve("bin");
×
95
  }
96

97
  @Override
98
  public boolean isExtract() {
99

100
    return switch (this.context.getSystemInfo().getOs()) {
×
101
      case WINDOWS -> false;
×
102
      case MAC -> this.context.getSystemInfo().getArchitecture().equals(SystemArchitecture.ARM64);
×
103
      case LINUX -> true;
×
104
    };
105
  }
106

107
  @Override
108
  protected ToolInstallation doInstall(ToolInstallRequest request) {
109

110
    ToolInstallation installation = super.doInstall(request);
×
111
    if (this.context.getSystemInfo().isLinux() && !Files.isDirectory(getRancherDesktopBinDir())) {
×
112
      throw new CliException("Rancher Desktop has been installed but not launched yet. Please start Rancher Desktop once so that it sets up its "
×
113
          + "command-line tools (docker, kubectl, ...) in ~/.rd/bin, then re-run your command.", 2);
114
    }
115
    return installation;
×
116
  }
117

118
  @Override
119
  protected List<PackageManagerCommand> getInstallPackageManagerCommands() {
120

121
    String edition = getConfiguredEdition();
×
122
    ToolRepository toolRepository = getToolRepository();
×
123
    VersionIdentifier configuredVersion = getConfiguredVersion();
×
124
    String resolvedVersion = toolRepository.resolveVersion(this.tool, edition, configuredVersion, this).toString();
×
125

126
    return List.of(new PackageManagerCommand(NativePackageManager.ZYPPER, List.of(
×
127
            "sudo zypper addrepo https://download.opensuse.org/repositories/isv:/Rancher:/stable/rpm/isv:Rancher:stable.repo",
128
            String.format("sudo zypper --no-gpg-checks install rancher-desktop=%s*", resolvedVersion))),
×
129
        new PackageManagerCommand(NativePackageManager.APT, List.of(
×
130
            "curl -s https://download.opensuse.org/repositories/isv:/Rancher:/stable/deb/Release.key | gpg --dearmor |"
131
                + " sudo dd status=none of=/usr/share/keyrings/isv-rancher-stable-archive-keyring.gpg",
132
            "echo 'deb [signed-by=/usr/share/keyrings/isv-rancher-stable-archive-keyring.gpg]"
133
                + " https://download.opensuse.org/repositories/isv:/Rancher:/stable/deb/ ./' |"
134
                + " sudo dd status=none of=/etc/apt/sources.list.d/isv-rancher-stable.list", "sudo apt update",
135
            String.format("sudo apt install -y --allow-downgrades rancher-desktop=%s*", resolvedVersion))));
×
136
  }
137

138
  @Override
139
  public VersionIdentifier getInstalledVersion() {
140

141
    if (!isDockerInstalled()) {
×
142
      return null;
×
143
    }
144

145
    if (isRancherDesktopInstalled()) {
×
146
      return getRancherDesktopClientVersion();
×
147
    } else {
148
      VersionIdentifier parsedVersion = switch (this.context.getSystemInfo().getOs()) {
×
149
        case WINDOWS -> getDockerDesktopVersionWindows();
×
150
        case LINUX -> getDockerDesktopVersionLinux();
×
151
        default -> null;
×
152
      };
153

154
      if (parsedVersion == null) {
×
155
        LOG.error("Couldn't get installed version of " + this.getName());
×
156
      }
157

158
      return parsedVersion;
×
159
    }
160
  }
161

162
  private VersionIdentifier getDockerDesktopVersionWindows() {
163

164
    String registryPath = "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Docker Desktop";
×
165

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

169
    return VersionIdentifier.of(version);
×
170
  }
171

172
  private VersionIdentifier getDockerDesktopVersionLinux() {
173

174
    String dockerDesktopVersionLinuxCommand = "apt list --installed | grep docker-desktop | awk '{print $2}'";
×
175
    String output = this.context.newProcess().runAndGetSingleOutput("bash", "-lc", dockerDesktopVersionLinuxCommand);
×
176
    return super.resolveVersionWithPattern(output, DOCKER_DESKTOP_LINUX_VERSION_PATTERN);
×
177
  }
178

179
  private VersionIdentifier getRancherDesktopClientVersion() {
180

181
    String rdctl = resolveRancherDesktopCommand("rdctl");
×
182
    String output = this.context.newProcess().runAndGetSingleOutput(rdctl, "version");
×
183
    return super.resolveVersionWithPattern(output, RDCTL_CLIENT_VERSION_PATTERN);
×
184
  }
185

186
  @Override
187
  public String getInstalledEdition() {
188

189
    if (!isDockerInstalled()) {
×
190
      return null;
×
191
    }
192

193
    if (isRancherDesktopInstalled()) {
×
194
      return "rancher";
×
195
    } else {
196
      return "desktop";
×
197
    }
198
  }
199

200
  @Override
201
  public void uninstall() {
202

203
    if (this.context.getSystemInfo().isLinux()) {
×
204
      runWithPackageManager(false, getPackageManagerCommandsUninstall());
×
205
    } else {
206
      super.uninstall();
×
207
    }
208

209
  }
×
210

211
  private List<PackageManagerCommand> getPackageManagerCommandsUninstall() {
212

213
    List<PackageManagerCommand> pmCommands = new ArrayList<>();
×
214
    pmCommands.add(
×
215
        new PackageManagerCommand(NativePackageManager.ZYPPER, List.of("sudo zypper remove rancher-desktop")));
×
216
    pmCommands.add(
×
217
        new PackageManagerCommand(NativePackageManager.APT, List.of("sudo apt -y autoremove rancher-desktop")));
×
218

219
    return pmCommands;
×
220
  }
221

222
  @Override
223
  public String getToolHelpArguments() {
224

225
    return "help";
×
226
  }
227
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc