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

devonfw / IDEasy / 24563263059

17 Apr 2026 11:41AM UTC coverage: 70.557% (+0.1%) from 70.455%
24563263059

push

github

web-flow
#906: Add feature configurable intellij vm args (#1820)

Co-authored-by: MarvMa <marvin.meitzner@gmail.com>
Co-authored-by: Jörg Hohwiller <hohwille@users.noreply.github.com>

4299 of 6734 branches covered (63.84%)

Branch coverage included in aggregate %.

11134 of 15139 relevant lines covered (73.55%)

3.1 hits per line

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

80.92
cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeaBasedIdeToolCommandlet.java
1
package com.devonfw.tools.ide.tool.ide;
2

3
import java.nio.file.Path;
4
import java.util.ArrayList;
5
import java.util.Collections;
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.log.IdeLogLevel;
16
import com.devonfw.tools.ide.process.ProcessContext;
17
import com.devonfw.tools.ide.process.ProcessMode;
18
import com.devonfw.tools.ide.process.ProcessResult;
19
import com.devonfw.tools.ide.step.Step;
20
import com.devonfw.tools.ide.tool.plugin.ToolPluginDescriptor;
21

22
/**
23
 * {@link IdeToolCommandlet} for IDEA based commandlets like: {@link com.devonfw.tools.ide.tool.intellij.Intellij IntelliJ} and
24
 * {@link com.devonfw.tools.ide.tool.androidstudio.AndroidStudio Android Studio}.
25
 */
26
public class IdeaBasedIdeToolCommandlet extends IdeToolCommandlet {
27

28
  private static final Logger LOG = LoggerFactory.getLogger(IdeaBasedIdeToolCommandlet.class);
4✔
29

30
  private static final String VM_OPTIONS_FILE_EXTENSION = ".vmoptions";
31

32
  private static final String VM_ARGS_ENV_SUFFIX = "_VM_ARGS";
33

34
  private static final String VM_OPTIONS_ENV_SUFFIX = "_VM_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 IdeaBasedIdeToolCommandlet(IdeContext context, String tool, Set<Tag> tags) {
44
    super(context, tool, tags);
5✔
45
  }
1✔
46

47
  @Override
48
  public boolean installPlugin(ToolPluginDescriptor plugin, final Step step, ProcessContext pc) {
49

50
    // In case of plugins with a custom repo url
51
    boolean customRepo = plugin.url() != null;
6!
52
    List<String> args = new ArrayList<>();
4✔
53
    args.add("installPlugins");
4✔
54
    args.add(plugin.id().replace("+", " "));
8✔
55
    if (customRepo) {
2!
56
      args.add(plugin.url());
5✔
57
    }
58
    ProcessResult result = runTool(pc, ProcessMode.DEFAULT, args);
6✔
59
    if (result.isSuccessful()) {
3!
60
      IdeLogLevel.SUCCESS.log(LOG, "Successfully installed plugin: {}", plugin.name());
11✔
61
      step.success();
2✔
62
      return true;
2✔
63
    } else {
64
      step.error("Failed to install plugin {} ({}): exit code was {}", plugin.name(), plugin.id(), result.getExitCode());
×
65
      return false;
×
66
    }
67
  }
68

69
  /**
70
   * Returns the IDE product prefix used in various files inside the {@code bin} directory, e.g. {@code "idea"} for {@code idea64.exe} or {@code "studio"} for
71
   * {@code studio64.vmoptions}.
72
   * <p>
73
   * By default, this method returns the tool name ({@link #getName()}). Subclasses may override this method if the IDE binary or vmoptions file uses a more
74
   * specific or different prefix.
75
   *
76
   * @return the IDE product prefix
77
   */
78
  protected String getIdeProductPrefix() {
79

80
    return getName();
×
81
  }
82

83
  @Override
