You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ri...@apache.org on 2009/07/13 15:26:06 UTC

svn commit: r793581 [7/23] - in /felix/trunk/sigil: ./ bld-ivy/ bld-ivy/example/ bld-ivy/example/dependence/ bld-ivy/example/dependence/dependee/ bld-ivy/example/dependence/dependee/src/ bld-ivy/example/dependence/dependee/src/standalone/ bld-ivy/examp...

Added: felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/BldConfig.java
URL: http://svn.apache.org/viewvc/felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/BldConfig.java?rev=793581&view=auto
==============================================================================
--- felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/BldConfig.java (added)
+++ felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/BldConfig.java Mon Jul 13 13:25:46 2009
@@ -0,0 +1,445 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.cauldron.bld.config;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TreeMap;
+
+import org.cauldron.bld.core.util.QuoteUtil;
+
+public class BldConfig {
+	
+	// control properties
+	public static final String C_BUNDLES = "-bundles";
+	public static final String C_REPOSITORIES = "-repositories";
+
+	// string properties
+	public static final String S_ACTIVATOR = "-activator";
+	public static final String S_DEFAULTS = "-defaults";
+	public static final String S_ID = "id";
+	public static final String S_SYM_NAME = "name";
+	public static final String S_VERSION = "version";
+	public static final String[] STRING_KEYS = { S_ACTIVATOR, S_DEFAULTS, S_ID, S_SYM_NAME, S_VERSION };
+
+	// list properties
+	public static final String L_COMPOSITES = "-composites";
+	public static final String L_CONTENTS = "-contents";
+	public static final String L_DL_CONTENTS = "-downloads";
+	public static final String L_SRC_CONTENTS = "-sourcedirs";
+	public static final String L_RESOURCES = "-resources";
+	public static final String[] LIST_KEYS = {
+		L_COMPOSITES, L_CONTENTS, L_DL_CONTENTS, L_SRC_CONTENTS, L_RESOURCES };
+
+	// map properties
+	public static final String M_EXPORTS = "-exports";
+	public static final String M_IMPORTS = "-imports";
+	public static final String M_REQUIRES = "-requires";
+	public static final String M_FRAGMENT = "-fragment";
+	public static final String M_LIBS = "-libs";
+	public static final String[] MAP_KEYS = { M_EXPORTS, M_IMPORTS, M_REQUIRES, M_FRAGMENT, M_LIBS };
+	
+	// property properties
+	public static final String P_HEADER = "header";
+	public static final String P_OPTION = "option";
+	public static final String P_PACKAGE_VERSION = "package";
+	public static final String P_BUNDLE_VERSION = "bundle";
+	public static final String[] PROP_KEYS = { P_HEADER, P_OPTION, P_PACKAGE_VERSION, P_BUNDLE_VERSION };
+
+	// private constants
+	private static final String LIST_REGEX = ",\\s*";
+	private static final String MAPATTR_REGEX = ";\\s*";
+	private static final String MAPATTR_SEP = ";";
+	private static final String SUBKEY_SEP = ";";
+
+	// configuration is stored in typed maps
+	private Map<String, String> string = new TreeMap<String, String>();
+	private Map<String, List<String>> list = new TreeMap<String, List<String>>();
+	private Map<String, Map<String, Map<String, String>>> map = new TreeMap<String, Map<String,Map<String,String>>>();
+	private Map<String, BldConfig> config = new TreeMap<String, BldConfig>();
+	private Map<String, Properties> property = new TreeMap<String, Properties>();
+	
+	// default config - not modified or saved
+	private BldConfig dflt;
+	
+	private Properties unknown = new Properties();
+	private String comment = "";
+	
+	public BldConfig() {
+	}
+		
+	public BldConfig(Properties p) throws IOException {
+		merge(p);
+	}
+	
+	public void setDefault(BldConfig dflt) {
+		this.dflt = dflt;
+	}
+
+	public void setComment(String comment) {
+		this.comment = comment;
+	}
+	
+	public Properties getUnknown() {
+		return unknown;
+	}
+
+	public String getString(String id, String key) {
+		if (id != null && config.containsKey(id)) {
+			String value = config.get(id).getString(null, key);
+			if (value != null)
+				return value;
+		}
+		return string.containsKey(key) ? string.get(key) : (dflt != null ? dflt.getString(id, key) : null);
+	}
+
+	public List<String> getList(String id, String key) {
+		if (id != null && config.containsKey(id)) {
+			List<String> value = config.get(id).getList(null, key);
+			if (value != null)
+				return value;
+		}
+		return list.containsKey(key) ? list.get(key) : (dflt != null ? dflt.getList(id, key) : Collections.<String>emptyList());
+	}
+
+	public Map<String, Map<String,String>> getMap(String id, String key) {
+		if (id != null && config.containsKey(id)) {
+			Map<String, Map<String,String>> value = config.get(id).getMap(null, key);
+			if (value != null)
+				return value;
+		}
+		return map.containsKey(key) ? map.get(key)
+				: (dflt != null ? dflt.getMap(id, key) : Collections.<String, Map<String,String>>emptyMap());
+	}
+	
+	public void setString(String id, String key, String value) {
+		if (!value.equals(getString(id, key))) {
+			if (id != null) {
+    			if (!config.containsKey(id))
+    				config.put(id, new BldConfig());
+    			config.get(id).setString(null, key, value);
+			} else {
+				String dval = (dflt == null ? dflt.getString(null, key) : null);
+				if (value.equals("") && (dval == null || dval.equals(""))) {
+    		        string.remove(key);	
+    			} else {
+            		string.put(key, value);
+    			}
+			}
+		}
+	}
+
+	public void setList(String id, String key, List<String> value) {
+		if (!value.equals(getList(id, key))) {
+			if (id != null) {
+    			if (!config.containsKey(id))
+    				config.put(id, new BldConfig());
+    			config.get(id).setList(null, key, value);
+			} else if (value.isEmpty() && (dflt == null || dflt.getList(null, key).isEmpty())) {
+		        list.remove(key);	
+			} else {
+        		list.put(key, value);
+			}
+		}
+	}
+
+	public void setMap(String id, String key, Map<String, Map<String,String>> value) {
+		if (!value.equals(getMap(id, key))) {
+			if (id != null) {
+    			if (!config.containsKey(id))
+    				config.put(id, new BldConfig());
+    			config.get(id).setMap(null, key, value);
+			} else if (value.isEmpty() && (dflt == null || dflt.getMap(null, key).isEmpty())) {
+		        map.remove(key);	
+			} else {
+        		map.put(key, value);
+			}
+		}
+	}
+	
+	public Properties getProps(String id, String key) {
+    	// merge main and sub properties
+		Properties props = new Properties();
+		
+		if (dflt != null)
+    		props.putAll(dflt.getProps(id, key));
+		
+		if (property.containsKey(key))
+			props.putAll(property.get(key));
+
+		if (id != null && config.containsKey(id)) {
+			Properties p2 = config.get(id).getProps(null, key);
+			if (p2 != null)
+				props.putAll(p2);
+		}
+
+		return props;
+	}
+	
+	// only sets one property at a time
+	public void setProp(String id, String key, String k2, String v2) {
+		if (v2 == null)
+			return;
+		Properties props = getProps(id, key);
+		if (!v2.equals(props.getProperty(key))) {
+			if (id != null) {
+    			if (!config.containsKey(id))
+    				config.put(id, new BldConfig());
+    			config.get(id).setProp(null, key, k2, v2);
+			} else {
+        		if (property.containsKey(key)) {
+        			property.get(key).put(k2, v2);
+        		} else {
+            		Properties value = new Properties();
+            		value.put(k2, v2);
+            		property.put(key, value);
+        		}
+			}
+		}
+	}
+
+	/**
+	 * write config in Property file format.
+	 * This allows us to make it prettier than Properties.store().
+	 */
+	public void write(final PrintWriter out) {
+		out.println(comment);
+		
+		// Note: don't add date stamp, or file will differ each time it's saved.
+		out.println("# sigil project file, saved by plugin.\n");
+		
+		dump("", new Properties() {
+			private static final long serialVersionUID = 1L; //appease eclipse
+			@Override
+			public Object put(Object key, Object value) {
+				if (value instanceof String) {
+					out.println(key + ": " + value);
+					out.println("");
+				} else if (value instanceof List) {
+					out.println(key + ": \\");
+					for (Object k : (List<?>) value) {
+						out.println("\t" + k + ", \\");
+					}
+					out.println("");
+				}
+				else if (value instanceof Map) {
+					out.println(key + ": \\");
+					StringBuilder b = new StringBuilder();
+					for (Map.Entry<?, ?> e : ((Map<?,?>) value).entrySet()) {
+						b.append("\t");
+						b.append(e.getKey());
+						Map<?, ?> v = (Map<?, ?>) e.getValue();
+						if (!v.isEmpty()) {
+							for (Map.Entry<?, ?> e2 : v.entrySet()) {
+    							b.append(MAPATTR_SEP);
+								b.append(e2.getKey());
+								b.append("=");
+								String v2 = e2.getValue().toString();
+								if (v2.contains(",")) {
+									b.append("\"");
+									b.append(v2);
+									b.append("\"");
+								}
+								else {
+									b.append(v2);
+								}
+							}
+						}
+						b.append (", \\\n"); 
+					}
+					out.println(b.toString());
+				}
+				return null;
+			}
+		});
+		out.println("# end");
+	}
+
+	/**
+	 * dump config in pseudo Properties format.
+	 * Note: some values are not Strings (they're List<String>).
+	 */
+	private void dump(String prefix, Properties p) {
+		for (String key : string.keySet()) {
+			p.put(prefix + key, string.get(key));
+		}
+		
+		for (String key : list.keySet()) {
+			List<String> list2 = list.get(key);
+			p.put(prefix + key, list2);
+		}
+
+		for (String key : map.keySet()) {
+			Map<String, Map<String,String>> map2 = map.get(key);
+			p.put(prefix + key, map2);
+		}
+
+		for (String key : property.keySet()) {
+			Properties props = property.get(key);
+			for (Object k2 : props.keySet()) {
+				p.put(prefix + key + SUBKEY_SEP + k2, props.get(k2));
+			}
+		}
+
+		for (String key : config.keySet()) {
+			BldConfig config2 = config.get(key);
+			config2.dump(key + SUBKEY_SEP + prefix, p);
+		}
+
+		for (Object key : unknown.keySet()) {
+			String value = unknown.getProperty((String)key);
+			if (value.length() > 0)
+    			p.put(prefix + key, value);
+		}
+	}
+
+	/**
+	 * merges properties into current configuration.
+	 * @param p
+	 * @throws IOException 
+	 */
+	public void merge(Properties p) throws IOException {
+		if (p.isEmpty())
+			return;
+		
+		final List<String> strings = Arrays.asList(STRING_KEYS);
+		final List<String> lists = Arrays.asList(LIST_KEYS);
+		final List<String> maps = Arrays.asList(MAP_KEYS);
+
+		List<String> bundleKeys = new ArrayList<String>();
+		List<String> repoKeys = new ArrayList<String>();
+
+		String bundles = p.getProperty(C_BUNDLES);
+		if (bundles != null) {
+			bundleKeys.addAll(Arrays.asList(bundles.split(LIST_REGEX)));
+			list.put(C_BUNDLES, bundleKeys);
+		}
+
+		String repos = p.getProperty(C_REPOSITORIES);
+		if (repos != null) {
+			for ( String s : repos.split(LIST_REGEX) ) {
+				repoKeys.add(s.trim());
+			}
+			list.put(C_REPOSITORIES, repoKeys);
+		}
+
+		List<String> subKeys = new ArrayList<String>();
+		subKeys.addAll(Arrays.asList(PROP_KEYS));
+		subKeys.addAll(bundleKeys);
+		subKeys.addAll(repoKeys);
+
+		Map<String, Properties> sub = new TreeMap<String, Properties>();
+
+		for (Object k : p.keySet()) {
+			String key = (String) k;
+			if (key.equals(C_BUNDLES) || key.equals(C_REPOSITORIES))
+				continue;
+			
+			String value = p.getProperty(key);
+			String[] keys = key.split(SUBKEY_SEP, 2);
+
+			if (keys.length > 1) {
+				Properties p2 = sub.get(keys[0]);
+				if (p2 == null) {
+					p2 = new Properties();
+					sub.put(keys[0], p2);
+					if (!subKeys.contains(keys[0])) {
+						unknown.setProperty(keys[0] + SUBKEY_SEP, "");
+					}
+				}
+				p2.setProperty(keys[1], value);
+			} else if (strings.contains(key)) {
+				if (!string.containsKey(key))
+					string.put(key, value);
+			} else if (lists.contains(key)) {
+				if (!list.containsKey(key)) {
+					ArrayList<String> list2 = new ArrayList<String>();
+					for (String s : value.split(LIST_REGEX)) {
+						if ( s.trim().length() > 0 ) {
+							list2.add(s.trim());
+						}
+					}
+					if ( !list2.isEmpty() ) {
+						list.put(key, list2);
+					}
+				}
+			} else if (maps.contains(key)) {
+				if (!map.containsKey(key)) {
+					Map<String, Map<String,String>> map2 = new TreeMap<String, Map<String,String>>();
+
+					for (String subValue : QuoteUtil.split(value)) {
+						if (subValue.trim().length() > 0) {
+							String[] split = subValue.split(MAPATTR_REGEX);
+							Map<String,String> map3 = new TreeMap<String,String>();
+							for (int i = 1; i < split.length; ++i){
+								String[] keyVal = split[i].split(":?=", 2);
+								if (keyVal.length != 2) {
+								    throw new IOException("attribute missing '=':" + subValue);
+								}
+								map3.put(keyVal[0], keyVal[1]);
+							}
+							map2.put(split[0], map3);
+						}
+					}
+
+					map.put(key, map2);
+				}
+			} else {
+				unknown.setProperty(key, value);
+			}
+		}
+		
+		for (String subKey : sub.keySet()) {
+			Properties props = sub.get(subKey);
+			if (!props.isEmpty()) {
+				if (bundleKeys.contains(subKey)) {
+					BldConfig config2 = new BldConfig(props);
+					Properties unkProps = config2.getUnknown();
+					
+					if (config2.map.containsKey(M_IMPORTS))
+						unkProps.setProperty(M_IMPORTS, "");
+						
+					if (config2.map.containsKey(M_REQUIRES))
+						unkProps.setProperty(M_REQUIRES, "");
+						
+					for (Object unk : unkProps.keySet()) {
+						unknown.setProperty(subKey + SUBKEY_SEP + unk, "");
+					}
+					config.put(subKey, config2);
+				} else {
+					property.put(subKey, props);
+				}
+			}
+		}
+	}
+	
+	@Override
+	public String toString() {
+		return "string: " + string + " list:" + list + " map: " + map + " prop: " + property + " config:" + config;
+	}
+
+}
+

