1 package org.apache.maven.plugins.deploy;
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.util.List;
24 import java.util.Map;
25 import java.util.regex.Matcher;
26 import java.util.regex.Pattern;
27
28 import org.apache.maven.RepositoryUtils;
29 import org.apache.maven.artifact.ArtifactUtils;
30 import org.apache.maven.plugin.MojoExecutionException;
31 import org.apache.maven.plugin.MojoFailureException;
32 import org.apache.maven.plugin.descriptor.PluginDescriptor;
33 import org.apache.maven.plugins.annotations.LifecyclePhase;
34 import org.apache.maven.plugins.annotations.Mojo;
35 import org.apache.maven.plugins.annotations.Parameter;
36 import org.apache.maven.project.MavenProject;
37 import org.apache.maven.project.artifact.ProjectArtifact;
38 import org.apache.maven.project.artifact.ProjectArtifactMetadata;
39 import org.eclipse.aether.deployment.DeployRequest;
40 import org.eclipse.aether.repository.RemoteRepository;
41 import org.eclipse.aether.util.artifact.SubArtifact;
42
43
44
45
46
47
48
49 @Mojo( name = "deploy", defaultPhase = LifecyclePhase.DEPLOY, threadSafe = true )
50 public class DeployMojo
51 extends AbstractDeployMojo
52 {
53 private static final Pattern ALT_LEGACY_REPO_SYNTAX_PATTERN = Pattern.compile( "(.+?)::(.+?)::(.+)" );
54
55 private static final Pattern ALT_REPO_SYNTAX_PATTERN = Pattern.compile( "(.+?)::(.+)" );
56
57 @Parameter( defaultValue = "${project}", readonly = true, required = true )
58 private MavenProject project;
59
60 @Parameter( defaultValue = "${reactorProjects}", required = true, readonly = true )
61 private List<MavenProject> reactorProjects;
62
63 @Parameter( defaultValue = "${plugin}", required = true, readonly = true )
64 private PluginDescriptor pluginDescriptor;
65
66
67
68
69
70
71
72
73 @Parameter( defaultValue = "false", property = "deployAtEnd" )
74 private boolean deployAtEnd;
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 @Parameter( property = "altDeploymentRepository" )
91 private String altDeploymentRepository;
92
93
94
95
96
97
98
99
100
101
102 @Parameter( property = "altSnapshotDeploymentRepository" )
103 private String altSnapshotDeploymentRepository;
104
105
106
107
108
109
110
111
112
113
114 @Parameter( property = "altReleaseDeploymentRepository" )
115 private String altReleaseDeploymentRepository;
116
117
118
119
120
121
122
123
124
125
126
127
128 @Parameter( property = "maven.deploy.skip", defaultValue = "false" )
129 private String skip = Boolean.FALSE.toString();
130
131 private enum State
132 {
133 SKIPPED, DEPLOYED, TO_BE_DEPLOYED
134 }
135
136 private static final String DEPLOY_PROCESSED_MARKER = DeployMojo.class.getName() + ".processed";
137
138 private static final String DEPLOY_ALT_RELEASE_DEPLOYMENT_REPOSITORY =
139 DeployMojo.class.getName() + ".altReleaseDeploymentRepository";
140
141 private static final String DEPLOY_ALT_SNAPSHOT_DEPLOYMENT_REPOSITORY =
142 DeployMojo.class.getName() + ".altSnapshotDeploymentRepository";
143
144 private static final String DEPLOY_ALT_DEPLOYMENT_REPOSITORY =
145 DeployMojo.class.getName() + ".altDeploymentRepository";
146
147 private void putState( State state )
148 {
149 getPluginContext().put( DEPLOY_PROCESSED_MARKER, state.name() );
150 }
151
152 private void putPluginContextValue( String key, String value )
153 {
154 if ( value != null )
155 {
156 getPluginContext().put( key, value );
157 }
158 }
159
160 private String getPluginContextValue( Map<String, Object> pluginContext, String key )
161 {
162 return (String) pluginContext.get( key );
163 }
164
165 private State getState( Map<String, Object> pluginContext )
166 {
167 return State.valueOf( getPluginContextValue( pluginContext, DEPLOY_PROCESSED_MARKER ) );
168 }
169
170 private boolean hasState( MavenProject project )
171 {
172 Map<String, Object> pluginContext = session.getPluginContext( pluginDescriptor, project );
173 return pluginContext.containsKey( DEPLOY_PROCESSED_MARKER );
174 }
175
176 public void execute()
177 throws MojoExecutionException, MojoFailureException
178 {
179 if ( Boolean.parseBoolean( skip )
180 || ( "releases".equals( skip ) && !ArtifactUtils.isSnapshot( project.getVersion() ) )
181 || ( "snapshots".equals( skip ) && ArtifactUtils.isSnapshot( project.getVersion() ) )
182 )
183 {
184 getLog().info( "Skipping artifact deployment" );
185 putState( State.SKIPPED );
186 }
187 else
188 {
189 failIfOffline();
190 warnIfAffectedPackagingAndMaven( project.getPackaging() );
191
192 if ( !deployAtEnd )
193 {
194 deploy( session.getRepositorySession(),
195 processProject( project,
196 altSnapshotDeploymentRepository, altReleaseDeploymentRepository, altDeploymentRepository ) );
197 putState( State.DEPLOYED );
198 }
199 else
200 {
201 putPluginContextValue( DEPLOY_ALT_RELEASE_DEPLOYMENT_REPOSITORY, altReleaseDeploymentRepository );
202 putPluginContextValue( DEPLOY_ALT_SNAPSHOT_DEPLOYMENT_REPOSITORY, altSnapshotDeploymentRepository );
203 putPluginContextValue( DEPLOY_ALT_DEPLOYMENT_REPOSITORY, altDeploymentRepository );
204 putState( State.TO_BE_DEPLOYED );
205 getLog().info( "Deferring deploy for " + project.getGroupId()
206 + ":" + project.getArtifactId() + ":" + project.getVersion() + " at end" );
207 }
208 }
209
210 if ( allProjectsMarked() )
211 {
212 for ( MavenProject reactorProject : reactorProjects )
213 {
214 Map<String, Object> pluginContext = session.getPluginContext( pluginDescriptor, reactorProject );
215 State state = getState( pluginContext );
216 if ( state == State.TO_BE_DEPLOYED )
217 {
218 String altReleaseDeploymentRepository =
219 getPluginContextValue( pluginContext, DEPLOY_ALT_RELEASE_DEPLOYMENT_REPOSITORY );
220 String altSnapshotDeploymentRepository =
221 getPluginContextValue( pluginContext, DEPLOY_ALT_SNAPSHOT_DEPLOYMENT_REPOSITORY );
222 String altDeploymentRepository =
223 getPluginContextValue( pluginContext, DEPLOY_ALT_DEPLOYMENT_REPOSITORY );
224
225 deploy( session.getRepositorySession(),
226 processProject( reactorProject,
227 altSnapshotDeploymentRepository, altReleaseDeploymentRepository, altDeploymentRepository )
228 );
229 }
230 }
231 }
232 }
233
234 private boolean allProjectsMarked()
235 {
236 for ( MavenProject reactorProject : reactorProjects )
237 {
238 if ( !hasState( reactorProject ) )
239 {
240 return false;
241 }
242 }
243 return true;
244 }
245
246 private DeployRequest processProject( final MavenProject project,
247 final String altSnapshotDeploymentRepository,
248 final String altReleaseDeploymentRepository,
249 final String altDeploymentRepository )
250 throws MojoExecutionException, MojoFailureException
251 {
252 DeployRequest request = new DeployRequest();
253 request.setRepository( getDeploymentRepository( project,
254 altSnapshotDeploymentRepository, altReleaseDeploymentRepository, altDeploymentRepository ) );
255
256 org.apache.maven.artifact.Artifact mavenMainArtifact = project.getArtifact();
257 String packaging = project.getPackaging();
258 File pomFile = project.getFile();
259 boolean isPomArtifact = "pom".equals( packaging );
260 boolean pomArtifactAttached = false;
261
262 if ( pomFile != null )
263 {
264 request.addArtifact( RepositoryUtils.toArtifact( new ProjectArtifact( project ) ) );
265 pomArtifactAttached = true;
266 }
267
268 if ( !isPomArtifact )
269 {
270 File file = mavenMainArtifact.getFile();
271 if ( file != null && file.isFile() )
272 {
273 org.eclipse.aether.artifact.Artifact mainArtifact = RepositoryUtils.toArtifact( mavenMainArtifact );
274 request.addArtifact( mainArtifact );
275
276 if ( !pomArtifactAttached )
277 {
278 for ( Object metadata : mavenMainArtifact.getMetadataList() )
279 {
280 if ( metadata instanceof ProjectArtifactMetadata )
281 {
282 request.addArtifact( new SubArtifact(
283 mainArtifact,
284 "",
285 "pom"
286 ).setFile( ( (ProjectArtifactMetadata) metadata ).getFile() ) );
287 pomArtifactAttached = true;
288 }
289 }
290 }
291 }
292 else if ( !project.getAttachedArtifacts().isEmpty() )
293 {
294 throw new MojoExecutionException( "The packaging plugin for this project did not assign "
295 + "a main file to the project but it has attachments. Change packaging to 'pom'." );
296 }
297 else
298 {
299 throw new MojoExecutionException( "The packaging for this project did not assign "
300 + "a file to the build artifact" );
301 }
302 }
303
304 if ( !pomArtifactAttached )
305 {
306 throw new MojoExecutionException( "The POM could not be attached" );
307 }
308
309 for ( org.apache.maven.artifact.Artifact attached : project.getAttachedArtifacts() )
310 {
311 getLog().debug( "Attaching for install: " + attached.getId() );
312 request.addArtifact( RepositoryUtils.toArtifact( attached ) );
313 }
314
315 return request;
316 }
317
318
319
320
321 RemoteRepository getDeploymentRepository( final MavenProject project,
322 final String altSnapshotDeploymentRepository,
323 final String altReleaseDeploymentRepository,
324 final String altDeploymentRepository )
325
326 throws MojoExecutionException, MojoFailureException
327 {
328 RemoteRepository repo = null;
329
330 String altDeploymentRepo;
331 if ( ArtifactUtils.isSnapshot( project.getVersion() ) && altSnapshotDeploymentRepository != null )
332 {
333 altDeploymentRepo = altSnapshotDeploymentRepository;
334 }
335 else if ( !ArtifactUtils.isSnapshot( project.getVersion() ) && altReleaseDeploymentRepository != null )
336 {
337 altDeploymentRepo = altReleaseDeploymentRepository;
338 }
339 else
340 {
341 altDeploymentRepo = altDeploymentRepository;
342 }
343
344 if ( altDeploymentRepo != null )
345 {
346 getLog().info( "Using alternate deployment repository " + altDeploymentRepo );
347
348 Matcher matcher = ALT_LEGACY_REPO_SYNTAX_PATTERN.matcher( altDeploymentRepo );
349
350 if ( matcher.matches() )
351 {
352 String id = matcher.group( 1 ).trim();
353 String layout = matcher.group( 2 ).trim();
354 String url = matcher.group( 3 ).trim();
355
356 if ( "default".equals( layout ) )
357 {
358 getLog().warn( "Using legacy syntax for alternative repository. "
359 + "Use \"" + id + "::" + url + "\" instead." );
360 repo = getRemoteRepository( id, url );
361 }
362 else
363 {
364 throw new MojoFailureException( altDeploymentRepo,
365 "Invalid legacy syntax and layout for repository.",
366 "Invalid legacy syntax and layout for alternative repository. Use \""
367 + id + "::" + url + "\" instead, and only default layout is supported."
368 );
369 }
370 }
371 else
372 {
373 matcher = ALT_REPO_SYNTAX_PATTERN.matcher( altDeploymentRepo );
374
375 if ( !matcher.matches() )
376 {
377 throw new MojoFailureException( altDeploymentRepo,
378 "Invalid syntax for repository.",
379 "Invalid syntax for alternative repository. Use \"id::url\"."
380 );
381 }
382 else
383 {
384 String id = matcher.group( 1 ).trim();
385 String url = matcher.group( 2 ).trim();
386
387 repo = getRemoteRepository( id, url );
388 }
389 }
390 }
391
392 if ( repo == null )
393 {
394 repo = RepositoryUtils.toRepo( project.getDistributionManagementArtifactRepository() );
395 }
396
397 if ( repo == null )
398 {
399 String msg = "Deployment failed: repository element was not specified in the POM inside"
400 + " distributionManagement element or in -DaltDeploymentRepository=id::url parameter";
401
402 throw new MojoExecutionException( msg );
403 }
404
405 return repo;
406 }
407
408 }