001: package tide.exttools.lint4j;
002:
003: import tide.editor.*;
004: import tide.project.*;
005: import tide.utils.*;
006: import tide.editor.linemessages.*;
007: import snow.utils.gui.*;
008: import snow.utils.storage.*;
009: import snow.utils.*;
010: import javax.swing.*;
011: import javax.swing.event.*;
012: import javax.swing.border.*;
013: import java.awt.event.*;
014: import java.io.*;
015: import java.util.*;
016: import java.util.regex.*;
017:
018: /** Problems: don't find the classes not named according to the java source name
019: * TODO: avoid passing all java sources one per one. Use wildcards !
020:
021: UNIX:
022: lint4j [-J vmoptions] [-v level] -sourcepath path[:path]* [-classpath path[:path]*] [-exclude packagename]* [-class class[:class]*] packagename+
023:
024: Windows (Make sure to enclose path arguments in quotes):
025: lint4j.bat [-J vmoptions] [-home lint4jpath] [-javahome path] [-v level] -sourcepath path[;path]* [-classpath path[;path]*] [-exclude packagename]* [-class class[:class]*] [packagename | filename]+
026: */
027: public final class Lint4JLauncher {
028: private Lint4JLauncher() {
029: }
030:
031: // BAd Lint4J Command length=125567, 1239 elts
032: // 44663, 609 elts
033:
034: // Good Lint4J Command length=11815, 117 elts
035: // Lint4J Command length=23460, 346 elts
036:
037: private static List<ArrayList<File>> split(List<File> srcs, int max) {
038: List<ArrayList<File>> splits = new ArrayList<ArrayList<File>>();
039: ArrayList<File> act = new ArrayList<File>();
040: splits.add(act);
041: int n = 0;
042: for (File fi : srcs) {
043: if (n >= max) {
044: act = new ArrayList<File>();
045: splits.add(act);
046: n = 0;
047: }
048: act.add(fi);
049:
050: n++;
051: }
052: return splits;
053: }
054:
055: public static void analyse(List<File> sourcesToAnalyse)
056: throws Exception {
057:
058: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
059: .clearDocument();
060: MainEditorFrame.instance.outputPanels.selectToolsTab(false);
061:
062: ProjectSettings actualProject = MainEditorFrame.instance
063: .getActualProject();
064:
065: String srcPath = MainEditorFrame.instance.getActualProject()
066: .getSources_Home().getAbsolutePath();
067: if (!srcPath.endsWith("\\"))
068: srcPath += "\\";
069: int srcPathLength = srcPath.length();
070:
071: // remove existing messages
072: for (File fa : sourcesToAnalyse) {
073: String javaName = fa.getAbsolutePath().substring(
074: srcPathLength);
075: javaName = javaName.substring(0, javaName.length() - 5)
076: .replace('\\', '.'); // remove ".java"
077: LineMessagesManager.getInstance().removeMessagesFor(
078: javaName, Lint4JLineMessage.class);
079: }
080:
081: File lint4jJar = new File(actualProject.getProperty(
082: "Lint4J_path", Lint4JSettingsDialog.defaultLint4JPath));
083: if (!lint4jJar.exists())
084: throw new Exception("lint4j.jar not found at "
085: + lint4jJar.getAbsolutePath());
086: File javaExePath = actualProject.getJava_TOOL();
087: String options = actualProject.getProperty("Lint4J_Options",
088: "-v 5");
089: boolean ignoreIrrelevantCat = actualProject.getBooleanProperty(
090: "Lint4J_ignoreIrrelevant", false);
091:
092: List<String> execCommand = new ArrayList<String>();
093: execCommand.add(javaExePath.getAbsolutePath());
094: execCommand.add("-jar");
095: execCommand.add(lint4jJar.getAbsolutePath());
096:
097: if (options != null && options.trim().length() > 0) {
098: execCommand.addAll(ProjectUtils.splitArgs(options, false));
099: }
100:
101: //execCommand.add( "-home" );
102: //execCommand.add( "lint4jhome" );
103:
104: //execCommand.add( "-v" );
105: //execCommand.add( "3" );
106:
107: // don't work, not required...
108: //execCommand.add( "-javahome" );
109: //execCommand.add( actualProject.getJava_Home().getAbsolutePath() );
110:
111: // replace "; " with the correct separator, ":" on linux, ";" on windows
112: java.util.List<File> cpf = actualProject.getClassPath(false,
113: true); // aux class path
114: //cpf.add( actualProject.getClasses_Home() );
115: String cp = FileUtils.filesToList(cpf).replace("; ",
116: System.getProperty("path.separator", ";")).trim();
117:
118: if (cp.length() > 0) {
119: execCommand.add("-classpath");
120: execCommand.add(cp);
121: }
122:
123: // sources and classes, separated with ";" on windows and ":" on linux !!
124: execCommand.add("-sourcepath");
125: execCommand.add(actualProject.getSources_Home()
126: .getAbsolutePath()
127: + System.getProperty("path.separator", ";")
128: + actualProject.getClasses_Home().getAbsolutePath());
129:
130: //execCommand.add( "-exclude" );
131: //execCommand.add( );
132:
133: // execCommand.add( "-classes" );
134: // execCommand.add( "net.\\*" );
135:
136: // [Sep2007] must be split,
137: // can't create Process processes with more than approx 400 args
138: // max len of cmd is 32'000 chars!
139: List<ArrayList<File>> splits = split(sourcesToAnalyse, 200);
140:
141: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
142: .appendLine("Lint4J analysis of "
143: + sourcesToAnalyse.size() + " sources:");
144: if (options.length() > 0) {
145: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
146: .appendLine(" options: " + options);
147: }
148: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
149: .appendLine("");
150:
151: try {
152:
153: int n = 0;
154: for (List<File> files : splits) {
155: n += proceedLint4JPartial(new ArrayList<String>(
156: execCommand), // COPY !!
157: files, ignoreIrrelevantCat);
158: }
159:
160: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
161: .appendLine("Lint4J analysis done, " + n
162: + " message" + (n == 1 ? "" : "s")
163: + " produced."
164: + (n > 0 ? " (See Messages tab)" : ""));
165: } catch (Exception e) {
166: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
167: .appendErrorLine("Cannot perform Lint4J analysis: "
168: + e.getMessage());
169: //System.out.println("Bad lint4j command: "+execCommand);
170: e.printStackTrace();
171: } finally {
172: LineMessagesManager.getInstance().refreshView();
173: }
174: }
175:
176: /** important: pass a copy of the command.
177: */
178: private static int proceedLint4JPartial(List<String> execCommand,
179: List<File> files, boolean ignoreIrrelevantCat)
180: throws Exception {
181: for (File fi : files) {
182: execCommand.add(fi.getAbsolutePath()); // the path must be complete, not partial !
183: }
184:
185: try {
186: //System.out.println("Lint4J Command length="+execCommand.toString().length()+", "+execCommand.size()+" elts");
187:
188: ProcessBuilder pb = new ProcessBuilder(execCommand);
189: Process proc = pb.start();
190: MainEditorFrame.instance.outputPanels.processesManager
191: .addProcess("Lint4J analysis of " + files.size()
192: + " sources", proc, true);
193:
194: LintStreamGobbler lsg = new LintStreamGobbler(
195: proc.getInputStream(),
196: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
197: .createWriterForThisDocument(false), null,
198: ignoreIrrelevantCat);
199: lsg.start();
200:
201: // errors
202: StreamGobbler sge = new StreamGobbler(
203: proc.getErrorStream(),
204: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
205: .createWriterForThisDocument(true), "");
206: sge.start();
207:
208: proc.waitFor();
209: lsg.join();
210: sge.join();
211:
212: return lsg.validMessagesCount;
213: } catch (Exception e) {
214: throw e;
215: }
216: }
217:
218: /** Reads the input lines and ignore some containing specified text.
219: */
220: static final class LintStreamGobbler extends Thread {
221: private final InputStream inputStream;
222: private final Writer writer;
223: final List<String> ignoredMessageParts;
224: public int ignoredCount = 0;
225: public int wroteLinesCount = 0;
226: public int validMessagesCount = 0;
227: private final boolean ignoreIrrelevantCat;
228:
229: public LintStreamGobbler(final InputStream inputStream,
230: final Writer w, final List<String> ignoredMessageParts,
231: final boolean ignoreIrrelevantCat) {
232: this .inputStream = inputStream;
233: this .writer = w;
234: this .ignoredMessageParts = ignoredMessageParts;
235: this .ignoreIrrelevantCat = ignoreIrrelevantCat;
236: }
237:
238: @Override
239: public void run() {
240: try {
241: final InputStreamReader isr = new InputStreamReader(
242: this .inputStream);
243: final BufferedReader br = new BufferedReader(isr);
244:
245: String line;
246: wl: while ((line = br.readLine()) != null) {
247: if (shouldIgnoreQ(line)) {
248: ignoredCount++;
249: continue wl;
250: } else {
251: wroteLinesCount++;
252: }
253:
254: if (Lint4JLineMessage.createAndAdd(line,
255: ignoreIrrelevantCat)) {
256: validMessagesCount++;
257: } else {
258: writer.append(line + "\r\n");
259: writer.flush();
260: }
261:
262: }
263: } catch (IOException ioe) {
264: ioe.printStackTrace();
265: }
266: }
267:
268: public boolean shouldIgnoreQ(String line) {
269: if (ignoredMessageParts == null)
270: return false;
271:
272: for (String imp : ignoredMessageParts) {
273: if (line.indexOf(imp) >= 0)
274: return true;
275: }
276: return false;
277:
278: }
279: }
280:
281: /*
282: // test
283: public static void main(String[] arguments) throws Exception
284: {
285: File lint4jJar = new File("C:/Java/lint4j-0.9.1/jars/lint4j.jar");
286: File javaExePath = new File("c:/java/jdk1.5.0_08/bin/java.exe");
287:
288: Vector<String> execCommand = new Vector<String>();
289: execCommand.add( javaExePath.getAbsolutePath() );
290: execCommand.add( "-jar" );
291: execCommand.add( lint4jJar.getAbsolutePath() );
292:
293:
294: / * execCommand.add( "-home" );
295: execCommand.add( lint4jJar.getParent() );* /
296:
297: execCommand.add( "-v" );
298: execCommand.add( "5" ); //1 severe - 5 suggestion
299:
300: // don't work, not required...
301: //execCommand.add( "-javahome" );
302: //execCommand.add( actualProject.getJava_Home().getAbsolutePath() );
303:
304: // replace "; " with the correct separator, ":" on linux, ";" on windows
305: //java.util.List<File> cpf = actualProject.getClassPath(false); // aux class path
306: //cpf. add( actualProject.getClasses_Home() );
307:
308: String cpCl = "c:\\classes\\tide";
309: String srcPa = "c:\\sources\\other\\Script\\src\\".replace('\\', '/');
310:
311: //execCommand.add( "-classpath" );
312: //execCommand.add( cpCl );
313:
314: // sources and classes, separated with ";" on windows and ":" on linux !!
315: execCommand.add( "-sourcepath" );
316: execCommand.add(
317: srcPa + System.getProperty("path.separator", ";") +
318: cpCl );
319:
320: //execCommand.add( "-exclude" );
321: //execCommand.add( );
322:
323: //execCommand.add( "-classes" );
324: //execCommand.add( "*.java" );
325: //execCommand.add("Main.java");
326: //execCommand.add("tide\\javaparser\\javacc_gen\\Javaparser.java");
327:
328: / * // sources
329: for(int i=0; i<sourcesToAnalyse.size(); i++)
330: {
331: // [Nov2006]: remove the source path ! unnecessary long
332: execCommand.add( sourcesToAnalyse.get(i).getAbsolutePath().substring(srcPathLength) );
333: } * /
334:
335: //execCommand.add("org.\\ * ");
336:
337:
338: System.out.println(""+execCommand);
339: Process proc = Runtime.getRuntime().exec( execCommand.toArray(new String[execCommand.size()]) );
340: StreamGobbler sgIn = new StreamGobbler( proc.getInputStream(), System.out, "out");
341: StreamGobbler sgErr = new StreamGobbler( proc.getErrorStream(), System.err, "err");
342:
343: sgIn.start();
344: sgErr.start();
345: System.out.println("running...");
346: sgIn.join();
347: sgErr.join();
348: System.out.println("done");
349:
350: }*/
351:
352: }
|