Added: felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/BldConverter.java
URL: http://svn.apache.org/viewvc/felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/BldConverter.java?rev=793581&view=auto
==============================================================================
--- felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/BldConverter.java (added)
+++ felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/BldConverter.java Mon Jul 13 13:25:46 2009
@@ -0,0 +1,464 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.cauldron.bld.config;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.cauldron.bld.config.IBldProject.IBldBundle;
+import org.cauldron.bld.core.BldCore;
+import org.cauldron.bld.core.internal.model.eclipse.SigilBundle;
+import org.cauldron.bld.core.internal.model.osgi.BundleModelElement;
+import org.cauldron.sigil.model.common.VersionRange;
+import org.cauldron.sigil.model.eclipse.ISCAComposite;
+import org.cauldron.sigil.model.eclipse.ISigilBundle;
+import org.cauldron.sigil.model.osgi.IBundleModelElement;
+import org.cauldron.sigil.model.osgi.IPackageExport;
+import org.cauldron.sigil.model.osgi.IPackageImport;
+import org.cauldron.sigil.model.osgi.IRequiredBundle;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.osgi.framework.Version;
+
+import aQute.lib.osgi.Constants;
+
+public class BldConverter {
+	private static final String classpathFormat = "<classpathentry kind=\"%s\" path=\"%s\"/>";
+	private BldConfig config;
+	private Properties packageDefaults;
+	private TreeSet<String> packageWildDefaults;
+
+	public BldConverter(BldConfig config) {
+		this.config = config;
+	}
+
+	/**
+	 * converts to an ISigilBundle.
+	 * @param id
+	 * @param bundle
+	 * @return
+	 */
+	public ISigilBundle getBundle(String id, IBldBundle bundle) {
+
+		ISigilBundle sigilBundle = new SigilBundle();
+		IBundleModelElement info = new BundleModelElement();
+		sigilBundle.setBundleInfo(info);
+
+		// exports
+		// FIXME: UI doesn't understand export wildcard packages
+		for (IPackageExport export : bundle.getExports()) {
+			IPackageExport clone = (IPackageExport) export.clone();
+			clone.setParent(null);
+			info.addExport(clone);
+		}
+
+		// imports
+		for (IPackageImport import1 : bundle.getImports()) {
+			IPackageImport clone = (IPackageImport) import1.clone();
+			clone.setParent(null);
+			info.addImport(clone);
+		}
+
+		// requires
+		for (IRequiredBundle require : bundle.getRequires()) {
+			IRequiredBundle clone = (IRequiredBundle) require.clone();
+			clone.setParent(null);
+			info.addRequiredBundle(clone);
+		}
+
+		// fragment
+		IRequiredBundle fragment = bundle.getFragmentHost();
+		if (fragment != null) {
+			info.setFragmentHost(fragment);
+		}
+		
+		// contents
+		for (String pkg : bundle.getContents()) {
+			sigilBundle.addPackage(pkg);
+		}
+		
+		// downloads
+		for (String pkg : bundle.getDownloadContents()) {
+			sigilBundle.addDownloadPackage(pkg);
+		}
+		
+		// sources
+		for (String source : config.getList(null, BldConfig.L_SRC_CONTENTS) ) {
+			sigilBundle.addClasspathEntry(String.format(classpathFormat, "src", source));
+		}
+
+		// libs
+		Map<String, Map<String, String>> libs = bundle.getLibs();
+		
+		for (String path : libs.keySet()) {
+			Map<String, String> attr = libs.get(path);
+			String kind = attr.get(BldAttr.KIND_ATTRIBUTE);
+			String publish = attr.get(BldAttr.PUBLISH_ATTRIBUTE);
+			
+			if (publish != null) {
+        		// FIXME: UI doesn't understand publish=name
+				BldCore.error("Can't convert -libs publish=" + publish);
+				continue;	
+			}
+			
+			if ("classpath".equals(kind)) {
+    			sigilBundle.addClasspathEntry(String.format(classpathFormat, "lib", path));
+			} else {
+				BldCore.error("Can't convert -libs kind=" + kind);
+			}
+		}
+
+		// resources
+		// FIXME: UI doesn't support -resources: path1=path2
+		Map<String, String> resources = bundle.getResources();
+		for (String resource : resources.keySet()) {
+			String fsPath = resources.get(resource);
+			if (!"".equals(fsPath)) {
+    			BldCore.error("FIXME: can't convert resource: " + resource + "=" + fsPath);
+			}
+			sigilBundle.addSourcePath(new Path(resource));
+		}
+		
+		////////////////////
+		// simple headers
+
+		info.setSymbolicName(bundle.getSymbolicName());
+
+		info.setVersion(Version.parseVersion(bundle.getVersion()));
+
+		String activator = bundle.getActivator();
+		if (activator != null)
+			info.setActivator(activator);
+		
+		Properties headers = config.getProps(id, BldConfig.P_HEADER);
+		String header;
+
+		header = headers.getProperty("CATEGORY");
+		if (header != null)
+			info.setCategory(header);
+
+		header = headers.getProperty(Constants.BUNDLE_CONTACTADDRESS);
+		if (header != null)
+			info.setContactAddress(header);
+
+		header = headers.getProperty(Constants.BUNDLE_COPYRIGHT);
+		if (header != null)
+			info.setCopyright(header);
+
+		header = headers.getProperty(Constants.BUNDLE_DESCRIPTION);
+		if (header != null)
+			info.setDescription(header);
+
+		header = headers.getProperty(Constants.BUNDLE_VENDOR);
+		if (header != null)
+			info.setVendor(header);
+
+		header = headers.getProperty(Constants.BUNDLE_NAME);
+		if (header != null)
+			info.setName(header);
+
+		header = headers.getProperty(Constants.BUNDLE_DOCURL);
+		if (header != null)
+			info.setDocURI(URI.create(header));
+
+		header = headers.getProperty(Constants.BUNDLE_LICENSE);
+		if (header != null)
+			info.setDocURI(URI.create(header));
+
+		return sigilBundle;
+	}
+
+	private VersionRange defaultVersion(VersionRange current, String defaultRange) {
+		if (current.equals(VersionRange.ANY_VERSION) ||
+			current.equals(VersionRange.parseVersionRange(defaultRange))) {
+			return null;
+		}
+		return current;
+	}
+	
+	// FIXME - copied from BldProject
+	private String getDefaultPackageVersion(String name) {
+		if (packageDefaults == null) {
+    		packageDefaults = config.getProps(null, BldConfig.P_PACKAGE_VERSION);
+    		packageWildDefaults = new TreeSet<String>();
+    		
+    		for (Object key : packageDefaults.keySet()) {
+    			String pkg = (String)key;
+    			if (pkg.endsWith("*")) {
+    				packageWildDefaults.add(pkg.substring(0, pkg.length() - 1));
+    			}
+    		}
+		}
+		
+		String version = packageDefaults.getProperty(name);
+		
+		if (version == null) {
+			for (String pkg : packageWildDefaults) {
+				if (name.startsWith(pkg)) {
+					version = packageDefaults.getProperty(pkg + "*");
+					// break; -- don't break, as we want the longest match
+				}
+			}
+		}
+		
+	    return version;
+	}
+	
+	
+	/**
+	 * converts from an ISigilBundle.
+	 * 
+	 * @param id
+	 * @param bundle
+	 */
+	public void setBundle(String id, ISigilBundle bundle) {
+		IBundleModelElement info = bundle.getBundleInfo();
+		String bundleVersion = config.getString(id, BldConfig.S_VERSION);
+
+		// exports
+		Map<String, Map<String, String>> exports = new TreeMap<String, Map<String,String>>();
+		for (IPackageExport export : info.getExports()) {
+			Map<String, String> map2 = new TreeMap<String, String>();
+			String version = export.getVersion().toString();
+			if (!version.equals(bundleVersion))
+				map2.put(BldAttr.VERSION_ATTRIBUTE, version);
+			exports.put(export.getPackageName(), map2);
+		}
+		
+		if (!exports.isEmpty() || !config.getMap(id, BldConfig.M_EXPORTS).isEmpty()) {
+			config.setMap(id, BldConfig.M_EXPORTS, exports);
+		}
+
+		// imports
+		Map<String, Map<String, String>> imports = new TreeMap<String, Map<String,String>>();
+
+		// FIXME: default version logic is wrong here
+		//    if the version to be saved is the same as the default version,
+		//    then we should _remove_ the version from the value being saved,
+		//    since config.getMap() does not apply default versions.
+		for (IPackageImport import1 : info.getImports()) {
+			Map<String, String> map2 = new TreeMap<String, String>();
+			String name = import1.getPackageName();
+			VersionRange versions = defaultVersion(import1.getVersions(), getDefaultPackageVersion(name));
+			
+			boolean isDependency = import1.isDependency();
+			Map<String, String> selfImport = exports.get(name);
+			
+			if (selfImport != null) {
+    			// avoid saving self-import attributes, e.g.
+    			// org.cauldron.newton.example.fractal.engine;resolve=auto;version=1.0.0
+				isDependency = true;
+				
+				if (versions != null) {
+    				String exportVersion = selfImport.get(BldAttr.VERSION_ATTRIBUTE);
+    				if (exportVersion == null)
+    					exportVersion = bundleVersion;
+    				
+    				if (exportVersion.equals(versions.toString())) {
+    					versions = null;
+    				}
+				}
+			}
+
+			if (versions != null) {
+				map2.put(BldAttr.VERSION_ATTRIBUTE, versions.toString());
+			}
+			
+			if (import1.isOptional()) {
+				map2.put(BldAttr.RESOLUTION_ATTRIBUTE, BldAttr.RESOLUTION_OPTIONAL);
+			}
+			
+			String resolve = BldProject.getResolve(import1, isDependency);
+			if (resolve != null)
+				map2.put(BldAttr.RESOLVE_ATTRIBUTE, resolve);
+			
+			imports.put(name, map2);
+		}
+		if (!imports.isEmpty() || !config.getMap(id, BldConfig.M_IMPORTS).isEmpty()) {
+			config.setMap(id, BldConfig.M_IMPORTS, imports);
+		}
+
+		// requires
+		Properties defaultBundles = config.getProps(null, BldConfig.P_BUNDLE_VERSION);
+		Map<String, Map<String, String>> requires = new TreeMap<String, Map<String,String>>();
+		
+		for (IRequiredBundle require : info.getRequiredBundles()) {
+			Map<String, String> map2 = new TreeMap<String, String>();
+			String name = require.getSymbolicName();
+			VersionRange versions = defaultVersion(require.getVersions(), defaultBundles.getProperty(name));
+			if (versions != null)
+    			map2.put(BldAttr.VERSION_ATTRIBUTE, versions.toString());
+			requires.put(name, map2);
+		}
+		if (!requires.isEmpty() || !config.getMap(id, BldConfig.M_REQUIRES).isEmpty()) {
+			config.setMap(id, BldConfig.M_REQUIRES, requires);
+		}
+
+		// fragment
+		Map<String, Map<String, String>> fragments = new TreeMap<String, Map<String,String>>();
+		IRequiredBundle fragment = info.getFragmentHost();
+		if (fragment != null) {
+			Map<String, String> map2 = new TreeMap<String, String>();
+			String name = fragment.getSymbolicName();
+			VersionRange versions = defaultVersion(fragment.getVersions(), defaultBundles.getProperty(name));
+			if (versions != null)
+    			map2.put(BldAttr.VERSION_ATTRIBUTE, versions.toString());
+			fragments.put(name, map2);
+		}
+		if (!fragments.isEmpty() || !config.getMap(id, BldConfig.M_FRAGMENT).isEmpty()) {
+			config.setMap(id, BldConfig.M_FRAGMENT, fragments);
+		}
+	
+		// contents
+		List<String> contents = new ArrayList<String>();
+		for (String pkg : bundle.getPackages()) {
+			contents.add(pkg);
+		}
+		if (!contents.isEmpty() || !config.getList(id, BldConfig.L_CONTENTS).isEmpty()) {
+			config.setList(id, BldConfig.L_CONTENTS, contents);
+		}
+		
+		// dl contents
+		List<String> dlcontents = new ArrayList<String>();
+		for (String pkg : bundle.getDownloadPackages()) {
+			dlcontents.add(pkg);
+		}
+		if (!dlcontents.isEmpty() || !config.getList(id, BldConfig.L_DL_CONTENTS).isEmpty()) {
+			config.setList(id, BldConfig.L_DL_CONTENTS, dlcontents);
+		}
+
+		// libs
+		Map<String, Map<String, String>> libs = new TreeMap<String, Map<String,String>>();
+		List<String> sources = new ArrayList<String>();
+
+		// classpathEntries map to -libs or -sources
+		for (String entry : bundle.getClasspathEntrys()) {
+			// <classpathentry kind="lib" path="lib/dependee.jar"/>
+			// <classpathentry kind="src" path="src"/>
+			final String regex = ".* kind=\"([^\"]+)\" path=\"([^\"]+)\".*";
+			Pattern pattern = Pattern.compile(regex);
+			Matcher matcher = pattern.matcher(entry);
+			if (matcher.matches()) {
+				String kind = matcher.group(1);
+				String path = matcher.group(2);
+				if (kind.equals("lib")) {
+    				Map<String, String> map2 = new TreeMap<String, String>();
+    				map2.put(BldAttr.KIND_ATTRIBUTE, "classpath");
+    				libs.put(path, map2);
+				} else if (kind.equals("src")) {
+					sources.add(path);
+				} else {
+    				BldCore.error("unknown classpathentry kind=" + kind);
+				}
+			} else {
+				BldCore.error("can't match classpathEntry in: " + entry);
+			}
+		}
+
+		if (!libs.isEmpty() || !config.getMap(id, BldConfig.M_LIBS).isEmpty()) {
+			config.setMap(id, BldConfig.M_LIBS, libs);
+		}
+
+		if (!sources.isEmpty() || !config.getList(id, BldConfig.L_SRC_CONTENTS).isEmpty()) {
+			config.setList(id, BldConfig.L_SRC_CONTENTS, sources);
+		}
+
+		// composites
+		ArrayList<String> composites = new ArrayList<String>();
+		for (ISCAComposite composite : bundle.getComposites()) {
+			String path = composite.getLocation().toString();
+			// TODO relativize
+			composites.add(path);
+		}
+		
+		if (!composites.isEmpty() || !config.getList(id, BldConfig.L_COMPOSITES).isEmpty()) {
+			Collections.sort(composites);
+			config.setList(id, BldConfig.L_COMPOSITES, composites);
+		}
+		
+		// resources
+		ArrayList<String> resources = new ArrayList<String>();
+		for (IPath ipath : bundle.getSourcePaths()) {
+			resources.add(ipath.toString());
+		}
+		
+		if (!resources.isEmpty() || !config.getList(id, BldConfig.L_RESOURCES).isEmpty()) {
+    		Collections.sort(resources);
+			config.setList(id, BldConfig.L_RESOURCES, resources);
+		}
+		
+		if (info.getSourceLocation() != null) {
+			BldCore.error("SourceLocation conversion not yet implemented.");
+		}
+
+		if (!info.getLibraryImports().isEmpty()) {
+			BldCore.error("LibraryImports conversion not yet implemented.");
+		}
+
+		////////////////////
+		// simple headers
+
+		List<String> ids = config.getList(null, BldConfig.C_BUNDLES);
+		String idBsn = id != null ? id : ids.get(0);
+		String oldBsn = config.getString(id, BldConfig.S_SYM_NAME);
+		String bsn = info.getSymbolicName();
+		
+		if (!bsn.equals(idBsn) || oldBsn != null)
+			config.setString(id, BldConfig.S_SYM_NAME, bsn);
+
+		String version = info.getVersion().toString();
+		if (version != null)
+			config.setString(id, BldConfig.S_VERSION, version);
+
+		String activator = info.getActivator();
+		if (activator != null)
+    		config.setString(id, BldConfig.S_ACTIVATOR, activator);
+		
+		Properties headers = config.getProps(null, BldConfig.P_HEADER);
+		
+		setHeader(headers, id, "CATEGORY", info.getCategory());
+		setHeader(headers, id, Constants.BUNDLE_CONTACTADDRESS, info.getContactAddress());
+		setHeader(headers, id, Constants.BUNDLE_COPYRIGHT, info.getCopyright());
+		setHeader(headers, id, Constants.BUNDLE_DESCRIPTION, info.getDescription());
+		setHeader(headers, id, Constants.BUNDLE_VENDOR, info.getVendor());
+		setHeader(headers, id, Constants.BUNDLE_NAME, info.getName());
+
+		if (info.getDocURI() != null)
+			config.setProp(id, BldConfig.P_HEADER, Constants.BUNDLE_DOCURL, info.getDocURI().toString());
+
+		if (info.getLicenseURI() != null)
+			config.setProp(id, BldConfig.P_HEADER, Constants.BUNDLE_LICENSE, info.getLicenseURI().toString());
+	}
+	
+	private void setHeader(Properties headers, String id, String key, String value) {
+		if (value == null)
+			value = "";
+		if (!value.equals(headers.getProperty(key, "")))
+    		config.setProp(id, BldConfig.P_HEADER, key, value);
+	}
+}

