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

devonfw / IDEasy / 19651727463

24 Nov 2025 10:43PM UTC coverage: 69.156% (+0.1%) from 69.024%
19651727463

push

github

web-flow
#1144: #1145: CVE warnings and suggestions (#1593)

Co-authored-by: KianRolf <kian.loroff@capgemini.com>
Co-authored-by: jan-vcapgemini <59438728+jan-vcapgemini@users.noreply.github.com>

3613 of 5721 branches covered (63.15%)

Branch coverage included in aggregate %.

9387 of 13077 relevant lines covered (71.78%)

3.15 hits per line

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

1.64
cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java
1
package com.devonfw.tools.ide.tool;
2

3
import java.nio.file.Files;
4
import java.nio.file.Path;
5
import java.util.Arrays;
6
import java.util.List;
7
import java.util.Set;
8

9
import com.devonfw.tools.ide.cli.CliException;
10
import com.devonfw.tools.ide.common.Tag;
11
import com.devonfw.tools.ide.context.IdeContext;
12
import com.devonfw.tools.ide.io.FileAccess;
13
import com.devonfw.tools.ide.process.ProcessContext;
14
import com.devonfw.tools.ide.process.ProcessErrorHandling;
15
import com.devonfw.tools.ide.process.ProcessMode;
16
import com.devonfw.tools.ide.step.Step;
17
import com.devonfw.tools.ide.tool.repository.ToolRepository;
18
import com.devonfw.tools.ide.version.VersionIdentifier;
19

20
/**
21
 * {@link ToolCommandlet} that is installed globally.
22
 */
23
public abstract class GlobalToolCommandlet extends ToolCommandlet {
24

25
  /**
26
   * The constructor.
27
   *
28
   * @param context the {@link IdeContext}.
29
   * @param tool the {@link #getName() tool name}.
30
   * @param tags the {@link #getTags() tags} classifying the tool. Should be created via {@link Set#of(Object) Set.of} method.
31
   */
32
  public GlobalToolCommandlet(IdeContext context, String tool, Set<Tag> tags) {
33

34
    super(context, tool, tags);
5✔
35
  }
1✔
36

37
  /**
38
   * Performs the installation or uninstallation of the {@link #getName() tool} via a package manager.
39
   *
40
   * @param silent {@code true} if called recursively to suppress verbose logging, {@code false} otherwise.
41
   * @param commandStrings commandStrings The package manager command strings to execute.
42
   * @return {@code true} if installation or uninstallation succeeds with any of the package manager commands, {@code false} otherwise.
43
   */
44
  protected boolean runWithPackageManager(boolean silent, String... commandStrings) {
45

46
    List<PackageManagerCommand> pmCommands = Arrays.stream(commandStrings).map(PackageManagerCommand::of).toList();
×
47
    return runWithPackageManager(silent, pmCommands);
×
48
  }
49

50
  /**
51
   * Performs the installation or uninstallation of the {@link #getName() tool} via a package manager.
52
   *
53
   * @param silent {@code true} if called recursively to suppress verbose logging, {@code false} otherwise.
54
   * @param pmCommands A list of {@link PackageManagerCommand} to be used for installation or uninstallation.
55
   * @return {@code true} if installation or uninstallation succeeds with any of the package manager commands, {@code false} otherwise.
56
   */
57
  protected boolean runWithPackageManager(boolean silent, List<PackageManagerCommand> pmCommands) {
58

59
    for (PackageManagerCommand pmCommand : pmCommands) {
×
60
      PackageManager packageManager = pmCommand.packageManager();
×
61
      Path packageManagerPath = this.context.getPath().findBinary(Path.of(packageManager.getBinaryName()));
×
62
      if (packageManagerPath == null || !Files.exists(packageManagerPath)) {
×
63
        this.context.debug("{} is not installed", packageManager.toString());
×
64
        continue; // Skip to the next package manager command
×
65
      }
66

67
      if (executePackageManagerCommand(pmCommand, silent)) {
×
68
        return true; // Success
×
69
      }
70
    }
×
71
    return false; // None of the package manager commands were successful
×
72
  }
73

74
  private void logPackageManagerCommands(PackageManagerCommand pmCommand) {
75

76
    this.context.interaction("We need to run the following privileged command(s):");
×
77
    for (String command : pmCommand.commands()) {
×
78
      this.context.interaction(command);
×
79
    }
×
80
    this.context.interaction("This will require root permissions!");
×
81
  }
×
82

83
  /**
84
   * Executes the provided package manager command.
85
   *
86
   * @param pmCommand The {@link PackageManagerCommand} containing the commands to execute.
87
   * @param silent {@code true} if called recursively to suppress verbose logging, {@code false} otherwise.
88
   * @return {@code true} if the package manager commands execute successfully, {@code false} otherwise.
89
   */
90
  private boolean executePackageManagerCommand(PackageManagerCommand pmCommand, boolean silent) {
91

92
    String bashPath = this.context.findBashRequired().toString();
×
93
    logPackageManagerCommands(pmCommand);
×
94
    for (String command : pmCommand.commands()) {
×
95
      ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.LOG_WARNING).executable(bashPath)
×
96
          .addArgs("-c", command);
×
97
      int exitCode = pc.run();
×
98
      if (exitCode != 0) {
×
99
        this.context.warning("{} command did not execute successfully", command);
×
100
        return false;
×
101
      }
102
    }
×
103

104
    if (!silent) {
×
105
      this.context.success("Successfully installed {}", this.tool);
×
106
    }
107
    return true;
×
108
  }
