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

devonfw / IDEasy / 8111080112

01 Mar 2024 12:07PM UTC coverage: 58.254% (+1.1%) from 57.131%
8111080112

push

github

web-flow
#9: background process (#200)

1519 of 2867 branches covered (52.98%)

Branch coverage included in aggregate %.

3954 of 6528 relevant lines covered (60.57%)

2.62 hits per line

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

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

3
import java.io.File;
4
import java.io.IOException;
5
import java.nio.file.Files;
6
import java.nio.file.Path;
7
import java.util.ArrayList;
8
import java.util.HashMap;
9
import java.util.Iterator;
10
import java.util.List;
11
import java.util.Map;
12
import java.util.regex.Pattern;
13
import java.util.stream.Stream;
14

15
import com.devonfw.tools.ide.context.IdeContext;
16

17
/**
18
 * Represents the PATH variable in a structured way.
19
 */
20
public class SystemPath {
21

22
  private final String envPath;
23

24
  private final char pathSeparator;
25

26
  private final Map<String, Path> tool2pathMap;
27

28
  private final List<Path> paths;
29

30
  private final IdeContext context;
31

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

34
  /**
35
   * The constructor.
36
   *
37
   * @param envPath the value of the PATH variable.
38
   * @param softwarePath the {@link IdeContext#getSoftwarePath() software path}.
39
   * @param context {@link IdeContext} for the output of information.
40
   */
41
  public SystemPath(String envPath, Path softwarePath, IdeContext context) {
42

43
    this(envPath, softwarePath, File.pathSeparatorChar, context);
6✔
44
  }
1✔
45

46
  /**
47
   * The constructor.
48
   *
49
   * @param envPath the value of the PATH variable.
50
   * @param softwarePath the {@link IdeContext#getSoftwarePath() software path}.
51
   * @param pathSeparator the path separator char (';' for Windows and ':' otherwise).
52
   * @param context {@link IdeContext} for the output of information.
53
   */
54
  public SystemPath(String envPath, Path softwarePath, char pathSeparator, IdeContext context) {
55

56
    super();
2✔
57
    this.context = context;
3✔
58
    this.envPath = envPath;
3✔
59
    this.pathSeparator = pathSeparator;
3✔
60
    this.tool2pathMap = new HashMap<>();
5✔
61
    this.paths = new ArrayList<>();
5✔
62
    String[] envPaths = envPath.split(Character.toString(pathSeparator));
5✔
63
    for (String segment : envPaths) {
16✔
64
      Path path = Path.of(segment);
5✔
65
      String tool = getTool(path, softwarePath);
4✔
66
      if (tool == null) {
2!
67
        this.paths.add(path);
6✔
68
      } else {
69
        Path duplicate = this.tool2pathMap.putIfAbsent(tool, path);
×
70
        if (duplicate != null) {
×
71
          context.warning("Duplicated tool path for tool: {} at path: {} with duplicated path: {}.", tool, path,
×
72
              duplicate);
73
        }
74
      }
75
    }
76
    collectToolPath(softwarePath);
3✔
77
  }
1✔
78

79
  private void collectToolPath(Path softwarePath) {
80

81
    if (softwarePath == null) {
2✔
82
      return;
1✔
83
    }
84
    if (Files.isDirectory(softwarePath)) {
5!
85
      try (Stream<Path> children = Files.list(softwarePath)) {
3✔
86
        Iterator<Path> iterator = children.iterator();
3✔
87
        while (iterator.hasNext()) {
3✔
88
          Path child = iterator.next();
4✔
89
          if (Files.isDirectory(child)) {
5!
90
            Path toolPath = child;
2✔
91
            Path bin = child.resolve("bin");
4✔
92
            if (Files.isDirectory(bin)) {
5!
93
              toolPath = bin;
2✔
94
            }
95
            this.paths.add(0, toolPath);
5✔
96
            this.tool2pathMap.put(child.getFileName().toString(), toolPath);
8✔
97
          }
98
        }
1✔
99
      } catch (IOException e) {
×
100
        throw new IllegalStateException("Failed to list children of " + softwarePath, e);
×
101
      }
1✔
102
    }
103
  }
1✔
104

105
  private static String getTool(Path path, Path softwarePath) {
106

107
    if (softwarePath == null) {
2✔
108
      return null;
2✔
109
    }
110
    if (path.startsWith(softwarePath)) {
4!
111
      int i = softwarePath.getNameCount();
×
112
      if (path.getNameCount() > i) {
×
113
        return path.getName(i).toString();
×
114
      }
115
    }
116
    return null;
2✔
117
  }
118

119
  private Path findBinaryInOrder(Path path, String tool) {
120

121
    for (String extension : EXTENSION_PRIORITY) {
×
122

123
      Path fileToExecute = path.resolve(tool + extension);
×
124

125
      if (Files.exists(fileToExecute)) {
×
126
        return fileToExecute;
×
127
      }
128
    }
×
129

130
    return null;
×
131
  }
132

133
  /**
134
   * @param toolPath the {@link Path} to the tool installation.
135
   * @return the {@link Path} to the binary executable of the tool. E.g. is "software/mvn" is given
136
   *         "software/mvn/bin/mvn" could be returned.
137
   */
138
  public Path findBinary(Path toolPath) {
139

140
    Path parent = toolPath.getParent();
×
141
    String fileName = toolPath.getFileName().toString();
×
142

143
    if (parent == null) {
×
144

145
      for (Path path : tool2pathMap.values()) {
×
146
        Path binaryPath = findBinaryInOrder(path, fileName);
×
147
        if (binaryPath != null) {
×
148
          return binaryPath;
×
149
        }
150
      }
×
151

152
      for (Path path : this.paths) {
×
153
        Path binaryPath = findBinaryInOrder(path, fileName);
×
154
        if (binaryPath != null) {
×
155
          return binaryPath;
×
156
        }
157
      }
×
158
    } else {
159
      Path binaryPath = findBinaryInOrder(parent, fileName);
×
160
      if (binaryPath != null) {
×
161
        return binaryPath;
×
162
      }
163
    }
164

165
    return toolPath;
×
166
  }
167

168
  /**
169
   * @param tool the name of the tool.
170
   * @return the {@link Path} to the directory of the tool where the binaries can be found or {@code null} if the tool
171
   *         is not installed.
172
   */
173
  public Path getPath(String tool) {
174

175
    return this.tool2pathMap.get(tool);
6✔
176
  }
177

178
  /**
179
   * @param tool the name of the tool.
180
   * @param path the new {@link #getPath(String) tool bin path}.
181
   */
182
  public void setPath(String tool, Path path) {
183

184
    this.tool2pathMap.put(tool, path);
6✔
185
  }
1✔
186

187
  @Override
188
  public String toString() {
189

190
    return toString(false);
4✔
191
  }
192

193
  /**
194
   * @param bash - {@code true} to convert the PATH to bash syntax (relevant for git-bash or cygwin on windows),
195
   *        {@code false} otherwise.
196
   * @return this {@link SystemPath} as {@link String} for the PATH environment variable.
197
   */
198
  public String toString(boolean bash) {
199

200
    char separator;
201
    if (bash) {
2!
202
      separator = ':';
×
203
    } else {
204
      separator = this.pathSeparator;
3✔
205
    }
206
    StringBuilder sb = new StringBuilder(this.envPath.length() + 128);
9✔
207
    for (Path path : this.tool2pathMap.values()) {
12✔
208
      appendPath(path, sb, separator, bash);
5✔
209
    }
1✔
210
    for (Path path : this.paths) {
11✔
211
      appendPath(path, sb, separator, bash);
5✔
212
    }
1✔
213
    return sb.toString();
3✔
214
  }
215

216
  private static void appendPath(Path path, StringBuilder sb, char separator, boolean bash) {
217

218
    if (sb.length() > 0) {
3✔
219
      sb.append(separator);
4✔
220
    }
221
    String pathString = path.toString();
3✔
222
    if (bash && (pathString.length() > 3) && (pathString.charAt(1) == ':')) {
2!
223
      pathString = convertWindowsPathToUnixPath(pathString);
×
224
    }
225
    sb.append(pathString);
4✔
226
  }
1✔
227

228
  /**
229
   * Method to convert a valid Windows path string representation to its corresponding one in Unix format.
230
   * 
231
   * @param pathString The Windows path string to convert.
232
   * @return The converted Unix path string.
233
   */
234
  public static String convertWindowsPathToUnixPath(String pathString) {
235

236
    char slash = pathString.charAt(2);
4✔
237
    if ((slash == '\\') || (slash == '/')) {
3!
238
      char drive = Character.toLowerCase(pathString.charAt(0));
5✔
239
      if ((drive >= 'a') && (drive <= 'z')) {
6!
240
        pathString = "/" + drive + pathString.substring(2).replace('\\', '/');
9✔
241
      }
242
    }
243
    return pathString;
2✔
244
  }
245

246
  /**
247
   * Method to validate if a given path string is a Windows path or not
248
   * 
249
   * @param pathString The string to check if it is a Windows path string.
250
   * @return {@code true} if it is a valid windows path string, else {@code false}.
251
   */
252
  public static boolean isValidWindowsPath(String pathString) {
253

254
    String windowsFilePathRegEx = "([a-zA-Z]:)?(\\\\[a-zA-Z0-9\\s_.-]+)+\\\\?";
2✔
255
    return Pattern.matches(windowsFilePathRegEx, pathString);
4✔
256
  }
257
}
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