Added: felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/BldFactory.java
URL: http://svn.apache.org/viewvc/felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/BldFactory.java?rev=793581&view=auto
==============================================================================
--- felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/BldFactory.java (added)
+++ felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/BldFactory.java Mon Jul 13 13:25:46 2009
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.cauldron.bld.config;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+public class BldFactory {
+	private static Map<URI, BldProject> projects = new HashMap<URI, BldProject>();
+	
+	public static IBldProject getProject(URI uri) throws IOException {
+		return getProject(uri, false);
+	}
+	
+	public static IBldProject getProject(URI uri, boolean ignoreCache) throws IOException {
+		return load(uri, ignoreCache);
+	}
+	
+	public static IRepositoryConfig getConfig(URI uri) throws IOException {
+		return load(uri, false);
+	}
+	
+	/**
+	 * creates a new project file, initialised with defaults.
+	 * @param uri where the file will be saved - used to resolve relative paths.
+	 * @param defaults relative path to defaults file - default ../sigil.properties.
+	 * @return
+	 * @throws IOException
+	 */
+	public static IBldProject newProject(URI uri, String defaults) throws IOException {
+		BldProject project = new BldProject(uri);
+		Properties p = new Properties();
+		if (defaults != null)
+    		p.setProperty(BldConfig.S_DEFAULTS, defaults);
+		project.loadDefaults(p);
+		return project;
+	}
+	
+	private static BldProject load(URI uri, boolean ignoreCache) throws IOException {
+		BldProject p = null; 
+		if (!ignoreCache) {
+			p = projects.get(uri);
+		}
+		
+		if (p == null) {
+			p = new BldProject(uri);
+			p.load();
+			projects.put(uri, p);
+    			
+    		if (Boolean.getBoolean("org.cauldron.bld.config.test")) {
+    			File path = new File(uri.getPath() + ".tmp");
+    			System.out.println("XXX: config.test writing: " + path);
+    			p.saveAs(path);
+    		}
+		}
+		return p;
+	}
+	
+}

