Search in sources :

Example 91 with FileEntriesLayer

use of com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer in project jib by google.

the class Layers method toLayers.

/**
 * Convert a layer spec to a list of layer objects.
 *
 * <p>Does not handle missing directories for files added via this method. We can either prefill
 * directories here, or allow passing of the file entry information directly to the reproducible
 * layer builder
 *
 * @param buildRoot the directory to resolve relative paths, usually the directory where the build
 *     config file is located
 * @param layersSpec a layersSpec containing configuration for all layers
 * @return a {@link List} of {@link FileEntriesLayer} to use as part of a jib container build
 * @throws IOException if traversing a directory fails
 */
static List<FileEntriesLayer> toLayers(Path buildRoot, LayersSpec layersSpec) throws IOException {
    List<FileEntriesLayer> layers = new ArrayList<>();
    FilePropertiesStack filePropertiesStack = new FilePropertiesStack();
    // base properties
    layersSpec.getProperties().ifPresent(filePropertiesStack::push);
    for (LayerSpec entry : layersSpec.getEntries()) {
        // each loop is a new layer
        if (entry instanceof FileLayerSpec) {
            FileEntriesLayer.Builder layerBuiler = FileEntriesLayer.builder();
            FileLayerSpec fileLayer = (FileLayerSpec) entry;
            layerBuiler.setName(fileLayer.getName());
            // layer properties
            fileLayer.getProperties().ifPresent(filePropertiesStack::push);
            for (CopySpec copySpec : ((FileLayerSpec) entry).getFiles()) {
                // copy spec properties
                copySpec.getProperties().ifPresent(filePropertiesStack::push);
                // relativize all paths to the buildRoot location
                Path rawSrc = copySpec.getSrc();
                Path src = rawSrc.isAbsolute() ? rawSrc : buildRoot.resolve(rawSrc);
                AbsoluteUnixPath dest = copySpec.getDest();
                if (!Files.isDirectory(src) && !Files.isRegularFile(src)) {
                    throw new UnsupportedOperationException("Cannot create FileLayers from non-file, non-directory: " + src.toString());
                }
                if (Files.isRegularFile(src)) {
                    // regular file
                    if (!copySpec.getExcludes().isEmpty() || !copySpec.getIncludes().isEmpty()) {
                        throw new UnsupportedOperationException("Cannot apply includes/excludes on single file copy directives.");
                    }
                    layerBuiler.addEntry(src, copySpec.isDestEndsWithSlash() ? dest.resolve(src.getFileName()) : dest, filePropertiesStack.getFilePermissions(), filePropertiesStack.getModificationTime(), filePropertiesStack.getOwnership());
                } else if (Files.isDirectory(src)) {
                    // directory
                    List<PathMatcher> excludes = copySpec.getExcludes().stream().map(Layers::toPathMatcher).collect(Collectors.toList());
                    List<PathMatcher> includes = copySpec.getIncludes().stream().map(Layers::toPathMatcher).collect(Collectors.toList());
                    try (Stream<Path> dirWalk = Files.walk(src)) {
                        List<Path> filtered = dirWalk.filter(path -> excludes.stream().noneMatch(exclude -> exclude.matches(path))).filter(path -> {
                            // if there are no includes directives, include everything
                            if (includes.isEmpty()) {
                                return true;
                            }
                            // if there are includes directives, only include those specified
                            for (PathMatcher matcher : includes) {
                                if (matcher.matches(path)) {
                                    return true;
                                }
                            }
                            return false;
                        }).collect(Collectors.toList());
                        BiFunction<Path, FilePermissions, FileEntry> newEntry = (file, permission) -> new FileEntry(file, dest.resolve(src.relativize(file)), permission, filePropertiesStack.getModificationTime(), filePropertiesStack.getOwnership());
                        Set<Path> addedDirectories = new HashSet<>();
                        for (Path path : filtered) {
                            if (!Files.isDirectory(path) && !Files.isRegularFile(path)) {
                                throw new UnsupportedOperationException("Cannot create FileLayers from non-file, non-directory: " + src.toString());
                            }
                            if (Files.isDirectory(path)) {
                                addedDirectories.add(path);
                                layerBuiler.addEntry(newEntry.apply(path, filePropertiesStack.getDirectoryPermissions()));
                            } else if (Files.isRegularFile(path)) {
                                if (!path.startsWith(src)) {
                                    // be from a link scenario that we do not understand.
                                    throw new IllegalStateException(src.toString() + " is not a parent of " + path.toString());
                                }
                                Path parent = Verify.verifyNotNull(path.getParent());
                                while (true) {
                                    if (addedDirectories.contains(parent)) {
                                        break;
                                    }
                                    layerBuiler.addEntry(newEntry.apply(parent, filePropertiesStack.getDirectoryPermissions()));
                                    addedDirectories.add(parent);
                                    if (parent.equals(src)) {
                                        break;
                                    }
                                    parent = Verify.verifyNotNull(parent.getParent());
                                }
                                layerBuiler.addEntry(newEntry.apply(path, filePropertiesStack.getFilePermissions()));
                            }
                        }
                    }
                }
                copySpec.getProperties().ifPresent(ignored -> filePropertiesStack.pop());
            }
            fileLayer.getProperties().ifPresent(ignored -> filePropertiesStack.pop());
            // TODO: add logging/handling for empty layers
            layers.add(layerBuiler.build());
        } else {
            throw new UnsupportedOperationException("Only FileLayers are supported at this time.");
        }
    }
    layersSpec.getProperties().ifPresent(ignored -> filePropertiesStack.pop());
    return layers;
}
Also used : AbsoluteUnixPath(com.google.cloud.tools.jib.api.buildplan.AbsoluteUnixPath) Path(java.nio.file.Path) AbsoluteUnixPath(com.google.cloud.tools.jib.api.buildplan.AbsoluteUnixPath) Verify(com.google.common.base.Verify) Files(java.nio.file.Files) BiFunction(java.util.function.BiFunction) FilePermissions(com.google.cloud.tools.jib.api.buildplan.FilePermissions) Set(java.util.Set) IOException(java.io.IOException) FileEntriesLayer(com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer) Collectors(java.util.stream.Collectors) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) List(java.util.List) Stream(java.util.stream.Stream) FileEntry(com.google.cloud.tools.jib.api.buildplan.FileEntry) PathMatcher(java.nio.file.PathMatcher) VisibleForTesting(com.google.common.annotations.VisibleForTesting) Path(java.nio.file.Path) FileSystems(java.nio.file.FileSystems) Set(java.util.Set) HashSet(java.util.HashSet) FileEntriesLayer(com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer) ArrayList(java.util.ArrayList) AbsoluteUnixPath(com.google.cloud.tools.jib.api.buildplan.AbsoluteUnixPath) PathMatcher(java.nio.file.PathMatcher) BiFunction(java.util.function.BiFunction) ArrayList(java.util.ArrayList) List(java.util.List) Stream(java.util.stream.Stream) FileEntry(com.google.cloud.tools.jib.api.buildplan.FileEntry)

