24
24
*/
25
25
package jdk .jpackage .internal .util ;
26
26
27
+ import static java .util .stream .Collectors .collectingAndThen ;
28
+ import static java .util .stream .Collectors .groupingBy ;
27
29
import static java .util .stream .Collectors .toMap ;
30
+ import static java .util .stream .Collectors .toSet ;
28
31
29
32
import java .io .IOException ;
30
33
import java .io .UncheckedIOException ;
34
37
import java .nio .file .LinkOption ;
35
38
import java .nio .file .Path ;
36
39
import java .util .ArrayList ;
40
+ import java .util .Collection ;
37
41
import java .util .Comparator ;
38
42
import java .util .HashMap ;
39
43
import java .util .List ;
@@ -53,6 +57,8 @@ public final class PathGroup {
53
57
* @param paths the initial paths
54
58
*/
55
59
public PathGroup (Map <Object , Path > paths ) {
60
+ paths .keySet ().forEach (Objects ::requireNonNull );
61
+ paths .values ().forEach (Objects ::requireNonNull );
56
62
entries = new HashMap <>(paths );
57
63
}
58
64
@@ -179,14 +185,32 @@ public List<Path> roots() {
179
185
*/
180
186
public long sizeInBytes () throws IOException {
181
187
long reply = 0 ;
182
- for (Path dir : roots ().stream ().filter (Files ::isDirectory ).toList ()) {
183
- try (Stream <Path > stream = Files .walk (dir )) {
184
- reply += stream .filter (Files ::isRegularFile ).mapToLong (f -> f .toFile ().length ()).sum ();
188
+ final var roots = roots ();
189
+ try {
190
+ for (Path dir : roots .stream ().filter (Files ::isDirectory ).toList ()) {
191
+ try (Stream <Path > stream = Files .walk (dir )) {
192
+ reply += stream .mapToLong (PathGroup ::sizeInBytes ).sum ();
193
+ }
185
194
}
195
+ reply += roots .stream ().mapToLong (PathGroup ::sizeInBytes ).sum ();
196
+ } catch (UncheckedIOException ex ) {
197
+ throw ex .getCause ();
186
198
}
187
199
return reply ;
188
200
}
189
201
202
+ private static long sizeInBytes (Path path ) throws UncheckedIOException {
203
+ if (Files .isRegularFile (path )) {
204
+ try {
205
+ return Files .size (path );
206
+ } catch (IOException ex ) {
207
+ throw new UncheckedIOException (ex );
208
+ }
209
+ } else {
210
+ return 0 ;
211
+ }
212
+ }
213
+
190
214
/**
191
215
* Creates a copy of this path group with all paths resolved against the given
192
216
* root. Taken action is equivalent to creating a copy of this path group and
@@ -300,16 +324,42 @@ private void deleteEntries() throws IOException {
300
324
}
301
325
}
302
326
303
- private record CopySpec (Path from , Path to , Path fromNormalized , Path toNormalized ) {
327
+ private record CopySpec (Path basepath , Path from , Path to ) {
304
328
CopySpec {
305
- Objects .requireNonNull (from );
306
- Objects .requireNonNull (fromNormalized );
329
+ Objects .requireNonNull (basepath );
307
330
Objects .requireNonNull (to );
308
- Objects .requireNonNull (toNormalized );
331
+ if (!from .startsWith (basepath )) {
332
+ throw new IllegalArgumentException ();
333
+ }
334
+ }
335
+
336
+ @ Override
337
+ public int hashCode () {
338
+ return Objects .hash (from , to );
339
+ }
340
+
341
+ @ Override
342
+ public boolean equals (Object obj ) {
343
+ if (this == obj ) {
344
+ return true ;
345
+ }
346
+ if ((obj == null ) || (getClass () != obj .getClass ())) {
347
+ return false ;
348
+ }
349
+ CopySpec other = (CopySpec ) obj ;
350
+ return Objects .equals (from , other .from ) && Objects .equals (to , other .to );
351
+ }
352
+
353
+ Path fromNormalized () {
354
+ return from ().normalize ();
355
+ }
356
+
357
+ Path toNormalized () {
358
+ return to ().normalize ();
309
359
}
310
360
311
361
CopySpec (Path from , Path to ) {
312
- this (from , to , from . normalize () , to . normalize () );
362
+ this (from , from , to );
313
363
}
314
364
}
315
365
@@ -361,47 +411,55 @@ private static void copy(List<CopySpec> copySpecs, List<Path> excludePaths,
361
411
Objects .requireNonNull (excludePaths );
362
412
Objects .requireNonNull (handler );
363
413
364
- final var copySpecMap = copySpecs .stream ().<CopySpec >mapMulti ((copySpec , consumer ) -> {
365
- final var src = copySpec .from ;
414
+
415
+ final var filteredCopySpecs = copySpecs .stream ().<CopySpec >mapMulti ((copySpec , consumer ) -> {
416
+ final var src = copySpec .from ();
366
417
367
418
if (!Files .exists (src ) || match (src , excludePaths )) {
368
419
return ;
369
420
}
370
421
371
- if (Files .isDirectory (copySpec .from )) {
422
+ if (Files .isDirectory (copySpec .from () )) {
372
423
final var dst = copySpec .to ;
373
424
final var walkMode = followSymlinks ? new FileVisitOption [] { FileVisitOption .FOLLOW_LINKS } : new FileVisitOption [0 ];
374
425
try (final var files = Files .walk (src , walkMode )) {
375
426
files .filter (file -> {
376
427
return !match (file , excludePaths );
377
428
}).map (file -> {
378
- return new CopySpec (file , dst .resolve (src .relativize (file )));
429
+ return new CopySpec (src , file , dst .resolve (src .relativize (file )));
379
430
}).toList ().forEach (consumer ::accept );
380
431
} catch (IOException ex ) {
381
432
throw new UncheckedIOException (ex );
382
433
}
383
434
} else {
384
435
consumer .accept (copySpec );
385
436
}
386
- }).collect (toMap (CopySpec ::toNormalized , x -> x , (x , y ) -> {
387
- if (x .fromNormalized .equals (y .fromNormalized )) {
388
- // Duplicated copy specs, accept.
389
- return x ;
390
- } else {
391
- throw new IllegalStateException (String .format (
392
- "Duplicate source files [%s] and [%s] for [%s] destination file" , x .from , y .from , x .to ));
393
- }
437
+ }).collect (groupingBy (CopySpec ::fromNormalized , collectingAndThen (toSet (), copySpecGroup -> {
438
+ return copySpecGroup .stream ().filter (copySpec -> {
439
+ for (final var otherCopySpec : copySpecGroup ) {
440
+ if (otherCopySpec != copySpec && !otherCopySpec .basepath ().equals (copySpec .basepath ())
441
+ && otherCopySpec .basepath ().startsWith (copySpec .basepath ())) {
442
+ return false ;
443
+ }
444
+ }
445
+ return true ;
446
+ }).toList ();
447
+ }))).values ().stream ().flatMap (Collection ::stream ).toList ();
448
+
449
+ filteredCopySpecs .stream ().collect (toMap (CopySpec ::toNormalized , x -> x , (x , y ) -> {
450
+ throw new IllegalStateException (String .format (
451
+ "Duplicate source files [%s] and [%s] for [%s] destination file" , x .from (), y .from (), x .to ()));
394
452
}));
395
453
396
454
try {
397
- copySpecMap . values () .stream ().forEach (copySpec -> {
455
+ filteredCopySpecs .stream ().forEach (copySpec -> {
398
456
try {
399
- if (Files .isSymbolicLink (copySpec .from )) {
400
- handler .copySymbolicLink (copySpec .from , copySpec .to );
401
- } else if (Files .isDirectory (copySpec .from )) {
402
- handler .createDirectory (copySpec .to );
457
+ if (Files .isSymbolicLink (copySpec .from () )) {
458
+ handler .copySymbolicLink (copySpec .from () , copySpec .to () );
459
+ } else if (Files .isDirectory (copySpec .from () )) {
460
+ handler .createDirectory (copySpec .to () );
403
461
} else {
404
- handler .copyFile (copySpec .from , copySpec .to );
462
+ handler .copyFile (copySpec .from () , copySpec .to () );
405
463
}
406
464
} catch (IOException ex ) {
407
465
throw new UncheckedIOException (ex );
0 commit comments