Added: felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/BldProject.java
URL: http://svn.apache.org/viewvc/felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/BldProject.java?rev=793581&view=auto
==============================================================================
--- felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/BldProject.java (added)
+++ felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/BldProject.java Mon Jul 13 13:25:46 2009
@@ -0,0 +1,823 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.cauldron.bld.config;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TreeSet;
+
+import org.cauldron.bld.bnd.BundleBuilder;
+import org.cauldron.bld.core.internal.model.osgi.BundleModelElement;
+import org.cauldron.bld.core.internal.model.osgi.PackageExport;
+import org.cauldron.bld.core.internal.model.osgi.PackageImport;
+import org.cauldron.bld.core.internal.model.osgi.RequiredBundle;
+import org.cauldron.sigil.model.IModelElement;
+import org.cauldron.sigil.model.common.VersionRange;
+import org.cauldron.sigil.model.eclipse.ISigilBundle;
+import org.cauldron.sigil.model.osgi.IBundleModelElement;
+import org.cauldron.sigil.model.osgi.IPackageExport;
+import org.cauldron.sigil.model.osgi.IPackageImport;
+import org.cauldron.sigil.model.osgi.IRequiredBundle;
+import org.cauldron.sigil.model.osgi.IPackageImport.OSGiImport;
+import org.osgi.framework.Version;
+
+public class BldProject implements IBldProject, IRepositoryConfig {
+    private static final String OVERRIDE_PREFIX = "sigil.";
+    private static final int MAX_HEADER = 10240;
+    // cache to avoid loading the same default config for each project
+    private static Map<URL, BldConfig> defaultsCache = new HashMap<URL, BldConfig>();
+    private static Properties overrides;
+
+    private List<String> sourcePkgs;
+    private BldConfig config;
+    private BldConverter convert;
+    private BundleModelElement requirements;
+    private File baseDir;
+    private URI loc;
+    private Properties packageDefaults;
+    private TreeSet<String> packageWildDefaults;
+    private long lastModified;
+
+    /* package */BldProject(URI relLoc) {
+        config = new BldConfig();
+        convert = new BldConverter(config);
+        loc = new File(".").toURI().resolve(relLoc).normalize();
+        File f = new File(loc);
+        lastModified = f.lastModified();
+        baseDir = f.getParentFile();
+    }
+
+    /* package */void load() throws IOException {
+        // allow System property overrides, e.g.
+        // ANT_OPTS='-Dsigil.option\;addMissingImports=false' ant
+        config.merge(getOverrides());
+
+        InputStream in = null;
+        try {
+        	in = loc.toURL().openStream();
+	        BufferedInputStream bis = new BufferedInputStream(in);
+	        bis.mark(MAX_HEADER);
+	        readHeader(bis);
+	        bis.reset();
+	
+	        Properties p = new Properties();
+	        p.load(bis);
+	        config.merge(p);
+	
+	        Properties unknown = config.getUnknown();
+	        if (!unknown.isEmpty())
+	            System.err.println("WARN: unknown keys " + unknown.keySet() + " in " + loc);
+	
+	        loadDefaults(p);
+	        requirements = parseRequirements();
+        }
+        finally {
+        	if ( in != null ) {
+        		in.close();
+        	}
+        }
+    }
+
+    /* package */void loadDefaults(Properties p) throws IOException {
+        BldConfig c = loadDefaults(p, baseDir, null);
+        config.setDefault(c);
+
+        Properties options = config.getProps(null, BldConfig.P_OPTION);
+
+        if (!options.containsKey(BldAttr.OPTION_ADD_IMPORTS))
+            c.setProp(null, BldConfig.P_OPTION, BldAttr.OPTION_ADD_IMPORTS, "true");
+
+        // default omitUnusedImports option depends on number of bundles...
+        // we set it here to avoid it being written by save(),
+        // but as this may alter cached defaults, once set we have to reset it
+        // for each project.
+
+        boolean omitSet = options.containsKey("__omit_set__");
+        boolean multiple = getBundleIds().size() > 1;
+
+        if (multiple || omitSet) {
+            if (!options.containsKey(BldAttr.OPTION_OMIT_IMPORTS) || omitSet) {
+                c.setProp(null, BldConfig.P_OPTION, BldAttr.OPTION_OMIT_IMPORTS, multiple + "");
+                c.setProp(null, BldConfig.P_OPTION, "__omit_set__", "true");
+            }
+        }
+    }
+
+    private synchronized BldConfig loadDefaults(Properties props, File base, BldConfig dflt)
+            throws IOException {
+        boolean cached = false;
+        String defaults = props.getProperty(BldConfig.S_DEFAULTS, "-"
+                + IBldProject.PROJECT_DEFAULTS);
+
+        if (base != null && defaults.length() > 0) {
+            boolean ignore = defaults.startsWith("-");
+
+            if (ignore)
+                defaults = defaults.substring(1);
+
+            try {
+                File file = new File(base, defaults).getCanonicalFile();
+                URL url = file.toURL();
+
+                if (dflt == null) {
+                    dflt = defaultsCache.get(url);
+                    if (dflt != null)
+                        return dflt;
+
+                    dflt = new BldConfig();
+                    defaultsCache.put(url, dflt);
+                    cached = true;
+                }
+
+                Properties p = new Properties();
+                p.load(url.openStream());
+                dflt.merge(p);
+
+                ignore = false;
+                loadDefaults(p, file.getParentFile(), dflt);
+            } catch (IOException e) {
+                if (!ignore)
+                    throw e;
+            }
+        }
+
+        if (dflt == null)
+            return new BldConfig();
+
+        if (cached) {
+            Properties unknown = dflt.getUnknown();
+            if (!unknown.isEmpty())
+                System.err.println("WARN: unknown keys " + unknown.keySet() + " in defaults for "
+                        + loc);
+        }
+
+        return dflt;
+    }
+
+    private static Properties getOverrides() {
+        if (overrides == null) {
+            overrides = new Properties();
+            Properties sysProps = System.getProperties();
+
+            for (Object okey : sysProps.keySet()) {
+                String key = (String) okey;
+                if (key.startsWith(OVERRIDE_PREFIX)) {
+                    overrides.setProperty(key.substring(OVERRIDE_PREFIX.length()), sysProps
+                            .getProperty(key));
+                }
+            }
+        }
+
+        return overrides;
+    }
+
+    private void readHeader(InputStream in) throws IOException {
+        BufferedReader r = new BufferedReader(new InputStreamReader(in));
+        StringBuffer header = new StringBuffer();
+        String line;
+        while ((line = r.readLine()) != null) {
+            if (line.startsWith("#")) {
+                header.append(line);
+                header.append("\n");
+            } else {
+                config.setComment(header.toString());
+                break;
+            }
+        }
+    }
+
+    public File resolve(String path) {
+        File file = new File(path);
+        if (!file.isAbsolute()) {
+            // can't use loc.resolve(value), as value may not be valid URI.
+            file = new File(baseDir, path);
+        }
+        return file;
+    }
+
+    public String getVersion() {
+        String version = config.getString(null, BldConfig.S_VERSION);
+        return version == null ? "0" : version;
+    }
+
+    public IBundleModelElement getDependencies() {
+        IBundleModelElement dependencies = new BundleModelElement();
+
+        for (IModelElement element : getRequirements().children()) {
+            if (element instanceof IPackageImport) {
+                IPackageImport import1 = (IPackageImport) element;
+                if (!import1.isDependency())
+                    continue;
+
+                IPackageImport pi = (IPackageImport) (element.clone());
+                pi.setParent(null);
+                dependencies.addImport(pi);
+            } else {
+                IRequiredBundle rb = (IRequiredBundle) (element.clone());
+                rb.setParent(null);
+                dependencies.addRequiredBundle(rb);
+            }
+        }
+
+        boolean containsComposite = false;
+
+        for (IBldBundle bundle : getBundles()) {
+            if (!bundle.getComposites().isEmpty()) {
+                containsComposite = true;
+                break;
+            }
+        }
+
+        // add dependency on component activator
+        if (containsComposite) {
+            PackageImport pi = new PackageImport();
+            pi.setPackageName(BundleBuilder.COMPONENT_ACTIVATOR_PKG);
+            pi.setOSGiImport(OSGiImport.NEVER);
+            dependencies.addImport(pi);
+        }
+
+        return dependencies;
+    }
+
+    private IBundleModelElement getRequirements() {
+        return requirements;
+    }
+
+    /*
+     * private boolean globMatch(String pkg, Set<String> set) { // exact match
+     * if (set.contains(pkg)) return true;
+     * 
+     * // org.foo.bar matches org.foo. for (String glob : set) { if
+     * (glob.matches(pkg)) { return true; } }
+     * 
+     * return false; }
+     */
+
+    /**
+     * set internal OSGiImport and isDependency flags, based on external
+     * resolution= attribute.
+     * 
+     * OSGiImport: AUTO ALWAYS NEVER dependency: default - compile !dependency:
+     * auto runtime ignore
+     * 
+     */
+    private void setResolve(IPackageImport pi, String resolve) throws IOException {
+        if (pi.isOptional())
+            pi.setDependency(false);
+
+        if (BldAttr.RESOLVE_COMPILE.equals(resolve)) {
+            if (pi.isOptional())
+                pi.setDependency(true);
+            else
+                pi.setOSGiImport(OSGiImport.NEVER);
+        } else if (BldAttr.RESOLVE_RUNTIME.equals(resolve)) {
+            pi.setDependency(false);
+            pi.setOSGiImport(OSGiImport.ALWAYS);
+        } else if (BldAttr.RESOLVE_AUTO.equals(resolve)) {
+            pi.setDependency(false);
+        } else if (BldAttr.RESOLVE_IGNORE.equals(resolve)) {
+            pi.setDependency(false);
+            pi.setOSGiImport(OSGiImport.NEVER);
+        } else if (resolve != null) {
+            throw new IOException("Bad attribute value: " + BldAttr.RESOLVE_ATTRIBUTE + "="
+                    + resolve);
+        }
+    }
+
+    /**
+     * get external resolve= attribute from internal PackageImport flags. This
+     * is called from BldConverter.setBundle().
+     */
+    public static String getResolve(IPackageImport pi, boolean isDependency) {
+        OSGiImport osgiImport = pi.getOSGiImport();
+        String resolve = null;
+
+        if (isDependency) {
+            if (osgiImport.equals(OSGiImport.NEVER) || pi.isOptional())
+                resolve = BldAttr.RESOLVE_COMPILE;
+        } else {
+            switch (osgiImport) {
+            case ALWAYS:
+                resolve = BldAttr.RESOLVE_RUNTIME;
+                break;
+            case AUTO:
+                resolve = BldAttr.RESOLVE_AUTO;
+                break;
+            case NEVER:
+                resolve = BldAttr.RESOLVE_IGNORE;
+                break;
+            }
+        }
+        return resolve;
+    }
+
+    public String getDefaultPackageVersion(String name) {
+        if (packageDefaults == null) {
+            packageDefaults = config.getProps(null, BldConfig.P_PACKAGE_VERSION);
+            packageWildDefaults = new TreeSet<String>();
+
+            for (Object key : packageDefaults.keySet()) {
+                String pkg = (String) key;
+                if (pkg.endsWith("*")) {
+                    packageWildDefaults.add(pkg.substring(0, pkg.length() - 1));
+                }
+            }
+        }
+
+        String version = packageDefaults.getProperty(name);
+
+        if (version == null) {
+            for (String pkg : packageWildDefaults) {
+                if (name.startsWith(pkg)) {
+                    version = packageDefaults.getProperty(pkg + "*");
+                    // break; -- don't break, as we want the longest match
+                }
+            }
+        }
+
+        return version;
+    }
+
+    private synchronized BundleModelElement parseRequirements() throws IOException {
+        BundleModelElement reqs = new BundleModelElement();
+
+        List<String> sourceContents = getSourcePkgs();
+        HashSet<String> exports = new HashSet<String>();
+
+        for (IBldBundle bundle : getBundles()) {
+            for (IPackageExport export : bundle.getExports()) {
+                exports.add(export.getPackageName());
+            }
+        }
+
+        Map<String, Map<String, String>> imports = config.getMap(null, BldConfig.M_IMPORTS);
+
+        for (String name : imports.keySet()) {
+            Map<String, String> attr = imports.get(name);
+
+            String resolve = attr.get(BldAttr.RESOLVE_ATTRIBUTE);
+            String resolution = attr.get(BldAttr.RESOLUTION_ATTRIBUTE);
+            String versions = attr.containsKey(BldAttr.VERSION_ATTRIBUTE) ? attr
+                    .get(BldAttr.VERSION_ATTRIBUTE) : getDefaultPackageVersion(name);
+
+            PackageImport pi = new PackageImport();
+            pi.setPackageName(name);
+
+            // avoid dependency on self-exports
+            // XXX: BldConverter.setBundle contains similar logic
+            if (exports.contains(name)
+                    && (sourceContents.contains(name) || sourceContents.isEmpty())) {
+                pi.setDependency(false);
+                if (versions == null)
+                    versions = getVersion();
+            }
+
+            if (!checkVersionRange(versions)) {
+                throw new IOException("Failed to parse version range for " + resolve
+                        + " missing \"'s around version range?");
+            }
+
+            pi.setVersions(VersionRange.parseVersionRange(versions));
+
+            if (BldAttr.RESOLUTION_OPTIONAL.equals(resolution)) {
+                pi.setOptional(true);
+            } else if (resolution != null) {
+                throw new IOException("Bad attribute value: " + BldAttr.RESOLUTION_ATTRIBUTE + "="
+                        + resolution);
+            }
+
+            setResolve(pi, resolve);
+
+            reqs.addImport(pi);
+        }
+
+        Map<String, Map<String, String>> requires = config.getMap(null, BldConfig.M_REQUIRES);
+        Properties bundleDefaults = config.getProps(null, BldConfig.P_BUNDLE_VERSION);
+
+        if (requires != null) {
+            for (String name : requires.keySet()) {
+                Map<String, String> attr = requires.get(name);
+                String versions = attr.containsKey(BldAttr.VERSION_ATTRIBUTE) ? attr
+                        .get(BldAttr.VERSION_ATTRIBUTE) : bundleDefaults.getProperty(name);
+
+                RequiredBundle rb = new RequiredBundle();
+                rb.setSymbolicName(name);
+                rb.setVersions(VersionRange.parseVersionRange(versions));
+
+                reqs.addRequiredBundle(rb);
+            }
+        }
+
+        for (IBldBundle bundle : getBundles()) {
+            IRequiredBundle fh = bundle.getFragmentHost();
+            if (fh != null)
+                reqs.addRequiredBundle(fh);
+        }
+
+        return reqs;
+    }
+
+    private boolean checkVersionRange(String versions) {
+        if (versions == null || versions.length() == 0) {
+            return true;
+        } else {
+            switch (versions.charAt(0)) {
+            case '(':
+            case '[':
+                switch (versions.charAt(versions.length() - 1)) {
+                case ')':
+                case ']':
+                    return true;
+                default:
+                    return false;
+                }
+            default:
+                return true;
+            }
+        }
+    }
+
+    public List<String> getBundleIds() {
+        List<String> ids = config.getList(null, BldConfig.C_BUNDLES);
+        if (ids == null)
+            return Collections.emptyList();
+        return ids;
+    }
+
+    public List<IBldBundle> getBundles() {
+        ArrayList<IBldBundle> list = new ArrayList<IBldBundle>();
+
+        for (String id : getBundleIds()) {
+            list.add(new BldBundle(id));
+        }
+
+        return list;
+    }
+
+    // Implement IBldConfig: getRepositoryConfig
+
+    public Map<String, Properties> getRepositoryConfig() {
+        HashMap<String, Properties> map = new HashMap<String, Properties>();
+
+        final Map<String, String> env = System.getenv();
+        final Properties props = new Properties();
+        try {
+            // supports ${.} and ${..} expansions
+            props.setProperty(".", resolve(".").getCanonicalPath());
+            props.setProperty("..", resolve("..").getCanonicalPath());
+        } catch (IOException e) {
+        }
+
+        for (String name : config.getList(null, BldConfig.C_REPOSITORIES)) {
+            Properties repo = config.getProps(null, name);
+
+            for (Object k : repo.keySet()) {
+                String key = (String) k;
+                String value = repo.getProperty(key);
+
+                String expand = BldUtil.expand(value, new Properties() {
+                    public String getProperty(String name) {
+                        return props.getProperty(name, env.get(name));
+                    }
+                });
+
+                if (!value.equals(expand)) {
+                    value = expand;
+                    repo.setProperty(key, value);
+                }
+
+                // backwards compatible support before ${.} and ${..} was added
+                if (value.startsWith("./") || value.startsWith("../")) {
+                    try {
+                        // need canonical path, to normalise
+                        value = resolve(value).getCanonicalPath();
+                    } catch (IOException e) {
+                    }
+                    repo.setProperty(key, value);
+                }
+            }
+
+            map.put(name, repo);
+        }
+        return map;
+    }
+
+    public Properties getOptions() {
+        return config.getProps(null, BldConfig.P_OPTION);
+    }
+
+    public Properties getDefaultPackageVersions() {
+        return config.getProps(null, BldConfig.P_PACKAGE_VERSION);
+    }
+
+    public ISigilBundle getDefaultBundle() {
+        List<String> bundles = getBundleIds();
+        if (bundles.isEmpty())
+            return null;
+
+        String id = bundles.get(0);
+        return getSigilBundle(id);
+    }
+
+    public ISigilBundle getSigilBundle(String id) {
+        BldBundle bundle = new BldBundle(id);
+        return convert.getBundle(id, bundle);
+    }
+
+    public void setDefaultBundle(ISigilBundle bundle) {
+        setSigilBundle(null, bundle);
+    }
+
+    public void setSigilBundle(String id, ISigilBundle bundle) {
+        List<String> ids = getBundleIds();
+
+        if (ids.isEmpty()) {
+            ArrayList<String> list = new ArrayList<String>();
+            list.add(id == null ? bundle.getBundleInfo().getSymbolicName() : id);
+            config.setList(null, BldConfig.C_BUNDLES, list);
+        } else if (id == null) {
+            id = ids.get(0);
+        } else if (!ids.contains(id)) {
+            List<String> list = config.getList(null, BldConfig.C_BUNDLES);
+            list.add(id);
+            config.setList(null, BldConfig.C_BUNDLES, list);
+        }
+
+        if (ids.size() == 1)
+            id = null; // don't prefix default bundle with id
+
+        convert.setBundle(id, bundle);
+    }
+
+    public void save() throws IOException {
+        saveAs(new File(loc));
+    }
+
+    public void saveAs(File path) throws IOException {
+        File part = new File(path.getPath() + ".part");
+        saveTo(new FileOutputStream((part)));
+
+        path.delete();
+        if (!part.renameTo(path))
+            throw new IOException("failed to rename " + part + " to " + path);
+    }
+
+    public void saveTo(OutputStream out) {
+        PrintWriter writer = new PrintWriter(new OutputStreamWriter(out));
+        config.write(writer);
+        writer.close();
+    }
+
+    public List<String> getSourceDirs() {
+        List<String> list = config.getList(null, BldConfig.L_SRC_CONTENTS);
+        return list != null ? list : Collections.<String> emptyList();
+    }
+
+    public List<String> getSourcePkgs() {
+        if (sourcePkgs == null) {
+            sourcePkgs = new ArrayList<String>();
+            for (String src : getSourceDirs()) {
+                File dir = resolve(src);
+                if (!dir.isDirectory()) {
+                    System.err.println("WARN: sourcedir does not exist: " + dir);
+                    continue;
+                    // throw new RuntimeException("sourcedir: " + dir +
+                    // " : is not a directory.");
+                }
+                findSrcPkgs(dir, null, sourcePkgs);
+            }
+        }
+
+        return sourcePkgs;
+    }
+
+    private void findSrcPkgs(File dir, String pkg, List<String> result) {
+        ArrayList<File> dirs = new ArrayList<File>();
+        boolean found = false;
+
+        for (String name : dir.list()) {
+            if (name.endsWith(".java")) {
+                found = true;
+            } else if (!name.equals(".svn")) {
+                File d = new File(dir, name);
+                if (d.isDirectory())
+                    dirs.add(d);
+            }
+        }
+
+        if (pkg == null) {
+            pkg = "";
+        } else if (pkg.equals("")) {
+            pkg = dir.getName();
+        } else {
+            pkg = pkg + "." + dir.getName();
+        }
+
+        if (found)
+            result.add(pkg);
+
+        for (File d : dirs)
+            findSrcPkgs(d, pkg, result);
+    }
+
+    /**
+     * BldBundle
+     * 
+     */
+    class BldBundle implements IBldBundle {
+        private String id;
+
+        public BldBundle(String id) {
+            this.id = id;
+        }
+
+        public File resolve(String path) {
+            return BldProject.this.resolve(path);
+        }
+
+        private String getString(String key) {
+            return config.getString(id, key);
+        }
+
+        private List<String> getList(String key) {
+            List<String> list = config.getList(id, key);
+            return list != null ? list : Collections.<String> emptyList();
+        }
+
+        private Map<String, Map<String, String>> getMap(String key) {
+            Map<String, Map<String, String>> map = config.getMap(id, key);
+            return map != null ? map : Collections.<String, Map<String, String>> emptyMap();
+        }
+
+        public String getActivator() {
+            return getString(BldConfig.S_ACTIVATOR);
+        }
+
+        public String getId() {
+            String name = getString("id");
+            return name != null ? name : id;
+        }
+
+        public String getVersion() {
+            String ver = getString(BldConfig.S_VERSION);
+            if (ver == null) {
+                ver = BldProject.this.getVersion();
+            }
+            return ver;
+        }
+
+        public String getSymbolicName() {
+            String name = getString(BldConfig.S_SYM_NAME);
+            return name != null ? name : getId();
+        }
+
+        public List<IPackageExport> getExports() {
+            ArrayList<IPackageExport> list = new ArrayList<IPackageExport>();
+            Map<String, Map<String, String>> exports = getMap(BldConfig.M_EXPORTS);
+
+            if (exports != null) {
+                for (String name : exports.keySet()) {
+                    Map<String, String> attrs = exports.get(name);
+                    PackageExport pkgExport = new PackageExport();
+                    pkgExport.setPackageName(name);
+
+                    String version = attrs.get(BldAttr.VERSION_ATTRIBUTE);
+                    // only default export version from local packages
+                    if (version == null
+                            && (getSourcePkgs().isEmpty() || getSourcePkgs().contains(name))) {
+                        version = getVersion();
+                    }
+
+                    if (version != null)
+                        pkgExport.setVersion(new Version(version));
+
+                    list.add(pkgExport);
+                }
+            }
+
+            return list;
+        }
+
+        public List<IPackageImport> getImports() {
+            ArrayList<IPackageImport> list = new ArrayList<IPackageImport>();
+
+            for (IPackageImport import1 : getRequirements().childrenOfType(IPackageImport.class)) {
+                list.add(import1);
+            }
+
+            return list;
+        }
+
+        public List<IRequiredBundle> getRequires() {
+            ArrayList<IRequiredBundle> list = new ArrayList<IRequiredBundle>();
+            list.addAll(Arrays.asList(getRequirements().childrenOfType(IRequiredBundle.class)));
+
+            for (IBldBundle bundle : getBundles()) {
+                IRequiredBundle fh = bundle.getFragmentHost();
+                if (fh != null)
+                    list.remove(fh);
+            }
+
+            return list;
+        }
+
+        public IRequiredBundle getFragmentHost() {
+            IRequiredBundle fragment = null;
+            Map<String, Map<String, String>> fragments = getMap(BldConfig.M_FRAGMENT);
+            if (fragments != null) {
+                for (String name : fragments.keySet()) {
+                    Map<String, String> attr = fragments.get(name);
+                    String versions = attr.isEmpty() ? null : attr.get(BldAttr.VERSION_ATTRIBUTE);
+                    fragment = new RequiredBundle();
+                    fragment.setSymbolicName(name);
+                    fragment.setVersions(VersionRange.parseVersionRange(versions));
+                    break;
+                }
+            }
+
+            return fragment;
+        }
+
+        public Map<String, Map<String, String>> getLibs() {
+            Map<String, Map<String, String>> libs = getMap(BldConfig.M_LIBS);
+            return (libs != null) ? libs : Collections.<String, Map<String, String>> emptyMap();
+        }
+
+        public List<String> getContents() {
+            return getList(BldConfig.L_CONTENTS);
+        }
+
+        public List<String> getDownloadContents() {
+            return getList(BldConfig.L_DL_CONTENTS);
+        }
+
+        public List<String> getComposites() {
+            ArrayList<String> list = new ArrayList<String>();
+            for (String composite : getList(BldConfig.L_COMPOSITES)) {
+                list.add(composite);
+            }
+
+            return list;
+        }
+
+        public Map<String, String> getResources() {
+            HashMap<String, String> map = new HashMap<String, String>();
+            List<String> resources = getList(BldConfig.L_RESOURCES);
+
+            if (resources != null) {
+                for (String resource : resources) {
+                    String[] paths = resource.split("=", 2);
+                    String fsPath = (paths.length > 1 ? paths[1] : "");
+                    map.put(paths[0], fsPath);
+                }
+            }
+            return map;
+        }
+
+        public Properties getHeaders() {
+            Properties headers = config.getProps(id, BldConfig.P_HEADER);
+            return headers;
+        }
+
+    }
+
+    public long getLastModified() {
+        return lastModified;
+    }
+
+}

