View Javadoc
1   package org.apache.maven.plugins.scmpublish;
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.IOException;
24  import java.util.ArrayList;
25  import java.util.Arrays;
26  import java.util.Collection;
27  import java.util.HashSet;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.Set;
31  import java.util.TreeSet;
32  
33  import org.apache.commons.io.FileUtils;
34  import org.apache.commons.io.FilenameUtils;
35  import org.apache.commons.lang3.time.DurationFormatUtils;
36  import org.apache.maven.plugin.AbstractMojo;
37  import org.apache.maven.plugin.MojoExecutionException;
38  import org.apache.maven.plugin.MojoFailureException;
39  import org.apache.maven.plugins.annotations.Component;
40  import org.apache.maven.plugins.annotations.Parameter;
41  import org.apache.maven.scm.CommandParameter;
42  import org.apache.maven.scm.CommandParameters;
43  import org.apache.maven.scm.ScmBranch;
44  import org.apache.maven.scm.ScmException;
45  import org.apache.maven.scm.ScmFileSet;
46  import org.apache.maven.scm.ScmResult;
47  import org.apache.maven.scm.command.add.AddScmResult;
48  import org.apache.maven.scm.command.checkin.CheckInScmResult;
49  import org.apache.maven.scm.manager.NoSuchScmProviderException;
50  import org.apache.maven.scm.manager.ScmManager;
51  import org.apache.maven.scm.provider.ScmProvider;
52  import org.apache.maven.scm.provider.ScmUrlUtils;
53  import org.apache.maven.scm.provider.svn.AbstractSvnScmProvider;
54  import org.apache.maven.scm.provider.svn.repository.SvnScmProviderRepository;
55  import org.apache.maven.scm.repository.ScmRepository;
56  import org.apache.maven.scm.repository.ScmRepositoryException;
57  import org.apache.maven.settings.Server;
58  import org.apache.maven.settings.Settings;
59  import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest;
60  import org.apache.maven.settings.crypto.SettingsDecrypter;
61  import org.apache.maven.settings.crypto.SettingsDecryptionRequest;
62  import org.apache.maven.settings.crypto.SettingsDecryptionResult;
63  import org.apache.maven.shared.release.config.ReleaseDescriptor;
64  import org.apache.maven.shared.release.scm.ScmRepositoryConfigurator;
65  import org.apache.maven.shared.utils.logging.MessageUtils;
66  
67  /**
68   * Base class for the scm-publish mojos.
69   */
70  public abstract class AbstractScmPublishMojo
71      extends AbstractMojo
72  {
73      // CHECKSTYLE_OFF: LineLength
74      /**
75       * Location of the scm publication tree:
76       * <code>scm:&lt;scm_provider&gt;&lt;delimiter&gt;&lt;provider_specific_part&gt;</code>.
77       * Example:
78       * <code>scm:svn:https://svn.apache.org/repos/infra/websites/production/maven/content/plugins/maven-scm-publish-plugin-LATEST/</code>
79       */
80      // CHECKSTYLE_ON: LineLength
81      @Parameter ( property = "scmpublish.pubScmUrl", defaultValue = "${project.distributionManagement.site.url}",
82                   required = true )
83      protected String pubScmUrl;
84  
85      /**
86       * If the checkout directory exists and this flag is activated, the plugin will try an SCM-update instead
87       * of delete then checkout.
88       */
89      @Parameter ( property = "scmpublish.tryUpdate", defaultValue = "false" )
90      protected boolean tryUpdate;
91  
92      // CHECKSTYLE_OFF: LineLength
93     /**
94       * Location where the scm check-out is done. By default, scm checkout is done in build (target) directory,
95       * which is deleted on every <code>mvn clean</code>. To avoid this and get better performance, configure
96       * this location outside build structure and set <code>tryUpdate</code> to <code>true</code>.
97       * See <a href="http://maven.apache.org/plugins/maven-scm-publish-plugin/various-tips.html#Improving_SCM_Checkout_Performance">
98       * Improving SCM Checkout Performance</a> for more information.
99       */
100     // CHECKSTYLE_ON: LineLength
101     @Parameter ( property = "scmpublish.checkoutDirectory",
102                  defaultValue = "${project.build.directory}/scmpublish-checkout" )
103     protected File checkoutDirectory;
104 
105     /**
106      * Display list of added, deleted, and changed files, but do not do any actual SCM operations.
107      */
108     @Parameter ( property = "scmpublish.dryRun" )
109     private boolean dryRun;
110 
111     /**
112      * Run add and delete commands, but leave the actually checkin for the user to run manually.
113      */
114     @Parameter ( property = "scmpublish.skipCheckin" )
115     private boolean skipCheckin;
116 
117     /**
118      * SCM log/checkin comment for this publication.
119      */
120     @Parameter ( property = "scmpublish.checkinComment", defaultValue = "Site checkin for project ${project.name}" )
121     private String checkinComment;
122 
123     /**
124      * Patterns to exclude from the scm tree.
125      */
126     @Parameter
127     protected String excludes;
128 
129     /**
130      * Patterns to include in the scm tree.
131      */
132     @Parameter
133     protected String includes;
134 
135     /**
136      * List of SCM provider implementations.
137      * Key is the provider type, eg. <code>cvs</code>.
138      * Value is the provider implementation (the role-hint of the provider), eg. <code>cvs</code> or
139      * <code>cvs_native</code>.
140      * @see ScmManager.setScmProviderImplementation
141      */
142     @Parameter
143     private Map<String, String> providerImplementations;
144 
145     /**
146      * The SCM manager.
147      */
148     @Component
149     private ScmManager scmManager;
150 
151     /**
152      * Tool that gets a configured SCM repository from release configuration.
153      */
154     @Component
155     protected ScmRepositoryConfigurator scmRepositoryConfigurator;
156     
157     /**
158      * The serverId specified in the settings.xml, which should be used for the authentication.
159      */
160     @Parameter
161     private String serverId;
162 
163     /**
164      * The SCM username to use.
165      */
166     @Parameter ( property = "username" )
167     protected String username;
168 
169     /**
170      * The SCM password to use.
171      */
172     @Parameter ( property = "password" )
173     protected String password;
174 
175     /**
176      * Use a local checkout instead of doing a checkout from the upstream repository.
177      * <b>WARNING</b>: This will only work with distributed SCMs which support the file:// protocol.
178      * TODO: we should think about having the defaults for the various SCM providers provided via Modello!
179      */
180     @Parameter ( property = "localCheckout", defaultValue = "false" )
181     protected boolean localCheckout;
182 
183     /**
184      * The outputEncoding parameter of the site plugin. This plugin will corrupt your site
185      * if this does not match the value used by the site plugin.
186      */
187     @Parameter ( property = "outputEncoding", defaultValue = "${project.reporting.outputEncoding}" )
188     protected String siteOutputEncoding;
189 
190     /**
191      * Do not delete files to the scm
192      */
193     @Parameter ( property = "scmpublish.skipDeletedFiles", defaultValue = "false" )
194     protected boolean skipDeletedFiles;
195 
196     /**
197      * Add each directory in a separated SCM command: this can be necessary if SCM does not support
198      * adding subdirectories in one command.
199      */
200     @Parameter( defaultValue = "false" )
201     protected boolean addUniqueDirectory;
202 
203     /**
204      */
205     @Parameter ( defaultValue = "${basedir}", readonly = true )
206     protected File basedir;
207 
208     /**
209      */
210     @Parameter( defaultValue = "${settings}", readonly = true, required = true )
211     protected Settings settings;
212     
213     @Component
214     private SettingsDecrypter settingsDecrypter;
215  
216 
217     /**
218      * Collections of paths not to delete when checking content to delete.
219      * If your site has subdirectories published by an other mechanism/build
220      */
221     @Parameter
222     protected String[] ignorePathsToDelete;
223 
224     /**
225      * SCM branch to use. For github, you must configure with <code>gh-pages</code>.
226      */
227     @Parameter ( property = "scmpublish.scm.branch" )
228     protected String scmBranch;
229 
230     /**
231      * Configure svn automatic remote url creation.
232      */
233     @Parameter ( property = "scmpublish.automaticRemotePathCreation", defaultValue = "true" )
234     protected boolean automaticRemotePathCreation;
235 
236     /**
237      * Filename extensions of files which need new line normalization.
238      */
239     private static final String[] NORMALIZE_EXTENSIONS = { "html", "css", "js" };
240 
241     /**
242      * Extra file extensions to normalize line ending (will be added to default
243      * <code>html</code>,<code>css</code>,<code>js</code> list)
244      */
245     @Parameter
246     protected String[] extraNormalizeExtensions;
247 
248     private Set<String> normalizeExtensions;
249 
250     protected ScmProvider scmProvider;
251 
252     protected ScmRepository scmRepository;
253 
254     protected void logInfo( String format, Object... params )
255     {
256         getLog().info( String.format( format, params ) );
257     }
258 
259     protected void logWarn( String format, Object... params )
260     {
261         getLog().warn( String.format( format, params ) );
262     }
263 
264     protected void logError( String format, Object... params )
265     {
266         getLog().error( String.format( format, params ) );
267     }
268 
269     private File relativize( File base, File file )
270     {
271         return new File( base.toURI().relativize( file.toURI() ).getPath() );
272     }
273 
274     protected boolean requireNormalizeNewlines( File f )
275         throws IOException
276     {
277         if ( normalizeExtensions == null )
278         {
279             normalizeExtensions = new HashSet<String>( Arrays.asList( NORMALIZE_EXTENSIONS ) );
280             if ( extraNormalizeExtensions != null )
281             {
282                 normalizeExtensions.addAll( Arrays.asList( extraNormalizeExtensions ) );
283             }
284         }
285 
286         return FilenameUtils.isExtension( f.getName(), normalizeExtensions );
287     }
288 
289     private ReleaseDescriptor setupScm()
290         throws ScmRepositoryException, NoSuchScmProviderException
291     {
292         String scmUrl;
293         if ( localCheckout )
294         {
295             // in the release phase we have to change the checkout URL
296             // to do a local checkout instead of going over the network.
297 
298             String provider = ScmUrlUtils.getProvider( pubScmUrl );
299             String delimiter = ScmUrlUtils.getDelimiter( pubScmUrl );
300             
301             String providerPart = "scm:" + provider + delimiter;
302 
303             // X TODO: also check the information from releaseDescriptor.getScmRelativePathProjectDirectory()
304             // X TODO: in case our toplevel git directory has no pom.
305             // X TODO: fix pathname once I understand this.
306             scmUrl = providerPart + "file://" + "target/localCheckout";
307             logInfo( "Performing a LOCAL checkout from " + scmUrl );
308         }
309 
310         ReleaseDescriptor releaseDescriptor = new ReleaseDescriptor();
311         releaseDescriptor.setInteractive( settings.isInteractiveMode() );
312 
313         if ( username == null || password == null )
314         {
315             for ( Server server : settings.getServers() )
316             {
317                 if ( server.getId().equals( serverId ) )
318                 {
319                     SettingsDecryptionRequest decryptionRequest = new DefaultSettingsDecryptionRequest( server );
320 
321                     SettingsDecryptionResult decryptionResult = settingsDecrypter.decrypt( decryptionRequest );
322 
323                     if ( !decryptionResult.getProblems().isEmpty() )
324                     {
325                         // todo throw exception?
326                     }
327 
328                     if ( username == null )
329                     {
330                         username = decryptionResult.getServer().getUsername();
331                     }
332 
333                     if ( password == null )
334                     {
335                         password = decryptionResult.getServer().getPassword();
336                     }
337 
338                     break;
339                 }
340             }
341         }
342 
343         releaseDescriptor.setScmPassword( password );
344         releaseDescriptor.setScmUsername( username );
345 
346         releaseDescriptor.setWorkingDirectory( basedir.getAbsolutePath() );
347         releaseDescriptor.setLocalCheckout( localCheckout );
348         releaseDescriptor.setScmSourceUrl( pubScmUrl );
349 
350         if ( providerImplementations != null )
351         {
352             for ( Map.Entry<String, String> providerEntry : providerImplementations.entrySet() )
353             {
354                 logInfo( "Changing the default '%s' provider implementation to '%s'.", providerEntry.getKey(),
355                          providerEntry.getValue() );
356                 scmManager.setScmProviderImplementation( providerEntry.getKey(), providerEntry.getValue() );
357             }
358         }
359 
360         scmRepository = scmRepositoryConfigurator.getConfiguredRepository( releaseDescriptor, settings );
361 
362         scmProvider = scmRepositoryConfigurator.getRepositoryProvider( scmRepository );
363 
364         return releaseDescriptor;
365     }
366 
367     protected void checkoutExisting()
368         throws MojoExecutionException
369     {
370 
371         if ( scmProvider instanceof AbstractSvnScmProvider )
372         {
373             checkCreateRemoteSvnPath();
374         }
375 
376         logInfo( MessageUtils.buffer().strong( "%s" ) + " the pub tree from " + MessageUtils.buffer().strong( "%s" )
377             + " into %s", ( tryUpdate ? "Updating" : "Checking out" ), pubScmUrl, checkoutDirectory );
378 
379         if ( checkoutDirectory.exists() && !tryUpdate )
380 
381         {
382             try
383             {
384                 FileUtils.deleteDirectory( checkoutDirectory );
385             }
386             catch ( IOException e )
387             {
388                 logError( e.getMessage() );
389 
390                 throw new MojoExecutionException( "Unable to remove old checkout directory: " + e.getMessage(), e );
391             }
392         }
393 
394         boolean forceCheckout = false;
395 
396         if ( !checkoutDirectory.exists() )
397 
398         {
399             if ( tryUpdate )
400             {
401                 logInfo( "TryUpdate is configured but no local copy currently available: forcing checkout." );
402             }
403             checkoutDirectory.mkdirs();
404             forceCheckout = true;
405         }
406 
407         try
408         {
409             ScmFileSet fileSet = new ScmFileSet( checkoutDirectory, includes, excludes );
410 
411             ScmBranch branch = ( scmBranch == null ) ? null : new ScmBranch( scmBranch );
412 
413             ScmResult scmResult = null;
414             if ( tryUpdate && !forceCheckout )
415             {
416                 scmResult = scmProvider.update( scmRepository, fileSet, branch );
417             }
418             else
419             {
420                 int attempt = 0;
421                 while ( scmResult == null )
422                 {
423                     try
424                     {
425                         scmResult = scmProvider.checkOut( scmRepository, fileSet, branch );
426                     }
427                     catch ( ScmException e )
428                     {
429                         // give it max 2 times to retry
430                         if ( attempt++ < 2 )
431                         {
432                             try
433                             {
434                                 // wait 3 seconds
435                                 Thread.sleep( 3 * 1000 );
436                             }
437                             catch ( InterruptedException ie )
438                             {
439                                 // noop
440                             }
441                         }
442                         else
443                         {
444                             throw e;
445                         }
446                     }
447                 }
448             }
449             checkScmResult( scmResult, "check out from SCM" );
450         }
451         catch ( ScmException e )
452         {
453             logError( e.getMessage() );
454 
455             throw new MojoExecutionException( "An error occurred during the checkout process: " + e.getMessage(), e );
456         }
457         catch ( IOException e )
458         {
459             logError( e.getMessage() );
460 
461             throw new MojoExecutionException( "An error occurred during the checkout process: " + e.getMessage(), e );
462         }
463     }
464 
465     private void checkCreateRemoteSvnPath()
466         throws MojoExecutionException
467     {
468         getLog().debug( "AbstractSvnScmProvider used, so we can check if remote url exists and eventually create it." );
469         AbstractSvnScmProvider svnScmProvider = (AbstractSvnScmProvider) scmProvider;
470 
471         try
472         {
473             boolean remoteExists = svnScmProvider.remoteUrlExist( scmRepository.getProviderRepository(), null );
474 
475             if ( remoteExists )
476             {
477                 return;
478             }
479         }
480         catch ( ScmException e )
481         {
482             throw new MojoExecutionException( e.getMessage(), e );
483         }
484 
485         String remoteUrl = ( (SvnScmProviderRepository) scmRepository.getProviderRepository() ).getUrl();
486 
487         if ( !automaticRemotePathCreation )
488         {
489             // olamy: return ?? that will fail during checkout IMHO :-)
490             logWarn( "Remote svn url %s does not exist and automatic remote path creation disabled.",
491                      remoteUrl );
492             return;
493         }
494 
495         logInfo( "Remote svn url %s does not exist: creating.", remoteUrl );
496 
497         File baseDir = null;
498         try
499         {
500 
501             // create a temporary directory for svnexec
502             baseDir = File.createTempFile( "scm", "tmp" );
503             baseDir.delete();
504             baseDir.mkdirs();
505             // to prevent fileSet cannot be empty
506             ScmFileSet scmFileSet = new ScmFileSet( baseDir, new File( "" ) );
507 
508             CommandParameters commandParameters = new CommandParameters();
509             commandParameters.setString( CommandParameter.SCM_MKDIR_CREATE_IN_LOCAL, Boolean.FALSE.toString() );
510             commandParameters.setString( CommandParameter.MESSAGE, "Automatic svn path creation: " + remoteUrl );
511             svnScmProvider.mkdir( scmRepository.getProviderRepository(), scmFileSet, commandParameters );
512 
513             // new remote url so force checkout!
514             if ( checkoutDirectory.exists() )
515             {
516                 FileUtils.deleteDirectory( checkoutDirectory );
517             }
518         }
519         catch ( IOException e )
520         {
521             throw new MojoExecutionException( e.getMessage(), e );
522         }
523         catch ( ScmException e )
524         {
525             throw new MojoExecutionException( e.getMessage(), e );
526         }
527         finally
528         {
529             if ( baseDir != null )
530             {
531                 try
532                 {
533                     FileUtils.forceDeleteOnExit( baseDir );
534                 }
535                 catch ( IOException e )
536                 {
537                     throw new MojoExecutionException( e.getMessage(), e );
538                 }
539             }
540         }
541     }
542 
543     public void execute()
544         throws MojoExecutionException, MojoFailureException
545     {
546         // setup the scm plugin with help from release plugin utilities
547         try
548         {
549             setupScm();
550         }
551         catch ( ScmRepositoryException e )
552         {
553             throw new MojoExecutionException( e.getMessage(), e );
554         }
555         catch ( NoSuchScmProviderException e )
556         {
557             throw new MojoExecutionException( e.getMessage(), e );
558         }
559 
560         boolean tmpCheckout = false;
561 
562         if ( checkoutDirectory.getPath().contains( "${project." ) )
563         {
564             try
565             {
566                 tmpCheckout = true;
567                 checkoutDirectory = File.createTempFile( "maven-scm-publish", ".checkout" );
568                 checkoutDirectory.delete();
569                 checkoutDirectory.mkdir();
570             }
571             catch ( IOException ioe )
572             {
573                 throw new MojoExecutionException( ioe.getMessage(), ioe );
574             }
575         }
576 
577         try
578         {
579             scmPublishExecute();
580         }
581         finally
582         {
583             if ( tmpCheckout )
584             {
585                 FileUtils.deleteQuietly( checkoutDirectory );
586             }
587         }
588     }
589 
590     /**
591      * Check-in content from scm checkout.
592      *
593      * @throws MojoExecutionException
594      */
595     protected void checkinFiles()
596         throws MojoExecutionException
597     {
598         if ( skipCheckin )
599         {
600             return;
601         }
602 
603         ScmFileSet updatedFileSet = new ScmFileSet( checkoutDirectory );
604         try
605         {
606             long start = System.currentTimeMillis();
607 
608             CheckInScmResult checkinResult =
609                 checkScmResult( scmProvider.checkIn( scmRepository, updatedFileSet, new ScmBranch( scmBranch ),
610                                                      checkinComment ), "check-in files to SCM" );
611 
612             logInfo( "Checked in %d file(s) to revision %s in %s", checkinResult.getCheckedInFiles().size(),
613                      checkinResult.getScmRevision(),
614                      DurationFormatUtils.formatPeriod( start, System.currentTimeMillis(), "H' h 'm' m 's' s'" ) );
615         }
616         catch ( ScmException e )
617         {
618             throw new MojoExecutionException( "Failed to perform SCM checkin", e );
619         }
620     }
621 
622     protected void deleteFiles( Collection<File> deleted )
623         throws MojoExecutionException
624     {
625         if ( skipDeletedFiles )
626         {
627             logInfo( "Deleting files is skipped." );
628             return;
629         }
630         List<File> deletedList = new ArrayList<File>();
631         for ( File f : deleted )
632         {
633             deletedList.add( relativize( checkoutDirectory, f ) );
634         }
635         ScmFileSet deletedFileSet = new ScmFileSet( checkoutDirectory, deletedList );
636         try
637         {
638             getLog().info( "Deleting files: " + deletedList );
639 
640             checkScmResult( scmProvider.remove( scmRepository, deletedFileSet, "Deleting obsolete site files." ),
641                             "delete files from SCM" );
642         }
643         catch ( ScmException e )
644         {
645             throw new MojoExecutionException( "Failed to delete removed files to SCM", e );
646         }
647     }
648 
649     /**
650      * Add files to scm.
651      *
652      * @param added files to be added
653      * @throws MojoFailureException
654      * @throws MojoExecutionException
655      */
656     protected void addFiles( Collection<File> added )
657         throws MojoFailureException, MojoExecutionException
658     {
659         List<File> addedList = new ArrayList<File>();
660         Set<File> createdDirs = new HashSet<File>();
661         Set<File> dirsToAdd = new TreeSet<File>();
662 
663         createdDirs.add( relativize( checkoutDirectory, checkoutDirectory ) );
664 
665         for ( File f : added )
666         {
667             for ( File dir = f.getParentFile(); !dir.equals( checkoutDirectory ); dir = dir.getParentFile() )
668             {
669                 File relativized = relativize( checkoutDirectory, dir );
670                 //  we do the best we can with the directories
671                 if ( createdDirs.add( relativized ) )
672                 {
673                     dirsToAdd.add( relativized );
674                 }
675                 else
676                 {
677                     break;
678                 }
679             }
680             addedList.add( relativize( checkoutDirectory, f ) );
681         }
682 
683         if ( addUniqueDirectory )
684         { // add one directory at a time
685             for ( File relativized : dirsToAdd )
686             {
687                 try
688                 {
689                     ScmFileSet fileSet = new ScmFileSet( checkoutDirectory, relativized );
690                     getLog().info( "scm add directory: " + relativized );
691                     AddScmResult addDirResult = scmProvider.add( scmRepository, fileSet, "Adding directory" );
692                     if ( !addDirResult.isSuccess() )
693                     {
694                         getLog().warn( " Error adding directory " + relativized + ": "
695                                            + addDirResult.getCommandOutput() );
696                     }
697                 }
698                 catch ( ScmException e )
699                 {
700                     //
701                 }
702             }
703         }
704         else
705         { // add all directories in one command
706             try
707             {
708                 List<File> dirs = new ArrayList<File>( dirsToAdd );
709                 ScmFileSet fileSet = new ScmFileSet( checkoutDirectory, dirs );
710                 getLog().info( "scm add directories: " + dirs );
711                 AddScmResult addDirResult = scmProvider.add( scmRepository, fileSet, "Adding directories" );
712                 if ( !addDirResult.isSuccess() )
713                 {
714                     getLog().warn( " Error adding directories " + dirs + ": " + addDirResult.getCommandOutput() );
715                 }
716             }
717             catch ( ScmException e )
718             {
719                 //
720             }
721         }
722 
723         // remove directories already added !
724         addedList.removeAll( dirsToAdd );
725 
726         ScmFileSet addedFileSet = new ScmFileSet( checkoutDirectory, addedList );
727         getLog().info( "scm add files: " + addedList );
728         try
729         {
730                 CommandParameters commandParameters = new CommandParameters();
731                 commandParameters.setString( CommandParameter.MESSAGE, "Adding new site files." );
732                 commandParameters.setString( CommandParameter.FORCE_ADD, Boolean.TRUE.toString() );
733                 checkScmResult( scmProvider.add( scmRepository, addedFileSet, commandParameters ),
734                                 "add new files to SCM" );
735         }
736         catch ( ScmException e )
737         {
738             throw new MojoExecutionException( "Failed to add new files to SCM", e );
739         }
740     }
741 
742     private <T extends ScmResult> T checkScmResult( T result, String failure )
743         throws MojoExecutionException
744     {
745         if ( !result.isSuccess() )
746         {
747             String msg = "Failed to " + failure + ": " + result.getProviderMessage() + " " + result.getCommandOutput();
748             logError( msg );
749             throw new MojoExecutionException( msg );
750         }
751         return result;
752     }
753 
754     public boolean isDryRun()
755     {
756         return dryRun;
757     }
758 
759     public abstract void scmPublishExecute()
760         throws MojoExecutionException, MojoFailureException;
761 
762     public void setPubScmUrl( String pubScmUrl )
763     {
764         // Fix required for Windows, which fit other OS as well
765         if ( pubScmUrl.startsWith( "scm:svn:" ) )
766         {
767             pubScmUrl = pubScmUrl.replaceFirst( "file:/[/]*", "file:///" );
768         }
769 
770         this.pubScmUrl = pubScmUrl;
771     }
772 
773 }