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