Added: felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/BldUtil.java
URL: http://svn.apache.org/viewvc/felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/BldUtil.java?rev=793581&view=auto
==============================================================================
--- felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/BldUtil.java (added)
+++ felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/BldUtil.java Mon Jul 13 13:25:46 2009
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.cauldron.bld.config;
+
+import java.util.Map;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+// taken from Newton Launcher
+
+public class BldUtil {
+    /**
+     * expands property references embedded in strings. Each occurrence of ${name} is replaced with the value of
+     * p.getProperty("name"); If the property is not set, then the original reference, is returned as follows "?<name>".
+     * 
+     * Strings to be expanded should not contain $ or }, except to indicate expansions.
+     * 
+     * Value is expanded recursively and so can contain further ${name} references. Also supports shell-expansions
+     * ${name:-value}, ${name:=value} and ${name:+value}.
+     * 
+     * <pre>
+     *      ${parameter}
+     *      The value of parameter is substituted.
+     *      ${parameter:-word}
+     *      Use  Default  Values.  If parameter is null, the expansion of word
+     *      is substituted.  Otherwise, the value of  parameter is substituted.
+     *      ${parameter:=word}
+     *      Assign  Default  Values.   If  parameter is null, the expansion of
+     *      word is assigned to parameter.  The value of parameter  is  then
+     *      substituted.
+     *      ${parameter:+word}
+     *      Use Alternate Value.  If parameter is null, nothing  is
+     *      substituted, otherwise the expansion of word is substituted.
+     *      ${parameter:?word}
+     *      Raise Error.  If parameter is null, a RuntimeException is thown,
+     *      with word as the message.
+     * </pre>
+     */
+    public static String expand(String s, Properties p) {
+        // regex to match property references e.g. ${name}
+        // TODO this is very simplistic, so strings to be expanded should not
+        // contain $ or }, except where substitution is expected.
+	// Update: propRef regex now allows substitutions to contain $,
+	// e.g. where a Windows ${user.name} is $Admin or similar.
+        final Pattern propRef = Pattern.compile("\\$\\{(((\\$[^\\{\\}])|[^\\$\\}])+\\$?)\\}");
+        final Pattern backslash = Pattern.compile("\\\\");
+        final Pattern dollar = Pattern.compile("\\$");
+
+        if (s == null) {
+            return null;
+        }
+
+        if (s.indexOf("${") == -1) { // shortcut if no expansions
+            return s;
+        }
+
+        for (int i = 0; i < 20; i++) { // avoids self-referencing expansions
+            // System.out.println("XXX expand[" + i + "] = [" + s + "]");
+            Matcher matcher = propRef.matcher(s);
+
+            if (!matcher.find()) {
+                // replace unmatched items
+                s = s.replaceAll("\\Q??[\\E", "\\${");
+                s = s.replaceAll("\\Q??]\\E", "}");
+                // debug("expanded: " + s);
+                if (s.indexOf("${") != -1) {
+                    throw new RuntimeException("Can't expand: " + s);
+                }
+                return s;
+            }
+
+            String key = matcher.group(1);
+            String[] keydef = key.split(":[=+-?@]", 2);
+            String replace;
+
+            if (keydef.length != 2) {
+                replace = key.length() == 0 ? null : p.getProperty(key);
+            }
+            else {
+                replace = keydef[0].length() == 0 ? null : p.getProperty(keydef[0]);
+
+                if (replace != null && (replace.length() == 0 || replace.indexOf("${") != -1)) {
+                    // don't want unexpanded replacement, as it may stop ${...:-default}
+                    replace = null;
+                }
+
+                if (key.indexOf(":+") != -1) {
+                    replace = ((replace == null) ? "" : keydef[1]);
+                }
+                else if (replace == null) {
+                    replace = keydef[1];
+
+                    if (key.indexOf(":?") != -1) {
+                        String msg = "${" + keydef[0] + ":?" + keydef[1] + "} property not set";
+                        throw new RuntimeException(msg);
+                    }
+
+                    if (key.indexOf(":=") != -1) {
+                        p.setProperty(keydef[0], keydef[1]);
+                    }
+                }
+            }
+
+            if (replace == null) {
+                // TODO: this is a hack to avoid looping on unmatched references
+                // should really leave unchanged and process rest of string.
+                // We use "]" as delimiter to avoid non-matched "}"
+                // terminating potential _propRef match
+                replace = "??[" + key + "??]";
+            }
+
+            // Excerpt from replaceAll() javadoc:
+            //
+            // Note that backslashes (\) and dollar signs ($) in the replacement
+            // string may cause the results to be different than if it were
+            // being
+            // treated as a literal replacement string. Dollar signs may be
+            // treated
+            // as references to captured subsequences, and backslashes are used
+            // to
+            // escape literal characters in the replacement string.
+            // escape any \ or $ in replacement string
+            replace = backslash.matcher(replace).replaceAll("\\\\\\\\");
+            replace = dollar.matcher(replace).replaceAll("\\\\\\$");
+
+            s = s.replaceAll("\\Q${" + key + "}\\E", replace);
+        }
+
+        throw new RuntimeException("expand: loop expanding: " + s);
+    }
+
+    public static String expand(String s) {
+        final Map<String, String> env = System.getenv();
+
+        return expand(s, new Properties() {
+            public String getProperty(String name) {
+                return System.getProperty(name, env.get(name));
+            }
+        });
+    }
+
+}

