001: /*
002: * Distributed as part of debuggen v.0.1.0
003: *
004: * Copyright (C) 2005 Machinery For Change, Inc.
005: *
006: * Author: Steve Waldman <swaldman@mchange.com>
007: *
008: * This library is free software; you can redistribute it and/or modify
009: * it under the terms of the GNU Lesser General Public License version 2.1, as
010: * published by the Free Software Foundation.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public License
018: * along with this software; see the file LICENSE. If not, write to the
019: * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020: * Boston, MA 02111-1307, USA.
021: */
022:
023: package com.mchange.v2.debug;
024:
025: import java.io.*;
026: import java.util.*;
027: import com.mchange.v2.cmdline.*;
028: import com.mchange.v2.io.FileIterator;
029: import com.mchange.v2.io.DirectoryDescentUtils;
030: import com.mchange.v1.io.WriterUtils;
031: import com.mchange.v1.lang.BooleanUtils;
032: import com.mchange.v1.util.SetUtils;
033: import com.mchange.v1.util.StringTokenizerUtils;
034:
035: public final class DebugGen implements DebugConstants {
036: final static String[] VALID = new String[] { "codebase",
037: "packages", "trace", "debug", "recursive", "javac",
038: "noclobber", "classname", "skipdirs", "outputbase" };
039:
040: final static String[] REQUIRED = new String[] { "codebase",
041: "packages", "trace", "debug" };
042:
043: final static String[] ARGS = new String[] { "codebase", "packages",
044: "trace", "debug", "classname", "outputbase" };
045:
046: final static String EOL;
047:
048: static {
049: EOL = System.getProperty("line.separator");
050: }
051:
052: static int trace_level;
053: static boolean debug;
054: static boolean recursive;
055: static String classname;
056: static boolean clobber;
057: static Set skipDirs;
058:
059: public synchronized static final void main(String[] argv) {
060: String codebase;
061: String outputbase;
062: File[] srcPkgDirs;
063:
064: try {
065: ParsedCommandLine pcl = CommandLineUtils.parse(argv, "--",
066: VALID, REQUIRED, ARGS);
067:
068: //get and normalize the codebase
069: codebase = pcl.getSwitchArg("codebase");
070: codebase = platify(codebase);
071: if (!codebase.endsWith(File.separator))
072: codebase += File.separator;
073:
074: //get and normalize the outputbase
075: outputbase = pcl.getSwitchArg("outputbase");
076: if (outputbase != null) {
077: outputbase = platify(outputbase);
078: if (!outputbase.endsWith(File.separator))
079: outputbase += File.separator;
080: } else
081: outputbase = codebase;
082:
083: File outputBaseDir = new File(outputbase);
084: //System.err.println("outputBaseDir: " + outputBaseDir + "; exists? " + outputBaseDir.exists());
085: if (outputBaseDir.exists()) {
086: if (!outputBaseDir.isDirectory()) {
087: //System.err.println("Output Base '" + outputBaseDir.getPath() + "' is not a directory!");
088: System.exit(-1);
089: } else if (!outputBaseDir.canWrite()) {
090: System.err.println("Output Base '"
091: + outputBaseDir.getPath()
092: + "' is not writable!");
093: System.exit(-1);
094: }
095: } else if (!outputBaseDir.mkdirs()) {
096: System.err
097: .println("Output Base directory '"
098: + outputBaseDir.getPath()
099: + "' does not exist, and could not be created!");
100: System.exit(-1);
101: }
102:
103: //find existing package dirs
104: String[] packages = StringTokenizerUtils.tokenizeToArray(
105: pcl.getSwitchArg("packages"), ", \t");
106: srcPkgDirs = new File[packages.length];
107: for (int i = 0, len = packages.length; i < len; ++i)
108: srcPkgDirs[i] = new File(codebase + sepify(packages[i]));
109:
110: //find trace level
111: trace_level = Integer.parseInt(pcl.getSwitchArg("trace"));
112:
113: //find debug
114: debug = BooleanUtils
115: .parseBoolean(pcl.getSwitchArg("debug"));
116:
117: //find classname, or use default
118: classname = pcl.getSwitchArg("classname");
119: if (classname == null)
120: classname = "Debug";
121:
122: //find recursive
123: recursive = pcl.includesSwitch("recursive");
124:
125: //find clobber
126: clobber = !pcl.includesSwitch("noclobber");
127:
128: //find skipDirs
129: String skipdirStr = pcl.getSwitchArg("skipdirs");
130: if (skipdirStr != null) {
131: String[] skipdirArray = StringTokenizerUtils
132: .tokenizeToArray(skipdirStr, ", \t");
133: skipDirs = SetUtils.setFromArray(skipdirArray);
134: } else {
135: skipDirs = new HashSet();
136: skipDirs.add("CVS");
137: }
138:
139: if (pcl.includesSwitch("javac"))
140: System.err
141: .println("autorecompilation of packages not yet implemented.");
142:
143: for (int i = 0, len = srcPkgDirs.length; i < len; ++i) {
144: if (recursive) {
145: if (!recursivePrecheckPackages(codebase,
146: srcPkgDirs[i], outputbase, outputBaseDir)) {
147: System.err
148: .println("One or more of the specifies packages"
149: + " could not be processed. Aborting."
150: + " No files have been modified.");
151: System.exit(-1);
152: }
153: } else {
154: if (!precheckPackage(codebase, srcPkgDirs[i],
155: outputbase, outputBaseDir)) {
156: System.err
157: .println("One or more of the specifies packages"
158: + " could not be processed. Aborting."
159: + " No files have been modified.");
160: System.exit(-1);
161: }
162: }
163: }
164:
165: for (int i = 0, len = srcPkgDirs.length; i < len; ++i) {
166: if (recursive)
167: recursiveWriteDebugFiles(codebase, srcPkgDirs[i],
168: outputbase, outputBaseDir);
169: else
170: writeDebugFile(outputbase, srcPkgDirs[i]);
171: }
172: } catch (Exception e) {
173: e.printStackTrace();
174: System.err.println();
175: usage();
176: }
177: }
178:
179: private static void usage() {
180: System.err.println("java " + DebugGen.class.getName() + " \\");
181: System.err
182: .println("\t--codebase=<directory under which packages live> \\ (no default)");
183: System.err
184: .println("\t--packages=<comma separated list of packages> \\ (no default)");
185: System.err
186: .println("\t--debug=<true|false> \\ (no default)");
187: System.err
188: .println("\t--trace=<an int between 0 and 10> \\ (no default)");
189: System.err
190: .println("\t--outputdir=<directory under which to generate> \\ (defaults to same dir as codebase)");
191: System.err
192: .println("\t--recursive \\ (no args)");
193: System.err
194: .println("\t--noclobber \\ (no args)");
195: System.err
196: .println("\t--classname=<class to generate> \\ (defaults to Debug)");
197: System.err
198: .println("\t--skipdirs=<directories that should be skipped> \\ (defaults to CVS)");
199: }
200:
201: private static String ify(String str, char fromChar, char toChar) {
202: if (fromChar == toChar)
203: return str;
204:
205: StringBuffer sb = new StringBuffer(str);
206: for (int i = 0, len = sb.length(); i < len; ++i)
207: if (sb.charAt(i) == fromChar)
208: sb.setCharAt(i, toChar);
209: return sb.toString();
210: }
211:
212: private static String platify(String str) {
213: String out;
214: out = ify(str, '/', File.separatorChar);
215: out = ify(out, '\\', File.separatorChar);
216: out = ify(out, ':', File.separatorChar);
217: return out;
218: }
219:
220: private static String dottify(String str) {
221: return ify(str, File.separatorChar, '.');
222: }
223:
224: private static String sepify(String str) {
225: return ify(str, '.', File.separatorChar);
226: }
227:
228: private static boolean recursivePrecheckPackages(String codebase,
229: File srcPkgDir, String outputbase, File outputBaseDir)
230: throws IOException {
231: FileIterator fii = DirectoryDescentUtils
232: .depthFirstEagerDescent(srcPkgDir);
233: while (fii.hasNext()) {
234: File pkgDir = fii.nextFile();
235: if (!pkgDir.isDirectory()
236: || skipDirs.contains(pkgDir.getName()))
237: continue;
238:
239: File outputDir = outputDir(codebase, pkgDir, outputbase,
240: outputBaseDir);
241: if (!outputDir.exists() && !outputDir.mkdirs()) {
242: System.err
243: .println("Required output dir: '"
244: + outputDir
245: + "' does not exist, and could not be created.");
246: return false;
247: }
248: if (!precheckOutputPackageDir(outputDir))
249: return false;
250: }
251: return true;
252: }
253:
254: private static File outputDir(String codebase, File srcPkgDir,
255: String outputbase, File outputBaseDir) {
256: //System.err.println("outputDir( " + codebase +", " + srcPkgDir + ", " + outputbase + ", " + outputBaseDir + " )");
257: if (codebase.equals(outputbase))
258: return srcPkgDir;
259:
260: String srcPath = srcPkgDir.getPath();
261: if (!srcPath.startsWith(codebase)) {
262: System.err.println(DebugGen.class.getName()
263: + ": program bug. Source package path '" + srcPath
264: + "' does not begin with codebase '" + codebase
265: + "'.");
266: System.exit(-1);
267: }
268: return new File(outputBaseDir, srcPath.substring(codebase
269: .length()));
270: }
271:
272: private static boolean precheckPackage(String codebase,
273: File srcPkgDir, String outputbase, File outputBaseDir)
274: throws IOException {
275: return precheckOutputPackageDir(outputDir(codebase, srcPkgDir,
276: outputbase, outputBaseDir));
277: }
278:
279: private static boolean precheckOutputPackageDir(File dir)
280: throws IOException {
281: File outFile = new File(dir, classname + ".java");
282: if (!dir.canWrite()) {
283: System.err.println("File '" + outFile.getPath()
284: + "' is not writable.");
285: return false;
286: } else if (!clobber && outFile.exists()) {
287: System.err.println("File '" + outFile.getPath()
288: + "' exists, and we are in noclobber mode.");
289: return false;
290: } else
291: return true;
292: }
293:
294: private static void recursiveWriteDebugFiles(String codebase,
295: File srcPkgDir, String outputbase, File outputBaseDir)
296: throws IOException {
297: FileIterator fii = DirectoryDescentUtils
298: .depthFirstEagerDescent(outputDir(codebase, srcPkgDir,
299: outputbase, outputBaseDir));
300: while (fii.hasNext()) {
301: File pkgDir = fii.nextFile();
302: //System.err.println("pkgDir: " + pkgDir);
303: if (!pkgDir.isDirectory()
304: || skipDirs.contains(pkgDir.getName()))
305: continue;
306:
307: writeDebugFile(outputbase, pkgDir);
308: }
309: }
310:
311: private static void writeDebugFile(String outputbase, File pkgDir)
312: throws IOException {
313: //System.err.println("outputbase: " + outputbase + "; pkgDir: " + pkgDir);
314:
315: File outFile = new File(pkgDir, classname + ".java");
316: String pkg = dottify(pkgDir.getPath().substring(
317: outputbase.length()));
318: System.err.println("Writing file: " + outFile.getPath());
319: Writer writer = null;
320: try {
321: writer = new OutputStreamWriter(new BufferedOutputStream(
322: new FileOutputStream(outFile)), "UTF8");
323: writer
324: .write("/********************************************************************"
325: + EOL);
326: writer.write(" * This class generated by "
327: + DebugGen.class.getName() + EOL);
328: writer
329: .write(" * and will probably be overwritten by the same! Edit at"
330: + EOL);
331: writer.write(" * YOUR PERIL!!! Hahahahaha." + EOL);
332: writer
333: .write(" ********************************************************************/"
334: + EOL);
335: writer.write(EOL);
336: writer.write("package " + pkg + ';' + EOL);
337: writer.write(EOL);
338: writer.write("import com.mchange.v2.debug.DebugConstants;"
339: + EOL);
340: writer.write(EOL);
341: writer.write("final class " + classname
342: + " implements DebugConstants" + EOL);
343: writer.write("{" + EOL);
344: writer.write("\tfinal static boolean DEBUG = " + debug
345: + ';' + EOL);
346: writer.write("\tfinal static int TRACE = "
347: + traceStr(trace_level) + ';' + EOL);
348: writer.write(EOL);
349: writer.write("\tprivate " + classname + "()" + EOL);
350: writer.write("\t{}" + EOL);
351: writer.write("}" + EOL);
352: writer.write(EOL);
353: writer.flush();
354: } finally {
355: WriterUtils.attemptClose(writer);
356: }
357: }
358:
359: private static String traceStr(int trace) {
360: if (trace == TRACE_NONE)
361: return "TRACE_NONE";
362: else if (trace == TRACE_MED)
363: return "TRACE_MED";
364: else if (trace == TRACE_MAX)
365: return "TRACE_MAX";
366: else
367: return String.valueOf(trace);
368: }
369: }
|