View Javadoc

1   package org.apache.maven.shared.utils.cli;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.util.ArrayList;
25  import java.util.Collections;
26  import java.util.LinkedHashMap;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Properties;
30  import java.util.Vector;
31  
32  import org.apache.maven.shared.utils.Os;
33  import org.apache.maven.shared.utils.StringUtils;
34  import org.apache.maven.shared.utils.cli.shell.BourneShell;
35  import org.apache.maven.shared.utils.cli.shell.CmdShell;
36  import org.apache.maven.shared.utils.cli.shell.CommandShell;
37  import org.apache.maven.shared.utils.cli.shell.Shell;
38  
39  /**
40   * <p/>
41   * Commandline objects help handling command lines specifying processes to
42   * execute.
43   * </p>
44   * <p/>
45   * The class can be used to define a command line as nested elements or as a
46   * helper to define a command line by an application.
47   * </p>
48   * <p/>
49   * <code>
50   * &lt;someelement&gt;<br>
51   * &nbsp;&nbsp;&lt;acommandline executable="/executable/to/run"&gt;<br>
52   * &nbsp;&nbsp;&nbsp;&nbsp;&lt;argument value="argument 1" /&gt;<br>
53   * &nbsp;&nbsp;&nbsp;&nbsp;&lt;argument line="argument_1 argument_2 argument_3" /&gt;<br>
54   * &nbsp;&nbsp;&nbsp;&nbsp;&lt;argument value="argument 4" /&gt;<br>
55   * &nbsp;&nbsp;&lt;/acommandline&gt;<br>
56   * &lt;/someelement&gt;<br>
57   * </code>
58   * </p>
59   * <p/>
60   * The element <code>someelement</code> must provide a method
61   * <code>createAcommandline</code> which returns an instance of this class.
62   * </p>
63   *
64   * @author thomas.haas@softwired-inc.com
65   * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
66   */
67  public class Commandline
68      implements Cloneable
69  {
70      private final List<Arg> arguments = new Vector<Arg>();
71  
72      //protected Vector envVars = new Vector();
73      // synchronized added to preserve synchronize of Vector class
74      private final Map<String, String> envVars = Collections.synchronizedMap( new LinkedHashMap<String, String>() );
75  
76      private Shell shell;
77  
78      /**
79       * Create a new command line object.
80       * Shell is autodetected from operating system
81       */
82      public Commandline( Shell shell )
83      {
84          this.shell = shell;
85      }
86  
87      /**
88       * Create a new command line object.
89       * Shell is autodetected from operating system
90       *
91       * @param toProcess The command to process
92       */
93      public Commandline( String toProcess )
94      {
95          setDefaultShell();
96          String[] tmp = new String[0];
97          try
98          {
99              tmp = CommandLineUtils.translateCommandline( toProcess );
100         }
101         catch ( Exception e )
102         {
103             System.err.println( "Error translating Commandline." );
104         }
105         if ( ( tmp != null ) && ( tmp.length > 0 ) )
106         {
107             setExecutable( tmp[0] );
108             for ( int i = 1; i < tmp.length; i++ )
109             {
110                 createArg().setValue( tmp[i] );
111             }
112         }
113     }
114 
115     /**
116      * Create a new command line object.
117      * Shell is autodetected from operating system
118      */
119     public Commandline()
120     {
121         setDefaultShell();
122     }
123 
124     /**
125      * <p>Sets the shell or command-line interpretor for the detected operating system,
126      * and the shell arguments.</p>
127      */
128     private void setDefaultShell()
129     {
130         //If this is windows set the shell to command.com or cmd.exe with correct arguments.
131         if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
132         {
133             if ( Os.isFamily( Os.FAMILY_WIN9X ) )
134             {
135                 setShell( new CommandShell() );
136             }
137             else
138             {
139                 setShell( new CmdShell() );
140             }
141         }
142         else
143         {
144             setShell( new BourneShell() );
145         }
146     }
147 
148     /**
149      * Creates an argument object.
150      * <p/>
151      * <p>Each commandline object has at most one instance of the
152      * argument class.  This method calls
153      * <code>this.createArgument(false)</code>.</p>
154      *
155      * @return the argument object.
156      */
157     public Arg createArg()
158     {
159         return this.createArg( false );
160     }
161 
162     /**
163      * Creates an argument object and adds it to our list of args.
164      * <p/>
165      * <p>Each commandline object has at most one instance of the
166      * argument class.</p>
167      *
168      * @param insertAtStart if true, the argument is inserted at the
169      *                      beginning of the list of args, otherwise it is appended.
170      */
171     public Arg createArg( boolean insertAtStart )
172     {
173         Arg argument = new Argument();
174         if ( insertAtStart )
175         {
176             arguments.add( 0, argument );
177         }
178         else
179         {
180             arguments.add( argument );
181         }
182         return argument;
183     }
184 
185     /**
186      * Sets the executable to run.
187      */
188     public void setExecutable( String executable )
189     {
190         shell.setExecutable( executable );
191     }
192 
193     public String getExecutable()
194     {
195 
196         return shell.getExecutable();
197     }
198 
199     public void addArguments( String... line )
200     {
201         for ( String aLine : line )
202         {
203             createArg().setValue( aLine );
204         }
205     }
206 
207     /**
208      * Add an environment variable
209      */
210     public void addEnvironment( String name, String value )
211     {
212         //envVars.add( name + "=" + value );
213         envVars.put( name, value );
214     }
215 
216     /**
217      * Add system environment variables
218      */
219     public void addSystemEnvironment()
220     {
221         Properties systemEnvVars = CommandLineUtils.getSystemEnvVars();
222 
223         for ( Object o : systemEnvVars.keySet() )
224         {
225             String key = (String) o;
226             if ( !envVars.containsKey( key ) )
227             {
228                 addEnvironment( key, systemEnvVars.getProperty( key ) );
229             }
230         }
231     }
232 
233     /**
234      * Return the list of environment variables
235      */
236     public String[] getEnvironmentVariables()
237     {
238         addSystemEnvironment();
239         String[] environmentVars = new String[envVars.size()];
240         int i = 0;
241         for ( String name : envVars.keySet() )
242         {
243             String value = envVars.get( name );
244             environmentVars[i] = name + "=" + value;
245             i++;
246         }
247         return environmentVars;
248     }
249 
250     /**
251      * Returns the executable and all defined arguments.
252      */
253     public String[] getCommandline()
254     {
255         final String[] args = getArguments();
256         String executable = getExecutable();
257 
258         if ( executable == null )
259         {
260             return args;
261         }
262         final String[] result = new String[args.length + 1];
263         result[0] = executable;
264         System.arraycopy( args, 0, result, 1, args.length );
265         return result;
266     }
267 
268     /**
269      * Returns the shell, executable and all defined arguments.
270      */
271     private String[] getShellCommandline()
272     {
273         List<String> shellCommandLine = getShell().getShellCommandLine( getArguments() );
274         return shellCommandLine.toArray( new String[shellCommandLine.size()] );
275     }
276 
277     /**
278      * Returns all arguments defined by <code>addLine</code>,
279      * <code>addValue</code> or the argument object.
280      */
281     public String[] getArguments()
282     {
283         List<String> result = new ArrayList<String>( arguments.size() * 2 );
284         for ( Arg argument : arguments )
285         {
286             Argument arg = (Argument) argument;
287             String[] s = arg.getParts();
288             if ( s != null )
289             {
290                 Collections.addAll( result, s );
291             }
292         }
293 
294         return result.toArray( new String[result.size()] );
295     }
296 
297     public String toString()
298     {
299         return StringUtils.join( getShellCommandline(), " " );
300     }
301 
302 
303     public Object clone()
304     {
305         throw new RuntimeException( "Do we ever clone a commandline?" );
306 /*        Commandline c = new Commandline( (Shell) shell.clone() );
307        c.addArguments( getArguments() );
308         return c;*/
309     }
310 
311     /**
312      * Sets execution directory.
313      */
314     public void setWorkingDirectory( String path )
315     {
316         shell.setWorkingDirectory( path );
317     }
318 
319     /**
320      * Sets execution directory.
321      */
322     public void setWorkingDirectory( File workingDirectory )
323     {
324         shell.setWorkingDirectory( workingDirectory );
325     }
326 
327     public File getWorkingDirectory()
328     {
329         return shell.getWorkingDirectory();
330     }
331 
332     /**
333      * Clear out the arguments but leave the executable in place for another operation.
334      */
335     public void clearArgs()
336     {
337         arguments.clear();
338     }
339 
340     /**
341      * Executes the command.
342      */
343     public Process execute()
344         throws CommandLineException
345     {
346         Process process;
347 
348         //addEnvironment( "MAVEN_TEST_ENVAR", "MAVEN_TEST_ENVAR_VALUE" );
349 
350         String[] environment = getEnvironmentVariables();
351 
352         File workingDir = shell.getWorkingDirectory();
353 
354         try
355         {
356             if ( workingDir == null )
357             {
358                 process = Runtime.getRuntime().exec( getShellCommandline(), environment );
359             }
360             else
361             {
362                 if ( !workingDir.exists() )
363                 {
364                     throw new CommandLineException(
365                         "Working directory \"" + workingDir.getPath() + "\" does not exist!" );
366                 }
367                 else if ( !workingDir.isDirectory() )
368                 {
369                     throw new CommandLineException(
370                         "Path \"" + workingDir.getPath() + "\" does not specify a directory." );
371                 }
372 
373                 process = Runtime.getRuntime().exec( getShellCommandline(), environment, workingDir );
374             }
375         }
376         catch ( IOException ex )
377         {
378             throw new CommandLineException( "Error while executing process.", ex );
379         }
380 
381         return process;
382     }
383 
384     /**
385      * Allows to set the shell to be used in this command line.
386      *
387      * @param shell the shell
388      */
389     void setShell( Shell shell )
390     {
391         this.shell = shell;
392     }
393 
394     /**
395      * Get the shell to be used in this command line.
396      */
397     public Shell getShell()
398     {
399         return shell;
400     }
401 
402     public static class Argument
403         implements Arg
404     {
405         private String[] parts;
406 
407         /* (non-Javadoc)
408          * @see org.apache.maven.shared.utils.cli.Argumnt#setValue(java.lang.String)
409          */
410         public void setValue( String value )
411         {
412             if ( value != null )
413             {
414                 parts = new String[]{ value };
415             }
416         }
417 
418         /* (non-Javadoc)
419          * @see org.apache.maven.shared.utils.cli.Argumnt#setLine(java.lang.String)
420          */
421         public void setLine( String line )
422         {
423             if ( line == null )
424             {
425                 return;
426             }
427             try
428             {
429                 parts = CommandLineUtils.translateCommandline( line );
430             }
431             catch ( Exception e )
432             {
433                 System.err.println( "Error translating Commandline." );
434             }
435         }
436 
437         /* (non-Javadoc)
438          * @see org.apache.maven.shared.utils.cli.Argumnt#setFile(java.io.File)
439          */
440         public void setFile( File value )
441         {
442             parts = new String[]{ value.getAbsolutePath() };
443         }
444 
445         /* (non-Javadoc)
446          * @see org.apache.maven.shared.utils.cli.Argumnt#getParts()
447          */
448         private String[] getParts()
449         {
450             return parts;
451         }
452     }
453 }