You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by an...@apache.org on 2021/08/03 13:05:43 UTC

[sling-org-apache-sling-feature-cpconverter] 01/01: SLING-10692 : VaultPackageAssembler.mergeFilters drops propertyFilterSets SLING-10694 : CPConverter drops mode from filters SLING-10699 : Incomplete path conversion in VaultPackageAssembler.toRepositoryPaths

This is an automated email from the ASF dual-hosted git repository.

angela pushed a commit to branch SLING-10692
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-cpconverter.git

commit 297967274e6e40fcd829efec335a5f72fc6b1f21
Author: angela <an...@adobe.com>
AuthorDate: Tue Aug 3 15:05:21 2021 +0200

    SLING-10692 : VaultPackageAssembler.mergeFilters drops propertyFilterSets
    SLING-10694 : CPConverter drops mode from filters
    SLING-10699 : Incomplete path conversion in VaultPackageAssembler.toRepositoryPaths
---
 .../cpconverter/vltpkg/VaultPackageAssembler.java  |  68 +++++++--
 .../ConverterUserAndPermissionTest.java            | 161 ++++++++++++++++++---
 .../vltpkg/VaultPackageAssemblerTest.java          |  60 ++++++--
 .../cpconverter/demo-cp-single-user-root.zip       | Bin 0 -> 15692 bytes
 .../cpconverter/demo-cp-with-importmode.zip        | Bin 0 -> 15802 bytes
 5 files changed, 242 insertions(+), 47 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/VaultPackageAssembler.java b/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/VaultPackageAssembler.java
index 3961aff..42b1d1e 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/VaultPackageAssembler.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/VaultPackageAssembler.java
@@ -49,8 +49,10 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Properties;
@@ -202,9 +204,16 @@ public class VaultPackageAssembler implements EntryHandler {
     }
 
     public void mergeFilters(@NotNull WorkspaceFilter filter) {
+        Map<String, PathFilterSet> propFilterSets = extractPropertyFilters(filter);
+        // copy over all node-filters together if the corresponding property-filters if existing.
         for (PathFilterSet pathFilterSet : filter.getFilterSets()) {
             if (!OSGI_BUNDLE_PATTERN.matcher(pathFilterSet.getRoot()).matches()) {
-                this.filter.add(pathFilterSet);
+                PathFilterSet propSet = propFilterSets.remove(pathFilterSet.getRoot());
+                if (propSet != null) {
+                    this.filter.add(pathFilterSet, propSet);
+                } else {
+                    this.filter.add(pathFilterSet);
+                }
             }
         }
     }
