Return-Path: Mailing-List: contact ant-dev-help@jakarta.apache.org; run by ezmlm Delivered-To: mailing list ant-dev@jakarta.apache.org Received: (qmail 89089 invoked from network); 14 Oct 2000 18:39:57 -0000 Received: from natmail2.webmailer.de (HELO post.webmailer.de) (192.67.198.65) by locus.apache.org with SMTP; 14 Oct 2000 18:39:57 -0000 Received: from ns2000 (pec-12-5.tnt2.hh2.uunet.de [149.225.12.5]) by post.webmailer.de (8.9.3/8.8.7) with SMTP id UAA13776 for ; Sat, 14 Oct 2000 20:39:47 +0200 (MET DST) Message-ID: <002301c0360e$608c8dc0$050ce195@ns2000> From: "Nico Seessle" To: Subject: For 2.0: Ant-Extension Mechanism Date: Sat, 14 Oct 2000 20:41:14 +0200 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_0020_01C0361F.18578990" X-Priority: 3 X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook Express 5.00.2919.6700 X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2919.6700 X-Spam-Rating: locus.apache.org 1.6.2 0/1000/N This is a multi-part message in MIME format. ------=_NextPart_000_0020_01C0361F.18578990 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit - Changed build.xml to create *.tsk-files (which is currently the extension I choose for ant-extension-files) for some of the currently-core tasks and all of the optional tasks - Changed Project.java to load Task-Information from the ext-subdirectory of ant.home (using AntExtensionHelper) - All calls to project.addTaskDefinition have been changed to create a new TaskDefinition in-place and use this to add the TaskDefinition (Project.java, Taskdef.java, Ant.java, CallTarget.java) - Changed Main and added an option to print the currently know tasks (-tasks) - Uncommented several tasks in taskdefs/default.properties (all optional and deprecated and some of the currently-core tasks (which I personally don't think are "really" core). Deprecated tasks will no longer be included in the task-list, optional-tasks will get some separate files (vss.tsk, script.tsk, ...) and all tasks formerly included in ant.jar and now removed from default.properties are in core.tsk. - Added a task TaskLib which creates the tsk-files (although one could use jar directly, but would not have the simple error-checking) I don't think this is complete (or how one would call it), but it worked for me (and my buildfile) and it's a starting-point. What do you think of it? Nico ------=_NextPart_000_0020_01C0361F.18578990 Content-Type: text/plain; name="diff.txt" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="diff.txt" Index: build.xml =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /home/cvspublic/jakarta-ant/build.xml,v retrieving revision 1.83 diff -u -r1.83 build.xml --- build.xml 2000/10/13 13:15:39 1.83 +++ build.xml 2000/10/14 18:21:13 @@ -21,6 +21,7 @@ + @@ -127,6 +128,7 @@ @@ -225,7 +227,7 @@ - + @@ -233,6 +235,9 @@ + + + =20 =20 @@ -259,6 +264,9 @@ + + + @@ -366,5 +374,231 @@ =20 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +=20 =20 Index: src/main/org/apache/tools/ant/Main.java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: = /home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/Main.java,v retrieving revision 1.21 diff -u -r1.21 Main.java --- src/main/org/apache/tools/ant/Main.java 2000/09/24 09:00:07 1.21 +++ src/main/org/apache/tools/ant/Main.java 2000/10/14 18:21:17 @@ -119,6 +119,11 @@ private boolean projectHelp =3D false; =20 /** + * Indicates we should only load the available Tasks and list them + */ + private boolean listTasks =3D false; + + /** * Command line entry point. This method kicks off the building * of a project object and executes a build using either a given * target or the default target. @@ -233,6 +243,9 @@ } else if (arg.equals("-projecthelp")) { // set the flag to display the targets and quit projectHelp =3D true; + } else if (arg.equals("-tasks")) { + // set the flag to display the targets and quit + listTasks =3D true; } else if (arg.startsWith("-")) { // we don't have any more args to recognize! String msg =3D "Unknown arg: " + arg; @@ -395,6 +408,8 @@ =20 if (projectHelp) { printTargets(project); + } else if (listTasks) {=20 + printTasks(project); } else { // actually do some work project.executeTargets(targets); @@ -473,6 +488,7 @@ msg.append("Options: " + lSep); msg.append(" -help print this message" + = lSep); msg.append(" -projecthelp print project help = information" + lSep); + msg.append(" -tasks print information about = available tasks" + lSep); msg.append(" -version print the version = information and exit" + lSep); msg.append(" -quiet be extra quiet" + lSep); msg.append(" -verbose be extra verbose" + lSep); @@ -547,6 +563,62 @@ printTargets(subNames, null, "Subtargets:", 0); } =20 + /** + * Print out a list of all defined tasks + */ + private static void printTasks(Project project) { + String lSep =3D System.getProperty("line.separator"); + StringBuffer msg =3D new StringBuffer(); + int maxLength =3D 0; + =20 + Vector builtIn =3D new Vector(); + Vector extension =3D new Vector(); + Vector thruTaskdef =3D new Vector(); + =20 + Enumeration taskDefinitions =3D = project.getTaskDefinitions().elements(); + while (taskDefinitions.hasMoreElements()) {=20 + TaskDefinition taskDef =3D = (TaskDefinition)taskDefinitions.nextElement(); + if (taskDef.isBuiltIn()) {=20 + builtIn.addElement(taskDef); + } else if (taskDef.isExtension()) {=20 + extension.addElement(taskDef); + } + else { + thruTaskdef.addElement(taskDef); + } + =20 + if (taskDef.getName().length() > maxLength) {=20 + maxLength =3D taskDef.getName().length(); + } + } + + printTasks(builtIn, "Built-In Tasks", maxLength); + printTasks(extension, "Extension Tasks", maxLength); + printTasks(thruTaskdef, "Tasks defined in the build-file", = maxLength); + } + =20 + private static void printTasks(Vector taskDefs, String heading, int = maxLength) {=20 + String lSep =3D System.getProperty("line.separator"); + String spaces =3D " "; + while (spaces.length(). */ package org.apache.tools.ant; import java.util.*; import java.io.*; import java.util.zip.*; import org.xml.sax.*; import org.w3c.dom.*; import javax.xml.parsers.*; import org.apache.tools.ant.types.Path; public class AntExtensionHelper {=20 =20 private static SAXParserFactory parserFactory =3D null; private org.xml.sax.Parser parser; private SAXParser saxParser; private Locator locator; private Project project =3D null; private File extensionDir =3D null; =20 private AntClassLoader loader =3D null; =20 public static void initExtensionTasks(Project project,=20 File extensionDir) {=20 new AntExtensionHelper(project, = extensionDir).initExtensionTasks(); } private AntExtensionHelper(Project project, File extensionDir) {=20 this.project =3D project; this.extensionDir =3D extensionDir; } =20 private void initExtensionTasks() {=20 try { saxParser =3D getParserFactory().newSAXParser(); parser =3D saxParser.getParser(); } catch(ParserConfigurationException exc) { throw new BuildException("Parser has not been configured = correctly", exc); } catch(SAXException exc) { Throwable t =3D exc.getException(); if (t instanceof BuildException) { throw (BuildException) t; } throw new BuildException(exc.getMessage(), t); } =20 String[] tskFiles =3D extensionDir.list(new = TskExtensionFilenameFilter()); =20 for (int i =3D 0; i < tskFiles.length; i++) {=20 =20 String taskFileName =3D extensionDir.getAbsolutePath() +=20 File.separator + tskFiles[i]; =20 project.log("Loading Extension: " + taskFileName, = Project.MSG_VERBOSE); =20 loadFile(taskFileName); =20 } } =20 private void loadFile(String filename) {=20 ZipFile zipFile =3D null; =20 loader =3D new AntClassLoader(project, new Path(project, = filename)); =20 try {=20 zipFile =3D new ZipFile(filename); =20 ZipEntry tasklibEntry =3D = zipFile.getEntry("META-INF/tasklib.xml"); if (tasklibEntry =3D=3D null) {=20 throw new BuildException("Not a valid Ant-Tasklib: " + = filename); } =20 InputStream in =3D zipFile.getInputStream(tasklibEntry); =20 try { saxParser.parse(in, new RootHandler()); } catch(SAXParseException exc) { Location location =3D new Location(filename,=20 exc.getLineNumber(),=20 exc.getColumnNumber()); Throwable t =3D exc.getException(); if (t instanceof BuildException) { BuildException be =3D (BuildException) t; if (be.getLocation() =3D=3D = Location.UNKNOWN_LOCATION) { be.setLocation(location); } throw be; } =20 throw new BuildException(exc.getMessage(), t, location); } catch(SAXException exc) { Throwable t =3D exc.getException(); if (t instanceof BuildException) { throw (BuildException) t; } throw new BuildException(exc.getMessage(), t); } =20 in.close(); } catch (IOException ex) {=20 throw new BuildException(ex); } finally {=20 if (zipFile !=3D null) {=20 try {=20 zipFile.close(); } catch (IOException ex) {=20 } } } =20 loader =3D null; } =20 private static SAXParserFactory getParserFactory() { if (parserFactory =3D=3D null) { parserFactory =3D SAXParserFactory.newInstance(); } return parserFactory; } private static class TskExtensionFilenameFilter implements = FilenameFilter {=20 public boolean accept(File f, String s) {=20 return s.toLowerCase().endsWith(".tsk"); } } private class RootHandler extends HandlerBase { public void startElement(String tag, AttributeList attrs) throws = SAXParseException { if (tag.equals("tasklib")) { new TasklibHandler(this).init(tag, attrs); } else { throw new SAXParseException("Config file is not of = expected XML type", locator); } } public void setDocumentLocator(Locator locator) { AntExtensionHelper.this.locator =3D locator; } } private class AbstractHandler extends HandlerBase { protected DocumentHandler parentHandler; public AbstractHandler(DocumentHandler parentHandler) { this.parentHandler =3D parentHandler; // Start handling SAX events parser.setDocumentHandler(this); } public void startElement(String tag, AttributeList attrs) throws = SAXParseException { throw new SAXParseException("Unexpected element \"" + tag + = "\"", locator); } public void characters(char[] buf, int start, int end) throws = SAXParseException { String s =3D new String(buf, start, end).trim(); if (s.length() > 0) { throw new SAXParseException("Unexpected text \"" + s + = "\"", locator); } } public void endElement(String name) throws SAXException { // Let parent resume handling SAX events parser.setDocumentHandler(parentHandler); } } private class TasklibHandler extends AbstractHandler { public TasklibHandler(DocumentHandler parentHandler) { super(parentHandler); } public void init(String tag, AttributeList attrs) throws = SAXParseException { String name =3D null; String version =3D null; String home =3D null; =20 for (int i =3D 0; i < attrs.getLength(); i++) { String key =3D attrs.getName(i); String value =3D attrs.getValue(i); if (key.equals("name")) { name =3D value; } else if (key.equals("version")) { version =3D value; } else if (key.equals("home")) { home =3D value; } else { throw new SAXParseException("Unexpected attribute = \"" + key + "\"", locator); } } } =20 public void startElement(String name, AttributeList attrs) = throws SAXParseException { if (name.equals("task")) { handleTask(name, attrs); } else { throw new SAXParseException("Unexpected element \"" + = name + "\"", locator); } } =20 private void handleTask(String name, AttributeList attrs) throws = SAXParseException { new TaskHandler(this).init(name, attrs); } } =20 private class TaskHandler extends AbstractHandler { public TaskHandler(DocumentHandler parentHandler) { super(parentHandler); } public void init(String tag, AttributeList attrs) throws = SAXParseException { String taskName =3D null; String className =3D null; String version =3D null; String description =3D null; =20 for (int i =3D 0; i < attrs.getLength(); i++) { String key =3D attrs.getName(i); String value =3D attrs.getValue(i); if (key.equals("name")) { taskName =3D value; } else if (key.equals("classname")) { className =3D value; } else if (key.equals("version")) { version =3D value; } else if (key.equals("description")) { description =3D value; } else { throw new SAXParseException("Unexpected attribute = \"" + key + "\"", locator); } } =20 if (taskName =3D=3D null) { throw new SAXParseException("task element appears = without a name attribute", locator); } if (className =3D=3D null) { throw new SAXParseException("task element appears = without a classname attribute", locator); } =20 try {=20 Class cls =3D loader.loadClass(className); TaskDefinition taskDef =3D new TaskDefinition(taskName, = cls, description, = TaskDefinition.TASK_EXTENSION); project.addTaskDefinition(taskName, taskDef); } catch (ClassNotFoundException ex) {=20 //throw new BuildException("Class " + className + " = could not ne found"); } } } } ------=_NextPart_000_0020_01C0361F.18578990 Content-Type: application/octet-stream; name="TaskDefinition.java" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="TaskDefinition.java" package org.apache.tools.ant; public class TaskDefinition { public static final int TASK_BUILT_IN = 0; public static final int TASK_EXTENSION = 1; public static final int TASK_TASKDEF = 2; private String taskName = null; private Class taskClass = null; private String taskDescription = null; private int taskType = -1; public TaskDefinition(String taskName, Class taskClass, String taskDescription, int taskType) { this.taskName = taskName; this.taskClass = taskClass; this.taskDescription = taskDescription; this.taskType = taskType; } public String getName() { return taskName; } public Class getTaskClass() { return taskClass; } public String getDescription() { return taskDescription; } public boolean isBuiltIn() { return taskType == TASK_BUILT_IN; } public boolean isExtension() { return taskType == TASK_EXTENSION; } } ------=_NextPart_000_0020_01C0361F.18578990 Content-Type: application/octet-stream; name="TaskLib.java" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="TaskLib.java" /* * The Apache Software License, Version 1.1 * * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software = itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * Foundation" must not be used to endorse or promote products = derived * from this software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . */ package org.apache.tools.ant.taskdefs; import org.apache.tools.ant.*; import java.util.*; import javax.xml.parsers.*; import org.w3c.dom.*; import java.io.*; import java.util.zip.*; public class TaskLib extends Jar {=20 private static String lSep =3D System.getProperty("line.separator"); private static final DocumentBuilder builder =3D = getDocumentBuilder(); private static DocumentBuilder getDocumentBuilder() { try { return = DocumentBuilderFactory.newInstance().newDocumentBuilder(); } catch(Exception exc) { throw new ExceptionInInitializerError(exc); } } private Document doc; private byte[] bytes; =20 private String name =3D null; private String version =3D null; private String home =3D null; =20 private Vector tasks =3D new Vector(); =20 public TaskLib() { super(); archiveType =3D "tsk"; emptyBehavior =3D "skip"; } =20 public void setName(String value) {=20 name =3D value; } public void setVersion(String value) {=20 version =3D value; } public void setHome(String value) {=20 home =3D value; } =20 public void execute() throws BuildException { doc =3D builder.newDocument(); =20 Element tasklibElement =3D doc.createElement("tasklib"); if (name !=3D null)=20 tasklibElement.setAttribute("name", name); if (version !=3D null)=20 tasklibElement.setAttribute("version", version); if (home !=3D null)=20 tasklibElement.setAttribute("home", home); Enumeration enum =3D tasks.elements(); while (enum.hasMoreElements()) {=20 TaskLib.Task task =3D (TaskLib.Task)enum.nextElement(); =20 Element taskElement =3D doc.createElement("task"); if (task.getName() =3D=3D null) {=20 throw new BuildException("Every task must have a name"); } taskElement.setAttribute("name", task.getName()); if (task.getClassname() =3D=3D null) {=20 throw new BuildException("Every task must have a = classname"); } taskElement.setAttribute("classname", task.getClassname()); if (task.getVersion() !=3D null)=20 taskElement.setAttribute("version", task.getVersion()); if (task.getDescription() !=3D null)=20 taskElement.setAttribute("description", = task.getDescription()); tasklibElement.appendChild(taskElement); } try { ByteArrayOutputStream bos =3D new ByteArrayOutputStream(); Writer out =3D new PrintWriter(bos); out.write("" + lSep + lSep); write(tasklibElement, out, 0); out.flush(); out.close(); bytes =3D bos.toByteArray(); =20 } catch(IOException exc) { throw new BuildException("Unable to close log file", exc); } super.execute(); } /** * Writes a DOM element to a file. */ private static void write(Element element, Writer out, int indent) = throws IOException { // Write indent characters for (int i =3D 0; i < indent; i++) { out.write("\t"); } // Write element out.write("<"); out.write(element.getTagName()); // Write attributes NamedNodeMap attrs =3D element.getAttributes(); for (int i =3D 0; i < attrs.getLength(); i++) { Attr attr =3D (Attr) attrs.item(i); out.write(" "); out.write(attr.getName()); out.write("=3D\""); out.write(attr.getValue()); out.write("\""); } out.write(">"); // Write child attributes and text boolean hasChildren =3D false; NodeList children =3D element.getChildNodes(); for (int i =3D 0; i < children.getLength(); i++) { Node child =3D children.item(i); if (child.getNodeType() =3D=3D Node.ELEMENT_NODE) { if (!hasChildren) { out.write(lSep); hasChildren =3D true; } write((Element)child, out, indent + 1); } if (child.getNodeType() =3D=3D Node.TEXT_NODE) { out.write(((Text)child).getData()); } } // If we had child elements, we need to indent before we close // the element, otherwise we're on the same line and don't need // to indent if (hasChildren) { for (int i =3D 0; i < indent; i++) { out.write("\t"); } } // Write element close out.write("" + lSep); } =20 public TaskLib.Task createTask() {=20 TaskLib.Task task =3D new TaskLib.Task(); tasks.addElement(task); return task; } =20 public static class Task { private String taskName =3D null; private String taskClass =3D null; private String taskVersion =3D null; private String description =3D null; =20 public void setName(String value) {=20 taskName =3D value; } public String getName() { return taskName; } public void setClassname(String value) {=20 taskClass =3D value; } public String getClassname() { return taskClass; } public void setVersion(String value) {=20 taskVersion =3D value; } public String getVersion() { return taskVersion; } public void setDescription(String value) {=20 description =3D value; } public String getDescription() {=20 return description; } } =20 protected void initZipOutputStream(ZipOutputStream zOut) throws IOException, BuildException {=20 =20 zipDir(null, zOut, "META-INF/"); zipFile(new ByteArrayInputStream(bytes), zOut,=20 "META-INF/tasklib.xml",=20 System.currentTimeMillis()); super.initZipOutputStream(zOut); } } ------=_NextPart_000_0020_01C0361F.18578990--