Example 92 with FileEntriesLayer

use of com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer in project jib by google.

the class JarFiles method toJibContainerBuilder.

/**
 * Generates a {@link JibContainerBuilder} from contents of a jar file.
 *
 * @param processor jar processor
 * @param jarOptions jar cli options
 * @param commonCliOptions common cli options
 * @param commonContainerConfigCliOptions common command line options shared between jar and war
 *     command
 * @param logger console logger
 * @return JibContainerBuilder
 * @throws IOException if I/O error occurs when opening the jar file or if temporary directory
 *     provided doesn't exist
 * @throws InvalidImageReferenceException if the base image reference is invalid
 */
public static JibContainerBuilder toJibContainerBuilder(ArtifactProcessor processor, Jar jarOptions, CommonCliOptions commonCliOptions, CommonContainerConfigCliOptions commonContainerConfigCliOptions, ConsoleLogger logger) throws IOException, InvalidImageReferenceException {
    String imageReference = commonContainerConfigCliOptions.getFrom().orElseGet(() -> getDefaultBaseImage(processor));
    JibContainerBuilder containerBuilder = ContainerBuilders.create(imageReference, Collections.emptySet(), commonCliOptions, logger);
    List<FileEntriesLayer> layers = processor.createLayers();
    List<String> customEntrypoint = commonContainerConfigCliOptions.getEntrypoint();
    List<String> entrypoint = customEntrypoint.isEmpty() ? processor.computeEntrypoint(jarOptions.getJvmFlags()) : customEntrypoint;
    containerBuilder.setEntrypoint(entrypoint).setFileEntriesLayers(layers).setExposedPorts(commonContainerConfigCliOptions.getExposedPorts()).setVolumes(commonContainerConfigCliOptions.getVolumes()).setEnvironment(commonContainerConfigCliOptions.getEnvironment()).setLabels(commonContainerConfigCliOptions.getLabels()).setProgramArguments(commonContainerConfigCliOptions.getProgramArguments());
    commonContainerConfigCliOptions.getUser().ifPresent(containerBuilder::setUser);
    commonContainerConfigCliOptions.getFormat().ifPresent(containerBuilder::setFormat);
    commonContainerConfigCliOptions.getCreationTime().ifPresent(containerBuilder::setCreationTime);
    return containerBuilder;
}
Also used : FileEntriesLayer(com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer) JibContainerBuilder(com.google.cloud.tools.jib.api.JibContainerBuilder)

