]> git.argeo.org Git - cc0/argeo-build.git/blobdiff - src/org/argeo/build/Repackage.java
Check whether all components have SPDX identifiers
[cc0/argeo-build.git] / src / org / argeo / build / Repackage.java
index 05ff7b177616cd4e01118d3c32e15aea9a717b4a..3e87c864b860308dd01f7cf75e9d8cef633d43d9 100644 (file)
@@ -6,11 +6,16 @@ import static java.lang.System.Logger.Level.INFO;
 import static java.lang.System.Logger.Level.TRACE;
 import static java.lang.System.Logger.Level.WARNING;
 import static java.nio.file.FileVisitResult.CONTINUE;
+import static java.util.jar.Attributes.Name.MANIFEST_VERSION;
+import static org.argeo.build.Repackage.ManifestConstants.ARGEO_ORIGIN_M2;
+import static org.argeo.build.Repackage.ManifestConstants.ARGEO_ORIGIN_M2_REPO;
+import static org.argeo.build.Repackage.ManifestConstants.BUNDLE_LICENSE;
 import static org.argeo.build.Repackage.ManifestConstants.BUNDLE_SYMBOLICNAME;
 import static org.argeo.build.Repackage.ManifestConstants.BUNDLE_VERSION;
+import static org.argeo.build.Repackage.ManifestConstants.ECLIPSE_SOURCE_BUNDLE;
 import static org.argeo.build.Repackage.ManifestConstants.EXPORT_PACKAGE;
