1 package org.apache.maven.wagon.providers.scm;
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.scm.ScmException;
23 import org.apache.maven.scm.ScmFile;
24 import org.apache.maven.scm.ScmFileSet;
25 import org.apache.maven.scm.ScmResult;
26 import org.apache.maven.scm.ScmVersion;
27 import org.apache.maven.scm.command.add.AddScmResult;
28 import org.apache.maven.scm.command.checkout.CheckOutScmResult;
29 import org.apache.maven.scm.command.list.ListScmResult;
30 import org.apache.maven.scm.manager.NoSuchScmProviderException;
31 import org.apache.maven.scm.manager.ScmManager;
32 import org.apache.maven.scm.provider.ScmProvider;
33 import org.apache.maven.scm.provider.ScmProviderRepository;
34 import org.apache.maven.scm.provider.ScmProviderRepositoryWithHost;
35 import org.apache.maven.scm.repository.ScmRepository;
36 import org.apache.maven.scm.repository.ScmRepositoryException;
37 import org.apache.maven.wagon.AbstractWagon;
38 import org.apache.maven.wagon.ConnectionException;
39 import org.apache.maven.wagon.ResourceDoesNotExistException;
40 import org.apache.maven.wagon.TransferFailedException;
41 import org.apache.maven.wagon.authorization.AuthorizationException;
42 import org.apache.maven.wagon.events.TransferEvent;
43 import org.apache.maven.wagon.resource.Resource;
44 import org.codehaus.plexus.util.FileUtils;
45 import org.codehaus.plexus.util.StringUtils;
46
47 import java.io.File;
48 import java.io.IOException;
49 import java.text.DecimalFormat;
50 import java.util.ArrayList;
51 import java.util.Iterator;
52 import java.util.List;
53 import java.util.Random;
54 import java.util.Stack;
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 public class ScmWagon
74 extends AbstractWagon
75 {
76
77
78
79 private ScmManager scmManager;
80
81 private File checkoutDirectory;
82
83
84
85
86
87
88 public ScmManager getScmManager()
89 {
90 return scmManager;
91 }
92
93
94
95
96
97
98 public void setScmManager( ScmManager scmManager )
99 {
100 this.scmManager = scmManager;
101 }
102
103
104
105
106
107
108 public File getCheckoutDirectory()
109 {
110 return checkoutDirectory;
111 }
112
113
114
115
116
117
118 public void setCheckoutDirectory( File checkoutDirectory )
119 {
120 this.checkoutDirectory = checkoutDirectory;
121 }
122
123
124
125
126
127
128
129
130 public ScmProvider getScmProvider( String scmType )
131 throws NoSuchScmProviderException
132 {
133 return getScmManager().getProviderByType( scmType );
134 }
135
136
137
138
139 public void openConnectionInternal()
140 throws ConnectionException
141 {
142 if ( checkoutDirectory == null )
143 {
144 checkoutDirectory = createCheckoutDirectory();
145 }
146
147 if ( checkoutDirectory.exists() )
148 {
149 removeCheckoutDirectory();
150 }
151
152 checkoutDirectory.mkdirs();
153 }
154
155 private File createCheckoutDirectory()
156 {
157 File checkoutDirectory;
158
159 DecimalFormat fmt = new DecimalFormat( "#####" );
160
161 Random rand = new Random( System.currentTimeMillis() + Runtime.getRuntime().freeMemory() );
162
163 synchronized ( rand )
164 {
165 do
166 {
167 checkoutDirectory = new File( System.getProperty( "java.io.tmpdir" ),
168 "wagon-scm" + fmt.format( Math.abs( rand.nextInt() ) ) + ".checkout" );
169 }
170 while ( checkoutDirectory.exists() );
171 }
172
173 return checkoutDirectory;
174 }
175
176
177 private void removeCheckoutDirectory()
178 throws ConnectionException
179 {
180 if( checkoutDirectory == null )
181 {
182 return;
183 }
184
185 try
186 {
187 FileUtils.deleteDirectory( checkoutDirectory );
188 }
189 catch ( IOException e )
190 {
191 throw new ConnectionException( "Unable to cleanup checkout directory", e );
192 }
193 }
194
195 private ScmRepository getScmRepository( String url )
196 throws ScmRepositoryException, NoSuchScmProviderException
197 {
198 String username = null;
199
200 String password = null;
201
202 String privateKey = null;
203
204 String passphrase = null;
205
206 if ( authenticationInfo != null )
207 {
208 username = authenticationInfo.getUserName();
209
210 password = authenticationInfo.getPassword();
211
212 privateKey = authenticationInfo.getPrivateKey();
213
214 passphrase = authenticationInfo.getPassphrase();
215 }
216
217 ScmRepository scmRepository = getScmManager().makeScmRepository( url );
218
219 ScmProviderRepository providerRepository = scmRepository.getProviderRepository();
220
221 if ( StringUtils.isNotEmpty( username ) )
222 {
223 providerRepository.setUser( username );
224 }
225
226 if ( StringUtils.isNotEmpty( password ) )
227 {
228 providerRepository.setPassword( password );
229 }
230
231 if ( providerRepository instanceof ScmProviderRepositoryWithHost )
232 {
233 ScmProviderRepositoryWithHost providerRepo = (ScmProviderRepositoryWithHost) providerRepository;
234
235 if ( StringUtils.isNotEmpty( privateKey ) )
236 {
237 providerRepo.setPrivateKey( privateKey );
238 }
239
240 if ( StringUtils.isNotEmpty( passphrase ) )
241 {
242 providerRepo.setPassphrase( passphrase );
243 }
244 }
245
246 return scmRepository;
247 }
248
249 public void put( File source, String targetName )
250 throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
251 {
252 if ( source.isDirectory() )
253 {
254 throw new IllegalArgumentException( "Source is a directory: " + source );
255 }
256 putInternal( source, targetName );
257 }
258
259
260
261
262
263
264
265
266 private void putInternal( File source, String targetName )
267 throws TransferFailedException
268 {
269 Resource target = new Resource( targetName );
270
271 firePutInitiated( target, source );
272
273 try
274 {
275 ScmRepository scmRepository = getScmRepository( getRepository().getUrl() );
276
277 target.setContentLength( source.length() );
278 target.setLastModified( source.lastModified() );
279
280 firePutStarted( target, source );
281
282 String msg = "Wagon: Adding " + source.getName() + " to repository";
283
284 ScmProvider scmProvider = getScmProvider( scmRepository.getProvider() );
285
286 String checkoutTargetName = source.isDirectory() ? targetName : getDirname( targetName );
287 String relPath = checkOut( scmProvider, scmRepository, checkoutTargetName, target );
288
289 File newCheckoutDirectory = new File( checkoutDirectory, relPath );
290
291 File scmFile =
292 new File( newCheckoutDirectory, source.isDirectory() ? "" : getFilename( targetName ) );
293
294 boolean fileAlreadyInScm = scmFile.exists();
295
296 if ( !scmFile.equals( source ) )
297 {
298 if ( source.isDirectory() )
299 {
300 FileUtils.copyDirectoryStructure( source, scmFile );
301 }
302 else
303 {
304 FileUtils.copyFile( source, scmFile );
305 }
306 }
307
308 if ( !fileAlreadyInScm || scmFile.isDirectory() )
309 {
310 int addedFiles = addFiles( scmProvider, scmRepository, newCheckoutDirectory,
311 source.isDirectory() ? "" : scmFile.getName() );
312
313 if ( !fileAlreadyInScm && addedFiles == 0 )
314 {
315 throw new ScmException(
316 "Unable to add file to SCM: " + scmFile + "; see error messages above for more information" );
317 }
318 }
319
320 ScmResult result = scmProvider.checkIn( scmRepository, new ScmFileSet( checkoutDirectory ),
321 (ScmVersion) null, msg );
322
323 checkScmResult( result );
324 }
325 catch ( ScmException e )
326 {
327 fireTransferError( target, e, TransferEvent.REQUEST_GET );
328
329 throw new TransferFailedException( "Error interacting with SCM: " + e.getMessage(), e );
330 }
331 catch ( IOException e )
332 {
333 fireTransferError( target, e, TransferEvent.REQUEST_GET );
334
335 throw new TransferFailedException( "Error interacting with SCM: " + e.getMessage(), e );
336 }
337
338 if ( source.isFile() )
339 {
340 postProcessListeners( target, source, TransferEvent.REQUEST_PUT );
341 }
342
343 firePutCompleted( target, source );
344 }
345
346
347
348
349
350
351
352
353
354
355
356 private String checkOut( ScmProvider scmProvider, ScmRepository scmRepository, String targetName,
357 Resource resource )
358 throws TransferFailedException
359 {
360 checkoutDirectory = createCheckoutDirectory();
361
362 Stack stack = new Stack();
363
364 String target = targetName;
365
366
367
368
369
370
371 try
372 {
373 while ( target.length() > 0 && !scmProvider
374 .list( scmRepository, new ScmFileSet( new File( "." ), new File( target ) ), false, (ScmVersion) null )
375 .isSuccess() )
376 {
377 stack.push( getFilename( target ) );
378 target = getDirname( target );
379 }
380 }
381 catch ( ScmException e )
382 {
383 fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
384
385 throw new TransferFailedException( "Error listing repository: " + e.getMessage(), e );
386 }
387
388
389
390
391
392
393 try
394 {
395 scmRepository = getScmRepository( getRepository().getUrl() + "/" + target.replace( '\\', '/' ) );
396
397 CheckOutScmResult ret = scmProvider.checkOut( scmRepository,
398 new ScmFileSet( new File( checkoutDirectory, "" ) ),
399 (ScmVersion) null, false );
400
401 checkScmResult( ret );
402 }
403 catch ( ScmException e )
404 {
405 fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
406
407 throw new TransferFailedException( "Error checking out: " + e.getMessage(), e );
408 }
409
410
411
412 String relPath = "";
413
414 while ( !stack.isEmpty() )
415 {
416 String p = (String) stack.pop();
417 relPath += p + "/";
418
419 File newDir = new File( checkoutDirectory, relPath );
420 if ( !newDir.mkdirs() )
421 {
422 throw new TransferFailedException( "Failed to create directory " + newDir.getAbsolutePath()
423 + "; parent should exist: " + checkoutDirectory );
424 }
425
426 try
427 {
428 addFiles( scmProvider, scmRepository, checkoutDirectory, relPath );
429 }
430 catch ( ScmException e )
431 {
432 fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
433
434 throw new TransferFailedException( "Failed to add directory " + newDir + " to working copy", e );
435 }
436 }
437
438 return relPath;
439 }
440
441
442
443
444
445
446
447
448
449
450
451
452
453 private int addFiles( ScmProvider scmProvider, ScmRepository scmRepository, File basedir, String scmFilePath )
454 throws ScmException
455 {
456 int addedFiles = 0;
457
458 File scmFile = new File( basedir, scmFilePath );
459
460 if ( scmFilePath.length() != 0 )
461 {
462 AddScmResult result = scmProvider.add( scmRepository, new ScmFileSet( basedir, new File( scmFilePath ) ) );
463
464
465
466
467
468
469 if ( !result.isSuccess() )
470 {
471 result = scmProvider.add( scmRepository, new ScmFileSet( basedir, new File( scmFilePath ) ) );
472 }
473
474 addedFiles = result.getAddedFiles().size();
475 }
476
477 String reservedScmFile = scmProvider.getScmSpecificFilename();
478
479 if ( scmFile.isDirectory() )
480 {
481 File[] files = scmFile.listFiles();
482
483 for ( int i = 0; i < files.length; i++ )
484 {
485 if ( reservedScmFile != null && !reservedScmFile.equals( files[i].getName() ) )
486 {
487 addedFiles += addFiles( scmProvider, scmRepository, basedir, ( scmFilePath.length() == 0 ? ""
488 : scmFilePath + "/" ) + files[i].getName() );
489 }
490 }
491 }
492
493 return addedFiles;
494 }
495
496
497
498
499 public boolean supportsDirectoryCopy()
500 {
501 return true;
502 }
503
504 public void putDirectory( File sourceDirectory, String destinationDirectory )
505 throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
506 {
507 if ( !sourceDirectory.isDirectory() )
508 {
509 throw new IllegalArgumentException( "Source is not a directory: " + sourceDirectory );
510 }
511
512 putInternal( sourceDirectory, destinationDirectory );
513 }
514
515
516
517
518
519
520
521
522 private void checkScmResult( ScmResult result )
523 throws ScmException
524 {
525 if ( !result.isSuccess() )
526 {
527 throw new ScmException( "Unable to commit file. " + result.getProviderMessage() + " "
528 + ( result.getCommandOutput() == null ? "" : result.getCommandOutput() ) );
529 }
530 }
531
532 public void closeConnection()
533 throws ConnectionException
534 {
535 removeCheckoutDirectory();
536 }
537
538
539
540
541
542
543 public boolean getIfNewer( String resourceName, File destination, long timestamp )
544 throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
545 {
546 throw new UnsupportedOperationException( "Not currently supported: getIfNewer" );
547 }
548
549 public void get( String resourceName, File destination )
550 throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
551 {
552 Resource resource = new Resource( resourceName );
553
554 fireGetInitiated( resource, destination );
555
556 String url = getRepository().getUrl() + "/" + resourceName;
557
558
559 url = url.substring( 0, url.lastIndexOf( '/' ) );
560
561 try
562 {
563 ScmRepository scmRepository = getScmRepository( url );
564
565 fireGetStarted( resource, destination );
566
567
568
569
570
571
572
573
574 File scmFile = new File( checkoutDirectory, resourceName );
575
576 File basedir = scmFile.getParentFile();
577
578 ScmProvider scmProvider = getScmProvider( scmRepository.getProvider() );
579
580 String reservedScmFile = scmProvider.getScmSpecificFilename();
581
582 if ( reservedScmFile != null && new File( basedir, reservedScmFile ).exists() )
583 {
584 scmProvider.update( scmRepository, new ScmFileSet( basedir ), (ScmVersion) null );
585 }
586 else
587 {
588
589 basedir.mkdirs();
590
591 scmProvider.checkOut( scmRepository, new ScmFileSet( basedir ), (ScmVersion) null );
592 }
593
594 if ( !scmFile.exists() )
595 {
596 throw new ResourceDoesNotExistException( "Unable to find resource " + destination + " after checkout" );
597 }
598
599 if ( !scmFile.equals( destination ) )
600 {
601 FileUtils.copyFile( scmFile, destination );
602 }
603 }
604 catch ( ScmException e )
605 {
606 fireTransferError( resource, e, TransferEvent.REQUEST_GET );
607
608 throw new TransferFailedException( "Error getting file from SCM", e );
609 }
610 catch ( IOException e )
611 {
612 fireTransferError( resource, e, TransferEvent.REQUEST_GET );
613
614 throw new TransferFailedException( "Error getting file from SCM", e );
615 }
616
617 postProcessListeners( resource, destination, TransferEvent.REQUEST_GET );
618
619 fireGetCompleted( resource, destination );
620 }
621
622
623
624
625
626 public List getFileList( String resourcePath )
627 throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
628 {
629 try
630 {
631 ScmRepository repository = getScmRepository( getRepository().getUrl() );
632
633 ScmProvider provider = getScmProvider( repository.getProvider() );
634
635 ListScmResult result = provider.list( repository,
636 new ScmFileSet( new File( "." ), new File( resourcePath ) ), false,
637 (ScmVersion) null );
638
639 if ( !result.isSuccess() )
640 {
641 throw new ResourceDoesNotExistException( result.getProviderMessage() );
642 }
643
644
645 List files = new ArrayList();
646
647 for ( Iterator it = result.getFiles().iterator(); it.hasNext(); )
648 {
649 ScmFile f = (ScmFile) it.next();
650 files.add( f.getPath() );
651 System.out.println( "LIST FILE: " + f + " (path=" + f.getPath() + ")" );
652 }
653
654 return files;
655 }
656 catch ( ScmException e )
657 {
658 throw new TransferFailedException( "Error getting filelist from SCM", e );
659 }
660 }
661
662 public boolean resourceExists( String resourceName )
663 throws TransferFailedException, AuthorizationException
664 {
665 try
666 {
667 getFileList( resourceName );
668
669 return true;
670 }
671 catch ( ResourceDoesNotExistException e )
672 {
673 return false;
674 }
675 }
676
677 private String getFilename( String filename )
678 {
679 String fname = StringUtils.replace( filename, "/", File.separator );
680 return FileUtils.filename( fname );
681 }
682
683 private String getDirname( String filename )
684 {
685 String fname = StringUtils.replace( filename, "/", File.separator );
686 return FileUtils.dirname( fname );
687 }
688 }