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

devonfw / IDEasy / 13063267543

30 Jan 2025 11:34PM UTC coverage: 68.379% (-0.2%) from 68.557%
13063267543

push

github

web-flow
#954: improve repository support (#990)

Co-authored-by: jan-vcapgemini <59438728+jan-vcapgemini@users.noreply.github.com>
Co-authored-by: jan-vcapgemini <jan-vincent.hoelzle@capgemini.com>

2857 of 4597 branches covered (62.15%)

Branch coverage included in aggregate %.

7391 of 10390 relevant lines covered (71.14%)

3.1 hits per line

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

82.14
cli/src/main/java/com/devonfw/tools/ide/io/FileAccess.java
1
package com.devonfw.tools.ide.io;
2

3
import java.io.IOException;
4
import java.io.Reader;
5
import java.io.Writer;
6
import java.nio.file.Files;
7
import java.nio.file.Path;
8
import java.nio.file.attribute.PosixFilePermission;
9
import java.util.List;
10
import java.util.Properties;
11
import java.util.Set;
12
import java.util.function.Consumer;
13
import java.util.function.Function;
14
import java.util.function.Predicate;
15

16
/**
17
 * Interface that gives access to various operations on files.
18
 */
19
public interface FileAccess {
20

21
  /** {@link PosixFilePermission}s for "rwxr-xr-x" or 0755. */
22
  Set<PosixFilePermission> RWX_RX_RX = Set.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE, PosixFilePermission.OWNER_EXECUTE,
10✔
23
      PosixFilePermission.GROUP_READ, PosixFilePermission.GROUP_EXECUTE, PosixFilePermission.OTHERS_READ, PosixFilePermission.OTHERS_EXECUTE);
24

25
  /**
26
   * Downloads a file from an arbitrary location.
27
   *
28
   * @param url the location of the binary file to download. May also be a local or remote path to copy from.
29
   * @param targetFile the {@link Path} to the target file to download to. Should not already exist. Missing parent directories will be created
30
   *     automatically.
31
   */
32
  void download(String url, Path targetFile);
33

34
  /**
35
   * Creates the entire {@link Path} as directories if not already existing.
36
   *
37
   * @param directory the {@link Path} to {@link java.nio.file.Files#createDirectories(Path, java.nio.file.attribute.FileAttribute...) create}.
38
   */
39
  void mkdirs(Path directory);
40

41
  /**
42
   * @param file the {@link Path} to check.
43
   * @return {@code true} if the given {@code file} points to an existing file, {@code false} otherwise (the given {@link Path} does not exist or is a
44
   *     directory).
45
   */
46
  boolean isFile(Path file);
47

48
  /**
49
   * @param folder the {@link Path} to check.
50
   * @return {@code true} if the given {@code folder} points to an existing directory, {@code false} otherwise (a warning is logged in this case).
51
   */
52
  boolean isExpectedFolder(Path folder);
53

54
  /**
55
   * @param file the {@link Path} to compute the checksum of.
56
   * @return the computed checksum (SHA-266).
57
   */
58
  String checksum(Path file);
59

60
  /**
61
   * Moves the given {@link Path} to the backup.
62
   *
63
   * @param fileOrFolder the {@link Path} to move to the backup (soft-deletion).
64
   */
65
  void backup(Path fileOrFolder);
66

67
  /**
68
   * @param source the source {@link Path file or folder} to move.
69
   * @param targetDir the {@link Path} with the directory to move {@code source} into.
70
   */
71
  void move(Path source, Path targetDir);
72

73
  /**
74
   * Creates a symbolic link. If the given {@code targetLink} already exists and is a symbolic link or a Windows junction, it will be replaced. In case of
75
   * missing privileges, Windows Junctions may be used as fallback, which must point to absolute paths. Therefore, the created link will be absolute instead of
76
   * relative.
77
   *
78
   * @param source the source {@link Path} to link to, may be relative or absolute.
79
   * @param targetLink the {@link Path} where the symbolic link shall be created pointing to {@code source}.
80
   * @param relative - {@code true} if the symbolic link shall be relative, {@code false} if it shall be absolute.
81
   */
82
  void symlink(Path source, Path targetLink, boolean relative);
