• Intro Headers Instructions Macros
  • Fork me on GitHub
    • Release
    • Introduction
    • How to install bnd
    • Guided Tour
    • Guided Tour Workspace & Projects
    • Concepts
    • Best practices
    • Build
    • Generating JARs
    • Versioning
    • Baselining
    • Service Components
    • Metatype
    • Contracts
    • Manifest Annotations
    • Resolving Dependencies
    • Launching
    • Testing
    • Packaging Applications
    • Wrapping Libraries to OSGi Bundles
    • From the command line
    • For Developers
    • Plugins
    • Tools bound to bnd
    • File Format
    • Header Reference
    • Instruction
    • Instruction Index
    • Macro Reference
    • Command Reference
    • Plugins Reference
    • Settings
    • Errors
    • Warnings
    • Frequently Asked Questions
    Supported by OSGi enRoute
  • -includeresource

    /**
     * Parse the Bundle-Includes header. Files in the bundles Include header are
     * included in the jar. The source can be a directory or a file.
     *
     * @throws IOException
     * @throws FileNotFoundException
     */
    private void doIncludeResources(Jar jar) throws Exception {
    	String includes = getProperty("Bundle-Includes");
    	if (includes == null) {
    		includes = getProperty(INCLUDERESOURCE);
    		if (includes == null || includes.length() == 0)
    			includes = getProperty(Constants.INCLUDE_RESOURCE);
    	} else
    		warning("Please use -includeresource instead of Bundle-Includes");
    
    	doIncludeResource(jar, includes);
    
    }
    
    private void doIncludeResource(Jar jar, String includes) throws Exception {
    	Parameters clauses = parseHeader(includes);
    	doIncludeResource(jar, clauses);
    }
    
    private void doIncludeResource(Jar jar, Parameters clauses) throws ZipException, IOException, Exception {
    	for (Entry<String,Attrs> entry : clauses.entrySet()) {
    		doIncludeResource(jar, entry.getKey(), entry.getValue());
    	}
    }
    
    private void doIncludeResource(Jar jar, String name, Map<String,String> extra) throws ZipException, IOException,
    		Exception {
    
    	Instructions preprocess = null;
    	boolean absentIsOk = false;
    
    	if (name.startsWith("{") && name.endsWith("}")) {
    		preprocess = getPreProcessMatcher(extra);
    		name = name.substring(1, name.length() - 1).trim();
    	}
    
    	String parts[] = name.split("\\s*=\\s*");
    	String source = parts[0];
    	String destination = parts[0];
    	if (parts.length == 2)
    		source = parts[1];
    
    	if (source.startsWith("-")) {
    		source = source.substring(1);
    		absentIsOk = true;
    	}
    
    	if (source.startsWith("@")) {
    		extractFromJar(jar, source.substring(1), parts.length == 1 ? "" : destination, absentIsOk);
    	} else if (extra.containsKey("cmd")) {
    		doCommand(jar, source, destination, extra, preprocess, absentIsOk);
    	} else if (extra.containsKey(LITERAL_ATTRIBUTE)) {
    		String literal = extra.get(LITERAL_ATTRIBUTE);
    		Resource r = new EmbeddedResource(literal.getBytes("UTF-8"), 0);
    		String x = extra.get("extra");
    		if (x != null)
    			r.setExtra(x);
    		jar.putResource(name, r);
    	} else {
    		File sourceFile;
    		String destinationPath;
    
    		sourceFile = getFile(source);
    		if (parts.length == 1) {
    			// Directories should be copied to the root
    			// but files to their file name ...
    			if (sourceFile.isDirectory())
    				destinationPath = "";
    			else
    				destinationPath = sourceFile.getName();
    		} else {
    			destinationPath = parts[0];
    		}
    		// Handle directories
    		if (sourceFile.isDirectory()) {
    			destinationPath = doResourceDirectory(jar, extra, preprocess, sourceFile, destinationPath);
    			return;
    		}
    
    		// destinationPath = checkDestinationPath(destinationPath);
    
    		if (!sourceFile.exists()) {
    			if (absentIsOk)
    				return;
    
    			noSuchFile(jar, name, extra, source, destinationPath);
    		} else
    			copy(jar, destinationPath, sourceFile, preprocess, extra);
    	}
    }
    
    private Instructions getPreProcessMatcher(Map<String,String> extra) {
    	if (defaultPreProcessMatcher == null) {
    		defaultPreProcessMatcher = new Instructions(getProperty(PREPROCESSMATCHERS,
    				Constants.DEFAULT_PREPROCESSS_MATCHERS));
    	}
    	if (extra == null)
    		return defaultPreProcessMatcher;
    
    	String additionalMatchers = extra.get(PREPROCESSMATCHERS);
    	if (additionalMatchers == null)
    		return defaultPreProcessMatcher;
    
    	Instructions specialMatcher = new Instructions(additionalMatchers);
    	specialMatcher.putAll(defaultPreProcessMatcher);
    	return specialMatcher;
    }
    
    /**
     * It is possible in Include-Resource to use a system command that generates
     * the contents, this is indicated with {@code cmd} attribute. The command
     * can be repeated for a number of source files with the {@code for}
     * attribute which indicates a list of repetitions, often down with the
     * {@link Macro#_lsa(String[])} or {@link Macro#_lsb(String[])} macro. The
     * repetition will repeat the given command for each item. The @} macro can
     * be used to replace the current item. If no {@code for} is given, the
     * source is used as the only item. If the destination contains a macro,
     * each iteration will create a new file, otherwise the destination name is
     * used.
     *
     * @param jar
     * @param source
     * @param destination
     * @param extra
     * @param preprocess
     * @param absentIsOk
     * @throws Exception
     */
    private void doCommand(Jar jar, String source, String destination, Map<String,String> extra,
    		Instructions preprocess, boolean absentIsOk) throws Exception {
    	String repeat = extra.get("for"); // TODO constant
    	if (repeat == null)
    		repeat = source;
    
    	Collection<String> requires = split(extra.get("requires"));
    	long lastModified = 0;
    	for (String required : requires) {
    		File file = getFile(required);
    		if (!file.exists()) {
    			error(Constants.INCLUDE_RESOURCE + ".cmd for %s, requires %s, but no such file %s", source, required,
    					file.getAbsoluteFile());
    		} else
    			lastModified = findLastModifiedWhileOlder(file, lastModified());
    	}
    
    	String cmd = extra.get("cmd");
    
    	List<String> paths = new ArrayList<String>();
    
    	for (String item : Processor.split(repeat)) {
    		File f = IO.getFile(item);
    		traverse(paths, f);
    	}
    
    	CombinedResource cr = null;
    
    	if (!destination.contains("${@}")) {
    		cr = new CombinedResource();
    		cr.lastModified = lastModified;
    	}
    
    	setProperty("@requires", join(requires, " "));
    	try {
    		for (String item : paths) {
    			setProperty("@", item);
    			try {
    				String path = getReplacer().process(destination);
    				String command = getReplacer().process(cmd);
    				File file = getFile(item);
    				if (file.exists())
    					lastModified = Math.max(lastModified, file.lastModified());
    
    				CommandResource cmdresource = new CommandResource(command, this, lastModified, getBase());
    
    				Resource r = cmdresource;
    
    				// Turn this resource into a file resource
    				// so we execute the command now and catch its
    				// errors
    				FileResource fr = new FileResource(r);
    
    				addClose(fr);
    				r = fr;
    
    				if (preprocess != null && preprocess.matches(path))
    					r = new PreprocessResource(this, r);
    
    				if (cr == null)
    					jar.putResource(path, r);
    				else
    					cr.addResource(r);
    			}
    			finally {
    				unsetProperty("@");
    			}
    		}
    	}
    	finally {
    		unsetProperty("@requires");
    	}
    
    	// Add last so the correct modification date is used
    	// to update the modified time.
    	if (cr != null)
    		jar.putResource(destination, cr);
    
    	updateModified(lastModified, Constants.INCLUDE_RESOURCE + ": cmd");
    }
    
    private void traverse(List<String> paths, File item) {
    
    	if (item.isDirectory()) {
    		for (File sub : item.listFiles()) {
    			traverse(paths, sub);
    		}
    	} else if (item.isFile())
    		paths.add(item.getAbsolutePath());
    	else
    		paths.add(item.getName());
    }
    
    
    
    
    	public class MakeBnd implements MakePlugin, Constants {
    		final static Pattern	JARFILE	= Pattern.compile("(.+)\\.(jar|ipa)");
    
    		public Resource make(Builder builder, String destination, Map<String,String> argumentsOnMake) throws Exception {
    			String type = argumentsOnMake.get("type");
    			if (!"bnd".equals(type))
    				return null;
    
    			String recipe = argumentsOnMake.get("recipe");
    			if (recipe == null) {
    				builder.error("No recipe specified on a make instruction for " + destination);
    				return null;
    			}
    			File bndfile = builder.getFile(recipe);
    			if (bndfile.isFile()) {
    				// We do not use a parent because then we would
    				// build ourselves again. So we can not blindly
    				// inherit the properties.
    				Builder bchild = builder.getSubBuilder();
    				bchild.removeBundleSpecificHeaders();
    
    				// We must make sure that we do not include ourselves again!
    				bchild.setProperty(Analyzer.INCLUDE_RESOURCE, "");
    				bchild.setProperty(Analyzer.INCLUDERESOURCE, "");
    				bchild.setProperties(bndfile, builder.getBase());
    
    				Jar jar = bchild.build();
    				Jar dot = builder.getTarget();
    
    				if (builder.hasSources()) {
    					for (String key : jar.getResources().keySet()) {
    						if (key.startsWith("OSGI-OPT/src"))
    							dot.putResource(key, jar.getResource(key));
    					}
    				}
    				builder.getInfo(bchild, bndfile.getName() + ": ");
    				return new JarResource(jar);
    			}
    			return null;
    		}
    
    	}
    
    • Contact
    • Developers
    • More