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

devonfw / IDEasy / 15932029172

27 Jun 2025 05:13PM UTC coverage: 68.261% (+0.009%) from 68.252%
15932029172

Pull #1348

github

web-flow
Merge 4dc00b327 into 98d1ed4f3
Pull Request #1348: #1331: add parser for .ini files

3257 of 5184 branches covered (62.83%)

Branch coverage included in aggregate %.

8316 of 11770 relevant lines covered (70.65%)

3.13 hits per line

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

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

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

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

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

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

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

40
  /**
41
   * @param file the {@link Path} to check.
42
   * @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
43
   *     directory).
44
   */
45
  boolean isFile(Path file);
46

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

53
  /**
54
   * @param file the {@link Path} to compute the checksum of.
55
   * @param hashAlgorithm the hash algorithm (e.g. SHA-266).
56
   * @return the computed hash checksum as hex {@link String}.
57
   */
58
  String checksum(Path file, String hashAlgorithm);
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
   * @return the {@link Path} in the backup where the given {@link Path} was moved to.
65
   */
66
  Path backup(Path fileOrFolder);
67

68
  /**
69
   * @param source the source {@link Path file or folder} to move.
70
   * @param targetDir the {@link Path} with the directory to move {@code source} into.
71
   * @param copyOptions the {@link java.nio.file.CopyOption} which specify how the move should be done
72
   */
73
  void move(Path source, Path targetDir, StandardCopyOption... copyOptions);
74

75
  /**
76
   * 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
77
   * missing privileges, Windows Junctions may be used as fallback, which must point to absolute paths. Therefore, the created link will be absolute instead of
78
   * relative.
79
   *
80
   * @param source the source {@link Path} to link to, may be relative or absolute.
81
   * @param targetLink the {@link Path} where the symbolic link shall be created pointing to {@code source}.
82
   * @param relative - {@code true} if the symbolic link shall be relative, {@code false} if it shall be absolute.
83
   */
84
  void symlink(Path source, Path targetLink, boolean relative);
85

86
  /**
87
   * 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
88
   * of missing privileges, Windows Junctions may be used as fallback, which must point to absolute paths. Therefore, the created link will be absolute instead
89
   * of relative.
90
   *
91
   * @param source the source {@link Path} to link to, may be relative or absolute.
92
   * @param targetLink the {@link Path} where the symbolic link shall be created pointing to {@code source}.
93
   */
94
  default void symlink(Path source, Path targetLink) {
95

96
    symlink(source, targetLink, true);
5✔
97
  }
1✔
98

99
  /**
100
   * @param source the source {@link Path file or folder} to copy.
101
   * @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
102
   *     you will find the same content of {@code source} in {@code target}.
103
   */
104
  default void copy(Path source, Path target) {
105

106
    copy(source, target, FileCopyMode.COPY_TREE_FAIL_IF_EXISTS);
5✔
107
  }
1✔
108

109
  /**
110
   * @param source the source {@link Path file or folder} to copy.
111
   * @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}
112
   *     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
113
   *     {@code target}. Therefore the result is always clear and easy to predict and understand. Also you can easily rename a file to copy. While
114
   *     {@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
115
   *     the same content of {@code source} in {@code target}.
116
   * @param mode the {@link FileCopyMode}.
117
   */
118
  default void copy(Path source, Path target, FileCopyMode mode) {
119

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

123
  /**
124
   * @param source the source {@link Path file or folder} to copy.
125
   * @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}
126
   *     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
127
   *     {@code target}. Therefore the result is always clear and easy to predict and understand. Also you can easily rename a file to copy. While
128
   *     {@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
129
   *     the same content of {@code source} in {@code target}.
130
   * @param mode the {@link FileCopyMode}.
131
   * @param listener the {@link PathCopyListener} that will be called for each copied {@link Path}.
132
   */
133
  void copy(Path source, Path target, FileCopyMode mode, PathCopyListener listener);
134

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

141
    extract(archiveFile, targetDir, null);
5✔
142
  }
1✔
143

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

151
    extract(archiveFile, targetDir, postExtractHook, true);
6✔
152
  }
1✔
153

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

162
  /**
163
   * 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.
164
   *
165
   * @param file the ZIP file to extract.
166
   * @param targetDir the {@link Path} with the directory to unzip to.
167
   */
168
  void extractZip(Path file, Path targetDir);
169

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

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

183
  /**
184
   * 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
185
   * 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
186
   * then copies the application to the applications folder via drag and drop in order to perform the installation.
187
   *
188
   * @param file the DMG file to extract.
189
   * @param targetDir the target directory where to extract the contents to.
190
   */
191
  void extractDmg(Path file, Path targetDir);
192

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

202
  /**
203
   * 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
204
   * 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
205
   * specific structure.
206
   *
207
   * @param file the PKG file to extract.
208
   * @param targetDir the target directory where to extract the contents to.
209
   */
210
  void extractPkg(Path file, Path targetDir);
