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.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       * Create a new session.
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         // Env variables prefixed with "env."
346         System.getenv().forEach((k, v) -> properties.put("env." + k, v));
347         // Java System properties
348         System.getProperties().forEach((k, v) -> properties.put(k.toString(), v.toString()));
349 
350         // SettingsDecrypter settingsDecrypter =
351         // (SettingsDecrypter)Objects.requireNonNull(this.createSettingsDecrypter(preBoot));
352         //        new DefaultProfileSelector(List.of(
353         //                new JdkVersionProfileActivator(),
354         //                new PropertyProfileActivator(),
355         //                new OperatingSystemProfileActivator(),
356         //                new FileProfileActivator(new ProfileActivationFilePathInterpolator(
357         //                        new DefaultPathTranslator(), new DefaultRootLocator()))));
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         // local repository
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         // active proxies
393         // TODO
394         // active profiles
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         // List<RemoteRepository> repositories = repositoryFactory.createRemote();
418 
419         //        session.getService(SettingsBuilder.class).convert()
420 
421         //        settings.getDelegate().getRepositories().stream()
422         //                        .map(r -> SettingsUtilsV4.)
423         //        defaultSession.getService(RepositoryFactory.class).createRemote()
424         //        return defaultSession;
425     }
426 
427     static class UnsupportedInStandaloneModeException extends MavenException {}
428 
429     record DumbPackaging(String id, Type type, Map<String, PluginContainer> plugins) implements Packaging {}
430 }