]> git.argeo.org Git - cc0/argeo-build.git/blobdiff - src/org/argeo/build/Repackage.java
Improve error reporting
[cc0/argeo-build.git] / src / org / argeo / build / Repackage.java
index ee15af42f324362d6c7e02d5b6d9c1016b1bfdd4..c72810bff625b9970bcefd28df0705b14b1d054f 100644 (file)
@@ -9,10 +9,12 @@ import static java.nio.file.FileVisitResult.CONTINUE;
 import static java.nio.file.StandardOpenOption.APPEND;
 import static java.nio.file.StandardOpenOption.CREATE;
 import static java.util.jar.Attributes.Name.MANIFEST_VERSION;
+import static org.argeo.build.Repackage.ManifestHeader.ARGEO_DO_NOT_MODIFY;
 import static org.argeo.build.Repackage.ManifestHeader.ARGEO_ORIGIN_M2;
 import static org.argeo.build.Repackage.ManifestHeader.ARGEO_ORIGIN_M2_MERGE;
 import static org.argeo.build.Repackage.ManifestHeader.ARGEO_ORIGIN_M2_REPO;
 import static org.argeo.build.Repackage.ManifestHeader.ARGEO_ORIGIN_NO_METADATA_GENERATION;
+import static org.argeo.build.Repackage.ManifestHeader.ARGEO_ORIGIN_SOURCES_URI;
 import static org.argeo.build.Repackage.ManifestHeader.ARGEO_ORIGIN_URI;
 import static org.argeo.build.Repackage.ManifestHeader.AUTOMATIC_MODULE_NAME;
 import static org.argeo.build.Repackage.ManifestHeader.BUNDLE_LICENSE;
@@ -171,6 +173,11 @@ public class Repackage {
                 * etc.).
                 */
                ARGEO_ORIGIN_URI("Argeo-Origin-URI"), //
+               /**
+                * Origin (non-Maven) URI of the source of the component. It may be anything
+                * (jar, archive, code repository, etc.).
+                */
+               ARGEO_ORIGIN_SOURCES_URI("Argeo-Origin-Sources-URI"), //
                ;
 
                final String value;
