View Javadoc

1   package org.apache.maven.plugins.site;
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 org.apache.commons.lang.StringUtils;
23  import org.apache.maven.artifact.manager.WagonConfigurationException;
24  import org.apache.maven.artifact.manager.WagonManager;
25  import org.apache.maven.model.DistributionManagement;
26  import org.apache.maven.model.Site;
27  import org.apache.maven.plugin.AbstractMojo;
28  import org.apache.maven.plugin.MojoExecutionException;
29  import org.apache.maven.plugin.logging.Log;
30  import org.apache.maven.project.MavenProject;
31  import org.apache.maven.settings.Server;
32  import org.apache.maven.settings.Settings;
33  import org.apache.maven.wagon.CommandExecutionException;
34  import org.apache.maven.wagon.CommandExecutor;
35  import org.apache.maven.wagon.ConnectionException;
36  import org.apache.maven.wagon.ResourceDoesNotExistException;
37  import org.apache.maven.wagon.TransferFailedException;
38  import org.apache.maven.wagon.UnsupportedProtocolException;
39  import org.apache.maven.wagon.Wagon;
40  import org.apache.maven.wagon.authentication.AuthenticationException;
41  import org.apache.maven.wagon.authorization.AuthorizationException;
42  import org.apache.maven.wagon.observers.Debug;
43  import org.apache.maven.wagon.proxy.ProxyInfo;
44  import org.apache.maven.wagon.repository.Repository;
45  import org.codehaus.plexus.PlexusConstants;
46  import org.codehaus.plexus.PlexusContainer;
47  import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
48  import org.codehaus.plexus.component.configurator.ComponentConfigurator;
49  import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
50  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
51  import org.codehaus.plexus.configuration.PlexusConfiguration;
52  import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
53  import org.codehaus.plexus.context.Context;
54  import org.codehaus.plexus.context.ContextException;
55  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
56  import org.codehaus.plexus.util.xml.Xpp3Dom;
57  
58  import java.io.File;
59  
60  /**
61   * Deploys the generated site using <code>scp</code> or <code>file</code>
62   * protocol to the site URL specified in the
63   * <code>&lt;distributionManagement&gt;</code> section of the POM.
64   * <p>
65   * For <code>scp</code> protocol, the website files are packaged into zip archive,
66   * then the archive is transfered to the remote host, next it is un-archived.
67   * This method of deployment should normally be much faster
68   * than making a file by file copy.  For <code>file</code> protocol, the files are copied
69   * directly to the destination directory.
70   * </p>
71   *
72   * @author <a href="mailto:michal@org.codehaus.org">Michal Maczka</a>
73   * @version $Id: SiteDeployMojo.html 816547 2012-05-08 11:51:09Z hboutemy $
74   * @goal deploy
75   */
76  public class SiteDeployMojo
77      extends AbstractMojo implements Contextualizable
78  {
79      /**
80       * Directory containing the generated project sites and report distributions.
81       *
82       * @parameter alias="outputDirectory" expression="${project.reporting.outputDirectory}"
83       * @required
84       */
85      private File inputDirectory;
86  
87      /**
88       * @parameter expression="${project}"
89       * @required
90       * @readonly
91       */
92      private MavenProject project;
93  
94      /**
95       * @component
96       */
97      private WagonManager wagonManager;
98  
99      /**
100      * The current user system settings for use in Maven.
101      *
102      * @parameter expression="${settings}"
103      * @required
104      * @readonly
105      */
106     private Settings settings;
107 
108     private PlexusContainer container;
109 
110     public void execute()
111         throws MojoExecutionException
112     {
113         if ( !inputDirectory.exists() )
114         {
115             throw new MojoExecutionException( "The site does not exist, please run site:site first" );
116         }
117 
118         DistributionManagement distributionManagement = project.getDistributionManagement();
119 
120         if ( distributionManagement == null )
121         {
122             throw new MojoExecutionException( "Missing distribution management information in the project" );
123         }
124 
125         Site site = distributionManagement.getSite();
126 
127         if ( site == null )
128         {
129             throw new MojoExecutionException(
130                 "Missing site information in the distribution management element in the project.." );
131         }
132 
133         String url = site.getUrl();
134 
135         String id = site.getId();
136 
137         if ( url == null )
138         {
139             throw new MojoExecutionException( "The URL to the site is missing in the project descriptor." );
140         }
141         getLog().debug( "The site will be deployed to '" + url + "'");
142 
143         Repository repository = new Repository( id, url );
144 
145         // TODO: work on moving this into the deployer like the other deploy methods
146 
147         Wagon wagon;
148 
149         try
150         {
151             wagon = wagonManager.getWagon( repository );
152             configureWagon( wagon, repository.getId(), settings, container, getLog() );
153         }
154         catch ( UnsupportedProtocolException e )
155         {
156             throw new MojoExecutionException( "Unsupported protocol: '" + repository.getProtocol() + "'", e );
157         }
158         catch ( WagonConfigurationException e )
159         {
160             throw new MojoExecutionException( "Unable to configure Wagon: '" + repository.getProtocol() + "'", e );
161         }
162 
163         if ( !wagon.supportsDirectoryCopy() )
164         {
165             throw new MojoExecutionException(
166                 "Wagon protocol '" + repository.getProtocol() + "' doesn't support directory copying" );
167         }
168 
169         try
170         {
171             Debug debug = new Debug();
172 
173             wagon.addSessionListener( debug );
174 
175             wagon.addTransferListener( debug );
176 
177             ProxyInfo proxyInfo = getProxyInfo( repository, wagonManager );
178             if ( proxyInfo != null )
179             {
180                 wagon.connect( repository, wagonManager.getAuthenticationInfo( id ), proxyInfo );
181             }
182             else
183             {
184                 wagon.connect( repository, wagonManager.getAuthenticationInfo( id ) );
185             }
186 
187             wagon.putDirectory( inputDirectory, "." );
188 
189             // TODO: current wagon uses zip which will use the umask on remote host instead of honouring our settings
190             //  Force group writeable
191             if ( wagon instanceof CommandExecutor )
192             {
193                 CommandExecutor exec = (CommandExecutor) wagon;
194                 exec.executeCommand( "chmod -Rf g+w,a+rX " + repository.getBasedir() );
195             }
196         }
197         catch ( ResourceDoesNotExistException e )
198         {
199             throw new MojoExecutionException( "Error uploading site", e );
200         }
201         catch ( TransferFailedException e )
202         {
203             throw new MojoExecutionException( "Error uploading site", e );
204         }
205         catch ( AuthorizationException e )
206         {
207             throw new MojoExecutionException( "Error uploading site", e );
208         }
209         catch ( ConnectionException e )
210         {
211             throw new MojoExecutionException( "Error uploading site", e );
212         }
213         catch ( AuthenticationException e )
214         {
215             throw new MojoExecutionException( "Error uploading site", e );
216         }
217         catch ( CommandExecutionException e )
218         {
219             throw new MojoExecutionException( "Error uploading site", e );
220         }
221         finally
222         {
223             try
224             {
225                 wagon.disconnect();
226             }
227             catch ( ConnectionException e )
228             {
229                 getLog().error( "Error disconnecting wagon - ignored", e );
230             }
231         }
232     }
233 
234     /**
235      * <p>
236      * Get the <code>ProxyInfo</code> of the proxy associated with the <code>host</code>
237      * and the <code>protocol</code> of the given <code>repository</code>.
238      * </p>
239      * <p>
240      * Extract from <a href="http://java.sun.com/j2se/1.5.0/docs/guide/net/properties.html">
241      * J2SE Doc : Networking Properties - nonProxyHosts</a> : "The value can be a list of hosts,
242      * each separated by a |, and in addition a wildcard character (*) can be used for matching"
243      * </p>
244      * <p>
245      * Defensively support for comma (",") and semi colon (";") in addition to pipe ("|") as separator.
246      * </p>
247      *
248      * @return a ProxyInfo object instantiated or <code>null</code> if no matching proxy is found
249      */
250     public static ProxyInfo getProxyInfo( Repository repository, WagonManager wagonManager )
251     {
252         ProxyInfo proxyInfo = wagonManager.getProxy( repository.getProtocol() );
253 
254         if ( proxyInfo == null )
255         {
256             return null;
257         }
258 
259         String host = repository.getHost();
260         String nonProxyHostsAsString = proxyInfo.getNonProxyHosts();
261         String[] nonProxyHosts = StringUtils.split( nonProxyHostsAsString, ",;|" );
262         for ( int i = 0; i < nonProxyHosts.length; i++ )
263         {
264             String nonProxyHost = nonProxyHosts[i];
265             if ( StringUtils.contains( nonProxyHost, "*" ) )
266             {
267                 // Handle wildcard at the end, beginning or middle of the nonProxyHost
268                 String nonProxyHostPrefix = StringUtils.substringBefore( nonProxyHost, "*" );
269                 String nonProxyHostSuffix = StringUtils.substringAfter( nonProxyHost, "*" );
270                 // prefix*
271                 if ( StringUtils.isNotEmpty( nonProxyHostPrefix ) && host.startsWith( nonProxyHostPrefix )
272                     && StringUtils.isEmpty( nonProxyHostSuffix ) )
273                 {
274                     return null;
275                 }
276                 // *suffix
277                 if ( StringUtils.isEmpty( nonProxyHostPrefix )
278                     && StringUtils.isNotEmpty( nonProxyHostSuffix ) && host.endsWith( nonProxyHostSuffix ) )
279                 {
280                     return null;
281                 }
282                 // prefix*suffix
283                 if ( StringUtils.isNotEmpty( nonProxyHostPrefix ) && host.startsWith( nonProxyHostPrefix )
284                     && StringUtils.isNotEmpty( nonProxyHostSuffix ) && host.endsWith( nonProxyHostSuffix ) )
285                 {
286                     return null;
287                 }
288             }
289             else if ( host.equals( nonProxyHost ) )
290             {
291                 return null;
292             }
293         }
294         return proxyInfo;
295     }
296 
297     /**
298      * Configure the Wagon with the information from serverConfigurationMap ( which comes from settings.xml )
299      *
300      * @todo Remove when {@link WagonManager#getWagon(Repository) is available}. It's available in Maven 2.0.5.
301      * @param wagon
302      * @param repositoryId
303      * @param settings
304      * @param container
305      * @param log
306      * @throws WagonConfigurationException
307      */
308     static void configureWagon( Wagon wagon, String repositoryId, Settings settings, PlexusContainer container,
309                                 Log log )
310         throws WagonConfigurationException
311     {
312         // MSITE-25: Make sure that the server settings are inserted
313         for ( int i = 0; i < settings.getServers().size(); i++ )
314         {
315             Server server = (Server) settings.getServers().get( i );
316             String id = server.getId();
317             if ( id != null && id.equals( repositoryId ) )
318             {
319                 if ( server.getConfiguration() != null )
320                 {
321                     final PlexusConfiguration plexusConf =
322                         new XmlPlexusConfiguration( (Xpp3Dom) server.getConfiguration() );
323 
324                     ComponentConfigurator componentConfigurator = null;
325                     try
326                     {
327                         componentConfigurator = (ComponentConfigurator) container.lookup( ComponentConfigurator.ROLE );
328                         componentConfigurator.configureComponent( wagon, plexusConf, container.getContainerRealm() );
329                     }
330                     catch ( final ComponentLookupException e )
331                     {
332                         throw new WagonConfigurationException( repositoryId, "Unable to lookup wagon configurator."
333                             + " Wagon configuration cannot be applied.", e );
334                     }
335                     catch ( ComponentConfigurationException e )
336                     {
337                         throw new WagonConfigurationException( repositoryId, "Unable to apply wagon configuration.",
338                                                                e );
339                     }
340                     finally
341                     {
342                         if ( componentConfigurator != null )
343                         {
344                             try
345                             {
346                                 container.release( componentConfigurator );
347                             }
348                             catch ( ComponentLifecycleException e )
349                             {
350                                 log.error( "Problem releasing configurator - ignoring: " + e.getMessage() );
351                             }
352                         }
353                     }
354 
355                 }
356 
357             }
358         }
359     }
360 
361     public void contextualize( Context context )
362         throws ContextException
363     {
364         container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
365     }
366 
367 }