109

110
  @Override
111
  protected boolean isExtract() {
112

113
    // for global tools we usually download installers and do not want to extract them (e.g. installer.msi file shall
114
    // not be extracted)
115
    return false;
×
116
  }
117

118
  @Override
119
  public ToolInstallation install(boolean silent, VersionIdentifier configuredVersion, ProcessContext processContext, Step step) {
120

121
    if (this.context.getSystemInfo().isLinux()) {
×
122
      // on Linux global tools are typically installed via the package manager of the OS
123
      // if a global tool implements this method to return at least one PackageManagerCommand, then we install this way.
124
      List<PackageManagerCommand> commands = getInstallPackageManagerCommands();
×
125
      if (!commands.isEmpty()) {
×
126
        boolean newInstallation = runWithPackageManager(silent, commands);
×
127
        Path rootDir = getInstallationPath(getConfiguredEdition(), configuredVersion);
×
128
        return createToolInstallation(rootDir, configuredVersion, newInstallation, processContext, false);
×
129
      }
130
    }
131

132
    ToolEdition toolEdition = getToolWithEdition();
×
133
    Path installationPath = getInstallationPath(toolEdition.edition(), configuredVersion);
×
134
    // if force mode is enabled, go through with the installation even if the tool is already installed
135
    if ((installationPath != null) && !this.context.isForceMode()) {
×
136
      return toolAlreadyInstalled(silent, toolEdition, configuredVersion, processContext, false);
×
137
    }
138
    String edition = toolEdition.edition();
×
139
    ToolRepository toolRepository = this.context.getDefaultToolRepository();
×
140
    VersionIdentifier resolvedVersion = toolRepository.resolveVersion(this.tool, edition, configuredVersion, this);
×
141
    resolvedVersion = cveCheck(toolEdition, resolvedVersion, null, false);
×
142
    // download and install the global tool
143
    FileAccess fileAccess = this.context.getFileAccess();
×
144
    Path target = toolRepository.download(this.tool, edition, resolvedVersion, this);
×
145
    Path executable = target;
×
146
    Path tmpDir = null;
×
147
    boolean extract = isExtract();
×
148
    if (extract) {
×
149
      tmpDir = fileAccess.createTempDir(getName());
×
150
      Path downloadBinaryPath = tmpDir.resolve(target.getFileName());
×
151
      fileAccess.extract(target, downloadBinaryPath);
×
152
      executable = fileAccess.findFirst(downloadBinaryPath, Files::isExecutable, false);
×
153
    }
154
    ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.LOG_WARNING).executable(executable);
×
155
    int exitCode = pc.run(ProcessMode.BACKGROUND).getExitCode();
×
156
    if (tmpDir != null) {
×
157
      fileAccess.delete(tmpDir);
×
158
    }
159
    if (exitCode == 0) {
×
160
      asSuccess(step).log("Installation process for {} in version {} has started", this.tool, resolvedVersion);
×
161
    } else {
162
      throw new CliException("Installation process for " + this.tool + " in version " + resolvedVersion + " failed with exit code " + exitCode + "!");
×
163
    }
164
    installationPath = getInstallationPath(toolEdition.edition(), configuredVersion);
×
165
    if (installationPath == null) {
×
166
      this.context.warning("Could not find binary {} on PATH after installation.", getBinaryName());
×
167
    }
168
    return createToolInstallation(installationPath, resolvedVersion, true, pc, false);
×
169
  }
170

171
  /**
172
   * @return the {@link List} of {@link PackageManagerCommand}s to use on Linux to install this tool. If empty, no package manager installation will be
173
   *     triggered on Linux.
174
   */
175
  protected List<PackageManagerCommand> getInstallPackageManagerCommands() {
176
    return List.of();
×
177
  }
178

179
  @Override
180
  public VersionIdentifier getInstalledVersion() {
181
    //TODO: handle "get-version <globaltool>"
182
    this.context.error("Couldn't get installed version of " + this.getName());
×
183
    return null;
×
184
  }
185

186
  @Override
187
  public String getInstalledEdition() {
188
    //TODO: handle "get-edition <globaltool>"
189
    this.context.error("Couldn't get installed edition of " + this.getName());
×
190
    return null;
×
191
  }
192

193
  @Override
194
  protected Path getInstallationPath(String edition, VersionIdentifier resolvedVersion) {
195

196
    Path toolBinary = Path.of(getBinaryName());
×
197
    Path binaryPath = this.context.getPath().findBinary(toolBinary);
×
198
    if ((binaryPath == toolBinary) || !Files.exists(binaryPath)) {
×
199
      return null;
×
200
    }
201
    Path binPath = binaryPath.getParent();
×
202
    if (binPath == null) {
×
203
      return null;
×
204
    }
205
    return this.context.getFileAccess().getBinParentPath(binPath);
×
206
  }
207

208
  @Override
209
  public void uninstall() {
210
    //TODO: handle "uninstall <globaltool>"
211
    this.context.error("Couldn't uninstall " + this.getName());
×
212
  }
×
213
}
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