Example 93 with FileEntriesLayer

use of com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer in project jib by google.

the class JarLayers method getDependenciesLayers.

static List<FileEntriesLayer> getDependenciesLayers(Path jarPath, ProcessingMode mode) throws IOException {
    // adding the dependencies layers.
    try (JarFile jarFile = new JarFile(jarPath.toFile())) {
        String classPath = jarFile.getManifest().getMainAttributes().getValue(Attributes.Name.CLASS_PATH);
        if (classPath == null) {
            return new ArrayList<>();
        }
        List<FileEntriesLayer> layers = new ArrayList<>();
        Path jarParent = jarPath.getParent() == null ? Paths.get("") : jarPath.getParent();
        Predicate<String> isSnapshot = name -> name.contains("SNAPSHOT");
        List<String> allDependencies = Splitter.onPattern("\\s+").splitToList(classPath.trim());
        List<Path> nonSnapshots = allDependencies.stream().filter(isSnapshot.negate()).map(Paths::get).collect(Collectors.toList());
        List<Path> snapshots = allDependencies.stream().filter(isSnapshot).map(Paths::get).collect(Collectors.toList());
        if (!nonSnapshots.isEmpty()) {
            FileEntriesLayer.Builder nonSnapshotLayer = FileEntriesLayer.builder().setName(ArtifactLayers.DEPENDENCIES);
            nonSnapshots.forEach(path -> addDependency(nonSnapshotLayer, jarParent.resolve(path), mode.equals(ProcessingMode.packaged) ? APP_ROOT.resolve(path) : APP_ROOT.resolve(ArtifactLayers.DEPENDENCIES).resolve(path.getFileName())));
            layers.add(nonSnapshotLayer.build());
        }
        if (!snapshots.isEmpty()) {
            FileEntriesLayer.Builder snapshotLayer = FileEntriesLayer.builder().setName(ArtifactLayers.SNAPSHOT_DEPENDENCIES);
            snapshots.forEach(path -> addDependency(snapshotLayer, jarParent.resolve(path), mode.equals(ProcessingMode.packaged) ? APP_ROOT.resolve(path) : APP_ROOT.resolve(ArtifactLayers.DEPENDENCIES).resolve(path.getFileName())));
            layers.add(snapshotLayer.build());
        }
        return layers;
    }
}
Also used : AbsoluteUnixPath(com.google.cloud.tools.jib.api.buildplan.AbsoluteUnixPath) Path(java.nio.file.Path) AbsoluteUnixPath(com.google.cloud.tools.jib.api.buildplan.AbsoluteUnixPath) Files(java.nio.file.Files) Predicate(java.util.function.Predicate) IOException(java.io.IOException) JarFile(java.util.jar.JarFile) FileEntriesLayer(com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer) Attributes(java.util.jar.Attributes) Collectors(java.util.stream.Collectors) ArtifactLayers(com.google.cloud.tools.jib.cli.ArtifactLayers) ArrayList(java.util.ArrayList) List(java.util.List) Paths(java.nio.file.Paths) Splitter(com.google.common.base.Splitter) Path(java.nio.file.Path) ArrayList(java.util.ArrayList) FileEntriesLayer(com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer) JarFile(java.util.jar.JarFile)

Example 94 with FileEntriesLayer

use of com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer in project jib by google.

the class SpringBootExplodedProcessor method createLayers.