83

84
  /**
85
   * Creates a relative symbolic link. If the given {@code targetLink} already exists and is a symbolic link or a Windows junction, it will be replaced. In case
86
   * of missing privileges, Windows Junctions may be used as fallback, which must point to absolute paths. Therefore, the created link will be absolute instead
87
   * of relative.
88
   *
89
   * @param source the source {@link Path} to link to, may be relative or absolute.
90
   * @param targetLink the {@link Path} where the symbolic link shall be created pointing to {@code source}.
91
   */
92
  default void symlink(Path source, Path targetLink) {
93

94
    symlink(source, targetLink, true);
5✔
95
  }
1✔
96

97
  /**
98
   * @param source the source {@link Path file or folder} to copy.
99
   * @param target the {@link Path} to copy {@code source} to. See {@link #copy(Path, Path, FileCopyMode)} for details. Will always ensure that in the end
100
   *     you will find the same content of {@code source} in {@code target}.
101
   */
102
  default void copy(Path source, Path target) {
103

104
    copy(source, target, FileCopyMode.COPY_TREE_FAIL_IF_EXISTS);
5✔
105
  }
1✔
106

107
  /**
108
   * @param source the source {@link Path file or folder} to copy.
109
   * @param target the {@link Path} to copy {@code source} to. Unlike the Linux {@code cp} command this method will not take the filename of {@code source}
110
   *     and copy that to {@code target} in case that is an existing folder. Instead it will always be simple and stupid and just copy from {@code source} to
111
   *     {@code target}. Therefore the result is always clear and easy to predict and understand. Also you can easily rename a file to copy. While
112
   *     {@code cp my-file target} may lead to a different result than {@code cp my-file target/} this method will always ensure that in the end you will find
113
   *     the same content of {@code source} in {@code target}.
114
   * @param mode the {@link FileCopyMode}.
115
   */
116
  default void copy(Path source, Path target, FileCopyMode mode) {
117

118
    copy(source, target, mode, PathCopyListener.NONE);
6✔
119
  }
1✔
120

121
  /**
122
   * @param source the source {@link Path file or folder} to copy.
123
   * @param target the {@link Path} to copy {@code source} to. Unlike the Linux {@code cp} command this method will not take the filename of {@code source}
124
   *     and copy that to {@code target} in case that is an existing folder. Instead it will always be simple and stupid and just copy from {@code source} to
125
   *     {@code target}. Therefore the result is always clear and easy to predict and understand. Also you can easily rename a file to copy. While
126
   *     {@code cp my-file target} may lead to a different result than {@code cp my-file target/} this method will always ensure that in the end you will find
127
   *     the same content of {@code source} in {@code target}.
128
   * @param mode the {@link FileCopyMode}.
129
   * @param listener the {@link PathCopyListener} that will be called for each copied {@link Path}.
130
   */
131
  void copy(Path source, Path target, FileCopyMode mode, PathCopyListener listener);
132

133
  /**
134
   * @param archiveFile the {@link Path} to the file to extract.
135
   * @param targetDir the {@link Path} to the directory where to extract the {@code archiveFile} to.
136
   */
137
  default void extract(Path archiveFile, Path targetDir) {
138

139
    extract(archiveFile, targetDir, null);
5✔
140
  }
1✔
141

142
  /**
143
   * @param archiveFile the {@link Path} to the archive file to extract.
144
   * @param targetDir the {@link Path} to the directory where to extract the {@code archiveFile}.
145
   * @param postExtractHook the {@link Consumer} to be called after the extraction on the final folder before it is moved to {@code targetDir}.
146
   */
147
  default void extract(Path archiveFile, Path targetDir, Consumer<Path> postExtractHook) {
148

149
    extract(archiveFile, targetDir, postExtractHook, true);
6✔
150
  }
1✔
151

152
  /**
153
   * @param archiveFile the {@link Path} to the archive file to extract.
154
   * @param targetDir the {@link Path} to the directory where to extract the {@code archiveFile}.
155
   * @param postExtractHook the {@link Consumer} to be called after the extraction on the final folder before it is moved to {@code targetDir}.
156
   * @param extract {@code true} if the {@code archiveFile} should be extracted (default), {@code false} otherwise.
157
   */
