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