diff --git a/WHATSNEW b/WHATSNEW index c355e6f18..657c8eb20 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -68,6 +68,8 @@ Other changes: * Added a new "failall" value for the onerror attribute of . Bugzilla report 31685. +* New task can retrieve library files from a maven repository. + Changes from Ant 1.6.2 to current Ant 1.6 CVS version ===================================================== diff --git a/build.xml b/build.xml index df53d5458..d431725cf 100644 --- a/build.xml +++ b/build.xml @@ -328,6 +328,11 @@ + + + + + @@ -561,6 +566,17 @@ classpathref="classpath"/> + + + + + + + + + @@ -679,6 +695,7 @@ + @@ -853,6 +870,7 @@ + @@ -897,6 +915,7 @@ + + @@ -1624,6 +1644,7 @@ + diff --git a/src/etc/testcases/taskdefs/optional/getlibraries.xml b/src/etc/testcases/taskdefs/optional/getlibraries.xml new file mode 100644 index 000000000..5a67e3881 --- /dev/null +++ b/src/etc/testcases/taskdefs/optional/getlibraries.xml @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + Not found: ${lib.dir}@{library} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/org/apache/tools/ant/taskdefs/defaults.properties b/src/main/org/apache/tools/ant/taskdefs/defaults.properties index 8c0d4b7cf..75148c0db 100644 --- a/src/main/org/apache/tools/ant/taskdefs/defaults.properties +++ b/src/main/org/apache/tools/ant/taskdefs/defaults.properties @@ -203,6 +203,7 @@ rexec=org.apache.tools.ant.taskdefs.optional.net.RExecTask scriptdef=org.apache.tools.ant.taskdefs.optional.script.ScriptDef ildasm=org.apache.tools.ant.taskdefs.optional.dotnet.Ildasm apt=org.apache.tools.ant.taskdefs.Apt +getlibraries=org.apache.tools.ant.taskdefs.optional.repository.GetLibraries # deprecated ant tasks (kept for back compatibility) starteam=org.apache.tools.ant.taskdefs.optional.scm.AntStarTeamCheckOut diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/repository/GetLibraries.java b/src/main/org/apache/tools/ant/taskdefs/optional/repository/GetLibraries.java new file mode 100644 index 000000000..742f36ed0 --- /dev/null +++ b/src/main/org/apache/tools/ant/taskdefs/optional/repository/GetLibraries.java @@ -0,0 +1,315 @@ +/* + * Copyright 2004 The Apache Software Foundation + * + * Licensed 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.apache.tools.ant.taskdefs.optional.repository; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.Reference; + +import java.io.File; +import java.io.IOException; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +/** + * This task will retrieve one or more libraries from a repository.
    + *
  1. Users must declare a repository, either inline or by reference
  2. + *
  3. Dependency checking is used (timestamps) unless forceDownload=true
  4. + *
  5. It is an error if, at the end of the task, a library is missing. + * + * @ant.task + * @since Ant 1.7 + */ +public class GetLibraries extends Task { + + /** + * destination + */ + private File destDir; + + /** + * flag to force a download + */ + private boolean forceDownload = false; + + /** + * flag to force offline + */ + private boolean offline = false; + + /** + * list of libraries + */ + private List libraries = new LinkedList(); + + /** + * repository for retrieval + */ + + private Repository repository; + + public static final String ERROR_ONE_REPOSITORY_ONLY = "Only one repository is allowed"; + public static final String ERROR_NO_DEST_DIR = "No destination directory"; + public static final String ERROR_NO_REPOSITORY = "No repository defined"; + public static final String ERROR_NO_LIBRARIES = "No libraries to load"; + public static final String ERROR_REPO_PROBE_FAILED = "repository probe failed with "; + public static final String ERROR_LIBRARY_FETCH_FAILED = "failed to retrieve "; + public static final String ERROR_FORCED_DOWNLOAD_FAILED = "Failed to download every file on a forced download"; + public static final String ERROR_INCOMPLETE_RETRIEVAL = "Not all libraries could be retrieved"; + + /** + * add a repository. Only one is (currently) supported + * + * @param repo + */ + public void add(Repository repo) { + if (repository != null) { + throw new BuildException(ERROR_ONE_REPOSITORY_ONLY); + } + repository = repo; + } + + + /** + * add a repository. Unless there is explicit support for a subclass + * + * @param repo + */ + public void addRepository(RepositoryRef repo) { + add(repo); + } + + + /** + * add a maven repository. + */ +/* + public void addMavenRepository(MavenRepository repo) { + add(repo); + } +*/ + + /** + * bind to a repository. + */ + public void setRepositoryRef(final Reference ref) { + //create a special repository that can only + //resolve references. + Repository r = new RepositoryRef(getProject(), ref); + add(r); + } + + + /** + * add a library for retrieval + * + * @param lib + */ + public void addLibrary(Library lib) { + libraries.add(lib); + } + + /** + * destination directory for all library files + * + * @param destDir + */ + public void setDestDir(File destDir) { + this.destDir = destDir; + } + + /** + * flag to force a download even if the clock indicates it aint needed. + * + * @param forceDownload + */ + public void setForceDownload(boolean forceDownload) { + this.forceDownload = forceDownload; + } + + /** + * test for being offline + * + * @return true if the offline flag is set + */ + public boolean isOffline() { + return offline; + } + + /** + * declare the system offline. This disables any attempt to retrieve files. + * In this mode, only the presence of files is verified. If forceDownload is + * true, or there is a missing library, then an error will be raised. + * + * @param offline + */ + public void setOffline(boolean offline) { + this.offline = offline; + } + + public File getDestDir() { + return destDir; + } + + public boolean isForceDownload() { + return forceDownload; + } + + public List getLibraries() { + return libraries; + } + + public Repository getRepository() { + return repository; + } + + /** + * validate ourselves + * + * @throws BuildException + */ + public void validate() { + if (destDir == null || !destDir.exists() || !destDir.isDirectory()) { + throw new BuildException(ERROR_NO_DEST_DIR); + } + if (repository == null) { + throw new BuildException(ERROR_NO_REPOSITORY); + } + Iterator it = libraries.iterator(); + while (it.hasNext()) { + Library library = (Library) it.next(); + library.validate(); + } + } + + /** + * Called by the project to let the task do its work. + * + * @throws org.apache.tools.ant.BuildException + * if something goes wrong with the build + */ + public void execute() throws BuildException { + validate(); + Repository repo = repository.resolve(); + repo.validate(); + int toFetch = libraries.size(); + if (toFetch == 0) { + throw new BuildException(ERROR_NO_LIBRARIES); + } + int fetched = 0; + log("Getting libraries from " + repo.toString(), Project.MSG_VERBOSE); + log("Saving libraries to " + destDir.toString(), Project.MSG_VERBOSE); + + bindAllLibraries(); + if (isOffline()) { + log("No retrieval, task is \"offline\""); + verifyAllLibrariesPresent(); + return; + } + + + //connect the repository + repo.connect(this); + try { + + //check for reachability. + //it is up to each repository to decide that. + boolean reachable; + try { + log("Checking repository for reachability", Project.MSG_DEBUG); + reachable = repo.checkRepositoryReachable(); + } catch (IOException e) { + + log(ERROR_REPO_PROBE_FAILED + e.getMessage(), + Project.MSG_VERBOSE); + reachable = false; + } + if (!reachable) { + if (forceDownload) { + throw new BuildException(repo.toString() + + " is unreachable and forceDownload is set"); + } + } else { + log("Repository is live", Project.MSG_DEBUG); + } + + //iterate through the libs we have + Iterator it = libraries.iterator(); + while (it.hasNext()) { + Library library = (Library) it.next(); + library.bind(destDir); + try { + if (repo.fetch(library)) { + fetched++; + } + } catch (IOException e) { + //failures to fetch are logged at verbose level + log(ERROR_LIBRARY_FETCH_FAILED + library); + log(e.getMessage(), Project.MSG_VERBOSE); + } + } + } finally { + repo.disconnect(); + } + + //at this point downloads have finished. + //we do still need to verify that everything worked. + if ((fetched < toFetch && forceDownload)) { + throw new BuildException(ERROR_FORCED_DOWNLOAD_FAILED); + } + + verifyAllLibrariesPresent(); + + } + + /** + * bind all libraries to our destination + */ + protected void bindAllLibraries() { + Iterator it = libraries.iterator(); + while (it.hasNext()) { + Library library = (Library) it.next(); + library.bind(destDir); + } + } + + /** + * verify that all libraries are present + */ + protected void verifyAllLibrariesPresent() { + //iterate through the libs we have + boolean missing = false; + + Iterator it = libraries.iterator(); + while (it.hasNext()) { + Library library = (Library) it.next(); + //check for the library existing + if (!library.exists()) { + //and log if one is missing + log("Missing: " + library.toString(), + Project.MSG_ERR); + missing = true; + } + } + if (missing) { + throw new BuildException(ERROR_INCOMPLETE_RETRIEVAL); + } + } + +} diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/repository/HttpRepository.java b/src/main/org/apache/tools/ant/taskdefs/optional/repository/HttpRepository.java new file mode 100644 index 000000000..4c4bef8eb --- /dev/null +++ b/src/main/org/apache/tools/ant/taskdefs/optional/repository/HttpRepository.java @@ -0,0 +1,447 @@ +/* + * Copyright 2004 The Apache Software Foundation + * + * Licensed 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.apache.tools.ant.taskdefs.optional.repository; + +import org.apache.commons.httpclient.*; +import org.apache.commons.httpclient.cookie.CookiePolicy; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.util.FileUtils; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Date; + +/** + * This is a base class for repositories that are built on URLs. Although you + * can share this datatype, it is *not* thread safe; you can only use it in one + * thread at at time + * + * @since Ant1.7 + */ +public abstract class HttpRepository extends Repository { + /** + * repositoryURL of repository + */ + private String url; + + /** + * username + */ + private String username; + + /** + * password + */ + private String password; + + + /** + * auth realm; can be null + */ + private String realm; + + /** + * this is our http client + */ + private HttpClient client; + + /** + * number of times to retry fetches + */ + private int retries = 1; + + /** + * no repository URL + */ + public static final String ERROR_NO_REPOSITORY_URL = "No repository URL"; + + /** + * owner class + */ + private GetLibraries owner; + + /** + * retry logic + */ + private DefaultMethodRetryHandler retryhandler; + public static final String ERROR_REENTRANT_USE = "Repository is already in use"; + private static final String IF_MODIFIED_SINCE = "If-Modified-Since"; + private static final int BLOCKSIZE = 8192; + + /** + * get the base URL of the repository + * + * @return + */ + public String getUrl() { + return url; + } + + /** + * Set the base URL of the repository + * + * @param url + */ + public void setUrl(String url) { + this.url = url; + } + + public String getUsername() { + return username; + } + + /** + * set the username for the remote repository + * + * @param username + */ + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + /** + * set the password for the remote repository + * + * @param password + */ + public void setPassword(String password) { + this.password = password; + } + + public String getRealm() { + return realm; + } + + /** + * set the realm for authentication; empty string is equivalent to "any + * realm" (the default) + * + * @param realm + */ + public void setRealm(String realm) { + if (realm != null) { + this.realm = realm; + } else { + this.realm = null; + } + } + + + /** + * @return number of times to retry fetches + */ + public int getRetries() { + return retries; + } + + /** + * number of times to retry fetches + * + * @param retries + */ + public void setRetries(int retries) { + this.retries = retries; + } + + /** + * get the client + * + * @return + */ + public HttpClient getClient() { + return client; + } + + public GetLibraries getOwner() { + return owner; + } + + /** + * validate yourself + * + * @throws org.apache.tools.ant.BuildException + * if unhappy + */ + public void validate() { + super.validate(); + checkChildrenAllowed(); + checkAttributesAllowed(); + if (url == null || url.length() == 0) { + throw new BuildException(ERROR_NO_REPOSITORY_URL); + } + } + + /** + * override point: connection is called at the start of the retrieval + * process + * + * @param newOwner + * + * @throws org.apache.tools.ant.BuildException + * + */ + public void connect(GetLibraries newOwner) { + this.owner = newOwner; + if (client != null) { + throw new BuildException(ERROR_REENTRANT_USE); + } + if (!url.endsWith("/")) { + url = url + '/'; + } + client = new HttpClient(); + //retry handler + retryhandler = new DefaultMethodRetryHandler(); + retryhandler.setRequestSentRetryEnabled(false); + retryhandler.setRetryCount(retries); + + //validate the URL + URL repository; + try { + repository = new URL(url); + } catch (MalformedURLException e) { + throw new BuildException(e); + } + //authentication + if (username != null) { + Credentials defaultcreds = + new UsernamePasswordCredentials(username, password); + client.getState().setCredentials(realm, + repository.getHost(), + defaultcreds); + //turn auth on on first call + client.getState().setAuthenticationPreemptive(true); + } + //cookies + client.getState().setCookiePolicy(CookiePolicy.COMPATIBILITY); + } + + /** + * override point: connection is called at the start of the retrieval + * process + * + * @throws org.apache.tools.ant.BuildException + * + */ + + public void disconnect() { + client = null; + retryhandler = null; + } + + /** + * Test for a repository being reachable. This method is called after {@link + * #connect(org.apache.tools.ant.taskdefs.optional.repository.GetLibraries)} + * is called, before any files are to be retrieved. + *

    + * If it returns false the repository considers itself offline. Similarly, + * any ioexception is interpreted as being offline. + *

    + * The Http implementation probes for the base URL being reachable, and + * returning a 200 status code. + * + * @return true if the repository is online. + * + * @throws java.io.IOException + */ + public boolean checkRepositoryReachable() throws IOException { + //return pingBaseURL(); + return true; + } + + private boolean pingBaseURL() throws IOException { + GetMethod get = createGet(getUrl()); + client.executeMethod(get); + return get.getStatusCode() == HttpStatus.SC_OK; + } + + /** + * create a new getMethod against any URI + * + * @param url + * + * @return + */ + public GetMethod createGet(String url) { + GetMethod method = new GetMethod(url); + + method.setMethodRetryHandler(retryhandler); + method.setDoAuthentication(true); + method.setFollowRedirects(true); + + return method; + } + + /** + * @param method + * @param timestamp + * + * @link http://www.w3.org/Protocols/HTTP/HTRQ_Headers.html#if-modified-since + * @link http://www.w3.org/Protocols/rfc850/rfc850.html#z10 + */ + public void setIfModifiedSinceHeader(HttpMethod method, long timestamp) { + Date date = new Date(timestamp); + //ooh, naughty, deprecated. and like why is it deprecated? + method.setRequestHeader(IF_MODIFIED_SINCE, date.toGMTString()); + } + + /** + * fetch a library from the repository + * + * @param library + * + * @return true if we retrieved + * + * @throws org.apache.tools.ant.BuildException + * + */ + public boolean fetch(Library library) throws IOException { + + String path = getRemoteLibraryURL(library); + logVerbose("Library URL=" + path); + logVerbose("destination =" + library.getAbsolutePath()); + GetMethod get = createGet(path); + boolean useTimestamps = !getOwner().isForceDownload() && + !library.exists(); + if (useTimestamps) { + setIfModifiedSinceHeader(get, library.getLastModified()); + } + try { + long start, finish; + start = System.currentTimeMillis(); + client.executeMethod(get); + if (useTimestamps && get.getStatusCode() == HttpStatus.SC_NOT_MODIFIED) { + logDebug("File is not modified"); + //we get here if there is no change in timestamp + //so no fetch + return false; + } + if (get.getStatusCode() != HttpStatus.SC_OK) { + String message = "Request Failed:" + + get.getStatusCode() + + " from " + get.getPath(); + logVerbose(message); + logVerbose(get.getStatusLine().toString()); + logVerbose(get.getStatusText()); + throw new BuildException(message); + } + saveStreamToLibrary(get, library); + finish = System.currentTimeMillis(); + long diff = finish - start; + logVerbose("downloaded in " + diff / 1000 + " seconds"); + } finally { + // Release the connection. + get.releaseConnection(); + } + + return true; + } + + /** + * log something at the verbose level + * + * @param message text to log + */ + protected void logVerbose(String message) { + getOwner().log(message, + Project.MSG_VERBOSE); + } + + protected void logDebug(String message) { + getOwner().log(message, + Project.MSG_DEBUG); + } + + /** + * Get the path to a remote library. This is the full URL + * + * @param library + * + * @return URL to library + */ + protected abstract String getRemoteLibraryURL(Library library); + + /** + * save a stream from a connection to a library. prerequisite: connection + * open and response=200. + * + * @param get + * @param library + * + * @throws java.io.IOException on any trouble. + */ + protected void saveStreamToLibrary(GetMethod get, Library library) + throws IOException { + //we only get here if we are happy + //so save it to a temp file + File tempDest = File.createTempFile("download", ".bin", getOwner() + .getDestDir()); + logDebug("Saving file to " + tempDest); + FileOutputStream fos = new FileOutputStream(tempDest); + InputStream is = get.getResponseBodyAsStream(); + boolean finished = false; + try { + byte[] buffer = new byte[BLOCKSIZE]; + int length; + + while ((length = is.read(buffer)) >= 0) { + fos.write(buffer, 0, length); + } + finished = true; + } finally { + FileUtils.close(fos); + FileUtils.close(is); + // we have started to (over)write dest, but failed. + // Try to delete the garbage we'd otherwise leave + // behind. + if (!finished) { + logVerbose("Deleting temporary file after failed download"); + tempDest.delete(); + } + } + logDebug("download complete; renaming destination file"); + //then copy over the file + File libraryFile = library.getLibraryFile(); + if (libraryFile.exists()) { + libraryFile.delete(); + } + // set the dest file + if (!tempDest.renameTo(libraryFile)) { + tempDest.delete(); + throw new IOException( + "Could not rename temp file to destination file"); + } + } + + /** + * Returns a string representation of the repository + * + * @return the base URL + */ + public String toString() { + return "Repository at " + getUrl(); + } +} diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/repository/Library.java b/src/main/org/apache/tools/ant/taskdefs/optional/repository/Library.java new file mode 100644 index 000000000..a4c3ca6e6 --- /dev/null +++ b/src/main/org/apache/tools/ant/taskdefs/optional/repository/Library.java @@ -0,0 +1,218 @@ +/* + * Copyright 2004 The Apache Software Foundation + * + * Licensed 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.apache.tools.ant.taskdefs.optional.repository; + +import org.apache.tools.ant.BuildException; + +import java.io.File; + +/** + * How we represent libraries + * + * @since 20-Oct-2004 + */ +public class Library { + + //project "ant" + private String project; + + //version "1.5" + private String version; + + //archive prefix "ant-optional" + private String archive; + + /** + * very optional attribute; name of the destination. Autocalculated if not + * set. + */ + + private String destinationName; + + private File libraryFile; + + public static final String ERROR_NO_ARCHIVE = "No archive defined"; + public static final String ERROR_NO_PROJECT = "No project defined"; + public static final String ERROR_NO_VERSION = "No version defined"; + public static final String ERROR_NO_SUFFIX = "No version defined"; + + /** + * suffix + */ + private String suffix = "jar"; + + + public String getProject() { + return project; + } + + public void setProject(String project) { + this.project = project; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getArchive() { + return archive; + } + + public void setArchive(String archive) { + this.archive = archive; + } + + public String getDestinationName() { + return destinationName; + } + + public void setDestinationName(String destinationName) { + this.destinationName = destinationName; + } + + /** + * get the suffix for this file. + * + * @return + */ + public String getSuffix() { + return suffix; + } + + public void setSuffix(String suffix) { + this.suffix = suffix; + } + + public File getLibraryFile() { + return libraryFile; + } + + /** + * fault if the field is null or empty + * + * @param field + * @param message text for fault + * + * @throws BuildException if the field is not set up + */ + private void faultIfEmpty(String field, String message) { + if (field == null || field.length() == 0) { + throw new BuildException(message); + } + } + + /** + * validate; + * + * @throws BuildException if invalid + */ + public void validate() { + faultIfEmpty(archive, ERROR_NO_ARCHIVE); + faultIfEmpty(project, ERROR_NO_PROJECT); + faultIfEmpty(version, ERROR_NO_VERSION); + faultIfEmpty(version, ERROR_NO_SUFFIX); + } + + public String toString() { + return "Library " + getNormalFilename() + + " from project " + project + + " to " + getDestinationName(); + } + + /** + * calculare the destination file of a library + * + * @param baseDir + * + * @throws BuildException if invalid + */ + public void bind(File baseDir) { + validate(); + if (destinationName == null) { + destinationName = getNormalFilename(); + } + libraryFile = new File(baseDir, destinationName); + } + + /** + * a test that is only valid after binding + * + * @return + */ + public boolean exists() { + return libraryFile.exists(); + } + + /** + * get the last modified date + * + * @return + */ + public long getLastModified() { + return libraryFile.lastModified(); + } + + /** + * get the filename from the rule of archive+version+'.'+suffix. Clearly + * only valid if all fields are defined. + * + * @return a string representing the expected name of the file at the + * source + */ + public String getNormalFilename() { + return archive + "-" + version + "." + suffix; + } + + /** + * get the filename of the destination; no path. + * + * @return + */ + public String getDestFilename() { + if (destinationName == null) { + return getNormalFilename(); + } else { + return destinationName; + } + } + + /** + * get a maven path (project/filename) + * + * @param separator directory separator + * + * @return + */ + public String getMavenPath(char separator) { + return project + separator + "jars" + separator + getNormalFilename(); + } + + /** + * get the absolute path of this library + * + * @return + */ + public String getAbsolutePath() { + return libraryFile.getAbsolutePath(); + } + +} diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/repository/MavenRepository.java b/src/main/org/apache/tools/ant/taskdefs/optional/repository/MavenRepository.java new file mode 100644 index 000000000..2de024538 --- /dev/null +++ b/src/main/org/apache/tools/ant/taskdefs/optional/repository/MavenRepository.java @@ -0,0 +1,65 @@ +/* + * Copyright 2004 The Apache Software Foundation + * + * Licensed 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.apache.tools.ant.taskdefs.optional.repository; + + +/** + * A Maven repository knows about maven repository layout rules It also defaults + * to http://www.ibiblio.org/maven/ + * + * @link http://maven.apache.org/reference/user-guide.html#Remote_Repository_Layout + * @link + * @since Ant1.7 + */ +public class MavenRepository extends HttpRepository { + public static final String MAVEN_URL = "http://www.ibiblio.org/maven/"; + + + /** + * bind to the main maven repository + */ + public MavenRepository() { + setUrl(MAVEN_URL); + } + + /** + * Get the path to a remote library. This is the full URL + * + * @param library + * + * @return URL to library + */ + protected String getRemoteLibraryURL(Library library) { + String base = getUrl(); + if (!base.endsWith("/")) { + base = base + '/'; + } + + return base + library.getMavenPath('/'); + } + + /** + * Returns a string representation of the repository + * + * @return the base URL + */ + public String toString() { + return "Maven Repository at " + getUrl(); + } + +} diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/repository/Repository.java b/src/main/org/apache/tools/ant/taskdefs/optional/repository/Repository.java new file mode 100644 index 000000000..2c9f4640b --- /dev/null +++ b/src/main/org/apache/tools/ant/taskdefs/optional/repository/Repository.java @@ -0,0 +1,109 @@ +/* + * Copyright 2004 The Apache Software Foundation + * + * Licensed 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.apache.tools.ant.taskdefs.optional.repository; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.DataType; + +import java.io.IOException; + +/** + * This type represents a repository; a place that stores libraries for + * retrieval. To use this type, you must use a non-abstract class, either one + * that ships with Ant, or one you implement and declare yourself. + *

    + * The <getlibraries> task lets you supply a repository by reference + * inline {@link GetLibraries#add(Repository)} or on the command line {@link + * GetLibraries#setRepositoryRef(org.apache.tools.ant.types.Reference)} + * + * @since Ant1.7 + */ +public abstract class Repository extends DataType { + + + /** + * validate yourself + * + * @throws BuildException if unhappy + */ + public void validate() { + } + + /** + * recursively resolve any references to get the real repository + * + * @return + */ + public final Repository resolve() { + if (getRefid() == null) { + return this; + } else { + Repository repository = (Repository) getCheckedRef(this.getClass(), + "Repository"); + return repository; + } + } + + /** + * override point: connection is called at the start of the retrieval + * process + * + * @param owner owner of the libraries + * + * @throws BuildException + */ + public void connect(GetLibraries owner) { + + } + + /** + * override point: connection is called at the start of the retrieval + * process + * + * @throws BuildException + */ + + public void disconnect() { + + } + + + /** + * Test for a repository being reachable. This method is called after {@link + * #connect(GetLibraries)} is called, before any files are to be retrieved. + *

    + * If it returns false the repository considers itself offline. Similarly, + * any ioexception is interpreted as being offline. + * + * @return true if the repository is online. + * + * @throws IOException + */ + public abstract boolean checkRepositoryReachable() throws IOException; + + /** + * fetch a library from the repository + * + * @param library + * + * @return + */ + public abstract boolean fetch(Library library) throws IOException; + + +} diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/repository/RepositoryRef.java b/src/main/org/apache/tools/ant/taskdefs/optional/repository/RepositoryRef.java new file mode 100644 index 000000000..d53c45576 --- /dev/null +++ b/src/main/org/apache/tools/ant/taskdefs/optional/repository/RepositoryRef.java @@ -0,0 +1,76 @@ +/* + * Copyright 2004 The Apache Software Foundation + * + * Licensed 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.apache.tools.ant.taskdefs.optional.repository; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.Reference; + +import java.io.IOException; + +/** + * not a real repository; one to paste a reference into the chain for + * resolution. + * + * @since Ant1.7 + */ +public final class RepositoryRef extends Repository { + + + /** + * create a repository reference + * + * @param reference + */ + public RepositoryRef(Project project, Reference reference) { + setRefid(reference); + setProject(project); + } + + /** + * empty constructor + */ + public RepositoryRef() { + } + + /** + * Test for a repository being reachable. This method is called after {@link + * #connect(GetLibraries)} is called, before any files are to be retrieved. + *

    + * If it returns false the repository considers itself offline. Similarly, + * any ioexception is interpreted as being offline. + * + * @return true if the repository is online. + * + * @throws java.io.IOException + */ + public boolean checkRepositoryReachable() throws IOException { + return false; + } + + /** + * fetch a library from the repository + * + * @param library + * + * @return + */ + public boolean fetch(Library library) throws IOException { + throw new BuildException("Not Implemented"); + } + +} diff --git a/src/main/org/apache/tools/ant/types/defaults.properties b/src/main/org/apache/tools/ant/types/defaults.properties index 48772bee7..f4cd8a1b9 100644 --- a/src/main/org/apache/tools/ant/types/defaults.properties +++ b/src/main/org/apache/tools/ant/types/defaults.properties @@ -33,4 +33,5 @@ scriptfilter=org.apache.tools.ant.types.optional.ScriptFilter propertyset=org.apache.tools.ant.types.PropertySet assertions=org.apache.tools.ant.types.Assertions concatfilter=org.apache.tools.ant.filters.ConcatFilter -ispingable=org.apache.tools.ant.taskdefs.optional.condition.IsPingable \ No newline at end of file +ispingable=org.apache.tools.ant.taskdefs.optional.condition.IsPingable +mavenrepository=org.apache.tools.ant.taskdefs.optional.repository.MavenRepository \ No newline at end of file diff --git a/src/testcases/org/apache/tools/ant/taskdefs/optional/GetLibrariesTest.java b/src/testcases/org/apache/tools/ant/taskdefs/optional/GetLibrariesTest.java new file mode 100644 index 000000000..bc6481fb9 --- /dev/null +++ b/src/testcases/org/apache/tools/ant/taskdefs/optional/GetLibrariesTest.java @@ -0,0 +1,109 @@ +/* + * Copyright 2004 The Apache Software Foundation + * + * Licensed 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.apache.tools.ant.taskdefs.optional; + +import org.apache.tools.ant.BuildFileTest; +import org.apache.tools.ant.taskdefs.optional.repository.GetLibraries; + +/** + * test the test libraries stuff. + * skip all the tests if we are offline + */ +public class GetLibrariesTest extends BuildFileTest { + private final static String TASKDEFS_DIR = "src/etc/testcases/taskdefs/optional/"; + + + public GetLibrariesTest(String name) { + super(name); + } + + public void setUp() { + configureProject(TASKDEFS_DIR + "getlibraries.xml"); + } + + + protected boolean offline() { + return "true".equals(System.getProperty("offline")); + } + + public void tearDown() { + executeTarget("cleanup"); + } + + public void testEmpty() { + expectBuildException("testEmpty",GetLibraries.ERROR_NO_DEST_DIR); + } + + public void testEmpty2() { + expectBuildException("testEmpty2", GetLibraries.ERROR_NO_REPOSITORY); + } + + public void testEmpty3() { + expectBuildException("testEmpty3", GetLibraries.ERROR_NO_LIBRARIES); + } + + public void testNoRepo() { + expectBuildException("testNoRepo", GetLibraries.ERROR_NO_REPOSITORY); + } + + public void testUnknownReference() { + expectBuildException("testUnknownReference", "Reference unknown not found."); + } + + /** + * refs are broken + * */ + public void testFunctionalInline() { + if(offline()) { + return; + } + executeTarget("testFunctionalInline"); + } + + public void testMavenInline() { + if (offline()) { + return; + } + executeTarget("testMavenInline"); + } + + public void testTwoRepositories() { + expectBuildException("testTwoRepositories", GetLibraries.ERROR_ONE_REPOSITORY_ONLY); + } + + public void testMavenInlineBadURL() { + if (offline()) { + return; + } + expectBuildException("testTwoRepositories", + GetLibraries.ERROR_INCOMPLETE_RETRIEVAL); + } + + public void testRenaming() { + if (offline()) { + return; + } + executeTarget("testRenaming"); + } + + public void testOverwrite() { + if (offline()) { + return; + } + executeTarget("testOverwrite"); + } + }