@Override
public List<FileEntriesLayer> createLayers() throws IOException {
    // Clear the exploded-artifact root first
    if (Files.exists(targetExplodedJarRoot)) {
        MoreFiles.deleteRecursively(targetExplodedJarRoot, RecursiveDeleteOption.ALLOW_INSECURE);
    }
    try (JarFile jarFile = new JarFile(jarPath.toFile())) {
        ZipUtil.unzip(jarPath, targetExplodedJarRoot, true);
        ZipEntry layerIndex = jarFile.getEntry(BOOT_INF + "/layers.idx");
        if (layerIndex != null) {
            return createLayersForLayeredSpringBootJar(targetExplodedJarRoot);
        }
        Predicate<Path> isFile = Files::isRegularFile;
        // Non-snapshot layer
        Predicate<Path> isInBootInfLib = path -> path.startsWith(targetExplodedJarRoot.resolve(BOOT_INF).resolve("lib"));
        Predicate<Path> isSnapshot = path -> path.getFileName().toString().contains("SNAPSHOT");
        Predicate<Path> isInBootInfLibAndIsNotSnapshot = isInBootInfLib.and(isSnapshot.negate());
        Predicate<Path> nonSnapshotPredicate = isFile.and(isInBootInfLibAndIsNotSnapshot);
        FileEntriesLayer nonSnapshotLayer = ArtifactLayers.getDirectoryContentsAsLayer(ArtifactLayers.DEPENDENCIES, targetExplodedJarRoot, nonSnapshotPredicate, JarLayers.APP_ROOT);
        // Snapshot layer
        Predicate<Path> isInBootInfLibAndIsSnapshot = isInBootInfLib.and(isSnapshot);
        Predicate<Path> snapshotPredicate = isFile.and(isInBootInfLibAndIsSnapshot);
        FileEntriesLayer snapshotLayer = ArtifactLayers.getDirectoryContentsAsLayer(ArtifactLayers.SNAPSHOT_DEPENDENCIES, targetExplodedJarRoot, snapshotPredicate, JarLayers.APP_ROOT);
        // Spring-boot-loader layer.
        Predicate<Path> isLoader = path -> path.startsWith(targetExplodedJarRoot.resolve("org"));
        Predicate<Path> loaderPredicate = isFile.and(isLoader);
        FileEntriesLayer loaderLayer = ArtifactLayers.getDirectoryContentsAsLayer("spring-boot-loader", targetExplodedJarRoot, loaderPredicate, JarLayers.APP_ROOT);
        // Classes layer.
        Predicate<Path> isClass = path -> path.getFileName().toString().endsWith(".class");
        Predicate<Path> isInBootInfClasses = path -> path.startsWith(targetExplodedJarRoot.resolve(BOOT_INF).resolve("classes"));
        Predicate<Path> classesPredicate = isInBootInfClasses.and(isClass);
        FileEntriesLayer classesLayer = ArtifactLayers.getDirectoryContentsAsLayer(ArtifactLayers.CLASSES, targetExplodedJarRoot, classesPredicate, JarLayers.APP_ROOT);
        // Resources layer.
        Predicate<Path> isInMetaInf = path -> path.startsWith(targetExplodedJarRoot.resolve("META-INF"));
        Predicate<Path> isResource = isInMetaInf.or(isInBootInfClasses.and(isClass.negate()));
        Predicate<Path> resourcesPredicate = isFile.and(isResource);
        FileEntriesLayer resourcesLayer = ArtifactLayers.getDirectoryContentsAsLayer(ArtifactLayers.RESOURCES, targetExplodedJarRoot, resourcesPredicate, JarLayers.APP_ROOT);
        return Arrays.asList(nonSnapshotLayer, loaderLayer, snapshotLayer, resourcesLayer, classesLayer);
    }
}
Also used : Path(java.nio.file.Path) Arrays(java.util.Arrays) Verify(com.google.common.base.Verify) Files(java.nio.file.Files) Predicate(java.util.function.Predicate) IOException(java.io.IOException) JarFile(java.util.jar.JarFile) RecursiveDeleteOption(com.google.common.io.RecursiveDeleteOption) FileEntriesLayer(com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer) StandardCharsets(java.nio.charset.StandardCharsets) ArtifactLayers(com.google.cloud.tools.jib.cli.ArtifactLayers) ZipUtil(com.google.cloud.tools.jib.plugins.common.ZipUtil) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) List(java.util.List) Matcher(java.util.regex.Matcher) ImmutableList(com.google.common.collect.ImmutableList) ArtifactProcessor(com.google.cloud.tools.jib.cli.ArtifactProcessor) MoreFiles(com.google.common.io.MoreFiles) Map(java.util.Map) Predicates(com.google.common.base.Predicates) Pattern(java.util.regex.Pattern) Path(java.nio.file.Path) ZipEntry(java.util.zip.ZipEntry) ZipEntry(java.util.zip.ZipEntry) FileEntriesLayer(com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer) JarFile(java.util.jar.JarFile)

