1 package org.apache.maven.plugins.site;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.net.MalformedURLException;
24 import java.net.URL;
25
26 import java.util.List;
27 import java.util.Locale;
28 import java.util.Set;
29
30 import org.apache.maven.artifact.manager.WagonManager;
31 import org.apache.maven.execution.MavenExecutionRequest;
32 import org.apache.maven.execution.MavenSession;
33 import org.apache.maven.model.DistributionManagement;
34 import org.apache.maven.model.Site;
35 import org.apache.maven.plugin.MojoExecutionException;
36 import org.apache.maven.plugin.logging.Log;
37 import org.apache.maven.project.MavenProject;
38 import org.apache.maven.settings.Proxy;
39 import org.apache.maven.settings.Server;
40 import org.apache.maven.settings.Settings;
41 import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest;
42 import org.apache.maven.settings.crypto.SettingsDecrypter;
43 import org.apache.maven.settings.crypto.SettingsDecryptionResult;
44 import org.apache.maven.wagon.CommandExecutionException;
45 import org.apache.maven.wagon.CommandExecutor;
46 import org.apache.maven.wagon.ConnectionException;
47 import org.apache.maven.wagon.ResourceDoesNotExistException;
48 import org.apache.maven.wagon.TransferFailedException;
49 import org.apache.maven.wagon.UnsupportedProtocolException;
50 import org.apache.maven.wagon.Wagon;
51 import org.apache.maven.wagon.authentication.AuthenticationException;
52 import org.apache.maven.wagon.authentication.AuthenticationInfo;
53 import org.apache.maven.wagon.authorization.AuthorizationException;
54 import org.apache.maven.wagon.observers.Debug;
55 import org.apache.maven.wagon.proxy.ProxyInfo;
56 import org.apache.maven.wagon.repository.Repository;
57
58 import org.codehaus.plexus.PlexusConstants;
59 import org.codehaus.plexus.PlexusContainer;
60 import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
61 import org.codehaus.plexus.component.configurator.ComponentConfigurator;
62 import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
63 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
64 import org.codehaus.plexus.configuration.PlexusConfiguration;
65 import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
66 import org.codehaus.plexus.context.Context;
67 import org.codehaus.plexus.context.ContextException;
68 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
69 import org.codehaus.plexus.util.StringUtils;
70 import org.codehaus.plexus.util.xml.Xpp3Dom;
71
72
73
74
75
76
77
78
79
80 public abstract class AbstractDeployMojo
81 extends AbstractSiteMojo implements Contextualizable
82 {
83
84
85
86
87
88
89 private File inputDirectory;
90
91
92
93
94
95
96
97
98 private boolean chmod;
99
100
101
102
103
104
105
106
107 private String chmodMode;
108
109
110
111
112
113
114
115
116 private String chmodOptions;
117
118
119
120
121
122
123
124 private boolean skipDeploy;
125
126
127
128
129 private WagonManager wagonManager;
130
131
132
133
134
135
136
137
138 private Settings settings;
139
140
141
142
143
144
145
146 protected MavenSession mavenSession;
147
148 private PlexusContainer container;
149
150
151
152
153 protected static final String DEFAULT_STAGING_DIRECTORY = "staging/";
154
155
156 public void execute()
157 throws MojoExecutionException
158 {
159 if ( skipDeploy )
160 {
161 getLog().info( "maven.site.deploy.skip = true: Skipping site deployment" );
162 return;
163 }
164
165 deployTo( new org.apache.maven.plugins.site.wagon.repository.Repository(
166 getDeployRepositoryID(),
167 appendSlash( getDeployRepositoryURL() ) ) );
168 }
169
170
171
172
173
174
175
176
177
178 protected static String appendSlash( final String url )
179 {
180 if ( url.endsWith( "/" ) )
181 {
182 return url;
183 }
184 else
185 {
186 return url + "/";
187 }
188 }
189
190
191
192
193
194
195
196
197
198 protected abstract String getDeployRepositoryID()
199 throws MojoExecutionException;
200
201
202
203
204
205
206
207
208
209
210 protected abstract String getDeployRepositoryURL()
211 throws MojoExecutionException;
212
213
214
215
216
217
218
219
220 private String getDeployModuleDirectory()
221 throws MojoExecutionException
222 {
223 String relative = siteTool.getRelativePath( getSite( project ).getUrl(),
224 getRootSite( project ).getUrl() );
225
226
227
228 relative = relative.replace( '\\', '/' );
229
230 return ( "".equals( relative ) ) ? "./" : relative;
231 }
232
233
234
235
236
237
238
239
240
241
242
243 private void deployTo( final Repository repository )
244 throws MojoExecutionException
245 {
246 if ( !inputDirectory.exists() )
247 {
248 throw new MojoExecutionException( "The site does not exist, please run site:site first" );
249 }
250
251 if ( getLog().isDebugEnabled() )
252 {
253 getLog().debug( "Deploying to '" + repository.getUrl()
254 + "',\n Using credentials from server id '" + repository.getId() + "'" );
255 }
256
257 deploy( inputDirectory, repository );
258 }
259
260 private void deploy( final File directory, final Repository repository )
261 throws MojoExecutionException
262 {
263
264 final Wagon wagon = getWagon( repository, wagonManager );
265
266 try
267 {
268 configureWagon( wagon, repository.getId(), settings, container, getLog() );
269 }
270 catch ( TransferFailedException e )
271 {
272 throw new MojoExecutionException( "Unable to configure Wagon: '" + repository.getProtocol() + "'", e );
273 }
274
275 try
276 {
277 final ProxyInfo proxyInfo;
278 if ( !isMaven3OrMore() )
279 {
280 proxyInfo = getProxyInfo( repository, wagonManager );
281 }
282 else
283 {
284 try
285 {
286 SettingsDecrypter settingsDecrypter = container.lookup( SettingsDecrypter.class );
287
288 proxyInfo = getProxy( repository, settingsDecrypter );
289 }
290 catch ( ComponentLookupException cle )
291 {
292 throw new MojoExecutionException( "Unable to lookup SettingsDecrypter: " + cle.getMessage(), cle );
293 }
294 }
295
296 push( directory, repository, wagon, proxyInfo, siteTool.getAvailableLocales( locales ),
297 getDeployModuleDirectory() );
298
299 if ( chmod )
300 {
301 chmod( wagon, repository, chmodOptions, chmodMode );
302 }
303 }
304 finally
305 {
306 try
307 {
308 wagon.disconnect();
309 }
310 catch ( ConnectionException e )
311 {
312 getLog().error( "Error disconnecting wagon - ignored", e );
313 }
314 }
315 }
316
317
318
319
320
321
322
323 protected File getTopLevelBuildDirectory()
324 {
325
326 final MavenProject topLevelProject = getTopLevelProject( reactorProjects );
327
328
329 final File buildDirectory;
330
331 if ( topLevelProject == null )
332 {
333 getLog().debug( "No top level project found in the reactor, using the current project." );
334
335 buildDirectory = new File( project.getBuild().getDirectory() );
336 }
337 else
338 {
339 getLog().debug( "Using the top level project found in the reactor." );
340
341 buildDirectory = new File( topLevelProject.getBuild().getDirectory() );
342 }
343
344 return buildDirectory;
345 }
346
347 private Wagon getWagon( final Repository repository, final WagonManager manager )
348 throws MojoExecutionException
349 {
350 final Wagon wagon;
351
352 try
353 {
354 wagon = manager.getWagon( repository );
355 }
356 catch ( UnsupportedProtocolException e )
357 {
358 String shortMessage =
359 "Unsupported protocol: '" + repository.getProtocol() + "' for site deployment to "
360 + "distributionManagement.site.url=" + repository.getUrl() + ".";
361 String longMessage =
362 "\n" + shortMessage + "\n" +
363 "Currently supported protocols are: " + getSupportedProtocols() + ".\n"
364 + " Protocols may be added through wagon providers.\n"
365 + " For more information, see "
366 + "http://maven.apache.org/plugins/maven-site-plugin/examples/adding-deploy-protocol.html";
367
368 getLog().error( longMessage );
369
370 throw new MojoExecutionException( shortMessage );
371 }
372 catch ( TransferFailedException e )
373 {
374 throw new MojoExecutionException( "Unable to configure Wagon: '" + repository.getProtocol() + "'", e );
375 }
376
377 if ( !wagon.supportsDirectoryCopy() )
378 {
379 throw new MojoExecutionException(
380 "Wagon protocol '" + repository.getProtocol() + "' doesn't support directory copying" );
381 }
382
383 return wagon;
384 }
385
386 private String getSupportedProtocols()
387 {
388 try
389 {
390 Set<String> protocols = container.lookupMap( Wagon.class ).keySet();
391
392 return StringUtils.join( protocols.iterator(), ", " );
393 }
394 catch ( ComponentLookupException e )
395 {
396
397 getLog().error( e );
398 }
399 return "";
400 }
401
402 private void push( final File inputDirectory, final Repository repository, final Wagon wagon,
403 final ProxyInfo proxyInfo, final List<Locale> localesList, final String relativeDir )
404 throws MojoExecutionException
405 {
406 AuthenticationInfo authenticationInfo = wagonManager.getAuthenticationInfo( repository.getId() );
407 getLog().debug( "authenticationInfo with id '" + repository.getId() + "': "
408 + ( ( authenticationInfo == null ) ? "-" : authenticationInfo.getUserName() ) );
409
410 try
411 {
412 Debug debug = new Debug();
413
414 wagon.addSessionListener( debug );
415
416 wagon.addTransferListener( debug );
417
418 if ( proxyInfo != null )
419 {
420 getLog().debug( "connect with proxyInfo" );
421 wagon.connect( repository, authenticationInfo, proxyInfo );
422 }
423 else if ( proxyInfo == null && authenticationInfo != null )
424 {
425 getLog().debug( "connect with authenticationInfo and without proxyInfo" );
426 wagon.connect( repository, authenticationInfo );
427 }
428 else
429 {
430 getLog().debug( "connect without authenticationInfo and without proxyInfo" );
431 wagon.connect( repository );
432 }
433
434 getLog().info( "Pushing " + inputDirectory );
435
436
437 final String defaultLocale = localesList.get( 0 ).getLanguage();
438
439 for ( Locale locale : localesList )
440 {
441 if ( locale.getLanguage().equals( defaultLocale ) )
442 {
443
444
445 getLog().info( " >>> to " + repository.getUrl() + relativeDir );
446
447 wagon.putDirectory( inputDirectory, relativeDir );
448 }
449 else
450 {
451 getLog().info( " >>> to " + repository.getUrl() + locale.getLanguage() + "/" + relativeDir );
452
453 wagon.putDirectory( new File( inputDirectory, locale.getLanguage() ),
454 locale.getLanguage() + "/" + relativeDir );
455 }
456 }
457 }
458 catch ( ResourceDoesNotExistException e )
459 {
460 throw new MojoExecutionException( "Error uploading site", e );
461 }
462 catch ( TransferFailedException e )
463 {
464 throw new MojoExecutionException( "Error uploading site", e );
465 }
466 catch ( AuthorizationException e )
467 {
468 throw new MojoExecutionException( "Error uploading site", e );
469 }
470 catch ( ConnectionException e )
471 {
472 throw new MojoExecutionException( "Error uploading site", e );
473 }
474 catch ( AuthenticationException e )
475 {
476 throw new MojoExecutionException( "Error uploading site", e );
477 }
478 }
479
480 private static void chmod( final Wagon wagon, final Repository repository, final String chmodOptions,
481 final String chmodMode )
482 throws MojoExecutionException
483 {
484 try
485 {
486 if ( wagon instanceof CommandExecutor )
487 {
488 CommandExecutor exec = (CommandExecutor) wagon;
489 exec.executeCommand( "chmod " + chmodOptions + " " + chmodMode + " " + repository.getBasedir() );
490 }
491
492 }
493 catch ( CommandExecutionException e )
494 {
495 throw new MojoExecutionException( "Error uploading site", e );
496 }
497 }
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517 public static ProxyInfo getProxyInfo( Repository repository, WagonManager wagonManager )
518 {
519 ProxyInfo proxyInfo = wagonManager.getProxy( repository.getProtocol() );
520
521 if ( proxyInfo == null )
522 {
523 return null;
524 }
525
526 String host = repository.getHost();
527 String nonProxyHostsAsString = proxyInfo.getNonProxyHosts();
528 String[] nonProxyHosts = StringUtils.split( nonProxyHostsAsString, ",;|" );
529 for ( int i = 0; i < nonProxyHosts.length; i++ )
530 {
531 String nonProxyHost = nonProxyHosts[i];
532 if ( StringUtils.contains( nonProxyHost, "*" ) )
533 {
534
535 final int pos = nonProxyHost.indexOf( '*' );
536 String nonProxyHostPrefix = nonProxyHost.substring( 0, pos );
537 String nonProxyHostSuffix = nonProxyHost.substring( pos + 1 );
538
539 if ( StringUtils.isNotEmpty( nonProxyHostPrefix ) && host.startsWith( nonProxyHostPrefix )
540 && StringUtils.isEmpty( nonProxyHostSuffix ) )
541 {
542 return null;
543 }
544
545 if ( StringUtils.isEmpty( nonProxyHostPrefix )
546 && StringUtils.isNotEmpty( nonProxyHostSuffix ) && host.endsWith( nonProxyHostSuffix ) )
547 {
548 return null;
549 }
550
551 if ( StringUtils.isNotEmpty( nonProxyHostPrefix ) && host.startsWith( nonProxyHostPrefix )
552 && StringUtils.isNotEmpty( nonProxyHostSuffix ) && host.endsWith( nonProxyHostSuffix ) )
553 {
554 return null;
555 }
556 }
557 else if ( host.equals( nonProxyHost ) )
558 {
559 return null;
560 }
561 }
562 return proxyInfo;
563 }
564
565
566
567
568
569
570
571
572
573
574 private ProxyInfo getProxy( Repository repository, SettingsDecrypter settingsDecrypter )
575 {
576 String protocol = repository.getProtocol();
577 String url = repository.getUrl();
578
579 getLog().debug( "repository protocol " + protocol );
580
581 String originalProtocol = protocol;
582
583
584
585
586 if ( StringUtils.equalsIgnoreCase( "dav", protocol ) && url.startsWith( "dav:" ) )
587 {
588 url = url.substring( 4 );
589 if ( url.startsWith( "http" ) )
590 {
591 try
592 {
593 URL urlSite = new URL( url );
594 protocol = urlSite.getProtocol();
595 getLog().debug( "found dav protocol so transform to real transport protocol " + protocol );
596 }
597 catch ( MalformedURLException e )
598 {
599 getLog().warn( "fail to build URL with " + url );
600 }
601
602 }
603 }
604 else
605 {
606 getLog().debug( "getProxy 'protocol': " + protocol );
607 }
608 if ( mavenSession != null && protocol != null )
609 {
610 MavenExecutionRequest request = mavenSession.getRequest();
611
612 if ( request != null )
613 {
614 List<Proxy> proxies = request.getProxies();
615
616 if ( proxies != null )
617 {
618 for ( Proxy proxy : proxies )
619 {
620 if ( proxy.isActive()
621 && ( protocol.equalsIgnoreCase( proxy.getProtocol() ) || originalProtocol
622 .equalsIgnoreCase( proxy.getProtocol() ) ) )
623 {
624 SettingsDecryptionResult result = settingsDecrypter
625 .decrypt( new DefaultSettingsDecryptionRequest( proxy ) );
626 proxy = result.getProxy();
627
628 ProxyInfo proxyInfo = new ProxyInfo();
629 proxyInfo.setHost( proxy.getHost() );
630
631 proxyInfo.setType( protocol );
632 proxyInfo.setPort( proxy.getPort() );
633 proxyInfo.setNonProxyHosts( proxy.getNonProxyHosts() );
634 proxyInfo.setUserName( proxy.getUsername() );
635 proxyInfo.setPassword( proxy.getPassword() );
636
637 getLog().debug( "found proxyInfo "
638 + ( proxyInfo == null ? "null" : "host:port " + proxyInfo.getHost()
639 + ":" + proxyInfo.getPort() + ", " + proxyInfo.getUserName() ) );
640
641 return proxyInfo;
642 }
643 }
644 }
645 }
646 }
647 getLog().debug( "getProxy 'protocol': " + protocol + " no ProxyInfo found");
648 return null;
649 }
650
651
652
653
654
655
656
657
658
659
660
661
662 private static void configureWagon( Wagon wagon, String repositoryId, Settings settings, PlexusContainer container,
663 Log log )
664 throws TransferFailedException
665 {
666 log.debug( " configureWagon " );
667
668
669 for ( int i = 0; i < settings.getServers().size(); i++ )
670 {
671 Server server = settings.getServers().get( i );
672 String id = server.getId();
673
674 log.debug( "configureWagon server " + id );
675
676 if ( id != null && id.equals( repositoryId ) )
677 {
678 if ( server.getConfiguration() != null )
679 {
680 final PlexusConfiguration plexusConf =
681 new XmlPlexusConfiguration( (Xpp3Dom) server.getConfiguration() );
682
683 ComponentConfigurator componentConfigurator = null;
684 try
685 {
686 componentConfigurator = (ComponentConfigurator) container.lookup( ComponentConfigurator.ROLE, "basic" );
687 componentConfigurator.configureComponent( wagon, plexusConf, container.getContainerRealm() );
688 }
689 catch ( final ComponentLookupException e )
690 {
691 throw new TransferFailedException( "While configuring wagon for \'" + repositoryId
692 + "\': Unable to lookup wagon configurator." + " Wagon configuration cannot be applied.", e );
693 }
694 catch ( ComponentConfigurationException e )
695 {
696 throw new TransferFailedException( "While configuring wagon for \'" + repositoryId
697 + "\': Unable to apply wagon configuration.", e );
698 }
699 finally
700 {
701 if ( componentConfigurator != null )
702 {
703 try
704 {
705 container.release( componentConfigurator );
706 }
707 catch ( ComponentLifecycleException e )
708 {
709 log.error( "Problem releasing configurator - ignoring: " + e.getMessage() );
710 }
711 }
712 }
713 }
714 }
715 }
716 }
717
718
719 public void contextualize( Context context )
720 throws ContextException
721 {
722 container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
723 }
724
725
726
727
728
729
730
731
732 private static MavenProject getTopLevelProject( List<MavenProject> reactorProjects )
733 {
734 if ( reactorProjects == null )
735 {
736 return null;
737 }
738
739 for ( MavenProject reactorProject : reactorProjects )
740 {
741 if ( reactorProject.isExecutionRoot() )
742 {
743 return reactorProject;
744 }
745 }
746
747 return null;
748 }
749
750
751
752
753
754
755
756
757
758
759
760 protected static Site getSite( final MavenProject project )
761 throws MojoExecutionException
762 {
763 final String name = project.getName() + " ("
764 + project.getGroupId() + ":" + project.getArtifactId() + ":" + project.getVersion() + ")";
765
766 final DistributionManagement distributionManagement = project.getDistributionManagement();
767
768 if ( distributionManagement == null )
769 {
770 throw new MojoExecutionException( "Missing distribution management in project " + name );
771 }
772
773 final Site site = distributionManagement.getSite();
774
775 if ( site == null )
776 {
777 throw new MojoExecutionException(
778 "Missing site information in the distribution management of the project " + name );
779 }
780
781 if ( site.getUrl() == null || site.getId() == null )
782 {
783 throw new MojoExecutionException( "Missing site data: specify url and id for project " + name );
784 }
785
786 return site;
787 }
788
789
790
791
792
793
794
795
796
797
798
799
800
801 protected Site getRootSite( MavenProject project )
802 throws MojoExecutionException
803 {
804 Site site = getSite( project );
805
806 MavenProject parent = project;
807
808 while ( parent.getParent() != null )
809 {
810
811 parent = siteTool.getParentProject( parent, reactorProjects, localRepository );
812
813 try
814 {
815 site = getSite( parent );
816 }
817 catch ( MojoExecutionException e )
818 {
819 break;
820 }
821 }
822
823 return site;
824 }
825 }