211

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

218
  /**
219
   * @param path the {@link Path} to convert.
220
   * @return the absolute and physical {@link Path}.
221
   */
222
  Path toCanonicalPath(Path path);
223

224
  /**
225
   * Deletes the given {@link Path} idempotent and recursive.
226
   * <p>
227
   * ATTENTION: In most cases we want to use {@link #backup(Path)} instead to prevent the user from data loss.
228
   * </p>
229
   *
230
   * @param path the {@link Path} to delete.
231
   */
232
  void delete(Path path);
233

234
  /**
235
   * 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
236
   * is done.
237
   *
238
   * @param name the default name of the temporary directory to create. A prefix or suffix may be added to ensure uniqueness.
239
   * @return the {@link Path} to the newly created and unique temporary directory.
240
   */
241
  Path createTempDir(String name);
242

243
  /**
244
   * @param dir the folder to search.
245
   * @param filter the {@link Predicate} used to find the {@link Predicate#test(Object) match}.
246
   * @param recursive - {@code true} to search recursive in all sub-folders, {@code false} otherwise.
247
   * @return the first child {@link Path} matching the given {@link Predicate} or {@code null} if no match was found.
248
   */
249
  Path findFirst(Path dir, Predicate<Path> filter, boolean recursive);
250

251
  /**
252
   * @param dir the {@link Path} to the directory where to list the children.
253
   * @param filter the {@link Predicate} used to {@link Predicate#test(Object) decide} which children to include (if {@code true} is returned).
254
   * @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
255
   *     directory.
256
   */
257
  default List<Path> listChildren(Path dir, Predicate<Path> filter) {
258

259
    return listChildrenMapped(dir, child -> (filter.test(child)) ? child : null);
13!
260
  }
261

262
  /**
263
   * @param dir the {@link Path} to the directory where to list the children.
264
   * @param filter the filter {@link Function} used to {@link Function#apply(Object) filter and transform} children to include. If the {@link Function}
265
   *     returns  {@code null}, the child will be filtered, otherwise the returned {@link Path} will be included in the resulting {@link List}.
266
   * @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
267
   *     directory.
268
   */
269
  List<Path> listChildrenMapped(Path dir, Function<Path, Path> filter);
270

271
  /**
272
   * Finds the existing file with the specified name in the given list of directories.
273
   *
274
   * @param fileName The name of the file to find.
275
   * @param searchDirs The list of directories to search for the file.
276
   * @return The {@code Path} of the existing file, or {@code null} if the file is not found.
277
   */
278
  Path findExistingFile(String fileName, List<Path> searchDirs);
279

280
  /**
281
   * Checks if the given directory is empty.
282
   *
283
   * @param dir The {@link Path} object representing the directory to check.
284
   * @return {@code true} if the directory is empty, {@code false} otherwise.
285
   */
286
  boolean isEmptyDir(Path dir);
287

288
  /**
289
   * Sets or unsets the writable permission for the specified file path.
290
   *
291
   * @param file {@link Path} to the file.
292
   * @param writable {@code true} to make the file writable, {@code false} to make it read-only
293
   * @return {@code true} if the operation was successful or supported, {@code false} otherwise
294
   */
295
  boolean setWritable(Path file, boolean writable);
296

297
  /**
298
   * Makes a file executable (analog to 'chmod a+x').
299
   *
300
   * @param file {@link Path} to the file.
301
   */
302
  default void makeExecutable(Path file) {
303

304
    makeExecutable(file, false);
4✔
305
  }
1✔
306

307
  /**
308
   * Makes a file executable (analog to 'chmod a+x').
309
   *
310
   * @param file {@link Path} to the file.
311
   * @param confirm - {@code true} to get user confirmation before adding missing executable flags, {@code false} otherwise (always set missing flags).
312
   */
313
  void makeExecutable(Path file, boolean confirm);
314

315
  /**
316
   * Like the linux touch command this method will update the modification time of the given {@link Path} to the current
317
   * {@link System#currentTimeMillis() system time}. In case the file does not exist, it will be created as empty file. If already the
318
   * {@link Path#getParent() parent folder} does not exist, the operation will fail.
319
   *
320
   * @param file the {@link Path} to the file or folder.
321
   */
322
  void touch(Path file);
323

324
  /**
325
   * @param file the {@link Path} to the file to read.
326
   * @return the content of the specified file (in UTF-8 encoding), or null if the file doesn't exist
327
   * @see java.nio.file.Files#readString(Path)
328
   */
329
  String readFileContent(Path file);
330

331
  /**
332
   * @param content the {@link String} with the text to write to a file.
333
   * @param file the {@link Path} to the file where to save.
334
   */
335
  default void writeFileContent(String content, Path file) {
336

337
    writeFileContent(content, file, false);
5✔
338
  }
1✔
339

