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

devonfw / IDEasy / 12181235589

05 Dec 2024 01:58PM UTC coverage: 66.902% (-0.02%) from 66.917%
12181235589

push

github

web-flow
#508: enabled autocompletion for commandlet options (#833)

2527 of 4130 branches covered (61.19%)

Branch coverage included in aggregate %.

6577 of 9478 relevant lines covered (69.39%)

3.06 hits per line

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

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

3
import java.util.ArrayList;
4
import java.util.Collections;
5
import java.util.HashMap;
6
import java.util.List;
7
import java.util.Map;
8
import java.util.Objects;
9

10
import com.devonfw.tools.ide.context.IdeContext;
11
import com.devonfw.tools.ide.nls.NlsBundle;
12
import com.devonfw.tools.ide.property.KeywordProperty;
13
import com.devonfw.tools.ide.property.Property;
14
import com.devonfw.tools.ide.tool.ToolCommandlet;
15
import com.devonfw.tools.ide.validation.ValidationResult;
16
import com.devonfw.tools.ide.validation.ValidationState;
17
import com.devonfw.tools.ide.version.VersionIdentifier;
18

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

24
  /** The {@link IdeContext} instance. */
25
  protected final IdeContext context;
26

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

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

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

33
  private final List<Property<?>> values;
34

35
  private final Map<String, Property<?>> optionMap;
36

37
  private Property<?> multiValued;
38

39
  private String firstKeyword;
40

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

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

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

62
    return this.properties;
3✔
63
  }
64

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

70
    return this.values;
3✔
71
  }
72

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

78
    for (Property<?> property : this.propertiesList) {
11✔
79
      property.clearValue();
2✔
80
    }
1✔
81
  }
1✔
82

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

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

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

97
    addKeyword(keyword, null);
4✔
98
  }
1✔
99

100
  /**
101
   * @param keyword the {@link KeywordProperty keyword} to {@link #add(Property) add}.
102
   * @param alias the optional {@link KeywordProperty#getAlias() alias}.
103
   */
104
  protected void addKeyword(String keyword, String alias) {
105

106
    if (this.properties.isEmpty()) {
4✔
107
      this.firstKeyword = keyword;
3✔
108
    }
109
    add(new KeywordProperty(keyword, true, alias));
9✔
110
  }
1✔
111

112
  /**
113
   * @param property the keyword {@link Property} to {@link #add(Property) add}.
114
   */
115
  protected void addKeyword(Property<?> property) {
116

117
    if (!this.properties.isEmpty()) {
×
118
      throw new IllegalStateException();
×
119
    }
120
    this.firstKeyword = property.getNameOrAlias();
×
121
    add(property);
×
122
  }
×
123

124
  /**
125
   * @param <P> type of the {@link Property}.
126
   * @param property the {@link Property} to register.
127
   * @return the given {@link Property}.
128
   */
129
  protected <P extends Property<?>> P add(P property) {
130

131
    if (this.multiValued != null) {
3!
132
      throw new IllegalStateException("The multi-valued property " + this.multiValued + " can not be followed by " + property);
×
133
    }
134
    this.propertiesList.add(property);
5✔
135
    if (property.isOption()) {
3✔
136
      add(property.getName(), property, false);
6✔
137
      add(property.getAlias(), property, true);
6✔
138
    }
139
    if (property.isValue()) {
3✔
140
      this.valuesList.add(property);
5✔
141
    }
142
    if (property.isMultiValued()) {
3✔
143
      this.multiValued = property;
3✔
144
    }
145
    return property;
2✔
146
  }
147

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

150
    if (alias && (name == null)) {
4✔
151
      return;
1✔
152
    }
153
    Objects.requireNonNull(name);
3✔
154
    assert (name.equals(name.trim()));
6!
155
    if (name.isEmpty() && !alias) {
3!
156
      return;
×
157
    }
158
    Property<?> duplicate = this.optionMap.put(name, property);
7✔
159
    if (duplicate != null) {
2!
160
      throw new IllegalStateException("Duplicate name or alias " + name + " for " + property + " and " + duplicate);
×
161
    }
162
  }
1✔
163

164
  /**
165
   * @return the name of this {@link Commandlet} (e.g. "help").
166
   */
167
  public abstract String getName();
168

169
  /**
170
   * @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").
171
   */
172
  public String getKeyword() {
173

174
    return this.firstKeyword;
3✔
175
  }
176

177
  /**
178
   * @param <C> type of the {@link Commandlet}.
179
   * @param commandletType the {@link Class} reflecting the requested {@link Commandlet}.
180
   * @return the requested {@link Commandlet}.
181
   * @see CommandletManager#getCommandlet(Class)
182
   */
183
  protected <C extends Commandlet> C getCommandlet(Class<C> commandletType) {
184

185
    return this.context.getCommandletManager().getCommandlet(commandletType);
6✔
186
  }
187

188
  /**
189
   * @return {@code true} if {@link IdeContext#getIdeHome() IDE_HOME} is required for this commandlet, {@code false} otherwise.
190
   */
191
  public boolean isIdeHomeRequired() {
192

193
    return isIdeRootRequired();
3✔
194
  }
195

196
  /**
197
   * @return {@code true} if {@link IdeContext#getIdeRoot() IDE_ROOT} is required for this commandlet, {@code false} otherwise.
198
   */
199
  public boolean isIdeRootRequired() {
200

201
    return true;
2✔
202
  }
203

204
  /**
205
   * @return {@code true} to suppress the {@link com.devonfw.tools.ide.step.StepImpl#logSummary(boolean) step summary success message}.
206
   */
207
  public boolean isSuppressStepSuccess() {
208

209
    return false;
2✔
210
  }
211

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

220
    return false;
2✔
221
  }
222

223
  /**
224
   * Runs this {@link Commandlet}.
225
   */
226
  public abstract void run();
227

228
  /**
229
   * @return {@code true} if this {@link Commandlet} is the valid candidate to be {@link #run()}, {@code false} otherwise.
230
   * @see Property#validate()
231
   */
232
  public ValidationResult validate() {
233
    ValidationState state = new ValidationState(null);
5✔
234
    // avoid validation exception if not a candidate to be run.
235
    for (Property<?> property : this.propertiesList) {
11✔
236
      state.add(property.validate());
4✔
237
    }
1✔
238
    return state;
2✔
239
  }
240

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

248
  }
1✔
249

250
  @Override
251
  public String toString() {
252

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

256
  /**
257
   * @return the {@link ToolCommandlet} set in a {@link Property} of this commandlet used for auto-completion of a {@link VersionIdentifier} or
258
   *     {@link com.devonfw.tools.ide.tool.plugin.ToolPluginDescriptor}, otherwise {@code null} if not exists or not configured.
259
   */
260
  public ToolCommandlet getToolForCompletion() {
261
    return null;
2✔
262
  }
263
}
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