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 java.util.Map;
23 import org.apache.commons.lang.StringUtils;
24 import org.apache.maven.model.Build;
25 import org.apache.maven.model.Plugin;
26 import org.apache.maven.model.PluginManagement;
27 import org.apache.maven.model.Site;
28 import org.apache.maven.plugin.MojoExecutionException;
29 import org.apache.maven.project.MavenProject;
30 import org.codehaus.plexus.util.xml.Xpp3Dom;
31
32 /**
33 * Deploys the generated site to a staging or mock directory to the site URL
34 * specified in the <code><distributionManagement></code> section of the
35 * POM, using <a href="/wagon/">wagon supported protocols</a>
36 *
37 * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
38 * @version $Id: SiteStageDeployMojo.html 816573 2012-05-08 12:11:59Z hboutemy $
39 * @goal stage-deploy
40 * @requiresDependencyResolution test
41 */
42 public class SiteStageDeployMojo
43 extends AbstractDeployMojo
44 {
45 /**
46 * The staged site will be deployed to this URL.
47 *
48 * If you don't specify this, the default-value will be
49 * "${project.distributionManagement.site.url}/staging", where "project" is
50 * either the current project or, in a reactor build, the top level project
51 * in the reactor.
52 * <p>
53 * Note that even if you specify this plugin parameter, you still need to indicate
54 * ${project.distributionManagement.site.url} at least in your top level project
55 * in order for relative links between modules to be resolved correctly.
56 * </p>
57 *
58 * @parameter expression="${stagingSiteURL}"
59 * @see <a href="http://maven.apache.org/maven-model/maven.html#class_site">MavenModel#class_site</a>
60 */
61 private String stagingSiteURL;
62
63 /**
64 * The identifier of the repository where the staging site will be deployed. This id will be used to lookup a
65 * corresponding <code><server></code> entry from the <code>settings.xml</code>. If a matching
66 * <code><server></code> entry is found, its configured credentials will be used for authentication.
67 *
68 * If this is not specified, then the corresponding value of <code>distributionManagement.site.id</code>
69 * will be taken as default, unless this is not defined either then the String
70 * <code>"stagingSite"</code> is used. (<strong>Note</strong>:
71 * until v. 2.3 and 3.0-beta-3 the String <code>"stagingSite"</code> is always used.)
72 *
73 * @parameter expression="${stagingRepositoryId}"
74 *
75 * @since 2.0.1
76 */
77 private String stagingRepositoryId;
78
79 @Override
80 /**
81 * Find the relative path between the distribution URLs of the parent that
82 * supplied the staging deploy URL and the current project.
83 *
84 * @return the relative path or "./" if the two URLs are the same.
85 *
86 * @throws MojoExecutionException
87 */
88 protected String getDeployModuleDirectory()
89 throws MojoExecutionException
90 {
91 // MSITE-602: If the user specified an explicit stagingSiteURL, use a special relative path
92 if( StringUtils.isNotEmpty( stagingSiteURL ) )
93 {
94 // We need to calculate the relative path between this project and
95 // the first one that supplied a stagingSiteURL
96 String relative = siteTool.getRelativePath( getSite( project ).getUrl(),
97 getSiteForTopMostParentWithStagingSiteURL( project ).getUrl() );
98
99 // SiteTool.getRelativePath() uses File.separatorChar,
100 // so we need to convert '\' to '/' in order for the URL to be valid for Windows users
101 relative = relative.replace( '\\', '/' );
102
103 getLog().debug( "The stagingSiteURL is configured, using special way to calculate relative path." );
104 return ( "".equals( relative ) ) ? "./" : relative;
105 }
106 else
107 {
108 getLog().debug( "No stagingSiteURL is configured, using standard way to calculate relative path." );
109 return super.getDeployModuleDirectory();
110 }
111 }
112
113 @Override
114 protected String getDeployRepositoryID()
115 throws MojoExecutionException
116 {
117 stagingRepositoryId = stagingRepoId( stagingRepositoryId );
118
119 getLog().info( "Using this server ID for stage deploy: " + stagingRepositoryId );
120
121 return stagingRepositoryId;
122 }
123
124 @Override
125 protected String getDeployRepositoryURL()
126 throws MojoExecutionException
127 {
128 String stagingURL = determineStagingSiteURL( stagingSiteURL );
129
130 getLog().info( "Using this base URL for stage deploy: " + stagingURL );
131
132 return stagingURL;
133 }
134
135 /**
136 * Extract the distributionManagement.site of the top most project in the
137 * hierarchy that specifies a stagingSiteURL, starting at the given
138 * MavenProject.
139 * <p/>
140 * This climbs up the project hierarchy and returns the site of the top most
141 * project for which
142 * {@link #getStagingSiteURL(org.apache.maven.project.MavenProject)} returns
143 * a URL.
144 *
145 * @param project the MavenProject. Not null.
146 * @return the site for the top most project that has a stagingSiteURL. Not null.
147 */
148 private Site getSiteForTopMostParentWithStagingSiteURL( MavenProject project )
149 {
150 Site site = project.getDistributionManagement().getSite();
151
152 MavenProject parent = project;
153
154 // @todo Should we check that the stagingSiteURL equals the one in this project instead of being non-empty?
155 while ( parent != null
156 && StringUtils.isNotEmpty( getStagingSiteURL( parent ) ) )
157 {
158 site = parent.getDistributionManagement().getSite();
159
160 // MSITE-585, MNG-1943
161 parent = siteTool.getParentProject( parent, reactorProjects, localRepository );
162 }
163
164 return site;
165 }
166
167 /**
168 * Extract the value of the stagingSiteURL configuration parameter of
169 * maven-site-plugin for the given project.
170 *
171 * @param project The MavenProject, not null
172 * @return The stagingSiteURL for the project, or null if it doesn't have one
173 */
174 private String getStagingSiteURL( MavenProject project )
175 {
176 final String sitePluginKey = "org.apache.maven.plugins:maven-site-plugin";
177
178 if ( project == null )
179 {
180 return null;
181 }
182
183 final Build build = project.getBuild();
184 if ( build == null )
185 {
186 return null;
187 }
188
189 Map<String, Plugin> plugins = build.getPluginsAsMap();
190
191 Plugin sitePlugin = plugins.get( sitePluginKey );
192 if ( sitePlugin == null )
193 {
194 final PluginManagement buildPluginManagement = build.getPluginManagement();
195 if ( buildPluginManagement == null )
196 {
197 return null;
198 }
199
200 plugins = buildPluginManagement.getPluginsAsMap();
201 sitePlugin = plugins.get( sitePluginKey );
202 }
203
204 if ( sitePlugin == null )
205 {
206 return null;
207 }
208
209 final Xpp3Dom sitePluginConfiguration = (Xpp3Dom) sitePlugin.getConfiguration();
210 if ( sitePluginConfiguration == null )
211 {
212 return null;
213 }
214
215 final Xpp3Dom child = sitePluginConfiguration.getChild( "stagingSiteURL" );
216 if ( child == null )
217 {
218 return null;
219 }
220 else
221 {
222 return child.getValue();
223 }
224 }
225
226 /**
227 * Find the URL where staging will take place.
228 *
229 * @param usersStagingSiteURL The staging site URL as suggested by the user's configuration
230 *
231 * @return the site URL for staging
232 */
233 private String determineStagingSiteURL( final String usersStagingSiteURL )
234 throws MojoExecutionException
235 {
236 String topLevelURL = null;
237
238 if ( usersStagingSiteURL != null )
239 {
240 // the user has specified a stagingSiteURL - use it
241 getLog().debug( "stagingSiteURL specified by the user: " + usersStagingSiteURL );
242 topLevelURL = usersStagingSiteURL;
243 }
244 else
245 {
246 // The user didn't specify a URL, use the top level site distribution URL and add "[/]staging/" to it
247 topLevelURL = appendSlash( getRootSite( project ).getUrl() )
248 + DEFAULT_STAGING_DIRECTORY;
249 getLog().debug( "stagingSiteURL NOT specified, using the top level project: " + topLevelURL );
250 }
251
252 // Return either
253 // usersURL
254 // or
255 // topLevelProjectURL + "staging"
256 return topLevelURL;
257 }
258
259 private String stagingRepoId( final String stagingRepoId )
260 {
261 if ( stagingRepoId != null )
262 {
263 return stagingRepoId;
264 }
265
266 try
267 {
268 return getSite( project ).getId();
269 }
270 catch ( MojoExecutionException ex )
271 {
272 return "stagingSite";
273 }
274 }
275 }