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 2009/07/13 12:06:50 UTC

svn commit: r793527 [1/7] - in /felix/trunk/bundleplugin: ./ src/main/java/aQute/ src/main/java/aQute/bnd/ src/main/java/aQute/bnd/build/ src/main/java/aQute/bnd/help/ src/main/java/aQute/bnd/make/ src/main/java/aQute/bnd/service/ src/main/java/aQute/b...

Author: mcculls
Date: Mon Jul 13 10:06:47 2009
New Revision: 793527

URL: http://svn.apache.org/viewvc?rev=793527&view=rev
Log:
FELIX-1262: add local Bnd source to apply temporary patches

Added:
    felix/trunk/bundleplugin/src/main/java/aQute/
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/CircularDependencyException.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/Container.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/Project.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/ProjectBuilder.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/ReflectAction.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/ScriptAction.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/Workspace.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/help/
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/help/Syntax.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/Make.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/MakeBnd.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/MakeCopy.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/ServiceComponent.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/AnalyzerPlugin.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/MakePlugin.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Plugin.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Refreshable.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RepositoryPlugin.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/SignerPlugin.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/action/
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/action/Action.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/test/
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/test/ProjectLauncher.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/
    felix/trunk/bundleplugin/src/main/java/aQute/lib/filter/
    felix/trunk/bundleplugin/src/main/java/aQute/lib/filter/Filter.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/About.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/AbstractResource.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Analyzer.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Builder.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/ClassDataCollector.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Clazz.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Constants.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/EmbeddedResource.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/FileResource.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Instruction.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/InstructionFilter.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Jar.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/JarResource.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Macro.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/OpCodes.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/PreprocessResource.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Processor.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Resource.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/URLResource.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Verifier.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/ZipResource.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/eclipse/
    felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/eclipse/EclipseClasspath.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/libg/
    felix/trunk/bundleplugin/src/main/java/aQute/libg/generics/
    felix/trunk/bundleplugin/src/main/java/aQute/libg/generics/Create.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/libg/header/
    felix/trunk/bundleplugin/src/main/java/aQute/libg/header/OSGiHeader.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/libg/qtokens/
    felix/trunk/bundleplugin/src/main/java/aQute/libg/qtokens/QuotedTokenizer.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/libg/reporter/
    felix/trunk/bundleplugin/src/main/java/aQute/libg/reporter/Reporter.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/libg/sed/
    felix/trunk/bundleplugin/src/main/java/aQute/libg/sed/Replacer.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/libg/sed/Sed.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/libg/version/
    felix/trunk/bundleplugin/src/main/java/aQute/libg/version/Version.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/libg/version/VersionRange.java   (with props)
    felix/trunk/bundleplugin/src/main/java/aQute/scripting/
    felix/trunk/bundleplugin/src/main/java/aQute/scripting/Scripter.java   (with props)
Modified:
    felix/trunk/bundleplugin/pom.xml
    felix/trunk/bundleplugin/src/main/java/org/apache/felix/bundleplugin/BundleAllPlugin.java
    felix/trunk/bundleplugin/src/main/java/org/apache/felix/bundleplugin/BundlePlugin.java
    felix/trunk/bundleplugin/src/main/java/org/apache/felix/bundleplugin/DependencyEmbedder.java
    felix/trunk/bundleplugin/src/main/java/org/apache/felix/bundleplugin/ManifestPlugin.java

Modified: felix/trunk/bundleplugin/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/pom.xml?rev=793527&r1=793526&r2=793527&view=diff
==============================================================================
--- felix/trunk/bundleplugin/pom.xml (original)
+++ felix/trunk/bundleplugin/pom.xml Mon Jul 13 10:06:47 2009
@@ -54,11 +54,6 @@
  
  <dependencies>
   <dependency>
