-
Notifications
You must be signed in to change notification settings - Fork 39
/
InstallMojo.java
245 lines (214 loc) · 10.2 KB
/
InstallMojo.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.plugins.install;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.apache.maven.RepositoryUtils;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginExecution;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.artifact.ProjectArtifact;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.installation.InstallRequest;
import org.eclipse.aether.installation.InstallationException;
import org.eclipse.aether.util.artifact.ArtifactIdUtils;
/**
* Installs the project's main artifact, and any other artifacts attached by other plugins in the lifecycle, to the
* local repository.
*
* @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
*/
@Mojo(name = "install", defaultPhase = LifecyclePhase.INSTALL, threadSafe = true)
public class InstallMojo extends AbstractMojo {
@Component
private RepositorySystem repositorySystem;
@Parameter(defaultValue = "${session}", required = true, readonly = true)
private MavenSession session;
@Parameter(defaultValue = "${project}", readonly = true, required = true)
private MavenProject project;
@Parameter(defaultValue = "${plugin}", required = true, readonly = true)
private PluginDescriptor pluginDescriptor;
/**
* Whether every project should be installed during its own install-phase or at the end of the multimodule build. If
* set to {@code true} and the build fails, none of the reactor projects is installed.
* <strong>(experimental)</strong>
*
* @since 2.5
*/
@Parameter(defaultValue = "false", property = "installAtEnd")
private boolean installAtEnd;
/**
* Set this to <code>true</code> to bypass artifact installation. Use this for artifacts that do not need to be
* installed in the local repository.
*
* @since 2.4
*/
@Parameter(property = "maven.install.skip", defaultValue = "false")
private boolean skip;
/**
* Set this to <code>true</code> to allow incomplete project processing. By default, such projects are forbidden
* and Mojo will fail to process them. Incomplete project is a Maven Project that has any other packaging than
* "pom" and has no main artifact packaged. In the majority of cases, what user really wants here is a project
* with "pom" packaging and some classified artifact attached (typical example is some assembly being packaged
* and attached with classifier).
*
* @since 3.1.1
*/
@Parameter(defaultValue = "false", property = "allowIncompleteProjects")
private boolean allowIncompleteProjects;
private enum State {
SKIPPED,
INSTALLED,
TO_BE_INSTALLED
}
private static final String INSTALL_PROCESSED_MARKER = InstallMojo.class.getName() + ".processed";
private void putState(State state) {
getPluginContext().put(INSTALL_PROCESSED_MARKER, state.name());
}
private State getState(MavenProject project) {
Map<String, Object> pluginContext = session.getPluginContext(pluginDescriptor, project);
return State.valueOf((String) pluginContext.get(INSTALL_PROCESSED_MARKER));
}
private boolean hasState(MavenProject project) {
Map<String, Object> pluginContext = session.getPluginContext(pluginDescriptor, project);
return pluginContext.containsKey(INSTALL_PROCESSED_MARKER);
}
@Override
public void execute() throws MojoExecutionException {
if (skip) {
getLog().info("Skipping artifact installation");
putState(State.SKIPPED);
} else {
if (installAtEnd) {
getLog().info("Deferring install for " + project.getGroupId() + ":" + project.getArtifactId() + ":"
+ project.getVersion() + " at end");
putState(State.TO_BE_INSTALLED);
} else {
InstallRequest request = new InstallRequest();
processProject(project, request);
installProject(request);
putState(State.INSTALLED);
}
}
List<MavenProject> allProjectsUsingPlugin = getAllProjectsUsingPlugin();
if (allProjectsMarked(allProjectsUsingPlugin)) {
InstallRequest request = new InstallRequest();
for (MavenProject reactorProject : allProjectsUsingPlugin) {
State state = getState(reactorProject);
if (state == State.TO_BE_INSTALLED) {
processProject(reactorProject, request);
}
}
installProject(request);
}
}
private boolean allProjectsMarked(List<MavenProject> allProjectsUsingPlugin) {
return allProjectsUsingPlugin.stream().allMatch(this::hasState);
}
private final Predicate<MavenProject> hasMavenInstallPluginExecution =
rp -> hasExecution(rp.getPlugin("org.apache.maven.plugins:maven-install-plugin"));
private List<MavenProject> getAllProjectsUsingPlugin() {
return session.getProjects().stream()
.filter(hasMavenInstallPluginExecution)
.collect(Collectors.toList());
}
private final Predicate<PluginExecution> havingGoals = pe -> !pe.getGoals().isEmpty();
private final Predicate<PluginExecution> nonePhase = pe -> !"none".equalsIgnoreCase(pe.getPhase());
private boolean hasExecution(Plugin plugin) {
if (plugin == null) {
return false;
}
return plugin.getExecutions().stream().filter(havingGoals).anyMatch(nonePhase);
}
private void installProject(InstallRequest request) throws MojoExecutionException {
try {
repositorySystem.install(session.getRepositorySession(), request);
} catch (InstallationException e) {
throw new MojoExecutionException(e.getMessage(), e);
}
}
/**
* Processes passed in {@link MavenProject} and prepares content of {@link InstallRequest} out of it.
*
* @throws MojoExecutionException if project is badly set up.
*/
private void processProject(MavenProject project, InstallRequest request) throws MojoExecutionException {
// always exists, as project exists
Artifact pomArtifact = RepositoryUtils.toArtifact(new ProjectArtifact(project));
// always exists, but at "init" is w/o file (packaging plugin assigns file to this when packaged)
Artifact projectArtifact = RepositoryUtils.toArtifact(project.getArtifact());
// pom project: pomArtifact and projectArtifact are SAME
// jar project: pomArtifact and projectArtifact are DIFFERENT
// incomplete project: is not pom project and projectArtifact has no file
// we must compare coordinates ONLY (as projectArtifact may not have file, and Artifact.equals factors it in)
// BUT if projectArtifact has file set, use that one
if (ArtifactIdUtils.equalsId(pomArtifact, projectArtifact)) {
if (isFile(projectArtifact.getFile())) {
pomArtifact = projectArtifact;
}
projectArtifact = null;
}
if (isFile(pomArtifact.getFile())) {
request.addArtifact(pomArtifact);
} else {
throw new MojoExecutionException("The project POM could not be attached");
}
// is not packaged, is "incomplete"
boolean isIncomplete = projectArtifact != null && !isFile(projectArtifact.getFile());
if (projectArtifact != null) {
if (!isIncomplete) {
request.addArtifact(projectArtifact);
} else if (!project.getAttachedArtifacts().isEmpty()) {
if (allowIncompleteProjects) {
getLog().warn("");
getLog().warn("The packaging plugin for this project did not assign");
getLog().warn("a main file to the project but it has attachments. Change packaging to 'pom'.");
getLog().warn("");
getLog().warn("Incomplete projects like this will fail in future Maven versions!");
getLog().warn("");
} else {
throw new MojoExecutionException("The packaging plugin for this project did not assign "
+ "a main file to the project but it has attachments. Change packaging to 'pom'.");
}
} else {
throw new MojoExecutionException(
"The packaging for this project did not assign a file to the build artifact");
}
}
for (org.apache.maven.artifact.Artifact attached : project.getAttachedArtifacts()) {
getLog().debug("Attaching for install: " + attached.getId());
request.addArtifact(RepositoryUtils.toArtifact(attached));
}
}
private boolean isFile(File file) {
return file != null && file.isFile();
}
}