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

devonfw / IDEasy / 13063227142

30 Jan 2025 11:31PM UTC coverage: 68.379% (-0.2%) from 68.557%
13063227142

Pull #990

github

web-flow
Merge dde1c0e39 into aaf4eb4e0
Pull Request #990: #954: improve repository support

2857 of 4597 branches covered (62.15%)

Branch coverage included in aggregate %.

7391 of 10390 relevant lines covered (71.14%)

3.1 hits per line

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

84.13
cli/src/main/java/com/devonfw/tools/ide/step/StepImpl.java
1
package com.devonfw.tools.ide.step;
2

3
import java.time.Duration;
4
import java.util.ArrayList;
5
import java.util.Arrays;
6
import java.util.List;
7

8
import com.devonfw.tools.ide.context.AbstractIdeContext;
9
import com.devonfw.tools.ide.context.IdeContext;
10
import com.devonfw.tools.ide.log.IdeSubLogger;
11

12
/**
13
 * Regular implementation of {@link Step}.
14
 */
15
public final class StepImpl implements Step {
1✔
16

17
  private final AbstractIdeContext context;
18

19
  private final StepImpl parent;
20

21
  private final String name;
22

23
  private final Object[] params;
24

25
  private final List<StepImpl> children;
26

27
  private final long start;
28

29
  private final boolean silent;
30

31
  private Boolean success;
32

33
  private String errorMessage;
34

35
  private long duration;
36

37
  /**
38
   * Creates and starts a new {@link StepImpl}.
39
   *
40
   * @param context the {@link IdeContext}.
41
   * @param parent the {@link #getParent() parent step}.
42
   * @param name the {@link #getName() step name}.
43
   * @param silent the {@link #isSilent() silent flag}.
44
   * @param params the parameters. Should have reasonable {@link Object#toString() string representations}.
45
   */
46
  public StepImpl(AbstractIdeContext context, StepImpl parent, String name, boolean silent, Object... params) {
47

48
    super();
2✔
49
    this.context = context;
3✔
50
    this.parent = parent;
3✔
51
    this.name = name;
3✔
52
    this.params = params;
3✔
53
    this.silent = silent;
3✔
54
    this.children = new ArrayList<>();
5✔
55
    this.start = System.currentTimeMillis();
3✔
56
    if (parent != null) {
2✔
57
      parent.children.add(this);
5✔
58
    }
59
    if (params.length == 0) {
3✔
60
      this.context.trace("Starting step {}...", name);
11✔
61
    } else {
62
      this.context.trace("Starting step {} with params {}...", name, Arrays.toString(params));
15✔
63
    }
64
    if (!this.silent) {
3✔
65
      this.context.step("Start: {}", name);
10✔
66
    }
67
  }
1✔
68

69
  @Override
70
  public StepImpl getParent() {
71

72
    return this.parent;
3✔
73
  }
74

75
  @Override
76
  public String getName() {
77

78
    return this.name;
×
79
  }
80

81
  @Override
82
  public Object getParameter(int i) {
83

84
    if ((i < 0) || (i >= this.params.length)) {
7!
85
      return null;
2✔
86
    }
87
    return this.params[i];
5✔
88
  }
89

90
  @Override
91
  public int getParameterCount() {
92

93
    return this.params.length;
4✔
94
  }
95

96
  @Override
97
  public boolean isSilent() {
98

99
    return this.silent;
×
100
  }
101

102
  @Override
103
  public long getDuration() {
104

105
    return this.duration;
3✔
106
  }
107

108
  @Override
109
  public Boolean getSuccess() {
110

111
    return this.success;
3✔
112
  }
113

114
  @Override
115
  public void success(String message, Object... args) {
116

117
    end(Boolean.TRUE, null, false, message, args);
7✔
118
  }
1✔
119

120
  @Override
121
  public void error(Throwable error, boolean suppress, String message, Object... args) {
122

123
    end(Boolean.FALSE, error, suppress, message, args);
7✔
124
  }
1✔
125

126
  @Override
127
  public void close() {
128

129
    end(null, null, false, null, null);
7✔
130
  }
1✔
131

132
  private void end(Boolean newSuccess, Throwable error, boolean suppress, String message, Object[] args) {
133

134
    boolean firstCallOfEnd = (this.success == null);
7✔
135
    if (!firstCallOfEnd) {
2✔
136
      assert (this.duration > 0);
6!
137
      if (newSuccess != null) {
2✔
138
        this.context.warning("Step '{}' already ended with {} and now ended again with {}.", this.name, this.success, newSuccess);
21✔
139
      } else {
140
        return;
1✔
141
      }
142
    }
143
    long delay = System.currentTimeMillis() - this.start;
5✔
144
    if (delay == 0) {
4✔
145
      delay = 1;
2✔
146
    }
147
    if (newSuccess == null) {
2!
148
      newSuccess = Boolean.FALSE;
×
149
    }
150
    if (!Boolean.FALSE.equals(this.success)) { // never allow a failed step to change to success
5✔
151
      this.duration = delay;
3✔
152
      this.success = newSuccess;
3✔
153
    }
154
    if (newSuccess.booleanValue()) {
3✔
155
      assert (error == null);
3!
156
      if (message != null) {
2✔
157
        this.context.success(message, args);
6✔
158
      } else if (!this.silent) {
3✔
159
        this.context.success("Successfully ended step '{}'.", this.name);
11✔
160
      }
161
      this.context.debug("Step '{}' ended successfully.", this.name);
12✔
162
    } else {
163
      IdeSubLogger logger;
164
      if ((message != null) || (error != null)) {
4!
165
        if (suppress) {
2✔
166
          if (error != null) {
2!
167
            this.errorMessage = error.toString();
5✔
168
          } else {
169
            this.errorMessage = message;
×
170
          }
171
        } else {
172
          this.errorMessage = this.context.error().log(error, message, args);
9✔
173
        }
174
        logger = this.context.debug();
5✔
175
      } else {
176
        logger = this.context.info();
×
177
      }
178
      logger.log("Step '{}' ended with failure.", this.name);
11✔
179
    }
180
    if (firstCallOfEnd) {
2✔
181
      this.context.endStep(this);
4✔
182
    }
183
  }
1✔
184

185
  /**
186
   * Logs the summary of this {@link Step}. Should typically only be called on the top-level {@link Step}.
187
   *
188
   * @param suppressSuccess - {@code true} to suppress the success message, {@code false} otherwise.
189
   */
190
  public void logSummary(boolean suppressSuccess) {
191

192
    if (this.context.trace().isEnabled()) {
5!
193
      this.context.trace(toString());
5✔
194
    }
195
    if (this.context.isQuietMode() || (this.children.isEmpty())) {
8!
196
      return;
1✔
197
    }
198
    StepSummary summary = new StepSummary();
4✔
199
    logErrorSummary(0, summary);
4✔
200
    if (summary.getError() == 0) {
3!
201
      if (!suppressSuccess) {
2!
202
        this.context.success("Successfully completed {}", getNameWithParams());
12✔
203
      }
204
    } else {
205
      this.context.error(summary.toString());
×
206
    }
207
  }
1✔
208

209
  private void logErrorSummary(int depth, StepSummary summary) {
210

211
    boolean failure = isFailure();
3✔
212
    summary.add(failure);
3✔
213
    if (failure) {
2!
214
      String error = this.errorMessage;
×
215
      if (error == null) {
×
216
        error = "unexpected error";
×
217
      }
218
      this.context.error("{}Step '{}' failed: {}", getIndent(depth), getNameWithParams(), error);
×
219
    }
220
    depth++;
1✔
221
    for (StepImpl child : this.children) {
11✔
222
      child.logErrorSummary(depth, summary);
4✔
223
    }
1✔
224
  }
1✔
225

226
  private String getNameWithParams() {
227

228
    if ((this.params == null) || (this.params.length == 0)) {
7!
229
      return this.name;
×
230
    }
231
    StringBuilder sb = new StringBuilder(this.name.length() + 3 + this.params.length * 6);
15✔
232
    getNameWithParams(sb);
3✔
233
    return sb.toString();
3✔
234
  }
235

236
  private void getNameWithParams(StringBuilder sb) {
237

238
    sb.append(this.name);
5✔
239
    sb.append(" (");
4✔
240
    String seperator = "";
2✔
241
    if (this.params != null) {
3!
242
      for (Object param : this.params) {
17✔
243
        sb.append(seperator);
4✔
244
        sb.append(param);
4✔
245
        seperator = ",";
2✔
246
      }
247
    }
248
    sb.append(')');
4✔
249
  }
1✔
250

251
  private void append(int depth, long totalDuration, long parentDuration, StringBuilder sb) {
252

253
    // indent
254
    sb.append(getIndent(depth));
6✔
255
    getNameWithParams(sb);
3✔
256
    sb.append(' ');
4✔
257
    if (this.success == null) {
3!
258
      sb.append("is still running or was not properly ended due to programming error not using finally block ");
×
259
    } else {
260
      if (this.success.booleanValue()) {
4✔
261
        sb.append("succeeded after ");
5✔
262
      } else {
263
        sb.append("failed after ");
4✔
264
      }
265
      sb.append(Duration.ofMillis(this.duration));
6✔
266
    }
267
    if (this.duration < totalDuration) {
5✔
268
      sb.append(" ");
4✔
269
      double percentageBase = this.duration * 100;
6✔
270
      double totalPercentage = percentageBase / totalDuration;
5✔
271
      sb.append(totalPercentage);
4✔
272
      sb.append("% of total ");
4✔
273
      if (parentDuration < totalDuration) {
4!
274
        double parentPercentage = percentageBase / parentDuration;
×
275
        sb.append(parentPercentage);
×
276
        sb.append("% of parent");
×
277
      }
278
    }
279
    sb.append('\n');
4✔
280
    int childDepth = depth + 1;
4✔
281
    for (StepImpl child : this.children) {
11✔
282
      child.append(childDepth, totalDuration, this.duration, sb);
7✔
283
    }
1✔
284
  }
1✔
285

286
  private String getIndent(int depth) {
287

288
    return " ".repeat(depth);
4✔
289
  }
290

291
  @Override
292
  public String toString() {
293

294
    StringBuilder sb = new StringBuilder(4096);
5✔
295
    append(0, this.duration, this.duration, sb);
8✔
296
    return sb.toString();
3✔
297
  }
298
}
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

© 2025 Coveralls, Inc