-import static org.argeo.build.Repackage.ManifestConstants.SLC_ORIGIN_M2;
-import static org.argeo.build.Repackage.ManifestConstants.SLC_ORIGIN_M2_REPO;
+import static org.argeo.build.Repackage.ManifestConstants.IMPORT_PACKAGE;
+import static org.argeo.build.Repackage.ManifestConstants.SPDX_LICENSE_IDENTIFIER;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -163,7 +168,7 @@ public class Repackage {
         * MAVEN ORIGIN
         */
        /** Process a whole category/group id. */
-       public void processCategory(Path categoryRelativePath) {
+       void processCategory(Path categoryRelativePath) {
                try {
                        Path targetCategoryBase = descriptorsBase.resolve(categoryRelativePath);
                        DirectoryStream<Path> bnds = Files.newDirectoryStream(targetCategoryBase,
@@ -187,7 +192,7 @@ public class Repackage {
        }
 
        /** Process a standalone Maven artifact. */
-       public void processSingleM2ArtifactDistributionUnit(Path bndFile) {
+       void processSingleM2ArtifactDistributionUnit(Path bndFile) {
                try {
                        Path categoryRelativePath = descriptorsBase.relativize(bndFile.getParent());
                        Path targetCategoryBase = a2Base.resolve(categoryRelativePath);
@@ -196,8 +201,8 @@ public class Repackage {
                        try (InputStream in = Files.newInputStream(bndFile)) {
                                fileProps.load(in);
                        }
-                       String repoStr = fileProps.containsKey(SLC_ORIGIN_M2_REPO.toString())
-                                       ? fileProps.getProperty(SLC_ORIGIN_M2_REPO.toString())
+                       String repoStr = fileProps.containsKey(ARGEO_ORIGIN_M2_REPO.toString())
+                                       ? fileProps.getProperty(ARGEO_ORIGIN_M2_REPO.toString())
                                        : null;
 
                        if (!fileProps.containsKey(BUNDLE_SYMBOLICNAME.toString())) {
@@ -207,7 +212,7 @@ public class Repackage {
                                fileProps.put(BUNDLE_SYMBOLICNAME.toString(), symbolicName);
                        }
 
-                       String m2Coordinates = fileProps.getProperty(SLC_ORIGIN_M2.toString());
+                       String m2Coordinates = fileProps.getProperty(ARGEO_ORIGIN_M2.toString());
                        if (m2Coordinates == null)
                                throw new IllegalArgumentException("No M2 coordinates available for " + bndFile);
                        M2Artifact artifact = new M2Artifact(m2Coordinates);
@@ -224,7 +229,7 @@ public class Repackage {
        }
 
        /** Process multiple Maven artifacts. */
-       public void processM2BasedDistributionUnit(Path duDir) {
+       void processM2BasedDistributionUnit(Path duDir) {
                try {
                        Path categoryRelativePath = descriptorsBase.relativize(duDir.getParent());
                        Path targetCategoryBase = a2Base.resolve(categoryRelativePath);
@@ -242,7 +247,7 @@ public class Repackage {
                                commonProps.load(in);
                        }
 
-                       String m2Version = commonProps.getProperty(SLC_ORIGIN_M2.toString());
+                       String m2Version = commonProps.getProperty(ARGEO_ORIGIN_M2.toString());
                        if (m2Version == null) {
                                logger.log(WARNING, "Ignoring " + duDir + " as it is not an M2-based distribution unit");
                                return;// ignore, this is probably an Eclipse archive
@@ -260,7 +265,7 @@ public class Repackage {
                                try (InputStream in = Files.newInputStream(p)) {
                                        fileProps.load(in);
                                }
-                               String m2Coordinates = fileProps.getProperty(SLC_ORIGIN_M2.toString());
+                               String m2Coordinates = fileProps.getProperty(ARGEO_ORIGIN_M2.toString());
                                M2Artifact artifact = new M2Artifact(m2Coordinates);
                                artifact.setVersion(m2Version);
 
@@ -269,7 +274,7 @@ public class Repackage {
                                mergeProps.putAll(commonProps);
 
                                fileEntries: for (Object key : fileProps.keySet()) {
-                                       if (ManifestConstants.SLC_ORIGIN_M2.toString().equals(key))
+                                       if (ManifestConstants.ARGEO_ORIGIN_M2.toString().equals(key))
                                                continue fileEntries;
                                        String value = fileProps.getProperty(key.toString());
                                        Object previousValue = mergeProps.put(key.toString(), value);
@@ -278,7 +283,7 @@ public class Repackage {
                                                                commonBnd + ": " + key + " was " + previousValue + ", overridden with " + value);
                                        }
                                }
-                               mergeProps.put(ManifestConstants.SLC_ORIGIN_M2.toString(), artifact.toM2Coordinates());
+                               mergeProps.put(ManifestConstants.ARGEO_ORIGIN_M2.toString(), artifact.toM2Coordinates());
                                if (!mergeProps.containsKey(BUNDLE_SYMBOLICNAME.toString())) {
                                        // use file name as symbolic name
                                        String symbolicName = p.getFileName().toString();
@@ -286,8 +291,8 @@ public class Repackage {
                                        mergeProps.put(BUNDLE_SYMBOLICNAME.toString(), symbolicName);
                                }
 
-                               String repoStr = mergeProps.containsKey(SLC_ORIGIN_M2_REPO.toString())
-                                               ? mergeProps.getProperty(SLC_ORIGIN_M2_REPO.toString())
+                               String repoStr = mergeProps.containsKey(ARGEO_ORIGIN_M2_REPO.toString())
+                                               ? mergeProps.getProperty(ARGEO_ORIGIN_M2_REPO.toString())
                                                : null;
 
                                // download
@@ -304,7 +309,7 @@ public class Repackage {
        }
 
        /** Merge multiple Maven artifacts. */
-       protected void mergeM2Artifacts(Path mergeBnd) throws IOException {
+       void mergeM2Artifacts(Path mergeBnd) throws IOException {
                Path duDir = mergeBnd.getParent();
                String category = duDir.getParent().getFileName().toString();
                Path targetCategoryBase = a2Base.resolve(category);
@@ -314,7 +319,7 @@ public class Repackage {
                        mergeProps.load(in);
                }
 
-               String m2Version = mergeProps.getProperty(SLC_ORIGIN_M2.toString());
+               String m2Version = mergeProps.getProperty(ARGEO_ORIGIN_M2.toString());
                if (m2Version == null) {
                        logger.log(WARNING, "Ignoring " + duDir + " as it is not an M2-based distribution unit");
                        return;// ignore, this is probably an Eclipse archive
@@ -325,13 +330,13 @@ public class Repackage {
                m2Version = m2Version.substring(1);
                mergeProps.put(ManifestConstants.BUNDLE_VERSION.toString(), m2Version);
 
-               String artifactsStr = mergeProps.getProperty(ManifestConstants.SLC_ORIGIN_M2_MERGE.toString());
+               String artifactsStr = mergeProps.getProperty(ManifestConstants.ARGEO_ORIGIN_M2_MERGE.toString());
                if (artifactsStr == null)
                        throw new IllegalArgumentException(
-                                       mergeBnd + ": " + ManifestConstants.SLC_ORIGIN_M2_MERGE + " must be set");
+                                       mergeBnd + ": " + ManifestConstants.ARGEO_ORIGIN_M2_MERGE + " must be set");
 
-               String repoStr = mergeProps.containsKey(SLC_ORIGIN_M2_REPO.toString())
-                               ? mergeProps.getProperty(SLC_ORIGIN_M2_REPO.toString())
+               String repoStr = mergeProps.containsKey(ARGEO_ORIGIN_M2_REPO.toString())
+                               ? mergeProps.getProperty(ARGEO_ORIGIN_M2_REPO.toString())
                                : null;
 
                String bundleSymbolicName = mergeProps.getProperty(ManifestConstants.BUNDLE_SYMBOLICNAME.toString());
@@ -457,18 +462,18 @@ public class Repackage {
        }
 
        /** Generate MANIFEST using BND. */
-       protected Path processBndJar(Path downloaded, Path targetCategoryBase, Properties fileProps, M2Artifact artifact) {
+       Path processBndJar(Path downloaded, Path targetCategoryBase, Properties fileProps, M2Artifact artifact) {
 
                try {
                        Map<String, String> additionalEntries = new TreeMap<>();
                        boolean doNotModify = Boolean.parseBoolean(fileProps
-                                       .getOrDefault(ManifestConstants.SLC_ORIGIN_MANIFEST_NOT_MODIFIED.toString(), "false").toString());
+                                       .getOrDefault(ManifestConstants.ARGEO_ORIGIN_MANIFEST_NOT_MODIFIED.toString(), "false").toString());
 
                        // we always force the symbolic name
 
                        if (doNotModify) {
                                fileEntries: for (Object key : fileProps.keySet()) {
-                                       if (ManifestConstants.SLC_ORIGIN_M2.toString().equals(key))
+                                       if (ManifestConstants.ARGEO_ORIGIN_M2.toString().equals(key))
                                                continue fileEntries;
                                        String value = fileProps.getProperty(key.toString());
                                        additionalEntries.put(key.toString(), value);
@@ -505,10 +510,8 @@ public class Repackage {
                                                }
                                                if ("Require-Capability".equals(key.toString())
                                                                && value.toString().equals("osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=1.1))\""))
-                                                       continue keys;// hack for very old classes
+                                                       continue keys;// !! hack for very old classes
                                                additionalEntries.put(key.toString(), value.toString());
-                                               // logger.log(DEBUG, () -> key + "=" + value);
-
                                        }
                                }
                        }
@@ -522,8 +525,7 @@ public class Repackage {
        }
 
        /** Download and integrates sources for a single Maven artifact. */
-       protected void downloadAndProcessM2Sources(String repoStr, M2Artifact artifact, Path targetBundleDir)
-                       throws IOException {
+       void downloadAndProcessM2Sources(String repoStr, M2Artifact artifact, Path targetBundleDir) throws IOException {
                try {
                        M2Artifact sourcesArtifact = new M2Artifact(artifact.toM2Coordinates(), "sources");
                        URL sourcesUrl = M2ConventionsUtils.mavenRepoUrl(repoStr, sourcesArtifact);
@@ -537,7 +539,7 @@ public class Repackage {
        }
 
        /** Integrate sources from a downloaded jar file. */
-       protected void processM2SourceJar(Path file, Path targetBundleDir) throws IOException {
+       void processM2SourceJar(Path file, Path targetBundleDir) throws IOException {
                try (JarInputStream jarIn = new JarInputStream(Files.newInputStream(file), false)) {
                        Path targetSourceDir = sourceBundles
                                        ? targetBundleDir.getParent().resolve(targetBundleDir.toString() + ".src")
@@ -568,12 +570,12 @@ public class Repackage {
        }
 
        /** Download a Maven artifact. */
-       protected Path downloadMaven(URL url, M2Artifact artifact) throws IOException {
+       Path downloadMaven(URL url, M2Artifact artifact) throws IOException {
                return downloadMaven(url, artifact, false);
        }
 
        /** Download a Maven artifact. */
-       protected Path downloadMaven(URL url, M2Artifact artifact, boolean sources) throws IOException {
+       Path downloadMaven(URL url, M2Artifact artifact, boolean sources) throws IOException {
                return download(url, mavenBase, artifact.getGroupId().replace(".", "/") //
                                + '/' + artifact.getArtifactId() + '/' + artifact.getVersion() //
                                + '/' + artifact.getArtifactId() + "-" + artifact.getVersion() + (sources ? "-sources" : "") + ".jar");
@@ -583,7 +585,7 @@ public class Repackage {
         * ECLIPSE ORIGIN
         */
        /** Process an archive in Eclipse format. */
-       public void processEclipseArchive(Path duDir) {
+       void processEclipseArchive(Path duDir) {
                try {
                        Path categoryRelativePath = descriptorsBase.relativize(duDir.getParent());
                        Path targetCategoryBase = a2Base.resolve(categoryRelativePath);
@@ -599,12 +601,12 @@ public class Repackage {
                        try (InputStream in = Files.newInputStream(commonBnd)) {
                                commonProps.load(in);
                        }
-                       String url = commonProps.getProperty(ManifestConstants.SLC_ORIGIN_URI.toString());
+                       String url = commonProps.getProperty(ManifestConstants.ARGEO_ORIGIN_URI.toString());
                        if (url == null) {
                                url = uris.getProperty(duDir.getFileName().toString());
                                if (url == null)
                                        throw new IllegalStateException("No url available for " + duDir);
-                               commonProps.put(ManifestConstants.SLC_ORIGIN_URI.toString(), url);
+                               commonProps.put(ManifestConstants.ARGEO_ORIGIN_URI.toString(), url);
                        }
                        Path downloaded = tryDownloadArchive(url, originBase);
 
@@ -675,13 +677,14 @@ public class Repackage {
        }
 
        /** Process sources in Eclipse format. */
-       protected void processEclipseSourceJar(Path file, Path targetBase) throws IOException {
+       void processEclipseSourceJar(Path file, Path targetBase) throws IOException {
                try {
                        Path targetBundleDir;
                        try (JarInputStream jarIn = new JarInputStream(Files.newInputStream(file), false)) {
                                Manifest manifest = jarIn.getManifest();
 
-                               String[] relatedBundle = manifest.getMainAttributes().getValue("Eclipse-SourceBundle").split(";");
+                               String[] relatedBundle = manifest.getMainAttributes().getValue(ECLIPSE_SOURCE_BUNDLE.toString())
+                                               .split(";");
                                String version = relatedBundle[1].substring("version=\"".length());
                                version = version.substring(0, version.length() - 1);
                                NameVersion nameVersion = new NameVersion(relatedBundle[0], version);
@@ -713,7 +716,7 @@ public class Repackage {
         * COMMON PROCESSING
         */
        /** Normalise a bundle. */
-       protected Path processBundleJar(Path file, Path targetBase, Map<String, String> entries) throws IOException {
+       Path processBundleJar(Path file, Path targetBase, Map<String, String> entries) throws IOException {
                NameVersion nameVersion;
                Path targetBundleDir;
                try (JarInputStream jarIn = new JarInputStream(Files.newInputStream(file), false)) {
@@ -826,25 +829,52 @@ public class Repackage {
                                                entries.get(BUNDLE_SYMBOLICNAME.toString()) + ";singleton:=true");
                        }
 
+                       // Final MANIFEST decisions
+                       // This also where we check the original OSGi metadata and compare with our
+                       // changes
                        for (String key : entries.keySet()) {
                                String value = entries.get(key);
-                               Object previousValue = manifest.getMainAttributes().putValue(key, value);
-                               if (previousValue != null && !previousValue.equals(value)) {
-                                       if (ManifestConstants.IMPORT_PACKAGE.toString().equals(key)
-                                                       || ManifestConstants.EXPORT_PACKAGE.toString().equals(key)
-                                                       || ManifestConstants.BUNDLE_LICENSE.toString().equals(key))
-                                               logger.log(TRACE, file.getFileName() + ": " + key + " was modified");
+                               String previousValue = manifest.getMainAttributes().getValue(key);
+                               boolean wasDifferent = previousValue != null && !previousValue.equals(value);
+                               boolean keepPrevious = false;
+                               if (wasDifferent) {
+                                       if (SPDX_LICENSE_IDENTIFIER.toString().equals(key) && previousValue != null)
+                                               keepPrevious = true;
+                                       else if (BUNDLE_VERSION.toString().equals(key) && wasDifferent)
+                                               if (previousValue.equals(value + ".0")) // typically a Maven first release
+                                                       keepPrevious = true;
+
+                                       if (keepPrevious) {
+                                               if (logger.isLoggable(TRACE))
+                                                       logger.log(TRACE, file.getFileName() + ": " + key + " was NOT modified, value kept is "
+                                                                       + previousValue + ", not overriden with " + value);
+                                               value = previousValue;
+                                       }
+                               }
+
+                               manifest.getMainAttributes().putValue(key, value);
+                               if (wasDifferent && !keepPrevious) {
+                                       if (IMPORT_PACKAGE.toString().equals(key) || EXPORT_PACKAGE.toString().equals(key))
+                                               logger.log(TRACE, () -> file.getFileName() + ": " + key + " was modified");
                                        else
                                                logger.log(WARNING, file.getFileName() + ": " + key + " was " + previousValue
                                                                + ", overridden with " + value);
                                }
 
-                               // hack to remove unresolvable
+                               // !! hack to remove unresolvable
                                if (key.equals("Provide-Capability") || key.equals("Require-Capability"))
                                        if (nameVersion.getName().equals("osgi.core") || nameVersion.getName().equals("osgi.cmpn")) {
                                                manifest.getMainAttributes().remove(key);
                                        }
                        }
+
+                       // last checks
+                       String spdxLicenceId = manifest.getMainAttributes().getValue(SPDX_LICENSE_IDENTIFIER.toString());
+                       String bundleLicense = manifest.getMainAttributes().getValue(BUNDLE_LICENSE.toString());
+                       if (spdxLicenceId == null)
+                               logger.log(WARNING, file.getFileName() + ": " + SPDX_LICENSE_IDENTIFIER + " not available, "
+                                               + BUNDLE_LICENSE + " is " + bundleLicense);
+
                        try (OutputStream out = Files.newOutputStream(manifestPath)) {
                                manifest.write(out);
                        }
@@ -856,7 +886,7 @@ public class Repackage {
         * UTILITIES
         */
        /** Recursively deletes a directory. */
-       private static void deleteDirectory(Path path) throws IOException {
+       static void deleteDirectory(Path path) throws IOException {
                if (!Files.exists(path))
                        return;
                Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
@@ -877,7 +907,7 @@ public class Repackage {
        }
 
        /** Extract name/version from a MANIFEST. */
-       protected NameVersion nameVersionFromManifest(Manifest manifest) {
+       NameVersion nameVersionFromManifest(Manifest manifest) {
                Attributes attrs = manifest.getMainAttributes();
                // symbolic name
                String symbolicName = attrs.getValue(ManifestConstants.BUNDLE_SYMBOLICNAME.toString());
@@ -891,7 +921,7 @@ public class Repackage {
        }
 
        /** Try to download from an URI. */
-       protected Path tryDownloadArchive(String uri, Path dir) throws IOException {
+       Path tryDownloadArchive(String uri, Path dir) throws IOException {
                // find mirror
                List<String> urlBases = null;
                String uriPrefix = null;
@@ -928,12 +958,12 @@ public class Repackage {
         * Effectively download. Synchronised in order to avoid downloading twice in
         * parallel.
         */
-       protected synchronized Path downloadArchive(URL url, Path dir) throws IOException {
+       synchronized Path downloadArchive(URL url, Path dir) throws IOException {
                return download(url, dir, (String) null);
        }
 
        /** Effectively download. */
-       protected Path download(URL url, Path dir, String name) throws IOException {
+       Path download(URL url, Path dir, String name) throws IOException {
 
                Path dest;
                if (name == null) {
@@ -959,7 +989,7 @@ public class Repackage {
        }
 
        /** Create a JAR file from a directory. */
-       protected Path createJar(Path bundleDir) throws IOException {
+       Path createJar(Path bundleDir) throws IOException {
                // Create the jar
                Path jarPath = bundleDir.getParent().resolve(bundleDir.getFileName() + ".jar");
                Path manifestPath = bundleDir.resolve("META-INF/MANIFEST.MF");
@@ -1004,12 +1034,12 @@ public class Repackage {
                        // in case there are additional directives
                        bundleSymbolicName = bundleSymbolicName.split(";")[0];
                        Manifest srcManifest = new Manifest();
-                       srcManifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
-                       srcManifest.getMainAttributes().putValue("Bundle-SymbolicName", bundleSymbolicName + ".src");
-                       srcManifest.getMainAttributes().putValue("Bundle-Version",
-                                       manifest.getMainAttributes().getValue("Bundle-Version").toString());
-                       srcManifest.getMainAttributes().putValue("Eclipse-SourceBundle",
-                                       bundleSymbolicName + ";version=\"" + manifest.getMainAttributes().getValue("Bundle-Version"));
+                       srcManifest.getMainAttributes().put(MANIFEST_VERSION, "1.0");
+                       srcManifest.getMainAttributes().putValue(BUNDLE_SYMBOLICNAME.toString(), bundleSymbolicName + ".src");
+                       srcManifest.getMainAttributes().putValue(BUNDLE_VERSION.toString(),
+                                       manifest.getMainAttributes().getValue(BUNDLE_VERSION.toString()).toString());
+                       srcManifest.getMainAttributes().putValue(ECLIPSE_SOURCE_BUNDLE.toString(), bundleSymbolicName
+                                       + ";version=\"" + manifest.getMainAttributes().getValue(BUNDLE_VERSION.toString()));
 
                        try (JarOutputStream srcJarOut = new JarOutputStream(Files.newOutputStream(srcJarP), srcManifest)) {
                                srcJarOut.setLevel(Deflater.BEST_COMPRESSION);
@@ -1037,20 +1067,49 @@ public class Repackage {
        /** MANIFEST headers. */
        enum ManifestConstants {
                // OSGi
+               /** OSGi bundle symbolic name. */
                BUNDLE_SYMBOLICNAME("Bundle-SymbolicName"), //
+               /** OSGi bundle version. */
                BUNDLE_VERSION("Bundle-Version"), //
+               /** OSGi bundle license. */
                BUNDLE_LICENSE("Bundle-License"), //
+               /** OSGi exported packages list. */
                EXPORT_PACKAGE("Export-Package"), //
+               /** OSGi imported packages list. */
                IMPORT_PACKAGE("Import-Package"), //
-               // JAVA
+               // Java
+               /** Java module name. */
                AUTOMATIC_MODULE_NAME("Automatic-Module-Name"), //
-               // SLC
-//             SLC_CATEGORY("SLC-Category"), //
-               SLC_ORIGIN_M2("SLC-Origin-M2"), //
-               SLC_ORIGIN_M2_MERGE("SLC-Origin-M2-Merge"), //
-               SLC_ORIGIN_M2_REPO("SLC-Origin-M2-Repo"), //
-               SLC_ORIGIN_MANIFEST_NOT_MODIFIED("SLC-Origin-ManifestNotModified"), //
-               SLC_ORIGIN_URI("SLC-Origin-URI"), //
+               // Eclipse
+               /** Eclipse source bundle. */
+               ECLIPSE_SOURCE_BUNDLE("Eclipse-SourceBundle"), //
+               // SPDX
+               /**
+                * SPDX license identifier.
+                * 
+                * @see https://spdx.org/licenses/
+                */
+               SPDX_LICENSE_IDENTIFIER("SPDX-License-Identifier"), //
+               // Argeo Origin
+               /**
+                * Maven coordinates of the origin, possibly partial when using common.bnd or
+                * merge.bnd.
+                */
+               ARGEO_ORIGIN_M2("Argeo-Origin-M2"), //
+               /** List of Maven coordinates to merge. */
+               ARGEO_ORIGIN_M2_MERGE("Argeo-Origin-M2-Merge"), //
+               /** Maven repository if not the default one. */
+               ARGEO_ORIGIN_M2_REPO("Argeo-Origin-M2-Repo"), //
+               /**
+                * Do not perform BND analysis of the origin component. Typically IMport_package
+                * and Export-Package will be kept untouched.
+                */
+               ARGEO_ORIGIN_MANIFEST_NOT_MODIFIED("Argeo-Origin-ManifestNotModified"), //
+               /**
+                * Origin (non-Maven) URI of the component. It may be anything (jar, archive,
+                * etc.).
+                */
+               ARGEO_ORIGIN_URI("Argeo-Origin-URI"), //
                ;
 
                final String value;