-   <groupId>biz.aQute</groupId>
-   <artifactId>bndlib</artifactId>
-   <version>0.0.311</version>
-  </dependency>
-  <dependency>
     <groupId>net.sf.kxml</groupId>
     <artifactId>kxml2</artifactId>
     <version>2.2.2</version>

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/CircularDependencyException.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/CircularDependencyException.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/CircularDependencyException.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/CircularDependencyException.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,10 @@
+package aQute.bnd.build;
+
+public class CircularDependencyException extends Exception {
+    public CircularDependencyException(String string) {
+        super(string);
+    }
+
+    private static final long serialVersionUID = 1L;
+
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/CircularDependencyException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/Container.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/Container.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/Container.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/Container.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,131 @@
+package aQute.bnd.build;
+
+import java.io.*;
+import java.util.*;
+
+public class Container {
+    public enum TYPE {
+        REPO, PROJECT, EXTERNAL, LIBRARY, ERROR
+    }
+
+    final File                file;
+    final TYPE                type;
+    final String              bsn;
+    final String              version;
+    final String              error;
+    final Project             project;
+    final Map<String, String> attributes;
+
+    Container(Project project, String bsn, String version, TYPE type,
+            File source, String error, Map<String, String> attributes) {
+        this.bsn = bsn;
+        this.version = version;
+        this.type = type;
+        this.file = source != null ? source : new File("/" + bsn + ":"
+                + version + ":" + type);
+        this.project = project;
+        this.error = error;
+        if (attributes == null || attributes.isEmpty())
+            this.attributes = Collections.emptyMap();
+        else
+            this.attributes = attributes;
+    }
+
+    public Container(Project project, File file) {
+        this(project, file.getName(), "project", TYPE.PROJECT, file, null, null);
+    }
+
+    public Container(File file) {
+        this(null, file.getName(), "project", TYPE.EXTERNAL, file, null, null);
+    }
+
+    public File getFile() {
+        return file;
+    }
+
+    public String getBundleSymbolicName() {
+        return bsn;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public TYPE getType() {
+        return type;
+    }
+
+    public String getError() {
+        return error;
+    }
+
+    public boolean equals(Object other) {
+        if (other instanceof Container)
+            return file.equals(((Container) other).file);
+        else
+            return false;
+    }
+
+    public int hashCode() {
+        return file.hashCode();
+    }
+
+    public Project getProject() {
+        return project;
+    }
+
+    /**
+     * Must show the file name or the error formatted as a file name
+     * 
+     * @return
+     */
+    public String toString() {
+        if (getError() != null)
+            return "/error/" + getError();
+        else
+            return getFile().getAbsolutePath();
+    }
+
+    public Map<String, String> getAttributes() {
+        return attributes;
+    }
+
+    /**
+     * Return the this if this is anything else but a library. If it is a
+     * library, return the members. This could work recursively, e.g., libraries
+     * can point to libraries.
+     * 
+     * @return
+     * @throws Exception
+     */
+    public List<Container> getMembers() throws Exception {
+        List<Container> result = project.newList();
+
+        // Are ww a library? If no, we are the result
+        if (getType() != TYPE.LIBRARY)
+            result.add(this);
+        else {
+            // We are a library, parse the file. This is
+            // basically a specification clause per line.
+            // I.e. you can do bsn; version, bsn2; version. But also
+            // spread it out over lines.
+            InputStream in = new FileInputStream(file);
+            BufferedReader rd = new BufferedReader(new InputStreamReader(in,
+                    "UTF-8"));
+            try {
+                String line;
+                while ((line = rd.readLine()) != null) {
+                    line = line.trim();
+                    if (!line.startsWith("#") && line.length() > 0) {
+                        List<Container> list = project.getBundles(
+                                Workspace.STRATEGY_EXACT, line);
+                        result.addAll(list);
+                    }
+                }
+            } finally {
+                in.close();
+            }
+        }
+        return result;
+    }
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/Container.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/Project.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/Project.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/Project.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/Project.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,1067 @@
+package aQute.bnd.build;
+
+import java.io.*;
+import java.util.*;
+import java.util.jar.*;
+
+import aQute.bnd.help.*;
+import aQute.bnd.service.*;
+import aQute.bnd.service.action.*;
+import aQute.bnd.test.*;
+import aQute.lib.osgi.*;
+import aQute.lib.osgi.eclipse.*;
+import aQute.libg.sed.*;
+import aQute.service.scripting.*;
+
+/**
+ * This class is NOT threadsafe
+ * 
+ * @author aqute
+ * 
+ */
+public class Project extends Processor {
+
+    final static String         DEFAULT_ACTIONS = "build; label='Build', test; label='Test', clean; label='Clean', release; label='Release', refreshAll; label=Refresh";
+    public final static String  BNDFILE         = "bnd.bnd";
+    public final static String  BNDCNF          = "cnf";
+    final Workspace             workspace;
+    long                        time;
+    int                         count;
+    boolean                     preparedPaths;
+    final Collection<Project>   dependson       = new LinkedHashSet<Project>();
+    final Collection<Container> buildpath       = new LinkedHashSet<Container>();
+    final Collection<Container> runpath         = new LinkedHashSet<Container>();
+    final Collection<File>      sourcepath      = new LinkedHashSet<File>();
+    final Collection<File>      allsourcepath   = new LinkedHashSet<File>();
+    final Collection<Container> bootclasspath   = new LinkedHashSet<Container>();
+    final Collection<Container> runbundles      = new LinkedHashSet<Container>();
+    File                        output;
+    File                        target;
+    boolean                     inPrepare;
+
+    public Project(Workspace workspace, File projectDir, File buildFile)
+            throws Exception {
+        super(workspace);
+        this.workspace = workspace;
+        setFileMustExist(false);
+        setProperties(buildFile);
+        assert workspace != null;
+        // For backward compatibility reasons, we also read
+        readBuildProperties();
+    }
+
+    public Project(Workspace workspace, File buildDir) throws Exception {
+        this(workspace, buildDir, new File(buildDir, BNDFILE));
+    }
+
+    private void readBuildProperties() throws Exception {
+        try {
+            File f = getFile("build.properties");
+            if (f.isFile()) {
+                Properties p = loadProperties(f);
+                for (Enumeration<?> e = p.propertyNames(); e.hasMoreElements();) {
+                    String key = (String) e.nextElement();
+                    String newkey = key;
+                    if (key.indexOf('$') >= 0) {
+                        newkey = getReplacer().process(key);
+                    }
+                    setProperty(newkey, p.getProperty(key));
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static Project getUnparented(File propertiesFile) throws Exception {
+        propertiesFile = propertiesFile.getAbsoluteFile();
+        Workspace workspace = new Workspace(propertiesFile.getParentFile());
+        Project project = new Project(workspace, propertiesFile.getParentFile());
+        project.setProperties(propertiesFile);
+        project.setFileMustExist(true);
+        return project;
+    }
+
+    public synchronized boolean isValid() {
+        return getBase().isDirectory() && getPropertiesFile().isFile();
+    }
+
+    /**
+     * Return a new builder that is nicely setup for this project. Please close
+     * this builder after use.
+     * 
+     * @param parent
+     *            The project builder to use as parent, use this project if null
+     * @return
+     * @throws Exception
+     */
+    public synchronized ProjectBuilder getBuilder(ProjectBuilder parent)
+            throws Exception {
+
+        ProjectBuilder builder;
+
+        if (parent == null)
+            builder = new ProjectBuilder(this);
+        else
+            builder = new ProjectBuilder(parent);
+
+        builder.setBase(getBase());
+
+        for (Container file : getBuildpath()) {
+            builder.addClasspath(file.getFile());
+        }
+
+        for (Container file : getBootclasspath()) {
+            builder.addClasspath(file.getFile());
+        }
+
+        for (File file : getAllsourcepath()) {
+            builder.addSourcepath(file);
+        }
+        return builder;
+    }
+
+    public synchronized int getChanged() {
+        return count;
+    }
+
+    public synchronized void setChanged() {
+        // if (refresh()) {
+        preparedPaths = false;
+        count++;
+        // }
+    }
+
+    public Workspace getWorkspace() {
+        return workspace;
+    }
+
+    public String toString() {
+        return getBase().getName();
+    }
+
+    /**
+     * Set up all the paths
+     */
+
+    public synchronized void prepare() throws Exception {
+        if (inPrepare)
+            throw new CircularDependencyException(toString());
+        if (!preparedPaths) {
+            inPrepare = true;
+            try {
+                dependson.clear();
+                buildpath.clear();
+                sourcepath.clear();
+                allsourcepath.clear();
+                bootclasspath.clear();
+                runpath.clear();
+                runbundles.clear();
+
+                // We use a builder to construct all the properties for
+                // use.
+                setProperty("basedir", getBase().getAbsolutePath());
+
+                // If a bnd.bnd file exists, we read it.
+                // Otherwise, we just do the build properties.
+                if (!getPropertiesFile().isFile()
+                        && new File(getBase(), ".classpath").isFile()) {
+                    // Get our Eclipse info, we might depend on other projects
+                    // though ideally this should become empty and void
+                    doEclipseClasspath();
+                }
+
+                // Calculate our source directory
+
+                File src = new File(getBase(), getProperty("src", "src"));
+                if (src.isDirectory()) {
+                    sourcepath.add(src);
+                    allsourcepath.add(src);
+                } else
+                    sourcepath.add(getBase());
+
+                // Set default bin directory
+                output = getFile(getProperty("bin", "bin")).getAbsoluteFile();
+                if (output.isDirectory()) {
+                    if (!buildpath.contains(output))
+                        buildpath.add(new Container(this, output));
+                } else {
+                    if (!output.exists())
+                        output.mkdirs();
+                    if (!output.isDirectory())
+                        error("Can not find output directory: " + output);
+                }
+
+                // Where we store all our generated stuff.
+                target = getFile(getProperty("target", "generated"));
+
+                // We might have some other projects we want build
+                // before we do anything, but these projects are not in
+                // our path. The -dependson allows you to build them before.
+
+                List<Project> dependencies = new ArrayList<Project>();
+
+                String dp = getProperty(Constants.DEPENDSON);
+                Set<String> requiredProjectNames = parseHeader(dp).keySet();
+                for (String p : requiredProjectNames) {
+                    Project required = getWorkspace().getProject(p);
+                    if (required == null)
+                        error("No such project " + required + " on "
+                                + Constants.DEPENDSON);
+                    else {
+                        dependencies.add(required);
+                    }
+
+                }
+
+                // We have two paths that consists of repo files, projects,
+                // or some other stuff. The doPath routine adds them to the
+                // path and extracts the projects so we can build them before.
+
+                doPath(buildpath, dependencies, parseBuildpath(), bootclasspath);
+                doPath(runpath, dependencies, parseTestpath(), bootclasspath);
+                doPath(runbundles, dependencies, parseTestbundles(), null);
+
+                // We now know all dependend projects. But we also depend
+                // on whatever those projects depend on. This creates an
+                // ordered list without any duplicates. This of course assumes
+                // that there is no circularity. However, this is checked
+                // by the inPrepare flag, will throw an exception if we
+                // are circular.
+
+                Set<Project> done = new HashSet<Project>();
+                done.add(this);
+                allsourcepath.addAll(sourcepath);
+
+                for (Project project : dependencies)
+                    project.traverse(dependson, done);
+
+                for (Project project : dependson) {
+                    allsourcepath.addAll(project.getSourcepath());
+                }
+                if (isOk())
+                    preparedPaths = true;
+            } finally {
+                inPrepare = false;
+            }
+        }
+    }
+
+    private void traverse(Collection<Project> dependencies, Set<Project> visited)
+            throws Exception {
+        if (visited.contains(this))
+            return;
+
+        visited.add(this);
+
+        for (Project project : getDependson())
+            project.traverse(dependencies, visited);
+
+        dependencies.add(this);
+    }
+
+    /**
+     * Iterate over the entries and place the projects on the projects list and
+     * all the files of the entries on the resultpath.
+     * 
+     * @param resultpath
+     *            The list that gets all the files
+     * @param projects
+     *            The list that gets any projects that are entries
+     * @param entries
+     *            The input list of classpath entries
+     */
+    private void doPath(Collection<Container> resultpath,
+            Collection<Project> projects, Collection<Container> entries,
+            Collection<Container> bootclasspath) {
+        for (Container cpe : entries) {
+            if (cpe.getError() != null)
+                error(cpe.getError());
+            else {
+                if (cpe.getType() == Container.TYPE.PROJECT) {
+                    projects.add(cpe.getProject());
+                }
+                if (bootclasspath != null
+                        && cpe.getBundleSymbolicName().startsWith("ee.")
+                        || cpe.getAttributes().containsKey("boot"))
+                    bootclasspath.add(cpe);
+                else
+                    resultpath.add(cpe);
+            }
+        }
+    }
+
+    /**
+     * Parse the list of bundles that are a prerequisite to this project.
+     * 
+     * Bundles are listed in repo specific names. So we just let our repo
+     * plugins iterate over the list of bundles and we get the highest version
+     * from them.
+     * 
+     * @return
+     */
+
+    private List<Container> parseBuildpath() throws Exception {
+        return getBundles(Constants.STRATEGY_LOWEST,
+                getProperty(Constants.BUILDPATH));
+    }
+
+    private List<Container> parseTestpath() throws Exception {
+        return getBundles(Constants.STRATEGY_HIGHEST,
+                getProperty(Constants.RUNPATH));
+    }
+
+    private List<Container> parseTestbundles() throws Exception {
+        return getBundles(Constants.STRATEGY_HIGHEST,
+                getProperty(Constants.RUNBUNDLES));
+    }
+
+    /**
+     * Analyze the header and return a list of files that should be on the
+     * build, test or some other path. The list is assumed to be a list of bsns
+     * with a version specification. The special case of version=project
+     * indicates there is a project in the same workspace. The path to the
+     * output directory is calculated. The default directory ${bin} can be
+     * overridden with the output attribute.
+     * 
+     * @param strategy
+     *            STRATEGY_LOWEST or STRATEGY_HIGHEST
+     * @param spec
+     *            The header
+     * @return
+     */
+    public List<Container> getBundles(int strategy, String spec)
+            throws Exception {
+        List<Container> result = new ArrayList<Container>();
+        Map<String, Map<String, String>> bundles = parseHeader(spec);
+
+        try {
+            for (Iterator<Map.Entry<String, Map<String, String>>> i = bundles
+                    .entrySet().iterator(); i.hasNext();) {
+                Map.Entry<String, Map<String, String>> entry = i.next();
+                String bsn = entry.getKey();
+                Map<String, String> attrs = entry.getValue();
+
+                Container found = null;
+
+                String versionRange = attrs.get("version");
+
+                if (versionRange != null && versionRange.equals("project")) {
+                    Project project = getWorkspace().getProject(bsn);
+                    if (project.exists()) {
+                        File f = project.getOutput();
+                        found = new Container(project, bsn, "project",
+                                Container.TYPE.PROJECT, f, null, attrs);
+                    } else {
+                        error(
+                                "Reference to project that does not exist in workspace\n"
+                                        + "  Project       %s\n"
+                                        + "  Specification %s", bsn, spec);
+                        continue;
+                    }
+                } else if (versionRange != null && versionRange.equals("file")) {
+                    File f = getFile(bsn);
+                    String error = null;
+                    if (!f.exists())
+                        error = "File does not exist";
+                    if (f.getName().endsWith(".lib")) {
+                        found = new Container(this, bsn, "file",
+                                Container.TYPE.LIBRARY, f, error, attrs);
+                    } else {
+                        found = new Container(this, bsn, "file",
+                                Container.TYPE.EXTERNAL, f, error, attrs);
+                    }
+                } else {
+                    found = getBundle(bsn, versionRange, strategy, attrs);
+                }
+
+                if (found != null) {
+                    List<Container> libs = found.getMembers();
+                    for (Container cc : libs) {
+                        if (result.contains(cc))
+                            warning("Multiple bundles with the same final URL: "
+                                    + cc);
+
+                        result.add(cc);
+                    }
+                } else {
+                    // Oops, not a bundle in sight :-(
+                    Container x = new Container(this, bsn, versionRange,
+                            Container.TYPE.ERROR, null, bsn + ";version="
+                                    + versionRange + " not found", attrs);
+                    result.add(x);
+                    warning("Can not find URL for bsn " + bsn);
+                }
+            }
+        } catch (Exception e) {
+            error("While tring to get the bundles from " + spec, e);
+            e.printStackTrace();
+        }
+        return result;
+    }
+
+    public long getTime() {
+        return time;
+    }
+
+    public Collection<Project> getDependson() throws Exception {
+        prepare();
+        return dependson;
+    }
+
+    public Collection<Container> getBuildpath() throws Exception {
+        prepare();
+        return buildpath;
+    }
+
+    public Collection<Container> getRunpath() throws Exception {
+        prepare();
+        return runpath;
+    }
+
+    public Collection<Container> getRunbundles() throws Exception {
+        prepare();
+        return runbundles;
+    }
+
+    public Collection<File> getSourcepath() throws Exception {
+        prepare();
+        return sourcepath;
+    }
+
+    public Collection<File> getAllsourcepath() throws Exception {
+        prepare();
+        return allsourcepath;
+    }
+
+    public Collection<Container> getBootclasspath() throws Exception {
+        prepare();
+        return bootclasspath;
+    }
+
+    public File getOutput() throws Exception {
+        prepare();
+        return output;
+    }
+
+    private void doEclipseClasspath() throws Exception {
+        EclipseClasspath eclipse = new EclipseClasspath(this, getWorkspace()
+                .getBase(), getBase());
+        eclipse.setRecurse(false);
+
+        // We get the file directories but in this case we need
+        // to tell ant that the project names
+        for (File dependent : eclipse.getDependents()) {
+            Project required = workspace.getProject(dependent.getName());
+            dependson.add(required);
+        }
+        for (File f : eclipse.getClasspath()) {
+            buildpath.add(new Container(f));
+        }
+        for (File f : eclipse.getBootclasspath()) {
+            bootclasspath.add(new Container(f));
+        }
+        sourcepath.addAll(eclipse.getSourcepath());
+        allsourcepath.addAll(eclipse.getAllSources());
+        output = eclipse.getOutput();
+    }
+
+    public String _p_dependson(String args[]) throws Exception {
+        return list(args, toFiles(getDependson()));
+    }
+
+    private Collection<?> toFiles(Collection<Project> projects) {
+        List<File> files = new ArrayList<File>();
+        for (Project p : projects) {
+            files.add(p.getBase());
+        }
+        return files;
+    }
+
+    public String _p_buildpath(String args[]) throws Exception {
+        return list(args, getBuildpath());
+    }
+
+    public String _p_testpath(String args[]) throws Exception {
+        return list(args, getRunpath());
+    }
+
+    public String _p_sourcepath(String args[]) throws Exception {
+        return list(args, getSourcepath());
+    }
+
+    public String _p_allsourcepath(String args[]) throws Exception {
+        return list(args, getAllsourcepath());
+    }
+
+    public String _p_bootclasspath(String args[]) throws Exception {
+        return list(args, getBootclasspath());
+    }
+
+    public String _p_output(String args[]) throws Exception {
+        if (args.length != 1)
+            throw new IllegalArgumentException(
+                    "${output} should not have arguments");
+        return getOutput().getAbsolutePath();
+    }
+
+    private String list(String[] args, Collection<?> list) {
+        if (args.length > 3)
+            throw new IllegalArgumentException(
+                    "${"
+                            + args[0]
+                            + "[;<separator>]} can only take a separator as argument, has "
+                            + Arrays.toString(args));
+
+        String separator = ",";
+        if (args.length == 2) {
+            separator = args[1];
+        }
+
+        return join(list, separator);
+    }
+
+    protected Object[] getMacroDomains() {
+        return new Object[] { workspace };
+    }
+
+    public File release(Jar jar) throws Exception {
+    	String name = getProperty(Constants.RELEASEREPO);
+    	return release(name, jar);
+    }
+
+    /**
+     * Release
+     * @param name The repository name
+     * @param jar
+     * @return
+     * @throws Exception
+     */
+    public File release(String name, Jar jar) throws Exception {
+        List<RepositoryPlugin> plugins = getPlugins(RepositoryPlugin.class);
+        RepositoryPlugin rp = null;
+        for (RepositoryPlugin plugin : plugins) {
+        	if (!plugin.canWrite()) {
+        		continue;
+        	}
+            if (name == null) {
+        		rp = plugin;
+        		break;
+            } else if (name.equals(plugin.getName())){
+        		rp = plugin;
+        		break;
+            }
+        }
+
+        if (rp != null) {
+            try {
+                return rp.put(jar);
+            } catch (Exception e) {
+                error("Deploying " + jar.getName() + " on " + rp.getName(), e);
+            } finally {
+                jar.close();
+            }
+        }
+        return null;
+   	
+    }
+    
+    public void release(boolean test) throws Exception {
+    	String name = getProperty(Constants.RELEASEREPO);
+    	release(name, test);
+    }
+    
+    /**
+     * Release
+     * @param name The respository name
+     * @param test Run testcases
+     * @throws Exception
+     */
+    public void release(String name, boolean test) throws Exception {
+        File[] jars = build(test);
+        // If build fails jars will be null
+        if (jars == null) {
+        	return;
+        }
+        for (File jar : jars) {
+            Jar j = new Jar(jar);
+            release(name, j);
+            j.close();
+        }
+    	
+    }
+    
+    /**
+     * Get a bundle from one of the plugin repositories.
+     * 
+     * @param bsn
+     *            The bundle symbolic name
+     * @param range
+     *            The version range
+     * @param lowest
+     *            set to LOWEST or HIGHEST
+     * @return the file object that points to the bundle or null if not found
+     * @throws Exception
+     *             when something goes wrong
+     */
+    public Container getBundle(String bsn, String range, int strategy,
+            Map<String, String> attrs) throws Exception {
+        List<RepositoryPlugin> plugins = getPlugins(RepositoryPlugin.class);
+
+        // If someone really wants the latest, lets give it to them.
+        // regardless of they asked for a lowest strategy
+        if (range != null && range.equals("latest"))
+            strategy = STRATEGY_HIGHEST;
+
+        for (RepositoryPlugin plugin : plugins) {
+            File[] results = plugin.get(bsn, range);
+            if (results != null && results.length > 0) {
+                File f = results[strategy == STRATEGY_LOWEST ? 0
+                        : results.length - 1];
+
+                if (f.getName().endsWith("lib"))
+                    return new Container(this, bsn, range,
+                            Container.TYPE.LIBRARY, f, null, attrs);
+                else
+                    return new Container(this, bsn, range, Container.TYPE.REPO,
+                            f, null, attrs);
+            }
+        }
+
+        return new Container(this, bsn, range, Container.TYPE.ERROR, null, bsn
+                + ";version=" + range + " Not found in " + plugins, null);
+    }
+
+    /**
+     * Deploy the file (which must be a bundle) into the repository.
+     * 
+     * @param name The repository name
+     * @param file
+     *            bundle
+     */
+    public void deploy(String name, File file) throws Exception {
+        List<RepositoryPlugin> plugins = getPlugins(RepositoryPlugin.class);
+        RepositoryPlugin rp = null;
+        for (RepositoryPlugin plugin : plugins) {
+        	if (!plugin.canWrite()) {
+        		continue;
+        	}
+            if (name == null) {
+        		rp = plugin;
+        		break;
+            } else if (name.equals(plugin.getName())){
+        		rp = plugin;
+        		break;
+            }
+        }
+
+        if (rp != null) {
+            Jar jar = new Jar(file);
+            try {
+                rp.put(jar);
+                return;
+            } catch (Exception e) {
+                error("Deploying " + file + " on " + rp.getName(), e);
+            } finally {
+                jar.close();
+            }
+            return;
+        }
+        trace("No repo found " + file);
+        throw new IllegalArgumentException("No repository found for " + file);
+    }
+
+    /**
+     * Deploy the file (which must be a bundle) into the repository.
+     * 
+     * @param file
+     *            bundle
+     */
+    public void deploy(File file) throws Exception {
+    	String name = getProperty(Constants.DEPLOYREPO);
+    	deploy(name, file);
+    }
+    /**
+     * Macro access to the repository
+     * 
+     * ${repo;<bsn>[;<version>[;<low|high>]]}
+     */
+
+    public String _repo(String args[]) throws Exception {
+        if (args.length < 2)
+            throw new IllegalArgumentException(
+                    "Too few arguments for repo, syntax=: ${repo ';'<bsn> [ ; <version> ]}");
+
+        String bsns = args[1];
+        String version = null;
+        int strategy = Constants.STRATEGY_HIGHEST;
+
+        if (args.length > 2) {
+            version = args[2];
+            if (args.length == 4) {
+                if (args[3].equalsIgnoreCase("HIGHEST"))
+                    strategy = Constants.STRATEGY_HIGHEST;
+                else if (args[3].equalsIgnoreCase("LOWEST"))
+                    strategy = STRATEGY_LOWEST;
+                else
+                    error("${repo;<bsn>;<version>;<'highest'|'lowest'>} macro requires a strategy of 'highest' or 'lowest', and is "
+                            + args[3]);
+            }
+        }
+
+        Collection<String> parts = split(bsns);
+        List<String> paths = new ArrayList<String>();
+
+        for (String bsn : parts) {
+            Container jar = getBundle(bsn, version, strategy, null);
+            if (jar.getError() == null) {
+                paths.add(jar.getFile().getAbsolutePath());
+            } else {
+                error("The ${repo} macro could not find " + bsn
+                        + " in the repo, because " + jar.getError() + "\n"
+                        + "Repositories     : "
+                        + getPlugins(RepositoryPlugin.class) + "\n"
+                        + "Strategy         : " + strategy + "\n"
+                        + "Bsn              : " + bsn + ";version=" + version);
+            }
+        }
+        return join(paths);
+    }
+
+    public File getTarget() throws Exception {
+        prepare();
+        return target;
+    }
+
+    public File[] build(boolean underTest) throws Exception {
+        ProjectBuilder builder = getBuilder(null);
+        if (underTest)
+            builder.setProperty(Constants.UNDERTEST, "true");
+        Jar jars[] = builder.builds();
+        File files[] = new File[jars.length];
+
+        File target = getTarget();
+        target.mkdirs();
+
+        for (int i = 0; i < jars.length; i++) {
+            Jar jar = jars[i];
+            try {
+                String bsn = jar.getName();
+                files[i] = new File(target, bsn + ".jar");
+                String msg = "";
+                if (!files[i].exists()
+                        || files[i].lastModified() < jar.lastModified()) {
+                    reportNewer(files[i].lastModified(), jar);
+                    files[i].delete();
+                    jar.write(files[i]);
+                } else {
+                    msg = "(not modified since "
+                            + new Date(files[i].lastModified()) + ")";
+                }
+                trace(jar.getName() + " (" + files[i].getName() + ") "
+                        + jar.getResources().size() + " " + msg);
+            } finally {
+                jar.close();
+            }
+        }
+        getInfo(builder);
+        builder.close();
+        if (isOk())
+            return files;
+        else
+            return null;
+    }
+
+    private void reportNewer(long lastModified, Jar jar) {
+        if (isTrue(getProperty(Constants.REPORTNEWER))) {
+            StringBuilder sb = new StringBuilder();
+            String del = "Newer than " + new Date(lastModified);
+            for (Map.Entry<String, Resource> entry : jar.getResources()
+                    .entrySet()) {
+                if (entry.getValue().lastModified() > lastModified) {
+                    sb.append(del);
+                    del = ", \n     ";
+                    sb.append(entry.getKey());
+                }
+            }
+            if (sb.length() > 0)
+                warning(sb.toString());
+        }
+    }
+
+    /**
+     * Refresh if we are based on stale data. This also implies our workspace.
+     */
+    public boolean refresh() {
+        boolean changed = false;
+        if (isCnf()) {
+            changed = workspace.refresh();
+        }
+        return super.refresh() || changed;
+    }
+
+    public boolean isCnf() {
+        return getBase().getName().equals(Workspace.CNFDIR);
+    }
+
+    public void propertiesChanged() {
+        super.propertiesChanged();
+        preparedPaths = false;
+    }
+
+    public String getName() {
+        return getBase().getName();
+    }
+
+    public Map<String, Action> getActions() {
+        Map<String, Action> all = newMap();
+        Map<String, Action> actions = newMap();
+        fillActions(all);
+        getWorkspace().fillActions(all);
+
+        for (Map.Entry<String, Action> action : all.entrySet()) {
+            String key = getReplacer().process(action.getKey());
+            if (key != null && key.trim().length() != 0)
+                actions.put(key, action.getValue());
+        }
+        return actions;
+    }
+
+    public void fillActions(Map<String, Action> all) {
+        Map<String, Map<String, String>> actions = parseHeader(getProperty(
+                "-actions", DEFAULT_ACTIONS));
+        for (Map.Entry<String, Map<String, String>> entry : actions.entrySet()) {
+            String key = Processor.removeDuplicateMarker(entry.getKey());
+            Action action;
+
+            if (entry.getValue().get("script") != null) {
+                // TODO check for the type
+                action = new ScriptAction(entry.getValue().get("type"), entry
+                        .getValue().get("script"));
+            } else {
+                action = new ReflectAction(key);
+            }
+            String label = entry.getValue().get("label");
+            all.put(label, action);
+        }
+    }
+
+    public void release() throws Exception {
+        release(false);
+    }
+
+    /**
+     * Release.
+     * @param name The repository name
+     * @throws Exception
+     */
+    public void release(String name) throws Exception {
+        release(name, false);
+    }
+
+    public void clean() throws Exception {
+        File target = getTarget();
+        if (target.isDirectory() && target.getParentFile() != null) {
+            delete(target);
+        }
+    }
+
+    public File[] build() throws Exception {
+        return build(false);
+    }
+
+    public boolean test() throws Exception {
+        boolean ok = true;
+        String testbundles = getProperty(TESTBUNDLES);
+
+        if (testbundles == null) {
+            File jars[] = build(true);
+            for (File jar : jars)
+                ok &= test(jar);
+
+        } else {
+            List<Container> containers = getBundles(STRATEGY_HIGHEST,
+                    testbundles);
+            for (Container container : containers) {
+                if (container.getError() == null) {
+                    File jar = container.getFile();
+                    ok &= test(jar);
+                } else
+                    error(container.getError());
+            }
+        }
+        return ok;
+    }
+
+    public boolean test(File f) throws Exception {
+        ProjectLauncher pl = new ProjectLauncher(this);
+        pl.setReport(getProperty("target") + "/" + f.getName().replace(".jar", ".xml"));
+        int errors = pl.run(f);
+        getInfo(pl);
+        if (errors == 0) {
+            trace("ok");
+            return true;
+        } else {
+            error("Failed: " + normalize(f) + ", " + errors + " test"
+                    + (errors > 1 ? "s" : "") + " failures, see "
+                    + normalize(pl.getTestreport()));
+            return false;
+        }
+    }
+
+    private void delete(File target) {
+        if (target.getParentFile() == null)
+            throw new IllegalArgumentException("Can not delete root!");
+        if (!target.exists())
+            return;
+
+        if (target.isDirectory()) {
+            File sub[] = target.listFiles();
+            for (File s : sub)
+                delete(s);
+        }
+        target.delete();
+    }
+
+    /**
+     * This methods attempts to turn any jar into a valid jar. If this is a
+     * bundle with manifest, a manifest is added based on defaults. If it is a
+     * bundle, but not r4, we try to add the r4 headers.
+     * 
+     * @param name
+     * @param in
+     * @return
+     * @throws Exception
+     */
+    public Jar getValidJar(File f) throws Exception {
+        Jar jar = new Jar(f);
+        Manifest manifest = jar.getManifest();
+        if (manifest == null) {
+            trace("Wrapping with all defaults");
+            Builder b = new Builder(this);
+            b.addClasspath(jar);
+            b.setProperty("Bnd-Message", "Wrapped from " + f.getAbsolutePath()
+                    + "because lacked manifest");
+            b.setProperty(Constants.EXPORT_PACKAGE, "*");
+            b.setProperty(Constants.IMPORT_PACKAGE, "*;resolution:=optional");
+            jar = b.build();
+        } else if (manifest.getMainAttributes().getValue(
+                Constants.BUNDLE_MANIFESTVERSION) == null) {
+            trace("Not a release 4 bundle, wrapping with manifest as source");
+            Builder b = new Builder(this);
+            b.addClasspath(jar);
+            b.setProperty(Constants.PRIVATE_PACKAGE, "*");
+            b.mergeManifest(manifest);
+            String imprts = manifest.getMainAttributes().getValue(
+                    Constants.IMPORT_PACKAGE);
+            if (imprts == null)
+                imprts = "";
+            else
+                imprts += ",";
+            imprts += "*;resolution=optional";
+
+            b.setProperty(Constants.IMPORT_PACKAGE, imprts);
+            b.setProperty("Bnd-Message", "Wrapped from " + f.getAbsolutePath()
+                    + "because had incomplete manifest");
+            jar = b.build();
+        }
+        return jar;
+    }
+
+    public String _project(String args[]) {
+        return getBase().getAbsolutePath();
+    }
+
+    public void bump(String mask) throws IOException {
+        Sed sed = new Sed(getReplacer(), getPropertiesFile());
+        sed
+                .replace(
+                        "(Bundle-Version\\s*(:|=)\\s*)(([0-9]+(\\.[0-9]+(\\.[0-9]+)?)?))",
+                        "$1${version;" + mask + ";$3}");
+        sed.doIt();
+        refresh();
+    }
+
+    public void bump() throws IOException {
+        bump(getProperty(BUMPPOLICY, "=+0"));
+    }
+
+    public void action(String command) throws Exception {
+        Action a = new ReflectAction(command);
+        a.execute(this, command);
+    }
+
+    public String _findfile(String args[]) {
+        File f = getFile(args[1]);
+        List<String> files = new ArrayList<String>();
+        tree(files, f, "", Instruction.getPattern(args[2]));
+        return join(files);
+    }
+
+    void tree(List<String> list, File current, String path, Instruction instr) {
+        if (path.length() > 0)
+            path = path + "/";
+
+        String subs[] = current.list();
+        for (String sub : subs) {
+            File f = new File(current, sub);
+            if (f.isFile()) {
+                if (instr.matches(sub) && !instr.isNegated())
+                    list.add(path + sub);
+            } else
+                tree(list, f, path + sub, instr);
+        }
+    }
+
+    public void refreshAll() {
+        workspace.refresh();
+        refresh();
+    }
+
+    @SuppressWarnings("unchecked")
+    public void script(String type, String script) throws Exception {
+        // TODO check tyiping
+        List<Scripter> scripters = getPlugins(Scripter.class);
+        if (scripters.isEmpty()) {
+            error(
+                    "Can not execute script because there are no scripters registered: %s",
+                    script);
+            return;
+        }
+        Map x = (Map) getProperties();
+        scripters.get(0)
+                .eval((Map<String, Object>) x, new StringReader(script));
+    }
+    
+    public String _repos(String args[]) throws Exception {
+        List<RepositoryPlugin> repos = getPlugins(RepositoryPlugin.class);
+        List<String> names = new ArrayList<String>();
+        for ( RepositoryPlugin rp : repos )
+            names.add(rp.getName());
+        return join(names,", ");        
+    }
+    
+    public String _help(String args[]) throws Exception {
+        if ( args.length == 1)
+            return "Specify the option or header you want information for";
+        
+        Syntax syntax = Syntax.HELP.get(args[1]);
+        if  (syntax == null )
+            return "No help for " + args[1];
+        
+        String what = null;
+        if ( args.length> 2)
+            what = args[2];
+     
+        if ( what == null || what.equals("lead"))
+            return syntax.getLead();
+        if ( what == null || what.equals("example"))
+            return syntax.getExample();
+        if ( what == null || what.equals("pattern"))
+            return syntax.getPattern();
+        if ( what == null || what.equals("values"))
+            return syntax.getValues();
+        
+        return "Invalid type specified for help: lead, example, pattern, values";
+    }
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/Project.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/ProjectBuilder.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/ProjectBuilder.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/ProjectBuilder.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/ProjectBuilder.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,34 @@
+package aQute.bnd.build;
+
+import aQute.lib.osgi.*;
+
+@SuppressWarnings("unchecked")
+public class ProjectBuilder extends Builder {
+    Project project;
+
+    public ProjectBuilder(Project project) {
+        super(project);
+        this.project = project;
+    }
+
+    public ProjectBuilder(ProjectBuilder builder) {
+        super(builder);
+        this.project = builder.project;
+    }
+
+
+    /** 
+     * We put our project and our workspace on the macro path.
+     */
+    protected Object [] getMacroDomains() {
+        return new Object[] {project, project.getWorkspace()};
+    }
+
+    public Builder getSubBuilder() throws Exception {
+        return project.getBuilder(this);
+    }
+
+    public Project getProject() {
+        return project;
+    }
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/ProjectBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/ReflectAction.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/ReflectAction.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/ReflectAction.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/ReflectAction.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,22 @@
+package aQute.bnd.build;
+
+import java.lang.reflect.*;
+
+import aQute.bnd.service.action.*;
+
+public class ReflectAction implements Action {
+    String  what;
+    
+    public ReflectAction(String what) {
+        this.what = what;
+    }
+    
+    public void execute(Project project, String action) throws Exception {
+        Method m = project.getClass().getMethod(what);
+        m.invoke(project);
+    }
+
+    public String toString() {
+        return "ra:" + what;
+    }
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/ReflectAction.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/ScriptAction.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/ScriptAction.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/ScriptAction.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/ScriptAction.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,18 @@
+package aQute.bnd.build;
+
+import aQute.bnd.service.action.*;
+
+public class ScriptAction implements Action {
+    final String script;
+    final String type;
+    
+    public ScriptAction(String type, String script) {
+        this.script = script;
+        this.type = type;
+    }
+
+    public void execute(Project project, String action) throws Exception {
+        project.script(type, script);
+    }
+
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/ScriptAction.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/Workspace.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/Workspace.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/Workspace.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/Workspace.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,109 @@
+package aQute.bnd.build;
+
+import java.io.*;
+import java.lang.ref.*;
+import java.util.*;
+
+import aQute.bnd.service.action.*;
+import aQute.lib.osgi.*;
+
+public class Workspace extends Processor {
+    public final static int                    STRATEGY_HIGHEST = 1;
+    public final static int                    STRATEGY_EXACT   = 0;
+    public final static int                    STRATEGY_LOWEST  = -1;
+    public static final String                 BUILDFILE        = "build.bnd";
+    public static final String                 CNFDIR           = "cnf";
+
+    static Map<File, WeakReference<Workspace>> cache            = newHashMap();
+    final Map<String, Project>                 models           = newHashMap();
+    final Map<String, Action>                  commands         = newMap();
+
+    /**
+     * This static method finds the workspace and creates a project (or returns
+     * an existing project)
+     * 
+     * @param projectDir
+     * @return
+     */
+    public static Project getProject(File projectDir) throws Exception {
+        projectDir = projectDir.getAbsoluteFile();
+        assert projectDir.isDirectory();
+
+        Workspace ws = getWorkspace(projectDir.getParentFile());
+        return ws.getProject(projectDir.getName());
+    }
+
+    public static Workspace getWorkspace(File workspaceDir) throws Exception {
+        workspaceDir = workspaceDir.getAbsoluteFile();
+        synchronized (cache) {
+            WeakReference<Workspace> wsr = cache.get(workspaceDir);
+            Workspace ws;
+            if (wsr == null || (ws = wsr.get()) == null) {
+                ws = new Workspace(workspaceDir);
+                cache.put(workspaceDir, new WeakReference<Workspace>(ws));
+            }
+            return ws;
+        }
+    }
+
+    public Workspace(File dir) throws Exception {
+        dir = dir.getAbsoluteFile();
+        dir.mkdirs();
+        assert dir.isDirectory();
+
+        File buildDir = new File(dir, CNFDIR).getAbsoluteFile();
+        File buildFile = new File(buildDir, BUILDFILE).getAbsoluteFile();
+        if (!buildFile.isFile())
+            warning("No Build File in " + dir);
+        setProperties(buildFile, dir);
+    }
+
+    public Project getProject(String bsn) throws Exception {
+        synchronized (models) {
+            Project project = models.get(bsn);
+            if (project != null)
+                return project;
+
+            File projectDir = getFile(bsn);
+            project = new Project(this, projectDir);
+            models.put(bsn, project);
+            return project;
+        }
+    }
+
+    public boolean isPresent(String name) {
+        return models.containsKey(name);
+    }
+
+    public Collection<Project> getCurrentProjects() {
+        return models.values();
+    }
+
+    public boolean refresh() {
+        if (super.refresh()) {
+            for (Project project : getCurrentProjects()) {
+                project.propertiesChanged();
+            }
+            return true;
+        }
+        return false;
+    }
+
+    public String _workspace(String args[]) {
+        return getBase().getAbsolutePath();
+    }
+
+    public void addCommand(String menu, Action action) {
+        commands.put(menu, action);
+    }
+
+    public void removeCommand(String menu) {
+        commands.remove(menu);
+    }
+
+    public void fillActions(Map<String, Action> all) {
+        all.putAll(commands);
+    }
+    
+    
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/build/Workspace.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/help/Syntax.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/help/Syntax.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/help/Syntax.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/help/Syntax.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,482 @@
+package aQute.bnd.help;
+
+import java.util.*;
+import java.util.regex.*;
+
+import aQute.lib.osgi.*;
+
+public class Syntax implements Constants {
+    final String                            header;
+    final String                            lead;
+    final String                            example;
+    final Pattern                           pattern;
+    final String                            values;
+    final Syntax[]                          children;
+
+    static Syntax                           version              = new Syntax(
+                                                                         VERSION_ATTRIBUTE,
+                                                                         "A version range to select the version of an export definition. The default value is 0.0.0 .",
+                                                                         "version=\"[1.2,3.0)\"",
+                                                                         null,
+                                                                         Verifier.VERSIONRANGE);
+    static Syntax                           bundle_symbolic_name = new Syntax(
+                                                                         BUNDLE_SYMBOLIC_NAME_ATTRIBUTE,
+                                                                         "The bundle symbolic name of the exporting bundle.",
+                                                                         "bundle-symbolic-name=com.acme.foo.daffy",
+                                                                         null,
+                                                                         Verifier.SYMBOLICNAME);
+
+    static Syntax                           bundle_version       = new Syntax(
+                                                                         BUNDLE_VERSION_ATTRIBUTE,
+                                                                         "a version range to select the bundle version of the exporting bundle. The default value is 0.0.0.",
+                                                                         "bundle-version=1.3",
+                                                                         null,
+                                                                         Verifier.VERSIONRANGE);
+
+    static Syntax                           path_version         = new Syntax(
+                                                                         VERSION_ATTRIBUTE,
+                                                                         "Specifies the range in the repository, project, or file",
+                                                                         "version=project",
+                                                                         "project,type",
+                                                                         Pattern
+                                                                                 .compile("project|type|"
+                                                                                         + Verifier.VERSIONRANGE
+                                                                                                 .toString()));
+
+    static Syntax[]                         syntaxes             = new Syntax[] {
+            new Syntax(
+                    BUNDLE_ACTIVATION_POLICY,
+                    "The Bundle-ActivationPolicy specifies how the framework should activate the bundle once started. ",
+                    "Bundle-ActivationPolicy: lazy", "lazy", Pattern
+                            .compile("lazy")),
+
+            new Syntax(
+                    BUNDLE_ACTIVATOR,
+                    "The Bundle-Activator header specifies the name of the class used to start and stop the bundle. ",
+                    "Bundle-Activator: com.acme.foo.Activator",
+                    "${classes;implementing;org.osgi.framework.BundleActivator}",
+                    Verifier.FQNPATTERN),
+            new Syntax(
+                    BUNDLE_CATEGORY,
+                    "The Bundle-Category header holds a comma-separated list of category names",
+                    "Bundle-Category: test",
+                    "osgi,test,game,util,eclipse,netbeans,jdk,specification",
+                    null),
+            new Syntax(
+                    BUNDLE_CLASSPATH,
+                    "The Bundle-ClassPath header defines a comma-separated list of JAR file path names or directories (inside the bundle) containing classes and resources. The period (’.’) specifies the root directory of the bundle’s JAR. The period is also the default.",
+                    "Bundle-Classpath: /lib/libnewgen.so, .", null,
+                    Verifier.PATHPATTERN),
+            new Syntax(
+                    BUNDLE_CONTACTADDRESS,
+                    "The Bundle-ContactAddress header provides the contact address of the vendor. ",
+                    "Bundle-ContactAddress: 2400 Oswego Road, Austin, TX 74563",
+                    null, null),
+            new Syntax(
+                    BUNDLE_COPYRIGHT,
+                    "The Bundle-Copyright header contains the copyright specification for this bundle. ",
+                    "Bundle-Copyright: OSGi (c) 2002", null, null),
+            new Syntax(
+                    BUNDLE_DESCRIPTION,
+                    "The Bundle-Description header defines a short description of this bundle.",
+                    "Bundle-Description: Ceci ce n'est pas une bundle", null,
+                    null),
+
+            new Syntax(
+                    BUNDLE_DOCURL,
+                    "The Bundle-DocURL headers must contain a URL pointing to documentation about this bundle.",
+                    "Bundle-DocURL: http://www.aQute.biz/Code/Bnd", null,
+                    Verifier.URLPATTERN),
+
+            new Syntax(
+                    BUNDLE_ICON,
+                    "The optional Bundle-Icon header provides a list of (relative) URLs to icons representing this bundle in different sizes. ",
+                    "Bundle-Icon: /icons/bnd.png;size=64", "/icons/bundle.png",
+                    Verifier.URLPATTERN, new Syntax("size",
+                            "Icons size in pixels, e.g. 64", "64",
+                            "16,32,48,64,128", Verifier.NUMBERPATTERN)),
+
+            new Syntax(
+                    BUNDLE_LICENSE,
+                    "The Bundle-License header provides an optional machine readable form of license information. The purpose of this header is to automate some of the license processing required by many organizations",
+                    "Bundle License: http://www.opensource.org/licenses/jabberpl.php",
+                    "http://www.apache.org/licenses/LICENSE-2.0,<<EXTERNAL>>",
+                    Pattern.compile("(" + Verifier.URLPATTERN
+                            + "|<<EXTERNAL>>)"), new Syntax(
+                            DESCRIPTION_ATTRIBUTE,
+                            "Human readable description of the license",
+                            "description=\"Described the license here\"", null,
+                            Verifier.ANYPATTERN), new Syntax(LINK_ATTRIBUTE,
+                            "", "", null, Verifier.URLPATTERN)),
+            new Syntax(
+                    BUNDLE_LOCALIZATION,
+                    "The Bundle-Localization header contains the location in the bundle where localization files can be found. The default value is OSGI-INF/l10n/bundle. Translations are by default therefore OSGI-INF/l10n/bundle_de.properties, OSGI-INF/l10n/bundle_nl.properties, etc.",
+                    "Bundle-Localization: OSGI-INF/l10n/bundle",
+                    "OSGI-INF/l10n/bundle", Verifier.URLPATTERN),
+            new Syntax(
+                    BUNDLE_MANIFESTVERSION,
+                    "This header is set by bnd automatically to 2. The Bundle-ManifestVersion header defines that the bundle follows the rules of this specification. The Bundle-ManifestVersion header determines whether the bundle follows the rules of this specification.",
+                    "# Bundle-ManifestVersion: 2", "2", Verifier.NUMBERPATTERN),
+            new Syntax(
+                    BUNDLE_NAME,
+                    "This header will be derived from the  Bundle-SymbolicName if not set. The Bundle-Name header defines a readable name for this bundle. This should be a short, human-readable name that can contain spaces.",
+                    "Bundle-Name: My Bundle", null, Verifier.ANYPATTERN),
+            new Syntax(
+                    BUNDLE_NATIVECODE,
+                    "The Bundle-NativeCode header contains a specification of native code libraries contained in this bundle. ",
+                    "Bundle-NativeCode: /lib/http.DLL; osname = QNX; osversion = 3.1",
+                    null,
+                    Verifier.PATHPATTERN,
+                    new Syntax(OSNAME_ATTRIBUTE,
+                            "The name of the operating system", "osname=MacOS",
+                            Processor.join(Verifier.OSNAMES, ","),
+                            Verifier.ANYPATTERN),
+                    new Syntax(OSVERSION_ATTRIBUTE, "Operating System Version",
+                            "osversion=3.1", null, Verifier.ANYPATTERN),
+                    new Syntax(LANGUAGE_ATTRIBUTE, "Language ISO 639 code",
+                            "language=nl", null, Verifier.ISO639),
+                    new Syntax(PROCESSOR_ATTRIBUTE, "Processor name",
+                            "processor=x86", Processor.join(
+                                    Verifier.PROCESSORNAMES, ","),
+                            Verifier.ANYPATTERN),
+                    new Syntax(
+                            SELECTION_FILTER_ATTRIBUTE,
+                            "The value of this attribute must be a filter expression that indicates if the native code clause should be selected or not.",
+                            "selection-filter=\"(com.acme.windowing=win32)\"",
+                            null, Verifier.FILTERPATTERN)),
+            new Syntax(
+                    BUNDLE_REQUIREDEXECUTIONENVIRONMENT,
+                    "The Bundle-RequiredExecutionEnvironment contains a comma-separated list of execution environments that must be present on the Service Platform.",
+                    "Bundle-RequiredExecutionEnvironment: CDC-1.0/Foundation-1.0",
+                    Processor.join(Verifier.EES, ","), Verifier.ANYPATTERN),
+
+            new Syntax(
+                    BUNDLE_SYMBOLICNAME,
+                    "The Bundle-SymbolicName header specifies a non-localizable name for this bundle. The bundle symbolic name together with a version must identify a  unique bundle. The bundle symbolic name should be based on the reverse  domain name convention",
+                    "Bundle-SymbolicName: com.acme.foo.daffy;singleton:=true",
+                    "${p}",
+                    Verifier.SYMBOLICNAME,
+                    new Syntax(
+                            SINGLETON_DIRECTIVE,
+                            " Indicates that the bundle can only have  a single version resolved.  A value of true indicates that the bundle is a singleton bundle. The default value is false. The Framework must resolve at most one  bundle when multiple versions of a singleton bundle with the same symbolic name are installed. Singleton bundles do not affect the resolution of non-singleton bundles with the same symbolic name.",
+                            "false", "true,false", Verifier.TRUEORFALSEPATTERN),
+                    new Syntax(
+                            FRAGMENT_ATTACHMENT_DIRECTIVE,
+                            "Defines how fragments are allowed to be attached, see the fragments in Fragment Bundles on page73. The following values are valid for this directive:",
+                            "", "always|never|resolve-time", Pattern
+                                    .compile("always|never|resolve-time")),
+                    new Syntax(BLUEPRINT_WAIT_FOR_DEPENDENCIES_ATTRIBUTE, "",
+                            "", "true,false", Verifier.TRUEORFALSEPATTERN),
+                    new Syntax(BLUEPRINT_TIMEOUT_ATTRIBUTE, "", "",
+                            "30000,60000,300000", Verifier.NUMBERPATTERN)),
+
+            new Syntax(
+                    BUNDLE_UPDATELOCATION,
+                    "The Bundle-UpdateLocation header specifies a URL where an update for this bundle should come from. If the bundle is updated, this location should be used, if present, to retrieve the updated JAR file.",
+                    "Bundle-UpdateLocation: http://www.acme.com/Firewall/bundle.jar",
+                    null, Verifier.URLPATTERN),
+
+            new Syntax(
+                    BUNDLE_VENDOR,
+                    "The Bundle-Vendor header contains a human-readable description of the bundle vendor. ",
+                    "Bundle-Vendor: OSGi Alliance ", null, null),
+
+            new Syntax(
+                    BUNDLE_VERSION,
+                    "The Bundle-Version header specifies the version of this bundle",
+                    "Bundle-Version: 1.23.4.build200903221000", null,
+                    Verifier.VERSION),
+
+            new Syntax(
+                    DYNAMICIMPORT_PACKAGE,
+                    "The DynamicImport-Package header contains a comma-separated list of package names that should be dynamically imported when needed.",
+                    "DynamicImport-Package: com.acme.plugin.*", "",
+                    Verifier.WILDCARDNAMEPATTERN, version,
+                    bundle_symbolic_name, bundle_version),
+
+            new Syntax(
+                    EXPORT_PACKAGE,
+                    "The Export-Package header contains a declaration of exported packages.",
+                    "Export-Package: org.osgi.util.tracker;version=1.3",
+                    "${packages}",
+                    null,
+                    new Syntax(
+                            NO_IMPORT_DIRECTIVE,
+                            "By default, bnd makes all exports also imports. Adding a -noimport to an exported package will make it export only",
+                            "-noimport:=true", "true,false",
+                            Verifier.TRUEORFALSEPATTERN),
+                    new Syntax(
+                            USES_DIRECTIVE,
+                            "Calculated by bnd: It is a comma-separated list of package names that are used by the exported package",
+                            "Is calculated by bnd", null, null),
+                    new Syntax(
+                            MANDATORY_DIRECTIVE,
+                            "A comma-separated list of attribute names. Note that the use of a comma in the value requires it to be enclosed in double quotes. A bundle importing the package must specify the mandatory attributes, with a value that matches, to resolve to the exported package",
+                            "mandatory=\"bar,foo\"", null, null),
+                    new Syntax(
+                            INCLUDE_DIRECTIVE,
+                            "A comma-separated list of class names that must be visible to an importer",
+                            "include:=\"Qux*\"", null, null),
+                    new Syntax(
+                            EXCLUDE_DIRECTIVE,
+                            "A comma-separated list of class names that must not be visible to an importer",
+                            "exclude:=\"QuxImpl*,BarImpl\"", null,
+                            Verifier.WILDCARDNAMEPATTERN), new Syntax(
+                            IMPORT_DIRECTIVE, "Experimental", "", null, null)
+
+            ),
+            new Syntax(EXPORT_SERVICE, "Deprecated",
+                    "Export-Service: org.osgi.service.log.LogService ",
+                    "${classes;implementing;*}", null),
+            new Syntax(
+                    FRAGMENT_HOST,
+                    "The Fragment-Host header defines the host bundle for this fragment.",
+                    "Fragment-Host: org.eclipse.swt; bundle-version=\"[3.0.0,4.0.0)\"",
+                    null,
+                    null,
+                    new Syntax(
+                            EXTENSION_DIRECTIVE,
+                            " Indicates this extension is a system or boot class path extension. It is only applicable when the Fragment-Host is the System Bundle",
+                            "extension:=framework", "framework,bootclasspath",
+                            Pattern.compile("framework|bootclasspath")),
+                    bundle_version),
+            new Syntax(
+                    IMPORT_PACKAGE,
+                    "This header is normally calculated by bnd, however, you can decorate packages or skip packages. The Import-Package header declares the imported packages for this bundle",
+                    "Import-Package: !com.exotic.*, com.acme.foo;vendor=ACME, *",
+                    "${exported_packages}",
+                    Verifier.WILDCARDNAMEPATTERN,
+                    new Syntax(
+                            REMOVE_ATTRIBUTE_DIRECTIVE,
+                            "Remove the given attributes from matching imported packages",
+                            "-remove-attribute:=foo.*", null,
+                            Verifier.WILDCARDNAMEPATTERN),
+                    new Syntax(
+                            RESOLUTION_DIRECTIVE,
+                            "Indicates that the packages must be resolved if the value is mandatory, which is the default. If mandatory packages cannot be resolved, then the bundle must fail to resolve. A value of optional indicates that the packages are optional",
+                            "resolution:=optional", "mandatory,optional",
+                            Pattern.compile("mandatory|optional")
+
+                    ), version, bundle_symbolic_name, bundle_version),
+
+            new Syntax(
+                    REQUIRE_BUNDLE,
+                    "The Require-Bundle header specifies the required exports from another bundle.",
+                    "Require-Bundle: com.acme.chess",
+                    null,
+                    Verifier.WILDCARDNAMEPATTERN,
+
+                    new Syntax(
+                            VISIBILITY_DIRECTIVE,
+                            " If the value is private (Default), then all visible packages from the required bundles are not re-exported. If the value is reexport then bundles that require this bundle will transitively have access to these required bundle’s exported packages.",
+                            "visibility:=private", "private,reexport", Pattern
+                                    .compile("private|reexport")),
+
+                    new Syntax(
+                            RESOLUTION_DIRECTIVE,
+                            "If the value is mandatory (default) then the required bundle must exist for this bundle to resolve. If the value is optional, the bundle will resolve even if the required bundle does not exist.",
+                            "resolution:=optional", "mandatory,optional",
+                            Pattern.compile("mandatory|optional")),
+
+                    new Syntax(
+                            SPLIT_PACKAGE_DIRECTIVE,
+                            "Indicates how an imported package should be merged when it is split between different exporters. The default is merge-first with warning",
+                            "-split-package:=merge-first",
+                            "merge-first,merge-last,error,first",
+                            Pattern
+                                    .compile("merge-first|merge-last|error|first")),
+                    bundle_version
+
+            ),
+
+            new Syntax(
+                    BUILDPATH,
+                    "Provides the class path for building the jar. The entries are references to the repository",
+                    "-buildpath=osgi;version=4.1", "${repo;bsns}",
+                    Verifier.SYMBOLICNAME, path_version),
+            new Syntax(
+                    BUMPPOLICY,
+                    "Sets the version bump policy. This is a parameter to the ${version} macro.",
+                    "-bumppolicy==+0", "==+,=+0,+00", Pattern
+                            .compile("[=+-0][=+-0][=+-0]")),
+
+            new Syntax(
+                    CONDUIT,
+                    "Allows a bnd file to point to files which will be returned when the bnd file is build",
+                    "-conduit= jar/osgi.jar", null, null),
+
+            new Syntax(
+                    DEPENDSON,
+                    "List of project names that this project directly depends on. These projects are always build ahead of this project",
+                    "-dependson=org.acme.cm", "${projects}", null),
+
+            new Syntax(DEPLOYREPO,
+                    "Specifies to which repo the project should be deployed.",
+                    "-deployrepo=cnf", "${repos}", null),
+
+            new Syntax(
+                    DONOTCOPY,
+                    "Regular expression for names of files and directories that should not be copied when discovered",
+                    "-donotcopy=(CVS|\\.svn)", null, null),
+
+            new Syntax(
+                    EXPORT_CONTENTS,
+                    "Build the JAR in the normal way but use this header for the Export-Package header manifest generation, same format",
+                    "-exportcontents=!*impl*,*;version=3.0", null, null),
+
+            new Syntax(
+                    FAIL_OK,
+                    "Return with an ok status (0) even if the build generates errors",
+                    "-failok=true", "true,false", Verifier.TRUEORFALSEPATTERN),
+
+            new Syntax(
+                    INCLUDE,
+                    "Include files. If an entry starts with '-', it does not have to exist. If it starts with '~', it must not overwrite any existing properties",
+                    "-include: -${java.user}/.bnd", null, null),
+
+            new Syntax(
+                    INCLUDERESOURCE,
+                    "Include resources from the file system. You can specify a directory, or file. All files are copied to the root, unless a destination directory is indicated",
+                    "-includeresource: lib=jar", null, null),
+
+            new Syntax(
+                    MAKE,
+                    "Set patterns for make plugins. These patterns are used to find a plugin that can make a resource that can not be found.",
+                    "-make: (*).jar;type=bnd;  recipe=\"bnd/$1.bnd\"", null,
+                    null, new Syntax("type", "Type name for plugin",
+                            "type=bnd", "bnd", null), new Syntax("recipe",
+                            "Recipe for the plugin, can use back references",
+                            "recipe=\"bnd/$1.bnd\"", "bnd", null)),
+
+            new Syntax(
+                    MANIFEST,
+                    "Directly include a manifest, do not use the calculated manifest",
+                    "-manifest = META-INF/MANIFEST.MF", null, null),
+
+            new Syntax(NOEXTRAHEADERS, "Do not generate housekeeping headers",
+                    "-noextraheaders", "true,false",
+                    Verifier.TRUEORFALSEPATTERN),
+
+            new Syntax(NOUSES,
+                    "Do not calculate the uses: directive on exports",
+                    "-nouses=true", "true,false", Verifier.TRUEORFALSEPATTERN),
+
+            new Syntax(NOPE,
+                    "Dont do anything, return without building any jars",
+                    "-nope=true", "true,false", Verifier.TRUEORFALSEPATTERN),
+
+            new Syntax(
+                    PEDANTIC,
+                    "Warn about things that are not really wrong but still not right",
+                    "-nope=true", "true,false", Verifier.TRUEORFALSEPATTERN),
+
+            new Syntax(
+                    PLUGIN,
+                    "Define the plugins",
+                    "-plugin=aQute.lib.spring.SpringComponent,aQute.lib.deployer.FileRepo;location=${repo}",
+                    null, null),
+
+            new Syntax(
+                    SERVICE_COMPONENT,
+                    "The header for Declarative Services",
+                    "Service-Component=com.acme.Foo?;activate='start'",
+                    null, null),
+
+            new Syntax(POM, "Generate a maven pom", "-pom=true", "true,false",
+                    Verifier.TRUEORFALSEPATTERN),
+
+            new Syntax(RELEASEREPO,
+                    "Specifies to which repo the project should be released.",
+                    "-releaserepo=cnf", "${repos}", null),
+
+            new Syntax(REMOVE_HEADERS,
+                    "Remove all headers that match the regular expressions",
+                    "-removeheaders=FOO_.*,Proprietary", null, null),
+            new Syntax(
+                    RESOURCEONLY,
+                    "Normally bnd warns when the JAR does not contain any classes, this option suppresses this warning",
+                    "-resourceonly=true", "true,false",
+                    Verifier.TRUEORFALSEPATTERN),
+            new Syntax(SOURCES, "Include sources in the jar", "-sources=true",
+                    "true,false", Verifier.TRUEORFALSEPATTERN),
+            new Syntax(
+                    SOURCEPATH,
+                    "List of directory names that used to source sources for -sources",
+                    "-sourcepath:= src, test", null, null),
+            new Syntax(
+                    SUB,
+                    "Build a set of bnd files that use this bnd file as a basis. The list of bnd file can be specified with wildcards",
+                    "-sub=com.acme.*.bnd", null, null),
+            new Syntax(
+                    RUNPROPERTIES,
+                    "Properties that are set as system properties before the framework is started",
+                    "-runproperties= foo=3, bar=4", null, null),
+            new Syntax(RUNSYSTEMPACKAGES,
+                    "Add additional system packages to a framework run",
+                    "-runsystempackages=com.acme.foo,javax.management", null,
+                    null),
+            new Syntax(
+                    RUNBUNDLES,
+                    "Add additional bundles, specified with their bsn and version like in -buildpath, that are started before the project is run",
+                    "-runbundles=osgi;version=\"[4.1,4.2)\", junit.junit, com.acme.foo;version=project",
+                    null, Verifier.SYMBOLICNAME, path_version),
+            new Syntax(
+                    RUNPATH,
+                    "Additional JARs for the VM path, should include the framework",
+                    "-runpath=org.eclipse.osgi;version=3.5", null, null,
+                    path_version),
+            new Syntax(
+                    RUNVM,
+                    "Additional arguments for the VM invokation. Keys that start with a - are added as options, otherwise they are treated as -D properties for the VM",
+                    "-runvm=-Xmax=30", null, null),
+            new Syntax(
+                    VERSIONPOLICY,
+                    "Provides a version policy to imports that are calculated from exports",
+                    "-versionpolicy = \"[${version;==;${@}},${version;+;${@}})\"",
+                    null, null)
+
+                                                                 };
+
+    public final static Map<String, Syntax> HELP                 = new HashMap<String, Syntax>();
+
+    static {
+        for (Syntax s : syntaxes) {
+            HELP.put(s.header, s);
+        }
+    }
+
+    public Syntax(String header, String lead, String example, String values,
+            Pattern pattern, Syntax... children) {
+        this.header = header;
+        this.children = children;
+        this.lead = lead;
+        this.example = example;
+        this.values = values;
+        this.pattern = pattern;
+    }
+
+    public String getLead() {
+        return lead;
+    }
+
+    public String getExample() {
+        return example;
+    }
+
+    public String getValues() {
+        return values;
+    }
+
+    public String getPattern() {
+        return lead;
+    }
+
+    public Syntax[] getChildren() {
+        return children;
+    }
+
+    public String getHeader() {
+        return header;
+    }
+
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/help/Syntax.java
------------------------------------------------------------------------------
    svn:eol-style = native