1 package org.apache.maven.wagon.providers.ssh;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
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
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
254
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
264 executor.executeCommand( "chgrp -Rf " + permissions.getGroup() + " \"" + path + "\"" );
265 }
266
267 if ( permissions != null && permissions.getFileMode() != null )
268 {
269
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
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
319 executor.executeCommand( "ls \"" + path + "\"" );
320
321
322
323
324 return true;
325 }
326 catch ( CommandExecutionException e )
327 {
328
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
348 String mkdirCmd = "mkdir -p \"" + path + "\"";
349
350 if ( umaskCmd != null )
351 {
352 mkdirCmd = umaskCmd + "; " + mkdirCmd;
353 }
354
355 executor.executeCommand( mkdirCmd );
356 }
357 }