Example 95 with FileEntriesLayer

use of com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer in project jib by google.

the class StandardExplodedProcessor method createLayers.

@Override
public List<FileEntriesLayer> createLayers() throws IOException {
    // Clear the exploded-artifact root first
    if (Files.exists(targetExplodedJarRoot)) {
        MoreFiles.deleteRecursively(targetExplodedJarRoot, RecursiveDeleteOption.ALLOW_INSECURE);
    }
    // Add dependencies layers.
    List<FileEntriesLayer> layers = JarLayers.getDependenciesLayers(jarPath, ProcessingMode.exploded);
    // Determine class and resource files in the directory containing jar contents and create
    // FileEntriesLayer for each type of layer (classes or resources).
    ZipUtil.unzip(jarPath, targetExplodedJarRoot, true);
    Predicate<Path> isClassFile = path -> path.getFileName().toString().endsWith(".class");
    Predicate<Path> isResourceFile = isClassFile.negate().and(Files::isRegularFile);
    FileEntriesLayer classesLayer = ArtifactLayers.getDirectoryContentsAsLayer(ArtifactLayers.CLASSES, targetExplodedJarRoot, isClassFile, JarLayers.APP_ROOT.resolve("explodedJar"));
    FileEntriesLayer resourcesLayer = ArtifactLayers.getDirectoryContentsAsLayer(ArtifactLayers.RESOURCES, targetExplodedJarRoot, isResourceFile, JarLayers.APP_ROOT.resolve("explodedJar"));
    if (!resourcesLayer.getEntries().isEmpty()) {
        layers.add(resourcesLayer);
    }
    if (!classesLayer.getEntries().isEmpty()) {
        layers.add(classesLayer);
    }
    return layers;
}
Also used : Path(java.nio.file.Path) Files(java.nio.file.Files) Predicate(java.util.function.Predicate) IOException(java.io.IOException) JarFile(java.util.jar.JarFile) RecursiveDeleteOption(com.google.common.io.RecursiveDeleteOption) FileEntriesLayer(com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer) Attributes(java.util.jar.Attributes) ArtifactLayers(com.google.cloud.tools.jib.cli.ArtifactLayers) ZipUtil(com.google.cloud.tools.jib.plugins.common.ZipUtil) List(java.util.List) ImmutableList(com.google.common.collect.ImmutableList) ArtifactProcessor(com.google.cloud.tools.jib.cli.ArtifactProcessor) MoreFiles(com.google.common.io.MoreFiles) Path(java.nio.file.Path) FileEntriesLayer(com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer) Files(java.nio.file.Files) MoreFiles(com.google.common.io.MoreFiles)

Aggregations

FileEntriesLayer (com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer)154 Test (org.junit.Test)111 Path (java.nio.file.Path)92 AbsoluteUnixPath (com.google.cloud.tools.jib.api.buildplan.AbsoluteUnixPath)85 ContainerBuildPlan (com.google.cloud.tools.jib.api.buildplan.ContainerBuildPlan)55 List (java.util.List)29 IOException (java.io.IOException)26 ArrayList (java.util.ArrayList)26 JibContainerBuilder (com.google.cloud.tools.jib.api.JibContainerBuilder)24 FileEntry (com.google.cloud.tools.jib.api.buildplan.FileEntry)23 Map (java.util.Map)23 Files (java.nio.file.Files)21 Predicate (java.util.function.Predicate)20 Platform (com.google.cloud.tools.jib.api.buildplan.Platform)16 Collectors (java.util.stream.Collectors)16 FilePermissions (com.google.cloud.tools.jib.api.buildplan.FilePermissions)13 Paths (java.nio.file.Paths)13 Optional (java.util.Optional)13 JavaContainerBuilder (com.google.cloud.tools.jib.api.JavaContainerBuilder)12 JibPluginExtensionException (com.google.cloud.tools.jib.plugins.extension.JibPluginExtensionException)12