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