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

devonfw / IDEasy / 9808498015

05 Jul 2024 12:43PM UTC coverage: 61.798% (+0.6%) from 61.159%
9808498015

push

github

web-flow
#25: implement tool commandlet for intellij (#447)

1983 of 3531 branches covered (56.16%)

Branch coverage included in aggregate %.

5264 of 8196 relevant lines covered (64.23%)

2.82 hits per line

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

82.99
cli/src/main/java/com/devonfw/tools/ide/common/SystemPath.java
1
package com.devonfw.tools.ide.common;
2

3
import com.devonfw.tools.ide.context.IdeContext;
4
import com.devonfw.tools.ide.os.SystemInfoImpl;
5
import com.devonfw.tools.ide.os.WindowsPathSyntax;
6
import com.devonfw.tools.ide.variable.IdeVariables;
7

8
import java.io.File;
9
import java.io.IOException;
10
import java.nio.file.Files;
11
import java.nio.file.Path;
12
import java.util.ArrayList;
13
import java.util.HashMap;
14
import java.util.Iterator;
15
import java.util.List;
16
import java.util.Map;
17
import java.util.regex.Pattern;
18
import java.util.stream.Stream;
19

20
/**
21
 * Represents the PATH variable in a structured way. The PATH contains the system path entries together with the entries
22
 * for the IDEasy tools. The generic system path entries are stored in a {@link List} ({@code paths}) and the tool
23
 * entries are stored in a {@link Map} ({@code tool2pathMap}) as they can change dynamically at runtime (e.g. if a new
24
 * tool is installed). As the tools must have priority the actual PATH is build by first the entries for the tools and
25
 * then the generic entries from the system PATH. Such tool entries are ignored from the actual PATH of the
26
 * {@link System#getenv(String) environment} at construction time and are recomputed from the "software" folder. This is
27
 * important as the initial {@link System#getenv(String) environment} PATH entries can come from a different IDEasy
28
 * project and the use may have changed projects before calling us again. Recomputing the PATH ensures side-effects from
29
 * other projects. However, it also will ensure all the entries to IDEasy locations are automatically managed and
30
 * therefore cannot be managed manually be the end-user.
31
 */
