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