src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java
branchJDK-8200758-branch
changeset 58301 e0efb29609bd
child 58302 718bd56695b3
equal deleted inserted replaced
58172:bf06a1d3aef6 58301:e0efb29609bd
       
     1 /*
       
     2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 package jdk.jpackage.internal;
       
    26 
       
    27 import java.io.IOException;
       
    28 import java.nio.file.Files;
       
    29 import java.nio.file.Path;
       
    30 import java.util.ArrayList;
       
    31 import java.util.Collection;
       
    32 import java.util.Collections;
       
    33 import java.util.List;
       
    34 import java.util.Map;
       
    35 import java.util.stream.Collectors;
       
    36 import java.util.stream.Stream;
       
    37 
       
    38 
       
    39 /**
       
    40  * Group of paths.
       
    41  * Each path in the group is assigned a unique id.
       
    42  */
       
    43 final class PathGroup {
       
    44     PathGroup(Map<Object, Path> paths) {
       
    45         entries = Collections.unmodifiableMap(paths);
       
    46     }
       
    47 
       
    48     Path getPath(Object id) {
       
    49         return entries.get(id);
       
    50     }
       
    51 
       
    52     /**
       
    53      * All configured entries.
       
    54      */
       
    55     Collection<Path> paths() {
       
    56         return entries.values();
       
    57     }
       
    58 
       
    59     /**
       
    60      * Root entries.
       
    61      */
       
    62     List<Path> roots() {
       
    63         // Sort by the number of path components in ascending order.
       
    64         List<Path> sorted = paths().stream().sorted(
       
    65                 (a, b) -> a.getNameCount() - b.getNameCount()).collect(
       
    66                         Collectors.toList());
       
    67 
       
    68         return paths().stream().filter(
       
    69                 v -> v == sorted.stream().sequential().filter(
       
    70                         v2 -> v == v2 || v2.endsWith(v)).findFirst().get()).collect(
       
    71                         Collectors.toList());
       
    72     }
       
    73 
       
    74     long sizeInBytes() throws IOException {
       
    75         long reply = 0;
       
    76         for (Path dir : roots().stream().filter(f -> Files.isDirectory(f)).collect(
       
    77                 Collectors.toList())) {
       
    78             reply += Files.walk(dir).filter(p -> Files.isRegularFile(p)).mapToLong(
       
    79                     f -> f.toFile().length()).sum();
       
    80         }
       
    81         return reply;
       
    82     }
       
    83 
       
    84     PathGroup resolveAt(Path root) {
       
    85         return new PathGroup(entries.entrySet().stream().collect(
       
    86                 Collectors.toMap(e -> e.getKey(),
       
    87                         e -> root.resolve(e.getValue()))));
       
    88     }
       
    89 
       
    90     void copy(PathGroup dst) throws IOException {
       
    91         copy(this, dst, false);
       
    92     }
       
    93 
       
    94     void move(PathGroup dst) throws IOException {
       
    95         copy(this, dst, true);
       
    96     }
       
    97 
       
    98     static interface Facade<T> {
       
    99         PathGroup pathGroup();
       
   100 
       
   101         default Collection<Path> paths() {
       
   102             return pathGroup().paths();
       
   103         }
       
   104 
       
   105         default List<Path> roots() {
       
   106             return pathGroup().roots();
       
   107         }
       
   108 
       
   109         default long sizeInBytes() throws IOException {
       
   110             return pathGroup().sizeInBytes();
       
   111         }
       
   112 
       
   113         T resolveAt(Path root);
       
   114 
       
   115         default void copy(Facade<T> dst) throws IOException {
       
   116             pathGroup().copy(dst.pathGroup());
       
   117         }
       
   118 
       
   119         default void move(Facade<T> dst) throws IOException {
       
   120             pathGroup().move(dst.pathGroup());
       
   121         }
       
   122     }
       
   123 
       
   124     private static void copy(PathGroup src, PathGroup dst, boolean move) throws
       
   125             IOException {
       
   126         copy(move, src.entries.keySet().stream().filter(
       
   127                 id -> dst.entries.containsKey(id)).map(id -> Map.entry(
       
   128                 src.entries.get(id), dst.entries.get(id))).collect(
       
   129                 Collectors.toCollection(ArrayList::new)));
       
   130     }
       
   131 
       
   132     private static void copy(boolean move, List<Map.Entry<Path, Path>> entries)
       
   133             throws IOException {
       
   134 
       
   135         // Reorder entries. Entries with source entries with the least amount of
       
   136         // descending entries found between source entries should go first.
       
   137         entries.sort((e1, e2) -> e1.getKey().getNameCount() - e2.getKey().getNameCount());
       
   138 
       
   139         for (var entry : entries.stream().sequential().filter(e -> {
       
   140             return e == entries.stream().sequential().filter(e2 -> isDuplicate(e2, e)).findFirst().get();
       
   141                 }).collect(Collectors.toList())) {
       
   142             Path src = entry.getKey();
       
   143             Path dst = entry.getValue();
       
   144 
       
   145             if (src.equals(dst)) {
       
   146                 continue;
       
   147             }
       
   148 
       
   149             Files.createDirectories(dst.getParent());
       
   150             if (move) {
       
   151                 Files.move(src, dst);
       
   152             } else if (src.toFile().isDirectory()) {
       
   153                 IOUtils.copyRecursive(src, dst);
       
   154             } else {
       
   155                 IOUtils.copyFile(src.toFile(), dst.toFile());
       
   156             }
       
   157         }
       
   158     }
       
   159 
       
   160     private static boolean isDuplicate(Map.Entry<Path, Path> a,
       
   161             Map.Entry<Path, Path> b) {
       
   162         if (a == b || a.equals(b)) {
       
   163             return true;
       
   164         }
       
   165 
       
   166         if (b.getKey().getNameCount() < a.getKey().getNameCount()) {
       
   167             return isDuplicate(b, a);
       
   168         }
       
   169 
       
   170         if (!a.getKey().endsWith(b.getKey())) {
       
   171             return false;
       
   172         }
       
   173 
       
   174         Path relativeSrcPath = a.getKey().relativize(b.getKey());
       
   175         Path relativeDstPath = a.getValue().relativize(b.getValue());
       
   176 
       
   177         return relativeSrcPath.equals(relativeDstPath);
       
   178     }
       
   179 
       
   180     private final Map<Object, Path> entries;
       
   181 }