1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 package groovy.ui;
47
48 import groovy.lang.GroovyShell;
49 import groovy.lang.MetaClass;
50 import groovy.lang.Script;
51
52 import java.io.BufferedReader;
53 import java.io.File;
54 import java.io.FileInputStream;
55 import java.io.FileNotFoundException;
56 import java.io.FileReader;
57 import java.io.FileWriter;
58 import java.io.IOException;
59 import java.io.InputStreamReader;
60 import java.io.PrintWriter;
61 import java.util.Iterator;
62 import java.util.List;
63
64 import org.apache.commons.cli.CommandLine;
65 import org.apache.commons.cli.CommandLineParser;
66 import org.apache.commons.cli.HelpFormatter;
67 import org.apache.commons.cli.OptionBuilder;
68 import org.apache.commons.cli.Options;
69 import org.apache.commons.cli.ParseException;
70 import org.apache.commons.cli.PosixParser;
71 import org.codehaus.groovy.control.CompilationFailedException;
72 import org.codehaus.groovy.control.CompilerConfiguration;
73 import org.codehaus.groovy.runtime.InvokerHelper;
74 import org.codehaus.groovy.runtime.InvokerInvocationException;
75
76 /***
77 * A Command line to execute groovy.
78 *
79 * @author Jeremy Rayner
80 * @author Yuri Schimke
81 * @version $Revision: 1.22 $
82 */
83 public class GroovyMain {
84
85 private List args;
86
87
88 private boolean isScriptFile;
89
90
91 private String script;
92
93
94 private boolean processFiles;
95
96
97 private boolean editFiles;
98
99
100 private boolean autoOutput;
101
102
103 private boolean processSockets;
104
105
106 private int port;
107
108
109 private String backupExtension;
110
111
112 private boolean debug = false;
113
114
115 private CompilerConfiguration conf = new CompilerConfiguration();
116
117 /***
118 * Main CLI interface.
119 *
120 * @param args all command line args.
121 */
122 public static void main(String args[]) {
123 MetaClass.setUseReflection(true);
124
125 Options options = buildOptions();
126
127 try {
128 CommandLine cmd = parseCommandLine(options, args);
129
130 if (cmd.hasOption('h')) {
131 HelpFormatter formatter = new HelpFormatter();
132 formatter.printHelp("groovy", options);
133 } else if (cmd.hasOption('v')) {
134 String version = InvokerHelper.getVersion();
135 System.out.println("Groovy Version: " + version + " JVM: " + System.getProperty("java.vm.version"));
136 } else {
137
138 if (!process(cmd)) {
139 System.exit(1);
140 }
141 }
142 } catch (ParseException pe) {
143 System.out.println("error: " + pe.getMessage());
144 HelpFormatter formatter = new HelpFormatter();
145 formatter.printHelp("groovy", options);
146 }
147 }
148
149 /***
150 * Parse the command line.
151 *
152 * @param options the options parser.
153 * @param args the command line args.
154 * @return parsed command line.
155 * @throws ParseException if there was a problem.
156 */
157 private static CommandLine parseCommandLine(Options options, String[] args) throws ParseException {
158 CommandLineParser parser = new PosixParser();
159 CommandLine cmd = parser.parse(options, args, true);
160 return cmd;
161 }
162
163 /***
164 * Build the options parser. Has to be synchronized because of the way Options are constructed.
165 *
166 * @return an options parser.
167 */
168 private static synchronized Options buildOptions() {
169 Options options = new Options();
170
171 options.addOption(OptionBuilder.hasArg(false).withDescription("usage information").withLongOpt("help").create('h'));
172
173 options.addOption(OptionBuilder.hasArg(false).withDescription("debug mode will print out full stack traces").withLongOpt("debug").create('d'));
174
175 options.addOption(OptionBuilder.hasArg(false).withDescription("display the Groovy and JVM versions").withLongOpt("version").create('v'));
176
177 options.addOption(OptionBuilder.withArgName("charset").hasArg().withDescription("specify the encoding of the files").withLongOpt("encoding").create('c'));
178
179 options.addOption(OptionBuilder.withArgName("script").hasArg().withDescription("specify a command line script").create('e'));
180
181 options.addOption(OptionBuilder.withArgName("extension").hasOptionalArg().withDescription("modify files in place").create('i'));
182
183 options.addOption(OptionBuilder.hasArg(false).withDescription("process files line by line").create('n'));
184
185 options.addOption(OptionBuilder.hasArg(false).withDescription("process files line by line and print result").create('p'));
186
187 options.addOption(OptionBuilder.withArgName("port").hasOptionalArg().withDescription("listen on a port and process inbound lines").create('l'));
188 return options;
189 }
190
191 /***
192 * Process the users request.
193 *
194 * @param line the parsed command line.
195 * @throws ParseException if invalid options are chosen
196 */
197 private static boolean process(CommandLine line) throws ParseException {
198 GroovyMain main = new GroovyMain();
199
200 List args = line.getArgList();
201
202
203 if (line.hasOption('c')) {
204 main.conf.setSourceEncoding(line.getOptionValue("encoding"));
205 }
206
207 main.isScriptFile = !line.hasOption('e');
208 main.debug = line.hasOption('d');
209 main.conf.setDebug(main.debug);
210 main.processFiles = line.hasOption('p') || line.hasOption('n');
211 main.autoOutput = line.hasOption('p');
212 main.editFiles = line.hasOption('i');
213 if (main.editFiles) {
214 main.backupExtension = line.getOptionValue('i');
215 }
216
217 if (main.isScriptFile) {
218 if (args.isEmpty())
219 throw new ParseException("neither -e or filename provided");
220
221 main.script = (String) args.remove(0);
222 if (main.script.endsWith(".java"))
223 throw new ParseException("error: cannot compile file with .java extension: " + main.script);
224 } else {
225 main.script = line.getOptionValue('e');
226 }
227
228 main.processSockets = line.hasOption('l');
229 if (main.processSockets) {
230 String p = line.getOptionValue('l', "1960");
231 main.port = new Integer(p).intValue();
232 }
233 main.args = args;
234
235 return main.run();
236 }
237
238
239 /***
240 * Run the script.
241 */
242 private boolean run() {
243 try {
244 if (processSockets) {
245 processSockets();
246 } else if (processFiles) {
247 processFiles();
248 } else {
249 processOnce();
250 }
251 return true;
252 } catch (CompilationFailedException e) {
253 System.err.println(e);
254 return false;
255 } catch (Throwable e) {
256 if (e instanceof InvokerInvocationException) {
257 InvokerInvocationException iie = (InvokerInvocationException) e;
258 e = iie.getCause();
259 }
260 System.err.println("Caught: " + e);
261 if (debug) {
262 e.printStackTrace();
263 } else {
264 StackTraceElement[] stackTrace = e.getStackTrace();
265 for (int i = 0; i < stackTrace.length; i++) {
266 StackTraceElement element = stackTrace[i];
267 String fileName = element.getFileName();
268 if (fileName!=null && !fileName.endsWith(".java")) {
269 System.err.println("\tat " + element);
270 }
271 }
272 }
273 return false;
274 }
275 }
276
277 /***
278 * Process Sockets.
279 */
280 private void processSockets() throws CompilationFailedException, IOException {
281 GroovyShell groovy = new GroovyShell(conf);
282
283 if (isScriptFile) {
284 groovy.parse(new FileInputStream(huntForTheScriptFile(script)));
285 } else {
286 groovy.parse(script);
287 }
288 new GroovySocketServer(groovy, isScriptFile, script, autoOutput, port);
289 }
290
291 /***
292 * Hunt for the script file, doesn't bother if it is named precisely.
293 *
294 * Tries in this order:
295 * - actual supplied name
296 * - name.groovy
297 * - name.gvy
298 * - name.gy
299 * - name.gsh
300 */
301 public File huntForTheScriptFile(String scriptFileName) {
302 File scriptFile = new File(scriptFileName);
303 String[] standardExtensions = {".groovy",".gvy",".gy",".gsh"};
304 int i = 0;
305 while (i < standardExtensions.length && !scriptFile.exists()) {
306 scriptFile = new File(scriptFileName + standardExtensions[i]);
307 i++;
308 }
309
310 if (!scriptFile.exists()) {
311 scriptFile = new File(scriptFileName);
312 }
313 return scriptFile;
314 }
315
316 /***
317 * Process the input files.
318 */
319 private void processFiles() throws CompilationFailedException, IOException {
320 GroovyShell groovy = new GroovyShell(conf);
321
322 Script s = null;
323
324 if (isScriptFile) {
325 s = groovy.parse(huntForTheScriptFile(script));
326 } else {
327 s = groovy.parse(script, "main");
328 }
329
330 if (args.isEmpty()) {
331 BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
332 PrintWriter writer = new PrintWriter(System.out);
333
334 processReader(s, reader, writer);
335 } else {
336 Iterator i = args.iterator();
337 while (i.hasNext()) {
338 String filename = (String) i.next();
339 File file = huntForTheScriptFile(filename);
340 processFile(s, file);
341 }
342 }
343 }
344
345 /***
346 * Process a single input file.
347 *
348 * @param s the script to execute.
349 * @param file the input file.
350 */
351 private void processFile(Script s, File file) throws IOException {
352 if (!file.exists())
353 throw new FileNotFoundException(file.getName());
354
355 if (!editFiles) {
356 BufferedReader reader = new BufferedReader(new FileReader(file));
357 try {
358 PrintWriter writer = new PrintWriter(System.out);
359 processReader(s, reader, writer);
360 writer.flush();
361 } finally {
362 reader.close();
363 }
364 } else {
365 File backup = null;
366 if (backupExtension == null) {
367 backup = File.createTempFile("groovy_", ".tmp");
368 backup.deleteOnExit();
369 } else {
370 backup = new File(file.getPath() + backupExtension);
371 backup.delete();
372 }
373 if (!file.renameTo(backup))
374 throw new IOException("unable to rename " + file + " to " + backup);
375
376 BufferedReader reader = new BufferedReader(new FileReader(backup));
377 try {
378 PrintWriter writer = new PrintWriter(new FileWriter(file));
379 try {
380 processReader(s, reader, writer);
381 } finally {
382 writer.close();
383 }
384 } finally {
385 reader.close();
386 }
387 }
388 }
389
390 /***
391 * Process a script against a single input file.
392 *
393 * @param s script to execute.
394 * @param reader input file.
395 * @param pw output sink.
396 */
397 private void processReader(Script s, BufferedReader reader, PrintWriter pw) throws IOException {
398 String line = null;
399 s.setProperty("out", pw);
400 while ((line = reader.readLine()) != null) {
401 s.setProperty("line", line);
402 Object o = s.run();
403
404 if (autoOutput) {
405 pw.println(o);
406 }
407 }
408 }
409
410 /***
411 * Process the standard, single script with args.
412 */
413 private void processOnce() throws CompilationFailedException, IOException {
414 GroovyShell groovy = new GroovyShell(conf);
415
416 if (isScriptFile)
417 groovy.run(huntForTheScriptFile(script), args);
418 else
419 groovy.run(script, "script_from_command_line", args);
420 }
421 }