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