158
  void extract(Path archiveFile, Path targetDir, Consumer<Path> postExtractHook, boolean extract);
159

160
  /**
161
   * Extracts a ZIP file what is the common archive format on Windows. Initially invented by PKZIP for MS-DOS and also famous from WinZIP software for Windows.
162
   *
163
   * @param file the ZIP file to extract.
164
   * @param targetDir the {@link Path} with the directory to unzip to.
165
   */
166
  void extractZip(Path file, Path targetDir);
167

168
  /**
169
   * @param file the ZIP file to extract.
170
   * @param targetDir the {@link Path} with the directory to unzip to.
171
   * @param compression the {@link TarCompression} to use.
172
   */
173
  void extractTar(Path file, Path targetDir, TarCompression compression);
174

175
  /**
176
   * @param file the JAR file to extract.
177
   * @param targetDir the {@link Path} with the directory to extract to.
178
   */
179
  void extractJar(Path file, Path targetDir);
180

181
  /**
182
   * Extracts an Apple DMG (Disk Image) file that is similar to an ISO image. DMG files are commonly used for software releases on MacOS. Double-clicking such
183
   * files on MacOS mounts them and show the application together with a symbolic link to the central applications folder and some help instructions. The user
184
   * then copies the application to the applications folder via drag and drop in order to perform the installation.
185
   *
186
   * @param file the DMG file to extract.
187
   * @param targetDir the target directory where to extract the contents to.
188
   */
189
  void extractDmg(Path file, Path targetDir);
190

191
  /**
192
   * Extracts an MSI (Microsoft Installer) file. MSI files are commonly used for software releases on Windows that allow an installation wizard and easy later
193
   * uninstallation.
194
   *
195
   * @param file the MSI file to extract.
196
   * @param targetDir the target directory where to extract the contents to.
197
   */
198
  void extractMsi(Path file, Path targetDir);
199

200
  /**
201
   * Extracts an Apple PKG (Package) file. PKG files are used instead of {@link #extractDmg(Path, Path) DMG files} if additional changes have to be performed
202
   * like drivers to be installed. Similar to what {@link #extractMsi(Path, Path) MSI} is on Windows. PKG files are internally a xar based archive with a
203
   * specific structure.
204
   *
205
   * @param file the PKG file to extract.
206
   * @param targetDir the target directory where to extract the contents to.
207
   */
208
  void extractPkg(Path file, Path targetDir);
209

210
  /**
211
   * @param path the {@link Path} to convert.
212
   * @return the absolute and physical {@link Path} (without symbolic links).
213
   */
214
  Path toRealPath(Path path);
215

216
  /**
217
   * Deletes the given {@link Path} idempotent and recursive.
218
   * <p>
219
   * ATTENTION: In most cases we want to use {@link #backup(Path)} instead to prevent the user from data loss.
220
   * </p>
221
   *
222
   * @param path the {@link Path} to delete.
223
   */
224
  void delete(Path path);
225

226
  /**
227
   * Creates a new temporary directory. ATTENTION: The user of this method is responsible to do house-keeping and {@link #delete(Path) delete} it after the work
228
   * is done.
229
   *
230
   * @param name the default name of the temporary directory to create. A prefix or suffix may be added to ensure uniqueness.
231
   * @return the {@link Path} to the newly created and unique temporary directory.
232
   */
233
  Path createTempDir(String name);
234

235
  /**
236
   * @param dir the folder to search.
237
   * @param filter the {@link Predicate} used to find the {@link Predicate#test(Object) match}.
238
   * @param recursive - {@code true} to search recursive in all sub-folders, {@code false} otherwise.
239
   * @return the first child {@link Path} matching the given {@link Predicate} or {@code null} if no match was found.
240
   */
241
  Path findFirst(Path dir, Predicate<Path> filter, boolean recursive);
242

243
  /**
244
   * @param dir the {@link Path} to the directory where to list the children.
245
   * @param filter the {@link Predicate} used to {@link Predicate#test(Object) decide} which children to include (if {@code true} is returned).
246
   * @return all children of the given {@link Path} that match the given {@link Predicate}. Will be the empty list of the given {@link Path} is not an existing
247
   *     directory.
248
   */
