View Javadoc

1   package org.apache.maven.shared.utils.cli.shell;
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  
23  import java.io.File;
24  import java.util.ArrayList;
25  import java.util.Arrays;
26  import java.util.List;
27  import org.apache.maven.shared.utils.StringUtils;
28  
29  /**
30   * <p>
31   * Class that abstracts the Shell functionality,
32   * with subclases for shells that behave particularly, like
33   * <ul>
34   * <li><code>command.com</code></li>
35   * <li><code>cmd.exe</code></li>
36   * </ul>
37   * </p>
38   *
39   * @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
40   * 
41   */
42  public class Shell
43      implements Cloneable
44  {
45      private static final char[] DEFAULT_QUOTING_TRIGGER_CHARS = { ' ' };
46  
47      private String shellCommand;
48  
49      private final List<String> shellArgs = new ArrayList<String>();
50  
51      private boolean quotedArgumentsEnabled = true;
52  
53      private String executable;
54  
55      private String workingDir;
56  
57      private boolean quotedExecutableEnabled = true;
58  
59      private boolean singleQuotedArgumentEscaped = false;
60  
61      private boolean singleQuotedExecutableEscaped = false;
62  
63      private char argQuoteDelimiter = '\"';
64  
65      private char exeQuoteDelimiter = '\"';
66  
67      /**
68       * Set the command to execute the shell (eg. COMMAND.COM, /bin/bash,...)
69       *
70       * @param shellCommand The command
71       */
72      void setShellCommand( String shellCommand )
73      {
74          this.shellCommand = shellCommand;
75      }
76  
77      /**
78       * Get the command to execute the shell
79       *
80       * @return  The command
81       */
82      String getShellCommand()
83      {
84          return shellCommand;
85      }
86  
87      /**
88       * Set the shell arguments when calling a command line (not the executable arguments)
89       * (eg. /X /C for CMD.EXE)
90       *
91       * @param shellArgs the arguments to the shell
92       */
93      void setShellArgs( String[] shellArgs )
94      {
95          this.shellArgs.clear();
96          this.shellArgs.addAll( Arrays.asList( shellArgs ) );
97      }
98  
99      /**
100      * Get the shell arguments
101      *
102      * @return  The arguments
103      */
104     String[] getShellArgs()
105     {
106         if ( ( shellArgs == null ) || shellArgs.isEmpty() )
107         {
108             return null;
109         }
110         else
111         {
112             return shellArgs.toArray( new String[shellArgs.size()] );
113         }
114     }
115 
116     /**
117      * Get the command line for the provided executable and arguments in this shell
118      *
119      * @param executable executable that the shell has to call
120      * @param arguments  arguments for the executable, not the shell
121      * @return List with one String object with executable and arguments quoted as needed
122      */
123     List<String> getCommandLine( String executable, String... arguments )
124     {
125         return getRawCommandLine( executable, arguments );
126     }
127 
128     List<String> getRawCommandLine( String executable, String... arguments )
129     {
130         List<String> commandLine = new ArrayList<String>();
131         StringBuilder sb = new StringBuilder();
132 
133         if ( executable != null )
134         {
135             String preamble = getExecutionPreamble();
136             if ( preamble != null )
137             {
138                 sb.append( preamble );
139             }
140 
141             if ( isQuotedExecutableEnabled() )
142             {
143                 char[] escapeChars =
144                     getEscapeChars( isSingleQuotedExecutableEscaped(), isDoubleQuotedExecutableEscaped() );
145 
146                 sb.append( StringUtils.quoteAndEscape( getExecutable(), getExecutableQuoteDelimiter(), escapeChars,
147                                                        getQuotingTriggerChars(), '\\', false ) );
148             }
149             else
150             {
151                 sb.append( getExecutable() );
152             }
153         }
154         for ( String argument : arguments )
155         {
156             if ( sb.length() > 0 )
157             {
158                 sb.append( ' ' );
159             }
160 
161             if ( isQuotedArgumentsEnabled() )
162             {
163                 char[] escapeChars = getEscapeChars( isSingleQuotedArgumentEscaped(), isDoubleQuotedArgumentEscaped() );
164 
165                 sb.append( StringUtils.quoteAndEscape( argument, getArgumentQuoteDelimiter(), escapeChars,
166                                                        getQuotingTriggerChars(), '\\', false ) );
167             }
168             else
169             {
170                 sb.append( argument );
171             }
172         }
173 
174         commandLine.add( sb.toString() );
175 
176         return commandLine;
177     }
178 
179     char[] getQuotingTriggerChars()
180     {
181         return DEFAULT_QUOTING_TRIGGER_CHARS;
182     }
183 
184     String getExecutionPreamble()
185     {
186         return null;
187     }
188 
189     char[] getEscapeChars( boolean includeSingleQuote, boolean includeDoubleQuote )
190     {
191         StringBuilder buf = new StringBuilder( 2 );
192         if ( includeSingleQuote )
193         {
194             buf.append( '\'' );
195         }
196 
197         if ( includeDoubleQuote )
198         {
199             buf.append( '\"' );
200         }
201 
202         char[] result = new char[buf.length()];
203         buf.getChars( 0, buf.length(), result, 0 );
204 
205         return result;
206     }
207 
208     protected boolean isDoubleQuotedArgumentEscaped()
209     {
210         return false;
211     }
212 
213     protected boolean isSingleQuotedArgumentEscaped()
214     {
215         return singleQuotedArgumentEscaped;
216     }
217 
218     boolean isDoubleQuotedExecutableEscaped()
219     {
220         return false;
221     }
222 
223     boolean isSingleQuotedExecutableEscaped()
224     {
225         return singleQuotedExecutableEscaped;
226     }
227 
228     void setArgumentQuoteDelimiter( char argQuoteDelimiter )
229     {
230         this.argQuoteDelimiter = argQuoteDelimiter;
231     }
232 
233     char getArgumentQuoteDelimiter()
234     {
235         return argQuoteDelimiter;
236     }
237 
238     void setExecutableQuoteDelimiter( char exeQuoteDelimiter )
239     {
240         this.exeQuoteDelimiter = exeQuoteDelimiter;
241     }
242 
243     char getExecutableQuoteDelimiter()
244     {
245         return exeQuoteDelimiter;
246     }
247 
248     /**
249      * Get the full command line to execute, including shell command, shell arguments,
250      * executable and executable arguments
251      *
252      * @param arguments arguments for the executable, not the shell
253      * @return List of String objects, whose array version is suitable to be used as argument
254      *         of Runtime.getRuntime().exec()
255      */
256     public List<String> getShellCommandLine( String... arguments )
257     {
258 
259         List<String> commandLine = new ArrayList<String>();
260 
261         if ( getShellCommand() != null )
262         {
263             commandLine.add( getShellCommand() );
264         }
265 
266         if ( getShellArgs() != null )
267         {
268             commandLine.addAll( getShellArgsList() );
269         }
270 
271         commandLine.addAll( getCommandLine( getExecutable(), arguments ) );
272 
273         return commandLine;
274 
275     }
276 
277     List<String> getShellArgsList()
278     {
279         return shellArgs;
280     }
281 
282     public void setQuotedArgumentsEnabled( boolean quotedArgumentsEnabled )
283     {
284         this.quotedArgumentsEnabled = quotedArgumentsEnabled;
285     }
286 
287     boolean isQuotedArgumentsEnabled()
288     {
289         return quotedArgumentsEnabled;
290     }
291 
292     void setQuotedExecutableEnabled( boolean quotedExecutableEnabled )
293     {
294         this.quotedExecutableEnabled = quotedExecutableEnabled;
295     }
296 
297     boolean isQuotedExecutableEnabled()
298     {
299         return quotedExecutableEnabled;
300     }
301 
302     /**
303      * Sets the executable to run.
304      */
305     public void setExecutable( String executable )
306     {
307         if ( ( executable == null ) || ( executable.length() == 0 ) )
308         {
309             return;
310         }
311         this.executable = executable.replace( '/', File.separatorChar ).replace( '\\', File.separatorChar );
312     }
313 
314     public String getExecutable()
315     {
316         return executable;
317     }
318 
319     /**
320      * Sets execution directory.
321      */
322     public void setWorkingDirectory( String path )
323     {
324         if ( path != null )
325         {
326             workingDir = path;
327         }
328     }
329 
330     /**
331      * Sets execution directory.
332      */
333     public void setWorkingDirectory( File workingDir )
334     {
335         if ( workingDir != null )
336         {
337             this.workingDir = workingDir.getAbsolutePath();
338         }
339     }
340 
341     public File getWorkingDirectory()
342     {
343         return workingDir == null ? null : new File( workingDir );
344     }
345 
346     String getWorkingDirectoryAsString()
347     {
348         return workingDir;
349     }
350 
351     public Object clone()
352     {
353         throw new RuntimeException( "Do we ever clone this?" );
354 /*        Shell shell = new Shell();
355         shell.setExecutable( getExecutable() );
356         shell.setWorkingDirectory( getWorkingDirectory() );
357         shell.setShellArgs( getShellArgs() );
358         return shell;*/
359     }
360 
361     void setSingleQuotedArgumentEscaped( boolean singleQuotedArgumentEscaped )
362     {
363         this.singleQuotedArgumentEscaped = singleQuotedArgumentEscaped;
364     }
365 
366     void setSingleQuotedExecutableEscaped( boolean singleQuotedExecutableEscaped )
367     {
368         this.singleQuotedExecutableEscaped = singleQuotedExecutableEscaped;
369     }
370 
371 }