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.Project;
38 import org.apache.maven.api.RemoteRepository;
39 import org.apache.maven.api.Session;
40 import org.apache.maven.api.Type;
41 import org.apache.maven.api.Version;
42 import org.apache.maven.api.di.Provides;
43 import org.apache.maven.api.model.PluginContainer;
44 import org.apache.maven.api.model.Profile;
45 import org.apache.maven.api.services.ArtifactManager;
46 import org.apache.maven.api.services.LifecycleRegistry;
47 import org.apache.maven.api.services.Lookup;
48 import org.apache.maven.api.services.MavenException;
49 import org.apache.maven.api.services.PackagingRegistry;
50 import org.apache.maven.api.services.RepositoryFactory;
51 import org.apache.maven.api.services.SettingsBuilder;
52 import org.apache.maven.api.services.TypeRegistry;
53 import org.apache.maven.api.services.model.*;
54 import org.apache.maven.api.settings.Settings;
55 import org.apache.maven.api.spi.ModelParser;
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.*;
61 import org.apache.maven.internal.impl.model.*;
62 import org.apache.maven.internal.impl.resolver.DefaultVersionRangeResolver;
63 import org.apache.maven.internal.impl.resolver.DefaultVersionResolver;
64 import org.apache.maven.internal.impl.resolver.MavenVersionScheme;
65 import org.apache.maven.internal.impl.resolver.type.DefaultTypeProvider;
66 import org.eclipse.aether.DefaultRepositorySystemSession;
67 import org.eclipse.aether.RepositorySystem;
68 import org.eclipse.aether.RepositorySystemSession;
69 import org.eclipse.aether.impl.RemoteRepositoryManager;
70 import org.eclipse.aether.repository.LocalRepository;
71 import org.eclipse.aether.repository.LocalRepositoryManager;
72
73 public class ApiRunner {
74
75
76
77
78 public static Session createSession() {
79 Injector injector = Injector.create();
80 injector.bindInstance(Injector.class, injector);
81 injector.bindImplicit(ApiRunner.class);
82 injector.bindImplicit(DefaultArtifactCoordinateFactory.class);
83 injector.bindImplicit(DefaultArtifactDeployer.class);
84 injector.bindImplicit(DefaultArtifactFactory.class);
85 injector.bindImplicit(DefaultArtifactInstaller.class);
86 injector.bindImplicit(DefaultArtifactResolver.class);
87 injector.bindImplicit(DefaultChecksumAlgorithmService.class);
88 injector.bindImplicit(DefaultDependencyCollector.class);
89 injector.bindImplicit(DefaultDependencyCoordinateFactory.class);
90 injector.bindImplicit(DefaultLocalRepositoryManager.class);
91 injector.bindImplicit(DefaultMessageBuilderFactory.class);
92 injector.bindImplicit(DefaultModelXmlFactory.class);
93 injector.bindImplicit(DefaultRepositoryFactory.class);
94 injector.bindImplicit(DefaultSettingsBuilder.class);
95 injector.bindImplicit(DefaultSettingsXmlFactory.class);
96 injector.bindImplicit(DefaultToolchainsBuilder.class);
97 injector.bindImplicit(DefaultToolchainsXmlFactory.class);
98 injector.bindImplicit(DefaultTransportProvider.class);
99 injector.bindImplicit(DefaultVersionParser.class);
100 injector.bindImplicit(DefaultVersionRangeResolver.class);
101 injector.bindImplicit(org.apache.maven.internal.impl.DefaultVersionParser.class);
102 injector.bindImplicit(org.apache.maven.internal.impl.DefaultVersionRangeResolver.class);
103 injector.bindImplicit(DefaultVersionResolver.class);
104 injector.bindImplicit(ExtensibleEnumRegistries.class);
105 injector.bindImplicit(DefaultTypeProvider.class);
106
107 injector.bindImplicit(MavenVersionScheme.class);
108 injector.bindImplicit(BuildModelTransformer.class);
109 injector.bindImplicit(DefaultDependencyManagementImporter.class);
110 injector.bindImplicit(DefaultDependencyManagementInjector.class);
111 injector.bindImplicit(DefaultModelBuilder.class);
112 injector.bindImplicit(DefaultModelProcessor.class);
113 injector.bindImplicit(DefaultModelValidator.class);
114 injector.bindImplicit(DefaultModelVersionProcessor.class);
115 injector.bindImplicit(DefaultModelNormalizer.class);
116 injector.bindImplicit(DefaultModelInterpolator.class);
117 injector.bindImplicit(DefaultPathTranslator.class);
118 injector.bindImplicit(DefaultRootLocator.class);
119 injector.bindImplicit(DefaultModelPathTranslator.class);
120 injector.bindImplicit(DefaultUrlNormalizer.class);
121 injector.bindImplicit(DefaultModelUrlNormalizer.class);
122 injector.bindImplicit(DefaultSuperPomProvider.class);
123 injector.bindImplicit(DefaultInheritanceAssembler.class);
124 injector.bindImplicit(DefaultProfileInjector.class);
125 injector.bindImplicit(DefaultProfileSelector.class);
126 injector.bindImplicit(DefaultPluginManagementInjector.class);
127 injector.bindImplicit(DefaultLifecycleBindingsInjector.class);
128 injector.bindImplicit(DefaultPluginConfigurationExpander.class);
129 injector.bindImplicit(ProfileActivationFilePathInterpolator.class);
130 injector.bindImplicit(DefaultModelVersionParser.class);
131
132 injector.bindImplicit(ProfileActivator.class);
133 injector.bindImplicit(ModelParser.class);
134
135 return injector.getInstance(Session.class);
136 }
137
138 static class DefaultSession extends AbstractSession {
139
140 private final Map<String, String> systemProperties;
141 private Instant startTime = Instant.now();
142
143 DefaultSession(RepositorySystemSession session, RepositorySystem repositorySystem, Lookup lookup) {
144 this(session, repositorySystem, Collections.emptyList(), null, lookup);
145 }
146
147 protected DefaultSession(
148 RepositorySystemSession session,
149 RepositorySystem repositorySystem,
150 List<RemoteRepository> repositories,
151 List<org.eclipse.aether.repository.RemoteRepository> resolverRepositories,
152 Lookup lookup) {
153 super(session, repositorySystem, repositories, resolverRepositories, lookup);
154 systemProperties = System.getenv().entrySet().stream()
155 .collect(Collectors.toMap(e -> "env." + e.getKey(), e -> e.getValue()));
156 System.getProperties().forEach((k, v) -> systemProperties.put(k.toString(), v.toString()));
157 }
158
159 @Override
160 protected Session newSession(RepositorySystemSession session, List<RemoteRepository> repositories) {
161 return new DefaultSession(session, repositorySystem, repositories, null, lookup);
162 }
163
164 @Override
165 public Settings getSettings() {
166 return Settings.newInstance();
167 }
168
169 @Override
170 public Map<String, String> getUserProperties() {
171 return Map.of();
172 }
173
174 @Override
175 public Map<String, String> getSystemProperties() {
176 return systemProperties;
177 }
178
179 @Override
180 public Map<String, String> getEffectiveProperties(Project project) {
181 HashMap<String, String> result = new HashMap<>(getSystemProperties());
182 if (project != null) {
183 result.putAll(project.getModel().getProperties());
184 }
185 result.putAll(getUserProperties());
186 return result;
187 }
188
189 @Override
190 public Version getMavenVersion() {
191 return null;
192 }
193
194 @Override
195 public int getDegreeOfConcurrency() {
196 return 0;
197 }
198
199 @Override
200 public Instant getStartTime() {
201 return startTime;
202 }
203
204 @Override
205 public Path getTopDirectory() {
206 return null;
207 }
208
209 @Override
210 public Path getRootDirectory() {
211 return null;
212 }
213
214 @Override
215 public List<Project> getProjects() {
216 return List.of();
217 }
218
219 @Override
220 public Map<String, Object> getPluginContext(Project project) {
221 throw new UnsupportedInStandaloneModeException();
222 }
223 }
224
225 @Provides
226 static Lookup newLookup(Injector injector) {
227 return new Lookup() {
228 @Override
229 public <T> T lookup(Class<T> type) {
230 try {
231 return injector.getInstance(type);
232 } catch (DIException e) {
233 throw new MavenException("Unable to locate instance of type " + type, e);
234 }
235 }
236
237 @Override
238 public <T> T lookup(Class<T> type, String name) {
239 try {
240 return injector.getInstance(Key.of(type, name));
241 } catch (DIException e) {
242 throw new MavenException("Unable to locate instance of type " + type, e);
243 }
244 }
245
246 @Override
247 public <T> Optional<T> lookupOptional(Class<T> type) {
248 try {
249 return Optional.of(injector.getInstance(type));
250 } catch (DIException e) {
251 return Optional.empty();
252 }
253 }
254
255 @Override
256 public <T> Optional<T> lookupOptional(Class<T> type, String name) {
257 try {
258 return Optional.of(injector.getInstance(Key.of(type, name)));
259 } catch (DIException e) {
260 return Optional.empty();
261 }
262 }
263
264 @Override
265 public <T> List<T> lookupList(Class<T> type) {
266 return injector.getInstance(new Key<List<T>>() {});
267 }
268
269 @Override
270 public <T> Map<String, T> lookupMap(Class<T> type) {
271 return injector.getInstance(new Key<Map<String, T>>() {});
272 }
273 };
274 }
275
276 @Provides
277 static ArtifactManager newArtifactManager() {
278 return new ArtifactManager() {
279 private final Map<Artifact, Path> paths = new ConcurrentHashMap<>();
280
281 @Override
282 public Optional<Path> getPath(Artifact artifact) {
283 return Optional.ofNullable(paths.get(artifact));
284 }
285
286 @Override
287 public void setPath(Artifact artifact, Path path) {
288 paths.put(artifact, path);
289 }
290 };
291 }
292
293 @Provides
294 static PackagingRegistry newPackagingRegistry(TypeRegistry typeRegistry) {
295 return id -> Optional.of(new DumbPackaging(id, typeRegistry.require(id), Map.of()));
296 }
297
298 @Provides
299 static TypeRegistry newTypeRegistry(List<TypeProvider> providers) {
300 return new TypeRegistry() {
301 @Override
302 public Optional<Type> lookup(String id) {
303 return providers.stream()
304 .flatMap(p -> p.provides().stream())
305 .filter(t -> Objects.equals(id, t.id()))
306 .findAny();
307 }
308 };
309 }
310
311 @Provides
312 static LifecycleRegistry newLifecycleRegistry() {
313 return new LifecycleRegistry() {
314
315 @Override
316 public Iterator<Lifecycle> iterator() {
317 return Collections.emptyIterator();
318 }
319
320 @Override
321 public Optional<Lifecycle> lookup(String id) {
322 return Optional.empty();
323 }
324 };
325 }
326
327 @Provides
328 static RepositorySystemSupplier newRepositorySystemSupplier() {
329 return new RepositorySystemSupplier();
330 }
331
332 @Provides
333 static RepositorySystem newRepositorySystem(RepositorySystemSupplier repositorySystemSupplier) {
334 return repositorySystemSupplier.getRepositorySystem();
335 }
336
337 @Provides
338 static RemoteRepositoryManager newRemoteRepositoryManager(RepositorySystemSupplier repositorySystemSupplier) {
339 return repositorySystemSupplier.getRemoteRepositoryManager();
340 }
341
342 @Provides
343 static Session newSession(RepositorySystem system, Lookup lookup) {
344 Map<String, String> properties = new HashMap<>();
345
346 System.getenv().forEach((k, v) -> properties.put("env." + k, v));
347
348 System.getProperties().forEach((k, v) -> properties.put(k.toString(), v.toString()));
349
350
351
352
353
354
355
356
357
358
359 Path userHome = Paths.get(properties.get("user.home"));
360 Path mavenUserHome = userHome.resolve(".m2");
361 Path mavenSystemHome = properties.containsKey("maven.home")
362 ? Paths.get(properties.get("maven.home"))
363 : properties.containsKey("env.MAVEN_HOME") ? Paths.get(properties.get("env.MAVEN_HOME")) : null;
364
365 DefaultRepositorySystemSession rsession = new DefaultRepositorySystemSession(h -> false);
366 rsession.setSystemProperties(properties);
367 rsession.setConfigProperties(properties);
368
369 DefaultSession session = new DefaultSession(
370 rsession,
371 system,
372 List.of(lookup.lookup(RepositoryFactory.class)
373 .createRemote("central", "https://repo.maven.apache.org/maven2")),
374 null,
375 lookup);
376
377 Settings settings = session.getService(SettingsBuilder.class)
378 .build(
379 session,
380 mavenSystemHome != null ? mavenSystemHome.resolve("settings.xml") : null,
381 mavenUserHome.resolve("settings.xml"))
382 .getEffectiveSettings();
383
384 settings.getProfiles();
385
386
387 String localRepository = settings.getLocalRepository() != null
388 ? settings.getLocalRepository()
389 : mavenUserHome.resolve("repository").toString();
390 LocalRepositoryManager llm = system.newLocalRepositoryManager(rsession, new LocalRepository(localRepository));
391 rsession.setLocalRepositoryManager(llm);
392
393
394
395
396 DefaultSession defaultSession = new DefaultSession(
397 rsession,
398 system,
399 List.of(lookup.lookup(RepositoryFactory.class)
400 .createRemote("central", "https://repo.maven.apache.org/maven2")),
401 null,
402 lookup);
403
404 Profile profile = session.getService(SettingsBuilder.class)
405 .convert(org.apache.maven.api.settings.Profile.newBuilder()
406 .repositories(settings.getRepositories())
407 .pluginRepositories(settings.getPluginRepositories())
408 .build());
409 RepositoryFactory repositoryFactory = session.getService(RepositoryFactory.class);
410 List<RemoteRepository> repositories = profile.getRepositories().stream()
411 .map(repositoryFactory::createRemote)
412 .toList();
413 InternalSession s = (InternalSession) session.withRemoteRepositories(repositories);
414 InternalSession.associate(rsession, s);
415 return s;
416
417
418
419
420
421
422
423
424
425 }
426
427 static class UnsupportedInStandaloneModeException extends MavenException {}
428
429 record DumbPackaging(String id, Type type, Map<String, PluginContainer> plugins) implements Packaging {}
430 }