Added: felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/IBldProject.java
URL: http://svn.apache.org/viewvc/felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/IBldProject.java?rev=793581&view=auto
==============================================================================
--- felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/IBldProject.java (added)
+++ felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/IBldProject.java Mon Jul 13 13:25:46 2009
@@ -0,0 +1,207 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.cauldron.bld.config;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.cauldron.sigil.model.eclipse.ISigilBundle;
+import org.cauldron.sigil.model.osgi.IBundleModelElement;
+import org.cauldron.sigil.model.osgi.IPackageExport;
+import org.cauldron.sigil.model.osgi.IPackageImport;
+import org.cauldron.sigil.model.osgi.IRequiredBundle;
+
+public interface IBldProject {
+	
+	static final String PROJECT_FILE = "sigil.properties";
+	static final String PROJECT_DEFAULTS = "../sigil-defaults.properties";
+	
+	void save() throws IOException;
+	
+	void saveAs(File path) throws IOException;
+	
+	void saveTo(OutputStream out) throws IOException;
+	
+	/**
+	 * gets default package version ranges.
+	 */
+	Properties getDefaultPackageVersions();
+	
+	/**
+	 * gets default package version range for named package.
+	 * Also handles wildcards in defaults.
+	 */
+	String getDefaultPackageVersion(String name);
+	
+	/**
+	 * get project options.
+	 */
+	Properties getOptions();
+	
+	/**
+	 * get project version.
+	 */
+	String getVersion();
+	
+	/**
+	 * gets dependencies (Package-Import and Require-Bundle) needed to compile.
+	 */
+	IBundleModelElement getDependencies();
+	
+	/**
+	 * gets project source directories.
+	 * This is a convenient way to specify bundle contents
+	 * when the project doesn't contains multiple bundles.
+	 */
+	List<String> getSourceDirs();
+	
+	/**
+	 * gets the list of packages represented by getSourceDirs().
+	 * @throws IOException 
+	 */
+	List<String> getSourcePkgs();
+	
+	/**
+	 * gets bundle ids.
+	 */
+	List<String> getBundleIds();
+	
+	/**
+	 * gets bundles.
+	 */
+	List<IBldBundle> getBundles();
+	
+	/**
+	 * convert specified bundle to SigilBundle.
+	 */
+	ISigilBundle getSigilBundle(String id);
+	
+	/**
+	 * convert SigilBundle to specified bundle.
+	 */
+	void setSigilBundle(String id, ISigilBundle sb);
+	
+	/**
+	 * converts default bundle to SigilBundle.
+	 */
+	ISigilBundle getDefaultBundle();
+	
+	/**
+	 * converts SigilBundle to default bundle.
+	 */
+	void setDefaultBundle(ISigilBundle sb);
+	
+	/**
+	 * resolves a relative path against the project file location.
+	 */
+	File resolve(String path);
+	
+	/**
+	 * gets the last modification date of the project file.
+	 */
+	long getLastModified();
+	
+	interface IBldBundle {
+		/**
+		 * gets bundle activator
+		 */
+		String getActivator();
+		
+		/**
+		 * gets bundle id within project.
+		 */
+		String getId();
+		
+		/**
+		 * gets bundle version.
+		 */
+		String getVersion();
+		
+		/**
+		 * gets the Bundle-SymbolicName.
+		 */
+		String getSymbolicName();
+
+		/**
+		 * gets bundles export-packages.
+		 */
+		List<IPackageExport> getExports();
+		
+		/**
+		 * gets project import-packages. 
+		 */
+		List<IPackageImport> getImports();
+		
+		/**
+		 * gets project require-bundles. 
+		 */
+		List<IRequiredBundle> getRequires();
+		
+		/**
+		 * get bundle fragment-host. 
+		 */
+		IRequiredBundle getFragmentHost();
+		
+		/**
+		 * gets bundle libs. 
+		 */
+		Map<String, Map<String, String>> getLibs();
+	
+		/**
+		 * gets the bundle contents
+		 * @return list of package patterns.
+		 */
+		List<String> getContents();
+		
+		/**
+		 * gets the bundle's associated dljar contents.
+		 * This is a convenience which avoids having to define another bundle
+		 * just for the dljar, which is then added to the parent bundle.
+		 * @return list of package patterns.
+		 */
+		List<String> getDownloadContents();
+	
+		/**
+		 * gets SCA composites.
+		 */
+		List<String> getComposites();
+		
+		/**
+		 * gets the additional resources.
+		 * @return map with key as path in bundle, value as path in file system.
+		 * Paths are resolved relative to location of project file and also from classpath.
+		 */
+		Map<String,String> getResources();
+		
+		/**
+		 * gets additional bundle headers.
+		 */
+		Properties getHeaders();
+		
+		/**
+		 * resolves a relative path against the project file location.
+		 */
+		File resolve(String path);
+	}
+}

