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

devonfw / IDEasy / 15217656699

23 May 2025 07:22PM UTC coverage: 67.562% (-0.3%) from 67.89%
15217656699

push

github

web-flow
#1332: fixed bug pattern, proper Step usage, allow running tool if plugin failed (#1334)

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

3151 of 5064 branches covered (62.22%)

Branch coverage included in aggregate %.

8048 of 11512 relevant lines covered (69.91%)

3.07 hits per line

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

2.06
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.log.IdeLogLevel;
14
import com.devonfw.tools.ide.process.ProcessContext;
15
import com.devonfw.tools.ide.process.ProcessErrorHandling;
16
import com.devonfw.tools.ide.process.ProcessMode;
17
import com.devonfw.tools.ide.step.Step;
18
import com.devonfw.tools.ide.tool.repository.ToolRepository;
19
import com.devonfw.tools.ide.version.VersionIdentifier;
20

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

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

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

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

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

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

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

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

75
  private void logPackageManagerCommands(PackageManagerCommand pmCommand) {
76

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

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

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

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

111
  @Override
112
  protected boolean isExtract() {
113

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

119
  @Override
120
  public boolean install(boolean silent, ProcessContext processContext, Step step) {
121

122
    Path binaryPath = this.context.getPath().findBinary(Path.of(getBinaryName()));
×
123
    // if force mode is enabled, go through with the installation even if the tool is already installed
124
    if (binaryPath != null && Files.exists(binaryPath) && !this.context.isForceMode()) {
×
125
      IdeLogLevel level = silent ? IdeLogLevel.DEBUG : IdeLogLevel.INFO;
×
126
      this.context.level(level).log("{} is already installed at {}", this.tool, binaryPath);
×
127
      return false;
×
128
    }
129
    String edition = getConfiguredEdition();
×
130
    ToolRepository toolRepository = this.context.getDefaultToolRepository();
×
131
    VersionIdentifier configuredVersion = getConfiguredVersion();
×
132
    VersionIdentifier resolvedVersion = toolRepository.resolveVersion(this.tool, edition, configuredVersion, this);
×
133
    // download and install the global tool
134
    FileAccess fileAccess = this.context.getFileAccess();
×
135
    Path target = toolRepository.download(this.tool, edition, resolvedVersion, this);
×
136
    Path executable = target;
×
137
    Path tmpDir = null;
×
138
    boolean extract = isExtract();
×
139
    if (extract) {
×
140
      tmpDir = fileAccess.createTempDir(getName());
×
141
      Path downloadBinaryPath = tmpDir.resolve(target.getFileName());
×
142
      fileAccess.extract(target, downloadBinaryPath);
×
143
      executable = fileAccess.findFirst(downloadBinaryPath, Files::isExecutable, false);
×
144
    }
145
    ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.LOG_WARNING).executable(executable);
×
146
    int exitCode = pc.run(ProcessMode.BACKGROUND).getExitCode();
×
147
    if (tmpDir != null) {
×
148
      fileAccess.delete(tmpDir);
×
149
    }
150
    if (exitCode == 0) {
×
151
      asSuccess(step).log("Installation process for {} in version {} has started", this.tool, resolvedVersion);
×
152
    } else {
153
      throw new CliException("Installation process for " + this.tool + " in version " + resolvedVersion + " failed with exit code " + exitCode + "!");
×
154
    }
155
    return true;
×
156
  }
157

158
  @Override
159
  public VersionIdentifier getInstalledVersion() {
160
    //TODO: handle "get-version <globaltool>"
161
    this.context.error("Couldn't get installed version of " + this.getName());
×
162
    return null;
×
163
  }
164

165
  @Override
166
  public String getInstalledEdition() {
167
    //TODO: handle "get-edition <globaltool>"
168
    this.context.error("Couldn't get installed edition of " + this.getName());
×
169
    return null;
×
170
  }
171

172
  @Override
173
  public void uninstall() {
174
    //TODO: handle "uninstall <globaltool>"
175
    this.context.error("Couldn't uninstall " + this.getName());
×
176
  }
×
177
}
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