340
  /**
341
   * @param content the {@link String} with the text to write to a file.
342
   * @param file the {@link Path} to the file where to save.
343
   * @param createParentDir if {@code true}, the parent directory will be created if it does not already exist, {@code false} otherwise (fail if parent does
344
   *     not exist).
345
   */
346
  void writeFileContent(String content, Path file, boolean createParentDir);
347

348
  /**
349
   * Like {@link #readFileContent(Path)} but giving one {@link String} per line of text. It will not allow to preserve line endings (CRLF vs. LF).
350
   *
351
   * @param file the {@link Path} to the file to read.
352
   * @return the content of the specified file (in UTF-8 encoding) as {@link List} of {@link String}s per line of text.
353
   */
354
  List<String> readFileLines(Path file);
355

356
  /**
357
   * Like {@link #writeFileContent(String, Path)} but taking a {@link List} with one {@link String} per line of text. It will always use LF as newline character
358
   * independent of the operating system.
359
   *
360
   * @param lines the {@link List} of {@link String}s per line of text.
361
   * @param file the {@link Path} to the file where to save.
362
   */
363
  default void writeFileLines(List<String> lines, Path file) {
364
    writeFileLines(lines, file, false);
5✔
365
  }
1✔
366

367
  /**
368
   * Like {@link #writeFileContent(String, Path, boolean)} but taking a {@link List} with one {@link String} per line of text. It will always use LF as newline
369
   * character independent of the operating system.
370
   *
371
   * @param lines the {@link List} of {@link String}s per line of text.
372
   * @param file the {@link Path} to the file where to save.
373
   * @param createParentDir if {@code true}, the parent directory will be created if it does not already exist, {@code false} otherwise (fail if parent does
374
   *     not exist).
375
   */
376
  void writeFileLines(List<String> lines, Path file, boolean createParentDir);
377

378
  /**
379
   * @param path that is checked whether it is a junction or not.
380
   * @return {@code true} if the given {@link Path} is a junction, false otherwise.
381
   */
382
  boolean isJunction(Path path);
383

384
  /**
385
   * @param file the {@link Path} to the {@link Properties} file to read.
386
   * @return the parsed {@link Properties}.
387
   */
388
  default Properties readProperties(Path file) {
389
    Properties properties = new Properties();
4✔
390
    readProperties(file, properties);
4✔
391
    return properties;
2✔
392
  }
393

394
  /**
395
   * @param file the {@link Path} to the {@link Properties} file to read.
396
   * @param properties the existing {@link Properties} to {@link Properties#load(Reader) load} into.
397
   */
398
  void readProperties(Path file, Properties properties);
399

400
  /**
401
   * @param properties the {@link Properties} to save.
402
   * @param file the {@link Path} to the file where to save the properties.
403
   */
404
  default void writeProperties(Properties properties, Path file) {
405

406
    writeProperties(properties, file, false);
5✔
407
  }
1✔
408

409

410
  /**
411
   * @param properties the {@link Properties} to save.
412
   * @param file the {@link Path} to the file where to save the properties.
413
   * @param createParentDir if {@code true}, the parent directory will created if it does not already exist, {@code false} otherwise (fail if parent does
414
   *     not exist).
415
   */
416
  void writeProperties(Properties properties, Path file, boolean createParentDir);
417

418
  /**
419
   * @param file the {@link Path} to read from
420
   * @return {@link IniFile}
421
   */
422
  default IniFile readIniFile(Path file) {
423
    IniFile iniFile = new IniFileImpl();
×
424
    readIniFile(file, iniFile);
×
425
    return iniFile;
×
426
  }
427

428
  /**
429
   * @param file the {@link Path} to read from
430
   * @param iniFile the {@link IniFile} object the data is loaded into
431
   */
432
  void readIniFile(Path file, IniFile iniFile);
433

434
  /**
435
   * @param iniFile the {@link IniFile} object
436
   * @param file the {@link Path} to write to
437
   */
438
  default void writeIniFile(IniFile iniFile, Path file) {
439
    writeIniFile(iniFile, file, false);
5✔
440
  }
1✔
441

442
  /**
443
   * @param iniFile the {@link IniFile} object
444
   * @param file the {@link Path} to write to
445
   * @param createParentDir whether to create missing parent directories
446
   */
447
  void writeIniFile(IniFile iniFile, Path file, boolean createParentDir);
448

449
  /**
450
   * @param path the {@link Path} to get the age from the modification time.
451
   * @return the age of the file as {@link Duration} from now to the modification time of the file.
452
   */
453
  public Duration getFileAge(Path path);
454

455
  /**
456
   * @param path the {@link Path} to check.
457
   * @param cacheDuration the {@link Duration} to consider as recent.
458
   * @return {@code true} if the given {@link Path} exists and is recent enough (its {@link #getFileAge(Path) age} is not greater than the given
459
   *     {@link Duration}), {@code false} otherwise.
460
   */
461
  boolean isFileAgeRecent(Path path, Duration cacheDuration);
462
}
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