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

devonfw / IDEasy / 9904178931

12 Jul 2024 07:32AM UTC coverage: 61.387% (-0.5%) from 61.842%
9904178931

push

github

web-flow
#400: fix error handling for undefined IDE_ROOT and IDE_HOME (#476)

1997 of 3575 branches covered (55.86%)

Branch coverage included in aggregate %.

5297 of 8307 relevant lines covered (63.77%)

2.8 hits per line

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

59.62
cli/src/main/java/com/devonfw/tools/ide/commandlet/Commandlet.java
1
package com.devonfw.tools.ide.commandlet;
2

3
import com.devonfw.tools.ide.context.IdeContext;
4
import com.devonfw.tools.ide.nls.NlsBundle;
5
import com.devonfw.tools.ide.property.KeywordProperty;
6
import com.devonfw.tools.ide.property.Property;
7
import com.devonfw.tools.ide.tool.ToolCommandlet;
8
import com.devonfw.tools.ide.version.VersionIdentifier;
9

10
import java.util.ArrayList;
11
import java.util.Collections;
12
import java.util.HashMap;
13
import java.util.List;
14
import java.util.Map;
15
import java.util.Objects;
16

17
/**
18
 * A {@link Commandlet} is a sub-command of the IDE CLI.
19
 */
20
public abstract class Commandlet {
1✔
21

22
  /** The {@link IdeContext} instance. */
23
  protected final IdeContext context;
24

25
  private final List<Property<?>> propertiesList;
26

27
  private final List<Property<?>> properties;
28

29
  private final List<Property<?>> valuesList;
30

31
  private final List<Property<?>> values;
32

33
  private final Map<String, Property<?>> optionMap;
34

35
  private Property<?> multiValued;
36

37
  private String firstKeyword;
38

39
  /**
40
   * The constructor.
41
   *
42
   * @param context the {@link IdeContext}.
43
   */
44
  public Commandlet(IdeContext context) {
45

46
    super();
2✔
47
    this.context = context;
3✔
48
    this.propertiesList = new ArrayList<>();
5✔
49
    this.properties = Collections.unmodifiableList(this.propertiesList);
5✔
50
    this.valuesList = new ArrayList<>();
5✔
51
    this.values = Collections.unmodifiableList(this.valuesList);
5✔
52
    this.optionMap = new HashMap<>();
5✔
53
  }
1✔
54

55
  /**
56
   * @return the {@link List} with all {@link Property properties} of this {@link Commandlet}.
57
   */
58
  public List<Property<?>> getProperties() {
59

60
    return this.properties;
3✔
61
  }
62

63
  /**
64
   * @return the {@link List} of {@link Property properties} that are {@link Property#isValue() values}.
65
   */
66
  public List<Property<?>> getValues() {
67

68
    return this.values;
3✔
69
  }
70

71
  /**
72
   * Clear the set values on all properties of the {@link Commandlet#propertiesList}
73
   */
74
  public void clearProperties() {
75

76
    for (Property<?> property : this.propertiesList) {
×
77
      property.clearValue();
×
78
    }
×
79
  }
×
80

81
  /**
82
   * @param nameOrAlias the potential {@link Property#getName() name} or {@link Property#getAlias() alias} of the
83
   *                    requested {@link Property}.
84
   * @return the requested {@link Property property} or {@code null} if not found.
85
   */
86
  public Property<?> getOption(String nameOrAlias) {
87

88
    return this.optionMap.get(nameOrAlias);
6✔
89
  }
90

91
  /**
92
   * @param keyword the {@link KeywordProperty keyword} to {@link #add(Property) add}.
93
   */
94
  protected void addKeyword(String keyword) {
95

96
    if (this.properties.isEmpty()) {
4✔
97
      this.firstKeyword = keyword;
3✔
98
    }
99
    add(new KeywordProperty(keyword, true, null));
9✔
100
  }
1✔
101

102
  /**
103
   * @param property the keyword {@link Property} to {@link #add(Property) add}.
104
   */
105
  protected void addKeyword(Property<?> property) {
106

107
    if (!this.properties.isEmpty()) {
4!
108
      throw new IllegalStateException();
×
109
    }
110
    this.firstKeyword = property.getNameOrAlias();
4✔
111
    add(property);
4✔
112
  }
1✔
113

114
  /**
115
   * @param <P>      type of the {@link Property}.
116
   * @param property the {@link Property} to register.
117
   * @return the given {@link Property}.
118
   */
119
  protected <P extends Property<?>> P add(P property) {
120

121
    if (this.multiValued != null) {
3!
122
      throw new IllegalStateException("The multi-valued property " + this.multiValued + " can not be followed by " + property);
×
123
    }
124
    this.propertiesList.add(property);
5✔
125
    if (property.isOption()) {
3✔
126
      add(property.getName(), property, false);
6✔
127
      add(property.getAlias(), property, true);
6✔
128
    }
129
    if (property.isValue()) {
3✔
130
      this.valuesList.add(property);
5✔
131
    }
132
    if (property.isMultiValued()) {
3✔
133
      this.multiValued = property;
3✔
134
    }
135
    return property;
2✔
136
  }
137

138
  private void add(String name, Property<?> property, boolean alias) {
139

140
    if (alias && (name == null)) {
4✔
141
      return;
1✔
142
    }
143
    Objects.requireNonNull(name);
3✔
144
    assert (name.equals(name.trim()));
6!
145
    if (name.isEmpty() && !alias) {
3!
146
      return;
×
147
    }
148
    Property<?> duplicate = this.optionMap.put(name, property);
7✔
149
    if (duplicate != null) {
2!
150
      throw new IllegalStateException("Duplicate name or alias " + name + " for " + property + " and " + duplicate);
×
151
    }
152
  }
1✔
153

154
  /**
155
   * @return the name of this {@link Commandlet} (e.g. "help").
156
   */
157
  public abstract String getName();
158

159
  /**
160
   * @return the first keyword of this {@link Commandlet}. Typically the same as {@link #getName() name} but may also differ (e.g. "set" vs. "set-version").
161
   */
162
  public String getKeyword() {
163

164
    return this.firstKeyword;
3✔
165
  }
166

167
  /**
168
   * @param <C>            type of the {@link Commandlet}.
169
   * @param commandletType the {@link Class} reflecting the requested {@link Commandlet}.
170
   * @return the requested {@link Commandlet}.
171
   * @see CommandletManager#getCommandlet(Class)
172
   */
173
  protected <C extends Commandlet> C getCommandlet(Class<C> commandletType) {
174

175
    return this.context.getCommandletManager().getCommandlet(commandletType);
6✔
176
  }
177

178
  /**
179
   * @return {@code true} if {@link IdeContext#getIdeHome() IDE_HOME} is required for this commandlet, {@code false} otherwise.
180
   */
181
  public boolean isIdeHomeRequired() {
182

183
    if (!isIdeRootRequired()) {
3!
184
      return false;
2✔
185
    }
186
    return true;
×
187
  }
188

189
  /**
190
   * @return {@code true} if {@link IdeContext#getIdeRoot() IDE_ROOT} is required for this commandlet, {@code false} otherwise.
191
   */
192
  public boolean isIdeRootRequired() {
193

194
    return true;
×
195
  }
196

197
  /**
198
   * @return {@code true} to suppress the {@link com.devonfw.tools.ide.step.StepImpl#logSummary(boolean) step summary success message}.
199
   */
200
  public boolean isSuppressStepSuccess() {
201

202
    return false;
×
203
  }
204

205
  /**
206
   * @return {@code true} if the output of this commandlet is (potentially) processed automatically from outside, {@code false} otherwise.
207
   * For example {@link CompleteCommandlet} logs the suggestions for auto-completion to a bash script. Also the {@link EnvironmentCommandlet}
208
   * logs the environment variables for the {@code ide} wrapper script. In such scenarios these logs shall not be spammed
209
   * with warnings like "IDE_ROOT is not set" that would break the processing of the output.
210
   */
211
  public boolean isProcessableOutput() {
212

213
    return false;
×
214
  }
215

216
  /**
217
   * Runs this {@link Commandlet}.
218
   */
219
  public abstract void run();
220

221
  /**
222
   * @return {@code true} if this {@link Commandlet} is the valid candidate to be {@link #run()}, {@code false} otherwise.
223
   * @see Property#validate()
224
   */
225
  public boolean validate() {
226

227
    // avoid validation exception if not a candidate to be run.
228
    for (Property<?> property : this.propertiesList) {
×
229
      if (property.isRequired() && (property.getValue() == null)) {
×
230
        return false;
×
231
      }
232
    }
×
233
    for (Property<?> property : this.propertiesList) {
×
234
      if (!property.validate()) {
×
235
        return false;
×
236
      }
237
    }
×
238
    return true;
×
239
  }
240

241
  /**
242
   * Provide additional usage help of this {@link Commandlet} to the user.
243
   */
244
  public void printHelp(NlsBundle bundle) {
245

246
  }
1✔
247

248
  @Override
249
  public String toString() {
250

251
    return getClass().getSimpleName() + "[" + getName() + "]";
7✔
252
  }
253

254
  /**
255
   * @return the {@link ToolCommandlet} set in a {@link Property} of this commandlet used for auto-completion of a {@link VersionIdentifier} or {@code null} if
256
   * not exists or not configured.
257
   */
258
  public ToolCommandlet getToolForVersionCompletion() {
259

260
    return null;
×
261
  }
262
}
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