1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.impl.standalone;
20
21 import java.nio.file.Path;
22 import java.nio.file.Paths;
23 import java.time.Instant;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Objects;
31 import java.util.Optional;
32 import java.util.concurrent.ConcurrentHashMap;
33 import java.util.function.Consumer;
34 import java.util.stream.Collectors;
35
36 import org.apache.maven.api.Artifact;
37 import org.apache.maven.api.Lifecycle;
38 import org.apache.maven.api.MonotonicClock;
39 import org.apache.maven.api.Packaging;
40 import org.apache.maven.api.ProducedArtifact;
41 import org.apache.maven.api.Project;
42 import org.apache.maven.api.RemoteRepository;
43 import org.apache.maven.api.Session;
44 import org.apache.maven.api.Type;
45 import org.apache.maven.api.Version;
46 import org.apache.maven.api.annotations.Nonnull;
47 import org.apache.maven.api.annotations.Nullable;
48 import org.apache.maven.api.di.Provides;
49 import org.apache.maven.api.di.SessionScoped;
50 import org.apache.maven.api.model.PluginContainer;
51 import org.apache.maven.api.model.Profile;
52 import org.apache.maven.api.services.ArtifactManager;
53 import org.apache.maven.api.services.LifecycleRegistry;
54 import org.apache.maven.api.services.Lookup;
55 import org.apache.maven.api.services.MavenException;
56 import org.apache.maven.api.services.PackagingRegistry;
57 import org.apache.maven.api.services.RepositoryFactory;
58 import org.apache.maven.api.services.SettingsBuilder;
59 import org.apache.maven.api.services.TypeRegistry;
60 import org.apache.maven.api.settings.Settings;
61 import org.apache.maven.api.spi.TypeProvider;
62 import org.apache.maven.api.toolchain.ToolchainModel;
63 import org.apache.maven.di.Injector;
64 import org.apache.maven.di.Key;
65 import org.apache.maven.di.impl.DIException;
66 import org.apache.maven.impl.AbstractSession;
67 import org.apache.maven.impl.InternalSession;
68 import org.apache.maven.impl.di.SessionScope;
69 import org.apache.maven.impl.resolver.scopes.Maven4ScopeManagerConfiguration;
70 import org.eclipse.aether.DefaultRepositorySystemSession;
71 import org.eclipse.aether.RepositorySystem;
72 import org.eclipse.aether.RepositorySystemSession;
73 import org.eclipse.aether.internal.impl.scope.ScopeManagerImpl;
74 import org.eclipse.aether.repository.LocalRepository;
75 import org.eclipse.aether.repository.LocalRepositoryManager;
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 public class ApiRunner {
101
102
103
104
105
106
107 public static Session createSession() {
108 return createSession(null);
109 }
110
111
112
113
114
115
116
117 public static Session createSession(Consumer<Injector> injectorConsumer) {
118 return createSession(injectorConsumer, null);
119 }
120
121
122
123
124
125
126
127
128 public static Session createSession(Consumer<Injector> injectorConsumer, Path localRepo) {
129 Injector injector = Injector.create();
130 injector.bindInstance(Injector.class, injector);
131 injector.bindImplicit(ApiRunner.class);
132 injector.bindImplicit(RepositorySystemSupplier.class);
133 injector.bindInstance(LocalRepoProvider.class, () -> localRepo);
134 injector.discover(ApiRunner.class.getClassLoader());
135 if (injectorConsumer != null) {
136 injectorConsumer.accept(injector);
137 }
138 Session session = injector.getInstance(Session.class);
139 SessionScope scope = new SessionScope();
140 scope.enter();
141 scope.seed(Session.class, session);
142 injector.bindScope(SessionScoped.class, scope);
143 return session;
144 }
145
146
147
148
149 interface LocalRepoProvider {
150
151
152
153
154
155 Path getLocalRepo();
156 }
157
158
159
160
161 static class DefaultSession extends AbstractSession {
162
163 private final Map<String, String> systemProperties;
164 private final Instant startTime = MonotonicClock.now();
165
166 DefaultSession(RepositorySystemSession session, RepositorySystem repositorySystem, Lookup lookup) {
167 this(session, repositorySystem, Collections.emptyList(), null, lookup);
168 }
169
170 protected DefaultSession(
171 RepositorySystemSession session,
172 RepositorySystem repositorySystem,
173 List<RemoteRepository> repositories,
174 List<org.eclipse.aether.repository.RemoteRepository> resolverRepositories,
175 Lookup lookup) {
176 super(session, repositorySystem, repositories, resolverRepositories, lookup);
177 systemProperties = System.getenv().entrySet().stream()
178 .collect(Collectors.toMap(e -> "env." + e.getKey(), Map.Entry::getValue));
179 System.getProperties().forEach((k, v) -> systemProperties.put(k.toString(), v.toString()));
180 }
181
182 @Override
183 protected Session newSession(RepositorySystemSession session, List<RemoteRepository> repositories) {
184 return new DefaultSession(session, repositorySystem, repositories, null, lookup);
185 }
186
187 @Override
188 public Settings getSettings() {
189 return Settings.newInstance();
190 }
191
192 @Override
193 @Nonnull
194 public Collection<ToolchainModel> getToolchains() {
195 return List.of();
196 }
197
198 @Override
199 public Map<String, String> getUserProperties() {
200 return Map.of();
201 }
202
203 @Override
204 public Map<String, String> getSystemProperties() {
205 return systemProperties;
206 }
207
208 @Override
209 public Map<String, String> getEffectiveProperties(Project project) {
210 HashMap<String, String> result = new HashMap<>(getSystemProperties());
211 if (project != null) {
212 result.putAll(project.getModel().getProperties());
213 }
214 result.putAll(getUserProperties());
215 return result;
216 }
217
218 @Override
219 public Version getMavenVersion() {
220 return null;
221 }
222
223 @Override
224 public int getDegreeOfConcurrency() {
225 return 0;
226 }
227
228 @Override
229 public Instant getStartTime() {
230 return startTime;
231 }
232
233 @Override
234 public Path getTopDirectory() {
235 return null;
236 }
237
238 @Override
239 public Path getRootDirectory() {
240 throw new IllegalStateException();
241 }
242
243 @Override
244 public List<Project> getProjects() {
245 return List.of();
246 }
247
248 @Override
249 public Map<String, Object> getPluginContext(Project project) {
250 throw new UnsupportedInStandaloneModeException();
251 }
252 }
253
254 @Provides
255 @SuppressWarnings("unused")
256 static Lookup newLookup(Injector injector) {
257 return new Lookup() {
258 @Override
259 public <T> T lookup(Class<T> type) {
260 try {
261 return injector.getInstance(type);
262 } catch (DIException e) {
263 throw new MavenException("Unable to locate instance of type " + type, e);
264 }
265 }
266
267 @Override
268 public <T> T lookup(Class<T> type, String name) {
269 try {
270 return injector.getInstance(Key.of(type, name));
271 } catch (DIException e) {
272 throw new MavenException("Unable to locate instance of type " + type, e);
273 }
274 }
275
276 @Override
277 public <T> Optional<T> lookupOptional(Class<T> type) {
278 try {
279 return Optional.of(injector.getInstance(type));
280 } catch (DIException e) {
281 return Optional.empty();
282 }
283 }
284
285 @Override
286 public <T> Optional<T> lookupOptional(Class<T> type, String name) {
287 try {
288 return Optional.of(injector.getInstance(Key.of(type, name)));
289 } catch (DIException e) {
290 return Optional.empty();
291 }
292 }
293
294 @Override
295 public <T> List<T> lookupList(Class<T> type) {
296 return injector.getInstance(new Key<List<T>>() {});
297 }
298
299 @Override
300 public <T> Map<String, T> lookupMap(Class<T> type) {
301 return injector.getInstance(new Key<Map<String, T>>() {});
302 }
303 };
304 }
305
306 @Provides
307 @SuppressWarnings("unused")
308 static ArtifactManager newArtifactManager() {
309 return new ArtifactManager() {
310 private final Map<Artifact, Path> paths = new ConcurrentHashMap<>();
311
312 @Override
313 public Optional<Path> getPath(Artifact artifact) {
314 return Optional.ofNullable(paths.get(artifact));
315 }
316
317 @Override
318 public void setPath(ProducedArtifact artifact, Path path) {
319 paths.put(artifact, path);
320 }
321 };
322 }
323
324 @Provides
325 @SuppressWarnings("unused")
326 static PackagingRegistry newPackagingRegistry(TypeRegistry typeRegistry) {
327 return id -> Optional.of(new DumbPackaging(id, typeRegistry.require(id), Map.of()));
328 }
329
330 @Provides
331 @SuppressWarnings("unused")
332 static TypeRegistry newTypeRegistry(List<TypeProvider> providers) {
333 return new TypeRegistry() {
334 @Override
335 public Optional<Type> lookup(String id) {
336 return providers.stream()
337 .flatMap(p -> p.provides().stream())
338 .filter(t -> Objects.equals(id, t.id()))
339 .findAny();
340 }
341 };
342 }
343
344 @Provides
345 @SuppressWarnings("unused")
346 static LifecycleRegistry newLifecycleRegistry() {
347 return new LifecycleRegistry() {
348
349 @Override
350 public Iterator<Lifecycle> iterator() {
351 return Collections.emptyIterator();
352 }
353
354 @Override
355 public Optional<Lifecycle> lookup(String id) {
356 return Optional.empty();
357 }
358
359 @Override
360 public List<String> computePhases(Lifecycle lifecycle) {
361 return List.of();
362 }
363 };
364 }
365
366 @Provides
367 @SuppressWarnings("unused")
368 static Session newSession(RepositorySystem system, Lookup lookup, @Nullable LocalRepoProvider localRepoProvider) {
369 Map<String, String> properties = new HashMap<>();
370
371 System.getenv().forEach((k, v) -> properties.put("env." + k, v));
372
373 System.getProperties().forEach((k, v) -> properties.put(k.toString(), v.toString()));
374
375
376
377 properties.put("user.home", "target");
378
379 Path userHome = Paths.get(properties.get("user.home"));
380 Path mavenUserHome = userHome.resolve(".m2");
381 Path mavenSystemHome = properties.containsKey("maven.home")
382 ? Paths.get(properties.get("maven.home"))
383 : properties.containsKey("env.MAVEN_HOME") ? Paths.get(properties.get("env.MAVEN_HOME")) : null;
384
385 DefaultRepositorySystemSession rsession = new DefaultRepositorySystemSession(h -> false);
386 rsession.setScopeManager(new ScopeManagerImpl(Maven4ScopeManagerConfiguration.INSTANCE));
387 rsession.setSystemProperties(properties);
388 rsession.setConfigProperties(properties);
389
390 DefaultSession session = new DefaultSession(
391 rsession,
392 system,
393 List.of(lookup.lookup(RepositoryFactory.class)
394 .createRemote("central", "https://repo.maven.apache.org/maven2")),
395 null,
396 lookup);
397
398 Settings settings = session.getService(SettingsBuilder.class)
399 .build(
400 session,
401 mavenSystemHome != null ? mavenSystemHome.resolve("settings.xml") : null,
402 mavenUserHome.resolve("settings.xml"))
403 .getEffectiveSettings();
404
405
406 String localRepository = settings.getLocalRepository() != null
407 && !settings.getLocalRepository().isEmpty()
408 ? settings.getLocalRepository()
409 : localRepoProvider != null && localRepoProvider.getLocalRepo() != null
410 ? localRepoProvider.getLocalRepo().toString()
411 : mavenUserHome.resolve("repository").toString();
412 LocalRepositoryManager llm = system.newLocalRepositoryManager(rsession, new LocalRepository(localRepository));
413 rsession.setLocalRepositoryManager(llm);
414
415
416
417
418 Profile profile = session.getService(SettingsBuilder.class)
419 .convert(org.apache.maven.api.settings.Profile.newBuilder()
420 .repositories(settings.getRepositories())
421 .pluginRepositories(settings.getPluginRepositories())
422 .build());
423 RepositoryFactory repositoryFactory = session.getService(RepositoryFactory.class);
424 List<RemoteRepository> repositories = profile.getRepositories().stream()
425 .map(repositoryFactory::createRemote)
426 .toList();
427 InternalSession s = (InternalSession) session.withRemoteRepositories(repositories);
428 InternalSession.associate(rsession, s);
429 return s;
430
431
432
433
434
435
436
437
438
439 }
440
441 record DumbPackaging(String id, Type type, Map<String, PluginContainer> plugins) implements Packaging {}
442 }