@@ -351,7 +360,15 @@ public class VaultPackageAssembler implements EntryHandler {
     private static @NotNull Set<String> toRepositoryPaths(@NotNull Set<String> paths) {
         return paths.stream().map(s -> {
             if (s.startsWith("/jcr_root")) {
-                return s.substring("/jcr_root".length());
+                String path = PlatformNameFormat.getRepositoryPath(s.substring("/jcr_root".length()));
+                if (path.endsWith("/.content.xml")) {
+                    return path.substring(0, path.lastIndexOf("/.content.xml"));
+                } else if (path.endsWith(".xml")) {
+                    // remove .xml extension from policy-nodes
+                    return path.substring(0, path.lastIndexOf(".xml"));
+                } else {
+                    return path;
+                }
             } else {
                 return s;
             }
@@ -361,11 +378,9 @@ public class VaultPackageAssembler implements EntryHandler {
     private static @NotNull WorkspaceFilter createAdjustedFilter(@NotNull WorkspaceFilter base, @NotNull Set<String> filteredPaths, @NotNull Set<String> cpPaths) throws IOException {
         try {
             DefaultWorkspaceFilter dwf = new DefaultWorkspaceFilter();
-            for (PathFilterSet pfs : base.getPropertyFilterSets()) {
-                processPathFilterSet(pfs, dwf, true, filteredPaths, cpPaths);
-            }
+            Map<String, PathFilterSet> propFilters = extractPropertyFilters(base);
             for (PathFilterSet pfs : base.getFilterSets()) {
-                processPathFilterSet(pfs, dwf, false, filteredPaths, cpPaths);
+                processPathFilterSet(pfs, propFilters, dwf, filteredPaths, cpPaths);
             }
             return dwf;
         } catch (ConfigurationException e) {
@@ -373,18 +388,33 @@ public class VaultPackageAssembler implements EntryHandler {
         }
     }
 
-    private static void processPathFilterSet(@NotNull PathFilterSet pfs, @NotNull DefaultWorkspaceFilter newFilter,
-                                             boolean isPropertyFilterSet, @NotNull Set<String> filteredPaths,
+    private static void processPathFilterSet(@NotNull PathFilterSet pfs, @NotNull Map<String, PathFilterSet> propFilters, 
+                                             @NotNull DefaultWorkspaceFilter newFilter, @NotNull Set<String> filteredPaths,
                                              @NotNull Set<String> cpPaths) throws ConfigurationException {
         if (cpPaths.stream().noneMatch(pfs::covers)) {
             // the given filterset no longer covers any of the paths included in the converted content package
-            // -> save to no longer include it in the new workspace filter.
+            // -> ok to no longer include it in the new workspace filter.
             return;
         }
         
+        // create a new node path-filter-set (and if existing the corresponding property filter)
+        PathFilterSet nodeFilterSet = copyPathFilterSet(pfs, filteredPaths);
+        PathFilterSet propPfs = propFilters.remove(pfs.getRoot());
+        if (propPfs != null) {
+            // note: no need to add additional exclude entries for property-filters
+            PathFilterSet propFilterSet = copyPathFilterSet(propPfs, Collections.emptySet());
+            newFilter.add(nodeFilterSet, propFilterSet);
+        } else {
+            newFilter.add(nodeFilterSet);
+        }
+    }
+    
+    @NotNull
+    private static PathFilterSet copyPathFilterSet(@NotNull PathFilterSet pfs, @NotNull Set<String> filteredPaths) throws ConfigurationException {
         // create a new path-filter-set
         PathFilterSet filterSet = new PathFilterSet(pfs.getRoot());
         filterSet.setType(pfs.getType());
+        filterSet.setImportMode(pfs.getImportMode());
 
         // copy all entries to the new path-filter-set
         for (FilterSet.Entry<PathFilter> entry : pfs.getEntries()) {
@@ -401,11 +431,21 @@ public class VaultPackageAssembler implements EntryHandler {
                 filterSet.addExclude(new DefaultPathFilter(path));
             }
         }
-        if (isPropertyFilterSet) {
-            newFilter.addPropertyFilterSet(filterSet);
-        } else {
-            newFilter.add(filterSet);
-        }
+        return filterSet;
+    }
+
+    /**
+     * Extract all property-filters and remember them for later as DefaultWorkspaceFilter.addPropertyFilterSet
+     * is deprecated in favor of DefaultWorkspaceFilter.add(PathFilterSet nodeFilter, PathFilterSet propFilter).
+     * The map created then allows to process property-filters together with node filters.
+     *
+     * @param base The filter from which to extract property-filters
+     * @return A map of path (the root) to the corresponding property-pathfilterset.
+     */
+    private static Map<String, PathFilterSet> extractPropertyFilters(@NotNull WorkspaceFilter base) {
+        Map<String, PathFilterSet> propFilters = new LinkedHashMap<>();
+        base.getPropertyFilterSets().forEach(pathFilterSet -> propFilters.put(pathFilterSet.getRoot(), pathFilterSet));
+        return propFilters;
     }
 
     private static void addDirectory(@NotNull final JarOutputStream jos, @NotNull final File dir, final int prefixLength) throws IOException {
diff --git a/src/test/java/org/apache/sling/feature/cpconverter/ConverterUserAndPermissionTest.java b/src/test/java/org/apache/sling/feature/cpconverter/ConverterUserAndPermissionTest.java
index 178f492..21777c1 100644
--- a/src/test/java/org/apache/sling/feature/cpconverter/ConverterUserAndPermissionTest.java
+++ b/src/test/java/org/apache/sling/feature/cpconverter/ConverterUserAndPermissionTest.java
@@ -18,7 +18,12 @@ package org.apache.sling.feature.cpconverter;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
-import org.apache.jackrabbit.vault.packaging.PackageType;
+import org.apache.jackrabbit.vault.fs.api.FilterSet;
+import org.apache.jackrabbit.vault.fs.api.ImportMode;
+import org.apache.jackrabbit.vault.fs.api.PathFilter;
+import org.apache.jackrabbit.vault.fs.api.PathFilterSet;
+import org.apache.jackrabbit.vault.fs.api.WorkspaceFilter;
+import org.apache.jackrabbit.vault.fs.config.DefaultWorkspaceFilter;
 import org.apache.sling.feature.Extension;
 import org.apache.sling.feature.Feature;
 import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter.PackagePolicy;
@@ -49,10 +54,8 @@ import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
 import java.io.File;
-import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.StringReader;
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
@@ -71,6 +74,7 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 @RunWith(Parameterized.class)
 public class ConverterUserAndPermissionTest  extends AbstractConverterTest {
@@ -225,6 +229,109 @@ public class ConverterUserAndPermissionTest  extends AbstractConverterTest {
         verifyRepoInit();
     }
 
+    @Test
+    public void testConvertPackageWithImportModes() throws Exception {
+        URL packageUrl = getClass().getResource("demo-cp-with-importmode.zip");
+        File packageFile = FileUtils.toFile(packageUrl);
+        converter.convert(packageFile);
+
+        File converted = new File(outputDirectory, "my_packages/demo-cp/0.0.0/demo-cp-0.0.0-cp2fm-converted.zip");
+
+        Set<String> notExpected = new HashSet<>(COMMON_NOT_EXPECTED_PATHS);
+        notExpected.add("jcr_root/apps/demo-cp/.content.xml");
+
+        Set<String> expected = new HashSet<>(COMMON_EXPECTED_PATHS);
+        expected.add("jcr_root/apps/.content.xml");
+
+        verifyContentPackage(converted, notExpected, expected);
+        assertExpectedPolicies(converted);
+        WorkspaceFilter filter = verifyWorkspaceFilter(converted, false);
+        verifyRepoInit();
+
+        assertEquals(ImportMode.MERGE, filter.getImportMode("/demo-cp"));
+        assertEquals(ImportMode.UPDATE, filter.getImportMode("/home/groups/demo-cp"));
+        assertEquals(ImportMode.REPLACE, filter.getImportMode("/home/users/demo-cp"));
+    }
+
+    @Test
+    public void testConvertPackageWithPropertyFilterSetEntry() throws Exception {
+        URL packageUrl = getClass().getResource("demo-cp-with-importmode.zip");
+        File packageFile = FileUtils.toFile(packageUrl);
+        converter.convert(packageFile);
+
+        File converted = new File(outputDirectory, "my_packages/demo-cp/0.0.0/demo-cp-0.0.0-cp2fm-converted.zip");
+        WorkspaceFilter filter = verifyWorkspaceFilter(converted, false);
+        
+        // verify that the 'matchProperties=true' exclude entry with /home/groups/demo-cp was properly converted
+        // and is still present in the adjusted filter.
+        List<PathFilterSet> propertyFilters = filter.getPropertyFilterSets();
+        assertNotNull(propertyFilters);
+        assertEquals(3, propertyFilters.size());
+        // there is only a single exclude entry matching properties with /home/groups/demo-cp
+        // the other filters don't have any property-entries
+        for (PathFilterSet filterSet : propertyFilters) {
+            List<FilterSet.Entry<PathFilter>> entries = filterSet.getEntries();
+            int expectedSize = ("/home/groups/demo-cp".equals(filterSet.getRoot())) ? 1 : 0;
+            assertEquals(expectedSize, entries.size());
+        }
+        
+        // verify that the node-filtersets got updated with additional excludes for paths filtered out
+        List<PathFilterSet> nodeFilters = filter.getFilterSets();
+        assertEquals(3, nodeFilters.size());
+        for (PathFilterSet filterSet : nodeFilters) {
+            List<FilterSet.Entry<PathFilter>> entries = filterSet.getEntries();
+            switch (filterSet.getRoot()) {
+                case "/demo-cp":
+                    assertEquals(0, entries.size());
+                    break;
+                case "/home/groups/demo-cp":
+                    assertEquals(1, entries.size());
+                    assertFalse(filterSet.contains(filterSet.getRoot() + "/rep:policy"));
+                    assertEquals(0, entries.stream().filter(FilterSet.Entry::isInclude).count());
+                    break;
+                case "/home/users/demo-cp":
+                    assertEquals(3, entries.size());
+                    assertFalse(filterSet.contains(filterSet.getRoot() + "/rep:policy"));
+                    assertEquals(1, entries.stream().filter(FilterSet.Entry::isInclude).count());
+                    break;
+                default:
+                    fail("unexpected path "+ filterSet.getRoot());
+            }
+        }
+    }
+
+    @Test
+    public void testConvertPackageWithSingleUserRoot() throws Exception {
+        URL packageUrl = getClass().getResource("demo-cp-single-user-root.zip");
+        File packageFile = FileUtils.toFile(packageUrl);
+        converter.convert(packageFile);
+
+        File converted = new File(outputDirectory, "my_packages/demo-cp/0.0.0/demo-cp-0.0.0-cp2fm-converted.zip");
+
+        Set<String> notExpected = new HashSet<>(COMMON_NOT_EXPECTED_PATHS);
+        notExpected.add("jcr_root/apps/demo-cp/.content.xml");
+
+        Set<String> expected = new HashSet<>(COMMON_EXPECTED_PATHS);
+        expected.add("jcr_root/apps/.content.xml");
+
+        verifyContentPackage(converted, notExpected, expected);
+        assertExpectedPolicies(converted);
+        verifyRepoInit();
+
+        WorkspaceFilter filter = getWorkspaceFilter(converted);
+        assertEquals(ImportMode.MERGE, filter.getImportMode("/home"));
+        
+        List<PathFilterSet> filterSets = filter.getFilterSets();
+        assertEquals(2, filterSets.size());
+        assertNotNull(filter.getCoveringFilterSet("/demo-cp"));
+        PathFilterSet homeFilter = filter.getCoveringFilterSet("/home");
+        assertNotNull(homeFilter);
+        // 11 excludes must have been added for paths that got moved to repo-init
+        List<FilterSet.Entry<PathFilter>> entries = homeFilter.getEntries();
+        assertEquals(11, entries.size());
+        assertFalse(entries.stream().anyMatch(FilterSet.Entry::isInclude));
+    }
+
     private static void assertExpectedPolicies(@NotNull File converted ) throws IOException {
         assertPolicy(converted, "jcr_root/demo-cp/_rep_policy.xml", "cp-serviceuser-1", "cp-user1", "cp-group1");
         assertPolicy(converted, "jcr_root/home/groups/demo-cp/EsYrXeBdSRkna2kqbxjl/_rep_policy.xml", null, "cp-group1");
@@ -297,26 +404,40 @@ public class ConverterUserAndPermissionTest  extends AbstractConverterTest {
         }
     }
 
-    private static void verifyWorkspaceFilter(@NotNull File contentPackage, boolean isContentOnly) throws IOException {
+    private static WorkspaceFilter verifyWorkspaceFilter(@NotNull File contentPackage, boolean isContentOnly) throws Exception {
+        DefaultWorkspaceFilter filter = getWorkspaceFilter(contentPackage);
+        if (!isContentOnly) {
+            assertFalse(filter.contains("/apps/demo-cp"));
+        }
+        assertFalse(filter.covers("/home/users/system"));
+        assertFalse(filter.covers("/home/users/system/demo-cp"));
+        assertFalse(filter.covers("/home/users/system/cq:services/demo-cp"));
+
+        assertTrue(filter.covers("/demo-cp"));
+        assertTrue(filter.covers("/home/users/demo-cp"));
+        assertTrue(filter.covers("/home/groups/demo-cp"));
+
+        // verify that explicit excludes have been added for filter roots that contain mixed content
+        PathFilterSet filterSet = filter.getCoveringFilterSet("/home/groups/demo-cp");
+        assertNotNull(filterSet);
+        assertEquals(1, filterSet.getEntries().stream().filter(pathFilterEntry -> !pathFilterEntry.isInclude() &&
+                pathFilterEntry.getFilter().matches("/home/groups/demo-cp/rep:policy")).count());
+
+        filterSet = filter.getCoveringFilterSet("/home/users/demo-cp");
+        assertNotNull(filterSet);
+        assertEquals(1, filterSet.getEntries().stream().filter(pathFilterEntry -> !pathFilterEntry.isInclude() &&
+                pathFilterEntry.getFilter().matches("/home/users/demo-cp/rep:policy")).count());
+        return filter;
+    }
+    
+    private static DefaultWorkspaceFilter getWorkspaceFilter(@NotNull File contentPackage) throws Exception {
+        DefaultWorkspaceFilter filter;
         try (ZipFile zipFile = new ZipFile(contentPackage)) {
+            filter = new DefaultWorkspaceFilter();
             ZipEntry entry = zipFile.getEntry("META-INF/vault/filter.xml");
             assertNotNull(entry);
-            String filter = IOUtils.toString(new InputStreamReader(zipFile.getInputStream(entry)));
-
-            if (!isContentOnly) {
-                assertFalse(filter.contains("/apps/demo-cp"));
-            }
-            assertFalse(filter.contains("/home/users/system"));
-            assertFalse(filter.contains("/home/users/system/demo-cp"));
-            assertFalse(filter.contains("/home/users/system/cq:services/demo-cp"));
-            
-            assertTrue(filter.contains("<filter root=\"/demo-cp\"/>"));
-            assertTrue(filter.contains("<filter root=\"/home/users/demo-cp\">"));
-            assertTrue(filter.contains("<filter root=\"/home/groups/demo-cp\">"));
-            
-            // verify that explicit excludes have been added for filter roots that contain mixed content
-            assertTrue(filter.contains("<exclude pattern=\"/home/groups/demo-cp/_rep_policy.xml\"/>"));
-            assertTrue(filter.contains("<exclude pattern=\"/home/users/demo-cp/_rep_policy.xml\"/>"));
+            filter.load(zipFile.getInputStream(entry));
         }
+        return filter;
     }
 }
diff --git a/src/test/java/org/apache/sling/feature/cpconverter/vltpkg/VaultPackageAssemblerTest.java b/src/test/java/org/apache/sling/feature/cpconverter/vltpkg/VaultPackageAssemblerTest.java
index 76b6ffc..efc96f5 100644
--- a/src/test/java/org/apache/sling/feature/cpconverter/vltpkg/VaultPackageAssemblerTest.java
+++ b/src/test/java/org/apache/sling/feature/cpconverter/vltpkg/VaultPackageAssemblerTest.java
@@ -16,20 +16,11 @@
  */
 package org.apache.sling.feature.cpconverter.vltpkg;
 
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.net.URL;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import java.util.zip.ZipInputStream;
-
 import org.apache.commons.io.FileUtils;
+import org.apache.jackrabbit.vault.fs.api.ImportMode;
+import org.apache.jackrabbit.vault.fs.api.PathFilterSet;
+import org.apache.jackrabbit.vault.fs.config.DefaultWorkspaceFilter;
+import org.apache.jackrabbit.vault.fs.filter.DefaultPathFilter;
 import org.apache.jackrabbit.vault.packaging.PackageId;
 import org.apache.jackrabbit.vault.packaging.VaultPackage;
 import org.apache.jackrabbit.vault.packaging.impl.PackageManagerImpl;
@@ -40,6 +31,20 @@ import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
 
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
 @RunWith(Parameterized.class)
 public class VaultPackageAssemblerTest {
 
@@ -107,6 +112,35 @@ public class VaultPackageAssemblerTest {
         assertTrue("Storing Directory for Vault Package does not exist", storingDirectory.exists());
     }
 
+    @Test
+    public void testMergeFiltersWithPropertyFilterSet() throws Exception {
+        PathFilterSet nodeFilter = new PathFilterSet();
+        nodeFilter.setRoot("/test");
+        nodeFilter.setImportMode(ImportMode.MERGE);
+        nodeFilter.addExclude(new DefaultPathFilter(".*/pattern"));
+        nodeFilter.addInclude(new DefaultPathFilter("/test/content/subtree"));
+
+        PathFilterSet propFilter = new PathFilterSet();
+        propFilter.setRoot("/test");
+        propFilter.addExclude(new DefaultPathFilter(".*/excludedProperty"));
+
+        DefaultWorkspaceFilter toMerge = new DefaultWorkspaceFilter();
+        toMerge.add(nodeFilter, propFilter);
+        
+        List<PathFilterSet> before = new ArrayList<>(assembler.getFilter().getFilterSets());
+        List<PathFilterSet> beforeProperties = new ArrayList<>(assembler.getFilter().getPropertyFilterSets());
+        
+        assembler.mergeFilters(toMerge);
+        
+        List<PathFilterSet> after = assembler.getFilter().getFilterSets();
+        assertEquals(before.size()+1, after.size());
+        assertTrue(after.contains(nodeFilter));
+
+        List<PathFilterSet> afterProperties = assembler.getFilter().getPropertyFilterSets();
+        assertEquals(beforeProperties.size()+1, afterProperties.size());
+        assertTrue(afterProperties.contains(propFilter));
+    }
+    
     @Parameters
     public static Collection<Object[]> data() throws Exception {
         return Arrays.asList(new Object[][] {
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/demo-cp-single-user-root.zip b/src/test/resources/org/apache/sling/feature/cpconverter/demo-cp-single-user-root.zip
new file mode 100644
index 0000000..bf4ceda
Binary files /dev/null and b/src/test/resources/org/apache/sling/feature/cpconverter/demo-cp-single-user-root.zip differ
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/demo-cp-with-importmode.zip b/src/test/resources/org/apache/sling/feature/cpconverter/demo-cp-with-importmode.zip
new file mode 100644
index 0000000..a0e2af5
Binary files /dev/null and b/src/test/resources/org/apache/sling/feature/cpconverter/demo-cp-with-importmode.zip differ