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

devonfw / IDEasy / 22315552991

23 Feb 2026 04:40PM UTC coverage: 70.563% (+0.09%) from 70.474%
22315552991

Pull #1714

github

web-flow
Merge 7d88da975 into 379acdc9d
Pull Request #1714: #404: #1713: advanced logging

4081 of 6382 branches covered (63.95%)

Branch coverage included in aggregate %.

10644 of 14486 relevant lines covered (73.48%)

3.09 hits per line

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

70.97
cli/src/main/java/com/devonfw/tools/ide/tool/ToolInstallRequest.java
1
package com.devonfw.tools.ide.tool;
2

3
import java.nio.file.Path;
4

5
import org.slf4j.Logger;
6
import org.slf4j.LoggerFactory;
7

8
import com.devonfw.tools.ide.process.ProcessContext;
9
import com.devonfw.tools.ide.step.Step;
10
import com.devonfw.tools.ide.version.GenericVersionRange;
11
import com.devonfw.tools.ide.version.VersionIdentifier;
12
import com.devonfw.tools.ide.version.VersionRange;
13

14
/**
15
 * Container for data related to a tool installation.
16
 */
17
public final class ToolInstallRequest {
18

19
  private static final Logger LOG = LoggerFactory.getLogger(ToolInstallRequest.class);
4✔
20

21
  private final ToolInstallRequest parent;
22

23
  private final boolean silent;
24

25
  private final boolean direct;
26

27
  private boolean cveCheckDone;
28

29
  private ToolEditionAndVersion requested;
30

31
  private ToolEditionAndVersion installed;
32

33
  private ProcessContext processContext;
34

35
  private Path toolPath;
36

37
  private boolean extraInstallation;
38

39
  private Step step;
40

41
  /**
42
   * The constructor.
43
   *
44
   * @param silent the {@link #isSilent() silent} flag.
45
   */
46
  public ToolInstallRequest(boolean silent) {
47
    this(null, silent, false);
5✔
48
  }
1✔
49

50
  /**
51
   * The constructor.
52
   *
53
   * @param parent the parent {@link ToolInstallRequest} (in case of a dependency).
54
   */
55
  public ToolInstallRequest(ToolInstallRequest parent) {
56
    this(parent, parent.silent, false);
6✔
57
  }
1✔
58

59
  /**
60
   * The constructor.
61
   *
62
   * @param silent the {@link #isSilent() silent} flag.
63
   * @param direct the {@link #isDirect() direct} flag.
64
   */
65
  private ToolInstallRequest(ToolInstallRequest parent, boolean silent, boolean direct) {
66
    super();
2✔
67
    this.parent = parent;
3✔
68
    this.silent = silent;
3✔
69
    this.direct = direct;
3✔
70
    if (parent != null) {
2✔
71
      this.processContext = parent.processContext;
4✔
72
    }
73
  }
1✔
74

75
  /**
76
   * @return {@code true} if an installation loop was found and logged, {@code false} otherwise.
77
   */
78
  public boolean isInstallLoop() {
79

80
    if ((this.requested == null) || (this.requested.getEdition() == null)) {
7!
81
      throw new IllegalStateException(); // this method was called too early
×
82
    }
83
    StringBuilder sb = new StringBuilder();
4✔
84
    boolean loopFound = detectInstallLoopRecursively(this.requested, sb);
6✔
85
    if (loopFound) {
2!
86
      LOG.warn("Found installation loop:\n"
×
87
              + "{}\n"
88
              + "This typically indicates an internal bug in IDEasy.\n"
89
              + "Please report this bug, when you see this and include this entire warning message.\n"
90
              + "We are now trying to prevent an infinity loop and abort the recursive installation.",
91
          sb);
92
    }
93
    return loopFound;
2✔
94
  }
95

96
  private boolean detectInstallLoopRecursively(ToolEditionAndVersion toolEditionAndVersion, StringBuilder sb) {
97

98
    if (this.requested != toolEditionAndVersion) {
4✔
99
      if (this.requested.getEdition().equals(toolEditionAndVersion.getEdition())) {
7!
100
        if (this.requested.getResolvedVersion().equals(toolEditionAndVersion.getResolvedVersion())) {
×
101
          sb.append(this.requested);
×
102
          return true;
×
103
        }
104
      }
105
    }
106
    if (this.parent == null) {
3✔
107
      return false;
2✔
108
    }
109
    boolean loopFound = this.parent.detectInstallLoopRecursively(toolEditionAndVersion, sb);
6✔
110
    if (loopFound && (sb != null)) {
2!
111
      sb.append("-->");
×
112
      sb.append(this.requested);
×
113
    }
114
    return loopFound;
2✔
115
  }
116

117
  /**
118
   * @return {@code true} if this installation should be silent and log information like "tool already installed" only on debug level to avoid spam,
119
   *     {@code false} otherwise. A {@link #isDirect() direct} installation should never be silent.
120
   */
121
  public boolean isSilent() {
122

123
    return this.silent;
3✔
124
  }
125

126
  /**
127
   * @return {@code true} if the user directly triggered this tool installation (via "ide install tool"), {@code false} otherwise (indirect installation e.g. as
128
   *     dependency or via "ide create" or "ide update").
129
   */
130
  public boolean isDirect() {
131

132
    return this.direct;
×
133
  }
134

135
  /**
136
   * @return {@code true} if CVEs have already been checked, {@code false} otherwise.
137
   */
138
  public boolean isCveCheckDone() {
139

140
    return this.cveCheckDone;
3✔
141
  }
142

143
  void setCveCheckDone() {
144

145
    assert !this.cveCheckDone;
4!
146
    this.cveCheckDone = true;
3✔
147
  }
1✔
148

149
  /**
150
   * @return the {@link ToolEditionAndVersion} that is requested to be installed.
151
   */
152
  public ToolEditionAndVersion getRequested() {
153

154
    return this.requested;
3✔
155
  }
156

157
  /**
158
   * @param requested new value of {@link #getRequested()}.
159
   */
160
  public void setRequested(ToolEditionAndVersion requested) {
161
    if (this.requested != null) {
3!
162
      throw new IllegalStateException();
×
163
    }
164
    this.requested = requested;
3✔
165
  }
1✔
166

167
  /**
168
   * @return the {@link ToolEditionAndVersion} that is currently installed or {@code null} if the tool is not installed yet.
169
   */
170
  public ToolEditionAndVersion getInstalled() {
171

172
    return this.installed;
3✔
173
  }
174

175
  /**
176
   * @param installed new value of {@link #getInstalled()}.
177
   */
178
  public void setInstalled(ToolEditionAndVersion installed) {
179

180
    if (this.installed != null) {
3!
181
      throw new IllegalStateException();
×
182
    }
183
    this.installed = installed;
3✔
184
  }
1✔
185

186
  /**
187
   * @return the {@link ProcessContext} to use for executing the tool. Will also be configured during the installation (variables set, PATH extended).
188
   */
189
  public ProcessContext getProcessContext() {
190
    return this.processContext;
3✔
191
  }
192

193
  /**
194
   * @param processContext new value of {@link #getProcessContext()}.
195
   */
196
  public void setProcessContext(ProcessContext processContext) {
197

198
    if (this.processContext != null) {
3!
199
      throw new IllegalStateException();
×
200
    }
201
    this.processContext = processContext;
3✔
202
  }
1✔
203

204
  /**
205
   * @return the {@link Path} inside the project where the tool installation should be linked to.
206
   */
207
  public Path getToolPath() {
208

209
    return this.toolPath;
3✔
210
  }
211

212
  /**
213
   * @param toolPath new value of {@link #getToolPath()}.
214
   */
215
  public void setToolPath(Path toolPath) {
216

217
    if (this.toolPath != null) {
3!
218
      throw new IllegalStateException();
×
219
    }
220
    this.toolPath = toolPath;
3✔
221
  }
1✔
222

223
  /**
224
   * Called to trigger an extra installation with a custom tool path.
225
   *
226
   * @param toolPath new value of {@link #getToolPath()}.
227
   */
228
  public void setToolPathForExtraInstallation(Path toolPath) {
229

230
    setToolPath(toolPath);
3✔
231
    this.extraInstallation = true;
3✔
232
  }
1✔
233

234
  /**
235
   * @return {@code true} if this is an extra installation, {@code false} otherwise (standard installation).
236
   */
237
  public boolean isExtraInstallation() {
238

239
    return this.extraInstallation;
3✔
240
  }
241

242
  /**
243
   * @return the {@link Step} for the installation.
244
   */
245
  public Step getStep() {
246

247
    return this.step;
3✔
248
  }
249

250
  /**
251
   * @param step new value of {@link #getStep()}.
252
   */
253
  public void setStep(Step step) {
254

255
    if (this.step != null) {
×
256
      throw new IllegalStateException();
×
257
    }
258
    this.step = step;
×
259
  }
×
260

261
  /**
262
   * @return {@code true} if an additional installation is required not linked to the project's software folder (e.g. because of a transitive installation from
263
   *     a dependency that is incompatible with the project version), {@code false} otherwise.
264
   */
265
  public boolean isAdditionalInstallation() {
266
    if (this.requested != null) {
3!
267
      GenericVersionRange versionToInstall = this.requested.getVersion();
4✔
268
      return (versionToInstall instanceof VersionRange);
3✔
269
    }
270
    return false;
×
271
  }
272

273
  /**
274
   * @return {@code true} if the {@link #getRequested() requested edition and version} matches the {@link #getInstalled() installed edition and version}
275
   */
276
  public boolean isAlreadyInstalled() {
277

278
    if (this.installed == null) {
3✔
279
      return false;
2✔
280
    }
281
    VersionIdentifier installedVersion = this.installed.getResolvedVersion();
4✔
282
    if (installedVersion == null) {
2✔
283
      return false;
2✔
284
    }
285
    ToolEdition installedEdition = this.installed.getEdition();
4✔
286
    if (installedEdition == null) {
2!
287
      return false; // should actually never happen
×
288
    }
289
    if (!this.requested.getEdition().equals(installedEdition)) {
6✔
290
      return false;
2✔
291
    }
292
    return installedVersion.equals(this.requested.getResolvedVersion());
6✔
293
  }
294

295
  /**
296
   * @return a new {@link #isDirect() direct} {@link ToolInstallRequest}.
297
   */
298
  public static ToolInstallRequest ofDirect() {
299

300
    return new ToolInstallRequest(null, false, true);
7✔
301
  }
302
}
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