diff --git a/jib-gradle-plugin/CHANGELOG.md b/jib-gradle-plugin/CHANGELOG.md index 262de8e832..8140b5d90a 100644 --- a/jib-gradle-plugin/CHANGELOG.md +++ b/jib-gradle-plugin/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ### Added - Included `imagePushed` field to image metadata json output file which provides information on whether an image was pushed by Jib. Note that the output file is `build/jib-image.json` by default or configurable with `jib.outputPaths.imageJson`. ([#3641](https://github.com/GoogleContainerTools/jib/pull/3641)) +- Added lazy evaluation for `jib.extraDirectories` parameters using Gradle Property and Provider. ([#3737](https://github.com/GoogleContainerTools/jib/issues/3737)) ### Changed diff --git a/jib-gradle-plugin/README.md b/jib-gradle-plugin/README.md index 5d94e2ec1b..32c6de2f8d 100644 --- a/jib-gradle-plugin/README.md +++ b/jib-gradle-plugin/README.md @@ -459,6 +459,28 @@ Using `paths` as a closure, you may also specify the target of the copy and incl } ``` +You can also configure `paths` and `permissions` through [lazy configuration in Gradle](https://docs.gradle.org/current/userguide/lazy_configuration.html), using providers in `build.gradle`: + +```groovy +extraDirectories { + paths = project.provider { 'src/main/custom-extra-dir' } + permissions = project.provider { ['/path/on/container/to/fileA': '755'] } +} +``` + +```groovy +extraDirectories { + paths { + path { + from = project.provider { 'src/main/custom-extra-dir' } + into = project.provider { '/dest-in-container' } + includes = project.provider { ['*.txt', '**/*.txt'] } + excludes = project.provider { ['hidden.txt'] } + } + } +} +``` + ### Authentication Methods Pushing/pulling from private registries require authorization credentials. diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoriesParameters.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoriesParameters.java index ae65353580..30dc526e89 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoriesParameters.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoriesParameters.java @@ -24,11 +24,14 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import javax.annotation.Nonnull; import javax.inject.Inject; import org.gradle.api.Action; import org.gradle.api.Project; import org.gradle.api.model.ObjectFactory; import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.MapProperty; +import org.gradle.api.provider.Provider; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Internal; @@ -40,7 +43,7 @@ public class ExtraDirectoriesParameters { private ListProperty paths; private ExtraDirectoryParametersSpec spec; - private Map permissions = Collections.emptyMap(); + private MapProperty permissions; @Inject public ExtraDirectoriesParameters(ObjectFactory objects, Project project) { @@ -48,6 +51,7 @@ public ExtraDirectoriesParameters(ObjectFactory objects, Project project) { this.project = project; paths = objects.listProperty(ExtraDirectoryParameters.class).empty(); spec = objects.newInstance(ExtraDirectoryParametersSpec.class, project, paths); + permissions = objects.mapProperty(String.class, String.class).empty(); } public void paths(Action action) { @@ -92,10 +96,28 @@ public List getPaths() { * @param paths paths to set. */ public void setPaths(Object paths) { - this.paths.set( - project.files(paths).getFiles().stream() - .map(file -> new ExtraDirectoryParameters(objects, project, file.toPath(), "/")) - .collect(Collectors.toList())); + this.paths.set(convertToExtraDirectoryParametersList(paths)); + } + + /** + * Sets paths, for lazy evaluation where {@code paths} is a {@link Provider} of a suitable object. + * + * @param paths provider of paths to set + * @see #setPaths(Object) + */ + public void setPaths(Provider paths) { + this.paths.set(paths.map(this::convertToExtraDirectoryParametersList)); + } + + /** + * Helper method to convert {@code Object} to {@code List} in {@code + * setFrom}. + */ + @Nonnull + private List convertToExtraDirectoryParametersList(Object obj) { + return project.files(obj).getFiles().stream() + .map(file -> new ExtraDirectoryParameters(objects, project, file.toPath(), "/")) + .collect(Collectors.toList()); } /** @@ -106,15 +128,15 @@ public void setPaths(Object paths) { * @return the permissions map from path on container to file permissions */ @Input - public Map getPermissions() { + public MapProperty getPermissions() { String property = System.getProperty(PropertyNames.EXTRA_DIRECTORIES_PERMISSIONS); if (property != null) { - return ConfigurationPropertyValidator.parseMapProperty(property); + Map parsedPermissions = + ConfigurationPropertyValidator.parseMapProperty(property); + if (!parsedPermissions.equals(permissions.get())) { + permissions.set(parsedPermissions); + } } 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/ExtraDirectoryParameters.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoryParameters.java index 008fd53b85..537b51f085 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 @@ -24,6 +24,8 @@ import org.gradle.api.Project; import org.gradle.api.model.ObjectFactory; import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.provider.Provider; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Internal; @@ -31,49 +33,59 @@ public class ExtraDirectoryParameters implements ExtraDirectoriesConfiguration { private Project project; - private Path from = Paths.get(""); - private String into = "/"; + private Property from; + private Property into; private ListProperty includes; private ListProperty excludes; @Inject public ExtraDirectoryParameters(ObjectFactory objects, Project project) { this.project = project; - includes = objects.listProperty(String.class).empty(); - excludes = objects.listProperty(String.class).empty(); + this.from = objects.property(Path.class).value(Paths.get("")); + this.into = objects.property(String.class).value("/"); + this.includes = objects.listProperty(String.class).empty(); + this.excludes = objects.listProperty(String.class).empty(); } ExtraDirectoryParameters(ObjectFactory objects, Project project, Path from, String into) { this(objects, project); - this.from = from; - this.into = into; + this.from = objects.property(Path.class).value(from); + this.into = objects.property(String.class).value(into); } @Input public String getFromString() { // Gradle warns about @Input annotations on File objects, so we have to expose a getter for a // String to make them go away. - return from.toString(); + return from.get().toString(); } @Override @Internal public Path getFrom() { - return from; + return from.get(); } public void setFrom(Object from) { - this.from = project.file(from).toPath(); + this.from.set(project.file(from).toPath()); + } + + public void setFrom(Provider from) { + this.from.set(from.map(obj -> project.file(obj).toPath())); } @Override @Input public String getInto() { - return into; + return into.get(); } public void setInto(String into) { - this.into = into; + this.into.set(into); + } + + public void setInto(Provider into) { + this.into.set(into); } @Input diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleRawConfiguration.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleRawConfiguration.java index 1e8359bb37..186ed0f020 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleRawConfiguration.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleRawConfiguration.java @@ -174,7 +174,8 @@ public List getExtraDirectories() { @Override public Map getExtraDirectoryPermissions() { - return TaskCommon.convertPermissionsMap(jibExtension.getExtraDirectories().getPermissions()); + return TaskCommon.convertPermissionsMap( + jibExtension.getExtraDirectories().getPermissions().get()); } @Override 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 c6cafa3c71..bd15b9e0c4 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 @@ -33,6 +33,8 @@ import java.util.List; import java.util.Properties; import org.gradle.api.Project; +import org.gradle.api.provider.Provider; +import org.gradle.api.provider.ProviderFactory; import org.gradle.testfixtures.ProjectBuilder; import org.junit.Before; import org.junit.Rule; @@ -241,7 +243,7 @@ public void testExtraDirectories_default() { assertThat(testJibExtension.getExtraDirectories().getPaths()).hasSize(1); assertThat(testJibExtension.getExtraDirectories().getPaths().get(0).getFrom()) .isEqualTo(fakeProject.getProjectDir().toPath().resolve("src/main/jib")); - assertThat(testJibExtension.getExtraDirectories().getPermissions()).isEmpty(); + assertThat(testJibExtension.getExtraDirectories().getPermissions().get()).isEmpty(); } @Test @@ -249,15 +251,34 @@ public void testExtraDirectories() { testJibExtension.extraDirectories( extraDirectories -> { extraDirectories.setPaths("test/path"); - extraDirectories.setPermissions(ImmutableMap.of("file1", "123", "file2", "456")); }); assertThat(testJibExtension.getExtraDirectories().getPaths()).hasSize(1); assertThat(testJibExtension.getExtraDirectories().getPaths().get(0).getFrom()) .isEqualTo(fakeProject.getProjectDir().toPath().resolve("test/path")); - assertThat(testJibExtension.getExtraDirectories().getPermissions()) - .containsExactly("file1", "123", "file2", "456") - .inOrder(); + } + + @Test + public void testExtraDirectories_lazyEvaluation_setFromInto() { + testJibExtension.extraDirectories( + extraDirectories -> + extraDirectories.paths( + paths -> { + ProviderFactory providerFactory = fakeProject.getProviders(); + Provider from = providerFactory.provider(() -> "test/path"); + Provider into = providerFactory.provider(() -> "/target"); + paths.path( + path -> { + path.setFrom(from); + path.setInto(into); + }); + })); + + assertThat(testJibExtension.getExtraDirectories().getPaths()).hasSize(1); + assertThat(testJibExtension.getExtraDirectories().getPaths().get(0).getFrom()) + .isEqualTo(fakeProject.getProjectDir().toPath().resolve("test/path")); + assertThat(testJibExtension.getExtraDirectories().getPaths().get(0).getInto()) + .isEqualTo("/target"); } @Test @@ -309,6 +330,23 @@ public void testExtraDirectories_stringListForPaths() { .isEqualTo(fakeProject.getProjectDir().toPath().resolve("another/path")); } + @Test + public void testExtraDirectories_lazyEvaluation_StringListForPaths() { + testJibExtension.extraDirectories( + extraDirectories -> { + ProviderFactory providerFactory = fakeProject.getProviders(); + Provider paths = + providerFactory.provider(() -> Arrays.asList("test/path", "another/path")); + extraDirectories.setPaths(paths); + }); + + assertThat(testJibExtension.getExtraDirectories().getPaths()).hasSize(2); + assertThat(testJibExtension.getExtraDirectories().getPaths().get(0).getFrom()) + .isEqualTo(fakeProject.getProjectDir().toPath().resolve("test/path")); + assertThat(testJibExtension.getExtraDirectories().getPaths().get(1).getFrom()) + .isEqualTo(fakeProject.getProjectDir().toPath().resolve("another/path")); + } + @Test public void testExtraDirectories_fileListForPaths() { testJibExtension.extraDirectories( @@ -456,7 +494,7 @@ public void testProperties() { assertThat(testJibExtension.getExtraDirectories().getPaths().get(1).getFrom()) .isEqualTo(Paths.get("/bar/baz")); System.setProperty("jib.extraDirectories.permissions", "/foo/bar=707,/baz=456"); - assertThat(testJibExtension.getExtraDirectories().getPermissions()) + assertThat(testJibExtension.getExtraDirectories().getPermissions().get()) .containsExactly("/foo/bar", "707", "/baz", "456") .inOrder(); diff --git a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibPluginTest.java b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibPluginTest.java index a5687b949d..7ba5ed904c 100644 --- a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibPluginTest.java +++ b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibPluginTest.java @@ -368,6 +368,37 @@ public void testLazyEvalForLabels() { "labels contain values [firstkey:updated-first-label, secondKey:updated-second-label]"); } + @Test + public void testLazyEvalForExtraDirectories() { + BuildResult checkExtraDirectories = + testProject.build("check-extra-directories", "-Djib.console=plain"); + assertThat(checkExtraDirectories.getOutput()).contains("[/updated:755]"); + assertThat(checkExtraDirectories.getOutput()).contains("updated-custom-extra-dir"); + } + + @Test + public void testLazyEvalForExtraDirectories_individualPaths() throws IOException { + BuildResult checkExtraDirectories = + testProject.build( + "check-extra-directories", "-b=build-extra-dirs.gradle", "-Djib.console=plain"); + + Path extraDirectoryPath = + testProject + .getProjectRoot() + .resolve("src") + .resolve("main") + .resolve("updated-custom-extra-dir") + .toRealPath(); + assertThat(checkExtraDirectories.getOutput()) + .contains("extraDirectories (from): [" + extraDirectoryPath + "]"); + assertThat(checkExtraDirectories.getOutput()) + .contains("extraDirectories (into): [/updated-custom-into-dir]"); + assertThat(checkExtraDirectories.getOutput()) + .contains("extraDirectories (includes): [[include.txt]]"); + assertThat(checkExtraDirectories.getOutput()) + .contains("extraDirectories (excludes): [[exclude.txt]]"); + } + private Project createProject(String... plugins) { Project project = ProjectBuilder.builder().withProjectDir(testProjectRoot.getRoot()).withName("root").build(); diff --git a/jib-gradle-plugin/src/test/resources/gradle/projects/lazy-evaluation/build-extra-dirs.gradle b/jib-gradle-plugin/src/test/resources/gradle/projects/lazy-evaluation/build-extra-dirs.gradle new file mode 100644 index 0000000000..628eb328d4 --- /dev/null +++ b/jib-gradle-plugin/src/test/resources/gradle/projects/lazy-evaluation/build-extra-dirs.gradle @@ -0,0 +1,47 @@ +plugins { + id 'java' + id 'com.google.cloud.tools.jib' +} + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + implementation 'com.google.guava:guava:23.6-jre' +} + +project.ext.value = 'original' + +project.afterEvaluate { + project.ext.value = 'updated' + project.ext.getCustomIncludes = { -> return ['include.txt'] } + project.ext.getCustomExcludes = { -> return ['exclude.txt'] } +} + +jib { + extraDirectories { + paths { + path { + from = project.provider { 'src/main/' + project.ext.value + '-custom-extra-dir' } + into = project.provider { '/' + project.ext.value + '-custom-into-dir' } + includes = project.provider { -> project.ext.getCustomIncludes() } + excludes = project.provider { -> project.ext.getCustomExcludes() } + } + } + } +} + +tasks.register('check-extra-directories') { + List from = project.extensions.getByName('jib')['extraDirectories']['paths'].collect{ path -> path['from']} + List into = project.extensions.getByName('jib')['extraDirectories']['paths'].collect{ path -> path['into']} + List includes = project.extensions.getByName('jib')['extraDirectories']['paths'].collect{ path -> path['includes'].get()} + List excludes = project.extensions.getByName('jib')['extraDirectories']['paths'].collect{ path -> path['excludes'].get()} + println('extraDirectories (from): ' + from) + println('extraDirectories (into): ' + into) + println('extraDirectories (includes): ' + includes) + println('extraDirectories (excludes): ' + excludes) +} diff --git a/jib-gradle-plugin/src/test/resources/gradle/projects/lazy-evaluation/build.gradle b/jib-gradle-plugin/src/test/resources/gradle/projects/lazy-evaluation/build.gradle index c188939cd3..ed358e4008 100644 --- a/jib-gradle-plugin/src/test/resources/gradle/projects/lazy-evaluation/build.gradle +++ b/jib-gradle-plugin/src/test/resources/gradle/projects/lazy-evaluation/build.gradle @@ -18,6 +18,7 @@ project.ext.value = 'original' project.afterEvaluate { project.ext.value = 'updated' + project.ext.getCustomPermissions = { -> return ['/updated': '755'] } } jib { @@ -33,9 +34,20 @@ jib { ] } } + extraDirectories { + paths = project.provider { ['src/main/' + project.ext.value + '-custom-extra-dir'] } + permissions = project.provider { -> project.ext.getCustomPermissions() } + } } tasks.register('showlabels') { Map prop = project.extensions.getByName('jib')['container']['labels'].get() println('labels contain values ' + prop) } + +tasks.register('check-extra-directories') { + List paths = project.extensions.getByName('jib')['extraDirectories']['paths'].collect{ path -> path['from']} + Map permissions = project.extensions.getByName('jib')['extraDirectories']['permissions'].get() + println('extraDirectories paths: ' + paths) + println('extraDirectories permissions: ' + permissions) +} diff --git a/jib-gradle-plugin/src/test/resources/gradle/projects/lazy-evaluation/src/main/updated-custom-extra-dir/foo b/jib-gradle-plugin/src/test/resources/gradle/projects/lazy-evaluation/src/main/updated-custom-extra-dir/foo new file mode 100644 index 0000000000..54315cd5f5 --- /dev/null +++ b/jib-gradle-plugin/src/test/resources/gradle/projects/lazy-evaluation/src/main/updated-custom-extra-dir/foo @@ -0,0 +1 @@ +Unused file for committing parent directory so that it exists for extraDirectories tests \ No newline at end of file