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

devonfw / IDEasy / 9907372175

12 Jul 2024 11:49AM UTC coverage: 61.142% (-0.02%) from 61.162%
9907372175

push

github

hohwille
fixed tests

1997 of 3595 branches covered (55.55%)

Branch coverage included in aggregate %.

5296 of 8333 relevant lines covered (63.55%)

2.8 hits per line

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

73.01
cli/src/main/java/com/devonfw/tools/ide/os/WindowsPathSyntax.java
1
package com.devonfw.tools.ide.os;
2

3
import java.nio.file.Path;
4
import java.util.Locale;
5
import java.util.Objects;
6

7
/**
8
 * Syntax of an absolute {@link Path} on Windows. The standard syntax is obviously {@link #WINDOWS}, however there is also {@link #MSYS} for shells based on
9
 * MSYS like the famous git-bash that uses a linux compatible path syntax.
10
 */
11
public enum WindowsPathSyntax {
3✔
12

13
  /**
14
   * Windows path like "C:\..." or "D:\...".
15
   */
16
  WINDOWS('\\'),
7✔
17

18
  /**
19
   * MSys (git-bash) path like "/c/..." or "/d/...".
20
   */
21
  MSYS('/');
7✔
22

23
  private final char separator;
24

25
  private WindowsPathSyntax(char separator) {
4✔
26
    this.separator = separator;
3✔
27
  }
1✔
28

29
  /**
30
   * @param path the potential path. May be any {@link String}.
31
   * @return the the drive letter (e.g. "C" or "D") or {@code null} if the given {@link String} is not a path in this {@link WindowsPathSyntax}.
32
   */
33
  public String getDrive(String path) {
34

35
    if ((path != null) && (path.length() >= 3)) {
6✔
36
      char c0 = path.charAt(0);
4✔
37
      char c1 = path.charAt(1);
4✔
38
      char c2 = path.charAt(2);
4✔
39
      switch (this) {
5!
40
        case WINDOWS: // 'C:\'
41
          if ((c1 == ':') && isSlash(c2) && (c0 >= 'A') && (c0 <= 'Z')) {
12!
42
            return Character.toString(c0);
3✔
43
          }
44
          break;
45
        case MSYS: // '/c/'
46
          if ((c0 == '/') && (c2 == '/') && isLowerLatinLetter(c1)) {
9!
47
            return Character.toString(c1);
3✔
48
          }
49
          break;
50
        default:
51
          throw new IllegalArgumentException(toString());
×
52
      }
53
    }
54
    return null;
2✔
55
  }
56

57
  private static boolean isSlash(char c2) {
58
    // on Windows both slash (/) and backslash (\) are acceptable as folder separator in a Path
59
    // While strict Windows syntax is to use backslash we are tolerant here so our Windows users can also configure
60
    // a path in ide.properties using slashes since backslash is the escape character in Java properties files and then
61
    // users have to use double backslash.
62
    return (c2 == '\\') || (c2 == '/');
6!
63
  }
64

65
  private static boolean isLowerLatinLetter(char c) {
66

67
    return (c >= 'a') && (c <= 'z');
9!
68
  }
69

70
  /**
71
   * @param path the {@link Path} to format.
72
   * @return the given {@link Path} formatted as {@link String} to this {@link WindowsPathSyntax}.
73
   */
74
  public String format(Path path) {
75

76
    if (path == null) {
2!
77
      return null;
×
78
    }
79
    int nameCount = path.getNameCount();
3✔
80
    StringBuilder sb = new StringBuilder(nameCount * 6);
7✔
81
    int start = formatRootPath(path, sb);
5✔
82
    for (int i = start; i < nameCount; i++) {
7✔
83
      if (i > 0) {
2✔
84
        sb.append(this.separator);
5✔
85
      }
86
      Path segment = path.getName(i);
4✔
87
      sb.append(segment);
4✔
88
    }
89
    return sb.toString();
3✔
90
  }
91

92
  private int formatRootPath(Path path, StringBuilder sb) {
93

94
    Path root = path.getRoot();
3✔
95
    if (root == null) {
2✔
96
      return 0;
2✔
97
    }
98
    String rootString = root.toString();
3✔
99
    int length = rootString.length();
3✔
100
    if ((length == 3) && (rootString.charAt(1) == ':') && (rootString.charAt(2) == '\\')) {
3!
101
      // so we have a WINDOWS driver letter as root
102
      char drive = Character.toLowerCase(rootString.charAt(0));
×
103
      if (isLowerLatinLetter(drive)) {
×
104
        if (this == MSYS) {
×
105
          sb.append(this.separator);
×
106
          sb.append(drive);
×
107
          sb.append(this.separator);
×
108
        } else {
109
          sb.append(rootString); // nothing to convert from WINDOWS to WINDOWS
×
110
        }
111
        return 0;
×
112
      }
113
    }
114
    if ((length == 1) && (this == WINDOWS)) {
6!
115
      if (path.getNameCount() > 0) {
3!
116
        root = path.getName(0);
4✔
117
        String drive = root.toString();
3✔
118
        if (drive.length() == 1) {
4✔
119
          char c = drive.charAt(0);
4✔
120
          if ((isLowerLatinLetter(c))) {
3!
121
            // so we have a path starting with a driver letter in MSYS syntax (e.g. "/c/") but want WINDOWS syntax
122
            sb.append(Character.toUpperCase(c));
5✔
123
            sb.append(':');
4✔
124
            return 1;
2✔
125
          }
126
        }
127
      }
128
    }
129
    sb.append(this.separator);
5✔
130
    if (length > 1) {
3!
131
      // this should actually never happen and only exists for robustness in odd edge-cases
132
      sb.append(rootString, 1, length);
×
133
      sb.append(this.separator);
×
134
    }
135
    return 0;
2✔
136
  }
137

138
  /**
139
   * @param path the path where to replace the drive letter.
140
   * @param drive the new {@link #getDrive(String) drive letter}.
141
   * @return the new path pointing to the given {@code drive} in this {@link WindowsPathSyntax}.
142
   */
143
  public String normalize(String path, String drive) {
144

145
    Objects.requireNonNull(path);
3✔
146
    Objects.requireNonNull(drive);
3✔
147
    if (path.length() < 3) {
4!
148
      throw new IllegalArgumentException(path);
×
149
    }
150
    String restPath = path.substring(3);
4✔
151
    restPath = switch (this) {
5!
152
      case WINDOWS -> restPath.replace('/', '\\');
5✔
153
      case MSYS -> restPath.replace('\\', '/');
5✔
154
      default -> throw new IllegalStateException(toString());
1✔
155
    };
156
    return getRootPath(drive) + restPath;
6✔
157
  }
158

159
  public String normalize(String value) {
160

161
    String drive = WindowsPathSyntax.WINDOWS.getDrive(value);
4✔
162
    if (drive == null) {
2✔
163
      drive = WindowsPathSyntax.MSYS.getDrive(value);
4✔
164
    }
165
    if (drive != null) {
2✔
166
      value = normalize(value, drive);
5✔
167
    }
168
    return value;
2✔
169
  }
170

171
  /**
172
   * @param drive the drive letter (e.g. "C" or "D").
173
   * @return the root path for the given {@code drive} (e.g. "C:\\" or "/c/").
174
   */
175
  public String getRootPath(String drive) {
176

177
    Objects.requireNonNull(drive);
3✔
178
    if ((drive.length() != 1) || !isLowerLatinLetter(Character.toLowerCase(drive.charAt(0)))) {
10!
179
      throw new IllegalArgumentException(drive);
×
180
    }
181
    return switch (this) {
6!
182
      case WINDOWS -> drive.toUpperCase(Locale.ROOT) + ":\\";
5✔
183
      case MSYS -> "/" + drive.toLowerCase(Locale.ROOT) + "/";
5✔
184
      default -> throw new IllegalStateException(toString());
×
185
    };
186
  }
187

188
  /**
189
   * Normalizes a {@link String} that may be an absolute Windows {@link Path}.
190
   *
191
   * @param value the {@link String} to normalize.
192
   * @param bash - {@code true} to convert paths to {@link #MSYS} (git-bash), {@code false} for {@link #WINDOWS}.
193
   * @return the given {@code value} that was normalized if it has been an absolute Windows {@link Path}.
194
   */
195
  public static String normalize(String value, boolean bash) {
196

197
    WindowsPathSyntax targetSyntax;
198
    if (bash) {
2✔
199
      targetSyntax = WindowsPathSyntax.MSYS;
3✔
200
    } else {
201
      targetSyntax = WindowsPathSyntax.WINDOWS;
2✔
202
    }
203
    return targetSyntax.normalize(value);
4✔
204
  }
205
}
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