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 org.apache.maven.wagon.CommandExecutionException;
23  import org.apache.maven.wagon.CommandExecutor;
24  import org.apache.maven.wagon.PathUtils;
25  import org.apache.maven.wagon.PermissionModeUtils;
26  import org.apache.maven.wagon.ResourceDoesNotExistException;
27  import org.apache.maven.wagon.Streams;
28  import org.apache.maven.wagon.TransferFailedException;
29  import org.apache.maven.wagon.Wagon;
30  import org.apache.maven.wagon.authentication.AuthenticationInfo;
31  import org.apache.maven.wagon.authorization.AuthorizationException;
32  import org.apache.maven.wagon.repository.Repository;
33  import org.apache.maven.wagon.repository.RepositoryPermissions;
34  import org.apache.maven.wagon.resource.Resource;
35  import org.codehaus.plexus.util.FileUtils;
36  import org.codehaus.plexus.util.IOUtil;
37  import org.codehaus.plexus.util.StringUtils;
38  
39  import java.io.File;
40  import java.io.FileInputStream;
41  import java.io.FileNotFoundException;
42  import java.io.FileOutputStream;
43  import java.io.IOException;
44  import java.util.List;
45  import java.util.zip.ZipEntry;
46  import java.util.zip.ZipOutputStream;
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<String> files, File zipName, File basedir )
144         throws IOException
145     {
146         ZipOutputStream zos = new ZipOutputStream( new FileOutputStream( zipName ) );
147 
148         try
149         {
150             for ( String file : files )
151             {
152                 file = file.replace( '\\', '/' );
153 
154                 writeZipEntry( zos, new File( basedir, file ), file );
155             }
156         }
157         finally
158         {
159             IOUtil.close( zos );
160         }
161     }
162 
163     private static void writeZipEntry( ZipOutputStream jar, File source, String entryName )
164         throws IOException
165     {
166         byte[] buffer = new byte[1024];
167 
168         int bytesRead;
169 
170         FileInputStream is = new FileInputStream( source );
171 
172         try
173         {
174             ZipEntry entry = new ZipEntry( entryName );
175 
176             jar.putNextEntry( entry );
177 
178             while ( ( bytesRead = is.read( buffer ) ) != -1 )
179             {
180                 jar.write( buffer, 0, bytesRead );
181             }
182         }
183         finally
184         {
185             is.close();
186         }
187     }
188 
189     protected static String getPath( String basedir, String dir )
190     {
191         String path;
192         path = basedir;
193         if ( !basedir.endsWith( "/" ) && !dir.startsWith( "/" ) )
194         {
195             path += "/";
196         }
197         path += dir;
198         return path;
199     }
200 
201     public void putDirectory( Wagon wagon, File sourceDirectory, String destinationDirectory )
202         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
203     {
204         Repository repository = wagon.getRepository();
205 
206         String basedir = repository.getBasedir();
207 
208         String destDir = StringUtils.replace( destinationDirectory, "\\", "/" );
209 
210         String path = getPath( basedir, destDir );
211         try
212         {
213             if ( repository.getPermissions() != null )
214             {
215                 String dirPerms = repository.getPermissions().getDirectoryMode();
216 
217                 if ( dirPerms != null )
218                 {
219                     String umaskCmd = "umask " + PermissionModeUtils.getUserMaskFor( dirPerms );
220                     executor.executeCommand( umaskCmd );
221                 }
222             }
223 
224             //String mkdirCmd = "mkdir -p " + path;
225             String mkdirCmd = "mkdir -p \"" + path + "\"";
226 
227             executor.executeCommand( mkdirCmd );
228         }
229         catch ( CommandExecutionException e )
230         {
231             throw new TransferFailedException( "Error performing commands for file transfer", e );
232         }
233 
234         File zipFile;
235         try
236         {
237             zipFile = File.createTempFile( "wagon", ".zip" );
238             zipFile.deleteOnExit();
239 
240             List<String> files = FileUtils.getFileNames( sourceDirectory, "**/**", "", false );
241 
242             createZip( files, zipFile, sourceDirectory );
243         }
244         catch ( IOException e )
245         {
246             throw new TransferFailedException( "Unable to create ZIP archive of directory", e );
247         }
248 
249         wagon.put( zipFile, getPath( destDir, zipFile.getName() ) );
250 
251         try
252         {
253             //executor.executeCommand(
254             //    "cd " + path + "; unzip -q -o " + zipFile.getName() + "; rm -f " + zipFile.getName() );
255             executor.executeCommand( "cd \"" + path + "\"; unzip -q -o \"" + zipFile.getName() + "\"; rm -f \"" + zipFile.getName() + "\"" );
256 
257             zipFile.delete();
258 
259             RepositoryPermissions permissions = repository.getPermissions();
260 
261             if ( permissions != null && permissions.getGroup() != null )
262             {
263                 //executor.executeCommand( "chgrp -Rf " + permissions.getGroup() + " " + path );
264                 executor.executeCommand( "chgrp -Rf " + permissions.getGroup() + " \"" + path + "\"" );
265             }
266 
267             if ( permissions != null && permissions.getFileMode() != null )
268             {
269                 //executor.executeCommand( "chmod -Rf " + permissions.getFileMode() + " " + path );
270                 executor.executeCommand( "chmod -Rf " + permissions.getFileMode() + " \"" + path + "\"" );
271             }
272         }
273         catch ( CommandExecutionException e )
274         {
275             throw new TransferFailedException( "Error performing commands for file transfer", e );
276         }
277     }
278 
279     public List<String> getFileList( String destinationDirectory, Repository repository )
280         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
281     {
282         try
283         {
284             String path = getPath( repository.getBasedir(), destinationDirectory );
285             //Streams streams = executor.executeCommand( "ls -FlA " + path, false );
286             Streams streams = executor.executeCommand( "ls -FlA \"" + path + "\"", false );
287 
288             List<String> ret = new LSParser().parseFiles( streams.getOut() );
289             if ( ret == null || ret.isEmpty() )
290             {
291                 throw new ResourceDoesNotExistException( "No such file or directory" );
292             }
293             return ret;
294         }
295         catch ( CommandExecutionException e )
296         {
297             if ( e.getMessage().trim().endsWith( "No such file or directory" ) )
298             {
299                 throw new ResourceDoesNotExistException( e.getMessage().trim(), e );
300             }
301             else if ( e.getMessage().trim().endsWith( "Not a directory" ) )
302             {
303                 throw new ResourceDoesNotExistException( e.getMessage().trim(), e );
304             }
305             else
306             {
307                 throw new TransferFailedException( "Error performing file listing.", e );
308             }
309         }
310     }
311 
312     public boolean resourceExists( String resourceName, Repository repository )
313         throws TransferFailedException, AuthorizationException
314     {
315         try
316         {
317             String path = getPath( repository.getBasedir(), resourceName );
318             //executor.executeCommand( "ls " + path, false );
319             executor.executeCommand( "ls \"" + path + "\"" );
320 
321             // Parsing of output not really needed.  As a failed ls results in a
322             // CommandExectionException on the 'ls' command.
323 
324             return true;
325         }
326         catch ( CommandExecutionException e )
327         {
328             // Error?  Then the 'ls' command failed.  No such file found.
329             return false;
330         }
331     }
332 
333     public void createRemoteDirectories( String path, RepositoryPermissions permissions )
334         throws CommandExecutionException
335     {
336         String umaskCmd = null;
337         if ( permissions != null )
338         {
339             String dirPerms = permissions.getDirectoryMode();
340 
341             if ( dirPerms != null )
342             {
343                 umaskCmd = "umask " + PermissionModeUtils.getUserMaskFor( dirPerms );
344             }
345         }
346 
347         //String mkdirCmd = "mkdir -p " + path;
348         String mkdirCmd = "mkdir -p \"" + path + "\"";
349 
350         if ( umaskCmd != null )
351         {
352             mkdirCmd = umaskCmd + "; " + mkdirCmd;
353         }
354 
355         executor.executeCommand( mkdirCmd );
356     }
357 }