1 package org.apache.maven.plugins.wrapper;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
23
24 import javax.inject.Inject;
25
26 import java.io.BufferedWriter;
27 import java.io.File;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.nio.charset.StandardCharsets;
31 import java.nio.file.DirectoryStream;
32 import java.nio.file.Files;
33 import java.nio.file.Path;
34 import java.util.Locale;
35 import java.util.Map;
36 import java.util.Properties;
37
38 import org.apache.maven.Maven;
39 import org.apache.maven.artifact.Artifact;
40 import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
41 import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
42 import org.apache.maven.execution.MavenExecutionRequest;
43 import org.apache.maven.execution.MavenSession;
44 import org.apache.maven.plugin.AbstractMojo;
45 import org.apache.maven.plugin.MojoExecutionException;
46 import org.apache.maven.plugin.MojoFailureException;
47 import org.apache.maven.plugins.annotations.Mojo;
48 import org.apache.maven.plugins.annotations.Parameter;
49 import org.apache.maven.repository.RepositorySystem;
50 import org.apache.maven.settings.Mirror;
51 import org.apache.maven.settings.Settings;
52 import org.codehaus.plexus.archiver.UnArchiver;
53 import org.codehaus.plexus.components.io.fileselectors.FileInfo;
54 import org.codehaus.plexus.components.io.fileselectors.FileSelector;
55
56
57
58
59
60
61
62 @Mojo( name = "wrapper", aggregator = true, requiresDirectInvocation = true )
63 public class WrapperMojo
64 extends AbstractMojo
65 {
66 private static final String MVNW_REPOURL = "MVNW_REPOURL";
67
68 private static final String DEFAULT_REPOURL = "https://repo.maven.apache.org/maven2";
69
70
71
72
73
74
75
76 @Parameter( property = "maven" )
77 private String mavenVersion;
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 @Parameter( defaultValue = "bin", property = "type" )
93 private String distributionType;
94
95
96
97
98 @Parameter( defaultValue = "false", property = "includeDebug" )
99 private boolean includeDebugScript;
100
101
102
103 @Parameter( defaultValue = "${session}", readonly = true, required = true )
104 private MavenSession session;
105
106 @Parameter( defaultValue = "${settings}", readonly = true, required = true )
107 private Settings settings;
108
109
110 @Parameter( defaultValue = "${project.basedir}", readonly = true, required = true )
111 private File basedir;
112
113
114
115 private static final String WRAPPER_DISTRIBUTION_GROUP_ID = "org.apache.maven.wrapper";
116
117 private static final String WRAPPER_DISTRIBUTION_ARTIFACT_ID = "maven-wrapper-distribution";
118
119 private static final String WRAPPER_DISTRIBUTION_EXTENSION = "zip";
120
121
122
123 @Inject
124 private RepositorySystem repositorySystem;
125
126 @Inject
127 private Map<String, UnArchiver> unarchivers;
128
129 @Override
130 public void execute()
131 throws MojoExecutionException, MojoFailureException
132 {
133 mavenVersion = getVersion( mavenVersion, Maven.class, "org.apache.maven/maven-core" );
134 String wrapperVersion = getVersion( null, this.getClass(), "org.apache.maven.plugins/maven-wrapper-plugin" );
135
136 final Artifact artifact = downloadWrapperDistribution( wrapperVersion );
137 final Path wrapperDir = createDirectories( basedir.toPath().resolve( ".mvn/wrapper" ) );
138
139 cleanup( wrapperDir );
140 unpack( artifact, basedir.toPath() );
141 replaceProperties( wrapperVersion, wrapperDir );
142 }
143
144 private Path createDirectories( Path dir )
145 throws MojoExecutionException
146 {
147 try
148 {
149 return Files.createDirectories( dir );
150 }
151 catch ( IOException ioe )
152 {
153 throw new MojoExecutionException( ioe.getMessage(), ioe );
154 }
155 }
156
157 private void cleanup( Path wrapperDir )
158 throws MojoExecutionException
159 {
160 try ( DirectoryStream<Path> dsClass = Files.newDirectoryStream( wrapperDir, "*.class" ) )
161 {
162 for ( Path file : dsClass )
163 {
164
165 Files.deleteIfExists( file );
166 }
167 Files.deleteIfExists( wrapperDir.resolve( "MavenWrapperDownloader.java" ) );
168 Files.deleteIfExists( wrapperDir.resolve( "maven-wrapper.jar" ) );
169 }
170 catch ( IOException ioe )
171 {
172 throw new MojoExecutionException( ioe.getMessage(), ioe );
173 }
174 }
175
176 private Artifact downloadWrapperDistribution( String wrapperVersion )
177 throws MojoExecutionException
178 {
179 Artifact artifact =
180 repositorySystem.createArtifactWithClassifier( WRAPPER_DISTRIBUTION_GROUP_ID,
181 WRAPPER_DISTRIBUTION_ARTIFACT_ID, wrapperVersion,
182 WRAPPER_DISTRIBUTION_EXTENSION, distributionType );
183
184 MavenExecutionRequest executionRequest = session.getRequest();
185
186 ArtifactResolutionRequest resolutionRequest = new ArtifactResolutionRequest()
187 .setArtifact( artifact )
188 .setLocalRepository( session.getLocalRepository() )
189 .setRemoteRepositories( session.getCurrentProject().getPluginArtifactRepositories() )
190 .setOffline( executionRequest.isOffline() )
191 .setForceUpdate( executionRequest.isUpdateSnapshots() );
192
193 ArtifactResolutionResult resolveResult = repositorySystem.resolve( resolutionRequest );
194
195 if ( !resolveResult.isSuccess() )
196 {
197 if ( executionRequest.isShowErrors() )
198 {
199 for ( Exception e : resolveResult.getExceptions() )
200 {
201 getLog().error( e.getMessage(), e );
202 }
203 }
204 throw new MojoExecutionException( "artifact: " + artifact + " not resolved." );
205 }
206
207 return artifact;
208 }
209
210 private void unpack( Artifact artifact, Path targetFolder )
211 {
212 UnArchiver unarchiver = unarchivers.get( WRAPPER_DISTRIBUTION_EXTENSION );
213 unarchiver.setDestDirectory( targetFolder.toFile() );
214 unarchiver.setSourceFile( artifact.getFile() );
215 if ( !includeDebugScript )
216 {
217 unarchiver.setFileSelectors( new FileSelector[] { new FileSelector()
218 {
219 @Override
220 public boolean isSelected( FileInfo fileInfo )
221 {
222 return !fileInfo.getName().contains( "Debug" );
223 }
224 } } );
225 }
226 unarchiver.extract();
227 getLog().info( "Unpacked " + buffer().strong( distributionType ) + " type wrapper distribution " + artifact );
228 }
229
230
231
232
233
234
235
236
237
238 private void replaceProperties( String wrapperVersion, Path targetFolder )
239 throws MojoExecutionException
240 {
241 String repoUrl = getRepoUrl();
242
243 String distributionUrl =
244 repoUrl + "/org/apache/maven/apache-maven/" + mavenVersion + "/apache-maven-" + mavenVersion + "-bin.zip";
245 String wrapperUrl = repoUrl + "/org/apache/maven/wrapper/maven-wrapper/" + wrapperVersion + "/maven-wrapper-"
246 + wrapperVersion + ".jar";
247
248 Path wrapperPropertiesFile = targetFolder.resolve( "maven-wrapper.properties" );
249
250 getLog().info( "Configuring .mvn/wrapper/maven-wrapper.properties to use "
251 + buffer().strong( "Maven " + mavenVersion ) + " and download from " + repoUrl );
252
253 final String license = "# Licensed to the Apache Software Foundation (ASF) under one%n"
254 + "# or more contributor license agreements. See the NOTICE file%n"
255 + "# distributed with this work for additional information%n"
256 + "# regarding copyright ownership. The ASF licenses this file%n"
257 + "# to you under the Apache License, Version 2.0 (the%n"
258 + "# \"License\"); you may not use this file except in compliance%n"
259 + "# with the License. You may obtain a copy of the License at%n"
260 + "#%n"
261 + "# https://www.apache.org/licenses/LICENSE-2.0%n"
262 + "#%n"
263 + "# Unless required by applicable law or agreed to in writing,%n"
264 + "# software distributed under the License is distributed on an%n"
265 + "# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY%n"
266 + "# KIND, either express or implied. See the License for the%n"
267 + "# specific language governing permissions and limitations%n"
268 + "# under the License.%n";
269
270 try ( BufferedWriter out = Files.newBufferedWriter( wrapperPropertiesFile, StandardCharsets.UTF_8 ) )
271 {
272 out.append( String.format( Locale.ROOT, license ) );
273 out.append( "distributionUrl=" + distributionUrl + System.lineSeparator() );
274 out.append( "wrapperUrl=" + wrapperUrl + System.lineSeparator() );
275 }
276 catch ( IOException ioe )
277 {
278 throw new MojoExecutionException( "Can't create maven-wrapper.properties", ioe );
279 }
280 }
281
282 private String getVersion( String defaultVersion, Class<?> clazz, String path )
283 {
284 String version = defaultVersion;
285 if ( version == null )
286 {
287 Properties props = new Properties();
288 try ( InputStream is = clazz.getResourceAsStream( "/META-INF/maven/" + path + "/pom.properties" ) )
289 {
290 if ( is != null )
291 {
292 props.load( is );
293 version = props.getProperty( "version" );
294 }
295 }
296 catch ( IOException e )
297 {
298
299 }
300 }
301 return version;
302 }
303
304
305
306
307 private String getRepoUrl()
308 {
309
310 String repoUrl = DEFAULT_REPOURL;
311
312
313 String mvnwRepoUrl = System.getenv( MVNW_REPOURL );
314 if ( mvnwRepoUrl != null && !mvnwRepoUrl.isEmpty() )
315 {
316 repoUrl = mvnwRepoUrl;
317 getLog().debug( "Using repo URL from " + MVNW_REPOURL + " environment variable." );
318 }
319
320 else if ( settings.getMirrors() != null && !settings.getMirrors().isEmpty() )
321 {
322 for ( Mirror current : settings.getMirrors() )
323 {
324 if ( "*".equals( current.getMirrorOf() ) )
325 {
326 repoUrl = current.getUrl();
327 break;
328 }
329 }
330 getLog().debug( "Using repo URL from * mirror in settings file." );
331 }
332
333 getLog().debug( "Determined repo URL to use as " + repoUrl );
334
335 return repoUrl;
336 }
337 }