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

devonfw / IDEasy / 8144002629

04 Mar 2024 04:56PM UTC coverage: 58.928% (+0.7%) from 58.254%
8144002629

push

github

web-flow
#208: improve test infrastructure # 219: fix wrong executable (#238)

* Add first implementation

* Add javadoc

* Add javadoc

* Using target path instead of ressource path to make sure one-to-one copy of set up folders is used

* Add JavaDoc and mac mock program

* Add support for multiple dependencies while testing

* Minor changes

* Modify mock programs for testing

* Refactored example JmcTest

* Add possibility to set execution path by using the context

* Reenable test after related issue 228 has been merged

* Replace ternary with regular if

* Add missing javadoc

* Add missing javadoc

* remove unnecessary semicolon

* Fix spelling typo

* Minor test changes

* Refactoring FileExtractor class for more modularity

* using const

* Add missing extensions

* Remove unnecessary execption declaration and minor rename

* Fix spelling

* Add javadoc

* Forget dot

* minor change

* Revert "minor change"

This reverts commit ec81c3ce6.

* Revert "Merge branch 'main' into feature/208-MockOutToolRepoRefactorTestInfra"

This reverts commit d58847230, reversing
changes made to f38b3105f.

* Revert "Revert "Merge branch 'main' into feature/208-MockOutToolRepoRefactorTestInfra""

This reverts commit 3e49a0b3d.

* Revert "Revert "minor change""

This reverts commit 2f7b94624.

* fix typo

* #208: review and complete rework

* #208: improved system path

* #208: found and fixed bug on windows

* #208: improve OS mocking

* #208: improve test logging

reveal logs/errors so the developer actually sees what is happening instead of leaving them in the dark

* #208: improve OS detection

* #208: fixed

found and fixed bug in MacOS app detection for JMC, fixed copy file to folder bug, moved !extract logic back to FileAccess, f... (continued)

1580 of 2930 branches covered (53.92%)

Branch coverage included in aggregate %.

4047 of 6619 relevant lines covered (61.14%)

2.65 hits per line

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

69.7
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.variable.IdeVariables;
6

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

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

33
  private final String envPath;
34

35
  private final char pathSeparator;
36

37
  private final Map<String, Path> tool2pathMap;
38

39
  private final List<Path> paths;
40

41
  private final IdeContext context;
42

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

45
  /**
46
   * The constructor.
47
   *
48
   * @param context {@link IdeContext}.
49
   */
50
  public SystemPath(IdeContext context) {
51

52
    this(context, System.getenv(IdeVariables.PATH.getName()));
6✔
53
  }
1✔
54

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

63
    this(context, envPath, context.getIdeRoot(), context.getSoftwarePath());
8✔
64
  }
1✔
65

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

76
    this(context, envPath, ideRoot, softwarePath, File.pathSeparatorChar);
7✔
77
  }
1✔
78

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

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

107
  private void collectToolPath(Path softwarePath) {
108

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

133
  private static String getTool(Path path, Path ideRoot) {
134

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

147
  private Path findBinaryInOrder(Path path, String tool) {
148

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

155
      Path fileToExecute = path.resolve(tool + extension);
6✔
156

157
      if (Files.exists(fileToExecute)) {
5!
158
        return fileToExecute;
2✔
159
      }
160
    }
×
161

162
    return null;
×
163
  }
164

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

172
    Path parent = toolPath.getParent();
3✔
173
    String fileName = toolPath.getFileName().toString();
4✔
174

175
    if (parent == null) {
2!
176

177
      for (Path path : tool2pathMap.values()) {
12!
178
        Path binaryPath = findBinaryInOrder(path, fileName);
5✔
179
        if (binaryPath != null) {
2!
180
          return binaryPath;
2✔
181
        }
182
      }
×
183

184
      for (Path path : this.paths) {
×
185
        Path binaryPath = findBinaryInOrder(path, fileName);
×
186
        if (binaryPath != null) {
×
187
          return binaryPath;
×
188
        }
189
      }
×
190
    } else {
191
      Path binaryPath = findBinaryInOrder(parent, fileName);
×
192
      if (binaryPath != null) {
×
193
        return binaryPath;
×
194
      }
195
    }
196

197
    return toolPath;
×
198
  }
199

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

207
    return this.tool2pathMap.get(tool);
6✔
208
  }
209

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

216
    this.tool2pathMap.put(tool, path);
6✔
217
  }
1✔
218

219
  @Override
220
  public String toString() {
221

222
    return toString(false);
4✔
223
  }
224

225
  /**
226
   * @param bash - {@code true} to convert the PATH to bash syntax (relevant for git-bash or cygwin on windows),
227
   * {@code false} otherwise.
228
   * @return this {@link SystemPath} as {@link String} for the PATH environment variable.
229
   */
230
  public String toString(boolean bash) {
231

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

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

250
    if (sb.length() > 0) {
3✔
251
      sb.append(separator);
4✔
252
    }
253
    String pathString = path.toString();
3✔
254
    if (bash && (pathString.length() > 3) && (pathString.charAt(1) == ':')) {
2!
255
      pathString = convertWindowsPathToUnixPath(pathString);
×
256
    }
257
    sb.append(pathString);
4✔
258
  }
1✔
259

260
  /**
261
   * Method to convert a valid Windows path string representation to its corresponding one in Unix format.
262
   *
263
   * @param pathString The Windows path string to convert.
264
   * @return The converted Unix path string.
265
   */
266
  public static String convertWindowsPathToUnixPath(String pathString) {
267

268
    char slash = pathString.charAt(2);
4✔
269
    if ((slash == '\\') || (slash == '/')) {
3!
270
      char drive = Character.toLowerCase(pathString.charAt(0));
5✔
271
      if ((drive >= 'a') && (drive <= 'z')) {
6!
272
        pathString = "/" + drive + pathString.substring(2).replace('\\', '/');
9✔
273
      }
274
    }
275
    return pathString;
2✔
276
  }
277

278
  /**
279
   * Method to validate if a given path string is a Windows path or not
280
   *
281
   * @param pathString The string to check if it is a Windows path string.
282
   * @return {@code true} if it is a valid windows path string, else {@code false}.
283
   */
284
  public static boolean isValidWindowsPath(String pathString) {
285

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