84
  public ProcessResult runTool(ProcessContext pc, ProcessMode processMode, List<String> args) {
85
    args.add(this.context.getWorkspacePath().toString());
7✔
86

87
    String variableName = getName().toUpperCase(Locale.ROOT).replace("-", "_") + VM_ARGS_ENV_SUFFIX;
9✔
88
    String userVmArgsContent = this.context.getVariables().get(variableName);
6✔
89
    if (userVmArgsContent == null || userVmArgsContent.isEmpty()) {
5!
90
      return super.runTool(pc, processMode, args);
6✔
91
    }
92
    String[] userVmArgs = userVmArgsContent.trim().split("\\s+");
5✔
93

94
    String prefix = getIdeProductPrefix();
3✔
95
    Path defaultVmOptionsPath = resolveDefaultVmOptionsPath(this.getToolPath(), prefix);
6✔
96
    String defaultVmArgsContent = this.context.getFileAccess().readFileContent(defaultVmOptionsPath);
6✔
97
    if (defaultVmArgsContent == null || defaultVmArgsContent.isEmpty()) {
5!
98
      LOG.debug("Default {} jvm options not found at: {}", getName(), defaultVmOptionsPath);
6✔
99
      return super.runTool(pc, processMode, args);
6✔
100
    }
101
    String[] defaultVmArgs = defaultVmArgsContent.trim().split("\\s+");
5✔
102

103
    String userOptionsFileName = "." + prefix + VM_OPTIONS_FILE_EXTENSION;
3✔
104
    Path confPath = this.context.getWorkspacePath().resolve(userOptionsFileName);
6✔
105
    this.context.getFileAccess().writeFileContent(mergeVmArgs(defaultVmArgs, userVmArgs), confPath, true);
10✔
106

107
    pc.withEnvVar(prefix.toUpperCase() + VM_OPTIONS_ENV_SUFFIX, confPath.toAbsolutePath().toString());
9✔
108
    return super.runTool(pc, processMode, args);
6✔
109
  }
110

111
  private Path resolveDefaultVmOptionsPath(Path softwarePath, String ideProductPrefix) {
112
    if (ideProductPrefix == null) {
2!
113
      LOG.debug("Binary prefix for tool {} is not set", getName());
×
114
      return null;
×
115
    }
116

117
    if (this.context.getSystemInfo().isWindows()) {
5✔
118
      return softwarePath
3✔
119
          .resolve("bin")
3✔
120
          .resolve(ideProductPrefix + "64.exe" + VM_OPTIONS_FILE_EXTENSION);
1✔
121
    }
122

123
    if (this.context.getSystemInfo().isMac()) {
5✔
124
      try {
125
        return softwarePath.toRealPath()
5✔
126
            .getParent()
2✔
127
            .resolve("bin")
3✔
128
            .resolve(ideProductPrefix + VM_OPTIONS_FILE_EXTENSION);
1✔
129
      } catch (Exception e) {
×
130
        LOG.error("Failed to resolve real path for software path: {}", softwarePath, e);
×
131
      }
132
    }
133

134
    return softwarePath // Linux
3✔
135
        .resolve("bin")
3✔
136
        .resolve(ideProductPrefix + "64" + VM_OPTIONS_FILE_EXTENSION);
1✔
137
  }
138

139
  private String mergeVmArgs(String[] defaults, String[] userArgs) {
140

141
    List<String> result = new ArrayList<>(defaults.length + userArgs.length);
9✔
142
    Collections.addAll(result, defaults);
4✔
143
    for (String userArg : userArgs) {
16✔
144
      boolean replaced = false;
2✔
145
      for (int i = 0; i < result.size(); i++) {
8!
146
        if (isSameJvmKey(result.get(i), userArg)) {
8✔
147
          result.set(i, userArg); //override default arg with user defined arg
5✔
148
          replaced = true;
2✔
149
          break;
1✔
150
        }
151
      }
152
      if (!replaced) { // Extend case: user configured arg does not exist in default options
2!
153
        result.add(userArg);
×
154
      }
155
    }
156

157
    return String.join(System.lineSeparator(), result);
4✔
158
  }
159

160
  private String extractJvmOptionsKey(String arg) {
161

162
    if (arg.startsWith("-Xmx")) {
4✔
163
      return "-Xmx";
2✔
164
    }
165
    if (arg.startsWith("-Xms")) {
4✔
166
      return "-Xms";
2✔
167
    }
168
    if (arg.startsWith("-Xmn")) {
4!
169
      return "-Xmn";
×
170
    }
171
    if (arg.startsWith("-Xss")) {
4!
172
      return "-Xss";
×
173
    }
174
    if (arg.startsWith("-D")) {
4✔
175
      int eq = arg.indexOf('=');
4✔
176
      return eq > 0 ? arg.substring(0, eq) : arg;
8!
177
    }
178
    if (arg.startsWith("-XX:")) {
4✔
179
      String opt = arg.substring(4);
4✔
180
      if (opt.startsWith("+") || opt.startsWith("-")) {
8!
181
        return "-XX:" + opt.substring(1);
×
182
      }
183
      int eq = opt.indexOf('=');
4✔
184
      return eq > 0 ? "-XX:" + opt.substring(0, eq) : arg;
9!
185
    }
186

187
    return arg;
2✔
188
  }
189

190
  private boolean isSameJvmKey(String a, String b) {
191

192
    return extractJvmOptionsKey(a).equals(extractJvmOptionsKey(b));
8✔
193
  }
194
}
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