From 9821463be7e1cac7c7e4bbabb9e157e1c2d1e4c9 Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Mon, 22 Oct 2018 16:56:18 -0400 Subject: [PATCH 1/6] Update gradle extraDirectory config parameter to include path and permissions field --- jib-gradle-plugin/CHANGELOG.md | 3 + .../gradle/SingleProjectIntegrationTest.java | 12 +-- .../resources/projects/simple/build.gradle | 4 +- .../projects/simple/complex-build.gradle | 5 +- .../src/main/java/com/test/HelloWorld.java | 5 ++ .../tools/jib/gradle/BuildDockerTask.java | 6 +- .../tools/jib/gradle/BuildImageTask.java | 6 +- .../cloud/tools/jib/gradle/BuildTarTask.java | 9 ++- .../tools/jib/gradle/DockerContextTask.java | 9 ++- .../jib/gradle/ExtraDirectoryParameters.java | 81 +++++++++++++++++++ .../cloud/tools/jib/gradle/FilesTask.java | 4 +- .../jib/gradle/GradleLayerConfigurations.java | 34 ++++++-- .../jib/gradle/GradleProjectProperties.java | 15 +++- .../cloud/tools/jib/gradle/JibExtension.java | 57 ++++++------- .../jib/gradle/DockerContextTaskTest.java | 14 ++-- .../gradle/GradleLayerConfigurationsTest.java | 32 ++++++-- .../tools/jib/gradle/JibExtensionTest.java | 26 +++++- .../complex-service/build.gradle | 4 +- .../resources/projects/simple/build.gradle | 4 +- .../jib/maven/JibPluginConfiguration.java | 2 +- .../jib/maven/MavenLayerConfigurations.java | 5 +- .../ConfigurationPropertyValidator.java | 21 +++++ .../common/JavaLayerConfigurationsHelper.java | 24 +++++- .../jib/plugins/common/PropertyNames.java | 3 +- .../ConfigurationPropertyValidatorTest.java | 22 +++++ .../JavaLayerConfigurationsHelperTest.java | 15 ++-- 26 files changed, 339 insertions(+), 83 deletions(-) create mode 100644 jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoryParameters.java diff --git a/jib-gradle-plugin/CHANGELOG.md b/jib-gradle-plugin/CHANGELOG.md index 86fc318812..09368f7eb8 100644 --- a/jib-gradle-plugin/CHANGELOG.md +++ b/jib-gradle-plugin/CHANGELOG.md @@ -16,6 +16,9 @@ All notable changes to this project will be documented in this file. - `jibExportDockerContext` generates different directory layout and `Dockerfile` to enable WAR support ([#1007](https://github.com/GoogleContainerTools/jib/pull/1007)) - File timestamps in the built image are set to 1 second since the epoch (hence 1970-01-01T00:00:01Z) to resolve compatibility with applications on Java 6 or below where the epoch means nonexistent or I/O errors; previously they were set to the epoch ([#1079](https://github.com/GoogleContainerTools/jib/issues/1079)) - Sets tag to "latest" instead of "unspecified" if `jib.to.image` and project version are both unspecified when running `jibDockerBuild` or `jibBuildTar` ([#1096](https://github.com/GoogleContainerTools/jib/issues/1096)) +- `jib.extraDirectory` parameter is now a configuration object with a `path` and a `permissions` field ([#794](https://github.com/GoogleContainerTools/jib/issues/794)) + - `jib.extraDirectory.path` is used in place of the original `jib.extraDirectory` and allows you to configure the extra layer directory + - `jib.extraDirectory.permissions` is a map from absolute path on container to the file's permission bits (represented as an octal string) ### Fixed diff --git a/jib-gradle-plugin/src/integration-test/java/com/google/cloud/tools/jib/gradle/SingleProjectIntegrationTest.java b/jib-gradle-plugin/src/integration-test/java/com/google/cloud/tools/jib/gradle/SingleProjectIntegrationTest.java index ffa4e27dbe..e530fdb925 100644 --- a/jib-gradle-plugin/src/integration-test/java/com/google/cloud/tools/jib/gradle/SingleProjectIntegrationTest.java +++ b/jib-gradle-plugin/src/integration-test/java/com/google/cloud/tools/jib/gradle/SingleProjectIntegrationTest.java @@ -142,7 +142,7 @@ public void testBuild_simple() throws IOException, InterruptedException { Instant beforeBuild = Instant.now(); Assert.assertEquals( - "Hello, world. An argument.\nfoo\ncat\n", + "Hello, world. An argument.\nrw-r--r--\nrw-r--r--\nfoo\ncat\n", JibRunHelper.buildAndRun(simpleTestProject, targetImage)); assertDockerInspect(targetImage); assertSimpleCreationTimeIsAfter(beforeBuild, targetImage); @@ -153,7 +153,7 @@ public void testBuild_complex() throws IOException, InterruptedException { String targetImage = "localhost:6000/compleximage:gradle" + System.nanoTime(); Instant beforeBuild = Instant.now(); Assert.assertEquals( - "Hello, world. An argument.\nfoo\ncat\n-Xms512m\n-Xdebug\nenvvalue1\nenvvalue2\n", + "Hello, world. An argument.\nrwxr-xr-x\nrwxrwxrwx\nfoo\ncat\n-Xms512m\n-Xdebug\nenvvalue1\nenvvalue2\n", buildAndRunComplex(targetImage, "testuser2", "testpassword2", localRegistry2)); assertSimpleCreationTimeIsAfter(beforeBuild, targetImage); } @@ -163,7 +163,7 @@ public void testBuild_complex_sameFromAndToRegistry() throws IOException, Interr String targetImage = "localhost:5000/compleximage:gradle" + System.nanoTime(); Instant beforeBuild = Instant.now(); Assert.assertEquals( - "Hello, world. An argument.\nfoo\ncat\n-Xms512m\n-Xdebug\nenvvalue1\nenvvalue2\n", + "Hello, world. An argument.\nrwxr-xr-x\nrwxrwxrwx\nfoo\ncat\n-Xms512m\n-Xdebug\nenvvalue1\nenvvalue2\n", buildAndRunComplex(targetImage, "testuser", "testpassword", localRegistry1)); assertSimpleCreationTimeIsAfter(beforeBuild, targetImage); } @@ -173,7 +173,7 @@ public void testDockerDaemon_simple() throws IOException, InterruptedException { String targetImage = "simpleimage:gradle" + System.nanoTime(); Instant beforeBuild = Instant.now(); Assert.assertEquals( - "Hello, world. An argument.\nfoo\ncat\n", + "Hello, world. An argument.\nrw-r--r--\nrw-r--r--\nfoo\ncat\n", JibRunHelper.buildToDockerDaemonAndRun(simpleTestProject, targetImage)); assertSimpleCreationTimeIsAfter(beforeBuild, targetImage); assertDockerInspect(targetImage); @@ -201,7 +201,7 @@ public void testDockerContext() throws IOException, InterruptedException { assertDockerInspect(imageName); Assert.assertEquals( - "Hello, world. An argument.\nfoo\ncat\n", + "Hello, world. An argument.\nrw-r--r--\nrw-r--r--\nfoo\ncat\n", new Command("docker", "run", "--rm", imageName).run()); // Checks that generating the Docker context again is skipped. @@ -249,7 +249,7 @@ public void testBuildTar_simple() throws IOException, InterruptedException { new Command("docker", "load", "--input", outputPath).run(); Assert.assertEquals( - "Hello, world. An argument.\nfoo\ncat\n", + "Hello, world. An argument.\nrw-r--r--\nrw-r--r--\nfoo\ncat\n", new Command("docker", "run", "--rm", targetImage).run()); assertDockerInspect(targetImage); assertSimpleCreationTimeIsAfter(beforeBuild, targetImage); diff --git a/jib-gradle-plugin/src/integration-test/resources/projects/simple/build.gradle b/jib-gradle-plugin/src/integration-test/resources/projects/simple/build.gradle index 2cf938a3c2..42d266fe94 100644 --- a/jib-gradle-plugin/src/integration-test/resources/projects/simple/build.gradle +++ b/jib-gradle-plugin/src/integration-test/resources/projects/simple/build.gradle @@ -25,7 +25,9 @@ jib { ports = ['1000/tcp', '2000-2003/udp'] labels = [key1:'value1', key2:'value2'] } - extraDirectory = file('src/main/custom-extra-dir') + extraDirectory { + path = file('src/main/custom-extra-dir') + } // Does not have tests use user-level cache for base image layers. useOnlyProjectCache = true diff --git a/jib-gradle-plugin/src/integration-test/resources/projects/simple/complex-build.gradle b/jib-gradle-plugin/src/integration-test/resources/projects/simple/complex-build.gradle index 0fd21b3dd4..b12d6940fd 100644 --- a/jib-gradle-plugin/src/integration-test/resources/projects/simple/complex-build.gradle +++ b/jib-gradle-plugin/src/integration-test/resources/projects/simple/complex-build.gradle @@ -38,8 +38,11 @@ jib { ports = ['1000/tcp', '2000-2003/udp'] labels = [key1:'value1', key2:'value2'] } + extraDirectory { + path = file('src/main/custom-extra-dir') + permissions = ['/foo':'755', '/bar/cat':'777'] + } allowInsecureRegistries = true - extraDirectory = file('src/main/custom-extra-dir') // Does not have tests use user-level cache for base image layers. useOnlyProjectCache = true diff --git a/jib-gradle-plugin/src/integration-test/resources/projects/simple/src/main/java/com/test/HelloWorld.java b/jib-gradle-plugin/src/integration-test/resources/projects/simple/src/main/java/com/test/HelloWorld.java index 733648707f..cf30f12cdf 100644 --- a/jib-gradle-plugin/src/integration-test/resources/projects/simple/src/main/java/com/test/HelloWorld.java +++ b/jib-gradle-plugin/src/integration-test/resources/projects/simple/src/main/java/com/test/HelloWorld.java @@ -24,6 +24,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.attribute.PosixFilePermissions; /** Example class that uses a dependency and a resource file. */ public class HelloWorld { @@ -41,6 +42,10 @@ public static void main(String[] args) throws IOException, URISyntaxException { // Prints the contents of the extra files. if (Files.exists(Paths.get("/foo"))) { + System.out.println( + PosixFilePermissions.toString(Files.getPosixFilePermissions(Paths.get("/foo")))); + System.out.println( + PosixFilePermissions.toString(Files.getPosixFilePermissions(Paths.get("/bar/cat")))); System.out.println(new String(Files.readAllBytes(Paths.get("/foo")), StandardCharsets.UTF_8)); System.out.println( new String(Files.readAllBytes(Paths.get("/bar/cat")), StandardCharsets.UTF_8)); diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildDockerTask.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildDockerTask.java index 22bda0354e..6bac5250e5 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildDockerTask.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildDockerTask.java @@ -84,7 +84,11 @@ public void buildDocker() AbsoluteUnixPath appRoot = PluginConfigurationProcessor.getAppRootChecked(jibExtension); GradleProjectProperties gradleProjectProperties = GradleProjectProperties.getForProject( - getProject(), getLogger(), jibExtension.getExtraDirectoryPath(), appRoot); + getProject(), + getLogger(), + jibExtension.getExtraDirectory().getPath(), + jibExtension.getExtraDirectory().getPermissions(), + appRoot); GradleHelpfulSuggestionsBuilder gradleHelpfulSuggestionsBuilder = new GradleHelpfulSuggestionsBuilder(HELPFUL_SUGGESTIONS_PREFIX, jibExtension); diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildImageTask.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildImageTask.java index aa2a1b6f32..26cb572ec1 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildImageTask.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildImageTask.java @@ -82,7 +82,11 @@ public void buildImage() AbsoluteUnixPath appRoot = PluginConfigurationProcessor.getAppRootChecked(jibExtension); GradleProjectProperties gradleProjectProperties = GradleProjectProperties.getForProject( - getProject(), getLogger(), jibExtension.getExtraDirectoryPath(), appRoot); + getProject(), + getLogger(), + jibExtension.getExtraDirectory().getPath(), + jibExtension.getExtraDirectory().getPermissions(), + appRoot); if (Strings.isNullOrEmpty(jibExtension.getTo().getImage())) { throw new GradleException( diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildTarTask.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildTarTask.java index 72cb89f03d..053fdaf7fc 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildTarTask.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildTarTask.java @@ -78,7 +78,8 @@ public void setTargetImage(String targetImage) { @InputFiles public FileCollection getInputFiles() { return GradleProjectProperties.getInputFiles( - Preconditions.checkNotNull(jibExtension).getExtraDirectoryPath().toFile(), getProject()); + Preconditions.checkNotNull(jibExtension).getExtraDirectory().getPath().toFile(), + getProject()); } /** @@ -109,7 +110,11 @@ public void buildTar() AbsoluteUnixPath appRoot = PluginConfigurationProcessor.getAppRootChecked(jibExtension); GradleProjectProperties gradleProjectProperties = GradleProjectProperties.getForProject( - getProject(), getLogger(), jibExtension.getExtraDirectoryPath(), appRoot); + getProject(), + getLogger(), + jibExtension.getExtraDirectory().getPath(), + jibExtension.getExtraDirectory().getPermissions(), + appRoot); GradleHelpfulSuggestionsBuilder gradleHelpfulSuggestionsBuilder = new GradleHelpfulSuggestionsBuilder(HELPFUL_SUGGESTIONS_PREFIX, jibExtension); diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/DockerContextTask.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/DockerContextTask.java index 2186c78b38..538ebbfbe6 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/DockerContextTask.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/DockerContextTask.java @@ -61,7 +61,8 @@ public JibExtension getJib() { @InputFiles public FileCollection getInputFiles() { return GradleProjectProperties.getInputFiles( - Preconditions.checkNotNull(jibExtension).getExtraDirectoryPath().toFile(), getProject()); + Preconditions.checkNotNull(jibExtension).getExtraDirectory().getPath().toFile(), + getProject()); } /** @@ -110,7 +111,11 @@ public void generateDockerContext() { AbsoluteUnixPath appRoot = PluginConfigurationProcessor.getAppRootChecked(jibExtension); GradleProjectProperties gradleProjectProperties = GradleProjectProperties.getForProject( - getProject(), getLogger(), jibExtension.getExtraDirectoryPath(), appRoot); + getProject(), + getLogger(), + jibExtension.getExtraDirectory().getPath(), + jibExtension.getExtraDirectory().getPermissions(), + appRoot); String targetDir = getTargetDir(); List entrypoint = diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoryParameters.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoryParameters.java new file mode 100644 index 0000000000..d414b6e3d9 --- /dev/null +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoryParameters.java @@ -0,0 +1,81 @@ +/* + * Copyright 2018 Google LLC. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.cloud.tools.jib.gradle; + +import com.google.cloud.tools.jib.plugins.common.ConfigurationPropertyValidator; +import com.google.cloud.tools.jib.plugins.common.PropertyNames; +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.Map; +import javax.inject.Inject; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.Internal; + +/** Object in {@link JibExtension} that configures the extra directory. */ +public class ExtraDirectoryParameters { + + private Path path; + private Map permissions = Collections.emptyMap(); + + private static Path resolveDefaultExtraDirectory(Path projectDirectory) { + return projectDirectory.resolve("src").resolve("main").resolve("jib"); + } + + @Inject + public ExtraDirectoryParameters(Path projectDirectory) { + path = resolveDefaultExtraDirectory(projectDirectory); + } + + @Input + public String getPathString() { + // Gradle warns about @Input annotations on File objects, so we have to expose a getter for a + // String to make them go away. + if (System.getProperty(PropertyNames.EXTRA_DIRECTORY_PATH) != null) { + return System.getProperty(PropertyNames.EXTRA_DIRECTORY_PATH); + } + return path.toString(); + } + + @Internal + public Path getPath() { + // Gradle warns about @Input annotations on File objects, so we have to expose a getter for a + // String to make them go away. + if (System.getProperty(PropertyNames.EXTRA_DIRECTORY_PATH) != null) { + return Paths.get(System.getProperty(PropertyNames.EXTRA_DIRECTORY_PATH)); + } + return path; + } + + public void setPath(File path) { + this.path = path.toPath(); + } + + @Input + public Map getPermissions() { + if (System.getProperty(PropertyNames.EXTRA_DIRECTORY_PERMISSIONS) != null) { + return ConfigurationPropertyValidator.parseMapProperty( + System.getProperty(PropertyNames.EXTRA_DIRECTORY_PERMISSIONS)); + } + return permissions; + } + + public void setPermissions(Map permissions) { + this.permissions = permissions; + } +} diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/FilesTask.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/FilesTask.java index 9a4e5347c1..fde1cf0456 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/FilesTask.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/FilesTask.java @@ -149,8 +149,8 @@ public void listFiles() { printProjectFiles(project); // Print extra layer - if (Files.exists(jibExtension.getExtraDirectoryPath())) { - System.out.println(jibExtension.getExtraDirectoryPath()); + if (Files.exists(jibExtension.getExtraDirectory().getPath())) { + System.out.println(jibExtension.getExtraDirectory().getPath()); } // Find project dependencies diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleLayerConfigurations.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleLayerConfigurations.java index 1f238f5df5..b3dfb19551 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleLayerConfigurations.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleLayerConfigurations.java @@ -16,6 +16,7 @@ package com.google.cloud.tools.jib.gradle; +import com.google.cloud.tools.jib.configuration.FilePermissions; import com.google.cloud.tools.jib.filesystem.AbsoluteUnixPath; import com.google.cloud.tools.jib.frontend.JavaEntrypointConstructor; import com.google.cloud.tools.jib.frontend.JavaLayerConfigurations; @@ -26,6 +27,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Map; import org.gradle.api.Project; import org.gradle.api.file.FileCollection; import org.gradle.api.logging.Logger; @@ -49,13 +51,17 @@ class GradleLayerConfigurations { * @throws IOException if an I/O exception occurred during resolution */ static JavaLayerConfigurations getForProject( - Project project, Logger logger, Path extraDirectory, AbsoluteUnixPath appRoot) + Project project, + Logger logger, + Path extraDirectory, + Map permissions, + AbsoluteUnixPath appRoot) throws IOException { if (GradleProjectProperties.getWarTask(project) != null) { logger.info("WAR project identified, creating WAR image: " + project.getDisplayName()); - return getForWarProject(project, logger, extraDirectory, appRoot); + return getForWarProject(project, extraDirectory, permissions, appRoot); } else { - return getForNonWarProject(project, logger, extraDirectory, appRoot); + return getForNonWarProject(project, logger, extraDirectory, permissions, appRoot); } } @@ -70,7 +76,11 @@ static JavaLayerConfigurations getForProject( * @throws IOException if an I/O exception occurred during resolution */ private static JavaLayerConfigurations getForNonWarProject( - Project project, Logger logger, Path extraDirectory, AbsoluteUnixPath appRoot) + Project project, + Logger logger, + Path extraDirectory, + Map permissions, + AbsoluteUnixPath appRoot) throws IOException { AbsoluteUnixPath dependenciesExtractionPath = appRoot.resolve(JavaEntrypointConstructor.DEFAULT_RELATIVE_DEPENDENCIES_PATH_ON_IMAGE); @@ -127,7 +137,11 @@ private static JavaLayerConfigurations getForNonWarProject( // Adds all the extra files. if (Files.exists(extraDirectory)) { layerBuilder.addDirectoryContents( - LayerType.EXTRA_FILES, extraDirectory, path -> true, AbsoluteUnixPath.get("/")); + LayerType.EXTRA_FILES, + extraDirectory, + path -> true, + AbsoluteUnixPath.get("/"), + permissions); } return layerBuilder.build(); @@ -137,17 +151,21 @@ private static JavaLayerConfigurations getForNonWarProject( * Resolves the {@link JavaLayerConfigurations} for a WAR Gradle {@link Project}. * * @param project the Gradle {@link Project} - * @param logger the build logger for providing feedback about the resolution * @param extraDirectory path to the source directory for the extra files layer + * @param permissions map from path on container to file permissions * @param appRoot root directory in the image where the app will be placed * @return {@link JavaLayerConfigurations} for the layers for the Gradle {@link Project} * @throws IOException if an I/O exception occurred during resolution */ private static JavaLayerConfigurations getForWarProject( - Project project, Logger logger, Path extraDirectory, AbsoluteUnixPath appRoot) + Project project, + Path extraDirectory, + Map permissions, + AbsoluteUnixPath appRoot) throws IOException { Path explodedWarPath = GradleProjectProperties.getExplodedWarDirectory(project); - return JavaLayerConfigurationsHelper.fromExplodedWar(explodedWarPath, appRoot, extraDirectory); + return JavaLayerConfigurationsHelper.fromExplodedWar( + explodedWarPath, appRoot, extraDirectory, permissions); } private GradleLayerConfigurations() {} diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleProjectProperties.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleProjectProperties.java index fa022d22a7..8512629205 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleProjectProperties.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleProjectProperties.java @@ -21,6 +21,7 @@ import com.google.cloud.tools.jib.event.events.LogEvent; import com.google.cloud.tools.jib.filesystem.AbsoluteUnixPath; import com.google.cloud.tools.jib.frontend.JavaLayerConfigurations; +import com.google.cloud.tools.jib.plugins.common.ConfigurationPropertyValidator; import com.google.cloud.tools.jib.plugins.common.MainClassInferenceException; import com.google.cloud.tools.jib.plugins.common.MainClassResolver; import com.google.cloud.tools.jib.plugins.common.ProjectProperties; @@ -32,6 +33,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Set; import javax.annotation.Nullable; import org.gradle.api.GradleException; @@ -57,12 +59,21 @@ class GradleProjectProperties implements ProjectProperties { /** @return a GradleProjectProperties from the given project and logger. */ static GradleProjectProperties getForProject( - Project project, Logger logger, Path extraDirectory, AbsoluteUnixPath appRoot) { + Project project, + Logger logger, + Path extraDirectory, + Map permissions, + AbsoluteUnixPath appRoot) { try { return new GradleProjectProperties( project, makeEventHandlers(logger), - GradleLayerConfigurations.getForProject(project, logger, extraDirectory, appRoot)); + GradleLayerConfigurations.getForProject( + project, + logger, + extraDirectory, + ConfigurationPropertyValidator.convertPermissionsMap(permissions), + appRoot)); } catch (IOException ex) { throw new GradleException("Obtaining project build output files failed", ex); diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibExtension.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibExtension.java index 8d37d461c9..f4a73eb89e 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibExtension.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibExtension.java @@ -17,15 +17,11 @@ package com.google.cloud.tools.jib.gradle; import com.google.cloud.tools.jib.plugins.common.PropertyNames; -import java.io.File; -import java.nio.file.Path; -import java.nio.file.Paths; import org.gradle.api.Action; import org.gradle.api.Project; import org.gradle.api.model.ObjectFactory; import org.gradle.api.provider.Property; import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.Nested; import org.gradle.api.tasks.Optional; @@ -52,6 +48,15 @@ * format = OCI * appRoot = "/app"; * } + * extraDirectory { + * path = file('path/to/extra/dir') + * permissions = [ + * '/path/on/container/file1': 744, + * '/path/on/container/file2': 123 + * ] + * } + * allowInsecureRegistries = false + * useOnlyProjectCache = false * } * } */ @@ -61,16 +66,13 @@ public class JibExtension { private static final boolean DEFAULT_USE_ONLY_PROJECT_CACHE = false; private static final boolean DEFAULT_ALLOW_INSECURE_REGISTIRIES = false; - private static Path resolveDefaultExtraDirectory(Path projectDirectory) { - return projectDirectory.resolve("src").resolve("main").resolve("jib"); - } - private final BaseImageParameters from; private final TargetImageParameters to; private final ContainerParameters container; + private final ExtraDirectoryParameters extraDirectory; + private final Property useOnlyProjectCache; private final Property allowInsecureRegistries; - private final Property extraDirectory; public JibExtension(Project project) { ObjectFactory objectFactory = project.getObjects(); @@ -78,15 +80,15 @@ public JibExtension(Project project) { from = objectFactory.newInstance(BaseImageParameters.class, "jib.from"); to = objectFactory.newInstance(TargetImageParameters.class, "jib.to"); container = objectFactory.newInstance(ContainerParameters.class); + extraDirectory = + objectFactory.newInstance(ExtraDirectoryParameters.class, project.getProjectDir().toPath()); useOnlyProjectCache = objectFactory.property(Boolean.class); allowInsecureRegistries = objectFactory.property(Boolean.class); - extraDirectory = objectFactory.property(Path.class); // Sets defaults. useOnlyProjectCache.set(DEFAULT_USE_ONLY_PROJECT_CACHE); allowInsecureRegistries.set(DEFAULT_ALLOW_INSECURE_REGISTIRIES); - extraDirectory.set(resolveDefaultExtraDirectory(project.getProjectDir().toPath())); } public void from(Action action) { @@ -101,12 +103,12 @@ public void container(Action action) { action.execute(container); } - public void setAllowInsecureRegistries(boolean allowInsecureRegistries) { - this.allowInsecureRegistries.set(allowInsecureRegistries); + public void extraDirectory(Action action) { + action.execute(extraDirectory); } - public void setExtraDirectory(File extraDirectory) { - this.extraDirectory.set(extraDirectory.toPath()); + public void setAllowInsecureRegistries(boolean allowInsecureRegistries) { + this.allowInsecureRegistries.set(allowInsecureRegistries); } void setUseOnlyProjectCache(boolean useOnlyProjectCache) { @@ -131,6 +133,12 @@ public ContainerParameters getContainer() { return container; } + @Nested + @Optional + public ExtraDirectoryParameters getExtraDirectory() { + return extraDirectory; + } + @Input @Optional boolean getUseOnlyProjectCache() { @@ -148,23 +156,4 @@ boolean getAllowInsecureRegistries() { } return allowInsecureRegistries.get(); } - - @Input - String getExtraDirectory() { - // Gradle warns about @Input annotations on File objects, so we have to expose a getter for a - // String to make them go away. - if (System.getProperty(PropertyNames.EXTRA_DIRECTORY) != null) { - return System.getProperty(PropertyNames.EXTRA_DIRECTORY); - } - return extraDirectory.get().toString(); - } - - @Internal - Path getExtraDirectoryPath() { - // TODO: Should inform user about nonexistent directory if using custom directory. - if (System.getProperty(PropertyNames.EXTRA_DIRECTORY) != null) { - return Paths.get(System.getProperty(PropertyNames.EXTRA_DIRECTORY)); - } - return extraDirectory.get(); - } } diff --git a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/DockerContextTaskTest.java b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/DockerContextTaskTest.java index edbd43ce22..a768010fa7 100644 --- a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/DockerContextTaskTest.java +++ b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/DockerContextTaskTest.java @@ -43,6 +43,7 @@ public class DockerContextTaskTest { @Mock private ContainerParameters containerParameters; @Mock private BaseImageParameters baseImageParameters; + @Mock private ExtraDirectoryParameters extraDirectoryParameters; private DockerContextTask task; private Project project; @@ -57,14 +58,17 @@ public void setUp() throws IOException { Mockito.when(jibExtension.getContainer()).thenReturn(containerParameters); Mockito.when(containerParameters.getEnvironment()) .thenReturn(ImmutableMap.of("envKey", "envVal")); - Mockito.when(jibExtension.getExtraDirectoryPath()) - .thenReturn(projectRoot.newFolder("src", "main", "jib").toPath()); - Mockito.when(jibExtension.getContainer().getMainClass()).thenReturn("MainClass"); - Mockito.when(jibExtension.getFrom()).thenReturn(baseImageParameters); - Mockito.when(baseImageParameters.getImage()).thenReturn("base image"); + Mockito.when(containerParameters.getMainClass()).thenReturn("MainClass"); Mockito.when(containerParameters.getAppRoot()).thenReturn("/app"); Mockito.when(containerParameters.getArgs()).thenCallRealMethod(); + Mockito.when(jibExtension.getFrom()).thenReturn(baseImageParameters); + Mockito.when(baseImageParameters.getImage()).thenReturn("base image"); + + Mockito.when(jibExtension.getExtraDirectory()).thenReturn(extraDirectoryParameters); + Mockito.when(extraDirectoryParameters.getPath()) + .thenReturn(projectRoot.newFolder("src", "main", "jib").toPath()); + project = ProjectBuilder.builder().withProjectDir(projectRoot.getRoot()).build(); project.getPluginManager().apply("java"); diff --git a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/GradleLayerConfigurationsTest.java b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/GradleLayerConfigurationsTest.java index 2104b155f7..d0de719443 100644 --- a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/GradleLayerConfigurationsTest.java +++ b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/GradleLayerConfigurationsTest.java @@ -29,6 +29,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -176,7 +177,11 @@ public void test_correctFiles() throws URISyntaxException, IOException { AbsoluteUnixPath appRoot = AbsoluteUnixPath.get("/app"); JavaLayerConfigurations javaLayerConfigurations = GradleLayerConfigurations.getForProject( - mockProject, mockLogger, Paths.get("nonexistent/path"), appRoot); + mockProject, + mockLogger, + Paths.get("nonexistent/path"), + Collections.emptyMap(), + appRoot); assertSourcePathsUnordered( expectedDependenciesFiles, javaLayerConfigurations.getDependencyLayerEntries()); assertSourcePathsUnordered( @@ -198,7 +203,7 @@ public void test_noClassesFiles() throws IOException { AbsoluteUnixPath appRoot = AbsoluteUnixPath.get("/app"); GradleLayerConfigurations.getForProject( - mockProject, mockLogger, Paths.get("nonexistent/path"), appRoot); + mockProject, mockLogger, Paths.get("nonexistent/path"), Collections.emptyMap(), appRoot); Mockito.verify(mockLogger) .info("Adding corresponding output directories of source sets to image"); @@ -210,7 +215,11 @@ public void test_noClassesFiles() throws IOException { public void test_extraFiles() throws IOException { JavaLayerConfigurations javaLayerConfigurations = GradleLayerConfigurations.getForProject( - mockProject, mockLogger, extraFilesDirectory, AbsoluteUnixPath.get("/app")); + mockProject, + mockLogger, + extraFilesDirectory, + Collections.emptyMap(), + AbsoluteUnixPath.get("/app")); ImmutableList expectedExtraFiles = ImmutableList.of( @@ -229,7 +238,11 @@ public void test_extraFiles() throws IOException { public void testGetForProject_nonDefaultAppRoot() throws IOException { JavaLayerConfigurations configuration = GradleLayerConfigurations.getForProject( - mockProject, mockLogger, extraFilesDirectory, AbsoluteUnixPath.get("/my/app")); + mockProject, + mockLogger, + extraFilesDirectory, + Collections.emptyMap(), + AbsoluteUnixPath.get("/my/app")); assertExtractionPathsUnordered( Arrays.asList( @@ -261,6 +274,7 @@ public void testGetForProject_defaultAppRoot() throws IOException { mockProject, mockLogger, extraFilesDirectory, + Collections.emptyMap(), AbsoluteUnixPath.get(JavaLayerConfigurations.DEFAULT_APP_ROOT)); assertExtractionPathsUnordered( @@ -289,7 +303,11 @@ public void testWebApp() throws URISyntaxException, IOException { JavaLayerConfigurations configuration = GradleLayerConfigurations.getForProject( - mockWebAppProject, mockLogger, extraFilesDirectory, AbsoluteUnixPath.get("/my/app")); + mockWebAppProject, + mockLogger, + extraFilesDirectory, + Collections.emptyMap(), + AbsoluteUnixPath.get("/my/app")); ImmutableList expectedDependenciesFiles = ImmutableList.of( webAppDirectory.resolve("jib-exploded-war/WEB-INF/lib/dependency-1.0.0.jar")); @@ -371,6 +389,7 @@ public void testWebApp_defaultWebAppRoot() throws URISyntaxException, IOExceptio mockWebAppProject, mockLogger, extraFilesDirectory, + Collections.emptyMap(), AbsoluteUnixPath.get(JavaLayerConfigurations.DEFAULT_WEB_APP_ROOT)); assertExtractionPathsUnordered( @@ -413,6 +432,7 @@ public void testGetForWarProject_noErrorIfWebInfClassesDoesNotExist() throws IOE mockWebAppProject, mockLogger, extraFilesDirectory, + Collections.emptyMap(), AbsoluteUnixPath.get(JavaLayerConfigurations.DEFAULT_WEB_APP_ROOT)); // should pass } @@ -425,6 +445,7 @@ public void testGetForWarProject_noErrorIfWebInfLibDoesNotExist() throws IOExcep mockWebAppProject, mockLogger, extraFilesDirectory, + Collections.emptyMap(), AbsoluteUnixPath.get(JavaLayerConfigurations.DEFAULT_WEB_APP_ROOT)); // should pass } @@ -437,6 +458,7 @@ public void testGetForWarProject_noErrorIfWebInfDoesNotExist() throws IOExceptio mockWebAppProject, mockLogger, extraFilesDirectory, + Collections.emptyMap(), AbsoluteUnixPath.get(JavaLayerConfigurations.DEFAULT_WEB_APP_ROOT)); // should pass } diff --git a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibExtensionTest.java b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibExtensionTest.java index 313dc56cb6..f95f080387 100644 --- a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibExtensionTest.java +++ b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibExtensionTest.java @@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import java.nio.file.Paths; import java.util.Arrays; import java.util.Collections; import org.gradle.api.Project; @@ -33,6 +34,7 @@ public class JibExtensionTest { private JibExtension testJibExtension; + private Project fakeProject; private static void clearProperties() { System.clearProperty("jib.from.image"); @@ -51,12 +53,14 @@ private static void clearProperties() { System.clearProperty("jib.container.ports"); System.clearProperty("jib.container.useCurrentTimestamp"); System.clearProperty("jib.container.user"); + System.clearProperty("jib.extraDirectory.path"); + System.clearProperty("jib.extraDirectory.permissions"); } @Before public void setUp() { clearProperties(); - Project fakeProject = ProjectBuilder.builder().build(); + fakeProject = ProjectBuilder.builder().build(); testJibExtension = fakeProject .getExtensions() @@ -141,6 +145,26 @@ public void testContainer() { Assert.assertEquals("some invalid appRoot value", container.getAppRoot()); } + @Test + public void testExtraDirectory() { + Assert.assertEquals( + fakeProject.getProjectDir().toPath().resolve("src").resolve("main").resolve("jib"), + testJibExtension.getExtraDirectory().getPath()); + Assert.assertEquals( + Collections.emptyMap(), testJibExtension.getExtraDirectory().getPermissions()); + + testJibExtension.extraDirectory( + extraDirectory -> { + extraDirectory.setPath(Paths.get("test").resolve("path").toFile()); + extraDirectory.setPermissions(ImmutableMap.of("file1", "123", "file2", "456")); + }); + Assert.assertEquals( + Paths.get("test").resolve("path"), testJibExtension.getExtraDirectory().getPath()); + Assert.assertEquals( + ImmutableMap.of("file1", "123", "file2", "456"), + testJibExtension.getExtraDirectory().getPermissions()); + } + @Test public void testProperties() { System.setProperty("jib.from.image", "fromImage"); diff --git a/jib-gradle-plugin/src/test/resources/projects/multi-service/complex-service/build.gradle b/jib-gradle-plugin/src/test/resources/projects/multi-service/complex-service/build.gradle index 28762e824c..92ca5a3e66 100644 --- a/jib-gradle-plugin/src/test/resources/projects/multi-service/complex-service/build.gradle +++ b/jib-gradle-plugin/src/test/resources/projects/multi-service/complex-service/build.gradle @@ -17,7 +17,9 @@ jib { to { image = System.getProperty("_TARGET_IMAGE") } - extraDirectory = file('src/main/other-jib') + extraDirectory { + path = file('src/main/other-jib') + } } sourceSets { diff --git a/jib-gradle-plugin/src/test/resources/projects/simple/build.gradle b/jib-gradle-plugin/src/test/resources/projects/simple/build.gradle index 4832a01f69..52d0f7cab5 100644 --- a/jib-gradle-plugin/src/test/resources/projects/simple/build.gradle +++ b/jib-gradle-plugin/src/test/resources/projects/simple/build.gradle @@ -18,5 +18,7 @@ jib { to { image = System.getProperty("_TARGET_IMAGE") } - extraDirectory = file('src/main/custom-extra-dir') + extraDirectory { + path = file('src/main/custom-extra-dir') + } } diff --git a/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/JibPluginConfiguration.java b/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/JibPluginConfiguration.java index bfe73996c3..21ff0a7484 100644 --- a/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/JibPluginConfiguration.java +++ b/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/JibPluginConfiguration.java @@ -174,7 +174,7 @@ public static class ContainerParameters { @Parameter( defaultValue = "${project.basedir}/src/main/jib", required = true, - property = PropertyNames.EXTRA_DIRECTORY) + property = PropertyNames.EXTRA_DIRECTORY_PATH) private File extraDirectory; @Parameter(defaultValue = "false", property = PropertyNames.SKIP) diff --git a/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/MavenLayerConfigurations.java b/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/MavenLayerConfigurations.java index 91f57da0fc..d6b4904120 100644 --- a/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/MavenLayerConfigurations.java +++ b/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/MavenLayerConfigurations.java @@ -26,6 +26,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collections; import java.util.function.Predicate; import org.apache.maven.artifact.Artifact; import org.apache.maven.project.MavenProject; @@ -119,7 +120,9 @@ private static JavaLayerConfigurations getForWarProject( // at build.getFinalName(). Path explodedWarPath = Paths.get(project.getBuild().getDirectory()).resolve(project.getBuild().getFinalName()); - return JavaLayerConfigurationsHelper.fromExplodedWar(explodedWarPath, appRoot, extraDirectory); + // TODO: Replace Collections.emptyMap() with configured permissions + return JavaLayerConfigurationsHelper.fromExplodedWar( + explodedWarPath, appRoot, extraDirectory, Collections.emptyMap()); } private MavenLayerConfigurations() {} diff --git a/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/ConfigurationPropertyValidator.java b/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/ConfigurationPropertyValidator.java index 708a2dfce1..8ea8e971b7 100644 --- a/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/ConfigurationPropertyValidator.java +++ b/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/ConfigurationPropertyValidator.java @@ -16,9 +16,11 @@ package com.google.cloud.tools.jib.plugins.common; +import com.google.cloud.tools.jib.configuration.FilePermissions; import com.google.cloud.tools.jib.configuration.credentials.Credential; import com.google.cloud.tools.jib.event.EventDispatcher; import com.google.cloud.tools.jib.event.events.LogEvent; +import com.google.cloud.tools.jib.filesystem.AbsoluteUnixPath; import com.google.cloud.tools.jib.http.Authorization; import com.google.cloud.tools.jib.image.ImageReference; import com.google.cloud.tools.jib.image.InvalidImageReferenceException; @@ -29,6 +31,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -184,5 +187,23 @@ public static List parseListProperty(String property) { return ImmutableList.copyOf(items); } + /** + * Validates and converts a {@code String->String} map to an {@code + * AbsoluteUnixPath->FilePermission} map. + * + * @param inputMap the map to convert + * @return the converted map + */ + public static Map convertPermissionsMap( + Map inputMap) { + ImmutableMap.Builder permissionsMap = ImmutableMap.builder(); + for (Entry entry : inputMap.entrySet()) { + AbsoluteUnixPath key = AbsoluteUnixPath.get(entry.getKey()); + FilePermissions value = FilePermissions.fromOctalString(entry.getValue()); + permissionsMap.put(key, value); + } + return permissionsMap.build(); + } + private ConfigurationPropertyValidator() {} } diff --git a/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/JavaLayerConfigurationsHelper.java b/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/JavaLayerConfigurationsHelper.java index ab9238c9c0..1c398790ac 100644 --- a/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/JavaLayerConfigurationsHelper.java +++ b/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/JavaLayerConfigurationsHelper.java @@ -16,6 +16,7 @@ package com.google.cloud.tools.jib.plugins.common; +import com.google.cloud.tools.jib.configuration.FilePermissions; import com.google.cloud.tools.jib.filesystem.AbsoluteUnixPath; import com.google.cloud.tools.jib.frontend.JavaLayerConfigurations; import com.google.cloud.tools.jib.frontend.JavaLayerConfigurations.Builder; @@ -23,13 +24,28 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Map; import java.util.function.Predicate; /** Helper for constructing {@link JavaLayerConfigurations}. */ public class JavaLayerConfigurationsHelper { + /** + * Constructs a new {@link JavaLayerConfigurations} for a WAR project. + * + * @param explodedWar the exploded WAR directory + * @param appRoot root directory in the image where the app will be placed + * @param extraFilesDirectory path to the source directory for the extra files layer + * @param permissions map from path on container to file permissions + * @return {@link JavaLayerConfigurations} for the layers for the exploded WAR + * @throws IOException if adding layer contents fails + */ public static JavaLayerConfigurations fromExplodedWar( - Path explodedWar, AbsoluteUnixPath appRoot, Path extraFilesDirectory) throws IOException { + Path explodedWar, + AbsoluteUnixPath appRoot, + Path extraFilesDirectory, + Map permissions) + throws IOException { Path webInfLib = explodedWar.resolve("WEB-INF/lib"); Path webInfClasses = explodedWar.resolve("WEB-INF/classes"); @@ -66,7 +82,11 @@ public static JavaLayerConfigurations fromExplodedWar( // Adds all the extra files. if (Files.exists(extraFilesDirectory)) { layerBuilder.addDirectoryContents( - LayerType.EXTRA_FILES, extraFilesDirectory, path -> true, AbsoluteUnixPath.get("/")); + LayerType.EXTRA_FILES, + extraFilesDirectory, + path -> true, + AbsoluteUnixPath.get("/"), + permissions); } return layerBuilder.build(); diff --git a/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/PropertyNames.java b/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/PropertyNames.java index 85bd87c3c1..3c8876f1d9 100644 --- a/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/PropertyNames.java +++ b/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/PropertyNames.java @@ -41,6 +41,7 @@ public class PropertyNames { public static final String CONTAINER_USE_CURRENT_TIMESTAMP = "jib.container.useCurrentTimestamp"; public static final String USE_ONLY_PROJECT_CACHE = "jib.useOnlyProjectCache"; public static final String ALLOW_INSECURE_REGISTRIES = "jib.allowInsecureRegistries"; - public static final String EXTRA_DIRECTORY = "jib.extraDirectory"; + public static final String EXTRA_DIRECTORY_PATH = "jib.extraDirectory.path"; + public static final String EXTRA_DIRECTORY_PERMISSIONS = "jib.extraDirectory.permissions"; public static final String SKIP = "jib.skip"; } diff --git a/jib-plugins-common/src/test/java/com/google/cloud/tools/jib/plugins/common/ConfigurationPropertyValidatorTest.java b/jib-plugins-common/src/test/java/com/google/cloud/tools/jib/plugins/common/ConfigurationPropertyValidatorTest.java index e539f21e73..2a7f2a135d 100644 --- a/jib-plugins-common/src/test/java/com/google/cloud/tools/jib/plugins/common/ConfigurationPropertyValidatorTest.java +++ b/jib-plugins-common/src/test/java/com/google/cloud/tools/jib/plugins/common/ConfigurationPropertyValidatorTest.java @@ -16,9 +16,11 @@ package com.google.cloud.tools.jib.plugins.common; +import com.google.cloud.tools.jib.configuration.FilePermissions; import com.google.cloud.tools.jib.configuration.credentials.Credential; import com.google.cloud.tools.jib.event.EventDispatcher; import com.google.cloud.tools.jib.event.events.LogEvent; +import com.google.cloud.tools.jib.filesystem.AbsoluteUnixPath; import com.google.cloud.tools.jib.image.ImageReference; import com.google.cloud.tools.jib.image.InvalidImageReferenceException; import com.google.common.collect.ImmutableList; @@ -172,4 +174,24 @@ public void testParseMapProperty() { // pass } } + + @Test + public void testConvertPermissionsMap() { + Assert.assertEquals( + ImmutableMap.of( + AbsoluteUnixPath.get("/test/folder/file1"), + FilePermissions.fromOctalString("123"), + AbsoluteUnixPath.get("/test/file2"), + FilePermissions.fromOctalString("456")), + ConfigurationPropertyValidator.convertPermissionsMap( + ImmutableMap.of("/test/folder/file1", "123", "/test/file2", "456"))); + + try { + ConfigurationPropertyValidator.convertPermissionsMap( + ImmutableMap.of("a path", "not valid permission")); + Assert.fail(); + } catch (IllegalArgumentException ignored) { + // pass + } + } } diff --git a/jib-plugins-common/src/test/java/com/google/cloud/tools/jib/plugins/common/JavaLayerConfigurationsHelperTest.java b/jib-plugins-common/src/test/java/com/google/cloud/tools/jib/plugins/common/JavaLayerConfigurationsHelperTest.java index 46b16bee57..3ed758c562 100644 --- a/jib-plugins-common/src/test/java/com/google/cloud/tools/jib/plugins/common/JavaLayerConfigurationsHelperTest.java +++ b/jib-plugins-common/src/test/java/com/google/cloud/tools/jib/plugins/common/JavaLayerConfigurationsHelperTest.java @@ -26,6 +26,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; @@ -61,13 +62,17 @@ public void testFromExplodedWar() throws URISyntaxException, IOException { JavaLayerConfigurations configuration = JavaLayerConfigurationsHelper.fromExplodedWar( - explodedWar, AbsoluteUnixPath.get("/my/app"), extraFilesDirectory); + explodedWar, + AbsoluteUnixPath.get("/my/app"), + extraFilesDirectory, + Collections.emptyMap()); assertSourcePathsUnordered( - Arrays.asList(explodedWar.resolve("WEB-INF/lib/dependency-1.0.0.jar")), + Collections.singletonList(explodedWar.resolve("WEB-INF/lib/dependency-1.0.0.jar")), configuration.getDependencyLayerEntries()); assertSourcePathsUnordered( - Arrays.asList(explodedWar.resolve("WEB-INF/lib/dependencyX-1.0.0-SNAPSHOT.jar")), + Collections.singletonList( + explodedWar.resolve("WEB-INF/lib/dependencyX-1.0.0-SNAPSHOT.jar")), configuration.getSnapshotDependencyLayerEntries()); assertSourcePathsUnordered( Arrays.asList( @@ -100,10 +105,10 @@ public void testFromExplodedWar() throws URISyntaxException, IOException { configuration.getExtraFilesLayerEntries()); assertExtractionPathsUnordered( - Arrays.asList("/my/app/WEB-INF/lib/dependency-1.0.0.jar"), + Collections.singletonList("/my/app/WEB-INF/lib/dependency-1.0.0.jar"), configuration.getDependencyLayerEntries()); assertExtractionPathsUnordered( - Arrays.asList("/my/app/WEB-INF/lib/dependencyX-1.0.0-SNAPSHOT.jar"), + Collections.singletonList("/my/app/WEB-INF/lib/dependencyX-1.0.0-SNAPSHOT.jar"), configuration.getSnapshotDependencyLayerEntries()); assertExtractionPathsUnordered( Arrays.asList( From e62272a540069368e13cd60bfaeed0369e1627e9 Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Tue, 23 Oct 2018 11:20:01 -0400 Subject: [PATCH 2/6] Support old method of configuring extra directory with just a path --- .../java/com/google/cloud/tools/jib/gradle/JibExtension.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibExtension.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibExtension.java index f4a73eb89e..2a68dea65f 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibExtension.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibExtension.java @@ -17,6 +17,7 @@ package com.google.cloud.tools.jib.gradle; import com.google.cloud.tools.jib.plugins.common.PropertyNames; +import java.io.File; import org.gradle.api.Action; import org.gradle.api.Project; import org.gradle.api.model.ObjectFactory; @@ -107,6 +108,10 @@ public void extraDirectory(Action action) { action.execute(extraDirectory); } + public void setExtraDirectory(File extraDirectory) { + this.extraDirectory.setPath(extraDirectory); + } + public void setAllowInsecureRegistries(boolean allowInsecureRegistries) { this.allowInsecureRegistries.set(allowInsecureRegistries); } From 59f641d4a6ecc2b88fb3742aca53c901306fc963 Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Tue, 23 Oct 2018 11:26:13 -0400 Subject: [PATCH 3/6] Changelog update --- jib-gradle-plugin/CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jib-gradle-plugin/CHANGELOG.md b/jib-gradle-plugin/CHANGELOG.md index 09368f7eb8..891464b9a8 100644 --- a/jib-gradle-plugin/CHANGELOG.md +++ b/jib-gradle-plugin/CHANGELOG.md @@ -9,16 +9,16 @@ All notable changes to this project will be documented in this file. - `jib.to.credHelper` and `jib.from.credHelper` can be used to specify a credential helper suffix or a full path to a credential helper executable ([#925](https://github.com/GoogleContainerTools/jib/issues/925)) - `container.user` configuration parameter to configure the user and group to run the container as ([#1029](https://github.com/GoogleContainerTools/jib/issues/1029)) - Preliminary support for building images for WAR projects ([#431](https://github.com/GoogleContainerTools/jib/issues/431)) - +- `jib.extraDirectory` closure with a `path` and `permissions` field ([#794](https://github.com/GoogleContainerTools/jib/issues/794)) + - `jib.extraDirectory.path` configures the extra layer directory (still also configurable via `jib.extraDirectory = file(...)`) + - `jib.extraDirectory.permissions` is a map from absolute path on container to the file's permission bits (represented as an octal string) + ### Changed - Removed deprecated `jib.jvmFlags`, `jib.mainClass`, `jib.args`, and `jib.format` in favor of the equivalents under `jib.container` ([#461](https://github.com/GoogleContainerTools/jib/issues/461)) - `jibExportDockerContext` generates different directory layout and `Dockerfile` to enable WAR support ([#1007](https://github.com/GoogleContainerTools/jib/pull/1007)) - File timestamps in the built image are set to 1 second since the epoch (hence 1970-01-01T00:00:01Z) to resolve compatibility with applications on Java 6 or below where the epoch means nonexistent or I/O errors; previously they were set to the epoch ([#1079](https://github.com/GoogleContainerTools/jib/issues/1079)) - Sets tag to "latest" instead of "unspecified" if `jib.to.image` and project version are both unspecified when running `jibDockerBuild` or `jibBuildTar` ([#1096](https://github.com/GoogleContainerTools/jib/issues/1096)) -- `jib.extraDirectory` parameter is now a configuration object with a `path` and a `permissions` field ([#794](https://github.com/GoogleContainerTools/jib/issues/794)) - - `jib.extraDirectory.path` is used in place of the original `jib.extraDirectory` and allows you to configure the extra layer directory - - `jib.extraDirectory.permissions` is a map from absolute path on container to the file's permission bits (represented as an octal string) ### Fixed From e01811d79a52e5264d74df1628a0c38aaed57c7e Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Tue, 23 Oct 2018 12:26:10 -0400 Subject: [PATCH 4/6] Feedback --- .../tools/jib/gradle/ExtraDirectoryParameters.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoryParameters.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoryParameters.java index d414b6e3d9..8ff93b188f 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoryParameters.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoryParameters.java @@ -30,13 +30,13 @@ /** Object in {@link JibExtension} that configures the extra directory. */ public class ExtraDirectoryParameters { - private Path path; - private Map permissions = Collections.emptyMap(); - private static Path resolveDefaultExtraDirectory(Path projectDirectory) { return projectDirectory.resolve("src").resolve("main").resolve("jib"); } + private Path path; + private Map permissions = Collections.emptyMap(); + @Inject public ExtraDirectoryParameters(Path projectDirectory) { path = resolveDefaultExtraDirectory(projectDirectory); @@ -66,6 +66,13 @@ public void setPath(File path) { this.path = path.toPath(); } + /** + * Gets the permissions for files in the extra layer on the container. Maps from absolute path on + * the container to a 3-digit octal string representation of the file permission bits (e.g. {@code + * "/path/on/container" -> "755"}). + * + * @return the permissions map from path on container to file permissions + */ @Input public Map getPermissions() { if (System.getProperty(PropertyNames.EXTRA_DIRECTORY_PERMISSIONS) != null) { From 7241babf19b6e6cd9d7f8bba5723be516268a062 Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Tue, 23 Oct 2018 12:40:51 -0400 Subject: [PATCH 5/6] Change a test to use old extraDirectory config --- .../integration-test/resources/projects/simple/build.gradle | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/jib-gradle-plugin/src/integration-test/resources/projects/simple/build.gradle b/jib-gradle-plugin/src/integration-test/resources/projects/simple/build.gradle index 42d266fe94..2cf938a3c2 100644 --- a/jib-gradle-plugin/src/integration-test/resources/projects/simple/build.gradle +++ b/jib-gradle-plugin/src/integration-test/resources/projects/simple/build.gradle @@ -25,9 +25,7 @@ jib { ports = ['1000/tcp', '2000-2003/udp'] labels = [key1:'value1', key2:'value2'] } - extraDirectory { - path = file('src/main/custom-extra-dir') - } + extraDirectory = file('src/main/custom-extra-dir') // Does not have tests use user-level cache for base image layers. useOnlyProjectCache = true From 8dc7cc892df1d870e03bce154b89dce381527eac Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Tue, 23 Oct 2018 14:32:37 -0400 Subject: [PATCH 6/6] Fix javadocs --- .../cloud/tools/jib/gradle/GradleLayerConfigurations.java | 4 +++- .../jib/plugins/common/ConfigurationPropertyValidator.java | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleLayerConfigurations.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleLayerConfigurations.java index b3dfb19551..b508435784 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleLayerConfigurations.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleLayerConfigurations.java @@ -46,6 +46,7 @@ class GradleLayerConfigurations { * @param project the Gradle {@link Project} * @param logger the logger for providing feedback about the resolution * @param extraDirectory path to the source directory for the extra files layer + * @param permissions map from path on container to file permissions for extra-layer files * @param appRoot root directory in the image where the app will be placed * @return {@link JavaLayerConfigurations} for the layers for the Gradle {@link Project} * @throws IOException if an I/O exception occurred during resolution @@ -71,6 +72,7 @@ static JavaLayerConfigurations getForProject( * @param project the Gradle {@link Project} * @param logger the logger for providing feedback about the resolution * @param extraDirectory path to the source directory for the extra files layer + * @param permissions map from path on container to file permissions for extra-layer files * @param appRoot root directory in the image where the app will be placed * @return {@link JavaLayerConfigurations} for the layers for the Gradle {@link Project} * @throws IOException if an I/O exception occurred during resolution @@ -152,7 +154,7 @@ private static JavaLayerConfigurations getForNonWarProject( * * @param project the Gradle {@link Project} * @param extraDirectory path to the source directory for the extra files layer - * @param permissions map from path on container to file permissions + * @param permissions map from path on container to file permissions for extra-layer files * @param appRoot root directory in the image where the app will be placed * @return {@link JavaLayerConfigurations} for the layers for the Gradle {@link Project} * @throws IOException if an I/O exception occurred during resolution diff --git a/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/ConfigurationPropertyValidator.java b/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/ConfigurationPropertyValidator.java index 8ea8e971b7..31ecab43b5 100644 --- a/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/ConfigurationPropertyValidator.java +++ b/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/ConfigurationPropertyValidator.java @@ -188,8 +188,8 @@ public static List parseListProperty(String property) { } /** - * Validates and converts a {@code String->String} map to an {@code - * AbsoluteUnixPath->FilePermission} map. + * Validates and converts a {@code String->String} file-path-to-file-permissions map to an + * equivalent {@code AbsoluteUnixPath->FilePermission} map. * * @param inputMap the map to convert * @return the converted map