Overview

The sigil-ivy-plugin integrates Sigil with Apache Ivy. If you are not familiar with Ivy, you should visit their tutorial.

Sigil provides a custom Ivy resolver, which allows Ivy to resolve dependencies specified as OSGi Package-Imports, rather than as specific jar artifacts. This avoids the duplication and possible error of having to specify build dependencies separately from OSGi runtime dependencies.

The plugin works by intercepting the ivy.xml parser and dynamically replacing any dependencies with the results of resolving the OSGi Package-Imports specified in sigil.properties. Sigil can resolve dependencies using a local directory of OSGi bundles, or using an OBR repository.

The plugin also provides an Ant task to generate (multiple) OSGi bundles from each sigil.properties file using Bnd. sigil.properties is similar to .bnd instruction files, but it supports multiple bundles.

This Quick Start is based on the Ivy project dependencies tutorial, modified to use Sigil. The modified example is in example/dependence in the Sigil download.

Shared Configuration

ivysettings.properties

You will need to change ivy.jar to point to the location of your Ivy jar. If you don't have Ivy, you can download it from http://ant.apache.org/ivy/download.cgi.

repository.dir=${ivy.settings.dir}/repository
sigil-ivy-plugin.jar=${ivy.settings.dir}/../../../lib/sigil-ivy-plugin.jar
ivy.jar=/opt/apache-ivy-2.0.0-rc2/ivy-2.0.0-rc2.jar

ivysettings.xml

The lines containing "sigil" need to be added to your ivysettings.xml:

  • classpath - this references the location of the sigil-ivy-plugin.jar
  • typedef - this defines the sigil-parser and sigil-resolver
  • parsers - the sigil-parser must be the last parser in the parsers section
  • resolvers - the sigil-resolver requires a config attribute to specify the repository configuration file
  • modules - the modules entry ensures that the sigil-resolver is used to resolve the injected dependencies
<ivysettings>
    <properties file="${ivy.settings.dir}/ivysettings.properties"/>
    <settings defaultResolver="projects"/>
    <caches defaultCacheDir="${ivy.settings.dir}/ivy-cache" />

    <classpath file="${sigil-ivy-plugin.jar}" />
    <typedef name="sigil-parser" classname="org.cauldron.bld.ivy.SigilParser" />
    <typedef name="sigil-resolver" classname="org.cauldron.bld.ivy.SigilResolver" />

    <parsers>
        <sigil-parser/>
    </parsers>

    <resolvers>
        <sigil-resolver name="sigil" config="${ivy.settings.dir}/sigil-repos.properties" />
        <filesystem name="projects">
            <artifact pattern="${repository.dir}/[artifact]-[revision].[ext]" />
            <ivy pattern="${repository.dir}/[module]-[revision].xml" />
        </filesystem>
    </resolvers>

    <modules>
        <module organisation="sigil" name="*" resolver="sigil"/>
    </modules>
</ivysettings>

sigil-repos.properties

This file contains the definition of the Sigil repositories. It is referenced via the config attribute on the sigil-resolver in ivysettings.xml.

The repositories defined are:

  • system - resolves internal Java packages, such as javax.swing and optionally packages from bundle 0 of an OSGi framework provider
  • project - resolves against exports in sigil.properties of other projects. This allows Ivy to automatically determine the correct build order.
  • spring - this resolves against an OBR index for the SpringSource Enterprise Repository.

It's also possible to define a filesystem repository based on a local directory containing bundles.

# repository config

-repositories:  system, project, spring

system;provider:        system
system;level:           -1

