View Javadoc

1   /*
2    $Id: GroovyMain.java,v 1.1 2004/07/13 17:38:03 jstrachan Exp $
3   
4    Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5   
6    Redistribution and use of this software and associated documentation
7    ("Software"), with or without modification, are permitted provided
8    that the following conditions are met:
9   
10   1. Redistributions of source code must retain copyright
11   statements and notices.  Redistributions must also contain a
12   copy of this document.
13  
14   2. Redistributions in binary form must reproduce the
15   above copyright notice, this list of conditions and the
16   following disclaimer in the documentation and/or other
17   materials provided with the distribution.
18  
19   3. The name "groovy" must not be used to endorse or promote
20   products derived from this Software without prior written
21   permission of The Codehaus.  For written permission,
22   please contact info@codehaus.org.
23  
24   4. Products derived from this Software may not be called "groovy"
25   nor may "groovy" appear in their names without prior written
26   permission of The Codehaus. "groovy" is a registered
27   trademark of The Codehaus.
28  
29   5. Due credit should be given to The Codehaus -
30   http://groovy.codehaus.org/
31  
32   THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
33   ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
34   NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
35   FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
36   THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43   OF THE POSSIBILITY OF SUCH DAMAGE.
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.FileNotFoundException;
55  import java.io.FileReader;
56  import java.io.FileWriter;
57  import java.io.IOException;
58  import java.io.InputStreamReader;
59  import java.io.PrintWriter;
60  import java.util.Iterator;
61  import java.util.List;
62  
63  import org.apache.commons.cli.CommandLine;
64  import org.apache.commons.cli.CommandLineParser;
65  import org.apache.commons.cli.HelpFormatter;
66  import org.apache.commons.cli.OptionBuilder;
67  import org.apache.commons.cli.Options;
68  import org.apache.commons.cli.ParseException;
69  import org.apache.commons.cli.PosixParser;
70  import org.codehaus.groovy.control.CompilationFailedException;
71  
72  /***
73   * A Command line to execute groovy.
74   * 
75   * @author Yuri Schimke
76   * @version $Revision: 1.1 $
77   */
78  public class GroovyMain {
79      // arguments to the script
80      private List args;
81  
82      // is this a file on disk
83      private boolean isScriptFile;
84  
85      // filename or content of script
86      private String script;
87  
88      // process args as input files
89      private boolean processFiles;
90  
91      // edit input files in place
92      private boolean editFiles;
93  
94      // automatically output the result of each script
95      private boolean autoOutput;
96  
97      // backup input files with extension
98      private String backupExtension;
99  
100     /***
101      * Main CLI interface.
102      * 
103      * @param args
104      *            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             }
118             else {
119                 process(cmd);
120             }
121         }
122         catch (ParseException pe) {
123             System.out.println("error: " + pe.getMessage());
124             System.out.println("usage: groovy [-e 'script'] [groovyScript] [arguments]");
125         }
126     }
127 
128     /***
129      * Parse the command line.
130      * 
131      * @param options
132      *            the options parser.
133      * @param args
134      *            the command line args.
135      * @return parsed command line.
136      * @throws ParseException
137      *             if there was a problem.
138      */
139     private static CommandLine parseCommandLine(Options options, String[] args) throws ParseException {
140         CommandLineParser parser = new PosixParser();
141         CommandLine cmd = parser.parse(options, args);
142         return cmd;
143     }
144 
145     /***
146      * Build the options parser.
147      * 
148      * @return an options parser.
149      */
150     private static Options buildOptions() {
151         Options options = new Options();
152 
153         options.addOption(OptionBuilder.hasArg(false).withDescription("usage information").withLongOpt("help").create('h'));
154 
155         options.addOption(OptionBuilder.withArgName("script").hasArg().withDescription("specify a command line script").create('e'));
156 
157         options.addOption(OptionBuilder.withArgName("extension").hasOptionalArg().withDescription("modify files in place").create('i'));
158 
159         options.addOption(OptionBuilder.hasArg(false).withDescription("process files line by line").create('n'));
160 
161         options.addOption(OptionBuilder.hasArg(false).withDescription("process files line by line and print result").create('p'));
162         return options;
163     }
164 
165     /***
166      * Process the users request.
167      * 
168      * @param line
169      *            the parsed command line.
170      * @throws ParseException
171      *             if invalid options are chosen
172      */
173     private static void process(CommandLine line) throws ParseException {
174         GroovyMain main = new GroovyMain();
175 
176         List args = line.getArgList();
177 
178         main.isScriptFile = !line.hasOption('e');
179         main.processFiles = line.hasOption('p') || line.hasOption('n');
180         main.autoOutput = line.hasOption('p');
181         main.editFiles = line.hasOption('i');
182         if (main.editFiles) {
183             main.backupExtension = line.getOptionValue('i');
184         }
185 
186         if (main.isScriptFile) {
187             if (args.isEmpty())
188                 throw new ParseException("neither -e or filename provided");
189 
190             main.script = (String) args.remove(0);
191             if (main.script.endsWith(".java"))
192                 throw new ParseException("error: cannot compile file with .java extension: " + main.script);
193         }
194         else {
195             main.script = line.getOptionValue('e');
196         }
197 
198         main.args = args;
199 
200         main.run();
201     }
202 
203     public GroovyMain() {
204     }
205 
206     /***
207      * Run the script.
208      */
209     private void run() {
210         try {
211             if (processFiles) {
212                 processFiles();
213             }
214             else {
215                 processOnce();
216             }
217         }
218         catch (Exception e) {
219             System.out.println("Caught: " + e);
220             e.printStackTrace();
221         }
222     }
223 
224     /***
225      * Process the input files.
226      */
227     private void processFiles() throws CompilationFailedException, IOException {
228         GroovyShell groovy = new GroovyShell();
229 
230         Script s = null;
231 
232         if (isScriptFile)
233             s = groovy.parse(new File(script));
234         else
235             s = groovy.parse(script, "main");
236 
237         if (args.isEmpty()) {
238             BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
239             PrintWriter writer = new PrintWriter(System.out);
240 
241             processReader(s, reader, writer);
242         }
243         else {
244             Iterator i = args.iterator();
245             while (i.hasNext()) {
246                 String filename = (String) i.next();
247                 File file = new File(filename);
248                 processFile(s, file);
249             }
250         }
251     }
252 
253     /***
254      * Process a single input file.
255      * 
256      * @param s
257      *            the script to execute.
258      * @param file
259      *            the input file.
260      */
261     private void processFile(Script s, File file) throws IOException {
262         if (!file.exists())
263             throw new FileNotFoundException(file.getName());
264 
265         if (!editFiles) {
266             BufferedReader reader = new BufferedReader(new FileReader(file));
267             try {
268                 PrintWriter writer = new PrintWriter(System.out);
269                 processReader(s, reader, writer);
270                 writer.flush();
271             }
272             finally {
273                 reader.close();
274             }
275         }
276         else {
277             File backup = null;
278             if (backupExtension == null) {
279                 backup = File.createTempFile("groovy_", ".tmp");
280                 backup.deleteOnExit();
281             }
282             else {
283                 backup = new File(file.getPath() + backupExtension);
284                 backup.delete();
285             }
286             if (!file.renameTo(backup))
287                 throw new IOException("unable to rename " + file + " to " + backup);
288 
289             BufferedReader reader = new BufferedReader(new FileReader(backup));
290             try {
291                 PrintWriter writer = new PrintWriter(new FileWriter(file));
292                 try {
293                     processReader(s, reader, writer);
294                 }
295                 finally {
296                     writer.close();
297                 }
298             }
299             finally {
300                 reader.close();
301             }
302         }
303     }
304 
305     /***
306      * Process a script against a single input file.
307      * 
308      * @param s
309      *            script to execute.
310      * @param reader
311      *            input file.
312      * @param pw
313      *            output sink.
314      */
315     private void processReader(Script s, BufferedReader reader, PrintWriter pw) throws IOException {
316         String line = null;
317         s.setProperty("out", pw);
318         while ((line = reader.readLine()) != null) {
319             s.setProperty("line", line);
320             Object o = s.run();
321 
322             if (autoOutput) {
323                 pw.println(o);
324             }
325         }
326     }
327 
328     /***
329      * Process the standard, single script with args.
330      */
331     private void processOnce() throws CompilationFailedException, IOException {
332         GroovyShell groovy = new GroovyShell();
333 
334         if (isScriptFile)
335             groovy.run(new File(script), args);
336         else
337             groovy.run(script, "main", args);
338     }
339 }