@@ -225,12 +232,12 @@ public class Repackage {
        final Map<String, List<String>> mirrors = new HashMap<String, List<String>>();
 
        /** Whether sources should be packaged separately */
-       final boolean sourceBundles;
+       final boolean separateSources;
 
        /** Constructor initialises the various variables */
        public Repackage(Path a2Base, Path descriptorsBase) {
-               sourceBundles = Boolean.parseBoolean(System.getenv(ENV_SOURCE_BUNDLES));
-               if (sourceBundles)
+               separateSources = Boolean.parseBoolean(System.getenv(ENV_SOURCE_BUNDLES));
+               if (separateSources)
                        logger.log(INFO, "Sources will be packaged separately");
 
                Objects.requireNonNull(a2Base);
@@ -240,7 +247,7 @@ public class Repackage {
 
                // TODO define and use a build base
                this.a2Base = a2Base;
-               this.a2SrcBase = a2Base.getParent().resolve(a2Base.getFileName() + ".src");
+               this.a2SrcBase = separateSources ? a2Base.getParent().resolve(a2Base.getFileName() + ".src") : a2Base;
                this.a2LibBase = a2Base.resolve("lib");
                this.descriptorsBase = descriptorsBase;
                if (!Files.exists(this.descriptorsBase))
@@ -311,10 +318,6 @@ public class Repackage {
                        try (InputStream in = Files.newInputStream(bndFile)) {
                                fileProps.load(in);
                        }
-                       String repoStr = fileProps.containsKey(ARGEO_ORIGIN_M2_REPO.toString())
-                                       ? fileProps.getProperty(ARGEO_ORIGIN_M2_REPO.toString())
-                                       : null;
-
                        // use file name as symbolic name
                        if (!fileProps.containsKey(BUNDLE_SYMBOLICNAME.toString())) {
                                String symbolicName = bndFile.getFileName().toString();
@@ -326,32 +329,20 @@ public class Repackage {
                        if (m2Coordinates == null)
                                throw new IllegalArgumentException("No M2 coordinates available for " + bndFile);
                        M2Artifact artifact = new M2Artifact(m2Coordinates);
-                       URL url = M2ConventionsUtils.mavenRepoUrl(repoStr, artifact);
-                       Path downloaded = downloadMaven(url, artifact);
-
-                       // some proprietary artifacts do not allow any modification
-                       // when releasing (with separate sources) we just copy it
-                       boolean doNotModify = Boolean.parseBoolean(
-                                       fileProps.getOrDefault(ManifestHeader.ARGEO_DO_NOT_MODIFY.toString(), "false").toString());
-                       if (doNotModify && sourceBundles) {
-                               Path unmodifiedTarget = targetCategoryBase.resolve(
-                                               fileProps.getProperty(BUNDLE_SYMBOLICNAME.toString()) + "." + artifact.getBranch() + ".jar");
-                               Files.copy(downloaded, unmodifiedTarget, StandardCopyOption.REPLACE_EXISTING);
-                               Path bundleDir = targetCategoryBase
-                                               .resolve(fileProps.getProperty(BUNDLE_SYMBOLICNAME.toString()) + "." + artifact.getBranch());
-                               downloadAndProcessM2Sources(repoStr, artifact, bundleDir, false);
-                               Manifest manifest;
-                               try (JarInputStream jarIn = new JarInputStream(Files.newInputStream(unmodifiedTarget))) {
-                                       manifest = jarIn.getManifest();
-                               }
-                               createSourceJar(bundleDir, manifest);
+
+                       Path downloaded = downloadMaven(fileProps, artifact);
+
+                       boolean doNotModify = Boolean
+                                       .parseBoolean(fileProps.getOrDefault(ARGEO_DO_NOT_MODIFY.toString(), "false").toString());
+                       if (doNotModify) {
+                               processNotModified(targetCategoryBase, downloaded, fileProps, artifact);
                                return;
                        }
 
                        // regular processing
                        A2Origin origin = new A2Origin();
                        Path bundleDir = processBndJar(downloaded, targetCategoryBase, fileProps, artifact, origin);
-                       downloadAndProcessM2Sources(repoStr, artifact, bundleDir, false);
+                       downloadAndProcessM2Sources(fileProps, artifact, bundleDir, false, false);
                        createJar(bundleDir, origin);
                } catch (Exception e) {
                        throw new RuntimeException("Cannot process " + bndFile, e);
@@ -412,39 +403,40 @@ public class Repackage {
                                }
 
                                // prepare manifest entries
-                               Properties mergeProps = new Properties();
-                               mergeProps.putAll(commonProps);
+                               Properties mergedProps = new Properties();
+                               mergedProps.putAll(commonProps);
 
                                fileEntries: for (Object key : fileProps.keySet()) {
                                        if (ARGEO_ORIGIN_M2.toString().equals(key))
                                                continue fileEntries;
                                        String value = fileProps.getProperty(key.toString());
-                                       Object previousValue = mergeProps.put(key.toString(), value);
+                                       Object previousValue = mergedProps.put(key.toString(), value);
                                        if (previousValue != null) {
                                                logger.log(WARNING,
                                                                commonBnd + ": " + key + " was " + previousValue + ", overridden with " + value);
                                        }
                                }
-                               mergeProps.put(ARGEO_ORIGIN_M2.toString(), artifact.toM2Coordinates());
-                               if (!mergeProps.containsKey(BUNDLE_SYMBOLICNAME.toString())) {
+                               mergedProps.put(ARGEO_ORIGIN_M2.toString(), artifact.toM2Coordinates());
+                               if (!mergedProps.containsKey(BUNDLE_SYMBOLICNAME.toString())) {
                                        // use file name as symbolic name
                                        String symbolicName = p.getFileName().toString();
                                        symbolicName = symbolicName.substring(0, symbolicName.length() - ".bnd".length());
-                                       mergeProps.put(BUNDLE_SYMBOLICNAME.toString(), symbolicName);
+                                       mergedProps.put(BUNDLE_SYMBOLICNAME.toString(), symbolicName);
                                }
 
-                               String repoStr = mergeProps.containsKey(ARGEO_ORIGIN_M2_REPO.toString())
-                                               ? mergeProps.getProperty(ARGEO_ORIGIN_M2_REPO.toString())
-                                               : null;
-
                                // download
-                               URL url = M2ConventionsUtils.mavenRepoUrl(repoStr, artifact);
-                               Path downloaded = downloadMaven(url, artifact);
+                               Path downloaded = downloadMaven(mergedProps, artifact);
 
-                               A2Origin origin = new A2Origin();
-                               Path targetBundleDir = processBndJar(downloaded, targetCategoryBase, mergeProps, artifact, origin);
-                               downloadAndProcessM2Sources(repoStr, artifact, targetBundleDir, false);
-                               createJar(targetBundleDir, origin);
+                               boolean doNotModify = Boolean
+                                               .parseBoolean(mergedProps.getOrDefault(ARGEO_DO_NOT_MODIFY.toString(), "false").toString());
+                               if (doNotModify) {
+                                       processNotModified(targetCategoryBase, downloaded, mergedProps, artifact);
+                               } else {
+                                       A2Origin origin = new A2Origin();
+                                       Path targetBundleDir = processBndJar(downloaded, targetCategoryBase, mergedProps, artifact, origin);
+                                       downloadAndProcessM2Sources(mergedProps, artifact, targetBundleDir, false, false);
+                                       createJar(targetBundleDir, origin);
+                               }
                        }
                } catch (IOException e) {
                        throw new RuntimeException("Cannot process " + duDir, e);
@@ -484,10 +476,6 @@ public class Repackage {
                if (artifactsStr == null)
                        throw new IllegalArgumentException(mergeBnd + ": " + ARGEO_ORIGIN_M2_MERGE + " must be set");
 
-               String repoStr = mergeProps.containsKey(ARGEO_ORIGIN_M2_REPO.toString())
-                               ? mergeProps.getProperty(ARGEO_ORIGIN_M2_REPO.toString())
-                               : null;
-
                String bundleSymbolicName = mergeProps.getProperty(BUNDLE_SYMBOLICNAME.toString());
                if (bundleSymbolicName == null)
                        throw new IllegalArgumentException("Bundle-SymbolicName must be set in " + mergeBnd);
@@ -506,8 +494,7 @@ public class Repackage {
                        if (artifact.getVersion() == null)
                                artifact.setVersion(m2Version);
                        originDesc.add(artifact.toString());
-                       URL url = M2ConventionsUtils.mavenRepoUrl(repoStr, artifact);
-                       Path downloaded = downloadMaven(url, artifact);
+                       Path downloaded = downloadMaven(mergeProps, artifact);
                        JarEntry entry;
                        try (JarInputStream jarIn = new JarInputStream(Files.newInputStream(downloaded), false)) {
                                entries: while ((entry = jarIn.getNextJarEntry()) != null) {
@@ -587,7 +574,7 @@ public class Repackage {
                        origin.added.add("binary content of " + artifact);
 
                        // process sources
-                       downloadAndProcessM2Sources(repoStr, artifact, bundleDir, true);
+                       downloadAndProcessM2Sources(mergeProps, artifact, bundleDir, true, false);
                }
 
                // additional service files
@@ -714,14 +701,38 @@ public class Repackage {
 
        }
 
-       /** Download and integrates sources for a single Maven artifact. */
-       void downloadAndProcessM2Sources(String repoStr, M2Artifact artifact, Path targetBundleDir, boolean merging)
+       /** Process an artifact that should not be modified. */
+       void processNotModified(Path targetCategoryBase, Path downloaded, Properties fileProps, M2Artifact artifact)
                        throws IOException {
+               // Some proprietary or signed artifacts do not allow any modification
+               // When releasing (with separate sources), we just copy it
+               Path unmodifiedTarget = targetCategoryBase
+                               .resolve(fileProps.getProperty(BUNDLE_SYMBOLICNAME.toString()) + "." + artifact.getBranch() + ".jar");
+               Files.createDirectories(unmodifiedTarget.getParent());
+               Files.copy(downloaded, unmodifiedTarget, StandardCopyOption.REPLACE_EXISTING);
+               Path bundleDir = targetCategoryBase
+                               .resolve(fileProps.getProperty(BUNDLE_SYMBOLICNAME.toString()) + "." + artifact.getBranch());
+               downloadAndProcessM2Sources(fileProps, artifact, bundleDir, false, true);
+               Manifest manifest;
+               try (JarInputStream jarIn = new JarInputStream(Files.newInputStream(unmodifiedTarget))) {
+                       manifest = jarIn.getManifest();
+               }
+               createSourceJar(bundleDir, manifest, true);
+       }
+
+       /** Download and integrates sources for a single Maven artifact. */
+       void downloadAndProcessM2Sources(Properties props, M2Artifact artifact, Path targetBundleDir, boolean merging,
+                       boolean unmodified) throws IOException {
                try {
+                       String repoStr = props.containsKey(ARGEO_ORIGIN_M2_REPO.toString())
+                                       ? props.getProperty(ARGEO_ORIGIN_M2_REPO.toString())
+                                       : null;
+                       String alternateUri = props.getProperty(ARGEO_ORIGIN_SOURCES_URI.toString());
                        M2Artifact sourcesArtifact = new M2Artifact(artifact.toM2Coordinates(), "sources");
-                       URL sourcesUrl = M2ConventionsUtils.mavenRepoUrl(repoStr, sourcesArtifact);
-                       Path sourcesDownloaded = downloadMaven(sourcesUrl, artifact, true);
-                       processM2SourceJar(sourcesDownloaded, targetBundleDir, merging ? artifact : null);
+                       URL sourcesUrl = alternateUri != null ? new URL(alternateUri)
+                                       : M2ConventionsUtils.mavenRepoUrl(repoStr, sourcesArtifact);
+                       Path sourcesDownloaded = downloadMaven(sourcesUrl, sourcesArtifact);
+                       processM2SourceJar(sourcesDownloaded, targetBundleDir, merging ? artifact : null, unmodified);
                        logger.log(TRACE, () -> "Processed source " + sourcesDownloaded);
                } catch (Exception e) {
                        logger.log(ERROR, () -> "Cannot download source for  " + artifact);
@@ -730,9 +741,9 @@ public class Repackage {
        }
 
        /** Integrate sources from a downloaded jar file. */
-       void processM2SourceJar(Path file, Path bundleDir, M2Artifact mergingFrom) throws IOException {
+       void processM2SourceJar(Path file, Path bundleDir, M2Artifact mergingFrom, boolean unmodified) throws IOException {
                A2Origin origin = new A2Origin();
-               Path sourceDir = sourceBundles ? bundleDir.getParent().resolve(bundleDir.toString() + ".src")
+               Path sourceDir = separateSources || unmodified ? bundleDir.getParent().resolve(bundleDir.toString() + ".src")
                                : bundleDir.resolve("OSGI-OPT/src");
                try (JarInputStream jarIn = new JarInputStream(Files.newInputStream(file), false)) {
 
@@ -776,7 +787,7 @@ public class Repackage {
                        }
                }
                // write the changes
-               if (sourceBundles) {
+               if (separateSources) {
                        origin.appendChanges(sourceDir);
                } else {
                        origin.added.add("source code under OSGI-OPT/src");
@@ -785,15 +796,18 @@ public class Repackage {
        }
 
        /** Download a Maven artifact. */
-       Path downloadMaven(URL url, M2Artifact artifact) throws IOException {
-               return downloadMaven(url, artifact, false);
+       Path downloadMaven(Properties props, M2Artifact artifact) throws IOException {
+               String repoStr = props.containsKey(ARGEO_ORIGIN_M2_REPO.toString())
+                               ? props.getProperty(ARGEO_ORIGIN_M2_REPO.toString())
+                               : null;
+               String alternateUri = props.getProperty(ARGEO_ORIGIN_URI.toString());
+               URL url = alternateUri != null ? new URL(alternateUri) : M2ConventionsUtils.mavenRepoUrl(repoStr, artifact);
+               return downloadMaven(url, artifact);
        }
 
        /** Download a Maven artifact. */
-       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");
+       Path downloadMaven(URL url, M2Artifact artifact) throws IOException {
+               return download(url, mavenBase, M2ConventionsUtils.artifactPath("", artifact));
        }
 
        /*
@@ -912,7 +926,7 @@ public class Repackage {
                                NameVersion nameVersion = new NameVersion(relatedBundle[0], version);
                                bundleDir = targetBase.resolve(nameVersion.getName() + "." + nameVersion.getBranch());
 
-                               Path sourceDir = sourceBundles ? bundleDir.getParent().resolve(bundleDir.toString() + ".src")
+                               Path sourceDir = separateSources ? bundleDir.getParent().resolve(bundleDir.toString() + ".src")
                                                : bundleDir.resolve("OSGI-OPT/src");
 
                                Files.createDirectories(sourceDir);
@@ -929,7 +943,7 @@ public class Repackage {
                                }
 
                                // write the changes
-                               if (sourceBundles) {
+                               if (separateSources) {
                                        origin.appendChanges(sourceDir);
                                } else {
                                        origin.added.add("source code under OSGI-OPT/src");
@@ -1346,21 +1360,23 @@ public class Repackage {
                }
                deleteDirectory(bundleDir);
 
-               if (sourceBundles)
-                       createSourceJar(bundleDir, manifest);
+               if (separateSources)
+                       createSourceJar(bundleDir, manifest, false);
 
                return jarPath;
        }
 
        /** Package sources separately, in the Eclipse-SourceBundle format. */
-       void createSourceJar(Path bundleDir, Manifest manifest) throws IOException {
+       void createSourceJar(Path bundleDir, Manifest manifest, boolean notModified) throws IOException {
                Path bundleCategoryDir = bundleDir.getParent();
                Path sourceDir = bundleCategoryDir.resolve(bundleDir.toString() + ".src");
                if (!Files.exists(sourceDir)) {
                        logger.log(WARNING, sourceDir + " does not exist, skipping...");
                        return;
                }
-               createReadMe(sourceDir, manifest);
+
+               if (!notModified)
+                       createReadMe(sourceDir, manifest);
 
                Path relPath = a2Base.relativize(bundleCategoryDir);
                Path srcCategoryDir = a2SrcBase.resolve(relPath);
@@ -1456,7 +1472,7 @@ public class Repackage {
 
                        writer.append("\nA detailed list of changes is available under " + CHANGES + ".\n");
                        if (!jarDir.getFileName().endsWith(".src")) {// binary archive
-                               if (sourceBundles)
+                               if (separateSources)
                                        writer.append("Corresponding sources are available in the related archive named "
                                                        + jarDir.toString() + ".src.jar.\n");
                                else
@@ -1574,7 +1590,8 @@ class M2ConventionsUtils {
 
        /** Absolute path to the directories where the files will be stored */
        static String artifactParentPath(String artifactBasePath, M2Artifact artifact) {
-               return artifactBasePath + (artifactBasePath.endsWith("/") ? "" : "/") + artifactParentPath(artifact);
+               return artifactBasePath + (artifactBasePath.endsWith("/") || artifactBasePath.equals("") ? "" : "/")
+                               + artifactParentPath(artifact);
        }
 
        /** Relative path to the directories where the files will be stored */