View Javadoc

1   package org.apache.maven.wagon.providers.ssh;
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.FileInputStream;
24  import java.io.FileNotFoundException;
25  import java.io.FileOutputStream;
26  import java.io.IOException;
27  import java.util.List;
28  import java.util.zip.ZipEntry;
29  import java.util.zip.ZipOutputStream;
30  
31  import org.apache.maven.wagon.CommandExecutionException;
32  import org.apache.maven.wagon.CommandExecutor;
33  import org.apache.maven.wagon.PathUtils;
34  import org.apache.maven.wagon.PermissionModeUtils;
35  import org.apache.maven.wagon.ResourceDoesNotExistException;
36  import org.apache.maven.wagon.Streams;
37  import org.apache.maven.wagon.TransferFailedException;
38  import org.apache.maven.wagon.Wagon;
39  import org.apache.maven.wagon.authentication.AuthenticationInfo;
40  import org.apache.maven.wagon.authorization.AuthorizationException;
41  import org.apache.maven.wagon.repository.Repository;
42  import org.apache.maven.wagon.repository.RepositoryPermissions;
43  import org.apache.maven.wagon.resource.Resource;
44  import org.codehaus.plexus.util.FileUtils;
45  import org.codehaus.plexus.util.IOUtil;
46  import org.codehaus.plexus.util.StringUtils;
47  
48  public class ScpHelper
49  {
50      public static final char PATH_SEPARATOR = '/';
51  
52      public static final int DEFAULT_SSH_PORT = 22;
53      
54      private final CommandExecutor executor;
55      
56      public ScpHelper( CommandExecutor executor )
57      {
58          this.executor = executor;
59      }
60  
61      public static String getResourceDirectory( String resourceName )
62      {
63          String dir = PathUtils.dirname( resourceName );
64          dir = StringUtils.replace( dir, "\\", "/" );
65          return dir;
66      }
67  
68      public static String getResourceFilename( String r )
69      {
70          String filename;
71          if ( r.lastIndexOf( PATH_SEPARATOR ) > 0 )
72          {
73              filename = r.substring( r.lastIndexOf( PATH_SEPARATOR ) + 1 );
74          }
75          else
76          {
77              filename = r;
78          }
79          return filename;
80      }
81  
82      public static Resource getResource( String resourceName )
83      {
84          String r = StringUtils.replace( resourceName, "\\", "/" );
85          return new Resource( r );
86      }
87  
88      public static File getPrivateKey( AuthenticationInfo authenticationInfo )
89          throws FileNotFoundException
90      {
91          // If user don't define a password, he want to use a private key
92          File privateKey = null;
93          if ( authenticationInfo.getPassword() == null )
94          {
95  
96              if ( authenticationInfo.getPrivateKey() != null )
97              {
98                  privateKey = new File( authenticationInfo.getPrivateKey() );
99                  if ( !privateKey.exists() )
100                 {
101                     throw new FileNotFoundException( "Private key '" + privateKey + "' not found" );
102                 }
103             }
104             else
105             {
106                 privateKey = findPrivateKey();
107             }
108 
109             if ( privateKey != null && privateKey.exists() )
110             {
111                 if ( authenticationInfo.getPassphrase() == null )
112                 {
113                     authenticationInfo.setPassphrase( "" );
114                 }
115             }
116         }
117         return privateKey;
118     }
119 
120     private static File findPrivateKey()
121     {
122         String privateKeyDirectory = System.getProperty( "wagon.privateKeyDirectory" );
123 
124         if ( privateKeyDirectory == null )
125         {
126             privateKeyDirectory = System.getProperty( "user.home" );
127         }
128 
129         File privateKey = new File( privateKeyDirectory, ".ssh/id_dsa" );
130 
131         if ( !privateKey.exists() )
132         {
133             privateKey = new File( privateKeyDirectory, ".ssh/id_rsa" );
134             if ( !privateKey.exists() )
135             {
136                 privateKey = null;
137             }
138         }
139 
140         return privateKey;
141     }
142     
143     public static void createZip( List files, File zipName, File basedir )
144         throws IOException
145     {
146         ZipOutputStream zos = new ZipOutputStream( new FileOutputStream( zipName ) );
147 
148         try
149         {
150             for ( int i = 0; i < files.size(); i++ )
151             {
152                 String file = (String) files.get( i );
153 
154                 file = file.replace( '\\', '/' );
155 
156                 writeZipEntry( zos, new File( basedir, file ), file );
157             }
158         }
159         finally
160         {
161             IOUtil.close( zos );
162         }
163     }
164 
165     private static void writeZipEntry( ZipOutputStream jar, File source, String entryName )
166         throws IOException
167     {
168         byte[] buffer = new byte[1024];
169 
170         int bytesRead;
171 
172         FileInputStream is = new FileInputStream( source );
173 
174         try
175         {
176             ZipEntry entry = new ZipEntry( entryName );
177 
178             jar.putNextEntry( entry );
179 
180             while ( ( bytesRead = is.read( buffer ) ) != -1 )
181             {
182                 jar.write( buffer, 0, bytesRead );
183             }
184         }
185         finally
186         {
187             is.close();
188         }
189     }
190 
191     protected static String getPath( String basedir, String dir )
192     {
193         String path;
194         path = basedir;
195         if ( !basedir.endsWith( "/" ) && !dir.startsWith( "/" ) )
196         {
197             path += "/";
198         }
199         path += dir;
200         return path;
201     }
202 
203     public void putDirectory( Wagon wagon, File sourceDirectory, String destinationDirectory )
204         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
205     {
206         Repository repository = wagon.getRepository();
207         
208         String basedir = repository.getBasedir();
209 
210         String destDir = StringUtils.replace( destinationDirectory, "\\", "/" );
211 
212         String path = getPath( basedir, destDir );
213         try
214         {
215             if ( repository.getPermissions() != null )
216             {
217                 String dirPerms = repository.getPermissions().getDirectoryMode();
218 
219                 if ( dirPerms != null )
220                 {
221                     String umaskCmd = "umask " + PermissionModeUtils.getUserMaskFor( dirPerms );
222                     executor.executeCommand( umaskCmd );
223                 }
224             }
225 
226             String mkdirCmd = "mkdir -p " + path;
227 
228             executor.executeCommand( mkdirCmd );
229         }
230         catch ( CommandExecutionException e )
231         {
232             throw new TransferFailedException( "Error performing commands for file transfer", e );
233         }
234 
235         File zipFile;
236         try
237         {
238             zipFile = File.createTempFile( "wagon", ".zip" );
239             zipFile.deleteOnExit();
240 
241             List files = FileUtils.getFileNames( sourceDirectory, "**/**", "", false );
242 
243             createZip( files, zipFile, sourceDirectory );
244         }
245         catch ( IOException e )
246         {
247             throw new TransferFailedException( "Unable to create ZIP archive of directory", e );
248         }
249 
250         wagon.put( zipFile, getPath( destDir, zipFile.getName() ) );
251 
252         try
253         {
254             executor.executeCommand( "cd " + path + "; unzip -q -o " + zipFile.getName() + "; rm -f " + zipFile.getName() );
255 
256             zipFile.delete();
257 
258             RepositoryPermissions permissions = repository.getPermissions();
259 
260             if ( permissions != null && permissions.getGroup() != null )
261             {
262                 executor.executeCommand( "chgrp -Rf " + permissions.getGroup() + " " + path );
263             }
264 
265             if ( permissions != null && permissions.getFileMode() != null )
266             {
267                 executor.executeCommand( "chmod -Rf " + permissions.getFileMode() + " " + path );
268             }
269         }
270         catch ( CommandExecutionException e )
271         {
272             throw new TransferFailedException( "Error performing commands for file transfer", e );
273         }
274     }
275 
276     public List getFileList( String destinationDirectory, Repository repository )
277         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
278     {
279         try
280         {
281             String path = getPath( repository.getBasedir(), destinationDirectory );
282             Streams streams = executor.executeCommand( "ls -FlA " + path, false );
283             
284             return new LSParser().parseFiles( streams.getOut() );
285         }
286         catch ( CommandExecutionException e )
287         {
288             if ( e.getMessage().trim().endsWith( "No such file or directory" ) )
289             {
290                 throw new ResourceDoesNotExistException( e.getMessage().trim() );
291             }
292             else if ( e.getMessage().trim().endsWith( "Not a directory" ) )
293             {
294                 throw new ResourceDoesNotExistException( e.getMessage().trim() );
295             }            
296             else
297             {
298                 throw new TransferFailedException( "Error performing file listing.", e );
299             }
300         }
301     }
302 
303     public boolean resourceExists( String resourceName, Repository repository )
304         throws TransferFailedException, AuthorizationException
305     {
306         try
307         {
308             String path = getPath( repository.getBasedir(), resourceName );
309             executor.executeCommand( "ls " + path );
310 
311             // Parsing of output not really needed.  As a failed ls results in a
312             // CommandExectionException on the 'ls' command.
313 
314             return true;
315         }
316         catch ( CommandExecutionException e )
317         {
318             // Error?  Then the 'ls' command failed.  No such file found.
319             return false;
320         }
321     }
322 
323     public void createRemoteDirectories( String path, RepositoryPermissions permissions )
324         throws CommandExecutionException
325     {
326         String umaskCmd = null;
327         if ( permissions != null )
328         {
329             String dirPerms = permissions.getDirectoryMode();
330 
331             if ( dirPerms != null )
332             {
333                 umaskCmd = "umask " + PermissionModeUtils.getUserMaskFor( dirPerms );
334             }
335         }
336 
337         String mkdirCmd = "mkdir -p " + path;
338 
339         if ( umaskCmd != null )
340         {
341             mkdirCmd = umaskCmd + "; " + mkdirCmd;
342         }
343 
344         executor.executeCommand( mkdirCmd );
345     }
346 }