View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
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.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.services.model.ProfileActivator;
55  import org.apache.maven.api.settings.Settings;
56  import org.apache.maven.api.spi.ModelParser;
57  import org.apache.maven.api.spi.TypeProvider;
58  import org.apache.maven.di.Injector;
59  import org.apache.maven.di.Key;
60  import org.apache.maven.di.impl.DIException;
61  import org.apache.maven.internal.impl.AbstractSession;
62  import org.apache.maven.internal.impl.DefaultArtifactCoordinatesFactory;
63  import org.apache.maven.internal.impl.DefaultArtifactDeployer;
64  import org.apache.maven.internal.impl.DefaultArtifactFactory;
65  import org.apache.maven.internal.impl.DefaultArtifactInstaller;
66  import org.apache.maven.internal.impl.DefaultArtifactResolver;
67  import org.apache.maven.internal.impl.DefaultChecksumAlgorithmService;
68  import org.apache.maven.internal.impl.DefaultDependencyCoordinatesFactory;
69  import org.apache.maven.internal.impl.DefaultDependencyResolver;
70  import org.apache.maven.internal.impl.DefaultLocalRepositoryManager;
71  import org.apache.maven.internal.impl.DefaultMessageBuilderFactory;
72  import org.apache.maven.internal.impl.DefaultModelUrlNormalizer;
73  import org.apache.maven.internal.impl.DefaultModelVersionParser;
74  import org.apache.maven.internal.impl.DefaultModelXmlFactory;
75  import org.apache.maven.internal.impl.DefaultPluginConfigurationExpander;
76  import org.apache.maven.internal.impl.DefaultRepositoryFactory;
77  import org.apache.maven.internal.impl.DefaultSettingsBuilder;
78  import org.apache.maven.internal.impl.DefaultSettingsXmlFactory;
79  import org.apache.maven.internal.impl.DefaultSuperPomProvider;
80  import org.apache.maven.internal.impl.DefaultToolchainsBuilder;
81  import org.apache.maven.internal.impl.DefaultToolchainsXmlFactory;
82  import org.apache.maven.internal.impl.DefaultTransportProvider;
83  import org.apache.maven.internal.impl.DefaultUrlNormalizer;
84  import org.apache.maven.internal.impl.DefaultVersionParser;
85  import org.apache.maven.internal.impl.ExtensibleEnumRegistries;
86  import org.apache.maven.internal.impl.InternalSession;
87  import org.apache.maven.internal.impl.model.BuildModelTransformer;
88  import org.apache.maven.internal.impl.model.DefaultDependencyManagementImporter;
89  import org.apache.maven.internal.impl.model.DefaultDependencyManagementInjector;
90  import org.apache.maven.internal.impl.model.DefaultInheritanceAssembler;
91  import org.apache.maven.internal.impl.model.DefaultLifecycleBindingsInjector;
92  import org.apache.maven.internal.impl.model.DefaultModelBuilder;
93  import org.apache.maven.internal.impl.model.DefaultModelInterpolator;
94  import org.apache.maven.internal.impl.model.DefaultModelNormalizer;
95  import org.apache.maven.internal.impl.model.DefaultModelPathTranslator;
96  import org.apache.maven.internal.impl.model.DefaultModelProcessor;
97  import org.apache.maven.internal.impl.model.DefaultModelValidator;
98  import org.apache.maven.internal.impl.model.DefaultModelVersionProcessor;
99  import org.apache.maven.internal.impl.model.DefaultPathTranslator;
100 import org.apache.maven.internal.impl.model.DefaultPluginManagementInjector;
101 import org.apache.maven.internal.impl.model.DefaultProfileInjector;
102 import org.apache.maven.internal.impl.model.DefaultProfileSelector;
103 import org.apache.maven.internal.impl.model.DefaultRootLocator;
104 import org.apache.maven.internal.impl.model.ProfileActivationFilePathInterpolator;
105 import org.apache.maven.internal.impl.resolver.DefaultVersionRangeResolver;
106 import org.apache.maven.internal.impl.resolver.DefaultVersionResolver;
107 import org.apache.maven.internal.impl.resolver.MavenVersionScheme;
108 import org.apache.maven.internal.impl.resolver.type.DefaultTypeProvider;
109 import org.eclipse.aether.DefaultRepositorySystemSession;
110 import org.eclipse.aether.RepositorySystem;
111 import org.eclipse.aether.RepositorySystemSession;
112 import org.eclipse.aether.impl.RemoteRepositoryManager;
113 import org.eclipse.aether.repository.LocalRepository;
114 import org.eclipse.aether.repository.LocalRepositoryManager;
115 
116 public class ApiRunner {
117 
118     /**
119      * Create a new session.
120      */
121     public static Session createSession() {
122         Injector injector = Injector.create();
123         injector.bindInstance(Injector.class, injector);
124         injector.bindImplicit(ApiRunner.class);
125         injector.bindImplicit(DefaultArtifactCoordinatesFactory.class);
126         injector.bindImplicit(DefaultArtifactDeployer.class);
127         injector.bindImplicit(DefaultArtifactFactory.class);
128         injector.bindImplicit(DefaultArtifactInstaller.class);
129         injector.bindImplicit(DefaultArtifactResolver.class);
130         injector.bindImplicit(DefaultChecksumAlgorithmService.class);
131         injector.bindImplicit(DefaultDependencyResolver.class);
132         injector.bindImplicit(DefaultDependencyCoordinatesFactory.class);
133         injector.bindImplicit(DefaultLocalRepositoryManager.class);
134         injector.bindImplicit(DefaultMessageBuilderFactory.class);
135         injector.bindImplicit(DefaultModelXmlFactory.class);
136         injector.bindImplicit(DefaultRepositoryFactory.class);
137         injector.bindImplicit(DefaultSettingsBuilder.class);
138         injector.bindImplicit(DefaultSettingsXmlFactory.class);
139         injector.bindImplicit(DefaultToolchainsBuilder.class);
140         injector.bindImplicit(DefaultToolchainsXmlFactory.class);
141         injector.bindImplicit(DefaultTransportProvider.class);
142         injector.bindImplicit(DefaultVersionParser.class);
143         injector.bindImplicit(DefaultVersionRangeResolver.class);
144         injector.bindImplicit(org.apache.maven.internal.impl.DefaultVersionParser.class);
145         injector.bindImplicit(org.apache.maven.internal.impl.DefaultVersionRangeResolver.class);
146         injector.bindImplicit(DefaultVersionResolver.class);
147         injector.bindImplicit(ExtensibleEnumRegistries.class);
148         injector.bindImplicit(DefaultTypeProvider.class);
149 
150         injector.bindImplicit(MavenVersionScheme.class);
151         injector.bindImplicit(BuildModelTransformer.class);
152         injector.bindImplicit(DefaultDependencyManagementImporter.class);
153         injector.bindImplicit(DefaultDependencyManagementInjector.class);
154         injector.bindImplicit(DefaultModelBuilder.class);
155         injector.bindImplicit(DefaultModelProcessor.class);
156         injector.bindImplicit(DefaultModelValidator.class);
157         injector.bindImplicit(DefaultModelVersionProcessor.class);
158         injector.bindImplicit(DefaultModelNormalizer.class);
159         injector.bindImplicit(DefaultModelInterpolator.class);
160         injector.bindImplicit(DefaultPathTranslator.class);
161         injector.bindImplicit(DefaultRootLocator.class);
162         injector.bindImplicit(DefaultModelPathTranslator.class);
163         injector.bindImplicit(DefaultUrlNormalizer.class);
164         injector.bindImplicit(DefaultModelUrlNormalizer.class);
165         injector.bindImplicit(DefaultSuperPomProvider.class);
166         injector.bindImplicit(DefaultInheritanceAssembler.class);
167         injector.bindImplicit(DefaultProfileInjector.class);
168         injector.bindImplicit(DefaultProfileSelector.class);
169         injector.bindImplicit(DefaultPluginManagementInjector.class);
170         injector.bindImplicit(DefaultLifecycleBindingsInjector.class);
171         injector.bindImplicit(DefaultPluginConfigurationExpander.class);
172         injector.bindImplicit(ProfileActivationFilePathInterpolator.class);
173         injector.bindImplicit(DefaultModelVersionParser.class);
174 
175         injector.bindImplicit(ProfileActivator.class);
176         injector.bindImplicit(ModelParser.class);
177 
178         return injector.getInstance(Session.class);
179     }
180 
181     static class DefaultSession extends AbstractSession {
182 
183         private final Map<String, String> systemProperties;
184         private Instant startTime = Instant.now();
185 
186         DefaultSession(RepositorySystemSession session, RepositorySystem repositorySystem, Lookup lookup) {
187             this(session, repositorySystem, Collections.emptyList(), null, lookup);
188         }
189 
190         protected DefaultSession(
191                 RepositorySystemSession session,
192                 RepositorySystem repositorySystem,
193                 List<RemoteRepository> repositories,
194                 List<org.eclipse.aether.repository.RemoteRepository> resolverRepositories,
195                 Lookup lookup) {
196             super(session, repositorySystem, repositories, resolverRepositories, lookup);
197             systemProperties = System.getenv().entrySet().stream()
198                     .collect(Collectors.toMap(e -> "env." + e.getKey(), e -> e.getValue()));
199             System.getProperties().forEach((k, v) -> systemProperties.put(k.toString(), v.toString()));
200         }
201 
202         @Override
203         protected Session newSession(RepositorySystemSession session, List<RemoteRepository> repositories) {
204             return new DefaultSession(session, repositorySystem, repositories, null, lookup);
205         }
206 
207         @Override
208         public Settings getSettings() {
209             return Settings.newInstance();
210         }
211 
212         @Override
213         public Map<String, String> getUserProperties() {
214             return Map.of();
215         }
216 
217         @Override
218         public Map<String, String> getSystemProperties() {
219             return systemProperties;
220         }
221 
222         @Override
223         public Map<String, String> getEffectiveProperties(Project project) {
224             HashMap<String, String> result = new HashMap<>(getSystemProperties());
225             if (project != null) {
226                 result.putAll(project.getModel().getProperties());
227             }
228             result.putAll(getUserProperties());
229             return result;
230         }
231 
232         @Override
233         public Version getMavenVersion() {
234             return null;
235         }
236 
237         @Override
238         public int getDegreeOfConcurrency() {
239             return 0;
240         }
241 
242         @Override
243         public Instant getStartTime() {
244             return startTime;
245         }
246 
247         @Override
248         public Path getTopDirectory() {
249             return null;
250         }
251 
252         @Override
253         public Path getRootDirectory() {
254             return null;
255         }
256 
257         @Override
258         public List<Project> getProjects() {
259             return List.of();
260         }
261 
262         @Override
263         public Map<String, Object> getPluginContext(Project project) {
264             throw new UnsupportedInStandaloneModeException();
265         }
266     }
267 
268     @Provides
269     static Lookup newLookup(Injector injector) {
270         return new Lookup() {
271             @Override
272             public <T> T lookup(Class<T> type) {
273                 try {
274                     return injector.getInstance(type);
275                 } catch (DIException e) {
276                     throw new MavenException("Unable to locate instance of type " + type, e);
277                 }
278             }
279 
280             @Override
281             public <T> T lookup(Class<T> type, String name) {
282                 try {
283                     return injector.getInstance(Key.of(type, name));
284                 } catch (DIException e) {
285                     throw new MavenException("Unable to locate instance of type " + type, e);
286                 }
287             }
288 
289             @Override
290             public <T> Optional<T> lookupOptional(Class<T> type) {
291                 try {
292                     return Optional.of(injector.getInstance(type));
293                 } catch (DIException e) {
294                     return Optional.empty();
295                 }
296             }
297 
298             @Override
299             public <T> Optional<T> lookupOptional(Class<T> type, String name) {
300                 try {
301                     return Optional.of(injector.getInstance(Key.of(type, name)));
302                 } catch (DIException e) {
303                     return Optional.empty();
304                 }
305             }
306 
307             @Override
308             public <T> List<T> lookupList(Class<T> type) {
309                 return injector.getInstance(new Key<List<T>>() {});
310             }
311 
312             @Override
313             public <T> Map<String, T> lookupMap(Class<T> type) {
314                 return injector.getInstance(new Key<Map<String, T>>() {});
315             }
316         };
317     }
318 
319     @Provides
320     static ArtifactManager newArtifactManager() {
321         return new ArtifactManager() {
322             private final Map<Artifact, Path> paths = new ConcurrentHashMap<>();
323 
324             @Override
325             public Optional<Path> getPath(Artifact artifact) {
326                 return Optional.ofNullable(paths.get(artifact));
327             }
328 
329             @Override
330             public void setPath(ProducedArtifact artifact, Path path) {
331                 paths.put(artifact, path);
332             }
333         };
334     }
335 
336     @Provides
337     static PackagingRegistry newPackagingRegistry(TypeRegistry typeRegistry) {
338         return id -> Optional.of(new DumbPackaging(id, typeRegistry.require(id), Map.of()));
339     }
340 
341     @Provides
342     static TypeRegistry newTypeRegistry(List<TypeProvider> providers) {
343         return new TypeRegistry() {
344             @Override
345             public Optional<Type> lookup(String id) {
346                 return providers.stream()
347                         .flatMap(p -> p.provides().stream())
348                         .filter(t -> Objects.equals(id, t.id()))
349                         .findAny();
350             }
351         };
352     }
353 
354     @Provides
355     static LifecycleRegistry newLifecycleRegistry() {
356         return new LifecycleRegistry() {
357 
358             @Override
359             public Iterator<Lifecycle> iterator() {
360                 return Collections.emptyIterator();
361             }
362 
363             @Override
364             public Optional<Lifecycle> lookup(String id) {
365                 return Optional.empty();
366             }
367 
368             @Override
369             public List<String> computePhases(Lifecycle lifecycle) {
370                 return List.of();
371             }
372         };
373     }
374 
375     @Provides
376     static RepositorySystemSupplier newRepositorySystemSupplier() {
377         return new RepositorySystemSupplier();
378     }
379 
380     @Provides
381     static RepositorySystem newRepositorySystem(RepositorySystemSupplier repositorySystemSupplier) {
382         return repositorySystemSupplier.getRepositorySystem();
383     }
384 
385     @Provides
386     static RemoteRepositoryManager newRemoteRepositoryManager(RepositorySystemSupplier repositorySystemSupplier) {
387         return repositorySystemSupplier.getRemoteRepositoryManager();
388     }
389 
390     @Provides
391     static Session newSession(RepositorySystem system, Lookup lookup) {
392         Map<String, String> properties = new HashMap<>();
393         // Env variables prefixed with "env."
394         System.getenv().forEach((k, v) -> properties.put("env." + k, v));
395         // Java System properties
396         System.getProperties().forEach((k, v) -> properties.put(k.toString(), v.toString()));
397 
398         // SettingsDecrypter settingsDecrypter =
399         // (SettingsDecrypter)Objects.requireNonNull(this.createSettingsDecrypter(preBoot));
400         //        new DefaultProfileSelector(List.of(
401         //                new JdkVersionProfileActivator(),
402         //                new PropertyProfileActivator(),
403         //                new OperatingSystemProfileActivator(),
404         //                new FileProfileActivator(new ProfileActivationFilePathInterpolator(
405         //                        new DefaultPathTranslator(), new DefaultRootLocator()))));
406 
407         Path userHome = Paths.get(properties.get("user.home"));
408         Path mavenUserHome = userHome.resolve(".m2");
409         Path mavenSystemHome = properties.containsKey("maven.home")
410                 ? Paths.get(properties.get("maven.home"))
411                 : properties.containsKey("env.MAVEN_HOME") ? Paths.get(properties.get("env.MAVEN_HOME")) : null;
412 
413         DefaultRepositorySystemSession rsession = new DefaultRepositorySystemSession(h -> false);
414         rsession.setSystemProperties(properties);
415         rsession.setConfigProperties(properties);
416 
417         DefaultSession session = new DefaultSession(
418                 rsession,
419                 system,
420                 List.of(lookup.lookup(RepositoryFactory.class)
421                         .createRemote("central", "https://repo.maven.apache.org/maven2")),
422                 null,
423                 lookup);
424 
425         Settings settings = session.getService(SettingsBuilder.class)
426                 .build(
427                         session,
428                         mavenSystemHome != null ? mavenSystemHome.resolve("settings.xml") : null,
429                         mavenUserHome.resolve("settings.xml"))
430                 .getEffectiveSettings();
431 
432         settings.getProfiles();
433 
434         // local repository
435         String localRepository = settings.getLocalRepository() != null
436                 ? settings.getLocalRepository()
437                 : mavenUserHome.resolve("repository").toString();
438         LocalRepositoryManager llm = system.newLocalRepositoryManager(rsession, new LocalRepository(localRepository));
439         rsession.setLocalRepositoryManager(llm);
440         // active proxies
441         // TODO
442         // active profiles
443 
444         DefaultSession defaultSession = new DefaultSession(
445                 rsession,
446                 system,
447                 List.of(lookup.lookup(RepositoryFactory.class)
448                         .createRemote("central", "https://repo.maven.apache.org/maven2")),
449                 null,
450                 lookup);
451 
452         Profile profile = session.getService(SettingsBuilder.class)
453                 .convert(org.apache.maven.api.settings.Profile.newBuilder()
454                         .repositories(settings.getRepositories())
455                         .pluginRepositories(settings.getPluginRepositories())
456                         .build());
457         RepositoryFactory repositoryFactory = session.getService(RepositoryFactory.class);
458         List<RemoteRepository> repositories = profile.getRepositories().stream()
459                 .map(repositoryFactory::createRemote)
460                 .toList();
461         InternalSession s = (InternalSession) session.withRemoteRepositories(repositories);
462         InternalSession.associate(rsession, s);
463         return s;
464 
465         // List<RemoteRepository> repositories = repositoryFactory.createRemote();
466 
467         //        session.getService(SettingsBuilder.class).convert()
468 
469         //        settings.getDelegate().getRepositories().stream()
470         //                        .map(r -> SettingsUtilsV4.)
471         //        defaultSession.getService(RepositoryFactory.class).createRemote()
472         //        return defaultSession;
473     }
474 
475     static class UnsupportedInStandaloneModeException extends MavenException {}
476 
477     record DumbPackaging(String id, Type type, Map<String, PluginContainer> plugins) implements Packaging {}
478 }