001 package org.apache.maven.scm.plugin; 002 003 /* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022 import java.io.File; 023 import java.io.IOException; 024 import java.util.ArrayList; 025 import java.util.Iterator; 026 import java.util.List; 027 import java.util.Map; 028 import java.util.Map.Entry; 029 import java.util.Properties; 030 031 import org.apache.maven.plugin.AbstractMojo; 032 import org.apache.maven.plugin.MojoExecutionException; 033 import org.apache.maven.scm.ScmBranch; 034 import org.apache.maven.scm.ScmException; 035 import org.apache.maven.scm.ScmFileSet; 036 import org.apache.maven.scm.ScmResult; 037 import org.apache.maven.scm.ScmRevision; 038 import org.apache.maven.scm.ScmTag; 039 import org.apache.maven.scm.ScmVersion; 040 import org.apache.maven.scm.manager.ScmManager; 041 import org.apache.maven.scm.provider.ScmProviderRepository; 042 import org.apache.maven.scm.provider.ScmProviderRepositoryWithHost; 043 import org.apache.maven.scm.provider.svn.repository.SvnScmProviderRepository; 044 import org.apache.maven.scm.repository.ScmRepository; 045 import org.apache.maven.scm.repository.ScmRepositoryException; 046 import org.apache.maven.settings.Server; 047 import org.apache.maven.settings.Settings; 048 import org.apache.maven.shared.model.fileset.FileSet; 049 import org.apache.maven.shared.model.fileset.util.FileSetManager; 050 import org.codehaus.plexus.util.StringUtils; 051 import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher; 052 import org.sonatype.plexus.components.sec.dispatcher.SecDispatcherException; 053 054 /** 055 * @author <a href="evenisse@apache.org">Emmanuel Venisse</a> 056 * @author Olivier Lamy 057 * @version $Id: AbstractScmMojo.java 1069361 2011-02-10 12:38:18Z bentmann $ 058 */ 059 public abstract class AbstractScmMojo 060 extends AbstractMojo 061 { 062 /** 063 * The SCM connection URL. 064 * 065 * @parameter expression="${connectionUrl}" default-value="${project.scm.connection}" 066 */ 067 private String connectionUrl; 068 069 /** 070 * The SCM connection URL for developers. 071 * 072 * @parameter expression="${connectionUrl}" default-value="${project.scm.developerConnection}" 073 */ 074 private String developerConnectionUrl; 075 076 /** 077 * The type of connection to use (connection or developerConnection). 078 * 079 * @parameter expression="${connectionType}" default-value="connection" 080 */ 081 private String connectionType; 082 083 /** 084 * The working directory. 085 * 086 * @parameter expression="${workingDirectory}" 087 */ 088 private File workingDirectory; 089 090 /** 091 * The user name (used by svn, starteam and perforce protocol). 092 * 093 * @parameter expression="${username}" 094 */ 095 private String username; 096 097 /** 098 * The user password (used by svn, starteam and perforce protocol). 099 * 100 * @parameter expression="${password}" 101 */ 102 private String password; 103 104 /** 105 * The private key (used by java svn). 106 * 107 * @parameter expression="${privateKey}" 108 */ 109 private String privateKey; 110 111 /** 112 * The passphrase (used by java svn). 113 * 114 * @parameter expression="${passphrase}" 115 */ 116 private String passphrase; 117 118 /** 119 * The url of tags base directory (used by svn protocol). It is not 120 * necessary to set it if you use the standard svn layout 121 * (branches/tags/trunk). 122 * 123 * @parameter expression="${tagBase}" 124 */ 125 private String tagBase; 126 127 /** 128 * Comma separated list of includes file pattern. 129 * 130 * @parameter expression="${includes}" 131 */ 132 private String includes; 133 134 /** 135 * Comma separated list of excludes file pattern. 136 * 137 * @parameter expression="${excludes}" 138 */ 139 private String excludes; 140 141 /** 142 * @component 143 */ 144 private ScmManager manager; 145 146 /** 147 * When this plugin requires Maven 3.0 as minimum, this component can be removed and o.a.m.s.c.SettingsDecrypter be 148 * used instead. 149 * 150 * @component roleHint="mng-4384" 151 */ 152 private SecDispatcher secDispatcher; 153 154 /** 155 * The base directory. 156 * 157 * @parameter expression="${basedir}" 158 * @required 159 */ 160 private File basedir; 161 162 /** 163 * @parameter default-value="${settings}" 164 * @required 165 * @readonly 166 */ 167 private Settings settings; 168 169 /** 170 * List of System properties to pass to the JUnit tests. 171 * 172 * @parameter 173 */ 174 private Properties systemProperties; 175 176 /** 177 * List of provider implementations. 178 * 179 * @parameter 180 */ 181 private Map<String,String> providerImplementations; 182 183 /** 184 * Should distributed changes be pushed to the central repository? 185 * For many distributed SCMs like Git, a change like a commit 186 * is only stored in your local copy of the repository. Pushing 187 * the change allows your to more easily share it with other users. 188 * 189 * @parameter expression="${pushChanges}" default-value="true" 190 * @since 1.4 191 */ 192 private boolean pushChanges; 193 194 /** {@inheritDoc} */ 195 public void execute() 196 throws MojoExecutionException 197 { 198 if ( systemProperties != null ) 199 { 200 // Add all system properties configured by the user 201 Iterator<Object> iter = systemProperties.keySet().iterator(); 202 203 while ( iter.hasNext() ) 204 { 205 String key = (String) iter.next(); 206 207 String value = systemProperties.getProperty( key ); 208 209 System.setProperty( key, value ); 210 } 211 } 212 213 if ( providerImplementations != null && !providerImplementations.isEmpty() ) 214 { 215 for ( Entry<String,String> entry : providerImplementations.entrySet() ) 216 { 217 String providerType = entry.getKey(); 218 String providerImplementation = entry.getValue(); 219 getLog().info( 220 "Change the default '" + providerType + "' provider implementation to '" 221 + providerImplementation + "'." ); 222 getScmManager().setScmProviderImplementation( providerType, providerImplementation ); 223 } 224 } 225 } 226 227 protected void setConnectionType( String connectionType ) 228 { 229 this.connectionType = connectionType; 230 } 231 232 public String getConnectionUrl() 233 { 234 boolean requireDeveloperConnection = !"connection".equals( connectionType.toLowerCase() ); 235 if ( StringUtils.isNotEmpty( connectionUrl ) && !requireDeveloperConnection ) 236 { 237 return connectionUrl; 238 } 239 else if ( StringUtils.isNotEmpty( developerConnectionUrl ) ) 240 { 241 return developerConnectionUrl; 242 } 243 if ( requireDeveloperConnection ) 244 { 245 throw new NullPointerException( "You need to define a developerConnectionUrl parameter" ); 246 } 247 else 248 { 249 throw new NullPointerException( "You need to define a connectionUrl parameter" ); 250 } 251 } 252 253 public void setConnectionUrl( String connectionUrl ) 254 { 255 this.connectionUrl = connectionUrl; 256 } 257 258 public File getWorkingDirectory() 259 { 260 if ( workingDirectory == null ) 261 { 262 return basedir; 263 } 264 265 return workingDirectory; 266 } 267 268 public void setWorkingDirectory( File workingDirectory ) 269 { 270 this.workingDirectory = workingDirectory; 271 } 272 273 public ScmManager getScmManager() 274 { 275 return manager; 276 } 277 278 public ScmFileSet getFileSet() 279 throws IOException 280 { 281 if ( includes != null || excludes != null ) 282 { 283 return new ScmFileSet( getWorkingDirectory(), includes, excludes ); 284 } 285 else 286 { 287 return new ScmFileSet( getWorkingDirectory() ); 288 } 289 } 290 291 public ScmRepository getScmRepository() 292 throws ScmException 293 { 294 ScmRepository repository; 295 296 try 297 { 298 repository = getScmManager().makeScmRepository( getConnectionUrl() ); 299 300 ScmProviderRepository providerRepo = repository.getProviderRepository(); 301 302 providerRepo.setPushChanges( pushChanges ); 303 304 if ( !StringUtils.isEmpty( username ) ) 305 { 306 providerRepo.setUser( username ); 307 } 308 309 if ( !StringUtils.isEmpty( password ) ) 310 { 311 providerRepo.setPassword( password ); 312 } 313 314 if ( repository.getProviderRepository() instanceof ScmProviderRepositoryWithHost ) 315 { 316 ScmProviderRepositoryWithHost repo = (ScmProviderRepositoryWithHost) repository.getProviderRepository(); 317 318 loadInfosFromSettings( repo ); 319 320 if ( !StringUtils.isEmpty( username ) ) 321 { 322 repo.setUser( username ); 323 } 324 325 if ( !StringUtils.isEmpty( password ) ) 326 { 327 repo.setPassword( password ); 328 } 329 330 if ( !StringUtils.isEmpty( privateKey ) ) 331 { 332 repo.setPrivateKey( privateKey ); 333 } 334 335 if ( !StringUtils.isEmpty( passphrase ) ) 336 { 337 repo.setPassphrase( passphrase ); 338 } 339 } 340 341 if ( !StringUtils.isEmpty( tagBase ) && repository.getProvider().equals( "svn" ) ) 342 { 343 SvnScmProviderRepository svnRepo = (SvnScmProviderRepository) repository.getProviderRepository(); 344 345 svnRepo.setTagBase( tagBase ); 346 } 347 } 348 catch ( ScmRepositoryException e ) 349 { 350 if ( !e.getValidationMessages().isEmpty() ) 351 { 352 for ( String message : e.getValidationMessages() ) 353 { 354 getLog().error( message ); 355 } 356 } 357 358 throw new ScmException( "Can't load the scm provider.", e ); 359 } 360 catch ( Exception e ) 361 { 362 throw new ScmException( "Can't load the scm provider.", e ); 363 } 364 365 return repository; 366 } 367 368 /** 369 * Load username password from settings if user has not set them in JVM properties 370 * 371 * @param repo not null 372 */ 373 private void loadInfosFromSettings( ScmProviderRepositoryWithHost repo ) 374 { 375 if ( username == null || password == null ) 376 { 377 String host = repo.getHost(); 378 379 int port = repo.getPort(); 380 381 if ( port > 0 ) 382 { 383 host += ":" + port; 384 } 385 386 Server server = this.settings.getServer( host ); 387 388 if ( server != null ) 389 { 390 if ( username == null ) 391 { 392 username = server.getUsername(); 393 } 394 395 if ( password == null ) 396 { 397 password = decrypt( server.getPassword(), host ); 398 } 399 400 if ( privateKey == null ) 401 { 402 privateKey = server.getPrivateKey(); 403 } 404 405 if ( passphrase == null ) 406 { 407 passphrase = decrypt( server.getPassphrase(), host ); 408 } 409 } 410 } 411 } 412 413 private String decrypt( String str, String server ) 414 { 415 try 416 { 417 return secDispatcher.decrypt( str ); 418 } 419 catch ( SecDispatcherException e ) 420 { 421 getLog().warn( "Failed to decrypt password/passphrase for server " + server + ", using auth token as is" ); 422 return str; 423 } 424 } 425 426 public void checkResult( ScmResult result ) 427 throws MojoExecutionException 428 { 429 if ( !result.isSuccess() ) 430 { 431 getLog().error( "Provider message:" ); 432 433 getLog().error( result.getProviderMessage() == null ? "" : result.getProviderMessage() ); 434 435 getLog().error( "Command output:" ); 436 437 getLog().error( result.getCommandOutput() == null ? "" : result.getCommandOutput() ); 438 439 throw new MojoExecutionException( 440 "Command failed." + StringUtils.defaultString( result.getProviderMessage() ) ); 441 } 442 } 443 444 public String getIncludes() 445 { 446 return includes; 447 } 448 449 public void setIncludes( String includes ) 450 { 451 this.includes = includes; 452 } 453 454 public String getExcludes() 455 { 456 return excludes; 457 } 458 459 public void setExcludes( String excludes ) 460 { 461 this.excludes = excludes; 462 } 463 464 public ScmVersion getScmVersion( String versionType, String version ) 465 throws MojoExecutionException 466 { 467 if ( StringUtils.isEmpty( versionType ) && StringUtils.isNotEmpty( version ) ) 468 { 469 throw new MojoExecutionException( "You must specify the version type." ); 470 } 471 472 if ( StringUtils.isEmpty( version ) ) 473 { 474 return null; 475 } 476 477 if ( "branch".equals( versionType ) ) 478 { 479 return new ScmBranch( version ); 480 } 481 482 if ( "tag".equals( versionType ) ) 483 { 484 return new ScmTag( version ); 485 } 486 487 if ( "revision".equals( versionType ) ) 488 { 489 return new ScmRevision( version ); 490 } 491 492 throw new MojoExecutionException( "Unknown '" + versionType + "' version type." ); 493 } 494 495 protected void handleExcludesIncludesAfterCheckoutAndExport( File checkoutDirectory ) 496 throws MojoExecutionException 497 { 498 List<String> includes = new ArrayList<String>(); 499 500 if ( ! StringUtils.isBlank( this.getIncludes() ) ) 501 { 502 String[] tokens = StringUtils.split( this.getIncludes(), "," ); 503 for ( int i = 0; i < tokens.length; ++i ) 504 { 505 includes.add( tokens[i] ); 506 } 507 } 508 509 List<String> excludes = new ArrayList<String>(); 510 511 if ( ! StringUtils.isBlank( this.getExcludes() ) ) 512 { 513 String[] tokens = StringUtils.split( this.getExcludes(), "," ); 514 for ( int i = 0; i < tokens.length; ++i ) 515 { 516 excludes.add( tokens[i] ); 517 } 518 } 519 520 if ( includes.isEmpty() && excludes.isEmpty() ) 521 { 522 return; 523 } 524 525 FileSetManager fileSetManager = new FileSetManager(); 526 527 FileSet fileset = new FileSet(); 528 fileset.setDirectory( checkoutDirectory.getAbsolutePath() ); 529 fileset.setIncludes( excludes );//revert the order to do the delete 530 fileset.setExcludes( includes ); 531 fileset.setUseDefaultExcludes( false ); 532 533 try 534 { 535 fileSetManager.delete( fileset ); 536 } 537 catch ( IOException e ) 538 { 539 throw new MojoExecutionException( "Error found while cleaning up output directory base on excludes/includes configurations.", e ); 540 } 541 542 } 543 }