Added: felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/IRepositoryConfig.java
URL: http://svn.apache.org/viewvc/felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/IRepositoryConfig.java?rev=793581&view=auto
==============================================================================
--- felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/IRepositoryConfig.java (added)
+++ felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/config/IRepositoryConfig.java Mon Jul 13 13:25:46 2009
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.cauldron.bld.config;
+
+import java.util.Map;
+import java.util.Properties;
+
+public interface IRepositoryConfig {
+	static final String REPOSITORY_PROVIDER = "provider";
+	static final String REPOSITORY_LEVEL = "level";
+
+	/**
+	 * get properties with which to instantiate repositories.
+	 * The key REPOSITORY_PROVIDER will be set to the fully qualified class name of the IRepositoryProvider.
+	 * The key REPOSITORY_LEVEL indicates repository search order.
+	 * @return
+	 */
+	Map<String,Properties> getRepositoryConfig();
+}

Added: felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/core/BldCore.java
URL: http://svn.apache.org/viewvc/felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/core/BldCore.java?rev=793581&view=auto
==============================================================================
--- felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/core/BldCore.java (added)
+++ felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/core/BldCore.java Mon Jul 13 13:25:46 2009
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.cauldron.bld.core;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.cauldron.bld.core.internal.license.LicenseManager;
+import org.cauldron.bld.core.internal.model.eclipse.DownloadJar;
+import org.cauldron.bld.core.internal.model.eclipse.Library;
+import org.cauldron.bld.core.internal.model.eclipse.LibraryImport;
+import org.cauldron.bld.core.internal.model.eclipse.SigilBundle;
+import org.cauldron.bld.core.internal.model.osgi.BundleModelElement;
+import org.cauldron.bld.core.internal.model.osgi.PackageExport;
+import org.cauldron.bld.core.internal.model.osgi.PackageImport;
+import org.cauldron.bld.core.internal.model.osgi.RequiredBundle;
+import org.cauldron.bld.core.licence.ILicenseManager;
+import org.cauldron.sigil.model.ModelElementFactory;
+import org.cauldron.sigil.model.eclipse.IDownloadJar;
+import org.cauldron.sigil.model.eclipse.ILibrary;
+import org.cauldron.sigil.model.eclipse.ILibraryImport;
+import org.cauldron.sigil.model.eclipse.INewtonSystem;
+import org.cauldron.sigil.model.eclipse.ISCAComposite;
+import org.cauldron.sigil.model.eclipse.ISigilBundle;
+import org.cauldron.sigil.model.osgi.IBundleModelElement;
+import org.cauldron.sigil.model.osgi.IPackageExport;
+import org.cauldron.sigil.model.osgi.IPackageImport;
+import org.cauldron.sigil.model.osgi.IRequiredBundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class BldCore implements BundleActivator {
+	private static LicenseManager licenceManager = new LicenseManager();
+	
+	private static final Logger log = Logger.getLogger(BldCore.class.getName());
+
+	public static void error(String string, Throwable e) {
+		// TODO 
+		log.log( Level.WARNING, string, e );
+	}
+
+	public static void error(String string) {
+		log.log( Level.WARNING, string );
+	}
+
+	public static ILicenseManager getLicenseManager() {
+		return licenceManager;
+	}
+
+	public void start(BundleContext context) throws Exception {
+		init();
+	}
+	
+	public static void init() throws Exception {
+		String uri = "http://sigil.codecauldron.org/xml/sigil-namespace";
+		ModelElementFactory.getInstance().register(ISigilBundle.class,
+				SigilBundle.class, "bundle", "sigil", uri);
+		ModelElementFactory.getInstance().register(IDownloadJar.class,
+				DownloadJar.class, "download", "sigil", uri);
+		ModelElementFactory.getInstance().register(ILibrary.class,
+				Library.class, "library", "sigil", uri);
+		ModelElementFactory.getInstance().register(ILibraryImport.class,
+				LibraryImport.class, "library-import", "sigil", uri);
+		
+		// osgi elements
+		ModelElementFactory.getInstance().register(IBundleModelElement.class,
+				BundleModelElement.class, "bundle", null, null);
+		ModelElementFactory.getInstance().register(IPackageExport.class,
+				PackageExport.class, "package.export", null, null);
+		ModelElementFactory.getInstance().register(IPackageImport.class,
+				PackageImport.class, "package.import", null, null);
+		ModelElementFactory.getInstance().register(IRequiredBundle.class,
+				RequiredBundle.class, "required.bundle", null, null);
+	}
+
+	public void stop(BundleContext context) throws Exception {
+		// TODO Auto-generated method stub
+		
+	}
+
+}

