Merge pull request #16 from apache/SLING-8251_merged_after_releases
SLING-8251 - Support checking dependencies for content packages
diff --git a/src/main/java/org/apache/sling/feature/scanner/impl/ContentPackageScanner.java b/src/main/java/org/apache/sling/feature/scanner/impl/ContentPackageScanner.java
index cea38b5..09f7781 100644
--- a/src/main/java/org/apache/sling/feature/scanner/impl/ContentPackageScanner.java
+++ b/src/main/java/org/apache/sling/feature/scanner/impl/ContentPackageScanner.java
@@ -19,25 +19,27 @@
import org.apache.sling.feature.Artifact;
import org.apache.sling.feature.ArtifactId;
import org.apache.sling.feature.Configuration;
+import org.apache.sling.feature.io.IOUtils;
import org.apache.sling.feature.scanner.BundleDescriptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
-import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
+import java.io.InputStream;
import java.io.Reader;
import java.net.URL;
import java.nio.file.Files;
import java.util.ArrayList;
+import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
+import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
public class ContentPackageScanner {
@@ -81,128 +83,129 @@
final List<File> toProcess = new ArrayList<>();
- try (final ZipInputStream zis = new ZipInputStream(archive.openStream()) ) {
- boolean done = false;
- while ( !done ) {
- final ZipEntry entry = zis.getNextEntry();
- if ( entry == null ) {
- done = true;
- } else {
- final String entryName = entry.getName();
- if ( !entryName.endsWith("/") && entryName.startsWith("jcr_root/") ) {
- final String contentPath = entryName.substring(8);
+ try (final JarFile zipFile = IOUtils.getJarFileFromURL(archive, true, null)) {
+ Enumeration<? extends ZipEntry> entries = zipFile.entries();
+ while (entries.hasMoreElements()) {
+ final ZipEntry entry = entries.nextElement();
+ final String entryName = entry.getName();
+ logger.debug("Content package entry {}", entryName);
+
+ if ( !entryName.endsWith("/") && entryName.startsWith("jcr_root/") ) {
+ final String contentPath = entryName.substring(8);
- FileType fileType = null;
+ FileType fileType = null;
- if ( entryName.endsWith(".zip") ) {
- // embedded content package
- fileType = FileType.PACKAGE;
+ if (entryName.endsWith(".zip")) {
+ // embedded content package
+ fileType = FileType.PACKAGE;
- // check for libs or apps
- } else if ( entryName.startsWith("jcr_root/libs/") || entryName.startsWith("jcr_root/apps/") ) {
+ // check for libs or apps
+ } else if (entryName.startsWith("jcr_root/libs/") || entryName.startsWith("jcr_root/apps/")) {
- // check if this is an install folder (I)
- // install folders are either named:
- // "install" or
- // "install.{runmode}"
- boolean isInstall = entryName.indexOf("/install/") != -1;
- if ( !isInstall ) {
- final int pos = entryName.indexOf("/install.");
- if ( pos != -1 ) {
+ // check if this is an install folder (I)
+ // install folders are either named:
+ // "install" or
+ // "install.{runmode}"
+ boolean isInstall = entryName.indexOf("/install/") != -1;
+ if (!isInstall) {
+ final int pos = entryName.indexOf("/install.");
+ if (pos != -1) {
+ final int endSlashPos = entryName.indexOf('/', pos + 1);
+ if (endSlashPos != -1) {
+ isInstall = true;
+ }
+ }
+ }
+ if (!isInstall) {
+ // check if this is an install folder (II)
+ // config folders are either named:
+ // "config" or
+ // "config.{runmode}"
+ isInstall = entryName.indexOf("/config/") != -1;
+ if (!isInstall) {
+ final int pos = entryName.indexOf("/config.");
+ if (pos != -1) {
final int endSlashPos = entryName.indexOf('/', pos + 1);
- if ( endSlashPos != -1 ) {
+ if (endSlashPos != -1) {
isInstall = true;
}
}
}
- if ( !isInstall ) {
- // check if this is an install folder (II)
- // config folders are either named:
- // "config" or
- // "config.{runmode}"
- isInstall = entryName.indexOf("/config/") != -1;
- if ( !isInstall ) {
- final int pos = entryName.indexOf("/config.");
- if ( pos != -1 ) {
- final int endSlashPos = entryName.indexOf('/', pos + 1);
- if ( endSlashPos != -1 ) {
- isInstall = true;
- }
- }
- }
- }
-
- if (isInstall ) {
-
- if ( entryName.endsWith(".jar") ) {
- fileType = FileType.BUNDLE;
- } else if ( entryName.endsWith(".xml") || entryName.endsWith(".config") ) {
- fileType = FileType.CONFIG;
- }
- }
}
- if ( fileType != null ) {
- logger.debug("- extracting : {}", entryName);
- final File newFile = new File(toDir, entryName.replace('/', File.separatorChar));
- newFile.getParentFile().mkdirs();
+ if (isInstall) {
- try (final FileOutputStream fos = new FileOutputStream(newFile)) {
- int len;
- while ((len = zis.read(buffer)) > -1) {
- fos.write(buffer, 0, len);
- }
+ if (entryName.endsWith(".jar")) {
+ fileType = FileType.BUNDLE;
+ } else if (entryName.endsWith(".xml") || entryName.endsWith(".config")) {
+ fileType = FileType.CONFIG;
+ }
+ }
+ }
+
+ if (fileType != null) {
+ logger.debug("- extracting : {}", entryName);
+ final File newFile = new File(toDir, entryName.replace('/', File.separatorChar));
+ newFile.getParentFile().mkdirs();
+
+ try (
+ final FileOutputStream fos = new FileOutputStream(newFile);
+ final InputStream zis = zipFile.getInputStream(entry);
+ ) {
+ int len;
+ while ((len = zis.read(buffer)) > -1) {
+ fos.write(buffer, 0, len);
+ }
+ }
+
+ if (fileType == FileType.BUNDLE) {
+ int startLevel = 20;
+ final int lastSlash = contentPath.lastIndexOf('/');
+ final int nextSlash = contentPath.lastIndexOf('/', lastSlash - 1);
+ final String part = contentPath.substring(nextSlash + 1, lastSlash);
+ try {
+ startLevel = Integer.valueOf(part);
+ } catch (final NumberFormatException ignore) {
+ // ignore
}
- if ( fileType == FileType.BUNDLE ) {
- int startLevel = 20;
- final int lastSlash = contentPath.lastIndexOf('/');
- final int nextSlash = contentPath.lastIndexOf('/', lastSlash - 1);
- final String part = contentPath.substring(nextSlash + 1, lastSlash);
- try {
- startLevel = Integer.valueOf(part);
- } catch ( final NumberFormatException ignore ) {
- // ignore
- }
+ final Artifact bundle = new Artifact(extractArtifactId(tempDir, newFile));
+ final BundleDescriptor info = new BundleDescriptorImpl(bundle, newFile.toURI().toURL(),
+ startLevel);
+ bundle.getMetadata().put("content-package", cp.getArtifact().getId().toMvnId());
+ bundle.getMetadata().put("content-path", contentPath);
- final Artifact bundle = new Artifact(extractArtifactId(tempDir, newFile));
- final BundleDescriptor info = new BundleDescriptorImpl(bundle, newFile.toURI().toURL(), startLevel);
- bundle.getMetadata().put("content-package", cp.getArtifact().getId().toMvnId());
- bundle.getMetadata().put("content-path", contentPath);
+ cp.bundles.add(info);
- cp.bundles.add(info);
+ } else if (fileType == FileType.CONFIG) {
- } else if ( fileType == FileType.CONFIG ) {
+ final Configuration configEntry = this.process(newFile, cp.getArtifact(), contentPath);
+ if (configEntry != null) {
- final Configuration configEntry = this.process(newFile, cp.getArtifact(), contentPath);
- if ( configEntry != null ) {
-
- cp.configs.add(configEntry);
- }
-
- } else if ( fileType == FileType.PACKAGE ) {
- toProcess.add(newFile);
+ cp.configs.add(configEntry);
}
+ } else if (fileType == FileType.PACKAGE) {
+ toProcess.add(newFile);
}
}
- zis.closeEntry();
+
}
+
}
- }
+ for (final File f : toProcess) {
+ extractContentPackage(cp, infos, f.toURI().toURL());
+ final ContentPackageDescriptor i = new ContentPackageDescriptor(f.getName());
+ final int lastDot = f.getName().lastIndexOf(".");
+ i.setName(f.getName().substring(0, lastDot));
+ i.setArtifactFile(f.toURI().toURL());
+ i.setContentPackageInfo(cp.getArtifact(), f.getName());
+ infos.add(i);
- for(final File f : toProcess) {
- extractContentPackage(cp, infos, f.toURI().toURL());
- final ContentPackageDescriptor i = new ContentPackageDescriptor(f.getName());
- final int lastDot = f.getName().lastIndexOf(".");
- i.setName(f.getName().substring(0, lastDot));
- i.setArtifactFile(f.toURI().toURL());
- i.setContentPackageInfo(cp.getArtifact(), f.getName());
- infos.add(i);
-
- i.lock();
+ i.lock();
+ }
}
} finally {
deleteOnExitRecursive(tempDir);
@@ -228,31 +231,29 @@
final File toDir = new File(tempDir, bundleFile.getName());
toDir.mkdirs();
- try (final ZipInputStream zis = new ZipInputStream(new FileInputStream(bundleFile)) ) {
- boolean done = false;
- while ( !done ) {
- final ZipEntry entry = zis.getNextEntry();
- if ( entry == null ) {
- done = true;
- } else {
- final String entryName = entry.getName();
- if ( !entryName.endsWith("/") && entryName.startsWith("META-INF/maven/") && entryName.endsWith("/pom.properties")) {
- logger.debug("- extracting : {}", entryName);
- final File newFile = new File(toDir, entryName.replace('/', File.separatorChar));
- newFile.getParentFile().mkdirs();
+ try (final JarFile zipFile = new JarFile(bundleFile)) {
+ Enumeration<? extends ZipEntry> entries = zipFile.entries();
+
+ while ( entries.hasMoreElements() ) {
+ final ZipEntry entry = entries.nextElement();
+
+ final String entryName = entry.getName();
+ if ( !entryName.endsWith("/") && entryName.startsWith("META-INF/maven/") && entryName.endsWith("/pom.properties")) {
+ logger.debug("- extracting : {}", entryName);
+ final File newFile = new File(toDir, entryName.replace('/', File.separatorChar));
+ newFile.getParentFile().mkdirs();
- try (final FileOutputStream fos = new FileOutputStream(newFile)) {
- int len;
- while ((len = zis.read(buffer)) > -1) {
- fos.write(buffer, 0, len);
- }
+ try (
+ final FileOutputStream fos = new FileOutputStream(newFile);
+ final InputStream zis = zipFile.getInputStream(entry)
+ ) {
+ int len;
+ while ((len = zis.read(buffer)) > -1) {
+ fos.write(buffer, 0, len);
}
-
}
- zis.closeEntry();
}
}
-
}
// check for maven
diff --git a/src/main/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScanner.java b/src/main/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScanner.java
index 956a90c..12f7879 100644
--- a/src/main/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScanner.java
+++ b/src/main/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScanner.java
@@ -17,6 +17,22 @@
package org.apache.sling.feature.scanner.impl;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.Set;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.zip.ZipEntry;
+
import org.apache.commons.text.StringSubstitutor;
import org.apache.commons.text.lookup.StringLookup;
import org.apache.felix.utils.manifest.Parser;
@@ -24,31 +40,15 @@
import org.apache.sling.feature.Artifact;
import org.apache.sling.feature.ArtifactId;
import org.apache.sling.feature.builder.ArtifactProvider;
+import org.apache.sling.feature.io.IOUtils;
import org.apache.sling.feature.scanner.BundleDescriptor;
import org.apache.sling.feature.scanner.PackageInfo;
import org.apache.sling.feature.scanner.spi.FrameworkScanner;
import org.osgi.framework.Constants;
import org.osgi.resource.Capability;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.net.URL;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Properties;
-import java.util.Set;
-import java.util.jar.Manifest;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
public class FelixFrameworkScanner implements FrameworkScanner {
-
@Override
public BundleDescriptor scan(final ArtifactId framework,
final Map<String,String> frameworkProps,
@@ -144,22 +144,20 @@
Map<String,String> getFrameworkProperties(final Map<String,String> appProps, final URL framework)
throws IOException {
final Map<String, Properties> propsMap = new HashMap<>();
- try (final ZipInputStream zis = new ZipInputStream(framework.openStream()) ) {
- boolean done = false;
- while ( !done ) {
- final ZipEntry entry = zis.getNextEntry();
- if ( entry == null ) {
- done = true;
- } else {
+
+ try (final JarFile zipFile = IOUtils.getJarFileFromURL(framework, true, null)) {
+ Enumeration<? extends ZipEntry> entries = zipFile.entries();
+
+ while ( entries.hasMoreElements() ) {
+ final ZipEntry entry = entries.nextElement();
+ try (final InputStream zis = zipFile.getInputStream(entry)) {
final String entryName = entry.getName();
if ( entryName.endsWith(".properties") ) {
final Properties props = new Properties();
props.load(zis);
-
propsMap.put(entryName, props);
}
- zis.closeEntry();
- }
+ }
}
}
diff --git a/src/test/java/org/apache/sling/feature/scanner/impl/ContentPackageScannerTest.java b/src/test/java/org/apache/sling/feature/scanner/impl/ContentPackageScannerTest.java
new file mode 100644
index 0000000..fdf23ca
--- /dev/null
+++ b/src/test/java/org/apache/sling/feature/scanner/impl/ContentPackageScannerTest.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.sling.feature.scanner.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import org.apache.sling.feature.Artifact;
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Configuration;
+import org.apache.sling.feature.scanner.BundleDescriptor;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ContentPackageScannerTest {
+
+ private static final String COORDINATES_TEST_PACKAGE_A_10 = "my_packages:test_a:1.0";
+ private static ArtifactId TEST_PACKAGE_AID_A_10 = ArtifactId.fromMvnId(COORDINATES_TEST_PACKAGE_A_10);
+
+ private File file;
+
+ private Artifact artifact;
+
+ ContentPackageDescriptor test_descriptor;
+
+ @Before
+ public void setUp() throws Exception {
+ file = getTestFile("/test-content.zip");
+
+ artifact = new Artifact(TEST_PACKAGE_AID_A_10);
+
+ test_descriptor = new ContentPackageDescriptor(file.getName());
+ test_descriptor.setName("test-content");
+ test_descriptor.setArtifact(artifact);
+ test_descriptor.setArtifactFile(file.toURI().toURL());
+ }
+
+ @Test
+ public void testScan() throws URISyntaxException, IOException {
+ ContentPackageScanner scanner = new ContentPackageScanner();
+ Set<ContentPackageDescriptor> descriptors = scanner.scan(artifact, file.toURI().toURL());
+ for(ContentPackageDescriptor desc : descriptors) {
+ String name = desc.getName();
+ assertNotNull(name);
+
+ if(name.equals(test_descriptor.getName())) {
+ assetDescriptor(desc, desc.getName());
+ } else {
+ assertEquals(name, "sub-content");
+ }
+ }
+ }
+
+ private File getTestFile(String path) throws URISyntaxException {
+ return new File(getClass().getResource(path).toURI());
+ }
+
+ private void assetDescriptor(ContentPackageDescriptor desc, String descName) {
+ assertEquals(descName, test_descriptor.getName());
+ assertEquals(desc.getArtifact().getId().getArtifactId(), test_descriptor.getArtifact().getId().getArtifactId());
+ assertEquals(desc.getArtifactFile().toString(), test_descriptor.getArtifactFile().toString());
+
+ assertTrue(desc.bundles != null && !desc.bundles.isEmpty());
+ BundleDescriptor bundles[] = desc.bundles.toArray(new BundleDescriptor[desc.bundles.size()]);
+
+ assertEquals(bundles[0].getArtifact().getId().toString(), "org.apache.felix:org.apache.felix.framework:jar:bundle:6.0.1");
+
+ assertTrue(desc.configs != null && !desc.configs.isEmpty());
+ Configuration configs[] = desc.configs.toArray(new Configuration[desc.configs.size()]);
+ assertConfiguration(configs[0]);
+ }
+
+ private void assertConfiguration(Configuration c) {
+ Dictionary<String, Object> props = c.getProperties();
+ String contentPath = (String) props.get(":configurator:feature:content-path");
+ assertEquals(contentPath, "/libs/config/com.example.some.Component.xml");
+ }
+
+ private void printPackageEntries(File archive) throws IOException {
+ ZipFile zip = new ZipFile(archive);
+ Enumeration<? extends ZipEntry> entries = zip.entries();
+ System.out.println("ZIP Archive: " + zip.getName());
+ while(entries.hasMoreElements())
+ System.out.println(" " + entries.nextElement().getName());
+ System.out.println();
+ }
+
+}
diff --git a/src/test/resources/test-content.zip b/src/test/resources/test-content.zip
new file mode 100644
index 0000000..672f0fa
--- /dev/null
+++ b/src/test/resources/test-content.zip
Binary files differ