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_MANIFEST_NOT_MODIFIED;
+import static org.argeo.build.Repackage.ManifestHeader.ARGEO_ORIGIN_NO_METADATA_GENERATION;
import static org.argeo.build.Repackage.ManifestHeader.ARGEO_ORIGIN_URI;
import static org.argeo.build.Repackage.ManifestHeader.BUNDLE_LICENSE;
import static org.argeo.build.Repackage.ManifestHeader.BUNDLE_SYMBOLICNAME;
* integrated in the bundles.
*/
final static String ENV_SOURCE_BUNDLES = "SOURCE_BUNDLES";
+ /** Environment variable on whether operations should be parallelised. */
+ final static String ENV_ARGEO_BUILD_SEQUENTIAL = "ARGEO_BUILD_SEQUENTIAL";
- /** Whether repackaging should run in parallel or sequentially. */
- final static boolean parallel = true;
+ /** Whether repackaging should run in parallel (default) or sequentially. */
+ final static boolean sequential = Boolean.parseBoolean(System.getenv(ENV_ARGEO_BUILD_SEQUENTIAL));
/** Main entry point. */
public static void main(String[] args) {
+ if (sequential)
+ logger.log(INFO, "Build will be sequential");
if (args.length < 2) {
System.err.println("Usage: <path to a2 output dir> <category1> <category2> ...");
System.exit(1);
List<CompletableFuture<Void>> toDos = new ArrayList<>();
for (int i = 1; i < args.length; i++) {
Path p = Paths.get(args[i]);
- if (parallel)
- toDos.add(CompletableFuture.runAsync(() -> factory.processCategory(p)));
- else
+ if (sequential)
factory.processCategory(p);
+ else
+ toDos.add(CompletableFuture.runAsync(() -> factory.processCategory(p)));
}
- CompletableFuture.allOf(toDos.toArray(new CompletableFuture[toDos.size()])).join();
+ if (!sequential)
+ CompletableFuture.allOf(toDos.toArray(new CompletableFuture[toDos.size()])).join();
// Summary
StringBuilder sb = new StringBuilder();
/** 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
+ * 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"), //
+ ARGEO_ORIGIN_NO_METADATA_GENERATION("Argeo-Origin-NoMetadataGeneration"), //
/**
* Embed the original jar without modifying it (may be required by some
* proprietary licenses, such as JCR Day License).
try {
Map<String, String> additionalEntries = new TreeMap<>();
boolean doNotModifyManifest = Boolean.parseBoolean(
- fileProps.getOrDefault(ARGEO_ORIGIN_MANIFEST_NOT_MODIFIED.toString(), "false").toString());
+ fileProps.getOrDefault(ARGEO_ORIGIN_NO_METADATA_GENERATION.toString(), "false").toString());
// Note: we always force the symbolic name
if (doNotModifyManifest) {
- fileEntries: for (Object key : fileProps.keySet()) {
- if (ARGEO_ORIGIN_M2.toString().equals(key))
- continue fileEntries;
+ for (Object key : fileProps.keySet()) {
String value = fileProps.getProperty(key.toString());
additionalEntries.put(key.toString(), value);
}
Files.createDirectories(sourceDir);
JarEntry entry;
entries: while ((entry = jarIn.getNextJarEntry()) != null) {
+ String relPath = entry.getName();
if (entry.isDirectory())
continue entries;
if (entry.getName().startsWith("META-INF")) {// skip META-INF entries
continue entries;
}
if (entry.getName().startsWith("/")) { // absolute paths
- // TODO does it really happen?
- logger.log(WARNING, entry.getName() + " has an absolute path");
- origin.deleted.add(entry.getName() + " from the sources" + mergingMsg);
+ int metaInfIndex = entry.getName().indexOf("META-INF");
+ if (metaInfIndex >= 0) {
+ relPath = entry.getName().substring(metaInfIndex);
+ origin.moved.add(" to " + relPath + " entry with absolute path " + entry.getName());
+ } else {
+ logger.log(WARNING, entry.getName() + " has an absolute path");
+ origin.deleted.add(entry.getName() + " from the sources" + mergingMsg);
+ }
continue entries;
}
- Path target = sourceDir.resolve(entry.getName());
+ Path target = sourceDir.resolve(relPath);
Files.createDirectories(target.getParent());
if (!Files.exists(target)) {
Files.copy(jarIn, target);
}
bundleDir = targetBase.resolve(nameVersion.getName() + "." + nameVersion.getBranch());
- if (sourceManifest != null) {// copy original MANIFEST
+ // copy original MANIFEST
+ if (sourceManifest != null) {
Path originalManifest = bundleDir.resolve(A2_ORIGIN).resolve("MANIFEST.MF");
Files.createDirectories(originalManifest.getParent());
try (OutputStream out = Files.newOutputStream(originalManifest)) {
sourceManifest.write(out);
}
- origin.moved.add("original MANIFEST (" + bundleDir.relativize(originalManifest) + ")");
+ origin.moved.add("original MANIFEST to " + bundleDir.relativize(originalManifest));
}
// force Java 9 module name
origin.deleted.add("MANIFEST header " + manifestEntry.getKey());
break;
default:
- if (!sourceManifest.getMainAttributes().containsKey(manifestEntry.getKey()))
+ if (sourceManifest != null && !sourceManifest.getMainAttributes().containsKey(manifestEntry.getKey()))
origin.added.add("MANIFEST header " + manifestEntry.getKey());
}
}
processLicense(bundleDir, manifest);
- origin.modified.add("jar MANIFEST (META-INF/MANIFEST.MF)");
+ origin.modified.add("MANIFEST (META-INF/MANIFEST.MF)");
// write the MANIFEST
try (OutputStream out = Files.newOutputStream(manifestPath)) {
manifest.write(out);
if (orIndex >= 0)
spdxLicenceId = spdxLicenceId.substring(0, orIndex).trim();
- // bundles starting with org.apache MUST be licensed with Apache-2.0
+ // set licenses of some well-known components
// even if we say otherwise (typically because coming from an Eclipse archive)
if (bundleDir.getFileName().startsWith("org.apache."))
spdxLicenceId = "Apache-2.0";
+ if (bundleDir.getFileName().startsWith("com.sun.jna."))
+ spdxLicenceId = "Apache-2.0";
+ if (bundleDir.getFileName().startsWith("com.ibm.icu."))
+ spdxLicenceId = "ICU";
+ if (bundleDir.getFileName().startsWith("javax.annotation."))
+ spdxLicenceId = "GPL-2.0-only WITH Classpath-exception-2.0";
+ if (bundleDir.getFileName().startsWith("javax.inject."))
+ spdxLicenceId = "Apache-2.0";
- manifest.getMainAttributes().put(SPDX_LICENSE_IDENTIFIER.toString(), spdxLicenceId);
+ manifest.getMainAttributes().putValue(SPDX_LICENSE_IDENTIFIER.toString(), spdxLicenceId);
if (!licensesUsed.containsKey(spdxLicenceId))
licensesUsed.put(spdxLicenceId, new TreeSet<>());
licensesUsed.get(spdxLicenceId).add(bundleDir.getParent().getFileName() + "/" + bundleDir.getFileName());
/** Create a JAR file from a directory. */
Path createJar(Path bundleDir, A2Origin origin) throws IOException {
- // write changes
- origin.appendChanges(bundleDir);
-
Path manifestPath = bundleDir.resolve("META-INF/MANIFEST.MF");
Manifest manifest;
try (InputStream in = Files.newInputStream(manifestPath)) {
manifest = new Manifest(in);
}
+ // legal requirements
+ origin.appendChanges(bundleDir);
createReadMe(bundleDir, manifest);
+
// create the jar
Path jarPath = bundleDir.getParent().resolve(bundleDir.getFileName() + ".jar");
try (JarOutputStream jarOut = new JarOutputStream(Files.newOutputStream(jarPath), manifest)) {
writer.append("This component is a repackaging of a third party component"
+ " in order to comply with A2 packaging standards.\n");
+ // license
+ String spdxLicenseId = manifest.getMainAttributes().getValue(ARGEO_ORIGIN_M2_REPO.toString());
+ writer.append("\nIt is redistributed under the following license:\n\n");
+ writer.append("SPDX-Identifier: " + spdxLicenseId + "\n\n");
+
+ if (!spdxLicenseId.startsWith("LicenseRef")) {// standard
+ int withIndex = spdxLicenseId.indexOf(" WITH ");
+ if (withIndex >= 0) {
+ String simpleId = spdxLicenseId.substring(0, withIndex).trim();
+ String exception = spdxLicenseId.substring(withIndex + " WITH ".length());
+ writer.append("which are available here: https://spdx.org/licenses/" + simpleId
+ + "\nand here: https://spdx.org/licenses/" + exception + "\n");
+ } else {
+ writer.append("which is available here: https://spdx.org/licenses/" + spdxLicenseId + "\n");
+ }
+ } else {
+ String url = manifest.getMainAttributes().getValue(BUNDLE_LICENSE.toString());
+ if (url != null) {
+ writer.write("which is avaliabel here: " + url + "\n");
+ } else {
+ logger.log(ERROR, "No licne URL for " + jarDir);
+ }
+ }
+ writer.write("\n");
+
String m2Repo = manifest.getMainAttributes().getValue(ARGEO_ORIGIN_M2_REPO.toString());
String originDesc = manifest.getMainAttributes().getValue(ARGEO_ORIGIN_M2.toString());
if (originDesc != null)
else
logger.log(ERROR, "Cannot find origin information in " + jarDir);
- writer.append("A detailed list of changes is available under " + CHANGES + "\n");
+ writer.append("A detailed list of changes is available under " + CHANGES + ".\n");
if (!jarDir.getFileName().endsWith(".src")) {// binary archive
if (sourceBundles)
writer.append("Corresponding sources are available in the related archive named "