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

devonfw / IDEasy / 30799297795

03 Aug 2026 08:55AM UTC coverage: 72.595% (-0.02%) from 72.61%
30799297795

Pull #2247

github

web-flow
Merge f6d271ba0 into cbb2c56d8
Pull Request #2247: #788: Add support for IDE_OPTIONS variable per IDE commandlet

4998 of 7633 branches covered (65.48%)

Branch coverage included in aggregate %.

13065 of 17249 relevant lines covered (75.74%)

3.22 hits per line

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

81.33
cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeToolCommandlet.java
1
package com.devonfw.tools.ide.tool.ide;
2

3
import java.nio.file.Files;
4
import java.nio.file.Path;
5
import java.util.ArrayList;
6
import java.util.List;
7
import java.util.Locale;
8
import java.util.Set;
9

10
import org.slf4j.Logger;
11
import org.slf4j.LoggerFactory;
12

13
import com.devonfw.tools.ide.common.Tag;
14
import com.devonfw.tools.ide.context.IdeContext;
15
import com.devonfw.tools.ide.io.FileAccess;
16
import com.devonfw.tools.ide.process.ProcessMode;
17
import com.devonfw.tools.ide.process.ProcessResult;
18
import com.devonfw.tools.ide.step.Step;
19
import com.devonfw.tools.ide.tool.ToolCommandlet;
20
import com.devonfw.tools.ide.tool.ToolInstallRequest;
21
import com.devonfw.tools.ide.tool.ToolInstallation;
22
import com.devonfw.tools.ide.tool.eclipse.Eclipse;
23
import com.devonfw.tools.ide.tool.intellij.Intellij;
24
import com.devonfw.tools.ide.tool.plugin.PluginBasedCommandlet;
25
import com.devonfw.tools.ide.tool.vscode.Vscode;
26

27
/**
28
 * {@link ToolCommandlet} for an IDE (integrated development environment) such as {@link Eclipse}, {@link Vscode}, or {@link Intellij}.
29
 */