32
public class SystemPath {
33

34
  private static final Pattern REGEX_WINDOWS_PATH = Pattern.compile("([a-zA-Z]:)?(\\\\[a-zA-Z0-9\\s_.-]+)+\\\\?");
3✔
35

36
  private final String envPath;
37

38
  private final char pathSeparator;
39

40
  private final Map<String, Path> tool2pathMap;
41

42
  private final List<Path> paths;
43

44
  private final IdeContext context;
45

46
  private static final List<String> EXTENSION_PRIORITY = List.of(".exe", ".cmd", ".bat", ".msi", ".ps1", "");
9✔
47

48
  /**
49
   * The constructor.
50
   *
51
   * @param context {@link IdeContext}.
52
   */
53
  public SystemPath(IdeContext context) {
54

55
    this(context, System.getenv(IdeVariables.PATH.getName()));
6✔
56
  }
1✔
57

58
  /**
59
   * The constructor.
60
   *
61
   * @param context {@link IdeContext}.
62
   * @param envPath the value of the PATH variable.
63
   */
64
  public SystemPath(IdeContext context, String envPath) {
65

66
    this(context, envPath, context.getIdeRoot(), context.getSoftwarePath());
8✔
67
  }
1✔
68

69
  /**
70
   * The constructor.
71
   *
72
   * @param context      {@link IdeContext} for the output of information.
73
   * @param envPath      the value of the PATH variable.
74
   * @param ideRoot      the {@link IdeContext#getIdeRoot() IDE_ROOT}.
75
   * @param softwarePath the {@link IdeContext#getSoftwarePath() software path}.
76
   */
77
  public SystemPath(IdeContext context, String envPath, Path ideRoot, Path softwarePath) {
78

79
    this(context, envPath, ideRoot, softwarePath, File.pathSeparatorChar);
7✔
80
  }
1✔
81

82
  /**
83
   * The constructor.
84
   *
85
   * @param context       {@link IdeContext} for the output of information.
86
   * @param envPath       the value of the PATH variable.
87
   * @param ideRoot       the {@link IdeContext#getIdeRoot() IDE_ROOT}.
88
   * @param softwarePath  the {@link IdeContext#getSoftwarePath() software path}.
89
   * @param pathSeparator the path separator char (';' for Windows and ':' otherwise).
90
   */
91
  public SystemPath(IdeContext context, String envPath, Path ideRoot, Path softwarePath, char pathSeparator) {
92

93
    super();
2✔
94
    this.context = context;
3✔
95
    this.envPath = envPath;
3✔
96
    this.pathSeparator = pathSeparator;
3✔
97
    this.tool2pathMap = new HashMap<>();
5✔
98
    this.paths = new ArrayList<>();
5✔
99
    String[] envPaths = envPath.split(Character.toString(pathSeparator));
5✔
100
    for (String segment : envPaths) {
16✔
101
      Path path = Path.of(segment);
5✔
102
      String tool = getTool(path, ideRoot);
4✔
103
      if (tool == null) {
2!
104
        this.paths.add(path);
5✔
105
      }
106
    }
107
    collectToolPath(softwarePath);
3✔
108
  }
1✔
109

110
  private void collectToolPath(Path softwarePath) {
111

112
    if (softwarePath == null) {
2✔
113
      return;
1✔
114
    }
115
    if (Files.isDirectory(softwarePath)) {
5✔
116
      try (Stream<Path> children = Files.list(softwarePath)) {
3✔
117
        Iterator<Path> iterator = children.iterator();
3✔
118
        while (iterator.hasNext()) {
3✔
119
          Path child = iterator.next();
4✔
120
          String tool = child.getFileName().toString();
4✔
121
          if (!"extra".equals(tool) && Files.isDirectory(child)) {
9!
122
            Path toolPath = child;
2✔
123
            Path bin = child.resolve("bin");
4✔
124
            if (Files.isDirectory(bin)) {
5✔
125
              toolPath = bin;
2✔
126
            }
127
            this.tool2pathMap.put(tool, toolPath);
6✔
128
          }
129
        }
1✔
130
      } catch (IOException e) {
×
131
        throw new IllegalStateException("Failed to list children of " + softwarePath, e);
×
132
      }
1✔
133
    }
134
  }
1✔
135

136
  private static String getTool(Path path, Path ideRoot) {
137

138
    if (ideRoot == null) {
2✔
139
      return null;
2✔
140
    }
141
    if (path.startsWith(ideRoot)) {
4!
142
      int i = ideRoot.getNameCount();
×
143
      if (path.getNameCount() > i) {
×
144
        return path.getName(i).toString();
×
145
      }
146
    }
147
    return null;
2✔
148
  }
149

150
  private Path findBinaryInOrder(Path path, String tool) {
151

152
    List<String> extensionPriority = List.of("");
3✔
153
    if (SystemInfoImpl.INSTANCE.isWindows()) {
3!
154
      extensionPriority = EXTENSION_PRIORITY;
×
155
    }
156
    for (String extension : extensionPriority) {
10✔
157

158
      Path fileToExecute = path.resolve(tool + extension);
6✔
159

160
      if (Files.exists(fileToExecute)) {
5✔
161
        return fileToExecute;
2✔
162
      }
163
    }
1✔
164

165
    return null;
2✔
166
  }
167

168
  /**
169
   * @param toolPath the {@link Path} to the tool installation.
170
   * @return the {@link Path} to the binary executable of the tool. E.g. is "software/mvn" is given
171
   * "software/mvn/bin/mvn" could be returned.
172
   */
173
  public Path findBinary(Path toolPath) {
174

175
    Path parent = toolPath.getParent();
3✔
176
    String fileName = toolPath.getFileName().toString();
4✔
177

178
    if (parent == null) {
2!
179

180
      for (Path path : tool2pathMap.values()) {
12✔
181
        Path binaryPath = findBinaryInOrder(path, fileName);
5✔
182
        if (binaryPath != null) {
2✔
183
          return binaryPath;
2✔
184
        }
185
      }
1✔
186

187
      for (Path path : this.paths) {
11✔
188
        Path binaryPath = findBinaryInOrder(path, fileName);
5✔
189
        if (binaryPath != null) {
2!
190
          return binaryPath;
×
191
        }
192
      }
2✔
193
    } else {
194
      Path binaryPath = findBinaryInOrder(parent, fileName);
×
195
      if (binaryPath != null) {
×
196
        return binaryPath;
×
197
      }
198
    }
199

200
    return toolPath;
2✔
201
  }
202

203
  /**
204
   * @param tool the name of the tool.
205
   * @return the {@link Path} to the directory of the tool where the binaries can be found or {@code null} if the tool
206
   * is not installed.
207
   */
208
  public Path getPath(String tool) {
209

210
    return this.tool2pathMap.get(tool);
6✔
211
  }
212

213
  /**
214
   * @param tool the name of the tool.
215
   * @param path the new {@link #getPath(String) tool bin path}.
216
   */
217
  public void setPath(String tool, Path path) {
218

219
    this.tool2pathMap.put(tool, path);
6✔
220
  }
1✔
221

222
  @Override
223
  public String toString() {
224

225
    return toString(null);
4✔
226
  }
227

228
  /**
229
   * @param pathSyntax the {@link WindowsPathSyntax} to convert to.
230
   * @return this {@link SystemPath} as {@link String} for the PATH environment variable.
231
   */
232
  public String toString(WindowsPathSyntax pathSyntax) {
233

234
    char separator;
235
    if (pathSyntax == WindowsPathSyntax.MSYS) {
3!
236
      separator = ':';
×
237
    } else {
238
      separator = this.pathSeparator;
3✔
239
    }
240
    StringBuilder sb = new StringBuilder(this.envPath.length() + 128);
9✔
241
    for (Path path : this.tool2pathMap.values()) {
12✔
242
      appendPath(path, sb, separator, pathSyntax);
5✔
243
    }
1✔
244
    for (Path path : this.paths) {
11✔
245
      appendPath(path, sb, separator, pathSyntax);
5✔
246
    }
1✔
247
    return sb.toString();
3✔
248
  }
249

250
  private static void appendPath(Path path, StringBuilder sb, char separator, WindowsPathSyntax pathSyntax) {
251

252
    if (sb.length() > 0) {
3✔
253
      sb.append(separator);
4✔
254
    }
255
    String pathString;
256
    if (pathSyntax == null) {
2!
257
      pathString = path.toString();
4✔
258
    } else {
259
      pathString = pathSyntax.format(path);
×
260
    }
261
    sb.append(pathString);
4✔
262
  }
1✔
263

264
  /**
265
   * Method to validate if a given path string is a Windows path or not
266
   *
267
   * @param pathString The string to check if it is a Windows path string.
268
   * @return {@code true} if it is a valid windows path string, else {@code false}.
269
   */
270
  public static boolean isValidWindowsPath(String pathString) {
271

272
    return REGEX_WINDOWS_PATH.matcher(pathString).matches();
5✔
273
  }
274
}
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