diff --git a/proposal/anteater/README b/proposal/anteater/README new file mode 100644 index 000000000..4fc1737ea --- /dev/null +++ b/proposal/anteater/README @@ -0,0 +1,14 @@ +README for Ant(Eater) +--------------------------------------------------------------------------------- + +Execution: + + ant [args] target + +Args: + + -help + -quiet + -verbose + -taskpath [path] + -antfile [file] \ No newline at end of file diff --git a/proposal/anteater/bootstrap/Bootstrap.java b/proposal/anteater/bootstrap/Bootstrap.java new file mode 100644 index 000000000..e15062fa2 --- /dev/null +++ b/proposal/anteater/bootstrap/Bootstrap.java @@ -0,0 +1,299 @@ +// ------------------------------------------------------------------------------- +// Copyright (c)2000 Apache Software Foundation +// ------------------------------------------------------------------------------- + +import java.io.*; +import java.util.*; +import java.util.zip.*; + +/** + * Quick and dirty single class bootstrap utility for getting Ant off + * the ground when in need. To use, compile this file in the directory + * where the source code is in the repository, then execute it. That's + * it.

+ * + * No pretense is made that this is an elegant peice of code. This code + * only exists to do a ground zero build of Ant. Any other building of + * Ant should be done with itself whenever possible. + * + * @author James Duncan Davidson (duncan@apache.org) + */ +public class Bootstrap { + + private static String base = "../"; + private static String[] modules = new String[]{"copy", "echo", "jar", "javac"}; + + /** + * Command line entry point. + */ + public static void main(String[] args) { + + // check for secret sugar left by MRJ startup script... + + if (args.length > 0) { + if (args[0].equals("osx")) { + base = ""; + } + } + + long startTime = System.currentTimeMillis(); + + System.out.println("Starting Bootstrap...."); + + // ------------------------------------------------------------ + // first create dirs that we need for strapping + // ------------------------------------------------------------ + + mkdir(base + "bootstrap/temp"); + mkdir(base + "bootstrap/temp/main"); + mkdir(base + "bootstrap/temp/tasks"); + mkdir(base + "bootstrap/temp/taskjars"); + + for (int i = 0; i < modules.length; i++) { + mkdir(base + "bootstrap/temp/tasks/" + modules[i]); + } + + // ------------------------------------------------------------ + // build the main thing + // ------------------------------------------------------------ + + Vector v = getSources(base + "source/main"); + doCompile(base + "bootstrap/temp/main", v); + + // ------------------------------------------------------------ + // now build each of the needed peices into their + // areas within the strapping area + // ------------------------------------------------------------ + + for (int i = 0; i < modules.length; i++) { + buildModule(modules[i]); + } + + // ------------------------------------------------------------ + // now, set classpaths and launch an Ant build to + // have Ant build itself nicely + // ------------------------------------------------------------ + + System.out.println(); + System.out.println("-------------------------------------------"); + System.out.println("STARTING REAL BUILD"); + System.out.println("-------------------------------------------"); + System.out.println(); + + String[] cmdarray = new String[9]; + cmdarray[0] = "java"; + cmdarray[1] = "-cp"; + cmdarray[2] = base + "bootstrap/temp/main:" + base + "lib/jaxp.jar:" + + base + "lib/crimson.jar"; + cmdarray[3] = "org.apache.ant.cli.Main"; + cmdarray[4] = "-taskpath"; + cmdarray[5] = base + "bootstrap/temp/taskjars"; + cmdarray[6] = "-buildfile"; + cmdarray[7] = base + "source/main.ant"; + cmdarray[8] = "default"; + + try { + Runtime runtime = Runtime.getRuntime(); + Process process = runtime.exec(cmdarray); + + // echo output from process + + InputStream in = process.getInputStream(); + byte[] buf = new byte[80]; + int count = 0; + count = in.read(buf, 0, buf.length); + while (count != -1) { + System.out.write(buf, 0, count); + count = in.read(buf, 0, buf.length); + } + + in = process.getErrorStream(); + count = in.read(buf, 0, buf.length); + if (count > 0) { + System.out.println(); + System.out.println("Error Stream Output:"); + + while (count != -1) { + System.out.write(buf, 0, count); + count = in.read(buf, 0, buf.length); + } + } + } catch (Exception e) { + System.out.println("OUCHY: " + e); + return; + } + + System.out.println(); + System.out.println("-------------------------------------------"); + System.out.println("FINISHED WITH REAL BUILD"); + System.out.println("-------------------------------------------"); + System.out.println(); + + // ------------------------------------------------------------ + // Remove Temporary classes + // ------------------------------------------------------------ + + // delete(tempDirName); + + // ------------------------------------------------------------ + // Print Closer + // ------------------------------------------------------------ + + long endTime = System.currentTimeMillis(); + long elapsd = endTime - startTime; + System.out.println("Bootstrap Time: " + (elapsd/1000) + "." + (elapsd%1000) + + " seconds"); + } + + private static void mkdir(String arg) { + File dir = new File(arg); + if (dir.exists() && !dir.isDirectory()) { + System.out.println("Oh, horrors! Dir " + arg + " " + + "doesn't seem to be a dir... Stop!"); + System.exit(1); + } + if (!dir.exists()) { + System.out.println("Making dir: " + arg); + dir.mkdir(); + } + } + + private static void buildModule(String arg) { + System.out.println("Building " + arg); + + // get all sources and hand them off to the compiler to + // build over into destination + + Vector v = getSources(base + "source/coretasks/" + arg); + if (v.size() > 0) { + doCompile(base + "bootstrap/temp/tasks/" + arg, v); + } + + + // move taskdef.properties for the module + + copyfile(base + "source/coretasks/" + arg + "/taskdef.properties", + base + "bootstrap/temp/tasks/" + arg + "/taskdef.properties"); + + // jar up tasks + try { + jarDir(new File(base + "bootstrap/temp/tasks/" + arg), + new File(base + "bootstrap/temp/taskjars/" + arg + ".jar")); + } catch(IOException ioe) { + System.out.println("problem jar'ing: " + arg); + } + } + + private static Vector getSources(String arg) { + + File sourceDir = new File(arg); + + Vector v = new Vector(); + scanDir(sourceDir, v, ".java"); + return v; + } + + private static void jarDir(File dir, File jarfile) throws IOException { + String[] files = dir.list(); + if (files.length > 0) { + System.out.println("Jaring: " + jarfile); + FileOutputStream fos = new FileOutputStream(jarfile); + ZipOutputStream zos = new ZipOutputStream(fos); + jarDir(dir, "", zos); + zos.close(); + } + } + + private static void jarDir(File dir, String prefix, ZipOutputStream zos) throws + IOException + { + String[] files = dir.list(); + for (int i = 0; i < files.length; i++) { + File f = new File(dir, files[i]); + if (f.isDirectory()) { + jarDir(f, prefix + "/" + files[i], zos); + } else { + ZipEntry ze = new ZipEntry(prefix + "/" + files[i]); + zos.putNextEntry(ze); + FileInputStream fis = new FileInputStream(f); + int count = 0; + byte[] buf = new byte[8 * 1024]; + count = fis.read(buf, 0, buf.length); + while (count != -1) { + zos.write(buf, 0, count); + count = fis.read(buf, 0, buf.length); + } + fis.close(); + } + } + } + + private static void scanDir(File dir, Vector v, String endsWith) { + // System.out.println("user.dir=" + System.getProperty("user.dir")); + // System.out.println("Scanning: " + dir); + String[] files = dir.list(); + // System.out.println("Files: " + files); + for (int i = 0; i < files.length; i++) { + File f = new File(dir, files[i]); + if (f.isDirectory()) { + scanDir(f, v, endsWith); + } else { + if (files[i].endsWith(endsWith)) { + v.addElement(f); + } + } + } + } + + private static void doCompile(String dest, Vector sources) { + System.out.println(" Compiling " + sources.size() + " files to " + dest); + + // XXX This should be more forgiving about compiling wherever + // under whatever compiler, but this works so... + + sun.tools.javac.Main compiler = new sun.tools.javac.Main(System.out, + "javac"); + String[] args = new String[sources.size() + 4]; + args[0] = "-classpath"; + args[1] = base + "bootstrap/temp/main:" + base + "lib/jaxp.jar:" + + base + "lib/crimson.jar"; + args[2] = "-d"; + args[3] = dest; + for (int i = 0; i < sources.size(); i++) { + args[4+i] = ((File)sources.elementAt(i)).toString(); + } + + // System.out.print("javac "); + // for (int i = 0; i < args.length; i++) { + // System.out.print(args[i] + " "); + // } + // System.out.println(); + + compiler.compile(args); + } + + private static void copyfile(String from, String dest) { + File fromF = new File(from); + File destF = new File(dest); + if (fromF.exists()) { + System.out.println(" Copying " + from); + try { + FileInputStream in = new FileInputStream(fromF); + FileOutputStream out = new FileOutputStream(destF); + byte[] buf = new byte[1024 * 16]; + int count = 0; + count = in.read(buf, 0, buf.length); + if (count != -1) { + out.write(buf, 0, count); + count = in.read(buf, 0, buf.length); + } + + in.close(); + out.close(); + } catch (IOException ioe) { + System.out.println("OUCH: " + from); + System.out.println(ioe); + } + } + } +} \ No newline at end of file diff --git a/proposal/anteater/bootstrap/README b/proposal/anteater/bootstrap/README new file mode 100644 index 000000000..1d551d508 --- /dev/null +++ b/proposal/anteater/bootstrap/README @@ -0,0 +1,52 @@ +BOOTSTRAP FOLDER README +--------------------------------------------------------------------- + +The utilities provided here are used by the developers of Ant to +bootstrap builds of Ant and will be used by the nightly build process +to build Ant from a zero state. + +That said, there is no reason for most folks -- even hard core Ant +developers -- to use the files here on a regular basis. You should +really have the latest stable version of Ant installed somewhere so +that you can easily build Ant using itself. Check out the +installation guidelines in the documentation for suggestions on how +Ant can be installed as a full time program of your system. + +HOW TO USE + +So, you really want to use the bootstrap facilities instead of just +downloading a build from somewhere? Ok. Here's how it works: + + * Make sure that sun.tools.javac.Main is on your classpath. + Sometimes it is, sometimes it isn't -- it depends on the JDK + installed on your machine. You can do a quick check using + the 'javap sun.tools.javac.Main' command to see if it is. + + * Make sure that you have a JAXP 1.1 compliant parser in your + classpath. The Bootstrap itself doesn't need XML parsing + classes, but Ant itself does. A good test for this is + 'javap javax.xml.parsers.DocumentBuilder' + + * Compile Bootstrap.java. You should end up with Bootstrap.class + and maybe a few other classes (depending). + + * Execute the Bootstrap class. + +How this will work in practice is: + + % javac Bootstrap.java + % java Bootstrap + +The Bootstrap class will grind out a preliminary build in the directory +'temp/' which will be placed in this directory, then use that build to +build a real copy of Ant into '../Build' using Ant's own makefile. After +doing this, the Boostrap class will remove the intermediate build in +the 'temp/' directory. + +HISTORICAL NOTE + +The Bootstrap class is somewhat the same rough hack as the first sketch +of Ant itself -- a proof of concept that a Java based build system +could work out halfway decently. Of course, Ant has expanded much past +the capabilities of this, but this little start serves as a useful +tool to bootstrap builds. \ No newline at end of file diff --git a/proposal/anteater/source/coretasks/echo/org/apache/ant/echo/EchoTask.java b/proposal/anteater/source/coretasks/echo/org/apache/ant/echo/EchoTask.java new file mode 100644 index 000000000..39bc2920e --- /dev/null +++ b/proposal/anteater/source/coretasks/echo/org/apache/ant/echo/EchoTask.java @@ -0,0 +1,44 @@ +package org.apache.ant.echo; + +import java.io.*; +import java.util.*; + +import org.apache.ant.*; + +/** + * Basic echo task that just spits out whatever it is supposed to... + * + * @author James Duncan Davidson (duncan@apache.org) + */ +public class EchoTask extends AbstractTask { + + // ----------------------------------------------------------------- + // PRIVATE DATA MEMBERS + // ----------------------------------------------------------------- + + /** + * Data to echo + */ + private String data; + + // ----------------------------------------------------------------- + // PUBLIC METHODS + // ----------------------------------------------------------------- + + /** + * + */ + public boolean execute() throws AntException { + + PrintStream out = project.getOutput(); + out.println("ECHOING: " + data); + return true; + } + + /** + * + */ + public void setData(String data) { + this.data = data; + } +} \ No newline at end of file diff --git a/proposal/anteater/source/coretasks/echo/taskdef.properties b/proposal/anteater/source/coretasks/echo/taskdef.properties new file mode 100644 index 000000000..e8627c8c0 --- /dev/null +++ b/proposal/anteater/source/coretasks/echo/taskdef.properties @@ -0,0 +1,4 @@ +# taskdef.properties for Echo task + +tasks=echo +echo.class=org.apache.ant.echo.EchoTask \ No newline at end of file diff --git a/proposal/anteater/source/main.ant b/proposal/anteater/source/main.ant new file mode 100644 index 000000000..a313562a7 --- /dev/null +++ b/proposal/anteater/source/main.ant @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/proposal/anteater/source/main/org/apache/ant/AbstractTask.java b/proposal/anteater/source/main/org/apache/ant/AbstractTask.java new file mode 100644 index 000000000..a4cfc2e51 --- /dev/null +++ b/proposal/anteater/source/main/org/apache/ant/AbstractTask.java @@ -0,0 +1,85 @@ +package org.apache.ant; + +import java.io.*; +import java.util.*; +import java.lang.reflect.*; +import java.beans.*; + +/** + * Superclass of all Tasks. All tasks extend from this. + * + * @author James Duncan Davidson (duncan@apache.org) + */ +public abstract class AbstractTask { + + // ----------------------------------------------------------------- + // PROTECTED DATA MEMBERS + // ----------------------------------------------------------------- + + /** + * + */ + protected Project project; + + // ----------------------------------------------------------------- + // ABSTRACT PUBLIC METHODS + // ----------------------------------------------------------------- + + /** + * + */ + public abstract boolean execute() throws AntException; + + // ----------------------------------------------------------------- + // PUBLIC METHODS + // ----------------------------------------------------------------- + + /** + * Used by the system to set the attributes which then get reflected + * into the particular implementation class + */ + public void setAttributes(Hashtable attributes) { + Class clazz = this.getClass(); + BeanInfo bi; + try { + bi = Introspector.getBeanInfo(clazz); + } catch (IntrospectionException ie) { + System.out.println("Can't reflect on: " + clazz); + // XXX exception out + return; + } + PropertyDescriptor[] pda = bi.getPropertyDescriptors(); + for (int i = 0; i < pda.length; i++) { + PropertyDescriptor pd = pda[i]; + String property = pd.getName(); + Object o = attributes.get(property); + if (o != null) { + String value = (String)o; + Method setMethod = pd.getWriteMethod(); + if (setMethod != null) { + Class[] ma = setMethod.getParameterTypes(); + if (ma.length == 1) { + Class c = ma[0]; + if (c.getName().equals("java.lang.String")) { + try { + setMethod.invoke(this, new String[] {value}); + } catch (Exception e) { + // XXX bad bad bad -- narrow to exact exceptions + System.out.println("OUCH: " + e); + // XXX exception out. + } + } + } + } + } + } + } + + /** + * Used by system to set the project. + */ + public void setProject(Project project) { + this.project = project; + } + +} \ No newline at end of file diff --git a/proposal/anteater/source/main/org/apache/ant/Ant.java b/proposal/anteater/source/main/org/apache/ant/Ant.java new file mode 100644 index 000000000..333e15a55 --- /dev/null +++ b/proposal/anteater/source/main/org/apache/ant/Ant.java @@ -0,0 +1,249 @@ +// ------------------------------------------------------------------------------- +// Copyright (c)2000 Apache Software Foundation +// ------------------------------------------------------------------------------- + +package org.apache.ant; + +import java.io.*; +import java.util.*; +import java.util.zip.*; + +/** + * Central class of Ant. This is the core 'kernel' of ant. Interfaces into + * ant talk to Ant through this class. + * + * @author James Duncan Davidson (duncan@apache.org) + */ +public class Ant { + + // ----------------------------------------------------------------- + // PRIVATE DATA MEMBERS + // ----------------------------------------------------------------- + + /** + * + */ + private Hashtable abstractTaskClasses = new Hashtable(); + + /** + * + */ + private Vector taskPathNodes = new Vector(); + + /** + * + */ + private File buildfile; + + /** + * + */ + private Project project; + + // ----------------------------------------------------------------- + // CONSTRUCTORS + // ----------------------------------------------------------------- + + /** + * Constructs a new Ant instance. + */ + public Ant() { + setUpTaskPath(); + } + + // ----------------------------------------------------------------- + // PUBLIC METHODS + // ----------------------------------------------------------------- + + /** + * Sets additional path nodes onto the task lookup path. These nodes + * take precendence over all previously set path nodes. + */ + public void addTaskPathNode(File node) { + taskPathNodes.insertElementAt(node, 0); + } + + /** + * + */ + public void buildTarget(String targetName) throws AntException { + + try { + loadTasks(); + } catch (IOException ioe) { + throw new AntException(ioe.getMessage()); + } + + Target target = project.getTarget(targetName); + + // XXX don't forget to execute dependancies first! + + Enumeration enum = target.getTasks().elements(); + while (enum.hasMoreElements()) { + Task task = (Task)enum.nextElement(); + Object o = abstractTaskClasses.get(task.getType()); + if (o != null) { + Class c = (Class)o; + try { + AbstractTask aTask = (AbstractTask)c.newInstance(); + aTask.setAttributes(task.getAttributes()); + aTask.setProject(project); + boolean b = aTask.execute(); + if (!b) { + throw new AntException("STOP: Task " + task + + " did not succeed"); + } + } catch (Exception e) { + // XXX yes yes yes, this shouldn't be a catch all... + throw new AntException("ERR: " + e); + } + } else { + throw new AntException("Don't have a class for task type: " + task); + } + } + } + + /** + * + */ + public Project getProject() { + return project; + } + + /** + * Sets the buildfile to be used. This action triggers a parse of + * the build file and assembles a Project object from it. + */ + public void setBuildfile(File file) throws AntException { + buildfile = file; + ProjectBuilder builder = new ProjectBuilder(); + project = builder.buildFromFile(file); + project.setAnt(this); + System.out.println("Loaded Project: " + project.getName()); + + // XXX remove the dump after comfort level is reached + + System.out.println("Dump of Project:"); + Enumeration enum = project.getTargets(); + while (enum.hasMoreElements()) { + Target target = (Target)enum.nextElement(); + System.out.println(" Target: " + target.getName()); + Enumeration enum2 = target.getTasks().elements(); + while (enum2.hasMoreElements()) { + Task task = (Task)enum2.nextElement(); + System.out.println(" Task: " + task.getType()); + Enumeration enum3 = task.getAttributeNames(); + while (enum3.hasMoreElements()) { + String atName = (String)enum3.nextElement(); + String atValue = task.getAttribute(atName); + System.out.println(" Att: " + atName + " = " + + atValue); + } + } + } + } + + // ----------------------------------------------------------------- + // PRIVATE METHODS + // ----------------------------------------------------------------- + + /** + * Searches through the taskpath and loads up the taskImpl hashtable + * + * XXX we also need to lookup a taskdef.properties file out of a few + * strategic locations on disk to allow generic classes to be pulled + * from the classpath + */ + private void loadTasks() throws IOException { + Enumeration enum = taskPathNodes.elements(); + while (enum.hasMoreElements()) { + File dir = (File)enum.nextElement(); + String[] files = dir.list(); + for (int i = 0; i < files.length; i++) { + if (files[i].endsWith(".jar")) { + File f = new File(dir, files[i]); + ZipFile zf = new ZipFile(f); + ZipEntry ze = zf.getEntry("/taskdef.properties"); + if (ze != null) { + InputStream is = zf.getInputStream(ze); + Properties props = new Properties(); + props.load(is); + is.close(); + //System.out.println("Props: " + props); + String s = props.getProperty("tasks"); + StringTokenizer tok = new StringTokenizer(s, ",", false); + while (tok.hasMoreTokens()) { + String taskType = tok.nextToken(); + String taskClassName = props.getProperty(taskType + + ".class"); + //System.out.println("TASK: " + taskType + " class: " + + // taskClassName); + ClassLoader pcl = this.getClass().getClassLoader(); + TaskClassLoader tcl = new TaskClassLoader(pcl, zf); + try { + Class clazz = tcl.findClass(taskClassName); + abstractTaskClasses.put(taskType, clazz); + } catch (ClassNotFoundException cnfe) { + System.out.println(cnfe); + System.out.println(cnfe.getMessage()); + } + } + } + } + } + } + } + + /** + * Sets up the taskpath based on the currently running operating + * system. In general, the ordering of the taskpath is: user directory, + * system directory, and then installation. This allows users or + * system admins to override or add tasks. + */ + private void setUpTaskPath() { + + // 1st, add user's home dir. + + File f; + + String userHome = System.getProperty("user.home"); + + // generic unix + f = new File(userHome + ".ant", "tasks"); + if (f.exists() && f.isDirectory()) { + taskPathNodes.addElement(f); + } + + // macos x + f = new File(userHome + "/Library/Ant", "Tasks"); + if (f.exists() && f.isDirectory()) { + taskPathNodes.addElement(f); + } + + // windows -- todo + + // 2nd, add system local dir. + + // generic unix + f = new File("/usr/local/ant/tasks"); + if (f.exists() && f.isDirectory()) { + taskPathNodes.addElement(f); + } + + // macos x + f = new File("/Library/Ant/Tasks"); + if (f.exists() && f.isDirectory()) { + taskPathNodes.addElement(f); + } + + // windows -- todo + + // 3rd, add installation local dir. + + //System.out.println("BASE: " + this.getClass().getResource("/")); + + // XXX ---- not really sure how the best way of getting this info is... + // hafta think about it. + } + +} \ No newline at end of file diff --git a/proposal/anteater/source/main/org/apache/ant/AntException.java b/proposal/anteater/source/main/org/apache/ant/AntException.java new file mode 100644 index 000000000..c0c6598c8 --- /dev/null +++ b/proposal/anteater/source/main/org/apache/ant/AntException.java @@ -0,0 +1,21 @@ +// ------------------------------------------------------------------------------- +// Copyright (c)2000 Apache Software Foundation +// ------------------------------------------------------------------------------- + +package org.apache.ant; + +/** + * Signals a problem. + * + * @author James Duncan Davidson (duncan@apache.org) + */ +public class AntException extends Exception { + + public AntException() { + super(); + } + + public AntException(String msg) { + super(msg); + } +} \ No newline at end of file diff --git a/proposal/anteater/source/main/org/apache/ant/Project.java b/proposal/anteater/source/main/org/apache/ant/Project.java new file mode 100644 index 000000000..92feddc81 --- /dev/null +++ b/proposal/anteater/source/main/org/apache/ant/Project.java @@ -0,0 +1,128 @@ +// --------------------------------------------------------------------- +// (c)2000 Apache Software Foundation +// +// --------------------------------------------------------------------- + +package org.apache.ant; + +import java.io.*; +import java.util.*; + +/** + * In memory container for an Ant project. + * + * @author James Duncan Davidson (duncan@apache.org) + */ +public class Project { + + // ----------------------------------------------------------------- + // PRIVATE DATA MEMBERS + // ----------------------------------------------------------------- + + /** + * + */ + private Ant ant; + + /** + * + */ + private PrintStream out; + + /** + * Parent project to this project, if one exists. + */ + private Project parentProject = null; + + /** + * + */ + private String name; + + /** + * Hashtable containing all of the targets that are part of this + * project. Targets are stored in this hashtable using the name + * of the target as the key and the Target object for the target + * as the value. + */ + private Hashtable targets = new Hashtable(); + + // ----------------------------------------------------------------- + // PUBLIC ACCESSOR METHODS + // ----------------------------------------------------------------- + + /** + * + */ + public void addTarget(Target target) { + // XXX check out for name, if null, reject! + targets.put(target.getName(), target); + } + + /** + * + */ + public PrintStream getOutput() { + // XXX check if null!!!!???? + return out; + } + + /** + * Returns the parent Project object to this Project if a parent + * project exists. If there is not a parent Project object, null + * is returned. + */ + public Project getParent() { + return parentProject; + } + + /** + * Returns the target identified with the given name. If no target + * is known by the given name, then null is returned. + */ + public Target getTarget(String name) { + return (Target)targets.get(name); + } + + /** + * + */ + public Enumeration getTargets() { + return targets.elements(); + } + + /** + * + */ + public String getName() { + return name; + } + + /** + * + */ + public void setAnt(Ant ant) { + this.ant = ant; + } + + /** + * + */ + public void setOutput(PrintStream out) { + this.out = out; + } + + /** + * + */ + public void setName(String name) { + this.name = name; + } + + /** + * + */ + public String toString() { + return "Project name=" + name; + } +} \ No newline at end of file diff --git a/proposal/anteater/source/main/org/apache/ant/ProjectBuilder.java b/proposal/anteater/source/main/org/apache/ant/ProjectBuilder.java new file mode 100644 index 000000000..ad9e50d8d --- /dev/null +++ b/proposal/anteater/source/main/org/apache/ant/ProjectBuilder.java @@ -0,0 +1,154 @@ +// ------------------------------------------------------------------------------- +// Copyright (c)2000 Apache Software Foundation +// ------------------------------------------------------------------------------- + +package org.apache.ant; + +import java.io.*; +import javax.xml.parsers.*; +import org.xml.sax.*; + +/** + * Helper class to build Project object trees. + * + * XXX right now this class only deals with the primary levels (project/target/task) + * and nothing else. Also, it only supports attributes.... + * + * @author James Duncan Davidson (duncan@apache.org) + */ +class ProjectBuilder { + + private SAXParserFactory parserFactory; + + // ----------------------------------------------------------------- + // CONSTRUCTORS + // ----------------------------------------------------------------- + + ProjectBuilder() { + parserFactory = SAXParserFactory.newInstance(); + parserFactory.setValidating(false); + } + + Project buildFromFile(File file) throws AntException { + try { + SAXParser parser = parserFactory.newSAXParser(); + BuilderHandlerBase bhb = new BuilderHandlerBase(); + parser.parse(file, bhb); + return bhb.getProject(); + } catch (ParserConfigurationException pce) { + throw new AntException(pce.getMessage()); + } catch (SAXException se) { + System.out.println(se); + System.out.println(se.getMessage()); + throw new AntException(se.getMessage()); + } catch (IOException ioe) { + throw new AntException(ioe.getMessage()); + } + } + + class BuilderHandlerBase extends HandlerBase { + + private static final int STATE_START = 0; + private static final int STATE_PROJECT = 1; + private static final int STATE_TARGET = 2; + private static final int STATE_TASK = 3; + private static final int STATE_FINISHED = 99; + + private int state = STATE_START; + + private Target currentTarget; + private Task currentTask; + + Project project = new Project(); + + Project getProject() { + return project; + } + + public void startElement(String name, AttributeList atts) throws SAXException { + //System.out.println("element: " + name); + + switch (state) { + case STATE_START: + if (name.equals("project")) { + state = STATE_PROJECT; + String projectName = atts.getValue("name"); + if (projectName == null) { + System.out.println("Projects *must* have names"); + // XXX exception out + } + project.setName(projectName); + } else { + System.out.println("Expecting project, got: " + name); + // XXX exception out + } + break; + case STATE_PROJECT: + if (name.equals("target")) { + state = STATE_TARGET; + String targetName = atts.getValue("name"); + if (targetName == null) { + System.out.println("Targets *must* have names"); + // XXX exception out + } + currentTarget = new Target(targetName); + project.addTarget(currentTarget); + + // XXX add dependency checks + } else { + System.out.println("Expecting target, got: " + name); + // XXX exception out + } + break; + case STATE_TARGET: + state = STATE_TASK; + //System.out.println("Getting task: " + name + " for target " + + // currentTarget); + // XXX need to validate that task type (name) exists in system + // else exception out. + currentTask = new Task(name); + currentTarget.addTask(currentTask); + for (int i = 0; i < atts.getLength(); i++) { + String atName = atts.getName(i); + String atValue = atts.getValue(i); + currentTask.addAttribute(atName, atValue); + } + break; + default: + System.out.println("I'm not sure, but we're off base here: " + name); + // XXX exception out + } + } + + public void characters(char ch[], int start, int length) throws SAXException { + } + + public void endElement(String name) throws SAXException { + // System.out.println("end: " + name); + switch (state) { + case STATE_TASK: + state = STATE_TARGET; + break; + case STATE_TARGET: + if (name.equals("target")) { + state = STATE_PROJECT; + } else { + System.out.println("Expecting to get an end of target, got: " + name); + // XXX exception out. + } + break; + case STATE_PROJECT: + if (name.equals("project")) { + state = STATE_FINISHED; + } else { + System.out.println("Expecting to get end of project, got: " + name); + // XXX exception out; + } + break; + default: + System.out.println("I'm not sure what we are ending here: " + name); + // XXX exception out; + } + } + } +} \ No newline at end of file diff --git a/proposal/anteater/source/main/org/apache/ant/Target.java b/proposal/anteater/source/main/org/apache/ant/Target.java new file mode 100644 index 000000000..41b5260c5 --- /dev/null +++ b/proposal/anteater/source/main/org/apache/ant/Target.java @@ -0,0 +1,77 @@ +// --------------------------------------------------------------------- +// (c)2000 Apache Software Foundation +// +// --------------------------------------------------------------------- + +package org.apache.ant; + +import java.util.*; + +/** + * In memory container for an Ant target. + */ +public class Target { + + // ----------------------------------------------------------------- + // PRIVATE DATA MEMBERS + // ----------------------------------------------------------------- + + /** + * String containing the name of the target. This name must be + * unique withing a project. + */ + private String name; + + /** + * Vector containing the tasks that are part of this target. + */ + private Vector tasks = new Vector(); + + // ----------------------------------------------------------------- + // CONSTRUCTORS + // ----------------------------------------------------------------- + + /** + * Constructs a new Target object with the given name. + */ + public Target(String name) { + this.name = name; + } + + // ----------------------------------------------------------------- + // PUBLIC ACCESSOR METHODS + // ----------------------------------------------------------------- + + /** + * + */ + public void addTask(Task task) { + tasks.addElement(task); + } + + /** + * Returns a String containing the name of this Target. + */ + public String getName() { + return name; + } + + /** + * + */ + public String toString() { + return "TARGET: " + name; + } + + /** + * Returns a Vector of Tasks contained in this Target. + *

+ * Please use caution when using this method. I am not happy + * about exposing this data as something other than a + * Collection, but don't want to use 1.1 collections. So, + * this method may change in the future. You have been warned. + */ + public Vector getTasks() { + return tasks; + } +} \ No newline at end of file diff --git a/proposal/anteater/source/main/org/apache/ant/Task.java b/proposal/anteater/source/main/org/apache/ant/Task.java new file mode 100644 index 000000000..363c80106 --- /dev/null +++ b/proposal/anteater/source/main/org/apache/ant/Task.java @@ -0,0 +1,86 @@ +// --------------------------------------------------------------------- +// (c)2000 Apache Software Foundation +// +// --------------------------------------------------------------------- + +package org.apache.ant; + +import java.util.*; + +/** + * In memory container for an Ant target. + * + * XXX need a way to query which attributes are valid for this particular + * task type... Like into Ant object to do this? + */ +public class Task { + + // ----------------------------------------------------------------- + // PRIVATE DATA MEMBERS + // ----------------------------------------------------------------- + + /** + * + */ + private Hashtable attributes = new Hashtable(); + + /** + * String containing the type of the task. + */ + private String type; + + // ----------------------------------------------------------------- + // CONSTRUCTORS + // ----------------------------------------------------------------- + + /** + * Constructs a new Target object with the given name. + */ + public Task(String type) { + this.type = type; + } + + // ----------------------------------------------------------------- + // PUBLIC ACCESSOR METHODS + // ----------------------------------------------------------------- + + /** + * + */ + public void addAttribute(String name, String value) { + attributes.put(name, value); + } + + public String getAttribute(String name) { + return (String)attributes.get(name); + } + + /** + * + */ + public Hashtable getAttributes() { + return attributes; + } + + /** + * + */ + public Enumeration getAttributeNames() { + return attributes.keys(); + } + + /** + * Returns a String containing the name of this Target. + */ + public String getType() { + return type; + } + + /** + * + */ + public String toString() { + return "TASK: " + type; + } + +} \ No newline at end of file diff --git a/proposal/anteater/source/main/org/apache/ant/TaskClassLoader.java b/proposal/anteater/source/main/org/apache/ant/TaskClassLoader.java new file mode 100644 index 000000000..46c8e55a7 --- /dev/null +++ b/proposal/anteater/source/main/org/apache/ant/TaskClassLoader.java @@ -0,0 +1,103 @@ +package org.apache.ant; + +import java.io.*; +import java.util.*; +import java.util.zip.*; + +/** + * + * + * @author James Duncan Davidson (duncan@apache.org) + */ +class TaskClassLoader extends ClassLoader { + + // ----------------------------------------------------------------- + // PRIVATE MEMBERS + // ----------------------------------------------------------------- + + /** + * + */ + private Hashtable cache = new Hashtable(); + + /** + * + */ + private ZipFile zf; + + // ----------------------------------------------------------------- + // CONSTRUCTORS + // ----------------------------------------------------------------- + + /** + * Constructs a classloader that loads classes from the specified + * zip file. + */ + TaskClassLoader(ClassLoader parent, ZipFile zf) { + super(parent); + this.zf = zf; + } + + // ----------------------------------------------------------------- + // PUBLIC METHODS + // ----------------------------------------------------------------- + + /** + * + */ + public Class findClass(String name) + throws ClassNotFoundException + { + Class c; + try { + return findSystemClass(name); + } catch (ClassNotFoundException cnfe) { + } + try { + return this.getClass().getClassLoader().loadClass(name); + } catch (Exception e) { + } + Object o = cache.get(name); + if (o != null) { + c = (Class)o; + } else { + byte[] data = loadClassData(name); + c = defineClass(data, 0, data.length); + cache.put(name, c); + } + //if (resolve) { + // resolveClass(c); + //} + return c; + } + + /** + * + */ + private byte[] loadClassData(String name) throws ClassNotFoundException { + String newName = name.replace('.', '/'); + ZipEntry ze = zf.getEntry("/" + newName + ".class"); + //System.out.println("/" + newName + ".class"); + //System.out.println("ZE: " + ze); + if (ze != null) { + byte[] buf = new byte[((int)ze.getSize())]; + // System.out.println("ZE SIZE " + ze.getSize()); + try { + InputStream in = zf.getInputStream(ze); + int count = 0; + int thisRead = 0; + while (count < buf.length && thisRead != -1) { + thisRead = in.read(buf, count, buf.length - count); + count += thisRead; + } + in.close(); + } catch (IOException ioe) { + throw new ClassNotFoundException("Can't load class: " + name + " " + + ioe.getMessage()); + } + return buf; + } else { + throw new ClassNotFoundException("Can't find class for: " + name); + } + } +} \ No newline at end of file diff --git a/proposal/anteater/source/main/org/apache/ant/cli/Main.java b/proposal/anteater/source/main/org/apache/ant/cli/Main.java new file mode 100644 index 000000000..85dfb3972 --- /dev/null +++ b/proposal/anteater/source/main/org/apache/ant/cli/Main.java @@ -0,0 +1,89 @@ +// ------------------------------------------------------------------------------- +// Copyright (c)2000 Apache Software Foundation +// ------------------------------------------------------------------------------- + +package org.apache.ant.cli; + +import java.io.*; +import java.util.*; +import org.apache.ant.*; + +/** + * Entry point for Ant on the Command Line Interface. + * + * @author James Duncan Davidson (duncan@apache.org) + */ +public class Main { + + /** + * Command line entry point. + */ + public static void main(String[] args) { + Ant ant = new Ant(); + String target = ""; + + System.out.println("Ant(Eater) -- Proposed Ant 2.0"); + + // flip through args and set things accordingly + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + // scan through -- all -aaa args come first. + if (arg.startsWith("-")) { + if (arg.equals("-help")) { + printHelp(); + return; + } else if (arg.equals("-taskpath")) { + // XXX + // need to seperate on pathsep, but not today + ant.addTaskPathNode(new File(args[++i])); + } else if (arg.equals("-buildfile")) { + // XXX + // need to check file to make sure it exists! + try { + ant.setBuildfile(new File(args[++i])); + } catch (AntException ae) { + System.out.println("ICK: " + ae); + System.out.println(ae.getMessage()); + return; + } + } + } else { + target = arg; + } + } + + // XXX do something if we dont' have a buildfile set! + + // XXX really should check to make sure that the target is set to something + + // set our listeners on the project + + Project project = ant.getProject(); + project.setOutput(System.out); + + System.out.println(); + System.out.println("Executing Target: " + target); + + try { + ant.buildTarget(target); + } catch (AntException ae) { + System.out.println("Problem while building: " + ae); + System.out.println(ae.getMessage()); + } + } + + // ----------------------------------------------------------------- + // PRIVATE METHODS + // ----------------------------------------------------------------- + + /** + * Prints help to System.out + */ + private static void printHelp() { + System.out.println("Usage: ant [args] [target]"); + System.out.println(" Arguments:"); + System.out.println(" -help"); + System.out.println(" -taskpath [path]"); + System.out.println(" -buildfile [file]"); + } +} \ No newline at end of file