1 package org.apache.maven.shared.verifier;
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.io.FileInputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.PrintStream;
27 import java.lang.reflect.Constructor;
28 import java.lang.reflect.InvocationTargetException;
29 import java.lang.reflect.Method;
30 import java.net.MalformedURLException;
31 import java.net.URL;
32 import java.net.URLClassLoader;
33 import java.nio.file.Files;
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.Properties;
37
38 import org.apache.maven.shared.utils.io.IOUtil;
39
40
41
42
43
44
45 class Embedded3xLauncher
46 implements MavenLauncher
47 {
48
49 private final Object mavenCli;
50
51 private final Method doMain;
52
53 private Embedded3xLauncher( Object mavenCli, Method doMain )
54 {
55 this.mavenCli = mavenCli;
56 this.doMain = doMain;
57 }
58
59
60
61
62 public static Embedded3xLauncher createFromMavenHome( String mavenHome, String classworldConf, List<URL> classpath )
63 throws LauncherException
64 {
65 if ( mavenHome == null || mavenHome.length() <= 0 )
66 {
67 throw new LauncherException( "Invalid Maven home directory " + mavenHome );
68 }
69
70 System.setProperty( "maven.home", mavenHome );
71
72 File config;
73 if ( classworldConf != null )
74 {
75 config = new File( classworldConf );
76 }
77 else
78 {
79 config = new File( mavenHome, "bin/m2.conf" );
80 }
81
82 ClassLoader bootLoader = getBootLoader( mavenHome, classpath );
83
84 ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
85 Thread.currentThread().setContextClassLoader( bootLoader );
86 try
87 {
88 Class<?> launcherClass = bootLoader.loadClass( "org.codehaus.plexus.classworlds.launcher.Launcher" );
89
90 Object launcher = launcherClass.newInstance();
91
92 Method configure = launcherClass.getMethod( "configure", new Class[] { InputStream.class } );
93
94 configure.invoke( launcher, new Object[] { new FileInputStream( config ) } );
95
96 Method getWorld = launcherClass.getMethod( "getWorld" );
97 Object classWorld = getWorld.invoke( launcher );
98
99 Method getMainClass = launcherClass.getMethod( "getMainClass" );
100 Class<?> cliClass = (Class<?>) getMainClass.invoke( launcher );
101
102 Constructor<?> newMavenCli = cliClass.getConstructor( new Class[] { classWorld.getClass() } );
103 Object mavenCli = newMavenCli.newInstance( new Object[] { classWorld } );
104
105 Class<?>[] parameterTypes = { String[].class, String.class, PrintStream.class, PrintStream.class };
106 Method doMain = cliClass.getMethod( "doMain", parameterTypes );
107
108 return new Embedded3xLauncher( mavenCli, doMain );
109 }
110 catch ( ReflectiveOperationException | IOException e )
111 {
112 throw new LauncherException( "Failed to initialize Laucher", e );
113 }
114 finally
115 {
116 Thread.currentThread().setContextClassLoader( oldClassLoader );
117 }
118 }
119
120
121
122
123
124 public static Embedded3xLauncher createFromClasspath()
125 throws LauncherException
126 {
127 ClassLoader coreLoader = Thread.currentThread().getContextClassLoader();
128
129 try
130 {
131 Class<?> cliClass = coreLoader.loadClass( "org.apache.maven.cli.MavenCli" );
132
133 Object mavenCli = cliClass.newInstance();
134
135 Class<?>[] parameterTypes = { String[].class, String.class, PrintStream.class, PrintStream.class };
136 Method doMain = cliClass.getMethod( "doMain", parameterTypes );
137
138 return new Embedded3xLauncher( mavenCli, doMain );
139 }
140 catch ( ReflectiveOperationException e )
141 {
142 throw new LauncherException( "Failed to initialize Laucher", e );
143 }
144 }
145
146 private static ClassLoader getBootLoader( String mavenHome, List<URL> classpath )
147 {
148 List<URL> urls = classpath;
149
150 if ( urls == null )
151 {
152 urls = new ArrayList<>();
153
154 File bootDir = new File( mavenHome, "boot" );
155 addUrls( urls, bootDir );
156 }
157
158 if ( urls.isEmpty() )
159 {
160 throw new IllegalArgumentException( "Invalid Maven home directory " + mavenHome );
161 }
162
163 URL[] ucp = urls.toArray( new URL[0] );
164
165 return new URLClassLoader( ucp, ClassLoader.getSystemClassLoader().getParent() );
166 }
167
168 private static void addUrls( List<URL> urls, File directory )
169 {
170 File[] jars = directory.listFiles();
171
172 if ( jars != null )
173 {
174 for ( int i = 0; i < jars.length; i++ )
175 {
176 File jar = jars[i];
177
178 if ( jar.getName().endsWith( ".jar" ) )
179 {
180 try
181 {
182 urls.add( jar.toURI().toURL() );
183 }
184 catch ( MalformedURLException e )
185 {
186 throw (RuntimeException) new IllegalStateException().initCause( e );
187 }
188 }
189 }
190 }
191 }
192
193 public int run( String[] cliArgs, Properties systemProperties, String workingDirectory, File logFile )
194 throws IOException, LauncherException
195 {
196 PrintStream out = ( logFile != null )
197 ? new PrintStream( Files.newOutputStream( logFile.toPath() ) ) : System.out;
198 try
199 {
200 File workingDirectoryPath = new File( workingDirectory );
201 Properties originalProperties = System.getProperties();
202 System.setProperties( null );
203 System.setProperty( "maven.home", originalProperties.getProperty( "maven.home", "" ) );
204 System.setProperty( "user.dir", workingDirectoryPath.getAbsolutePath() );
205 System.setProperty( "maven.multiModuleProjectDirectory",
206 findProjectBaseDirectory( workingDirectoryPath ).getAbsolutePath() );
207
208 for ( Object o : systemProperties.keySet() )
209 {
210 String key = (String) o;
211 String value = systemProperties.getProperty( key );
212 System.setProperty( key, value );
213 }
214
215 ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
216 Thread.currentThread().setContextClassLoader( mavenCli.getClass().getClassLoader() );
217 try
218 {
219 Object result = doMain.invoke( mavenCli, new Object[] { cliArgs, workingDirectory, out, out } );
220
221 return ( (Number) result ).intValue();
222 }
223 finally
224 {
225 Thread.currentThread().setContextClassLoader( originalClassLoader );
226
227 System.setProperties( originalProperties );
228 }
229 }
230 catch ( IllegalAccessException | InvocationTargetException e )
231 {
232 throw new LauncherException( "Failed to run Maven", e );
233 }
234 finally
235 {
236 if ( logFile != null )
237 {
238 out.close();
239 }
240 }
241 }
242
243 public String getMavenVersion()
244 throws LauncherException
245 {
246 Properties props = new Properties();
247
248 InputStream is =
249 mavenCli.getClass().getResourceAsStream( "/META-INF/maven/org.apache.maven/maven-core/pom.properties" );
250 if ( is != null )
251 {
252 try
253 {
254 props.load( is );
255 }
256 catch ( IOException e )
257 {
258 throw new LauncherException( "Failed to read Maven version", e );
259 }
260 finally
261 {
262 IOUtil.close( is );
263 }
264 }
265
266 String version = props.getProperty( "version" );
267 if ( version != null )
268 {
269 return version;
270 }
271
272 throw new LauncherException( "Could not determine embedded Maven version" );
273 }
274
275
276
277
278
279
280
281 private static File findProjectBaseDirectory( File workingDirectory )
282 {
283 File currentDirectory = workingDirectory;
284
285
286 while ( currentDirectory != null && currentDirectory.getParentFile() != null )
287 {
288
289 if ( new File( currentDirectory, ".mvn" ).isDirectory() )
290 {
291 return currentDirectory;
292 }
293 currentDirectory = currentDirectory.getParentFile();
294 }
295 return workingDirectory;
296 }
297 }