On Nov 16, 2007 1:10 PM, John Rasmussen <[EMAIL PROTECTED]> wrote:

>
>
> Xavier Hanin wrote:
> >
> > On 10/30/07, John Rasmussen <[EMAIL PROTECTED]> wrote:
> >>
> >> I have extended org.apache.ivy.plugins.repository.AbstractRepository
> >> in order to build modules directly from source.
> >
> > Interesting use case, feel free to share more about that with the
> > community
> > if you can.
> >
> >
>
> The following might be useful.


Thanks a lot for sharing, with a lot of details, I'm pretty sure this will
help other users trying to do similar stuff!

Xavier


>
> Please notice that to build a module from source requires that all module
> are structured in a uniform way and that the implementation highly depends
> on that structure.
> Thus a lot of details regarding structure is skipped, because that depends
> on your structure.
>
> First of all, this will only work in Ivy 2.0+
> For Ivy 1.4.1, see https://issues.apache.org/jira/browse/IVY-448
>
> Some of the examples below is in "it works" state and not in "brilliant"
> state.
> Feel free to comment on that, if some can be changed or made more simple.
>
>
> First the ivysettings.xml is updated like:
> <ivysettings>
>    <typedef name="my-resolver" classname="mypackage.MyResolver"/>
>    <typedef name="my-latest-strategy"
> classname="mypackage.MyLatestStrategy"/>
>    <latest-strategies>
>        <my-latest-strategy/>
>    </latest-strategies>
>    <conflict-managers>
>        <latest-cm name="my-latest-strategy" latest="my-latest-strategy"/>
>    </conflict-managers>
>    <resolvers>
>        <my-resolver name="my-resolver" changingPattern="head"
> changingMatcher="exact"
>                      allownomd="false" checksums=""
> latest="my-latest-strategy">
>            <ivy
>
> pattern="svn://myhost/[organisation]/[module]/[revision]/ivy-[module]-[revision].xml"/>
>            <artifact
>
> pattern="svn://myhost/[organisation]/[module]/[revision]/[artifact]/[artifact]-[revision].[type]"/>
>        </my-resolver>
>    </resolvers>
>    <modules>
>        <module organisation="myorg" name=".*" resolver="my-resolver"
> conflict-manager="my-latest-strategy"/>
>    </modules>
> </ivysettings>
>
>
>
> Two classes are required. The mypackage.MyResolver class builds the
> module,
> and the mypackage.MyLatestStrategy class evicts other revisions than the
> "build-from-source" revisions. In the ivysettings that revision is called
> 'head'.
>
> In order to load these two classes, the classes are inserted into
> myIvyPlugin.jar, and the retrieve target in ant looks like:
> Notice my.classpath should contain whatever you are using. I have module
> revisions stored in Subversion which are retrieved from the repository
> using
> svnkit, which has to be included in my.classpath.
>  <path id="my.classpath">
>      <pathelement location="myIvyPlugin.jar"/>
>      <pathelement location="/path/to/ivy-2.0.0-alpha2-incubating.jar"/>
>  </path>
>
>  <taskdef name="ivy-retrieve" classname="org.apache.ivy.ant.IvyRetrieve"
>         classpathref="my.classpath" loaderref="ivy.task.loader"/>
>
>  <target name="retrieve">
>      <ivy-retrieve/>
>  </target>
>
>
>
> Now for the java stuff
>
> First MyResolver, which is simple:
> import org.apache.ivy.plugins.resolver.RepositoryResolver;
> public class MyResolver extends RepositoryResolver {
>    public MyResolver() {
>        setRepository(new MyRepository());
>    }
>
>    public String getTypeName() {
>        return "myrepo";
>    }
> }
>
>
> MyRepository is the next java class.
> Please notice, that the put method is unimplemented.
> I'm not using Ivy to stored revisions - historical reasons.
> Notice the uri cache, otherwise the build process is repeated a couple of
> times.
>
> import org.apache.ivy.core.module.descriptor.Artifact;
> import org.apache.ivy.plugins.repository.AbstractRepository;
> import org.apache.ivy.plugins.repository.Resource;
> import org.apache.ivy.plugins.repository.TransferEvent;
> import org.apache.ivy.util.Message;
>
> public final class MyRepository extends AbstractRepository {
>    private final Map uriMap = new HashMap();
>    public final void get(final String source, final File destination)
> throws IOException {
>        try {
>            final RepositoryResource repositoryResource =
> getRepositoryResource(source);
>            fireTransferInitiated(repositoryResource,
> TransferEvent.REQUEST_GET);
>            fireTransferStarted();
>            repositoryResource.save(destination);
>            fireTransferCompleted(repositoryResource.getContentLength());
>        } catch (final MyException e) {
>            Message.error("Cannot get " + source);
>            fireTransferError(e);
>        }
>    }
>
>    public final Resource getResource(final String source) throws
> IOException {
>        try {
>            final Resource resource = getRepositoryResource(source);
>            return resource;
>        } catch (final MyException e) {
>            Message.error("Cannot get " + source);
>            fireTransferError(e);
>            throw new IOException("Failed");
>        }
>    }
>
>    public final List list(final String source) throws IOException {
>        try {
>            final List list = getRepositoryResource(source).list();
>            return list;
>        } catch (final MyException e) {
>            fireTransferError(e);
>            return Collections.EMPTY_LIST;
>        }
>    }
>
>    public final void put(final Artifact artifact, final File source, final
> String destination, final boolean overwrite) throws IOException {
>        fireTransferError(new MyException("Put-operation not supported.
> Source " + source + ", destination " +
>                                           destination));
>    }
>
>    private final RepositoryResource getRepositoryResource(final String
> uri)
> throws MyException {
>        RepositoryResource repositoryResource = ( RepositoryResource )
> uriMap.get(uri);
>        if (repositoryResource == null) {
>            repositoryResource = MyResource(uri);
>            uriMap.put(uri, repositoryResource);
>        }
>        return repositoryResource;
>    }
> }
>
>
> A simple interface
> public interface RepositoryResource extends Resource {
>    List list();
>
>    void save(final File destination) throws IOException;
> }
>
>
> Given an uri in a format defined in ivysettings, the task is to build the
> module from source.
> This is done in MyResource, where all module structure details are placed.
> Thus this java class does not compile as is. You need to add your details
> or
> return "null" if not used.
> I have listed a few "null" methods.
> Notice, if a module build more than one artifact, then some caching/"need
> to
> update"
> functionality must be implemented somewhere to avoid that the system
> builds
> everything
> for each artifact.
> The files generated from the build is returned to ivy in the save() method
>
>
> public final class MyResource implements RepositoryResource {
>    public MyResource(final String uri {
>        // Build source
>    }
>
>    public final long getContentLength() {
>        return getFile().length();
>    }
>
>    public final String getName() {
>        return uri;
>    }
>
>    public final boolean isLocal() {
>        return false;
>    }
>
>    public final List list() {
>        return Collections.EMPTY_LIST;
>    }
>
>    public InputStream openStream() throws IOException {
>        throw new IOException("openStream unsupported.");
>    }
>
>    public final void save(final File destination) throws IOException {
>        final File source = getFile();
>        final InputStream is = new FileInputStream(source);
>        final OutputStream os = new FileOutputStream(destination);
>        final byte[] b = new byte[BUFFER_SIZE];
>        int size;
>
>        while ((size = is.read(b)) != -1) {
>            os.write(b, 0, size);
>        }
>
>        os.close();
>        is.close();
>    }
>
>    private final File getFile() {
>          // Return the file being build given the uri
>    }
> }
>
>
> Other revisions than "head" should also be handled. That depends on how
> your
> revisions are stored.
> I have an svnkit implementation to retrieve from Subversion - historical
> reasons.
> Today such an implementation might already exists in Ivy??
>
> Most artifacts can be returned "as is".
> One exception is the ivy.xml artifact.
> The revision in Ivy.xml must correspond to the revision in the dependency
> tag, otherwise Ivy complains.
> Of course, this depends on how you return your ivy.xml file. (You might
> build/deliver an ivy.xml with correct version)
> I did a simple OutputStream replace:
> And use a replaced os in the save() method BUT only for the ivy.xml
> artifact!
>  new StringReplaceOutputStream(os, " revision *= *\"[^\"]*\"",
>                                                  " revision=\"head\"");
>
> public final class StringReplaceOutputStream extends OutputStream {
>    private int index;
>    private final OutputStream outputStream;
>    private final String regex;
>    private final String replacement;
>    private final StringBuffer strBuf;
>
>    public StringReplaceOutputStream(final OutputStream outputStream, final
> String regex, final String replacement) {
>        this.outputStream = outputStream;
>        strBuf = new StringBuffer();
>        this.regex = regex;
>        this.replacement = replacement;
>        index = 0;
>    }
>
>    public final void close() throws IOException {
>        flush();
>        outputStream.close();
>    }
>
>    public final synchronized void flush() throws IOException {
>        writeFromStrBuf(strBuf.length());
>        outputStream.flush();
>    }
>
>    public final void write(final int b) throws IOException {
>        strBuf.append(( char ) (b & 0xFF));
>        update();
>    }
>
>    public final void write(final byte[] b, final int off, final int len)
> throws IOException {
>        strBuf.append(new String(b, off, len));
>        update();
>    }
>
>    private final void update() throws IOException {
>        while (index < (strBuf.length() - 1)) {
>            if (strBuf.charAt(index) == 0x0D) {
>                if (strBuf.charAt(index + 1) == 0x0A) {
>                    index++;
>                }
>
>                writeFromStrBuf(index + 1);
>            } else {
>                index++;
>            }
>        }
>    }
>
>    private final void writeFromStrBuf(final int index) throws IOException
> {
>        final String str = strBuf.substring(0, index).toString();
>        final String strRep = str.replaceAll(regex, replacement);
>        outputStream.write(strRep.getBytes());
>        strBuf.delete(0, index);
>        this.index = 0;
>    }
> }
>
>
> To evict other revisions than "head" add MyLatestStrategy.java
> import java.util.Comparator;
> import org.apache.ivy.plugins.latest.ArtifactInfo;
> import org.apache.ivy.plugins.latest.ComparatorLatestStrategy;
> import org.apache.ivy.plugins.latest.LatestRevisionStrategy;
>
>
> public class MyLatestStrategy extends ComparatorLatestStrategy {
>    public MyLatestStrategy() {
>        super(new Comparator() {
>                private final Comparator comparator = new
> LatestRevisionStrategy().COMPARATOR;
>
>                public int compare(Object o1, Object o2) {
>                    String rev1 = (( ArtifactInfo ) o1).getRevision();
>                    String rev2 = (( ArtifactInfo ) o2).getRevision();
>
>                    if (rev1.startsWith("head")) {
>                        return 1;
>                    } else if (rev2.startsWith("head")) {
>                        return -1;
>                    } else {
>                        return comparator.compare(o1, o2);
>                    }
>                }
>            });
>        setName("my-latest-strategy");
>    }
> }
>
> --
> View this message in context:
> http://www.nabble.com/How-to-halt-on-an-unresolved-dependency-tf4717519.html#a13791968
> Sent from the ivy-dev mailing list archive at Nabble.com.
>
>


-- 
Xavier Hanin - Independent Java Consultant
http://xhab.blogspot.com/
http://ant.apache.org/ivy/
http://www.xoocode.org/

Reply via email to