249
  default List<Path> listChildren(Path dir, Predicate<Path> filter) {
250

251
    return listChildrenMapped(dir, child -> (filter.test(child)) ? child : null);
13!
252
  }
253

254
  /**
255
   * @param dir the {@link Path} to the directory where to list the children.
256
   * @param filter the filter {@link Function} used to {@link Function#apply(Object) filter and transform} children to include. If the {@link Function}
257
   *     returns  {@code null}, the child will be filtered, otherwise the returned {@link Path} will be included in the resulting {@link List}.
258
   * @return all children of the given {@link Path} returned by the given {@link Function}. Will be the empty list if the given {@link Path} is not an existing
259
   *     directory.
260
   */
261
  List<Path> listChildrenMapped(Path dir, Function<Path, Path> filter);
262

263
  /**
264
   * Finds the existing file with the specified name in the given list of directories.
265
   *
266
   * @param fileName The name of the file to find.
267
   * @param searchDirs The list of directories to search for the file.
268
   * @return The {@code Path} of the existing file, or {@code null} if the file is not found.
269
   */
270
  Path findExistingFile(String fileName, List<Path> searchDirs);
271

272
  /**
273
   * Checks if the given directory is empty.
274
   *
275
   * @param dir The {@link Path} object representing the directory to check.
276
   * @return {@code true} if the directory is empty, {@code false} otherwise.
277
   */
278
  boolean isEmptyDir(Path dir);
279

280
  /**
281
   * Makes a file executable (analog to 'chmod a+x').
282
   *
283
   * @param file {@link Path} to the file.
284
   */
285
  default void makeExecutable(Path file) {
286

287
    makeExecutable(file, false);
4✔
288
  }
1✔
289

290
  /**
291
   * Makes a file executable (analog to 'chmod a+x').
292
   *
293
   * @param file {@link Path} to the file.
294
   * @param confirm - {@code true} to get user confirmation before adding missing executable flags, {@code false} otherwise (always set missing flags).
295
   */
296
  void makeExecutable(Path file, boolean confirm);
297

298
  /**
299
   * Like the linux touch command this method will update the modification time of the given {@link Path} to the current
300
   * {@link System#currentTimeMillis() system time}. In case the file does not exist, it will be created as empty file. If already the
301
   * {@link Path#getParent() parent folder} does not exist, the operation will fail.
302
   *
303
   * @param file the {@link Path} to the file or folder.
304
   */
305
  void touch(Path file);
306

307
  /**
308
   * @param file the {@link Path} to the file to read.
309
   * @return the content of the specified file (in UTF-8 encoding).
310
   * @see java.nio.file.Files#readString(Path)
311
   */
312
  String readFileContent(Path file);
313

314
  /**
315
   * @param content the {@link String} with the text to write to a file.
316
   * @param file the {@link Path} to the file where to save.
317
   */
318
  void writeFileContent(String content, Path file);
319

320
  /**
321
   * @param path that is checked whether it is a junction or not.
322
   * @return {@code true} if the given {@link Path} is a junction, false otherwise.
323
   */
324
  boolean isJunction(Path path);
325

326
  /**
327
   * @param file the {@link Path} to the {@link Properties} file to read.
328
   * @return the parsed {@link Properties}.
329
   */
330
  default Properties readProperties(Path file) {
331

332
    Properties properties = new Properties();
4✔
333
    try (Reader reader = Files.newBufferedReader(file)) {
3✔
334
      properties.load(reader);
3✔
335
      return properties;
4✔
336
    } catch (IOException e) {
×
337
      throw new IllegalStateException("Failed to read properties file: " + file, e);
×
338
    }
339
  }
340

341
  /**
342
   * @param properties the {@link Properties} to save.
343
   * @param file the {@link Path} to the file where to save the properties.
344
   */
345
  default void writeProperties(Properties properties, Path file) {
346

347
    try (Writer writer = Files.newBufferedWriter(file)) {
5✔
348
      properties.store(writer, null);
4✔
349
    } catch (IOException e) {
×
350
      throw new IllegalStateException("Failed to save properties file during tests.", e);
×
351
    }
1✔
352
  }
1✔
353

354
}
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