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