30
public abstract class IdeToolCommandlet extends PluginBasedCommandlet {
31

32
  private static final Logger LOG = LoggerFactory.getLogger(IdeToolCommandlet.class);
4✔
33

34
  private static final String OPTIONS_ENV_SUFFIX = "_OPTIONS";
35

36
  /**
37
   * The constructor.
38
   *
39
   * @param context the {@link IdeContext}.
40
   * @param tool the {@link #getName() tool name}.
41
   * @param tags the {@link #getTags() tags} classifying the tool. Should be created via {@link Set#of(Object) Set.of} method.
42
   */
43
  public IdeToolCommandlet(IdeContext context, String tool, Set<Tag> tags) {
44

45
    super(context, tool, tags);
5✔
46
    assert (hasIde(tags));
5!
47
  }
1✔
48

49
  private boolean hasIde(Set<Tag> tags) {
50

51
    for (Tag tag : tags) {
10!
52
      if (tag.isAncestorOf(Tag.IDE) || (tag == Tag.IDE)) {
7!
53
        return true;
2✔
54
      }
55
    }
×
56
    throw new IllegalStateException("Tags of IdeTool has to be connected with tag IDE: " + tags);
×
57
  }
58

59
  @Override
60
  protected final void doRun() {
61
    super.doRun();
2✔
62
  }
1✔
63

64
  @Override
65
  public ProcessResult runTool(List<String> args) {
66

67
    List<String> effectiveArgs = new ArrayList<>(args);
5✔
68
    addIdeOptions(effectiveArgs);
3✔
69
    return runTool(ProcessMode.BACKGROUND, null, effectiveArgs);
6✔
70
  }
71

72
  /**
73
   * Appends the tokens of {@code «IDE»_OPTIONS} (e.g. {@code INTELLIJ_OPTIONS}) to the given {@code args}. This is the per-tool analogue of the global
74
   * {@code IDE_OPTIONS} and only applies when actually starting the IDE (not for internal calls like plugin installation or repository import).
75
   *
76
   * @param args the command-line arguments to launch this IDE, extended in place.
77
   */
78
  private void addIdeOptions(List<String> args) {
79

80
    String variableName = getName().toUpperCase(Locale.ROOT).replace("-", "_") + OPTIONS_ENV_SUFFIX;
9✔
81
    String options = this.context.getVariables().get(variableName);
6✔
82
    if ((options != null) && !options.isBlank()) {
5!
83
      for (String option : options.trim().split("\\s+")) {
19✔
84
        args.add(option);
4✔
85
      }
86
    }
87
  }
1✔
88

89
  @Override
90
  public ToolInstallation install(ToolInstallRequest request) {
91

92
    configureWorkspace();
2✔
93
    return super.install(request);
4✔
94
  }
95

96
  /**
97
   * @return the {@link Path} to the IDE-specific metadata folder for the {@link IdeContext#getWorkspaceName() current workspace}, located at
98
   *     {@code $IDE_HOME/.ide/«ide»/«workspace»}. Unlike {@link IdeContext#getWorkspacePath() the workspace path} (which holds the projects to open), this
99
   *     folder keeps IDE-specific metadata (e.g. {@code .vmoptions} or {@code *.properties} files) out of the workspace so it stays clean and independent of
100
   *     the IDE being used.
101
   */
102
  protected Path getIdeMetadataPath() {
103

104
    return this.context.getIdeHome().resolve(IdeContext.FOLDER_DOT_IDE).resolve(getName()).resolve(this.context.getWorkspaceName());
13✔
105
  }
106

107
  /**
108
   * Configure (initialize or update) the workspace for this IDE using the templates from the settings.
109
   */
110
  protected void configureWorkspace() {
111

112
    FileAccess fileAccess = this.context.getFileAccess();
4✔
113
    Path workspaceFolder = this.context.getWorkspacePath();
4✔
114
    if (!fileAccess.isExpectedFolder(workspaceFolder)) {
4!
115
      LOG.warn("Current workspace does not exist: {}", workspaceFolder);
×
116
      return; // should actually never happen...
×
117
    }
118
    Step step = this.context.newStep("Configuring workspace " + workspaceFolder.getFileName() + " for IDE " + this.tool);
10✔
119
    step.run(() -> doMergeWorkspaceStep(step, workspaceFolder));
12✔
120
  }
1✔
121

122
  private void doMergeWorkspaceStep(Step step, Path workspaceFolder) {
123

124
    int errors = 0;
2✔
125
    errors = mergeWorkspace(this.context.getUserHomeIde(), workspaceFolder, errors);
8✔
126
    errors = mergeWorkspace(this.context.getSettingsPath(), workspaceFolder, errors);
8✔
127
    errors = mergeWorkspace(this.context.getConfPath(), workspaceFolder, errors);
8✔
128
    if (errors == 0) {
2!
129
      step.success();
3✔
130
    } else {
131
      step.error("Your workspace configuration failed with {} error(s) - see log above.\n"
×
132
          + "This is either a configuration error in your settings git repository or a bug in IDEasy.\n"
133
          + "Please analyze the above errors with your team or IDE-admin and try to fix the problem.", errors);
×
134
      this.context.askToContinue(
×
135
          "In order to prevent you from being blocked, you can start your IDE anyhow but some configuration may not be in sync.");
136
    }
137
  }
1✔
138

139
  private int mergeWorkspace(Path configFolder, Path workspaceFolder, int errors) {
140

141
    int result = errors;
2✔
142
    result = mergeWorkspaceSingle(configFolder.resolve(IdeContext.FOLDER_WORKSPACE), workspaceFolder, result);
8✔
143
    result = mergeWorkspaceSingle(configFolder.resolve(this.tool).resolve(IdeContext.FOLDER_WORKSPACE), workspaceFolder, result);
11✔
144
    return result;
2✔
145
  }
146

147
  private int mergeWorkspaceSingle(Path templatesFolder, Path workspaceFolder, int errors) {
148

149
    Path setupFolder = templatesFolder.resolve(IdeContext.FOLDER_SETUP);
4✔
150
    Path updateFolder = templatesFolder.resolve(IdeContext.FOLDER_UPDATE);
4✔
151
    if (!Files.isDirectory(setupFolder) && !Files.isDirectory(updateFolder)) {
10✔
152
      LOG.trace("Skipping empty or non-existing workspace template folder {}.", templatesFolder);
4✔
153
      return errors;
2✔
154
    }
155
    LOG.debug("Merging workspace templates from {}...", templatesFolder);
4✔
156
    return errors + this.context.getWorkspaceMerger().merge(setupFolder, updateFolder, this.context.getVariables(), workspaceFolder);
13✔
157
  }
158

159
  /**
160
   * Imports the repository specified by the given {@link Path} into the IDE managed by this {@link IdeToolCommandlet}.
161
   *
162
   * @param repositoryPath the {@link Path} to the repository directory to import.
163
   */
164
  public void importRepository(Path repositoryPath) {
165

166
    throw new UnsupportedOperationException("Repository import is not yet implemented for IDE " + this.tool);
×
167
  }
168
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc