PageRenderTime 32ms CodeModel.GetById 16ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/maven-scalate-plugin/src/main/java/org/fusesource/scalate/maven/SiteDeployMojo.java

http://github.com/scalate/scalate
Java | 390 lines | 180 code | 38 blank | 172 comment | 35 complexity | 4de3894d88034eeb2ad90c36e271ebb9 MD5 | raw file
  1/**
  2 * Copyright (C) 2009-2011 the original author or authors.
  3 * See the notice.md file distributed with this work for additional
  4 * information regarding copyright ownership.
  5 *
  6 * Licensed under the Apache License, Version 2.0 (the "License");
  7 * you may not use this file except in compliance with the License.
  8 * You may obtain a copy of the License at
  9 *
 10 *     http://www.apache.org/licenses/LICENSE-2.0
 11 *
 12 * Unless required by applicable law or agreed to in writing, software
 13 * distributed under the License is distributed on an "AS IS" BASIS,
 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15 * See the License for the specific language governing permissions and
 16 * limitations under the License.
 17 */
 18package org.fusesource.scalate.maven;
 19
 20/*
 21 * Licensed to the Apache Software Foundation (ASF) under one
 22 * or more contributor license agreements.  See the NOTICE file
 23 * distributed with this work for additional information
 24 * regarding copyright ownership.  The ASF licenses this file
 25 * to you under the Apache License, Version 2.0 (the
 26 * "License"); you may not use this file except in compliance
 27 * with the License.  You may obtain a copy of the License at
 28 *
 29 *   http://www.apache.org/licenses/LICENSE-2.0
 30 *
 31 * Unless required by applicable law or agreed to in writing,
 32 * software distributed under the License is distributed on an
 33 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 34 * KIND, either express or implied.  See the License for the
 35 * specific language governing permissions and limitations
 36 * under the License.
 37 */
 38
 39import org.apache.commons.lang.StringUtils;
 40import org.apache.maven.repository.legacy.WagonConfigurationException;
 41import org.apache.maven.artifact.manager.WagonManager;
 42import org.apache.maven.plugin.AbstractMojo;
 43import org.apache.maven.plugin.MojoExecutionException;
 44import org.apache.maven.plugin.logging.Log;
 45import org.apache.maven.project.MavenProject;
 46import org.apache.maven.settings.Server;
 47import org.apache.maven.settings.Settings;
 48import org.apache.maven.wagon.CommandExecutionException;
 49import org.apache.maven.wagon.CommandExecutor;
 50import org.apache.maven.wagon.ConnectionException;
 51import org.apache.maven.wagon.ResourceDoesNotExistException;
 52import org.apache.maven.wagon.TransferFailedException;
 53import org.apache.maven.wagon.UnsupportedProtocolException;
 54import org.apache.maven.wagon.Wagon;
 55import org.apache.maven.wagon.authentication.AuthenticationException;
 56import org.apache.maven.wagon.authorization.AuthorizationException;
 57import org.apache.maven.wagon.observers.Debug;
 58import org.apache.maven.wagon.proxy.ProxyInfo;
 59import org.apache.maven.wagon.repository.Repository;
 60import org.codehaus.plexus.PlexusConstants;
 61import org.codehaus.plexus.PlexusContainer;
 62import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
 63import org.codehaus.plexus.component.configurator.ComponentConfigurator;
 64import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
 65import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 66import org.codehaus.plexus.configuration.PlexusConfiguration;
 67import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
 68import org.codehaus.plexus.context.Context;
 69import org.codehaus.plexus.context.ContextException;
 70import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
 71import org.codehaus.plexus.util.xml.Xpp3Dom;
 72
 73import java.io.File;
 74
 75/**
 76 * Deploys the generated site using <code>scp</code> or <code>file</code>
 77 * protocol to the site URL specified in the
 78 * <code>&lt;distributionManagement&gt;</code> section of the POM.
 79 * <p>
 80 * For <code>scp</code> protocol, the website files are packaged into zip archive,
 81 * then the archive is transfered to the remote host, next it is un-archived.
 82 * This method of deployment should normally be much faster
 83 * than making a file by file copy.  For <code>file</code> protocol, the files are copied
 84 * directly to the destination directory.
 85 * </p>
 86 *
 87 * @author <a href="mailto:michal@org.codehaus.org">Michal Maczka</a>
 88 * @phase deploy
 89 * @goal deploy
 90 */
 91public class SiteDeployMojo
 92        extends AbstractMojo implements Contextualizable {
 93    /**
 94     * Directory containing the generated site.
 95     *
 96     * @parameter alias="outputDirectory" expression="${project.build.directory}/sitegen"
 97     * @required
 98     */
 99    private File inputDirectory;
100
101    /**
102     * Whether to run the "chmod" command on the remote site after the deploy.
103     * Defaults to "true".
104     *
105     * @parameter expression="${maven.site.chmod}" default-value="true"
106     * @since 2.1
107     */
108    private boolean chmod;
109
110    /**
111     * The mode used by the "chmod" command. Only used if chmod = true.
112     * Defaults to "g+w,a+rX".
113     *
114     * @parameter expression="${maven.site.chmod.mode}" default-value="g+w,a+rX"
115     * @since 2.1
116     */
117    private String chmodMode;
118
119    /**
120     * The Server ID used to deploy the site which should reference a &lt;server&gt; in your
121     * ~/.m2/settings.xml file for username/pwd
122     *
123     * @parameter expression="${scalate.remoteServerId}"
124     */
125    private String remoteServerId;
126
127    /**
128     * The Server Server URL to deploy the site to which uses the same URL format as the
129     * distributionManagement / site / url expression in the pom.xml
130     *
131     * @parameter expression="${scalate.remoteServerUrl}"
132     */
133    private String remoteServerUrl;
134
135    /**
136     * The path used relative to the distribution URL in maven.
137     * TODO...
138     * Defaults to ".." so that the module name of the maven project using this goal is not included in the URL.
139     * Configure to "." if you want to include the module name in the site URL
140     *
141     * @parameter default-value="."
142     */
143    private String remoteDirectory;
144
145    /**
146     * The options used by the "chmod" command. Only used if chmod = true.
147     * Defaults to "-Rf".
148     *
149     * @parameter expression="${maven.site.chmod.options}" default-value="-Rf"
150     * @since 2.1
151     */
152    private String chmodOptions;
153
154    /**
155     * @parameter expression="${project}"
156     * @required
157     * @readonly
158     */
159    private MavenProject project;
160
161    /**
162     * @component
163     */
164    private WagonManager wagonManager;
165
166    /**
167     * The current user system settings for use in Maven.
168     *
169     * @parameter expression="${settings}"
170     * @required
171     * @readonly
172     */
173    private Settings settings;
174
175    private PlexusContainer container;
176
177    /**
178     * {@inheritDoc}
179     */
180    public void execute()
181            throws MojoExecutionException {
182        if (!inputDirectory.exists()) {
183            throw new MojoExecutionException("The site does not exist, please run site:site first");
184        }
185
186/*
187        DistributionManagement distributionManagement = project.getDistributionManagement();
188
189        if ( distributionManagement == null )
190        {
191            throw new MojoExecutionException( "Missing distribution management information in the project" );
192        }
193
194        Site site = distributionManagement.getSite();
195
196        if ( site == null )
197        {
198            throw new MojoExecutionException(
199                "Missing site information in the distribution management element in the project.." );
200        }
201
202        String url = site.getUrl();
203
204        String id = site.getId();
205
206*/
207
208        String url = remoteServerUrl;
209        String id = remoteServerId;
210
211        if (id == null) {
212            throw new MojoExecutionException("The remoteServerId is missing in the plugin configuration.");
213        }
214        if (url == null) {
215            throw new MojoExecutionException("The remoteServerUrl is missing in the plugin configuration.");
216        }
217        getLog().debug("The site will be deployed to '" + url + "' with id '" + id + "'");
218
219        Repository repository = new Repository(id, url);
220
221        // TODO: work on moving this into the deployer like the other deploy methods
222
223        Wagon wagon;
224
225        try {
226            wagon = wagonManager.getWagon(repository);
227            configureWagon(wagon, repository.getId(), settings, container, getLog());
228        } catch (UnsupportedProtocolException e) {
229            throw new MojoExecutionException("Unsupported protocol: '" + repository.getProtocol() + "'", e);
230        } catch (WagonConfigurationException e) {
231            throw new MojoExecutionException("Unable to configure Wagon: '" + repository.getProtocol() + "'", e);
232        }
233
234        if (!wagon.supportsDirectoryCopy()) {
235            throw new MojoExecutionException(
236                    "Wagon protocol '" + repository.getProtocol() + "' doesn't support directory copying");
237        }
238
239        try {
240            Debug debug = new Debug();
241
242            wagon.addSessionListener(debug);
243
244            wagon.addTransferListener(debug);
245
246            ProxyInfo proxyInfo = getProxyInfo(repository, wagonManager);
247            if (proxyInfo != null) {
248                wagon.connect(repository, wagonManager.getAuthenticationInfo(id), proxyInfo);
249            } else {
250                wagon.connect(repository, wagonManager.getAuthenticationInfo(id));
251            }
252
253            wagon.putDirectory(inputDirectory, remoteDirectory);
254
255            if (chmod && wagon instanceof CommandExecutor) {
256                CommandExecutor exec = (CommandExecutor) wagon;
257                exec.executeCommand("chmod " + chmodOptions + " " + chmodMode + " " + repository.getBasedir());
258            }
259        } catch (ResourceDoesNotExistException e) {
260            throw new MojoExecutionException("Error uploading site", e);
261        } catch (TransferFailedException e) {
262            throw new MojoExecutionException("Error uploading site", e);
263        } catch (AuthorizationException e) {
264            throw new MojoExecutionException("Error uploading site", e);
265        } catch (ConnectionException e) {
266            throw new MojoExecutionException("Error uploading site", e);
267        } catch (AuthenticationException e) {
268            throw new MojoExecutionException("Error uploading site", e);
269        } catch (CommandExecutionException e) {
270            throw new MojoExecutionException("Error uploading site", e);
271        } finally {
272            try {
273                wagon.disconnect();
274            } catch (ConnectionException e) {
275                getLog().error("Error disconnecting wagon - ignored", e);
276            }
277        }
278    }
279
280    /**
281     * <p>
282     * Get the <code>ProxyInfo</code> of the proxy associated with the <code>host</code>
283     * and the <code>protocol</code> of the given <code>repository</code>.
284     * </p>
285     * <p>
286     * Extract from <a href="http://java.sun.com/j2se/1.5.0/docs/guide/net/properties.html">
287     * J2SE Doc : Networking Properties - nonProxyHosts</a> : "The value can be a list of hosts,
288     * each separated by a |, and in addition a wildcard character (*) can be used for matching"
289     * </p>
290     * <p>
291     * Defensively support for comma (",") and semi colon (";") in addition to pipe ("|") as separator.
292     * </p>
293     *
294     * @param repository   the Repository to extract the ProxyInfo from.
295     * @param wagonManager the WagonManager used to connect to the Repository.
296     * @return a ProxyInfo object instantiated or <code>null</code> if no matching proxy is found
297     */
298    public static ProxyInfo getProxyInfo(Repository repository, WagonManager wagonManager) {
299        ProxyInfo proxyInfo = wagonManager.getProxy(repository.getProtocol());
300
301        if (proxyInfo == null) {
302            return null;
303        }
304
305        String host = repository.getHost();
306        String nonProxyHostsAsString = proxyInfo.getNonProxyHosts();
307        String[] nonProxyHosts = StringUtils.split(nonProxyHostsAsString, ",;|");
308        for (int i = 0; i < nonProxyHosts.length; i++) {
309            String nonProxyHost = nonProxyHosts[i];
310            if (StringUtils.contains(nonProxyHost, "*")) {
311                // Handle wildcard at the end, beginning or middle of the nonProxyHost
312                String nonProxyHostPrefix = StringUtils.substringBefore(nonProxyHost, "*");
313                String nonProxyHostSuffix = StringUtils.substringAfter(nonProxyHost, "*");
314                // prefix*
315                if (StringUtils.isNotEmpty(nonProxyHostPrefix) && host.startsWith(nonProxyHostPrefix)
316                        && StringUtils.isEmpty(nonProxyHostSuffix)) {
317                    return null;
318                }
319                // *suffix
320                if (StringUtils.isEmpty(nonProxyHostPrefix)
321                        && StringUtils.isNotEmpty(nonProxyHostSuffix) && host.endsWith(nonProxyHostSuffix)) {
322                    return null;
323                }
324                // prefix*suffix
325                if (StringUtils.isNotEmpty(nonProxyHostPrefix) && host.startsWith(nonProxyHostPrefix)
326                        && StringUtils.isNotEmpty(nonProxyHostSuffix) && host.endsWith(nonProxyHostSuffix)) {
327                    return null;
328                }
329            } else if (host.equals(nonProxyHost)) {
330                return null;
331            }
332        }
333        return proxyInfo;
334    }
335
336    /**
337     * Configure the Wagon with the information from serverConfigurationMap ( which comes from settings.xml )
338     *
339     * @param wagon
340     * @param repositoryId
341     * @param settings
342     * @param container
343     * @param log
344     * @throws WagonConfigurationException
345     * @todo Remove when {@link WagonManager#getWagon(Repository) is available}. It's available in Maven 2.0.5.
346     */
347    static void configureWagon(Wagon wagon, String repositoryId, Settings settings, PlexusContainer container,
348                               Log log)
349            throws WagonConfigurationException {
350        // MSITE-25: Make sure that the server settings are inserted
351        for (int i = 0; i < settings.getServers().size(); i++) {
352            Server server = (Server) settings.getServers().get(i);
353            String id = server.getId();
354            if (id != null && id.equals(repositoryId)) {
355                if (server.getConfiguration() != null) {
356                    final PlexusConfiguration plexusConf =
357                            new XmlPlexusConfiguration((Xpp3Dom) server.getConfiguration());
358
359                    ComponentConfigurator componentConfigurator = null;
360                    try {
361                        componentConfigurator = (ComponentConfigurator) container.lookup(ComponentConfigurator.ROLE);
362                        componentConfigurator.configureComponent(wagon, plexusConf, container.getContainerRealm());
363                    } catch (final ComponentLookupException e) {
364                        throw new WagonConfigurationException(repositoryId, "Unable to lookup wagon configurator."
365                                + " Wagon configuration cannot be applied.", e);
366                    } catch (ComponentConfigurationException e) {
367                        throw new WagonConfigurationException(repositoryId, "Unable to apply wagon configuration.",
368                                e);
369                    } finally {
370                        if (componentConfigurator != null) {
371                            try {
372                                container.release(componentConfigurator);
373                            } catch (ComponentLifecycleException e) {
374                                log.error("Problem releasing configurator - ignoring: " + e.getMessage());
375                            }
376                        }
377                    }
378
379                }
380
381            }
382        }
383    }
384
385    public void contextualize(Context context)
386            throws ContextException {
387        container = (PlexusContainer) context.get(PlexusConstants.PLEXUS_KEY);
388    }
389
390}