You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by mc...@apache.org on 2012/09/06 20:28:09 UTC
svn commit: r1381708 [3/3] - in
/felix/trunk/bundleplugin/src/main/java/aQute: bnd/build/ bnd/build/model/
bnd/build/model/conversions/ bnd/component/ bnd/differ/ bnd/filerepo/
bnd/help/ bnd/make/calltree/ bnd/make/component/ bnd/make/coverage/
bnd/mav...
Modified: felix/trunk/bundleplugin/src/main/java/aQute/lib/deployer/FileRepo.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/deployer/FileRepo.java?rev=1381708&r1=1381707&r2=1381708&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/deployer/FileRepo.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/deployer/FileRepo.java Thu Sep 6 18:28:06 2012
@@ -3,29 +3,204 @@ package aQute.lib.deployer;
import java.io.*;
import java.security.*;
import java.util.*;
-import java.util.jar.*;
import java.util.regex.*;
-import aQute.bnd.header.*;
import aQute.bnd.osgi.*;
+import aQute.bnd.osgi.Verifier;
import aQute.bnd.service.*;
import aQute.bnd.version.*;
+import aQute.lib.collections.*;
+import aQute.lib.hex.*;
import aQute.lib.io.*;
+import aQute.libg.command.*;
+import aQute.libg.cryptography.*;
+import aQute.libg.reporter.*;
import aQute.service.reporter.*;
-public class FileRepo implements Plugin, RepositoryPlugin, Refreshable, RegistryPlugin {
- public final static String LOCATION = "location";
- public final static String READONLY = "readonly";
- public final static String NAME = "name";
+/**
+ * A FileRepo is the primary and example implementation of a repository based on
+ * a file system. It maintains its files in a bsn/bsn-version.jar style from a
+ * given location. It implements all the functions of the
+ * {@link RepositoryPlugin}, {@link Refreshable}, {@link Actionable}, and
+ * {@link Closeable}. The FileRepo can be extended or used as is. When used as
+ * is, it is possible to add shell commands to the life cycle of the FileRepo.
+ * This life cycle is as follows:
+ * <ul>
+ * <li>{@link #CMD_INIT} - Is only executed when the location did not exist</li>
+ * <li>{@link #CMD_OPEN} - Called (after init if necessary) to open it once</li>
+ * <li>{@link #CMD_REFRESH} - Called when refreshed.</li>
+ * <li>{@link #CMD_BEFORE_PUT} - Before the file system is changed</li>
+ * <li>{@link #CMD_AFTER_PUT} - After the file system has changed, and the put
+ * <li>{@link #CMD_BEFORE_GET} - Before the file is gotten</li>
+ * <li>{@link #CMD_AFTER_ACTION} - Before the file is gotten</li>
+ * <li>{@link #CMD_CLOSE} - When the repo is closed and no more actions will
+ * take place</li> was a success</li>
+ * <li>{@link #CMD_ABORT_PUT} - When the put is aborted.</li>
+ * <li>{@link #CMD_CLOSE} - To close the repository.</li>
+ * </ul>
+ * Additionally, it is possible to set the {@link #CMD_SHELL} and the
+ * {@link #CMD_PATH}. Notice that you can use the ${global} macro to read global
+ * (that is, machine local) settings from the ~/.bnd/settings.json file (can be
+ * managed with bnd).
+ */
+public class FileRepo implements Plugin, RepositoryPlugin, Refreshable, RegistryPlugin, Actionable, Closeable {
- File[] EMPTY_FILES = new File[0];
+ /**
+ * If set, will trace to stdout. Works only if no reporter is set.
+ */
+ public final static String TRACE = "trace";
+
+ /**
+ * Property name for the location of the repo, must be a valid path name
+ * using forward slashes (see {@link IO#getFile(String)}.
+ */
+ public final static String LOCATION = "location";
+
+ /**
+ * Property name for the readonly state of the repository. If no, will
+ * read/write, otherwise it must be a boolean value read by
+ * {@link Boolean#parseBoolean(String)}. Read only repositories will not
+ * accept writes.
+ */
+ public final static String READONLY = "readonly";
+
+ /**
+ * Set the name of this repository (optional)
+ */
+ public final static String NAME = "name";
+
+ /**
+ * Path property for commands. A comma separated path for directories to be
+ * searched for command. May contain $ @} which will be replaced by the
+ * system path. If this property is not set, the system path is assumed.
+ */
+ public static final String CMD_PATH = "cmd.path";
+
+ /**
+ * The name ( and path) of the shell to execute the commands. By default
+ * this is sh and searched in the path.
+ */
+ public static final String CMD_SHELL = "cmd.shell";
+
+ /**
+ * Property for commands. The command only runs when the location does not
+ * exist. </p>
+ *
+ * @param rootFile
+ * the root of the repo (directory exists)
+ */
+ public static final String CMD_INIT = "cmd.init";
+
+ /**
+ * Property for commands. Command is run before the repo is first used. </p>
+ *
+ * @param $0
+ * rootFile the root of the repo (directory exists)
+ */
+ public static final String CMD_OPEN = "cmd.open";
+
+ /**
+ * Property for commands. The command runs after a put operation. </p>
+ *
+ * @param $0
+ * the root of the repo (directory exists)
+ * @param $1
+ * the file that was put
+ * @param $2
+ * the hex checksum of the file
+ */
+ public static final String CMD_AFTER_PUT = "cmd.after.put";
+
+ /**
+ * Property for commands. The command runs when the repository is refreshed.
+ * </p>
+ *
+ * @param $
+ * {0} the root of the repo (directory exists)
+ */
+ public static final String CMD_REFRESH = "cmd.refresh";
+
+ /**
+ * Property for commands. The command runs after the file is put. </p>
+ *
+ * @param $0
+ * the root of the repo (directory exists)
+ * @param $1
+ * the path to a temporary file
+ */
+ public static final String CMD_BEFORE_PUT = "cmd.before.put";
+
+ /**
+ * Property for commands. The command runs when a put is aborted after file
+ * changes were made. </p>
+ *
+ * @param $0
+ * the root of the repo (directory exists)
+ * @param $1
+ * the temporary file that was used (optional)
+ */
+ public static final String CMD_ABORT_PUT = "cmd.abort.put";
+
+ /**
+ * Property for commands. The command runs after the file is put. </p>
+ *
+ * @param $0
+ * the root of the repo (directory exists)
+ */
+ public static final String CMD_CLOSE = "cmd.close";
+
+ /**
+ * Property for commands. Will be run after an action has been executed.
+ * </p>
+ *
+ * @param $0
+ * the root of the repo (directory exists)
+ * @param $1
+ * the path to the file that the action was executed on
+ * @param $2
+ * the action executed
+ */
+ public static final String CMD_AFTER_ACTION = "cmd.after.action";
+
+ /**
+ * Called before a before get.
+ *
+ * @param $0
+ * the root of the repo (directory exists)
+ * @param $1
+ * the bsn
+ * @param $2
+ * the version
+ */
+ public static final String CMD_BEFORE_GET = "cmd.before.get";
+
+ /**
+ * Options used when the options are null
+ */
+ static final PutOptions DEFAULTOPTIONS = new PutOptions();
+
+ String shell;
+ String path;
+ String init;
+ String open;
+ String refresh;
+ String beforePut;
+ String afterPut;
+ String abortPut;
+ String beforeGet;
+ String close;
+ String action;
+
+ File[] EMPTY_FILES = new File[0];
protected File root;
Registry registry;
- boolean canWrite = true;
- Pattern REPO_FILE = Pattern.compile("([-a-zA-z0-9_\\.]+)-([0-9\\.]+|latest)\\.(jar|lib)");
+ boolean canWrite = true;
+ Pattern REPO_FILE = Pattern.compile("([-a-zA-z0-9_\\.]+)-([0-9\\.]+)\\.(jar|lib)");
Reporter reporter;
boolean dirty;
String name;
+ boolean inited;
+ boolean trace;
public FileRepo() {}
@@ -35,280 +210,200 @@ public class FileRepo implements Plugin,
this.canWrite = canWrite;
}
- protected void init() throws Exception {
- // for extensions
+ /**
+ * Initialize the repository Subclasses should first call this method and
+ * then if it returns true, do their own initialization
+ *
+ * @return true if initialized, false if already had been initialized.
+ * @throws Exception
+ */
+ protected boolean init() throws Exception {
+ if (inited)
+ return false;
+
+ inited = true;
+
+ if (reporter == null) {
+ ReporterAdapter reporter = trace ? new ReporterAdapter(System.out) : new ReporterAdapter();
+ reporter.setTrace(trace);
+ reporter.setExceptions(trace);
+ this.reporter = reporter;
+ }
+
+ if (!root.isDirectory()) {
+ root.mkdirs();
+ if (!root.isDirectory())
+ throw new IllegalArgumentException("Location cannot be turned into a directory " + root);
+
+ exec(init, root.getAbsolutePath());
+ }
+ open();
+ return true;
}
+ /**
+ * @see aQute.bnd.service.Plugin#setProperties(java.util.Map)
+ */
public void setProperties(Map<String,String> map) {
String location = map.get(LOCATION);
if (location == null)
throw new IllegalArgumentException("Location must be set on a FileRepo plugin");
- root = new File(location);
-
+ root = IO.getFile(IO.home, location);
String readonly = map.get(READONLY);
if (readonly != null && Boolean.valueOf(readonly).booleanValue())
canWrite = false;
name = map.get(NAME);
+ path = map.get(CMD_PATH);
+ shell = map.get(CMD_SHELL);
+ init = map.get(CMD_INIT);
+ open = map.get(CMD_OPEN);
+ refresh = map.get(CMD_REFRESH);
+ beforePut = map.get(CMD_BEFORE_PUT);
+ abortPut = map.get(CMD_ABORT_PUT);
+ afterPut = map.get(CMD_AFTER_PUT);
+ beforeGet = map.get(CMD_BEFORE_GET);
+ close = map.get(CMD_CLOSE);
+ action = map.get(CMD_AFTER_ACTION);
+
+ trace = map.get(TRACE) != null && Boolean.parseBoolean(map.get(TRACE));
}
/**
- * Get a list of URLs to bundles that are constrained by the bsn and
- * versionRange.
+ * Answer if this repository can write.
*/
- private File[] get(String bsn, String versionRange) throws Exception {
- init();
-
- // If the version is set to project, we assume it is not
- // for us. A project repo will then get it.
- if (versionRange != null && versionRange.equals("project"))
- return null;
-
- //
- // Check if the entry exists
- //
- File f = new File(root, bsn);
- if (!f.isDirectory())
- return null;
-
- //
- // The version range we are looking for can
- // be null (for all) or a version range.
- //
- VersionRange range;
- if (versionRange == null || versionRange.equals("latest")) {
- range = new VersionRange("0");
- } else
- range = new VersionRange(versionRange);
-
- //
- // Iterator over all the versions for this BSN.
- // Create a sorted map over the version as key
- // and the file as URL as value. Only versions
- // that match the desired range are included in
- // this list.
- //
- File instances[] = f.listFiles();
- SortedMap<Version,File> versions = new TreeMap<Version,File>();
- for (int i = 0; i < instances.length; i++) {
- Matcher m = REPO_FILE.matcher(instances[i].getName());
- if (m.matches() && m.group(1).equals(bsn)) {
- String versionString = m.group(2);
- Version version;
- if (versionString.equals("latest"))
- version = new Version(Integer.MAX_VALUE);
- else
- version = new Version(versionString);
-
- if (range.includes(version) || versionString.equals(versionRange))
- versions.put(version, instances[i]);
- }
- }
-
- File[] files = versions.values().toArray(EMPTY_FILES);
- if ("latest".equals(versionRange) && files.length > 0) {
- return new File[] {
- files[files.length - 1]
- };
- }
- return files;
- }
-
public boolean canWrite() {
return canWrite;
}
- protected PutResult putArtifact(File tmpFile, PutOptions options) throws Exception {
+ /**
+ * Local helper method that tries to insert a file in the repository. This
+ * method can be overridden but MUST not change the content of the tmpFile.
+ * This method should also create a latest version of the artifact for
+ * reference by tools like ant etc. </p> It is allowed to rename the file,
+ * the tmp file must be beneath the root directory to prevent rename
+ * problems.
+ *
+ * @param tmpFile
+ * source file
+ * @param digest
+ * @return a File that contains the content of the tmpFile
+ * @throws Exception
+ */
+ protected File putArtifact(File tmpFile, byte[] digest) throws Exception {
assert (tmpFile != null);
- assert (options != null);
- Jar jar = null;
+ Jar jar = new Jar(tmpFile);
try {
- init();
dirty = true;
- jar = new Jar(tmpFile);
-
- Manifest manifest = jar.getManifest();
- if (manifest == null)
- throw new IllegalArgumentException("No manifest in JAR: " + jar);
-
- String bsn = manifest.getMainAttributes().getValue(Analyzer.BUNDLE_SYMBOLICNAME);
+ String bsn = jar.getBsn();
if (bsn == null)
- throw new IllegalArgumentException("No Bundle SymbolicName set");
-
- Parameters b = Processor.parseHeader(bsn, null);
- if (b.size() != 1)
- throw new IllegalArgumentException("Multiple bsn's specified " + b);
-
- for (String key : b.keySet()) {
- bsn = key;
- if (!Verifier.SYMBOLICNAME.matcher(bsn).matches())
- throw new IllegalArgumentException("Bundle SymbolicName has wrong format: " + bsn);
- }
+ throw new IllegalArgumentException("No bsn set in jar: " + tmpFile);
- String versionString = manifest.getMainAttributes().getValue(Analyzer.BUNDLE_VERSION);
- Version version;
+ String versionString = jar.getVersion();
if (versionString == null)
- version = new Version();
- else
- version = new Version(versionString);
+ versionString = "0";
+ else if (!Verifier.isVersion(versionString))
+ throw new IllegalArgumentException("Incorrect version in : " + tmpFile + " " + versionString);
- if (reporter != null)
- reporter.trace("bsn=%s version=%s", bsn, version);
+ Version version = new Version(versionString);
+
+ reporter.trace("bsn=%s version=%s", bsn, version);
File dir = new File(root, bsn);
- if (!dir.exists() && !dir.mkdirs()) {
+ dir.mkdirs();
+ if (!dir.isDirectory())
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();
+ reporter.trace("updating %s ", file.getAbsolutePath());
- 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();
+ IO.rename(tmpFile, 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)");
- }
- }
+ fireBundleAdded(jar, file);
+ afterPut(file, bsn, version, Hex.toHexString(digest));
+ // TODO like to beforeGet rid of the latest option. This is only
+ // used to have a constant name for the outside users (like ant)
+ // we should be able to handle this differently?
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();
- }
+ IO.copy(file, latest);
- return result;
+ reporter.trace("updated %s", file.getAbsolutePath());
+
+ return file;
}
finally {
- if (jar != null) {
- jar.close();
- }
+ jar.close();
}
}
- /* a straight copy of this method lives in LocalIndexedRepo */
+ /*
+ * (non-Javadoc)
+ * @see aQute.bnd.service.RepositoryPlugin#put(java.io.InputStream,
+ * aQute.bnd.service.RepositoryPlugin.PutOptions)
+ */
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");
- }
-
/* 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");
- }
+ assert stream != null;
- /* determine if the artifact needs to be verified */
- boolean verifyFetch = (options.digest != null);
- boolean verifyPut = !options.allowArtifactChange;
+ if (options == null)
+ options = DEFAULTOPTIONS;
- /* determine which digests are needed */
- boolean needFetchDigest = verifyFetch || verifyPut;
- boolean needPutDigest = verifyPut || options.generateDigest;
+ init();
/*
- * setup a new stream that encapsulates the stream and calculates (when
- * needed) the digest
+ * copy the artifact from the (new/digest) stream into a temporary file
+ * in the root directory of the repository
*/
- DigestInputStream dis = new DigestInputStream(stream, MessageDigest.getInstance("SHA-1"));
- dis.on(needFetchDigest);
-
- File tmpFile = null;
+ File tmpFile = IO.createTempFile(root, "put", ".jar");
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");
- }
+ DigestInputStream dis = new DigestInputStream(stream, MessageDigest.getInstance("SHA-1"));
+ try {
+ IO.copy(dis, tmpFile);
- /* put the artifact into the repository (from the temporary file) */
- PutResult r = putArtifact(tmpFile, options);
+ byte[] digest = dis.getMessageDigest().digest();
- /* 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();
- }
+ if (options.digest != null && !Arrays.equals(digest, options.digest))
+ throw new IOException("Retrieved artifact digest doesn't match specified 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");
- }
+ /*
+ * put the artifact into the repository (from the temporary
+ * file)
+ */
+ beforePut(tmpFile);
+ File file = putArtifact(tmpFile, digest);
+ file.setReadOnly();
- return r;
- }
- finally {
- if (tmpFile != null && tmpFile.exists()) {
- IO.delete(tmpFile);
- }
- }
- }
+ PutResult result = new PutResult();
+ result.digest = digest;
+ result.artifact = file.toURI();
- protected void fireBundleAdded(Jar jar, File file) {
- if (registry == null)
- return;
- List<RepositoryListenerPlugin> listeners = registry.getPlugins(RepositoryListenerPlugin.class);
- for (RepositoryListenerPlugin listener : listeners) {
- try {
- listener.bundleAdded(this, jar, file);
+ return result;
}
- catch (Exception e) {
- if (reporter != null)
- reporter.warning("Repository listener threw an unexpected exception: %s", e);
+ finally {
+ dis.close();
}
}
+ catch (Exception e) {
+ abortPut(tmpFile);
+ throw e;
+ }
+ finally {
+ IO.delete(tmpFile);
+ }
}
public void setLocation(String string) {
- root = new File(string);
- if (!root.isDirectory())
- throw new IllegalArgumentException("Invalid repository directory");
+ root = IO.getFile(string);
}
public void setReporter(Reporter reporter) {
@@ -344,7 +439,7 @@ public class FileRepo implements Plugin,
return result;
}
- public List<Version> versions(String bsn) throws Exception {
+ public SortedSet<Version> versions(String bsn) throws Exception {
init();
File dir = new File(root, bsn);
if (dir.isDirectory()) {
@@ -359,9 +454,9 @@ public class FileRepo implements Plugin,
list.add(new Version(version));
}
}
- return list;
+ return new SortedList<Version>(list);
}
- return null;
+ return SortedList.empty();
}
@Override
@@ -373,7 +468,9 @@ public class FileRepo implements Plugin,
return root;
}
- public boolean refresh() {
+ public boolean refresh() throws Exception {
+ init();
+ exec(refresh, root);
if (dirty) {
dirty = false;
return true;
@@ -388,60 +485,290 @@ public class FileRepo implements Plugin,
return name;
}
- public Jar get(String bsn, Version v) throws Exception {
+ /*
+ * (non-Javadoc)
+ * @see aQute.bnd.service.RepositoryPlugin#get(java.lang.String,
+ * aQute.bnd.version.Version, java.util.Map)
+ */
+ public File get(String bsn, Version version, Map<String,String> properties, DownloadListener... listeners)
+ throws Exception {
init();
- File bsns = new File(root, bsn);
- File version = new File(bsns, bsn + "-" + v.getMajor() + "." + v.getMinor() + "." + v.getMicro() + ".jar");
- if (version.exists())
- return new Jar(version);
+ beforeGet(bsn, version);
+ File file = getLocal(bsn, version, properties);
+ if (file.exists()) {
+ for (DownloadListener l : listeners) {
+ try {
+ l.success(file);
+ }
+ catch (Exception e) {
+ reporter.exception(e, "Download listener for %s", file);
+ }
+ }
+ return file;
+ }
return null;
}
- public File get(String bsn, String version, Strategy strategy, Map<String,String> properties) throws Exception {
- if (version == null)
- version = "0.0.0";
+ public void setRegistry(Registry registry) {
+ this.registry = registry;
+ }
- if (strategy == Strategy.EXACT) {
- VersionRange vr = new VersionRange(version);
- if (vr.isRange())
- return null;
+ public String getLocation() {
+ return root.toString();
+ }
- if (vr.getHigh().getMajor() == Integer.MAX_VALUE)
- version = "latest";
+ public Map<String,Runnable> actions(Object... target) throws Exception {
+ if (target == null || target.length == 0)
+ return null; // no default actions
- File file = IO.getFile(root, bsn + "/" + bsn + "-" + version + ".jar");
- if (file.isFile())
- return file;
- file = IO.getFile(root, bsn + "/" + bsn + "-" + version + ".lib");
- if (file.isFile())
- return file;
- return null;
+ try {
+ String bsn = (String) target[0];
+ Version version = (Version) target[1];
+ final File f = get(bsn, version, null);
+ if (f == null)
+ return null;
+
+ Map<String,Runnable> actions = new HashMap<String,Runnable>();
+ actions.put("Delete " + bsn + "-" + status(bsn, version), new Runnable() {
+ public void run() {
+ IO.delete(f);
+ if (f.getParentFile().list().length == 0)
+ IO.delete(f.getParentFile());
+ afterAction(f, "delete");
+ };
+ });
+ return actions;
}
- File[] files = get(bsn, version);
- if (files == null || files.length == 0)
+ catch (Exception e) {
return null;
+ }
+ }
+
+ protected void afterAction(File f, String key) {
+ exec(action, root, f, key);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see aQute.bnd.service.Actionable#tooltip(java.lang.Object[])
+ */
+ @SuppressWarnings("unchecked")
+ public String tooltip(Object... target) throws Exception {
+ if (target == null || target.length == 0)
+ return String.format("%s\n%s", getName(), root);
- if (files.length >= 0) {
- switch (strategy) {
- case LOWEST :
- return files[0];
- case HIGHEST :
- return files[files.length - 1];
- case EXACT :
- // TODO
- break;
+ try {
+ String bsn = (String) target[0];
+ Version version = (Version) target[1];
+ Map<String,String> map = null;
+ if (target.length > 2)
+ map = (Map<String,String>) target[2];
+
+ File f = getLocal(bsn, version, map);
+ String s = String.format("Path: %s\nSize: %s\nSHA1: %s", f.getAbsolutePath(), readable(f.length(), 0), SHA1
+ .digest(f).asHex());
+ if (f.getName().endsWith(".lib") && f.isFile()) {
+ s += "\n" + IO.collect(f);
}
+ return s;
+
+ }
+ catch (Exception e) {
+ return null;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see aQute.bnd.service.Actionable#title(java.lang.Object[])
+ */
+ public String title(Object... target) throws Exception {
+ if (target == null || target.length == 0)
+ return getName();
+
+ if (target.length == 1 && target[0] instanceof String)
+ return (String) target[0];
+
+ if (target.length == 2 && target[0] instanceof String && target[1] instanceof Version) {
+ return status((String) target[0], (Version) target[1]);
}
+
return null;
}
- public void setRegistry(Registry registry) {
- this.registry = registry;
+ protected File getLocal(String bsn, Version version, Map<String,String> properties) {
+ File dir = new File(root, bsn);
+
+ File fjar = new File(dir, bsn + "-" + version.getWithoutQualifier() + ".jar");
+ if (fjar.isFile())
+ return fjar.getAbsoluteFile();
+
+ File flib = new File(dir, bsn + "-" + version.getWithoutQualifier() + ".lib");
+ if (flib.isFile())
+ return flib.getAbsoluteFile();
+
+ return fjar.getAbsoluteFile();
}
- public String getLocation() {
- return root.toString();
+ protected String status(String bsn, Version version) {
+ File file = getLocal(bsn, version, null);
+ StringBuilder sb = new StringBuilder(version.toString());
+ String del = " [";
+
+ if (file.getName().endsWith(".lib")) {
+ sb.append(del).append("L");
+ del = "";
+ }
+ if (!file.getName().endsWith(".jar")) {
+ sb.append(del).append("?");
+ del = "";
+ }
+ if (!file.isFile()) {
+ sb.append(del).append("X");
+ del = "";
+ }
+ if (file.length() == 0) {
+ sb.append(del).append("0");
+ del = "";
+ }
+ if (del.equals(""))
+ sb.append("]");
+ return sb.toString();
+ }
+
+ private static String[] names = {
+ "bytes", "Kb", "Mb", "Gb"
+ };
+
+ private Object readable(long length, int n) {
+ if (length < 0)
+ return "<invalid>";
+
+ if (length < 1024 || n >= names.length)
+ return length + names[n];
+
+ return readable(length / 1024, n + 1);
+ }
+
+ public void close() throws IOException {
+ if (inited)
+ exec(close, root.getAbsolutePath());
+ }
+
+ protected void open() {
+ exec(open, root.getAbsolutePath());
+ }
+
+ protected void beforePut(File tmp) {
+ exec(beforePut, root.getAbsolutePath(), tmp.getAbsolutePath());
+ }
+
+ protected void afterPut(File file, String bsn, Version version, String sha) {
+ exec(afterPut, root.getAbsolutePath(), file.getAbsolutePath(), sha);
+ }
+
+ protected void abortPut(File tmpFile) {
+ exec(abortPut, root.getAbsolutePath(), tmpFile.getAbsolutePath());
+ }
+
+ protected void beforeGet(String bsn, Version version) {
+ exec(beforeGet, root.getAbsolutePath(), bsn, version);
+ }
+
+ protected void fireBundleAdded(Jar jar, File file) {
+ if (registry == null)
+ return;
+ List<RepositoryListenerPlugin> listeners = registry.getPlugins(RepositoryListenerPlugin.class);
+ for (RepositoryListenerPlugin listener : listeners) {
+ try {
+ listener.bundleAdded(this, jar, file);
+ }
+ catch (Exception e) {
+ if (reporter != null)
+ reporter.warning("Repository listener threw an unexpected exception: %s", e);
+ }
+ }
+ }
+
+ /**
+ * Execute a command. Used in different stages so that the repository can be
+ * synced with external tools.
+ *
+ * @param line
+ * @param target
+ */
+ void exec(String line, Object... args) {
+ if (line == null)
+ return;
+
+ try {
+ if (args != null)
+ for (int i = 0; i < args.length; i++) {
+ if (i == 0)
+ line = line.replaceAll("\\$\\{@\\}", args[0].toString());
+ line = line.replaceAll("\\$" + i, args[i].toString());
+ }
+
+ if (shell == null) {
+ shell = System.getProperty("os.name").toLowerCase().indexOf("win") > 0 ? "cmd.exe" : "sh";
+ }
+ Command cmd = new Command(shell);
+
+ if (path != null) {
+ cmd.inherit();
+ String oldpath = cmd.var("PATH");
+ path = path.replaceAll("\\s*,\\s*", File.pathSeparator);
+ path = path.replaceAll("\\$\\{@\\}", oldpath);
+ cmd.var("PATH", path);
+ }
+
+ cmd.setCwd(getRoot());
+ StringBuilder stdout = new StringBuilder();
+ StringBuilder stderr = new StringBuilder();
+ int result = cmd.execute(line, stdout, stderr);
+ if (result != 0) {
+ reporter.error("Command %s failed with %s %s %s", line, result, stdout, stderr);
+ }
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ reporter.exception(e, e.getMessage());
+ }
+ }
+
+ /*
+ * 8 Set the root directory directly
+ */
+ public void setDir(File repoDir) {
+ this.root = repoDir;
+ }
+
+ /**
+ * Delete an entry from the repository and cleanup the directory
+ *
+ * @param bsn
+ * @param version
+ * @throws Exception
+ */
+ public void delete(String bsn, Version version) throws Exception {
+ assert bsn != null;
+
+ SortedSet<Version> versions;
+ if (version == null)
+ versions = versions(bsn);
+ else
+ versions = new SortedList<Version>(version);
+
+ for (Version v : versions) {
+ File f = getLocal(bsn, version, null);
+ if (!f.isFile())
+ reporter.error("No artifact found for %s:%s", bsn, version);
+ else
+ IO.delete(f);
+ }
+ if ( versions(bsn).isEmpty())
+ IO.delete( new File(root,bsn));
}
}
Modified: felix/trunk/bundleplugin/src/main/java/aQute/lib/io/IO.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/io/IO.java?rev=1381708&r1=1381707&r2=1381708&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/io/IO.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/io/IO.java Thu Sep 6 18:28:06 2012
@@ -7,6 +7,8 @@ import java.security.*;
import java.util.*;
public class IO {
+ static public File work = new File(System.getProperty("user.dir"));
+ static public File home = new File(System.getProperty("user.home"));
public static void copy(Reader r, Writer w) throws IOException {
try {
@@ -226,7 +228,7 @@ public class IO {
/**
* Create a temporary file.
- *
+ *
* @param directory
* the directory in which to create the file. Can be null, in
* which case the system TMP directory is used
@@ -257,16 +259,32 @@ public class IO {
}
public static File getFile(String filename) {
- return new File(filename.replace("/", File.separator));
+ return getFile(work, filename);
}
-
+
public static File getFile(File base, String file) {
+
+ if (file.startsWith("~/")) {
+ file = file.substring(2);
+ if (!file.startsWith("~/")) {
+ return getFile(home, file);
+ }
+ }
+ if (file.startsWith("~")) {
+ file = file.substring(1);
+ return getFile(home.getParentFile(), file);
+ }
+
File f = new File(file);
if (f.isAbsolute())
return f;
int n;
+ if (base == null)
+ base = work;
+
f = base.getAbsoluteFile();
+
while ((n = file.indexOf('/')) > 0) {
String first = file.substring(0, n);
file = file.substring(n + 1);
@@ -280,28 +298,35 @@ public class IO {
return new File(f, file).getAbsoluteFile();
}
- /** Deletes the specified file.
- * Folders are recursively deleted.<br>
+ /**
+ * Deletes the specified file. Folders are recursively deleted.<br>
* If file(s) cannot be deleted, no feedback is provided (fail silently).
- * @param f file to be deleted
+ *
+ * @param f
+ * file to be deleted
*/
public static void delete(File f) {
try {
deleteWithException(f);
- } catch (IOException e) {
+ }
+ catch (IOException e) {
// Ignore a failed delete
}
}
-
- /** Deletes the specified file.
- * Folders are recursively deleted.<br>
+
+ /**
+ * Deletes the specified file. Folders are recursively deleted.<br>
* Throws exception if any of the files could not be deleted.
- * @param f file to be deleted
- * @throws IOException if the file (or contents of a folder) could not be deleted
+ *
+ * @param f
+ * file to be deleted
+ * @throws IOException
+ * if the file (or contents of a folder) could not be deleted
*/
public static void deleteWithException(File f) throws IOException {
f = f.getAbsoluteFile();
- if (!f.exists()) return;
+ if (!f.exists())
+ return;
if (f.getParentFile() == null)
throw new IllegalArgumentException("Cannot recursively delete root for safety reasons");
@@ -311,7 +336,8 @@ public class IO {
for (File sub : subs) {
try {
deleteWithException(sub);
- } catch (IOException e) {
+ }
+ catch (IOException e) {
wasDeleted = false;
}
}
@@ -323,19 +349,25 @@ public class IO {
}
}
- /** Deletes <code>to</code> file if it exists, and renames <code>from</code> file to <code>to</code>.<br>
- * Throws exception the rename operation fails.
- * @param from source file
- * @param to destination file
- * @throws IOException if the rename operation fails
- */
- public static void rename(File from, File to) throws IOException {
- IO.deleteWithException(to);
-
- boolean renamed = from.renameTo(to);
- if (!renamed) throw new IOException("Could not rename " + from.getAbsoluteFile() + " to " + to.getAbsoluteFile());
- }
+ /**
+ * Deletes <code>to</code> file if it exists, and renames <code>from</code>
+ * file to <code>to</code>.<br>
+ * Throws exception the rename operation fails.
+ *
+ * @param from
+ * source file
+ * @param to
+ * destination file
+ * @throws IOException
+ * if the rename operation fails
+ */
+ public static void rename(File from, File to) throws IOException {
+ IO.deleteWithException(to);
+ boolean renamed = from.renameTo(to);
+ if (!renamed)
+ throw new IOException("Could not rename " + from.getAbsoluteFile() + " to " + to.getAbsoluteFile());
+ }
public static long drain(InputStream in) throws IOException {
long result = 0;
Modified: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ByteArrayHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ByteArrayHandler.java?rev=1381708&r1=1381707&r2=1381708&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ByteArrayHandler.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/json/ByteArrayHandler.java Thu Sep 6 18:28:06 2012
@@ -4,17 +4,17 @@ import java.io.*;
import java.lang.reflect.*;
import java.util.*;
-import aQute.lib.base64.*;
import aQute.lib.hex.*;
+/**
+ *
+ * Will now use hex for encoding byte arrays
+ *
+ */
public class ByteArrayHandler extends Handler {
-
@Override
void encode(Encoder app, Object object, Map<Object,Type> visited) throws IOException, Exception {
- if ( app.codec.isHex())
- StringHandler.string(app, Hex.toHexString((byte[]) object));
- else
- StringHandler.string(app, Base64.encodeBase64((byte[]) object));
+ StringHandler.string(app, Hex.toHexString((byte[]) object));
}
@Override
@@ -31,8 +31,6 @@ public class ByteArrayHandler extends Ha
@Override
Object decode(Decoder dec, String s) throws Exception {
- if ( dec.codec.isHex())
- return Hex.toByteArray(s);
- return Base64.decodeBase64(s);
+ return Hex.toByteArray(s);
}
}
Modified: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/JSONCodec.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/json/JSONCodec.java?rev=1381708&r1=1381707&r2=1381708&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/json/JSONCodec.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/json/JSONCodec.java Thu Sep 6 18:28:06 2012
@@ -34,6 +34,8 @@ import java.util.regex.*;
* <p/>
* This Codec class can be used in a concurrent environment. The Decoders and
* Encoders, however, must only be used in a single thread.
+ * <p/>
+ * Will now use hex for encoding byte arrays
*/
public class JSONCodec {
final static String START_CHARACTERS = "[{\"-0123456789tfn";
@@ -51,7 +53,6 @@ public class JSONCodec {
private static ByteArrayHandler byteh = new ByteArrayHandler();
boolean ignorenull;
- boolean useHex;
/**
* Create a new Encoder with the state and appropriate API.
@@ -488,19 +489,4 @@ public class JSONCodec {
return ignorenull;
}
- /**
- * Use hex instead of default base 64 encoding
- *
- * @param useHex
- * @return
- */
- public JSONCodec setHex(boolean useHex) {
- this.useHex = useHex;
- return this;
- }
-
- public boolean isHex() {
- return useHex;
- }
-
}
\ No newline at end of file
Modified: felix/trunk/bundleplugin/src/main/java/aQute/lib/json/packageinfo
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/json/packageinfo?rev=1381708&r1=1381707&r2=1381708&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/json/packageinfo (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/json/packageinfo Thu Sep 6 18:28:06 2012
@@ -1 +1 @@
-version 2.4.0
+version 3.0.0
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/settings/Settings.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/settings/Settings.java?rev=1381708&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/settings/Settings.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/settings/Settings.java Thu Sep 6 18:28:06 2012
@@ -0,0 +1,251 @@
+package aQute.lib.settings;
+
+import java.io.*;
+import java.security.*;
+import java.security.spec.*;
+import java.util.*;
+
+import aQute.lib.io.*;
+import aQute.lib.json.*;
+
+/**
+ * Maintains persistent settings for bnd (or other apps). The default is
+ * ~/.bnd/settings.json). The settings are normal string properties but it
+ * specially maintains a public/private key pair and it provides a method to
+ * sign a byte array with this pair.
+ * <p/>
+ * Why not keystore and preferences? Well, keystore is hard to use (you can only
+ * store a private key when you have a certificate, but you cannot create a
+ * certificate without using com.sun classes) and preferences are not editable.
+ */
+public class Settings implements Map<String,String> {
+ static JSONCodec codec = new JSONCodec();
+
+ private File where;
+ private PublicKey publicKey;
+ private PrivateKey privateKey;
+ private boolean loaded;
+ private boolean dirty;
+
+ public static class Data {
+ public int version = 1;
+ public byte[] secret;
+ public byte[] id;
+ public Map<String,String> map = new HashMap<String,String>();
+ }
+
+ Data data = new Data();
+
+ public Settings() {
+ this("~/.bnd/settings.json");
+ }
+
+ public Settings(String where) {
+ assert where != null;
+ this.where = IO.getFile(IO.work, where);
+ }
+
+ public boolean load() {
+ if (this.where.isFile() && this.where.length() > 1) {
+ try {
+ data = codec.dec().from(this.where).get(Data.class);
+ loaded = true;
+ return true;
+ }
+ catch (Exception e) {
+ throw new RuntimeException("Cannot read settings file " + this.where, e);
+ }
+ }
+
+ if (!data.map.containsKey("name"))
+ data.map.put("name", System.getProperty("user.name"));
+ return false;
+ }
+
+ private void check() {
+ if (loaded)
+ return;
+ load();
+ loaded = true;
+ }
+
+ public void save() {
+ if (!this.where.getParentFile().isDirectory() && !this.where.getParentFile().mkdirs())
+ throw new RuntimeException("Cannot create directory in " + this.where.getParent());
+
+ try {
+ codec.enc().to(this.where).put(data).flush();
+ assert this.where.isFile();
+ }
+ catch (Exception e) {
+ throw new RuntimeException("Cannot write settings file " + this.where, e);
+ }
+ }
+
+ public void generate() throws Exception {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+ SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
+ keyGen.initialize(1024, random);
+ KeyPair pair = keyGen.generateKeyPair();
+ privateKey = pair.getPrivate();
+ publicKey = pair.getPublic();
+ data.secret = privateKey.getEncoded();
+ data.id = publicKey.getEncoded();
+ save();
+ }
+
+ public String getEmail() {
+ return get("email");
+ }
+
+ public void setEmail(String email) {
+ put("email", email);
+ }
+
+ public void setName(String v) {
+ put("name", v);
+ }
+
+ public String getName() {
+ String name = get("name");
+ if (name != null)
+ return name;
+ return System.getProperty("user.name");
+ }
+
+ /**
+ * Return an encoded public RSA key. this key can be decoded with an
+ * X509EncodedKeySpec
+ *
+ * @return an encoded public key.
+ * @throws Exception
+ */
+ public byte[] getPublicKey() throws Exception {
+ initKeys();
+ return data.id;
+ }
+
+ /**
+ * Return an encoded private RSA key. this key can be decoded with an
+ * PKCS8EncodedKeySpec
+ *
+ * @return an encoded private key.
+ * @throws Exception
+ */
+ public byte[] getPrivateKey() throws Exception {
+ initKeys();
+ return data.secret;
+ }
+
+ /*
+ * Initialize the keys.
+ */
+ private void initKeys() throws Exception {
+ check();
+ if (publicKey != null)
+ return;
+
+ if (data.id == null || data.secret == null) {
+ generate();
+ } else {
+ PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(data.secret);
+ X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(data.id);
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ privateKey = keyFactory.generatePrivate(privateKeySpec);
+ publicKey = keyFactory.generatePublic(publicKeySpec);
+ }
+ }
+
+ /**
+ * Sign a byte array
+ */
+ public byte[] sign(byte[] con) throws Exception {
+ initKeys();
+
+ Signature hmac = Signature.getInstance("SHA1withRSA");
+ hmac.initSign(privateKey);
+ hmac.update(con);
+ return hmac.sign();
+ }
+
+ /**
+ * Verify a signed byte array
+ */
+ public boolean verify(byte[] con) throws Exception {
+ initKeys();
+
+ Signature hmac = Signature.getInstance("SHA1withRSA");
+ hmac.initVerify(publicKey);
+ hmac.update(con);
+ return hmac.verify(con);
+ }
+
+ public void clear() {
+ data = new Data();
+ IO.delete(where);
+ }
+
+ public boolean containsKey(Object key) {
+ check();
+ return data.map.containsKey(key);
+ }
+
+ public boolean containsValue(Object value) {
+ check();
+ return data.map.containsValue(value);
+ }
+
+ public Set<java.util.Map.Entry<String,String>> entrySet() {
+ check();
+ return data.map.entrySet();
+ }
+
+ public String get(Object key) {
+ check();
+
+ return data.map.get(key);
+ }
+
+ public boolean isEmpty() {
+ check();
+ return data.map.isEmpty();
+ }
+
+ public Set<String> keySet() {
+ check();
+ return data.map.keySet();
+ }
+
+ public String put(String key, String value) {
+ check();
+ dirty = true;
+ return data.map.put(key, value);
+ }
+
+ public void putAll(Map< ? extends String, ? extends String> v) {
+ check();
+ dirty = true;
+ data.map.putAll(v);
+ }
+
+ public String remove(Object key) {
+ check();
+ dirty = true;
+ return data.map.remove(key);
+ }
+
+ public int size() {
+ check();
+ return data.map.size();
+ }
+
+ public Collection<String> values() {
+ check();
+ return data.map.values();
+ }
+
+ public boolean isDirty() {
+ return dirty;
+ }
+
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/settings/Settings.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/settings/Settings.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/settings/packageinfo
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/settings/packageinfo?rev=1381708&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/settings/packageinfo (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/settings/packageinfo Thu Sep 6 18:28:06 2012
@@ -0,0 +1 @@
+version 1.1
\ No newline at end of file
Modified: felix/trunk/bundleplugin/src/main/java/aQute/libg/command/Command.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/libg/command/Command.java?rev=1381708&r1=1381707&r2=1381708&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/libg/command/Command.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/libg/command/Command.java Thu Sep 6 18:28:06 2012
@@ -68,7 +68,7 @@ public class Command {
if (timeout != 0) {
timer = new TimerTask() {
- @Override
+ //@Override TODO why did this not work? TimerTask implements Runnable
public void run() {
timedout = true;
process.destroy();
Modified: felix/trunk/bundleplugin/src/main/java/aQute/libg/cryptography/Digester.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/libg/cryptography/Digester.java?rev=1381708&r1=1381707&r2=1381708&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/libg/cryptography/Digester.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/libg/cryptography/Digester.java Thu Sep 6 18:28:06 2012
@@ -48,4 +48,13 @@ public abstract class Digester<T extends
public abstract T digest(byte[] bytes) throws Exception;
public abstract String getAlgorithm();
+
+ public T from(File f) throws Exception {
+ IO.copy(f, this);
+ return digest();
+ }
+ public T from(byte[] f) throws Exception {
+ IO.copy(f, this);
+ return digest();
+ }
}
Modified: felix/trunk/bundleplugin/src/main/java/aQute/libg/cryptography/MD5.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/libg/cryptography/MD5.java?rev=1381708&r1=1381707&r2=1381708&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/libg/cryptography/MD5.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/libg/cryptography/MD5.java Thu Sep 6 18:28:06 2012
@@ -36,6 +36,13 @@ public class MD5 extends Digest {
}
public static MD5 digest(byte [] data) throws Exception {
- return getDigester().digest(data);
+ return getDigester().from(data);
+ }
+
+ public static MD5 digest(File f) throws NoSuchAlgorithmException, Exception {
+ return getDigester().from(f);
+ }
+ public static MD5 digest(InputStream f) throws NoSuchAlgorithmException, Exception {
+ return getDigester().from(f);
}
}
\ No newline at end of file
Modified: felix/trunk/bundleplugin/src/main/java/aQute/libg/cryptography/SHA1.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/libg/cryptography/SHA1.java?rev=1381708&r1=1381707&r2=1381708&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/libg/cryptography/SHA1.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/libg/cryptography/SHA1.java Thu Sep 6 18:28:06 2012
@@ -36,6 +36,13 @@ public class SHA1 extends Digest {
}
public static SHA1 digest(byte [] data) throws Exception {
- return getDigester().digest(data);
+ return getDigester().from(data);
+ }
+
+ public static SHA1 digest(File f) throws NoSuchAlgorithmException, Exception {
+ return getDigester().from(f);
+ }
+ public static SHA1 digest(InputStream f) throws NoSuchAlgorithmException, Exception {
+ return getDigester().from(f);
}
}
\ No newline at end of file
Modified: felix/trunk/bundleplugin/src/main/java/aQute/libg/cryptography/SHA256.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/libg/cryptography/SHA256.java?rev=1381708&r1=1381707&r2=1381708&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/libg/cryptography/SHA256.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/libg/cryptography/SHA256.java Thu Sep 6 18:28:06 2012
@@ -35,7 +35,15 @@ public class SHA256 extends Digest {
return ALGORITHM;
}
+
public static SHA256 digest(byte [] data) throws Exception {
- return getDigester().digest(data);
+ return getDigester().from(data);
+ }
+
+ public static SHA256 digest(File f) throws NoSuchAlgorithmException, Exception {
+ return getDigester().from(f);
+ }
+ public static SHA256 digest(InputStream f) throws NoSuchAlgorithmException, Exception {
+ return getDigester().from(f);
}
}
\ No newline at end of file
Modified: felix/trunk/bundleplugin/src/main/java/aQute/libg/qtokens/QuotedTokenizer.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/libg/qtokens/QuotedTokenizer.java?rev=1381708&r1=1381707&r2=1381708&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/libg/qtokens/QuotedTokenizer.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/libg/qtokens/QuotedTokenizer.java Thu Sep 6 18:28:06 2012
@@ -82,7 +82,7 @@ public class QuotedTokenizer {
c = string.charAt(index++);
if (c == quote)
break;
- if (c == '\\' && index < string.length() && string.charAt(index + 1) == quote)
+ if (c == '\\' && index < string.length() && string.charAt(index) == quote)
c = string.charAt(index++);
sb.append(c);
}
Modified: felix/trunk/bundleplugin/src/main/java/aQute/libg/reporter/ReporterAdapter.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/libg/reporter/ReporterAdapter.java?rev=1381708&r1=1381707&r2=1381708&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/libg/reporter/ReporterAdapter.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/libg/reporter/ReporterAdapter.java Thu Sep 6 18:28:06 2012
@@ -246,20 +246,9 @@ public class ReporterAdapter implements
return getInfo(other,null);
}
public boolean getInfo(Report other, String prefix) {
- boolean ok = true;
- if ( prefix == null)
- prefix = "";
- else
- prefix = prefix + ": ";
- for ( String error : other.getErrors()) {
- errors.add( prefix + error);
- ok = false;
- }
-
- for ( String warning : other.getWarnings()) {
- warnings.add( prefix + warning);
- }
- return ok;
+ addErrors(prefix, other.getErrors());
+ addWarnings(prefix, other.getWarnings());
+ return other.isOk();
}
public Location getLocation(String msg) {
@@ -285,4 +274,31 @@ public class ReporterAdapter implements
public <T> T getMessages(Class<T> c) {
return ReporterMessages.base(this, c);
}
+
+ /**
+ * Add a number of errors
+ */
+
+ public void addErrors( String prefix, Collection<String> errors) {
+ if ( prefix == null)
+ prefix = "";
+ else
+ prefix = prefix + ": ";
+ for ( String s: errors) {
+ this.errors.add( prefix + s);
+ }
+ }
+ /**
+ * Add a number of warnings
+ */
+
+ public void addWarnings( String prefix, Collection<String> warnings) {
+ if ( prefix == null)
+ prefix = "";
+ else
+ prefix = prefix + ": ";
+ for ( String s: warnings) {
+ this.warnings.add( prefix + s);
+ }
+ }
}
Modified: felix/trunk/bundleplugin/src/main/java/aQute/libg/sed/ReplacerAdapter.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/libg/sed/ReplacerAdapter.java?rev=1381708&r1=1381707&r2=1381708&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/libg/sed/ReplacerAdapter.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/libg/sed/ReplacerAdapter.java Thu Sep 6 18:28:06 2012
@@ -268,7 +268,7 @@ public class ReplacerAdapter extends Rep
}
catch (InvocationTargetException e) {
if (e.getCause() instanceof IllegalArgumentException) {
- reporter.error("%s, for cmd: %s, arguments; %s", e.getMessage(), method, Arrays.toString(args));
+ reporter.error("%s, for cmd: %s, arguments; %s", e.getCause().getMessage(), method, Arrays.toString(args));
} else {
reporter.warning("Exception in replace: " + e.getCause());
e.getCause().printStackTrace();