Beginnings of automated Java library publishing, dependency tracking and

downloading system.


git-svn-id: https://samskivert.googlecode.com/svn/trunk@702 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
mdb
2002-04-11 07:23:59 +00:00
parent 6caf731ff9
commit d2fbfd11cf
19 changed files with 1223 additions and 0 deletions
+69
View File
@@ -0,0 +1,69 @@
<?xml version="1.0"?>
<!-- build configuration -->
<project name="depends" default="compile" basedir=".">
<!-- things you may want to change -->
<property name="build.compiler" value="jikes"/>
<property name="build.optimize" value="on"/>
<!-- things you probably don't want to change -->
<property name="app.name" value="depends"/>
<property name="copyright.holder" value="Michael Bayne"/>
<property name="deploy.dir" value="dist"/>
<property name="dist.jar" value="${app.name}.jar"/>
<property name="javadoc.dir" value="${deploy.dir}/docs"/>
<!-- things you definitely don't want to change -->
<property name="doc.packages" value="com.samskivert.depends.*"/>
<property name="doc.overview" value="com/samskivert/depends/overview.html"/>
<property name="src.dir" value="src/java"/>
<!-- prepares the application directories -->
<target name="prepare">
<tstamp><format property="year" pattern="yyyy" /></tstamp>
<mkdir dir="${deploy.dir}"/>
<mkdir dir="${deploy.dir}/classes"/>
<mkdir dir="${javadoc.dir}"/>
<copy todir="${deploy.dir}/classes">
<fileset dir="${src.dir}" includes="**/*.properties"/>
</copy>
</target>
<!-- cleans out the installed application -->
<target name="clean">
<delete dir="${deploy.dir}"/>
</target>
<!-- builds the java class files -->
<target name="compile" depends="prepare">
<javac srcdir="${src.dir}" destdir="${deploy.dir}/classes"
debug="on" optimize="${build.optimize}" deprecation="off">
</javac>
</target>
<!-- builds the javadoc documentation -->
<target name="javadoc" depends="prepare">
<javadoc sourcepath="${src.dir}"
packagenames="${doc.packages}"
windowtitle="${app.name} API"
doctitle="${app.name} API"
overview="${src.dir}/${doc.overview}"
destdir="${javadoc.dir}"
additionalparam="-breakiterator">
<bottom>Copyright &#169; 2000-${year} ${copyright.holder}.
All Rights Reserved.</bottom>
<link href="http://java.sun.com/j2se/1.4/docs/api/"/>
</javadoc>
</target>
<!-- builds our distribution files -->
<target name="dist" depends="prepare,compile">
<jar destfile="${deploy.dir}/${dist.jar}"
basedir="${deploy.dir}/classes"/>
</target>
<!-- a target for rebuilding everything -->
<target name="all" depends="clean,prepare,compile,javadoc,dist"/>
</project>
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0"?>
<depends>
<library name="jakarta-commons-util" version="1.0+"
url="http://jakarta.apache.org/commons/commons-util.ldf"/>
<library name="jakarta-commons-digester" version="1.2"
url="http://jakarta.apache.org/commons/commons-digester.ldf"/>
<!-- use local build until those kooks incorporate our patches
<library name="samskivert" version="1.1+"
url="http://www.waywardgeeks.org/code/samskivert/samskivert.ldf"/>
-->
<library name="samskivert" version="1.1+"
url="file:/home/mdb/projects/samskivert/target/samskivert.ldf"/>
</depends>
+54
View File
@@ -0,0 +1,54 @@
<?xml version="1.0"?>
<library>
<!-- the library identifier: case insensitive; matches ([-_A-Za-z]+) -->
<name>samskivert</name>
<!-- is the inclusion of copyright necessary or desirable? -->
<copyright>2000-2002, Michael Bayne</copyright>
<!-- contact information for this library (optional) -->
<contact>mdb@samskivert.com</contact>
<!-- a web page that provides information about the library and the
base URL from which other URLs are interpreted to be relative -->
<url>http://www.waywardgeeks.org/code/samskivert/</url>
<!-- composed with <url> using the standard rules:
<url> + samskivert.ldf =
http://www.waywardgeeks.org/code/samskivert/samskivert.ldf
<url> + /samskivert.ldf =
http://www.waywardgeeks.org/samskivert.ldf
<url> + http://foo.bar.com/samskivert.ldf =
http://foo.bar.com/samskivert.ldf
-->
<descriptor>samskivert.ldf</descriptor>
<!-- enumerates the "supported" releases -->
<releases>
<release>
<version>1.1</version>
<date>2001-12-03</date>
<!-- composed with <url> using the standard rules -->
<jar>releases/samskivert-1.1.jar</jar>
<!-- describes this release's dependencies -->
<depends>
<!-- version strings ending with + means automatically use the
latest version; versions are ordered by release date -->
<library name="jakarta-commons-util" version="1.0+"
url="http://jakarta.apache.org/commons/commons-util.ldf"/>
<library name="jakarta-commons-digester" version="1.2"
url="http://jakarta.apache.org/commons/commons-digester.ldf"/>
</depends>
</release>
<release>
<version>1.01</version>
<date>2001-08-13</date>
<jar>releases/samskivert-1.01.jar</jar>
<depends>
<library name="jakarta-commons-util" version="1.0+"
url="http://jakarta.apache.org/commons/util/commons-util.ldf"/>
</depends>
</release>
</releases>
</library>
+33
View File
@@ -0,0 +1,33 @@
Dependency system design
------------------------
- Two interfaces: Java object interface and ANT wrapper
- If possible, use no external libraries to avoid bootstrapping problems
(can't use depends to download depends for depends):
+ make use of built-in Java XML parsing services
+ make use of built-in Java logging services
+ will have to "depend" on ant
- Object interface available via the following classes:
public class Dependency
{
public String getLibraryName ();
public File getLocalJar ();
public boolean isUpToDate ();
public void bringUpToDate ();
}
public class DependencyParser
{
public <Dependency>List parseDependencies (
File definition, File repository);
}
public class LibraryDescriptor
{
}
+8
View File
@@ -0,0 +1,8 @@
Dependency system notes
-----------------------
- Will need tool (ant task) for "stamping" a jar file (inserting the
library descriptor).
- Will want tool that dumps library descriptor information from an
existing jar file (both in XML and formatted text).
+177
View File
@@ -0,0 +1,177 @@
Dependency system specification
-------------------------------
- Libraries publish "library descriptor file" which is a simple XML file
describing the library's dependencies, latest release information and
where supported releases can be downloaded:
<?xml version="1.0"?>
<library>
<!-- the library identifier: case insensitive; matches ([-_A-Za-z]+) -->
<name>samskivert</name>
<!-- is the inclusion of copyright necessary or desirable? -->
<copyright>2000-2002, Michael Bayne</copyright>
<!-- contact information for this library (optional) -->
<contact>mdb@samskivert.com</contact>
<!-- a web page that provides information about the library and the
base URL from which other URLs are interpreted to be relative -->
<url>http://www.waywardgeeks.org/code/samskivert/</url>
<!-- composed with <url> using the standard rules:
<url> + samskivert.ldf =
http://www.waywardgeeks.org/code/samskivert/samskivert.ldf
<url> + /samskivert.ldf =
http://www.waywardgeeks.org/samskivert.ldf
<url> + http://foo.bar.com/samskivert.ldf =
http://foo.bar.com/samskivert.ldf
-->
<descriptor>samskivert.ldf</descriptor>
<!-- enumerates the "supported" releases -->
<releases>
<release>
<version>1.1</version>
<date>2001-12-03</date>
<!-- composed with <url> using the standard rules -->
<jar>releases/samskivert-1.1.jar</jar>
<!-- describes this release's dependencies -->
<depends>
<!-- version strings ending with + means automatically use the
latest version; versions are ordered by release date -->
<library name="jakarta-commons-util" version="1.0+"
url="http://jakarta.apache.org/commons/commons-util.ldf"/>
<library name="jakarta-commons-digester" version="1.2"
url="http://jakarta.apache.org/commons/commons-digester.ldf"/>
</depends>
</release>
<release>
<version>1.01</version>
<date>2001-08-13</date>
<jar>releases/samskivert-1.01.jar</jar>
<depends>
<library name="jakarta-commons-util" version="1.0+"
url="http://jakarta.apache.org/commons/util/commons-util.ldf"/>
</depends>
</release>
</releases>
</library>
This would be made available at:
http://www.waywardgeeks.org/code/samskivert/samskivert.ldf
Some sort of version information should be inserted into the JAR file so
that the downloader doesn't have to maintain a cached copy of the LDF
file it used to retrieve the JAR file. Perhaps an additional file
included in the jar:
META-INF/RELEASE.LDF:
<?xml version="1.0"?>
<library>
<name>samskivert</name>
<copyright>2000-2002, Michael Bayne</copyright>
<url>http://www.waywardgeeks.org/code/samskivert/</url>
<descriptor>samskivert.ldf</descriptor>
<release>
<version>1.1</version>
<date>2001-12-03</date>
<jar>releases/samskivert-1.1.jar</jar>
<depends>
<library name="jakarta-commons-util" version="1.0+"
url="http://jakarta.apache.org/commons/commons-util.ldf"/>
<library name="jakarta-commons-digester" version="1.2"
url="http://jakarta.apache.org/commons/commons-digester.ldf"/>
</depends>
</release>
</library>
This would be automatically generated by the depends system and inserted
into the jar file during the build process.
Perhaps it is desirable to support the publishing of multiple libraries
in a single LDF file?
- Projects reference dependencies via an ANT front-end or by other means
(eg. Maven). Perhaps using an external file:
depends.xml:
<depends>
<library name="samskivert" version="1.1+"
url="http://www.waywardgeeks.org/code/samskivert/samskivert.ldf"/>
<library name="jakarta-commons-collections" version="1.2+"
url="http://jakarta.apache.org/commons/commons-collections.ldf"/>
</depends>
build.xml:
<!-- includes the appropriate library files in the classpath -->
<target name="include-depends">
<taskdef name="include" classname="...IncludeDependsTask"/>
<include deps="depends.xml" refid="classpath" repository="libs/"/>
</target>
<!-- checks for updates to the dependencies; reports newer versions,
obsolescence, etc. -->
<target name="check-depends">
<taskdef name="check" classname="...CheckDependsTask"/>
<check deps="depends.xml" repository="libs/"/>
</target>
<!-- downloads any newer versions of dependencies for which we have
indicated a desire to use the latest version -->
<target name="update-depends">
<taskdef name="update" classname="...UpdateDependsTask"/>
<update deps="depends.xml" repository="libs/"/>
</target>
Or perhaps the dependencies should be specified directly in ant's build
file (which would probably involve more sophisticated extension of ant
than just implementing a task). This latter approach would make it more
difficult for external tools to inspect a project's dependencies, but
fewer files is also good.
- A developer could override the standard library location and specify a
dependency to a local build:
<depends>
<library name="samskivert" version="1.1+"
<!-- use local build until those kooks incorporate our patches
url="http://www.waywardgeeks.org/code/samskivert/samskivert.ldf"/>
-->
url="file:/home/mdb/projects/samskivert/target/samskivert.ldf"/>
</depends>
Because the build system would tag a library with a "release" date of
the current date at the time of the build, it would pick up the local
build so long as it was built more recently than any public build that
might be referenced in the dependency hierarchy.
- KISS: place as little information as is necessary in the library
descriptor files so as to minimize the possibility of that information
becoming out of date.
- Facilitate build stability: don't automatically check for or download
new libraries; provide an explicit mechanism for checking for updates
(separate build directive), a means for specifying "use the latest
version" and one for specifying "use a specific version".
- Facilitate the bleeding edge: a project should be able to include
libraries from the web site where the most recent stable release is
published, or build from CVS and reference their local build directly.
- Facilitate forward progress: report when a project depends on a version
of a library that is no longer supported (meaning it is no longer listed
in the library's descriptor).
- Facilitate dependency generation: check project's generated classfiles
for references to classes not enumerated in dependencies hierarchy;
report findings.
- Facilitate obsolete dependency removal: report dependencies that are not
referenced by any class in the project.
@@ -0,0 +1,235 @@
//
// $Id: Dependency.java,v 1.1 2002/04/11 07:23:59 mdb Exp $
package com.samskivert.depends;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
/**
* Describes a particular library dependency.
*/
public class Dependency
{
/**
* Constructs a dependency from its specification criterion.
*/
public Dependency (String libraryName,
Version requiredVersion,
URL descriptorURL)
{
_libraryName = libraryName;
_requiredVersion = requiredVersion;
_descriptorURL = descriptorURL;
}
/**
* Informs this dependency of the location of our local library
* repository.
*/
public void setLocalRepository (File repository)
{
_repository = repository;
}
/**
* Returns the human-readable library identifier.
*/
public String getLibraryName ()
{
return _libraryName;
}
/**
* Returns the library version required by this dependency
* specification.
*/
public Version getRequiredVersion ()
{
return _requiredVersion;
}
/**
* Returns the descriptor URL for the library referenced by this
* dependency.
*/
public URL getDescriptorURL ()
{
return _descriptorURL;
}
/**
* Returns the version of our local copy of the library referenced by
* this dependency, or null if we have no local copy of the library.
*
* @exception IllegalStateException thrown if the dependency has not
* yet been configured with the path to the local library repository.
*/
public Version getLocalVersion ()
throws IOException, FormatException
{
if (_localVersion == null) {
resolveLocalVersion();
}
return _localVersion;
}
/**
* Returns a file object referencing our local copy of the library
* referenced by this dependency, or null if the dependency hasn't
* been resolved.
*
* @exception IllegalStateException thrown if the dependency has not
* yet been configured with the path to the local library repository.
*/
public File getLocalJar ()
{
if (_repository == null) {
String errmsg = "Dependency has not yet been configured " +
"with path to local library repository.";
throw new IllegalStateException(errmsg);
}
return new File(_repository, constructJarName());
}
/**
* Returns true if we have a local copy of the library referenced by
* this dependency that satisfies the dependency's version constraints
* <em>and</em> that we have local copies with satisfactory versions
* of all libraries upon which this library depends, ad infinitum. If
* we have no local copy of the library or the version of the local
* copy is older than the version specified by the dependency or same
* for any derived dependencies, this method returns false.
*
* <p> Note that this method caches its results once they are computed
* in the expectation that it will be used in a "one shot" manner
* (meaning the JVM that instantiates and uses this class is not long
* lived). Once a dependency is resolved, it does not go back and
* reresolve it, thus it could become out of date if the library (or
* its dependencies) is updated between the time that this method is
* called and the time that the calling JVM exits.
*/
public boolean isSatisified ()
{
// TBD
return false;
}
/**
* Returns true if we have a local copy of the library and it is the
* most recent release of that library. This method results in an HTTP
* request being issued to download the latest library descriptor for
* the library
*
* <p> Note that this method caches its results once they are computed
* in the expectation that it will be used in a "one shot" manner
* (meaning the JVM that instantiates and uses this class is not long
* lived). Once a dependency is resolved, it does not go back and
* reresolve it, thus it could become out of date if the library (or
* its dependencies) is updated between the time that this method is
* called and the time that the calling JVM exits.
*/
public boolean isUpToDate ()
throws IOException
{
// TBD
return false;
}
/**
* Downloads the library descriptor for the library referenced by this
* dependency and returns it. Note that once the descriptor has been
* downloaded once, it is cached for the remainder of the lifetime of
* the JVM, hiding updates that take place between the time that this
* method is called and the time that the calling JVM exists. This is
* considered to be more desirable than making an HTTP request every
* time this method is called.
*/
public LibraryDescriptor getLibraryDescriptor ()
throws IOException, FormatException
{
if (_remoteDescriptor != null) {
return _remoteDescriptor;
}
// download the descriptor data from the publishing site
URLConnection uconn = _descriptorURL.openConnection();
_remoteDescriptor = LibraryDescriptorParser.parseLibraryDescriptor(
uconn.getInputStream());
return _remoteDescriptor;
}
/**
* Downloads the library descriptor for the library referenced by this
* dependency and reports the most recent version available of said
* library.
*
* @see #getLibraryDescriptor
*/
public Version getRemoteVersion ()
throws IOException, FormatException
{
LibraryDescriptor descriptor = getLibraryDescriptor();
return descriptor.getLatestRelease().getVersion();
}
/**
* Returns a string representation of this instance.
*/
public String toString ()
{
return "[name=" + _libraryName + ", version=" + _requiredVersion +
", url=" + _descriptorURL + "]";
}
/**
* Constructs the file name of our local copy of the jar file.
*/
protected String constructJarName ()
{
return _libraryName + LIBRARY_SUFFIX;
}
/**
* Loads up the library stamp from our local copy of the library and
* extracts the version information from it.
*/
protected Version resolveLocalVersion ()
throws IOException, FormatException
{
File jar = getLocalJar();
// TBD
return null;
}
/** The name of the library referenced by this dependency. */
protected String _libraryName;
/** The version required by this dependency. */
protected Version _requiredVersion;
/** The URL for the descriptor of the library referenced by this
* dependency. */
protected URL _descriptorURL;
/** The path to our local library repository. */
protected File _repository;
/** The version of our local copy of the library or null if we have no
* local copy. */
protected Version _localVersion;
/** A parsed library descriptor, obtained from our local copy of the
* library. */
protected LibraryDescriptor _localDescriptor;
/** A parsed library descriptor, downloaded from the site that
* publishes this library. */
protected LibraryDescriptor _remoteDescriptor;
/** All libraries end with this suffix: <code>.jar</code> */
protected static final String LIBRARY_SUFFIX = ".jar";
}
@@ -0,0 +1,122 @@
//
// $Id: DependencyParser.java,v 1.1 2002/04/11 07:23:59 mdb Exp $
package com.samskivert.depends;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;
/**
* Parses XML dependency definitions.
*/
public class DependencyParser
{
/**
* Parses the specified dependency definition file into a list of
* {@link Dependency} instances.
*/
public static List parseDependencies (File definition)
throws FormatException, IOException
{
try {
ArrayList list = new ArrayList();
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
DependencyHandler handler = new DependencyHandler(list);
parser.parse(definition, handler);
return list;
} catch (SAXException saxe) {
throw new FormatException(saxe.getMessage());
} catch (ParserConfigurationException pce) {
throw new FormatException(
"Unable to load parser: " + pce.getMessage());
}
}
public static void main (String[] args)
{
try {
parseDependencies(new File(args[0]));
} catch (Exception e) {
Log.warning("Chokey choke-opolis", e);
}
}
/**
* Used to parse the dependency specification.
*/
protected static class DependencyHandler extends DefaultHandler
{
public DependencyHandler (List list)
{
_list = list;
}
public void startElement (String namespaceURI, String localName,
String qName, Attributes attrs)
{
if (qName.equals("library")) {
String name = null;
String version = null;
String url = null;
for (int i = 0; i < attrs.getLength(); i++) {
String attrName = attrs.getQName(i);
if (attrName.equals("name")) {
name = attrs.getValue(i);
} else if (attrName.equals("version")) {
version = attrs.getValue(i);
} else if (attrName.equals("url")) {
url = attrs.getValue(i);
}
}
if (!validateAttribute("name", name) ||
!validateAttribute("version", version) ||
!validateAttribute("url", url)) {
return;
}
try {
Dependency dep = new Dependency(
name, new Version(version), new URL(url));
Log.info("Parsed dependency " + dep + ".");
_list.add(dep);
} catch (MalformedURLException mue) {
Log.warning("Skipping dependency with invalid 'url' " +
"specification [url=" + url + "]: " + mue);
}
}
}
protected boolean validateAttribute (String name, String value)
{
if (value == null || value.length() == 0) {
Log.warning("Skipping dependency declaration that is " +
"missing required attribute '" + name + "'.");
return false;
} else {
return true;
}
}
protected List _list;
}
}
@@ -0,0 +1,15 @@
//
// $Id: FormatException.java,v 1.1 2002/04/11 07:23:59 mdb Exp $
package com.samskivert.depends;
/**
* Used to communicate file format exceptions.
*/
public class FormatException extends Exception
{
public FormatException (String message)
{
super(message);
}
}
@@ -0,0 +1,61 @@
//
// $Id: LibraryDescriptor.java,v 1.1 2002/04/11 07:23:59 mdb Exp $
package com.samskivert.depends;
import java.net.URL;
import java.util.List;
/**
* Describes a library.
*/
public class LibraryDescriptor
{
public String getLibraryName ()
{
return _libraryName;
}
public String getCopyright ()
{
return _copyright;
}
public String getContact ()
{
return _contact;
}
public URL getLibraryURL ()
{
return _libraryURL;
}
public URL getDescriptorURL ()
{
return _descriptorURL;
}
public List getReleases ()
{
return _releases;
}
public Release getLatestRelease ()
{
return null;
}
protected String _libraryName;
protected String _copyright;
protected String _contact;
protected URL _libraryURL;
protected URL _descriptorURL;
protected List _releases;
}
@@ -0,0 +1,97 @@
//
// $Id: LibraryDescriptorParser.java,v 1.1 2002/04/11 07:23:59 mdb Exp $
package com.samskivert.depends;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.MalformedURLException;
/**
* Parses XML library descriptor definitions.
*/
public class LibraryDescriptorParser
{
/**
* Parses the specified library descriptor file.
*/
public static LibraryDescriptor parseLibraryDescriptor (File descriptor)
throws FormatException, IOException
{
return parseLibraryDescriptor(new FileInputStream(descriptor));
}
/**
* Parses the library descriptor definition provided via the supplied
* input stream.
*/
public static LibraryDescriptor parseLibraryDescriptor (InputStream source)
throws FormatException, IOException
{
try {
LibraryDescriptor ld = new LibraryDescriptor();
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
DescriptorHandler handler = new DescriptorHandler(ld);
parser.parse(source, handler);
return ld;
} catch (SAXException saxe) {
throw new FormatException(saxe.getMessage());
} catch (ParserConfigurationException pce) {
throw new FormatException(
"Unable to load parser: " + pce.getMessage());
}
}
public static void main (String[] args)
{
try {
parseLibraryDescriptor(new File(args[0]));
} catch (Exception e) {
Log.warning("Chokey choke-opolis", e);
}
}
/**
* Used to parse a library descriptor specification.
*/
protected static class DescriptorHandler extends DefaultHandler
{
public DescriptorHandler (LibraryDescriptor descriptor)
{
_descriptor = descriptor;
}
public void startElement (String namespaceURI, String localName,
String qName, Attributes attrs)
{
}
protected boolean validateAttribute (String name, String value)
{
if (value == null || value.length() == 0) {
Log.warning("Skipping dependency declaration that is " +
"missing required attribute '" + name + "'.");
return false;
} else {
return true;
}
}
protected LibraryDescriptor _descriptor;
}
}
@@ -0,0 +1,66 @@
//
// $Id: Log.java,v 1.1 2002/04/11 07:23:59 mdb Exp $
package com.samskivert.depends;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Provides convenient access to our logging instance.
*/
public class Log
{
/** A reference to our logger. */
public static Logger log = Logger.getLogger("com.samskivert.depends");
/**
* Passes through to {@link Logger#fine(String)}.
*/
public static void fine (String message)
{
log.fine(message);
}
/**
* Passes through to {@link Logger#info(String)}.
*/
public static void info (String message)
{
log.info(message);
}
/**
* Passes through to {@link Logger#warning(String)}.
*/
public static void warning (String message)
{
log.warning(message);
}
/**
* Passes through to {@link Logger#log} with level
* <code>WARNING</code>.
*/
public static void warning (String message, Exception e)
{
log.log(Level.WARNING, message, e);
}
/**
* Passes through to {@link Logger#severe(String)}.
*/
public static void severe (String message)
{
log.severe(message);
}
/**
* Passes through to {@link Logger#log} with level
* <code>SEVERE</code>.
*/
public static void severe (String message, Exception e)
{
log.log(Level.SEVERE, message, e);
}
}
@@ -0,0 +1,43 @@
//
// $Id: Release.java,v 1.1 2002/04/11 07:23:59 mdb Exp $
package com.samskivert.depends;
import java.net.URL;
import java.util.Date;
import java.util.List;
/**
* Describes a particular release of a library.
*/
public class Release
{
public Version getVersion ()
{
return _version;
}
public Date getDate ()
{
return _date;
}
public URL getJarURL ()
{
return _jarURL;
}
public List getDependencies ()
{
return _dependencies;
}
protected Version _version;
protected Date _date;
protected URL _jarURL;
protected List _dependencies;
}
@@ -0,0 +1,11 @@
//
// $Id: ReleaseDescriptor.java,v 1.1 2002/04/11 07:23:59 mdb Exp $
package com.samskivert.depends;
/**
* Does something extraordinary.
*/
public class ReleaseDescriptor
{
}
@@ -0,0 +1,48 @@
//
// $Id: Version.java,v 1.1 2002/04/11 07:23:59 mdb Exp $
package com.samskivert.depends;
/**
* Represents a library version. Version strings are not constrained to a
* particular format, but must meet a couple of criterion: first, they
* must contain only valid filename characters as they will be used to
* create the filename of our local copy of the library's jar file.
* Second, if a dependency's version specification ends with a
* '<code>+</code>', the dependency is considered satisfied by any library
* release newer than the specified version. Thus, if a version string
* ends in plus, wackiness ensues. Fortunately, we can issue a warning if
* anyone tries to stamp a library with a descriptor that declares its
* version to end with a plus.
*/
public class Version
{
/**
* Constructs a version instance from the supplied version
* specification string.
*/
public Version (String version)
{
_version = version;
}
/**
* Returns true if this version specification allows replacement by
* newer versions, false otherwise.
*/
public boolean openEnded ()
{
return _version.endsWith("+");
}
/**
* Returns a string representation of this instance.
*/
public String toString ()
{
return _version;
}
/** Our version specification string. */
protected String _version;
}
@@ -0,0 +1,46 @@
//
// $Id: CheckDependsTask.java,v 1.1 2002/04/11 07:23:59 mdb Exp $
package com.samskivert.depends.tasks;
import java.util.List;
import org.apache.tools.ant.BuildException;
import com.samskivert.depends.Dependency;
/**
* An ant task for checking that a set of dependencies are satisfied by
* the jar files that currently exist in our local library repository.
*/
public class CheckDependsTask extends DependsTask
{
/**
* Performs the actual work of the task.
*/
public void execute ()
throws BuildException
{
// load and resolve our dependencies
List depends = loadDependencies();
resolveDependencies(depends);
int dcount = depends.size();
for (int i = 0; i < dcount; i++) {
Dependency dep = (Dependency)depends.get(i);
try {
if (!dep.isUpToDate()) {
System.out.println("Library '" + dep.getLibraryName() +
"' has newer version " +
"[have=" + dep.getLocalVersion() +
", latest=" + dep.getRemoteVersion() +
"].");
}
} catch (Exception e) {
System.err.println("Error checking dependency " +
"[dep=" + dep + ", error=" + e + "].");
}
}
}
}
@@ -0,0 +1,103 @@
//
// $Id: DependsTask.java,v 1.1 2002/04/11 07:23:59 mdb Exp $
package com.samskivert.depends.tasks;
import java.io.File;
import java.util.List;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import com.samskivert.depends.Dependency;
import com.samskivert.depends.DependencyParser;
/**
* A base class that handles functionality common to all dependency
* related ant tasks.
*/
public abstract class DependsTask extends Task
{
/**
* Called by ant to set the 'deps' attribute.
*/
public void setDeps (File deps)
{
_deps = deps;
}
/**
* Called by ant to set the 'repository' attribute.
*/
public void setRepository (File repository)
{
_repository = repository;
}
/**
* Throws a build exception using the supplied error message if the
* supplied value is null.
*/
protected void ensureSet (Object value, String errmsg)
throws BuildException
{
if (value == null) {
throw new BuildException(errmsg);
}
}
/**
* Loads up a set of dependencies from the dependency file specified
* via the 'deps' task attribute.
*/
protected List loadDependencies ()
throws BuildException
{
ensureSet(_deps, "Missing 'deps' attribute which should " +
"reference the dependency definition file.");
try {
return DependencyParser.parseDependencies(_deps);
} catch (Exception e) {
throw new BuildException("Error parsing dependency " +
"definition file.", e);
}
}
/**
* Configures the supplied set of dependencies with the local library
* repository specified via the 'repository' task attribute.
*/
protected void resolveDependencies (List depends)
throws BuildException
{
// make sure the repository directory was specified...
ensureSet(_repository, "Missing 'repository' attribute which should " +
"reference the local library repository directory.");
// ...exists...
if (!_repository.exists()) {
String errmsg = "Local library repository directory '" +
_repository.getPath() + "' does not exist.";
throw new BuildException(errmsg);
}
// ...and is actually a directory
if (!_repository.isDirectory()) {
String errmsg = "Specified local library repository '" +
_repository.getPath() + "' is not a directory.";
throw new BuildException(errmsg);
}
int dcount = depends.size();
for (int i = 0; i < dcount; i++) {
Dependency dep = (Dependency)depends.get(i);
dep.setLocalRepository(_repository);
}
}
/** The dependency definition file. */
protected File _deps;
/** The local library repository directory. */
protected File _repository;
}
@@ -0,0 +1,11 @@
//
// $Id: IncludeDependsTask.java,v 1.1 2002/04/11 07:23:59 mdb Exp $
package com.samskivert.depends.tasks;
/**
* Does something extraordinary.
*/
public class IncludeDependsTask
{
}
@@ -0,0 +1,11 @@
//
// $Id: UpdateDependsTask.java,v 1.1 2002/04/11 07:23:59 mdb Exp $
package com.samskivert.depends.tasks;
/**
* Does something extraordinary.
*/
public class UpdateDependsTask
{
}