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.bridge;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  import javax.inject.Singleton;
24  
25  import java.io.File;
26  import java.net.MalformedURLException;
27  import java.net.URL;
28  import java.util.ArrayList;
29  import java.util.Collection;
30  import java.util.Collections;
31  import java.util.HashSet;
32  import java.util.LinkedHashMap;
33  import java.util.List;
34  import java.util.Map;
35  import java.util.Set;
36  
37  import org.apache.maven.RepositoryUtils;
38  import org.apache.maven.artifact.Artifact;
39  import org.apache.maven.artifact.DefaultArtifact;
40  import org.apache.maven.artifact.InvalidRepositoryException;
41  import org.apache.maven.artifact.handler.ArtifactHandler;
42  import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
43  import org.apache.maven.artifact.repository.ArtifactRepository;
44  import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
45  import org.apache.maven.artifact.repository.Authentication;
46  import org.apache.maven.artifact.repository.MavenArtifactRepository;
47  import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
48  import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout2;
49  import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
50  import org.apache.maven.artifact.resolver.filter.ExclusionArtifactFilter;
51  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
52  import org.apache.maven.artifact.versioning.VersionRange;
53  import org.apache.maven.execution.MavenExecutionRequest;
54  import org.apache.maven.model.Dependency;
55  import org.apache.maven.model.Plugin;
56  import org.apache.maven.repository.Proxy;
57  import org.apache.maven.settings.Mirror;
58  import org.eclipse.aether.RepositorySystemSession;
59  import org.eclipse.aether.repository.AuthenticationContext;
60  import org.eclipse.aether.repository.AuthenticationSelector;
61  import org.eclipse.aether.repository.ProxySelector;
62  import org.eclipse.aether.repository.RemoteRepository;
63  
64  /**
65   * @since 3.2.3
66   */
67  @Named("default")
68  @Singleton
69  public class MavenRepositorySystem {
70  
71      public static final String DEFAULT_REMOTE_REPO_ID = "central";
72  
73      public static final String DEFAULT_REMOTE_REPO_URL = "https://repo.maven.apache.org/maven2";
74  
75      public static final String DEFAULT_LOCAL_REPO_ID = "local";
76  
77      private final ArtifactHandlerManager artifactHandlerManager;
78  
79      private final Map<String, ArtifactRepositoryLayout> layouts;
80  
81      @Inject
82      public MavenRepositorySystem(
83              ArtifactHandlerManager artifactHandlerManager, Map<String, ArtifactRepositoryLayout> layouts) {
84          this.artifactHandlerManager = artifactHandlerManager;
85          this.layouts = layouts;
86      }
87  
88      // DefaultProjectBuilder
89      public Artifact createArtifact(String groupId, String artifactId, String version, String scope, String type) {
90          return createArtifactX(groupId, artifactId, version, scope, type);
91      }
92  
93      // DefaultProjectBuilder
94      public Artifact createProjectArtifact(String groupId, String artifactId, String metaVersionId) {
95          return createProjectArtifactX(groupId, artifactId, metaVersionId);
96      }
97  
98      // DefaultProjectBuilder
99      public Artifact createDependencyArtifact(Dependency d) {
100         if (d.getVersion() == null) {
101             return null;
102         }
103 
104         VersionRange versionRange;
105         try {
106             versionRange = VersionRange.createFromVersionSpec(d.getVersion());
107         } catch (InvalidVersionSpecificationException e) {
108             return null;
109         }
110 
111         Artifact artifact = createDependencyArtifactX(
112                 d.getGroupId(),
113                 d.getArtifactId(),
114                 versionRange,
115                 d.getType(),
116                 d.getClassifier(),
117                 d.getScope(),
118                 d.isOptional());
119 
120         if (Artifact.SCOPE_SYSTEM.equals(d.getScope()) && d.getSystemPath() != null) {
121             artifact.setFile(new File(d.getSystemPath()));
122         }
123 
124         if (!d.getExclusions().isEmpty()) {
125             artifact.setDependencyFilter(new ExclusionArtifactFilter(d.getExclusions()));
126         }
127 
128         return artifact;
129     }
130 
131     // DefaultProjectBuilder
132     public Artifact createExtensionArtifact(String groupId, String artifactId, String version) {
133         VersionRange versionRange;
134         try {
135             versionRange = VersionRange.createFromVersionSpec(version);
136         } catch (InvalidVersionSpecificationException e) {
137             return null;
138         }
139 
140         return createExtensionArtifactX(groupId, artifactId, versionRange);
141     }
142 
143     // DefaultProjectBuilder
144     public Artifact createParentArtifact(String groupId, String artifactId, String version) {
145         return createParentArtifactX(groupId, artifactId, version);
146     }
147 
148     // DefaultProjectBuilder
149     public Artifact createPluginArtifact(Plugin plugin) {
150         VersionRange versionRange;
151         try {
152             String version = plugin.getVersion();
153             if (version == null || version.isEmpty()) {
154                 version = "RELEASE";
155             }
156             versionRange = VersionRange.createFromVersionSpec(version);
157         } catch (InvalidVersionSpecificationException e) {
158             return null;
159         }
160 
161         return createPluginArtifactX(plugin.getGroupId(), plugin.getArtifactId(), versionRange);
162     }
163 
164     public void injectMirror(List<ArtifactRepository> repositories, List<Mirror> mirrors) {
165         if (repositories != null && mirrors != null) {
166             for (ArtifactRepository repository : repositories) {
167                 Mirror mirror = getMirror(repository, mirrors);
168                 injectMirror(repository, mirror);
169             }
170         }
171     }
172 
173     private Mirror getMirror(RepositorySystemSession session, ArtifactRepository repository) {
174         if (session != null) {
175             org.eclipse.aether.repository.MirrorSelector selector = session.getMirrorSelector();
176             if (selector != null) {
177                 RemoteRepository repo = selector.getMirror(RepositoryUtils.toRepo(repository));
178                 if (repo != null) {
179                     Mirror mirror = new Mirror();
180                     mirror.setId(repo.getId());
181                     mirror.setUrl(repo.getUrl());
182                     mirror.setLayout(repo.getContentType());
183                     mirror.setBlocked(repo.isBlocked());
184                     return mirror;
185                 }
186             }
187         }
188         return null;
189     }
190 
191     public void injectMirror(RepositorySystemSession session, List<ArtifactRepository> repositories) {
192         if (repositories != null && session != null) {
193             for (ArtifactRepository repository : repositories) {
194                 Mirror mirror = getMirror(session, repository);
195                 injectMirror(repository, mirror);
196             }
197         }
198     }
199 
200     private void injectMirror(ArtifactRepository repository, Mirror mirror) {
201         if (mirror != null) {
202             ArtifactRepository original = createArtifactRepository(
203                     repository.getId(),
204                     repository.getUrl(),
205                     repository.getLayout(),
206                     repository.getSnapshots(),
207                     repository.getReleases());
208 
209             repository.setMirroredRepositories(Collections.singletonList(original));
210 
211             repository.setId(mirror.getId());
212             repository.setUrl(mirror.getUrl());
213 
214             if (mirror.getLayout() != null && !mirror.getLayout().isEmpty()) {
215                 repository.setLayout(getLayout(mirror.getLayout()));
216             }
217 
218             repository.setBlocked(mirror.isBlocked());
219         }
220     }
221 
222     private Authentication getAuthentication(RepositorySystemSession session, ArtifactRepository repository) {
223         if (session != null) {
224             AuthenticationSelector selector = session.getAuthenticationSelector();
225             if (selector != null) {
226                 RemoteRepository repo = RepositoryUtils.toRepo(repository);
227                 org.eclipse.aether.repository.Authentication auth = selector.getAuthentication(repo);
228                 if (auth != null) {
229                     repo = new RemoteRepository.Builder(repo)
230                             .setAuthentication(auth)
231                             .build();
232                     AuthenticationContext authCtx = AuthenticationContext.forRepository(session, repo);
233                     Authentication result = new Authentication(
234                             authCtx.get(AuthenticationContext.USERNAME), authCtx.get(AuthenticationContext.PASSWORD));
235                     result.setPrivateKey(authCtx.get(AuthenticationContext.PRIVATE_KEY_PATH));
236                     result.setPassphrase(authCtx.get(AuthenticationContext.PRIVATE_KEY_PASSPHRASE));
237                     authCtx.close();
238                     return result;
239                 }
240             }
241         }
242         return null;
243     }
244 
245     public void injectAuthentication(RepositorySystemSession session, List<ArtifactRepository> repositories) {
246         if (repositories != null && session != null) {
247             for (ArtifactRepository repository : repositories) {
248                 repository.setAuthentication(getAuthentication(session, repository));
249             }
250         }
251     }
252 
253     private Proxy getProxy(RepositorySystemSession session, ArtifactRepository repository) {
254         if (session != null) {
255             ProxySelector selector = session.getProxySelector();
256             if (selector != null) {
257                 RemoteRepository repo = RepositoryUtils.toRepo(repository);
258                 org.eclipse.aether.repository.Proxy proxy = selector.getProxy(repo);
259                 if (proxy != null) {
260                     Proxy p = new Proxy();
261                     p.setHost(proxy.getHost());
262                     p.setProtocol(proxy.getType());
263                     p.setPort(proxy.getPort());
264                     if (proxy.getAuthentication() != null) {
265                         repo = new RemoteRepository.Builder(repo)
266                                 .setProxy(proxy)
267                                 .build();
268                         AuthenticationContext authCtx = AuthenticationContext.forProxy(session, repo);
269                         p.setUserName(authCtx.get(AuthenticationContext.USERNAME));
270                         p.setPassword(authCtx.get(AuthenticationContext.PASSWORD));
271                         p.setNtlmDomain(authCtx.get(AuthenticationContext.NTLM_DOMAIN));
272                         p.setNtlmHost(authCtx.get(AuthenticationContext.NTLM_WORKSTATION));
273                         authCtx.close();
274                     }
275                     return p;
276                 }
277             }
278         }
279         return null;
280     }
281 
282     public void injectProxy(RepositorySystemSession session, List<ArtifactRepository> repositories) {
283         if (repositories != null && session != null) {
284             for (ArtifactRepository repository : repositories) {
285                 repository.setProxy(getProxy(session, repository));
286             }
287         }
288     }
289 
290     private ArtifactRepositoryLayout getLayout(String id) {
291         return layouts.get(id);
292     }
293 
294     //
295     // Taken from LegacyRepositorySystem
296     //
297 
298     public static org.apache.maven.model.Repository fromSettingsRepository(
299             org.apache.maven.settings.Repository settingsRepository) {
300         org.apache.maven.model.Repository modelRepository = new org.apache.maven.model.Repository();
301         modelRepository.setId(settingsRepository.getId());
302         modelRepository.setLayout(settingsRepository.getLayout());
303         modelRepository.setName(settingsRepository.getName());
304         modelRepository.setUrl(settingsRepository.getUrl());
305         modelRepository.setReleases(fromSettingsRepositoryPolicy(settingsRepository.getReleases()));
306         modelRepository.setSnapshots(fromSettingsRepositoryPolicy(settingsRepository.getSnapshots()));
307         return modelRepository;
308     }
309 
310     public static org.apache.maven.model.RepositoryPolicy fromSettingsRepositoryPolicy(
311             org.apache.maven.settings.RepositoryPolicy settingsRepositoryPolicy) {
312         org.apache.maven.model.RepositoryPolicy modelRepositoryPolicy = new org.apache.maven.model.RepositoryPolicy();
313         if (settingsRepositoryPolicy != null) {
314             modelRepositoryPolicy.setEnabled(settingsRepositoryPolicy.isEnabled());
315             modelRepositoryPolicy.setUpdatePolicy(settingsRepositoryPolicy.getUpdatePolicy());
316             modelRepositoryPolicy.setChecksumPolicy(settingsRepositoryPolicy.getChecksumPolicy());
317         }
318         return modelRepositoryPolicy;
319     }
320 
321     public static ArtifactRepository buildArtifactRepository(org.apache.maven.settings.Repository repo)
322             throws InvalidRepositoryException {
323         return buildArtifactRepository(fromSettingsRepository(repo));
324     }
325 
326     public static ArtifactRepository buildArtifactRepository(org.apache.maven.model.Repository repo)
327             throws InvalidRepositoryException {
328         if (repo != null) {
329             String id = repo.getId();
330 
331             if (id == null || id.isEmpty()) {
332                 throw new InvalidRepositoryException("Repository identifier missing", "");
333             }
334 
335             String url = repo.getUrl();
336 
337             if (url == null || url.isEmpty()) {
338                 throw new InvalidRepositoryException("URL missing for repository " + id, id);
339             }
340 
341             ArtifactRepositoryPolicy snapshots = buildArtifactRepositoryPolicy(repo.getSnapshots());
342 
343             ArtifactRepositoryPolicy releases = buildArtifactRepositoryPolicy(repo.getReleases());
344 
345             ArtifactRepositoryLayout layout = new DefaultRepositoryLayout();
346 
347             return createArtifactRepository(id, url, layout, snapshots, releases);
348         } else {
349             return null;
350         }
351     }
352 
353     public static ArtifactRepositoryPolicy buildArtifactRepositoryPolicy(
354             org.apache.maven.model.RepositoryPolicy policy) {
355         boolean enabled = true;
356 
357         String updatePolicy = null;
358 
359         String checksumPolicy = null;
360 
361         if (policy != null) {
362             enabled = policy.isEnabled();
363 
364             if (policy.getUpdatePolicy() != null) {
365                 updatePolicy = policy.getUpdatePolicy();
366             }
367             if (policy.getChecksumPolicy() != null) {
368                 checksumPolicy = policy.getChecksumPolicy();
369             }
370         }
371 
372         return new ArtifactRepositoryPolicy(enabled, updatePolicy, checksumPolicy);
373     }
374 
375     public ArtifactRepository createArtifactRepository(
376             String id,
377             String url,
378             String layoutId,
379             ArtifactRepositoryPolicy snapshots,
380             ArtifactRepositoryPolicy releases)
381             throws InvalidRepositoryException {
382         ArtifactRepositoryLayout layout = layouts.get(layoutId);
383 
384         checkLayout(id, layoutId, layout);
385 
386         return createArtifactRepository(id, url, layout, snapshots, releases);
387     }
388 
389     private void checkLayout(String repositoryId, String layoutId, ArtifactRepositoryLayout layout)
390             throws InvalidRepositoryException {
391         if (layout == null) {
392             throw new InvalidRepositoryException(
393                     String.format("Cannot find ArtifactRepositoryLayout instance for: %s %s", layoutId, repositoryId),
394                     repositoryId);
395         }
396     }
397 
398     public static ArtifactRepository createArtifactRepository(
399             String id,
400             String url,
401             ArtifactRepositoryLayout repositoryLayout,
402             ArtifactRepositoryPolicy snapshots,
403             ArtifactRepositoryPolicy releases) {
404         if (snapshots == null) {
405             snapshots = new ArtifactRepositoryPolicy();
406         }
407 
408         if (releases == null) {
409             releases = new ArtifactRepositoryPolicy();
410         }
411 
412         ArtifactRepository repository;
413         if (repositoryLayout instanceof ArtifactRepositoryLayout2) {
414             repository = ((ArtifactRepositoryLayout2) repositoryLayout)
415                     .newMavenArtifactRepository(id, url, snapshots, releases);
416         } else {
417             repository = new MavenArtifactRepository(id, url, repositoryLayout, snapshots, releases);
418         }
419 
420         return repository;
421     }
422 
423     // ArtifactFactory
424     private Artifact createArtifactX(String groupId, String artifactId, String version, String scope, String type) {
425         return createArtifactX(groupId, artifactId, version, scope, type, null, null);
426     }
427 
428     private Artifact createDependencyArtifactX(
429             String groupId,
430             String artifactId,
431             VersionRange versionRange,
432             String type,
433             String classifier,
434             String scope,
435             boolean optional) {
436         return createArtifactX(groupId, artifactId, versionRange, type, classifier, scope, null, optional);
437     }
438 
439     private Artifact createProjectArtifactX(String groupId, String artifactId, String version) {
440         return createProjectArtifactX(groupId, artifactId, version, null);
441     }
442 
443     private Artifact createParentArtifactX(String groupId, String artifactId, String version) {
444         return createProjectArtifactX(groupId, artifactId, version);
445     }
446 
447     private Artifact createPluginArtifactX(String groupId, String artifactId, VersionRange versionRange) {
448         return createArtifactX(groupId, artifactId, versionRange, "maven-plugin", null, Artifact.SCOPE_RUNTIME, null);
449     }
450 
451     private Artifact createProjectArtifactX(String groupId, String artifactId, String version, String scope) {
452         return createArtifactX(groupId, artifactId, version, scope, "pom");
453     }
454 
455     private Artifact createExtensionArtifactX(String groupId, String artifactId, VersionRange versionRange) {
456         return createArtifactX(groupId, artifactId, versionRange, "jar", null, Artifact.SCOPE_RUNTIME, null);
457     }
458 
459     private Artifact createArtifactX(
460             String groupId,
461             String artifactId,
462             String version,
463             String scope,
464             String type,
465             String classifier,
466             String inheritedScope) {
467         VersionRange versionRange = null;
468         if (version != null) {
469             versionRange = VersionRange.createFromVersion(version);
470         }
471         return createArtifactX(groupId, artifactId, versionRange, type, classifier, scope, inheritedScope);
472     }
473 
474     private Artifact createArtifactX(
475             String groupId,
476             String artifactId,
477             VersionRange versionRange,
478             String type,
479             String classifier,
480             String scope,
481             String inheritedScope) {
482         return createArtifactX(groupId, artifactId, versionRange, type, classifier, scope, inheritedScope, false);
483     }
484 
485     @SuppressWarnings("checkstyle:parameternumber")
486     private Artifact createArtifactX(
487             String groupId,
488             String artifactId,
489             VersionRange versionRange,
490             String type,
491             String classifier,
492             String scope,
493             String inheritedScope,
494             boolean optional) {
495         String desiredScope = Artifact.SCOPE_RUNTIME;
496 
497         if (inheritedScope == null) {
498             desiredScope = scope;
499         } else if (Artifact.SCOPE_TEST.equals(scope) || Artifact.SCOPE_PROVIDED.equals(scope)) {
500             return null;
501         } else if (Artifact.SCOPE_COMPILE.equals(scope) && Artifact.SCOPE_COMPILE.equals(inheritedScope)) {
502             // added to retain compile artifactScope. Remove if you want compile inherited as runtime
503             desiredScope = Artifact.SCOPE_COMPILE;
504         }
505 
506         if (Artifact.SCOPE_TEST.equals(inheritedScope)) {
507             desiredScope = Artifact.SCOPE_TEST;
508         }
509 
510         if (Artifact.SCOPE_PROVIDED.equals(inheritedScope)) {
511             desiredScope = Artifact.SCOPE_PROVIDED;
512         }
513 
514         if (Artifact.SCOPE_SYSTEM.equals(scope)) {
515             // system scopes come through unchanged...
516             desiredScope = Artifact.SCOPE_SYSTEM;
517         }
518 
519         ArtifactHandler handler = artifactHandlerManager.getArtifactHandler(type);
520 
521         return new DefaultArtifact(
522                 groupId, artifactId, versionRange, desiredScope, type, classifier, handler, optional);
523     }
524 
525     //
526     // Code taken from LegacyRepositorySystem
527     //
528     public ArtifactRepository createDefaultRemoteRepository() throws Exception {
529         return createDefaultRemoteRepository(null);
530     }
531 
532     public ArtifactRepository createDefaultRemoteRepository(MavenExecutionRequest request) throws Exception {
533         return createRepository(
534                 MavenRepositorySystem.DEFAULT_REMOTE_REPO_URL,
535                 MavenRepositorySystem.DEFAULT_REMOTE_REPO_ID,
536                 true,
537                 ArtifactRepositoryPolicy.UPDATE_POLICY_DAILY,
538                 false,
539                 ArtifactRepositoryPolicy.UPDATE_POLICY_DAILY,
540                 ArtifactRepositoryPolicy.DEFAULT_CHECKSUM_POLICY);
541     }
542 
543     public ArtifactRepository createRepository(
544             String url,
545             String repositoryId,
546             boolean releases,
547             String releaseUpdates,
548             boolean snapshots,
549             String snapshotUpdates,
550             String checksumPolicy)
551             throws InvalidRepositoryException {
552         ArtifactRepositoryPolicy snapshotsPolicy =
553                 new ArtifactRepositoryPolicy(snapshots, snapshotUpdates, checksumPolicy);
554 
555         ArtifactRepositoryPolicy releasesPolicy =
556                 new ArtifactRepositoryPolicy(releases, releaseUpdates, checksumPolicy);
557 
558         return createArtifactRepository(repositoryId, url, "default", snapshotsPolicy, releasesPolicy);
559     }
560 
561     public Set<String> getRepoIds(List<ArtifactRepository> repositories) {
562         Set<String> repoIds = new HashSet<>();
563 
564         if (repositories != null) {
565             for (ArtifactRepository repository : repositories) {
566                 repoIds.add(repository.getId());
567             }
568         }
569 
570         return repoIds;
571     }
572 
573     /**
574      * Source from org.apache.maven.repository.legacy.LegacyRepositorySystem#getEffectiveRepositories
575      *
576      * @param repositories a list of repositories
577      * @return corresponding effective repositories
578      * @since 3.6.1
579      */
580     public List<ArtifactRepository> getEffectiveRepositories(List<ArtifactRepository> repositories) {
581         if (repositories == null) {
582             return null;
583         }
584 
585         Map<String, List<ArtifactRepository>> reposByKey = new LinkedHashMap<>();
586 
587         for (ArtifactRepository repository : repositories) {
588             String key = repository.getId();
589 
590             List<ArtifactRepository> aliasedRepos = reposByKey.computeIfAbsent(key, k -> new ArrayList<>());
591 
592             aliasedRepos.add(repository);
593         }
594 
595         List<ArtifactRepository> effectiveRepositories = new ArrayList<>();
596 
597         for (List<ArtifactRepository> aliasedRepos : reposByKey.values()) {
598             List<ArtifactRepository> mirroredRepos = new ArrayList<>();
599 
600             List<ArtifactRepositoryPolicy> releasePolicies = new ArrayList<>(aliasedRepos.size());
601 
602             for (ArtifactRepository aliasedRepo : aliasedRepos) {
603                 releasePolicies.add(aliasedRepo.getReleases());
604                 mirroredRepos.addAll(aliasedRepo.getMirroredRepositories());
605             }
606 
607             ArtifactRepositoryPolicy releasePolicy = getEffectivePolicy(releasePolicies);
608 
609             List<ArtifactRepositoryPolicy> snapshotPolicies = new ArrayList<>(aliasedRepos.size());
610 
611             for (ArtifactRepository aliasedRepo : aliasedRepos) {
612                 snapshotPolicies.add(aliasedRepo.getSnapshots());
613             }
614 
615             ArtifactRepositoryPolicy snapshotPolicy = getEffectivePolicy(snapshotPolicies);
616 
617             ArtifactRepository aliasedRepo = aliasedRepos.get(0);
618 
619             ArtifactRepository effectiveRepository = createArtifactRepository(
620                     aliasedRepo.getId(), aliasedRepo.getUrl(), aliasedRepo.getLayout(), snapshotPolicy, releasePolicy);
621 
622             effectiveRepository.setAuthentication(aliasedRepo.getAuthentication());
623 
624             effectiveRepository.setProxy(aliasedRepo.getProxy());
625 
626             effectiveRepository.setMirroredRepositories(mirroredRepos);
627 
628             effectiveRepository.setBlocked(aliasedRepo.isBlocked());
629 
630             effectiveRepositories.add(effectiveRepository);
631         }
632 
633         return effectiveRepositories;
634     }
635 
636     private ArtifactRepositoryPolicy getEffectivePolicy(Collection<ArtifactRepositoryPolicy> policies) {
637         ArtifactRepositoryPolicy effectivePolicy = null;
638 
639         for (ArtifactRepositoryPolicy policy : policies) {
640             if (effectivePolicy == null) {
641                 effectivePolicy = new ArtifactRepositoryPolicy(policy);
642             } else {
643                 effectivePolicy.merge(policy);
644             }
645         }
646 
647         return effectivePolicy;
648     }
649 
650     public ArtifactRepository createLocalRepository(MavenExecutionRequest request, File localRepository)
651             throws InvalidRepositoryException {
652         return createLocalRepository(localRepository);
653     }
654 
655     public ArtifactRepository createLocalRepository(File localRepository) throws InvalidRepositoryException {
656         return createRepository(
657                 "file://" + localRepository.toURI().getRawPath(),
658                 MavenRepositorySystem.DEFAULT_LOCAL_REPO_ID,
659                 true,
660                 ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS,
661                 true,
662                 ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS,
663                 ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE);
664     }
665 
666     private static final String WILDCARD = "*";
667 
668     private static final String EXTERNAL_WILDCARD = "external:*";
669 
670     private static final String EXTERNAL_HTTP_WILDCARD = "external:http:*";
671 
672     public static Mirror getMirror(ArtifactRepository repository, List<Mirror> mirrors) {
673         String repoId = repository.getId();
674 
675         if (repoId != null && mirrors != null) {
676             for (Mirror mirror : mirrors) {
677                 if (repoId.equals(mirror.getMirrorOf()) && matchesLayout(repository, mirror)) {
678                     return mirror;
679                 }
680             }
681 
682             for (Mirror mirror : mirrors) {
683                 if (matchPattern(repository, mirror.getMirrorOf()) && matchesLayout(repository, mirror)) {
684                     return mirror;
685                 }
686             }
687         }
688 
689         return null;
690     }
691 
692     /**
693      * This method checks if the pattern matches the originalRepository. Valid patterns:
694      * <ul>
695      * <li>{@code *} (since 2.0.5)= everything,</li>
696      * <li>{@code external:*}  (since 2.0.9)= everything not on the localhost and not file based,</li>
697      * <li>{@code external:http:*} (since 3.8.0)= any repository not on the localhost using HTTP,</li>
698      * <li>{@code repo,repo1}  (since 2.0.9)= {@code repo} or {@code repo1},</li>
699      * <li>{@code *,!repo1} (since 2.0.9)= everything except {@code repo1}.</li>
700      * </ul>
701      *
702      * @param originalRepository to compare for a match.
703      * @param pattern used for match.
704      * @return true if the repository is a match to this pattern.
705      */
706     static boolean matchPattern(ArtifactRepository originalRepository, String pattern) {
707         boolean result = false;
708         String originalId = originalRepository.getId();
709 
710         // simple checks first to short circuit processing below.
711         if (WILDCARD.equals(pattern) || pattern.equals(originalId)) {
712             result = true;
713         } else {
714             // process the list
715             String[] repos = pattern.split(",");
716             for (String repo : repos) {
717                 // see if this is a negative match
718                 if (repo.length() > 1 && repo.startsWith("!")) {
719                     if (repo.substring(1).equals(originalId)) {
720                         // explicitly exclude. Set result and stop processing.
721                         result = false;
722                         break;
723                     }
724                 }
725                 // check for exact match
726                 else if (repo.equals(originalId)) {
727                     result = true;
728                     break;
729                 }
730                 // check for external:*
731                 else if (EXTERNAL_WILDCARD.equals(repo) && isExternalRepo(originalRepository)) {
732                     result = true;
733                     // don't stop processing in case a future segment explicitly excludes this repo
734                 }
735                 // check for external:http:*
736                 else if (EXTERNAL_HTTP_WILDCARD.equals(repo) && isExternalHttpRepo(originalRepository)) {
737                     result = true;
738                     // don't stop processing in case a future segment explicitly excludes this repo
739                 } else if (WILDCARD.equals(repo)) {
740                     result = true;
741                     // don't stop processing in case a future segment explicitly excludes this repo
742                 }
743             }
744         }
745         return result;
746     }
747 
748     /**
749      * Checks the URL to see if this repository refers to an external repository
750      *
751      * @param originalRepository
752      * @return true if external.
753      */
754     static boolean isExternalRepo(ArtifactRepository originalRepository) {
755         try {
756             URL url = new URL(originalRepository.getUrl());
757             return !(isLocal(url.getHost()) || url.getProtocol().equals("file"));
758         } catch (MalformedURLException e) {
759             // bad url just skip it here. It should have been validated already, but the wagon lookup will deal with it
760             return false;
761         }
762     }
763 
764     private static boolean isLocal(String host) {
765         return "localhost".equals(host) || "127.0.0.1".equals(host);
766     }
767 
768     /**
769      * Checks the URL to see if this repository refers to a non-localhost repository using HTTP.
770      *
771      * @param originalRepository
772      * @return true if external.
773      */
774     static boolean isExternalHttpRepo(ArtifactRepository originalRepository) {
775         try {
776             URL url = new URL(originalRepository.getUrl());
777             return ("http".equalsIgnoreCase(url.getProtocol())
778                             || "dav".equalsIgnoreCase(url.getProtocol())
779                             || "dav:http".equalsIgnoreCase(url.getProtocol())
780                             || "dav+http".equalsIgnoreCase(url.getProtocol()))
781                     && !isLocal(url.getHost());
782         } catch (MalformedURLException e) {
783             // bad url just skip it here. It should have been validated already, but the wagon lookup will deal with it
784             return false;
785         }
786     }
787 
788     static boolean matchesLayout(ArtifactRepository repository, Mirror mirror) {
789         return matchesLayout(RepositoryUtils.getLayout(repository), mirror.getMirrorOfLayouts());
790     }
791 
792     /**
793      * Checks whether the layouts configured for a mirror match with the layout of the repository.
794      *
795      * @param repoLayout The layout of the repository, may be {@code null}.
796      * @param mirrorLayout The layouts supported by the mirror, may be {@code null}.
797      * @return {@code true} if the layouts associated with the mirror match the layout of the original repository,
798      *         {@code false} otherwise.
799      */
800     static boolean matchesLayout(String repoLayout, String mirrorLayout) {
801         boolean result = false;
802 
803         // simple checks first to short circuit processing below.
804         if ((mirrorLayout == null || mirrorLayout.isEmpty()) || WILDCARD.equals(mirrorLayout)) {
805             result = true;
806         } else if (mirrorLayout.equals(repoLayout)) {
807             result = true;
808         } else {
809             // process the list
810             String[] layouts = mirrorLayout.split(",");
811             for (String layout : layouts) {
812                 // see if this is a negative match
813                 if (layout.length() > 1 && layout.startsWith("!")) {
814                     if (layout.substring(1).equals(repoLayout)) {
815                         // explicitly exclude. Set result and stop processing.
816                         result = false;
817                         break;
818                     }
819                 }
820                 // check for exact match
821                 else if (layout.equals(repoLayout)) {
822                     result = true;
823                     break;
824                 } else if (WILDCARD.equals(layout)) {
825                     result = true;
826                     // don't stop processing in case a future segment explicitly excludes this repo
827                 }
828             }
829         }
830 
831         return result;
832     }
833 }