Latest bnd sync
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1370165 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundleplugin/src/main/java/aQute/lib/deployer/FileRepo.java b/bundleplugin/src/main/java/aQute/lib/deployer/FileRepo.java
index 922b39c..2256f63 100644
--- a/bundleplugin/src/main/java/aQute/lib/deployer/FileRepo.java
+++ b/bundleplugin/src/main/java/aQute/lib/deployer/FileRepo.java
@@ -1,6 +1,7 @@
package aQute.lib.deployer;
import java.io.*;
+import java.security.*;
import java.util.*;
import java.util.jar.*;
import java.util.regex.*;
@@ -118,64 +119,175 @@
return canWrite;
}
- public File put(Jar jar) throws Exception {
- init();
- dirty = true;
+ protected PutResult putArtifact(File tmpFile, PutOptions options) throws Exception {
+ assert (tmpFile != null);
+ assert (options != null);
- Manifest manifest = jar.getManifest();
- if (manifest == null)
- throw new IllegalArgumentException("No manifest in JAR: " + jar);
+ Jar jar = null;
+ try {
+ init();
+ dirty = true;
- String bsn = manifest.getMainAttributes().getValue(Analyzer.BUNDLE_SYMBOLICNAME);
- if (bsn == null)
- throw new IllegalArgumentException("No Bundle SymbolicName set");
+ jar = new Jar(tmpFile);
- Parameters b = Processor.parseHeader(bsn, null);
- if (b.size() != 1)
- throw new IllegalArgumentException("Multiple bsn's specified " + b);
+ Manifest manifest = jar.getManifest();
+ if (manifest == null)
+ throw new IllegalArgumentException("No manifest in JAR: " + jar);
- for (String key : b.keySet()) {
- bsn = key;
- if (!Verifier.SYMBOLICNAME.matcher(bsn).matches())
- throw new IllegalArgumentException("Bundle SymbolicName has wrong format: " + bsn);
- }
+ String bsn = manifest.getMainAttributes().getValue(Analyzer.BUNDLE_SYMBOLICNAME);
+ if (bsn == null)
+ throw new IllegalArgumentException("No Bundle SymbolicName set");
- String versionString = manifest.getMainAttributes().getValue(Analyzer.BUNDLE_VERSION);
- Version version;
- if (versionString == null)
- version = new Version();
- else
- version = new Version(versionString);
+ Parameters b = Processor.parseHeader(bsn, null);
+ if (b.size() != 1)
+ throw new IllegalArgumentException("Multiple bsn's specified " + b);
- if (reporter != null)
- reporter.trace("bsn=%s version=%s", bsn, version);
+ for (String key : b.keySet()) {
+ bsn = key;
+ if (!Verifier.SYMBOLICNAME.matcher(bsn).matches())
+ throw new IllegalArgumentException("Bundle SymbolicName has wrong format: " + bsn);
+ }
- File dir = new File(root, bsn);
- dir.mkdirs();
- String fName = bsn + "-" + version.getWithoutQualifier() + ".jar";
- File file = new File(dir, fName);
+ String versionString = manifest.getMainAttributes().getValue(Analyzer.BUNDLE_VERSION);
+ Version version;
+ if (versionString == null)
+ version = new Version();
+ else
+ version = new Version(versionString);
- if (reporter != null)
- reporter.trace("updating %s ", file.getAbsolutePath());
- if (!file.exists() || file.lastModified() < jar.lastModified()) {
- jar.write(file);
if (reporter != null)
- reporter.progress(-1, "updated " + file.getAbsolutePath());
- fireBundleAdded(jar, file);
- } else {
- if (reporter != null) {
- reporter.progress(-1, "Did not update " + jar + " because repo has a newer version");
- reporter.trace("NOT Updating " + fName + " (repo is newer)");
+ reporter.trace("bsn=%s version=%s", bsn, version);
+
+ File dir = new File(root, bsn);
+ if (!dir.exists() && !dir.mkdirs()) {
+ throw new IOException("Could not create directory " + dir);
+ }
+ String fName = bsn + "-" + version.getWithoutQualifier() + ".jar";
+ File file = new File(dir, fName);
+
+ boolean renamed = false;
+ PutResult result = new PutResult();
+
+ if (reporter != null)
+ reporter.trace("updating %s ", file.getAbsolutePath());
+ if (!file.exists() || file.lastModified() < jar.lastModified()) {
+ if (file.exists()) {
+ IO.delete(file);
+ }
+ IO.rename(tmpFile, file);
+ renamed = true;
+ result.artifact = file.toURI();
+
+ if (reporter != null)
+ reporter.progress(-1, "updated " + file.getAbsolutePath());
+
+ fireBundleAdded(jar, file);
+ } else {
+ if (reporter != null) {
+ reporter.progress(-1, "Did not update " + jar + " because repo has a newer version");
+ reporter.trace("NOT Updating " + fName + " (repo is newer)");
+ }
+ }
+
+ File latest = new File(dir, bsn + "-latest.jar");
+ boolean latestExists = latest.exists() && latest.isFile();
+ boolean latestIsOlder = latestExists && (latest.lastModified() < jar.lastModified());
+ if ((options.createLatest && !latestExists) || latestIsOlder) {
+ if (latestExists) {
+ IO.delete(latest);
+ }
+ if (!renamed) {
+ IO.rename(tmpFile, latest);
+ } else {
+ IO.copy(file, latest);
+ }
+ result.latest = latest.toURI();
+ }
+
+ return result;
+ }
+ finally {
+ if (jar != null) {
+ jar.close();
}
}
+ }
- File latest = new File(dir, bsn + "-latest.jar");
- if (latest.exists() && latest.lastModified() < jar.lastModified()) {
- jar.write(latest);
- file = latest;
+ /* a straight copy of this method lives in LocalIndexedRepo */
+ public PutResult put(InputStream stream, PutOptions options) throws Exception {
+ /* both parameters are required */
+ if ((stream == null) || (options == null)) {
+ throw new IllegalArgumentException("No stream and/or options specified");
}
- return file;
+ /* determine if the put is allowed */
+ if (!canWrite) {
+ throw new IOException("Repository is read-only");
+ }
+
+ /* the root directory of the repository has to be a directory */
+ if (!root.isDirectory()) {
+ throw new IOException("Repository directory " + root + " is not a directory");
+ }
+
+ /* determine if the artifact needs to be verified */
+ boolean verifyFetch = (options.digest != null);
+ boolean verifyPut = !options.allowArtifactChange;
+
+ /* determine which digests are needed */
+ boolean needFetchDigest = verifyFetch || verifyPut;
+ boolean needPutDigest = verifyPut || options.generateDigest;
+
+ /*
+ * setup a new stream that encapsulates the stream and calculates (when
+ * needed) the digest
+ */
+ DigestInputStream dis = new DigestInputStream(stream, MessageDigest.getInstance("SHA-1"));
+ dis.on(needFetchDigest);
+
+ File tmpFile = null;
+ try {
+ /*
+ * copy the artifact from the (new/digest) stream into a temporary
+ * file in the root directory of the repository
+ */
+ tmpFile = IO.createTempFile(root, "put", ".bnd");
+ IO.copy(dis, tmpFile);
+
+ /* get the digest if available */
+ byte[] disDigest = needFetchDigest ? dis.getMessageDigest().digest() : null;
+
+ /* verify the digest when requested */
+ if (verifyFetch && !MessageDigest.isEqual(options.digest, disDigest)) {
+ throw new IOException("Retrieved artifact digest doesn't match specified digest");
+ }
+
+ /* put the artifact into the repository (from the temporary file) */
+ PutResult r = putArtifact(tmpFile, options);
+
+ /* calculate the digest when requested */
+ if (needPutDigest && (r.artifact != null)) {
+ MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
+ IO.copy(new File(r.artifact), sha1);
+ r.digest = sha1.digest();
+ }
+
+ /* verify the artifact when requested */
+ if (verifyPut && (r.digest != null) && !MessageDigest.isEqual(disDigest, r.digest)) {
+ File f = new File(r.artifact);
+ if (f.exists()) {
+ IO.delete(f);
+ }
+ throw new IOException("Stored artifact digest doesn't match specified digest");
+ }
+
+ return r;
+ }
+ finally {
+ if (tmpFile != null && tmpFile.exists()) {
+ IO.delete(tmpFile);
+ }
+ }
}
protected void fireBundleAdded(Jar jar, File file) {
@@ -252,6 +364,7 @@
return null;
}
+ @Override
public String toString() {
return String.format("%-40s r/w=%s", root.getAbsolutePath(), canWrite());
}