001: package antlr.build;
002:
003: import antlr.Utils;
004:
005: import java.io.*;
006: import java.lang.reflect.*;
007:
008: /** An application-specific build tool for ANTLR. Old build
009: * was a shell script that of course is not portable. All it
010: * did though was to compile; this Java program is a portable
011: * compile script. :)
012: *
013: * This class knows how to portable invoke a system command with
014: * wildcard expansion. It also knows to how dynamically load a project
015: * description based upon the name. Actions are just method names
016: * within that object. The ANTLR object defines build and jar methods
017: * that use Tool to portably compile and jar--it is the replacement
018: * the script.
019: *
020: * I almost used Python for this, but I hate forcing users to download
021: * yet another tool just to compile this one. (Another reason not
022: * to use Ant).
023: *
024: * I am using a class to describe the build (e.g., ANTLR) rather than
025: * a file format at the moment since I am not sure how all this will
026: * progress.
027: *
028: * Properties antlr.build.compiler and antlr.build.root may be set
029: * according to your needs. They default to "javac" and ".". The
030: * root is the dir containing the antlr directory associated with
031: * the antlr Java package.
032: *
033: * To build this builder, run "javac *.java" in this dir.
034: *
035: * To build ANTLR, just run
036: *
037: * java antlr.build.Tool build"
038: *
039: * from the
040: * directory containing package antlr's "antlr" dir. Or, use
041: * something like:
042: *
043: * java -Dantlr.build.root=/usr/local/antlr-2.7.2 antlr.build.Tool build
044: *
045: * To make the antlr.jar file, use
046: *
047: * java antlr.build.Tool jar
048: */
049: public class Tool {
050: public String os = null;
051:
052: public Tool() {
053: os = System.getProperty("os.name");
054: }
055:
056: public static void main(String[] args) {
057: if (args.length != 1) {
058: System.err.println("usage: java antlr.build.Tool action");
059: return;
060: }
061: String app = "antlr.build.ANTLR"; // hardcode to build ANTLR app
062: String action = args[0];
063: Tool t = new Tool();
064: t.perform(app, action);
065: }
066:
067: /** Find a class named after the app and then find a method within
068: * that is named after the action.
069: */
070: public void perform(String app, String action) {
071: if (app == null || action == null) {
072: error("missing app or action");
073: return;
074: }
075: Class c = null;
076: Method m = null;
077: Object appObj = null;
078: try {
079: appObj = Utils.createInstanceOf(app);
080: } catch (Exception e) {
081: // try again with antlr.build.app
082: try {
083: if (!app.startsWith("antlr.build.")) {
084: c = Utils.loadClass("antlr.build." + app);
085: }
086: error("no such application " + app, e);
087: } catch (Exception e2) {
088: error("no such application " + app, e2);
089: }
090: }
091: if (c == null || appObj == null) {
092: return;
093: }
094: try {
095: m = c.getMethod(action,
096: new Class[] { antlr.build.Tool.class });
097: //log("begin "+action+" on "+app);
098: m.invoke(appObj, new Object[] { this });
099: //log("end "+action+" on "+app);
100: } catch (Exception e) {
101: error("no such action for application " + app, e);
102: }
103: }
104:
105: /** A portable system command execution routine that logs stdout/stderr
106: * and handles cmd-line wildcards properly.
107: */
108: public void system(String cmd) {
109: Runtime rt = Runtime.getRuntime();
110: try {
111: log(cmd);
112: Process proc = null;
113: if (!os.startsWith("Windows")) {
114: // assume unixen if not windoze (windoze tool expands *)
115: proc = rt.exec(new String[] { "sh", "-c", cmd });
116: } else {
117: proc = rt.exec(cmd);
118: }
119: StreamScarfer stderrScarfer = new StreamScarfer(proc
120: .getErrorStream(), "stderr", this );
121: StreamScarfer stdoutScarfer = new StreamScarfer(proc
122: .getInputStream(), "stdout", this );
123: stderrScarfer.start();
124: stdoutScarfer.start();
125: int exitVal = proc.waitFor();
126: } catch (Exception e) {
127: error("cannot exec " + cmd, e);
128: }
129: }
130:
131: /** Run ANTLR on a grammar file, leaving the output in the directory of the
132: * grammar file.
133: */
134: public void antlr(String fullyQualifiedFilename) {
135: String path = null;
136: try {
137: path = new File(fullyQualifiedFilename).getParent();
138: if (path != null) {
139: path = new File(path).getCanonicalPath();
140: }
141: } catch (IOException ioe) {
142: error("Invalid grammar file: " + fullyQualifiedFilename);
143: }
144: if (path != null) {
145: log("java antlr.Tool -o " + path + " "
146: + fullyQualifiedFilename);
147: antlr.Tool theTool = new antlr.Tool();
148: theTool.doEverything(new String[] { "-o", path,
149: fullyQualifiedFilename });
150: }
151: }
152:
153: /** Stdout from executing sub tools */
154: public void stdout(String s) {
155: System.out.println(s);
156: }
157:
158: /** Stderr from executing sub tools */
159: public void stderr(String s) {
160: System.err.println(s);
161: }
162:
163: public void error(String msg) {
164: System.err.println("antlr.build.Tool: " + msg);
165: }
166:
167: public void log(String cmd) {
168: System.out.println("executing: " + cmd);
169: }
170:
171: public void error(String msg, Exception e) {
172: System.err.println("antlr.build.Tool: " + msg);
173: e.printStackTrace(System.err);
174: }
175: }
|