diff --git a/first-party/ownership-extension/maven/build.gradle b/first-party/ownership-extension/maven/build.gradle
index 7517d41..9ce5652 100644
--- a/first-party/ownership-extension/maven/build.gradle
+++ b/first-party/ownership-extension/maven/build.gradle
@@ -6,6 +6,7 @@ plugins {
dependencies {
compileOnly "com.google.cloud.tools:jib-maven-plugin-extension-api:${dependencyVersions.GRADLE_EXTENSION}"
+ compileOnly "com.google.guava:guava:${dependencyVersions.GUAVA}"
testImplementation "com.google.cloud.tools:jib-maven-plugin-extension-api:${dependencyVersions.GRADLE_EXTENSION}"
testImplementation "junit:junit:${dependencyVersions.JUNIT}"
@@ -44,9 +45,9 @@ publishing {
// Release plugin (git release commits and version updates)
release {
- tagTemplate = 'v$version-maven-ownership'
+ tagTemplate = 'v$version-ownership-maven'
git {
- requireBranch = /^maven_ownership_release_v\d+.*$/ //regex
+ requireBranch = /^ownership_maven_release_v\d+.*$/ //regex
}
}
/* RELEASE */
diff --git a/first-party/ownership-extension/maven/src/main/java/com/google/cloud/tools/jib/plugins/extension/maven/ownership/Configuration.java b/first-party/ownership-extension/maven/src/main/java/com/google/cloud/tools/jib/plugins/extension/maven/ownership/Configuration.java
new file mode 100644
index 0000000..2e0653e
--- /dev/null
+++ b/first-party/ownership-extension/maven/src/main/java/com/google/cloud/tools/jib/plugins/extension/maven/ownership/Configuration.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2020 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.plugins.extension.maven.ownership;
+
+import com.google.common.annotations.VisibleForTesting;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Extension-specific Maven configuration.
+ *
+ *
Example usage in {@code pom.xml}:
+ *
+ *
{@code
+ *
+ *
+ *
+ *
+ * /app/classes/**
+ * 300
+ *
+ *
+ *
+ * /static/**
+ * 300:500
+ *
+ *
+ *
+ * }
+ */
+public class Configuration {
+
+ public static class Rule {
+ @VisibleForTesting String glob = "";
+ @VisibleForTesting String ownership = "";
+
+ String getGlob() {
+ return glob;
+ }
+
+ String getOwnership() {
+ return ownership;
+ }
+ }
+
+ @VisibleForTesting List rules = new ArrayList<>();
+
+ List getRules() {
+ return rules;
+ }
+}
diff --git a/first-party/ownership-extension/maven/src/main/java/com/google/cloud/tools/jib/plugins/extension/maven/ownership/JibOwnershipExtension.java b/first-party/ownership-extension/maven/src/main/java/com/google/cloud/tools/jib/plugins/extension/maven/ownership/JibOwnershipExtension.java
new file mode 100644
index 0000000..71beb53
--- /dev/null
+++ b/first-party/ownership-extension/maven/src/main/java/com/google/cloud/tools/jib/plugins/extension/maven/ownership/JibOwnershipExtension.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2020 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.plugins.extension.maven.ownership;
+
+import com.google.cloud.tools.jib.api.buildplan.ContainerBuildPlan;
+import com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer;
+import com.google.cloud.tools.jib.api.buildplan.FileEntry;
+import com.google.cloud.tools.jib.maven.extension.JibMavenPluginExtension;
+import com.google.cloud.tools.jib.maven.extension.MavenData;
+import com.google.cloud.tools.jib.plugins.extension.ExtensionLogger;
+import com.google.cloud.tools.jib.plugins.extension.ExtensionLogger.LogLevel;
+import com.google.cloud.tools.jib.plugins.extension.JibPluginExtensionException;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.nio.file.Paths;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+public class JibOwnershipExtension implements JibMavenPluginExtension {
+
+ private Map pathMatchers = new LinkedHashMap<>();
+
+ @Override
+ public Optional> getExtraConfigType() {
+ return Optional.of(Configuration.class);
+ }
+
+ @Override
+ public ContainerBuildPlan extendContainerBuildPlan(
+ ContainerBuildPlan buildPlan,
+ Map properties,
+ Optional config,
+ MavenData mavenData,
+ ExtensionLogger logger)
+ throws JibPluginExtensionException {
+ logger.log(LogLevel.LIFECYCLE, "Running Jib Ownership Extension");
+ if (!config.isPresent()) {
+ logger.log(LogLevel.WARN, "Nothing configured for Jib Ownership Extension");
+ return buildPlan;
+ }
+
+ for (Configuration.Rule rule : config.get().getRules()) {
+ if (rule.getGlob().isEmpty()) {
+ throw new JibPluginExtensionException(
+ getClass(), "glob pattern not given in ownership configuration");
+ }
+ pathMatchers.put(
+ FileSystems.getDefault().getPathMatcher("glob:" + rule.getGlob()), rule.getOwnership());
+ }
+
+ @SuppressWarnings("unchecked")
+ List layers = (List) buildPlan.getLayers();
+ List newLayers =
+ layers.stream().map(this::applyRulesToLayer).collect(Collectors.toList());
+ return buildPlan.toBuilder().setLayers(newLayers).build();
+ }
+
+ private FileEntriesLayer applyRulesToLayer(FileEntriesLayer layer) {
+ List entries =
+ layer.getEntries().stream().map(this::applyRulesToFileEntry).collect(Collectors.toList());
+ return layer.toBuilder().setEntries(entries).build();
+ }
+
+ private FileEntry applyRulesToFileEntry(FileEntry entry) {
+ String newOwnership = null;
+
+ for (Entry mapEntry : pathMatchers.entrySet()) {
+ PathMatcher matcher = mapEntry.getKey();
+ Path pathInContainer = Paths.get(entry.getExtractionPath().toString());
+ if (matcher.matches(pathInContainer)) {
+ newOwnership = mapEntry.getValue();
+ }
+ }
+ return newOwnership == null
+ ? entry
+ : new FileEntry(
+ entry.getSourceFile(),
+ entry.getExtractionPath(),
+ entry.getPermissions(),
+ entry.getModificationTime(),
+ newOwnership);
+ }
+}
diff --git a/first-party/ownership-extension/maven/src/main/resources/META-INF/services/com.google.cloud.tools.jib.maven.extension.JibMavenPluginExtension b/first-party/ownership-extension/maven/src/main/resources/META-INF/services/com.google.cloud.tools.jib.maven.extension.JibMavenPluginExtension
new file mode 100644
index 0000000..b988283
--- /dev/null
+++ b/first-party/ownership-extension/maven/src/main/resources/META-INF/services/com.google.cloud.tools.jib.maven.extension.JibMavenPluginExtension
@@ -0,0 +1 @@
+com.google.cloud.tools.jib.plugins.extension.maven.ownership.JibOwnershipExtension
\ No newline at end of file
diff --git a/first-party/ownership-extension/maven/src/test/java/com/google/cloud/tools/jib/plugins/extension/maven/ownership/JibOwnershipExtensionTest.java b/first-party/ownership-extension/maven/src/test/java/com/google/cloud/tools/jib/plugins/extension/maven/ownership/JibOwnershipExtensionTest.java
new file mode 100644
index 0000000..23d90dc
--- /dev/null
+++ b/first-party/ownership-extension/maven/src/test/java/com/google/cloud/tools/jib/plugins/extension/maven/ownership/JibOwnershipExtensionTest.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2020 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.plugins.extension.maven.ownership;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.verify;
+
+import com.google.cloud.tools.jib.api.buildplan.AbsoluteUnixPath;
+import com.google.cloud.tools.jib.api.buildplan.ContainerBuildPlan;
+import com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer;
+import com.google.cloud.tools.jib.api.buildplan.FileEntry;
+import com.google.cloud.tools.jib.maven.extension.MavenData;
+import com.google.cloud.tools.jib.plugins.extension.ExtensionLogger;
+import com.google.cloud.tools.jib.plugins.extension.ExtensionLogger.LogLevel;
+import com.google.cloud.tools.jib.plugins.extension.JibPluginExtensionException;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class JibOwnershipExtensionTest {
+
+ @Mock private MavenData mavenData;
+ @Mock private ExtensionLogger logger;
+
+ private Map properties;
+
+ private static List mapLayerEntries(
+ FileEntriesLayer layer, Function mapper) {
+ return layer.getEntries().stream().map(mapper).collect(Collectors.toList());
+ }
+
+ @Test
+ public void testExtendContainerBuildPlan_noConfiguration() throws JibPluginExtensionException {
+ ContainerBuildPlan buildPlan = ContainerBuildPlan.builder().build();
+ ContainerBuildPlan newPlan =
+ new JibOwnershipExtension()
+ .extendContainerBuildPlan(buildPlan, properties, Optional.empty(), mavenData, logger);
+ assertSame(buildPlan, newPlan);
+ verify(logger).log(LogLevel.WARN, "Nothing configured for Jib Ownership Extension");
+ }
+
+ @Test
+ public void testExtendContainerBuildPlan_noGlobGiven() {
+ ContainerBuildPlan buildPlan = ContainerBuildPlan.builder().build();
+ Configuration config = new Configuration();
+ config.rules = Arrays.asList(new Configuration.Rule());
+ try {
+ new JibOwnershipExtension()
+ .extendContainerBuildPlan(buildPlan, properties, Optional.of(config), mavenData, logger);
+ fail();
+ } catch (JibPluginExtensionException ex) {
+ assertEquals(JibOwnershipExtension.class, ex.getExtensionClass());
+ assertEquals("glob pattern not given in ownership configuration", ex.getMessage());
+ }
+ }
+
+ @Test
+ public void testExtendContainerBuildPlan() throws JibPluginExtensionException {
+ FileEntriesLayer layer1 =
+ FileEntriesLayer.builder()
+ .addEntry(Paths.get("whatever"), AbsoluteUnixPath.get("/target/file"))
+ .addEntry(Paths.get("whatever"), AbsoluteUnixPath.get("/target/another"))
+ .addEntry(Paths.get("whatever"), AbsoluteUnixPath.get("/target/sub/dir/file"))
+ .addEntry(Paths.get("whatever"), AbsoluteUnixPath.get("/target/sub/dir/another"))
+ .addEntry(Paths.get("whatever"), AbsoluteUnixPath.get("/untouched/file"))
+ .addEntry(Paths.get("whatever"), AbsoluteUnixPath.get("/untouched/another"))
+ .build();
+ FileEntriesLayer layer2 =
+ FileEntriesLayer.builder()
+ .addEntry(Paths.get("whatever"), AbsoluteUnixPath.get("/target/foo"))
+ .addEntry(Paths.get("whatever"), AbsoluteUnixPath.get("/target/bar"))
+ .addEntry(Paths.get("whatever"), AbsoluteUnixPath.get("/target/sub/dir/foo"))
+ .addEntry(Paths.get("whatever"), AbsoluteUnixPath.get("/target/sub/dir/bar"))
+ .addEntry(Paths.get("whatever"), AbsoluteUnixPath.get("/untouched/foo"))
+ .addEntry(Paths.get("whatever"), AbsoluteUnixPath.get("/untouched/bar"))
+ .build();
+ ContainerBuildPlan buildPlan =
+ ContainerBuildPlan.builder().addLayer(layer1).addLayer(layer2).build();
+
+ Configuration.Rule rule1 = new Configuration.Rule();
+ rule1.glob = "/target/**";
+ rule1.ownership = "10:20";
+ Configuration.Rule rule2 = new Configuration.Rule();
+ rule2.glob = "**/bar";
+ rule2.ownership = "999:777";
+ Configuration config = new Configuration();
+ config.rules = Arrays.asList(rule1, rule2);
+
+ ContainerBuildPlan newPlan =
+ new JibOwnershipExtension()
+ .extendContainerBuildPlan(
+ buildPlan, properties, Optional.of(config), mavenData, logger);
+
+ FileEntriesLayer newLayer1 = (FileEntriesLayer) newPlan.getLayers().get(0);
+ FileEntriesLayer newLayer2 = (FileEntriesLayer) newPlan.getLayers().get(1);
+
+ assertEquals(
+ Arrays.asList(
+ AbsoluteUnixPath.get("/target/file"),
+ AbsoluteUnixPath.get("/target/another"),
+ AbsoluteUnixPath.get("/target/sub/dir/file"),
+ AbsoluteUnixPath.get("/target/sub/dir/another"),
+ AbsoluteUnixPath.get("/untouched/file"),
+ AbsoluteUnixPath.get("/untouched/another")),
+ mapLayerEntries(newLayer1, FileEntry::getExtractionPath));
+ assertEquals(
+ Arrays.asList("10:20", "10:20", "10:20", "10:20", "", ""),
+ mapLayerEntries(newLayer1, FileEntry::getOwnership));
+
+ assertEquals(
+ Arrays.asList(
+ AbsoluteUnixPath.get("/target/foo"),
+ AbsoluteUnixPath.get("/target/bar"),
+ AbsoluteUnixPath.get("/target/sub/dir/foo"),
+ AbsoluteUnixPath.get("/target/sub/dir/bar"),
+ AbsoluteUnixPath.get("/untouched/foo"),
+ AbsoluteUnixPath.get("/untouched/bar")),
+ mapLayerEntries(newLayer2, FileEntry::getExtractionPath));
+ assertEquals(
+ Arrays.asList("10:20", "999:777", "10:20", "999:777", "", "999:777"),
+ mapLayerEntries(newLayer2, FileEntry::getOwnership));
+ }
+
+ @Test
+ public void testExtendContainerBuildPlan_lastConfigWins() throws JibPluginExtensionException {
+ FileEntriesLayer layer =
+ FileEntriesLayer.builder()
+ .addEntry(Paths.get("whatever"), AbsoluteUnixPath.get("/target/file"))
+ .build();
+ ContainerBuildPlan buildPlan = ContainerBuildPlan.builder().addLayer(layer).build();
+
+ Configuration.Rule rule1 = new Configuration.Rule();
+ rule1.glob = "**";
+ rule1.ownership = "10:20";
+ Configuration.Rule rule2 = new Configuration.Rule();
+ rule2.glob = "**";
+ rule2.ownership = "999:777";
+ Configuration config = new Configuration();
+ config.rules = Arrays.asList(rule1, rule2);
+
+ ContainerBuildPlan newPlan =
+ new JibOwnershipExtension()
+ .extendContainerBuildPlan(
+ buildPlan, properties, Optional.of(config), mavenData, logger);
+
+ FileEntriesLayer newLayer = (FileEntriesLayer) newPlan.getLayers().get(0);
+ assertEquals(Arrays.asList("999:777"), mapLayerEntries(newLayer, FileEntry::getOwnership));
+ }
+}