Added: felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/core/internal/license/LicenseManager.java
URL: http://svn.apache.org/viewvc/felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/core/internal/license/LicenseManager.java?rev=793581&view=auto
==============================================================================
--- felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/core/internal/license/LicenseManager.java (added)
+++ felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/core/internal/license/LicenseManager.java Mon Jul 13 13:25:46 2009
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.cauldron.bld.core.internal.license;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import org.cauldron.bld.core.licence.ILicenseManager;
+import org.cauldron.bld.core.licence.ILicensePolicy;
+//import org.cauldron.sigil.model.project.ISigilProjectModel;
+
+public class LicenseManager implements ILicenseManager {
+
+	private HashMap<String, Pattern> licenses = new HashMap<String, Pattern>();
+	private HashMap<String, LicensePolicy> policies = new HashMap<String, LicensePolicy>();
+	private LicensePolicy defaultPolicy = new LicensePolicy(this);
+	
+	public void addLicense(String name, Pattern pattern) {
+		licenses.put( name, pattern );
+	}
+
+	public void removeLicense(String name) {
+		licenses.remove(name);
+	}
+
+	public Set<String> getLicenseNames() {
+		return Collections.unmodifiableSet(licenses.keySet());
+	}
+
+	public Pattern getLicensePattern(String name) {
+		return licenses.get( name );
+	}
+
+	public ILicensePolicy getDefaultPolicy() {
+		return defaultPolicy;
+	}
+
+	//public ILicensePolicy getPolicy(ISigilProjectModel project) {
+	//	synchronized( policies ) {
+	//		LicensePolicy p = policies.get(project.getName());
+	//		
+	//		if ( p == null ) {
+	//			p = new LicensePolicy(this, project);
+	//			policies.put( project.getName(), p );
+	//		}
+	//		
+	//		return p;
+	//	}
+	//}
+
+}

Added: felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/core/internal/license/LicensePolicy.java
URL: http://svn.apache.org/viewvc/felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/core/internal/license/LicensePolicy.java?rev=793581&view=auto
==============================================================================
--- felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/core/internal/license/LicensePolicy.java (added)
+++ felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/core/internal/license/LicensePolicy.java Mon Jul 13 13:25:46 2009
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.cauldron.bld.core.internal.license;
+
+import org.cauldron.bld.core.licence.ILicensePolicy;
+import org.cauldron.sigil.model.eclipse.ISigilBundle;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+public class LicensePolicy implements ILicensePolicy {
+
+	private LicenseManager licenseManager;
+	
+	public LicensePolicy(LicenseManager licenseManager) {
+		this.licenseManager = licenseManager;
+	}
+
+	public boolean accept(ISigilBundle bundle) {
+		return true;
+	}
+
+	public void addAllowed(String licenseName) {
+		// TODO Auto-generated method stub
+		
+	}
+
+	public void removeAllowed(String licenseName) {
+		// TODO Auto-generated method stub
+		
+	}
+
+	public void save(IProgressMonitor monitor) {
+		// TODO Auto-generated method stub
+		
+	}
+
+}

Added: felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/core/internal/model/eclipse/DownloadJar.java
URL: http://svn.apache.org/viewvc/felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/core/internal/model/eclipse/DownloadJar.java?rev=793581&view=auto
==============================================================================
--- felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/core/internal/model/eclipse/DownloadJar.java (added)
+++ felix/trunk/sigil/org.cauldron.bld.core/src/org/cauldron/bld/core/internal/model/eclipse/DownloadJar.java Mon Jul 13 13:25:46 2009
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.cauldron.bld.core.internal.model.eclipse;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.cauldron.sigil.model.AbstractCompoundModelElement;
+import org.cauldron.sigil.model.eclipse.IDownloadJar;
+import org.eclipse.core.runtime.IPath;
+
+public class DownloadJar extends AbstractCompoundModelElement implements IDownloadJar {
+
+	private static final long serialVersionUID = 1L;
+
+	private Set<IPath> entries = new HashSet<IPath>();
+	
+	public DownloadJar() {
+		super("RMI Classpath Download Jar");
+	}
+	
+	public void addEntry(IPath entry) {
+		entries.add( entry );
+	}
+	
+	public void removeEntry(IPath entry) {
+		entries.remove( entry );
+	}
+	
+	public Set<IPath> getEntrys() {
+		return entries;
+	}
+
+	public void clearEntries() {
+		entries.clear();
+	}
+}