project;provider:       project
project;level:  0
project;pattern:        ../*/[sigilproject]

spring;provider:        obr
spring;level:           2
spring;url:             http://sigil.codecauldron.org/spring-repository.obr
spring;index:           ../settings/spring-repository.obr

Project Configuration

build.xml

The sigil-ivy-plugin provides an Ant task to build bundles using Bnd. It requires bndlib.jar, which is on the manifest Class-Path, so you don't need to explicitly add bndlib.jar to the classpath, as long as it is present in the same directory as sigil-ivy-plugin.jar.

<taskdef name="sigil.bundle"
    classname="org.cauldron.bld.ant.BundleTask"
    classpath="${sigil-ivy-plugin.jar}"/>

<target name="jar" depends="compile">
    <sigil.bundle destpattern="${build.dir}/[id].[ext]"
                 classpathref="run.path.id" />
</target>

ivy.xml

The ivy.xml for the dependee project is unchanged (but, by default, Sigil ignores any dependences it contains).

<ivy-module version="1.0">
    <info organisation="org.apache" module="dependee"/>
    <dependencies>
        <dependency org="commons-lang" name="commons-lang" rev="2.0"/>
    </dependencies>
</ivy-module>

sigil.properties

Placing a sigil.properties file next to an ivy.xml file, causes the sigil-parser to dynamically replace the dependencies contained in ivy.xml with dependencies determined from the -imports property in sigil.properties.

# dependee sigil.properties

version: 1.0.0

-bundles: dependee

-exports: standalone

-imports: \
  org.apache.commons.lang;version="[2.0.0,2.4.0)", \

-resources: \
  version.properties

Project Build

$ cd dependee
$ ant jar
Buildfile: build.xml

init:

resolve:
[ivy:retrieve] :: Ivy 2.0.0-rc2 - 20081028224207 :: http://ant.apache.org/ivy/ ::
:: loading settings :: file = /Volumes/Users/derek/sigil-0.7.0/example/dependence/settings/ivysettings.xml
[ivy:retrieve] Sigil: augmenting module=dependee ant.project.name=dependee
[ivy:retrieve] Sigil: loading Project Repository: /Volumes/Users/derek/sigil-0.7.0/example/dependence/*/sigil.properties
[ivy:retrieve] :: resolving dependencies :: org.apache#dependee;working@rodney
[ivy:retrieve]  confs: [default]
[ivy:retrieve] Sigil: augmenting module=com.springsource.org.apache.commons.lang ant.project.name=dependee
[ivy:retrieve]  found sigil#com.springsource.org.apache.commons.lang;2.1.0 in sigil
[ivy:retrieve] downloading http://repository.springsource.com/ivy/bundles/external/org.apache.commons/
    com.springsource.org.apache.commons.lang/2.1.0/com.springsource.org.apache.commons.lang-2.1.0.jar ...
[ivy:retrieve]  [SUCCESSFUL ] sigil#com.springsource.org.apache.commons.lang;2.1.0!com.springsource.org.apache.commons.lang.jar (2619ms)
[ivy:retrieve] :: resolution report :: resolve 232ms :: artifacts dl 2620ms
        ---------------------------------------------------------------------
        |                  |            modules            ||   artifacts   |
        |       conf       | number| search|dwnlded|evicted|| number|dwnlded|
        ---------------------------------------------------------------------
        |      default     |   1   |   1   |   1   |   0   ||   1   |   1   |
        ---------------------------------------------------------------------
[ivy:retrieve] :: retrieving :: org.apache#dependee
[ivy:retrieve]  confs: [default]
[ivy:retrieve]  1 artifacts copied, 0 already retrieved (204kB/11ms)

compile:
    [mkdir] Created dir: /Volumes/Users/derek/sigil-0.7.0/example/dependence/dependee/build/classes
    [javac] Compiling 1 source file to /Volumes/Users/derek/sigil-0.7.0/example/dependence/dependee/build/classes

jar:
[propertyfile] Creating new property file: /Volumes/Users/derek/sigil-0.7.0/example/dependence/dependee/build/classes/version.properties
[sigil.bundle] creating bundle: dependee
[sigil.bundle] dependee: 0 errors, 0 warnings

BUILD SUCCESSFUL
Total time: 6 seconds

Notice how

-imports: \
  org.apache.commons.lang;version="[2.0.0,2.4.0)"

in sigil.properties is resolved to com.springsource.org.apache.commons.lang-2.1.0.jar, using the OBR resolver.

The dependencies in ivy.xml are ignored by default, you can retain them by setting the keepDependencies attribute on the sigil-parser.

Now let's pretend that we've added some code which requires the following imports in sigil.properties:

-imports: \
  org.apache.commons.lang;version="[2.0.0,2.4.0)", \
  javax.servlet;version="(2.4,3.0]", \
  org.apache.log4j;version="[1.2.14,1.3)", \
  org.apache.commons.logging
$ ant jar
Buildfile: build.xml

init:

resolve:
[ivy:retrieve] :: Ivy 2.0.0-rc2 - 20081028224207 :: http://ant.apache.org/ivy/ ::
:: loading settings :: file = /Volumes/Users/derek/sigil-0.7.0/example/dependence/settings/ivysettings.xml
[ivy:retrieve] Sigil: augmenting module=dependee ant.project.name=dependee
[ivy:retrieve] Sigil: loading Project Repository: /Volumes/Users/derek/sigil-0.7.0/example/dependence/*/sigil.properties
[ivy:retrieve] :: resolving dependencies :: org.apache#dependee;working@rodney
[ivy:retrieve]  confs: [default]
[ivy:retrieve] Sigil: augmenting module=com.springsource.org.apache.commons.logging ant.project.name=dependee
[ivy:retrieve]  found sigil#com.springsource.org.apache.commons.logging;1.1.1 in sigil
[ivy:retrieve] Sigil: augmenting module=com.springsource.org.apache.log4j ant.project.name=dependee
[ivy:retrieve]  found sigil#com.springsource.org.apache.log4j;1.2.15 in sigil
[ivy:retrieve]  found sigil#com.springsource.org.apache.commons.lang;2.1.0 in sigil
[ivy:retrieve] Sigil: augmenting module=com.springsource.javax.servlet ant.project.name=dependee
[ivy:retrieve]  found sigil#com.springsource.javax.servlet;2.5.0 in sigil
[ivy:retrieve] downloading http://repository.springsource.com/ivy/bundles/external/org.apache.commons/
    com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar ...
[ivy:retrieve]  [SUCCESSFUL ] sigil#com.springsource.org.apache.commons.logging;1.1.1!com.springsource.org.apache.commons.logging.jar (3180ms)
[ivy:retrieve] downloading http://repository.springsource.com/ivy/bundles/external/org.apache.log4j/
    com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-1.2.15.jar ...
[ivy:retrieve]  [SUCCESSFUL ] sigil#com.springsource.org.apache.log4j;1.2.15!com.springsource.org.apache.log4j.jar (5680ms)
[ivy:retrieve] downloading http://repository.springsource.com/ivy/bundles/external/javax.servlet/
    com.springsource.javax.servlet/2.5.0/com.springsource.javax.servlet-2.5.0.jar ...
[ivy:retrieve]  [SUCCESSFUL ] sigil#com.springsource.javax.servlet;2.5.0!com.springsource.javax.servlet.jar (1856ms)
[ivy:retrieve] :: resolution report :: resolve 562ms :: artifacts dl 10733ms
        ---------------------------------------------------------------------
        |                  |            modules            ||   artifacts   |
        |       conf       | number| search|dwnlded|evicted|| number|dwnlded|
        ---------------------------------------------------------------------
        |      default     |   4   |   3   |   3   |   0   ||   4   |   3   |
        ---------------------------------------------------------------------
[ivy:retrieve] :: retrieving :: org.apache#dependee
[ivy:retrieve]  confs: [default]
[ivy:retrieve]  3 artifacts copied, 1 already retrieved (534kB/50ms)

compile:

jar:
[propertyfile] Updating property file: /Volumes/Users/derek/sigil-0.7.0/example/dependence/dependee/build/classes/version.properties
[sigil.bundle] creating bundle: dependee
[sigil.bundle] BND: Importing packages that are never refered to by any class on the Bundle-Classpath[Jar:dot]: 
    [javax.servlet, org.apache.commons.logging, org.apache.log4j]
[sigil.bundle] dependee: 0 errors, 1 warning

BUILD SUCCESSFUL
Total time: 16 seconds

Notice that the additional dependencies have been resolved against the OBR repository. The warning from Bnd, is because those additional imports are not actually used.

Next Steps

This Quick Start has shown how easily Sigil can integrate with existing Ivy builds. You should now examine the other examples, which give more details of the Sigil configuration and show some real-world examples.

  • No labels