attribute to DynamicDependency
11 |
12 | ## 1.2.6
13 |
14 | - [#20](https://github.com/qaware/go-offline-maven-plugin/issues/20) Validate the user provided DynamicDependency
15 | configuration and print an error to help the user fix the configuration if it is incorrect.
16 |
17 | ## 1.2.6
18 |
19 | - fixed: Errors when downloading dependencies completely skipped the download of plugins.
20 |
21 | ## 1.2.4
22 |
23 | - [#16](https://github.com/qaware/go-offline-maven-plugin/issues/16) fixed attachedArtifacts with different types/extensions than the main artifact not recognized as part of the reactor build.
24 | - [#16](https://github.com/qaware/go-offline-maven-plugin/issues/16) fixed: 'IgnoreArtifactDescriptorRepositories' flag was always set to true instead of using maven provided value. This could lead to unresolvable artifacts if a dependency declared an additional repository.
25 |
26 | ## 1.2.3
27 |
28 | - [#14](https://github.com/qaware/go-offline-maven-plugin/issues/14) fixed Dependencies not resolving correctly when depending on a reactor artifact and changing one of the transitive dependencies of that artifact via dependency management
29 |
30 | ## 1.2.2
31 |
32 | - [#15](https://github.com/qaware/go-offline-maven-plugin/issues/15) added support for classifier to DynamicDependency configuration
33 |
34 | ## 1.2.1
35 | - [#10](https://github.com/qaware/go-offline-maven-plugin/issues/10) Fixed regression in 1.2.0: Only transitive dependencies of plugins and dynamicDependencies where downloaded,
36 | not the artifact itself.
37 |
38 | ## 1.2.0
39 |
40 | - added ability to fail on errors
41 | - rewrote how dependencies are downloaded. Should fix concurrency issues with broken downloads.
42 |
43 | ##1.1.0
44 |
45 | - [#4](https://github.com/qaware/go-offline-maven-plugin/issues/4) Added downloadJavadoc feature
46 | - [#3](https://github.com/qaware/go-offline-maven-plugin/issues/3) Fixed typos and improve readablility of Readme (thanks [vlow](https://github.com/vlow))
47 |
48 | ## 1.0
49 |
50 | - initial version
--------------------------------------------------------------------------------
/src/main/java/de/qaware/maven/plugin/offline/ReactorArtifact.java:
--------------------------------------------------------------------------------
1 | package de.qaware.maven.plugin.offline;
2 |
3 |
4 | import java.util.Objects;
5 |
6 | /**
7 | * Describes an artifact in the current build reactor. Used to compare artifacts in a set.
8 | *
9 | * To determine if an artifact to download is part of the current reactor (and thus should not be downloaded from the internet)
10 | * we have to test if an artifact with the same groupId, artifactId and version is part of the build reactor.
11 | *
12 | * Since a maven project can output multiple artifacts with different types and classifiers, we explicitly do not test
13 | * for those properties. This is not 100% correct, since it theoretically possible to output an artifact with the same
14 | * groupId:artifactId:version identifier and different type/classifier from different projects. But the information on
15 | * which additional artifacts are produced by a project are not available to the go-offline-maven plugin, since they are
16 | * added dynamically at build time. So we have to live with this fuzziness.
17 | *
18 | * @author andreas.janning
19 | */
20 | public class ReactorArtifact {
21 |
22 | private final String groupId;
23 | private final String artifactId;
24 | private final String version;
25 |
26 | /**
27 | * Convert a maven artifact to a ReactorArtifact
28 | *
29 | * @param mavenArtifact the artifact to create a ReactorArtifact for.
30 | */
31 | public ReactorArtifact(org.apache.maven.artifact.Artifact mavenArtifact) {
32 | this(mavenArtifact.getGroupId(), mavenArtifact.getArtifactId(), mavenArtifact.getBaseVersion());
33 | }
34 |
35 | /**
36 | * Convert a aether artifact to a ReactorArtifact
37 | *
38 | * @param aetherArtifact the artifact to create a ReactorArtifact for.
39 | */
40 | public ReactorArtifact(org.eclipse.aether.artifact.Artifact aetherArtifact) {
41 | this(aetherArtifact.getGroupId(), aetherArtifact.getArtifactId(), aetherArtifact.getBaseVersion());
42 | }
43 |
44 | private ReactorArtifact(String groupId, String artifactId, String version) {
45 | this.groupId = groupId;
46 | this.artifactId = artifactId;
47 | this.version = version;
48 | }
49 |
50 | @Override
51 | public boolean equals(Object o) {
52 | if (this == o) return true;
53 | if (o == null || getClass() != o.getClass()) return false;
54 | ReactorArtifact that = (ReactorArtifact) o;
55 | return groupId.equals(that.groupId) &&
56 | artifactId.equals(that.artifactId) &&
57 | version.equals(that.version);
58 | }
59 |
60 | @Override
61 | public int hashCode() {
62 | return Objects.hash(groupId, artifactId, version);
63 | }
64 |
65 | @Override
66 | public String toString() {
67 | final StringBuilder sb = new StringBuilder("ReactorArtifact{");
68 | sb.append("groupId='").append(groupId).append('\'');
69 | sb.append(", artifactId='").append(artifactId).append('\'');
70 | sb.append(", version='").append(version).append('\'');
71 | sb.append('}');
72 | return sb.toString();
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/de/qaware/maven/plugin/offline/AbstractGoOfflineMojo.java:
--------------------------------------------------------------------------------
1 | package de.qaware.maven.plugin.offline;
2 |
3 | import org.apache.maven.artifact.repository.ArtifactRepository;
4 | import org.apache.maven.execution.MavenSession;
5 | import org.apache.maven.plugin.AbstractMojo;
6 | import org.apache.maven.plugins.annotations.Parameter;
7 | import org.apache.maven.project.DefaultProjectBuildingRequest;
8 | import org.apache.maven.project.MavenProject;
9 | import org.apache.maven.project.ProjectBuildingRequest;
10 |
11 | import java.util.Collections;
12 | import java.util.List;
13 |
14 | /**
15 | * Base class for mojos in the in the go-offline maven plugin.
16 | *
17 | * Provides access to parameters and injected configuration needed by the plugin.
18 | *
19 | * Also provides functionality to schedule tasks for asynchronous completion.
20 | *
21 | * @author Andreas Janning andreas.janning@qaware.de
22 | */
23 | public abstract class AbstractGoOfflineMojo extends AbstractMojo {
24 |
25 | /**
26 | * Remote repositories used to download dependencies.
27 | */
28 | @Parameter(defaultValue = "${project.remoteArtifactRepositories}", readonly = true, required = true)
29 | private List remoteRepositories;
30 |
31 | /**
32 | * Remote repositories used to download plugins.
33 | */
34 | @Parameter(defaultValue = "${project.pluginArtifactRepositories}", readonly = true, required = true)
35 | private List remotePluginRepositories;
36 |
37 | /**
38 | * Contains the full list of projects in the reactor.
39 | */
40 | @Parameter(defaultValue = "${reactorProjects}", readonly = true)
41 | private List reactorProjects;
42 |
43 | /**
44 | * The Maven session.
45 | */
46 | @Parameter(defaultValue = "${session}", readonly = true, required = true)
47 | private MavenSession session;
48 |
49 | private ProjectBuildingRequest buildingRequest;
50 |
51 | AbstractGoOfflineMojo() {
52 | // Noop
53 | }
54 |
55 | /**
56 | * Returns a building request initialized with the data of the current maven session
57 | *
58 | * @return a building request initialized with the data of the current maven session
59 | */
60 | protected ProjectBuildingRequest getBuildingRequest() {
61 | if (buildingRequest == null) {
62 | buildingRequest = new DefaultProjectBuildingRequest(session.getProjectBuildingRequest());
63 | buildingRequest.setRemoteRepositories(remoteRepositories);
64 | buildingRequest.setPluginArtifactRepositories(remotePluginRepositories);
65 | buildingRequest.setRepositoryMerging(ProjectBuildingRequest.RepositoryMerging.REQUEST_DOMINANT);
66 | buildingRequest.setResolveDependencies(true);
67 | }
68 | return buildingRequest;
69 | }
70 |
71 | /**
72 | * Returns the full list of projects in the current build-reactor
73 | *
74 | * @return the full list of projects in the current build-reactor
75 | */
76 | protected List getReactorProjects() {
77 | return Collections.unmodifiableList(reactorProjects);
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/de/qaware/maven/plugin/offline/ResolveDependenciesMojo.java:
--------------------------------------------------------------------------------
1 | package de.qaware.maven.plugin.offline;
2 |
3 | import org.apache.maven.model.Plugin;
4 | import org.apache.maven.plugin.MojoExecutionException;
5 | import org.apache.maven.plugins.annotations.Component;
6 | import org.apache.maven.plugins.annotations.Mojo;
7 | import org.apache.maven.plugins.annotations.Parameter;
8 | import org.apache.maven.project.MavenProject;
9 |
10 | import java.util.ArrayList;
11 | import java.util.HashSet;
12 | import java.util.List;
13 | import java.util.Set;
14 |
15 | /**
16 | * Mojo used to download all dependencies of a project or reactor to the local repository.
17 | *
18 | * This includes:
19 | *
20 | * - Direct and transitive dependencies declared in POMs
21 | * - All plugins used for the build and their transitive dependencies
22 | * - Dependencies of plugins declared in POMs
23 | * - DynamicDependencies configured in the go-offline-maven-plugin configuration
24 | *
25 | *
26 | * @author Andreas Janning andreas.janning@qaware.de
27 | */
28 | @Mojo(name = "resolve-dependencies", threadSafe = true, requiresOnline = true, aggregator = true)
29 | public class ResolveDependenciesMojo extends AbstractGoOfflineMojo {
30 |
31 | @Component
32 | private DependencyDownloader dependencyDownloader;
33 |
34 | @Parameter
35 | private List dynamicDependencies;
36 |
37 | @Parameter(defaultValue = "false", property = "downloadSources")
38 | private boolean downloadSources;
39 |
40 | @Parameter(defaultValue = "false", property = "downloadJavadoc")
41 | private boolean downloadJavadoc;
42 |
43 | @Parameter(defaultValue = "false", property = "failOnErrors")
44 | private boolean failOnErrors;
45 |
46 | ResolveDependenciesMojo() {
47 | // Noop
48 | }
49 |
50 | public void execute() throws MojoExecutionException {
51 | validateConfiguration();
52 | dependencyDownloader.init(getBuildingRequest(), getReactorProjects(), getLog());
53 | if (downloadSources) {
54 | dependencyDownloader.enableDownloadSources();
55 | }
56 | if (downloadJavadoc) {
57 | dependencyDownloader.enableDownloadJavadoc();
58 | }
59 |
60 | List allPlugins = new ArrayList<>();
61 | for (MavenProject mavenProject : getReactorProjects()) {
62 | List buildPlugins = mavenProject.getBuildPlugins();
63 | allPlugins.addAll(buildPlugins);
64 | }
65 |
66 | Set artifactsToDownload = new HashSet<>();
67 |
68 |
69 | for (Plugin plugin : allPlugins) {
70 | artifactsToDownload.addAll(dependencyDownloader.resolvePlugin(plugin));
71 | }
72 | for (MavenProject project : getReactorProjects()) {
73 | artifactsToDownload.addAll(dependencyDownloader.resolveDependencies(project));
74 | }
75 | if (dynamicDependencies != null) {
76 | for (DynamicDependency dep : dynamicDependencies) {
77 | artifactsToDownload.addAll(dependencyDownloader.resolveDynamicDependency(dep));
78 | }
79 | }
80 |
81 | dependencyDownloader.downloadArtifacts(artifactsToDownload);
82 |
83 |
84 | List errors = dependencyDownloader.getErrors();
85 | for (Exception error : errors) {
86 | getLog().warn(error.getMessage());
87 | }
88 |
89 | if (failOnErrors && !errors.isEmpty()) {
90 | throw new MojoExecutionException("Unable to download dependencies, consult the errors and warnings printed above.");
91 | }
92 | }
93 |
94 | private void validateConfiguration() throws MojoExecutionException {
95 | if (dynamicDependencies != null) {
96 | for (DynamicDependency dynamicDependency : dynamicDependencies) {
97 | dynamicDependency.validate();
98 | }
99 | }
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/src/main/java/de/qaware/maven/plugin/offline/DynamicDependency.java:
--------------------------------------------------------------------------------
1 | package de.qaware.maven.plugin.offline;
2 |
3 | import org.apache.maven.plugin.MojoExecutionException;
4 |
5 | /**
6 | * Configuration used to declare extra dependencies for the {@link ResolveDependenciesMojo}.
7 | *
8 | * Users can declare extra dependencies that do not appear in any dependency tree of the project but are still needed for the build to work.
9 | *
10 | * The most common examples are artifacts that are dynamically loaded by plugins during build runtime
11 | *
12 | * @author Andreas Janning andreas.janning@qaware.de
13 | */
14 | public class DynamicDependency {
15 |
16 | /** The config error message */
17 | public static final String CONFIGURATION_ERROR_MESSAGE = "DynamicDependency configuration error";
18 |
19 | private String artifactId;
20 | private String groupId;
21 | private String version;
22 | private String classifier;
23 | private String type;
24 | private RepositoryType repositoryType;
25 |
26 | DynamicDependency() {
27 | // Noop
28 | }
29 |
30 | /**
31 | * Validate that all required parameters are set.
32 | *
33 | * @throws MojoExecutionException if any required parameter is not set
34 | */
35 | public void validate() throws MojoExecutionException {
36 | if (artifactId == null || artifactId.isEmpty()) {
37 | throw new MojoExecutionException(this, CONFIGURATION_ERROR_MESSAGE, "Invalid " + this + ": The artifactId must not empty");
38 | }
39 | if (groupId == null || groupId.isEmpty()) {
40 | throw new MojoExecutionException(this, CONFIGURATION_ERROR_MESSAGE, "Invalid " + this + ": The groupId must not empty");
41 | }
42 | if (version == null || version.isEmpty()) {
43 | throw new MojoExecutionException(this, CONFIGURATION_ERROR_MESSAGE, "Invalid " + this + ": The version must not empty");
44 | }
45 | if (repositoryType == null) {
46 | throw new MojoExecutionException(this, CONFIGURATION_ERROR_MESSAGE, "Invalid " + this + ": The repositoryType must be defined");
47 | }
48 | }
49 |
50 | /**
51 | * Returns the artifactId of the {@link DynamicDependency}
52 | *
53 | * @return The artifactId of the {@link DynamicDependency}
54 | */
55 | public String getArtifactId() {
56 | return artifactId;
57 | }
58 |
59 | /**
60 | * Set the artifactId
61 | *
62 | * @param artifactId - Id to set
63 | */
64 | public void setArtifactId(String artifactId) {
65 | this.artifactId = artifactId;
66 | }
67 |
68 | /**
69 | * Returns the groupId of the {@link DynamicDependency}
70 | *
71 | * @return The groupId of the {@link DynamicDependency}
72 | */
73 | public String getGroupId() {
74 | return groupId;
75 | }
76 |
77 | /**
78 | * Set the groupId
79 | *
80 | * @param groupId - Id to set
81 | */
82 | public void setGroupId(String groupId) {
83 | this.groupId = groupId;
84 | }
85 |
86 | /**
87 | * Returns the version of the {@link DynamicDependency}
88 | *
89 | * @return The version of the {@link DynamicDependency}
90 | */
91 | public String getVersion() {
92 | return version;
93 | }
94 |
95 | /**
96 | * Set the version
97 | *
98 | * @param version - Version to set
99 | */
100 | public void setVersion(String version) {
101 | this.version = version;
102 | }
103 |
104 | /**
105 | * Either returns the user entered value or "jar" as a default if the user provided no value.
106 | *
107 | * @return The type of the {@link DynamicDependency}.
108 | */
109 | public String getType() {
110 | if (type == null || type.isEmpty()) {
111 | return "jar";
112 | }
113 | return type;
114 | }
115 |
116 | /**
117 | * Set the type
118 | *
119 | * @param type - Type to set
120 | */
121 | public void setType(String type) {
122 | this.type = type;
123 | }
124 |
125 | /**
126 | * Returns the classifier of the {@link DynamicDependency}. May be null.
127 | *
128 | * @return The classifier of the {@link DynamicDependency}. May be null.
129 | */
130 | public String getClassifier() {
131 | return classifier;
132 | }
133 |
134 | /**
135 | * Set the classifier
136 | *
137 | * @param classifier - classifier to set
138 | */
139 | public void setClassifier(String classifier) {
140 | this.classifier = classifier;
141 | }
142 |
143 | /**
144 | * Returns from which type of remoteRepository this dependency must be downloaded
145 | *
146 | * @return from which type of remoteRepository this dependency must be downloaded
147 | */
148 | public RepositoryType getRepositoryType() {
149 | return repositoryType;
150 | }
151 |
152 | /**
153 | * Set the type of remoteRepository from which the dependency should be downloaded
154 | *
155 | * @param repositoryType - The repository type to set
156 | */
157 | public void setRepositoryType(RepositoryType repositoryType) {
158 | this.repositoryType = repositoryType;
159 | }
160 |
161 | @Override
162 | public String toString() {
163 | return "DynamicDependency{" +
164 | "artifactId='" + artifactId + '\'' +
165 | ", groupId='" + groupId + '\'' +
166 | ", version='" + version + '\'' +
167 | ", classifier='" + classifier + '\'' +
168 | ", repositoryType=" + repositoryType +
169 | '}';
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | # Go Offline Maven Plugin
2 | [](https://opensource.org/licenses/Apache-2.0)
3 | [](https://maven-badges.herokuapp.com/maven-central/de.qaware.maven/go-offline-maven-plugin)
4 |
5 | Maven Plugin used to download all Dependencies and Plugins required in a Maven build,
6 | so the build can be run without an internet connection afterwards.
7 |
8 | This is especially relevant for modern CI-Systems like Gitlab and Circle-CI which
9 | need a consistent local Maven repository in their cache to build efficiently.
10 |
11 | The plugin can also be used to download all source files of all transitive dependencies
12 | of a project.
13 |
14 | Maven already has an official way to do all this: the maven-dependency-plugin go-offline goal;
15 | Unfortunately, the go-offline goal suffers from several drawbacks:
16 |
17 | - Multi-Module builds are not supported since the plugin tries to download reactor-dependencies from the remote repository
18 | - Most parameters simply do not work
19 | - There is no option to download dynamic dependencies
20 |
21 | The Go Offline Maven Plugin fixes these drawbacks.
22 |
23 | ## Requirements
24 | - Java 1.7 or higher
25 | - Maven 3.1.x or higher
26 |
27 | **Warning:** Maven 3.5.2 has a Bug that causes the Plugin to hang. If you experience hangups during downloading dependencies, please upgrade to Maven 3.5.3 or higher (See [MNG-6323](https://issues.apache.org/jira/browse/MNG-6323) )
28 |
29 | **Warning:** Maven versions 3.2.x and 3.3.x have a bug that can cause the plugin to fail if maven is started in parallel build mode (-T option). Please call the go-offline-maven-plugin
30 | without the -T option or upgrade Maven to a newer version. (See [MNG-6170](https://issues.apache.org/jira/browse/MNG-6170))
31 |
32 | ## Goals
33 | The Go Offline Maven Plugin only has one goal: "resolve-dependencies". This goal downloads
34 | all external dependencies and plugins needed for your build to your local repository.
35 | Dependencies that are built inside the reactor build of your project are excluded. For downloading,
36 | the repositories specified in your pom.xml are used.
37 |
38 | ## Usage
39 | Simply add the plugin to the pom.xml of your project. Use the root reactor pom in case of a multi module project.
40 | Make sure to configure any dynamic dependency your project has (see below).
41 |
42 |
43 | de.qaware.maven
44 | go-offline-maven-plugin
45 | 1.2.8
46 |
47 |
48 |
49 | org.apache.maven.surefire
50 | surefire-junit4
51 | 2.20.1
52 | PLUGIN
53 |
54 |
55 | com.querydsl
56 | querydsl-apt
57 | 4.2.1
58 | jpa
59 | MAIN
60 |
61 |
62 | org.flywaydb
63 | flyway-commandline
64 | 4.0.3
65 | zip
66 | MAIN
67 |
68 |
69 |
70 |
71 |
72 | To download all dependencies to your local repository, use
73 |
74 | mvn de.qaware.maven:go-offline-maven-plugin:resolve-dependencies
75 |
76 | Make sure to activate any profiles etc. so that all relevant modules of your project are included
77 | in the Maven run.
78 |
79 | ### Dynamic Dependencies
80 | Unfortunately some Maven Plugins dynamically load additional dependencies when they are run. Since those
81 | dependencies are not necessarily specified anywhere in the plugins pom.xml, the Go Offline Maven Plugin
82 | cannot know that it has to download those dependencies. Most prominently, the surefire-maven-plugin dynamically
83 | loads test-providers based on the tests it finds in the project.
84 |
85 | You must tell the Go Offline Maven Plugin of those dynamic depenencies to ensure all dependencies are downloaded.
86 | For each dependency, add a DynamicDependency block to the plugin's configuration as seen in the [Usage](#usage) section.
87 | Each dynamic dependency block consists of the following parameters:
88 |
89 | - *groupId* The GroupId of the dynamic dependency to download
90 | - *artifactId* The ArtifactId of the dynamic dependency to download
91 | - *version* The version of the dynamic dependency to download
92 | - *classifier* (optional) The classifier of the dynamic dependency to download
93 | - *type* (optional) The type of the dynamic dependency to download
94 | - *repositoryType* Either 'MAIN' or 'PLUGIN' to control from which repository the dependency is downloaded
95 |
96 | Note that Plugins are not consistent about where they pull their dynamic dependencies from. Some use the Plugin-Repository
97 | , some the Main-Repository. If one doesn't work, try the other.
98 |
99 | ### Downloading Sources and Javadoc
100 | The plugin can also download the source files and/or javadoc of the project's transitive dependencies. This behaviour can either be activated via the pom.xml
101 | or a command line parameter.
102 |
103 |
104 | de.qaware.maven
105 | go-offline-maven-plugin
106 | 1.2.8
107 |
108 | true
109 | true
110 |
111 |
112 |
113 | or
114 |
115 | mvn de.qaware.maven:go-offline-maven-plugin:resolve-dependencies -DdownloadSources -DdownloadJavadoc
116 |
117 | ### Usage in CI environments
118 | The Go Offline Maven Plugin can be used to build a clean repository for build server environments. The resulting repository includes exactly the dependencies and
119 | plugins needed for building the project.
120 |
121 | #### Gitlab
122 |
123 | For gitlab, add the following build step to the front of your pipeline:
124 |
125 | download-dependencies:
126 | image: maven:3-jdk-8
127 | stage: prepare
128 | script:
129 | - 'mvn de.qaware.maven:go-offline-maven-plugin:1.2.8:resolve-dependencies -Dmaven.repo.local=.m2/repository'
130 | cache:
131 | key: M2_REPO
132 | paths:
133 | - .m2/repository
134 |
135 | This will fill the cache "M2_REPO" with all needed artifacts, reusing the previous "M2_REPO" cache to avoid downloading all artifacts on each run.
136 |
137 | Build steps using the repository may then be configured like this:
138 |
139 | .build
140 | image: maven:3-jdk-8
141 | stage: build
142 | script:
143 | - 'mvn install -Dmaven.repo.local=.m2/repository'
144 | cache:
145 | key: M2_REPO
146 | paths:
147 | - .m2/repository
148 | policy: pull
149 |
150 | This will pull the previously filled cache into the build image and use it as the local maven repository.
151 | Policy: pull ensures that artifacts that are generated as part of the build are not written back to the cache
152 | .
153 |
154 | ## License
155 |
156 | Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0.txt)
157 |
158 |
--------------------------------------------------------------------------------
/License.txt:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | de.qaware.maven
8 | go-offline-maven-plugin
9 | 1.2.8
10 | maven-plugin
11 | Go Offline Maven Plugin
12 | Maven Plugin used to download all Dependencies and Plugins required in a Maven build,
13 | so the build can be run without an internet connection afterwards.
14 |
15 | https://github.com/qaware/go-offline-maven-plugin
16 |
17 | 2018
18 |
19 |
20 | Apache License, Version 2.0
21 | https://www.apache.org/licenses/LICENSE-2.0.txt
22 |
23 |
24 |
25 | QAware GmbH
26 | https://www.qaware.de/
27 |
28 |
29 |
30 | ajanning
31 | Andreas Janning
32 | andreas.janning@qaware.de
33 | QAware GmbH
34 | https://www.qaware.de/
35 |
36 |
37 |
38 |
39 | scm:git:https://github.com/qaware/go-offline-maven-plugin.git
40 | scm:git:https://github.com/qaware/go-offline-maven-plugin.git
41 | scm:git:https://github.com/qaware/go-offline-maven-plugin/tree/master
42 |
43 |
44 |
45 | GitHub
46 | https://github.com/qaware/go-offline-maven-plugin/issues
47 |
48 |
49 |
50 | 3.8.6
51 | UTF-8
52 | 1.8
53 | 1.8
54 | 3.6.4
55 |
56 |
57 |
58 | ${mavenVersion}
59 |
60 |
61 |
62 |
63 |
64 | org.apache.maven
65 | maven-core
66 | ${mavenVersion}
67 | true
68 | provided
69 |
70 |
71 |
72 | org.apache.maven
73 | maven-model
74 | ${mavenVersion}
75 | true
76 | provided
77 |
78 |
79 |
80 | org.apache.maven
81 | maven-settings
82 | ${mavenVersion}
83 | true
84 | provided
85 |
86 |
87 |
88 | org.apache.maven
89 | maven-settings-builder
90 | ${mavenVersion}
91 | true
92 | provided
93 |
94 |
95 |
96 | org.apache.maven
97 | maven-builder-support
98 | ${mavenVersion}
99 | true
100 | provided
101 |
102 |
103 |
104 | org.apache.maven
105 | maven-repository-metadata
106 | ${mavenVersion}
107 | true
108 | provided
109 |
110 |
111 |
112 | org.apache.maven
113 | maven-artifact
114 | ${mavenVersion}
115 | true
116 | provided
117 |
118 |
119 |
120 | org.apache.maven
121 | maven-plugin-api
122 | ${mavenVersion}
123 | true
124 | provided
125 |
126 |
127 |
128 | org.apache.maven
129 | maven-model-builder
130 | ${mavenVersion}
131 | true
132 | provided
133 |
134 |
135 |
136 | org.apache.maven
137 | maven-resolver-provider
138 | ${mavenVersion}
139 | true
140 | provided
141 |
142 |
143 |
144 |
145 | org.apache.maven.plugin-tools
146 | maven-plugin-annotations
147 | ${maven.plugin.tools.version}
148 | true
149 |
150 |
151 |
152 |
153 |
154 |
155 | org.apache.maven.plugins
156 | maven-enforcer-plugin
157 | true
158 |
159 |
160 | enforce-versions
161 |
162 | enforce
163 |
164 |
165 |
166 |
167 | ${mavenVersion}
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 | org.apache.maven.plugins
177 | maven-source-plugin
178 |
179 |
180 | attach-sources
181 | verify
182 |
183 | jar-no-fork
184 |
185 |
186 |
187 |
188 |
189 | org.apache.maven.plugins
190 | maven-javadoc-plugin
191 |
192 |
193 | attach-javadoc
194 | verify
195 |
196 | jar
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 | org.apache.maven.plugins
206 | maven-clean-plugin
207 | 3.2.0
208 |
209 |
210 | org.apache.maven.plugins
211 | maven-compiler-plugin
212 | 3.10.1
213 |
214 |
215 | org.apache.maven.plugins
216 | maven-deploy-plugin
217 | 3.0.0
218 |
219 |
220 | org.apache.maven.plugins
221 | maven-enforcer-plugin
222 | 3.1.0
223 |
224 |
225 | org.apache.maven.plugins
226 | maven-install-plugin
227 | 3.0.1
228 |
229 |
230 | org.apache.maven.plugins
231 | maven-jar-plugin
232 | 3.3.0
233 |
234 |
235 | org.apache.maven.plugins
236 | maven-javadoc-plugin
237 | 3.4.1
238 |
239 |
240 | org.apache.maven.plugins
241 | maven-plugin-plugin
242 | ${maven.plugin.tools.version}
243 |
244 |
245 | org.apache.maven.plugins
246 | maven-project-info-reports-plugin
247 | 3.4.1
248 |
249 |
250 | org.apache.maven.plugins
251 | maven-resources-plugin
252 | 3.3.0
253 |
254 |
255 | org.apache.maven.plugins
256 | maven-site-plugin
257 | 4.0.0-M3
258 |
259 |
260 | org.apache.maven.plugins
261 | maven-source-plugin
262 | 3.2.1
263 |
264 |
265 | org.apache.maven.plugins
266 | maven-surefire-plugin
267 | 3.0.0-M7
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 | org.apache.maven.plugins
277 | maven-project-info-reports-plugin
278 | 3.4.1
279 |
280 |
281 |
282 |
283 |
284 |
285 | bintray-qaware-oss
286 | https://api.bintray.com/maven/qaware-oss/maven/go-offline-maven-plugin/;publish=1
287 |
288 |
289 |
--------------------------------------------------------------------------------
/src/main/java/de/qaware/maven/plugin/offline/DependencyDownloader.java:
--------------------------------------------------------------------------------
1 | package de.qaware.maven.plugin.offline;
2 |
3 | import org.apache.maven.RepositoryUtils;
4 | import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
5 | import org.apache.maven.model.DependencyManagement;
6 | import org.apache.maven.model.Plugin;
7 | import org.apache.maven.plugin.logging.Log;
8 | import org.apache.maven.project.MavenProject;
9 | import org.apache.maven.project.ProjectBuildingRequest;
10 | import org.codehaus.plexus.component.annotations.Component;
11 | import org.codehaus.plexus.component.annotations.Requirement;
12 | import org.eclipse.aether.DefaultRepositoryCache;
13 | import org.eclipse.aether.DefaultRepositorySystemSession;
14 | import org.eclipse.aether.RepositoryException;
15 | import org.eclipse.aether.RepositorySystem;
16 | import org.eclipse.aether.RepositorySystemSession;
17 | import org.eclipse.aether.artifact.Artifact;
18 | import org.eclipse.aether.artifact.ArtifactType;
19 | import org.eclipse.aether.artifact.ArtifactTypeRegistry;
20 | import org.eclipse.aether.artifact.DefaultArtifact;
21 | import org.eclipse.aether.collection.CollectRequest;
22 | import org.eclipse.aether.collection.CollectResult;
23 | import org.eclipse.aether.collection.DependencyCollectionException;
24 | import org.eclipse.aether.collection.DependencySelector;
25 | import org.eclipse.aether.graph.Dependency;
26 | import org.eclipse.aether.graph.DependencyNode;
27 | import org.eclipse.aether.graph.DependencyVisitor;
28 | import org.eclipse.aether.repository.RemoteRepository;
29 | import org.eclipse.aether.resolution.ArtifactRequest;
30 | import org.eclipse.aether.resolution.ArtifactResolutionException;
31 | import org.eclipse.aether.util.graph.selector.AndDependencySelector;
32 | import org.eclipse.aether.util.graph.selector.ExclusionDependencySelector;
33 | import org.eclipse.aether.util.graph.selector.OptionalDependencySelector;
34 | import org.eclipse.aether.util.graph.selector.ScopeDependencySelector;
35 |
36 | import java.lang.reflect.Constructor;
37 | import java.util.ArrayList;
38 | import java.util.Collection;
39 | import java.util.Collections;
40 | import java.util.HashSet;
41 | import java.util.List;
42 | import java.util.Set;
43 |
44 | /**
45 | * Downloads artifacts for project dependencies and plugins. This class maintains two separate sessions with separate caches
46 | * for project and plugin dependencies so all artifacts are resolved for all remote repository contexts.
47 | *
48 | * The downloader must be initialized by calling {@link #init(ProjectBuildingRequest, List, Log)} before any of its other methods my be used.
49 | *
50 | * This class only works for maven versions >=3.1
51 | *
52 | * @author Andreas Janning andreas.janning@qaware.de
53 | */
54 | @Component(role = DependencyDownloader.class, hint = "default")
55 | public class DependencyDownloader {
56 |
57 | /**
58 | * Artifact type for maven plugins.
59 | */
60 | private static final String MAVEN_PLUGIN_ARTIFACT_TYPE = "maven-plugin";
61 |
62 | /**
63 | * Aether repository system
64 | */
65 | @Requirement
66 | private RepositorySystem repositorySystem;
67 |
68 | /**
69 | * Maven artifact handler manager
70 | */
71 | @Requirement
72 | private ArtifactHandlerManager artifactHandlerManager;
73 |
74 | private DefaultRepositorySystemSession remoteSession;
75 | private DefaultRepositorySystemSession pluginSession;
76 | private List remoteRepositories;
77 | private List pluginRepositories;
78 | private ArtifactTypeRegistry typeRegistry;
79 | private Log log;
80 | private List errors;
81 |
82 | private boolean downloadSources = false;
83 | private boolean downloadJavadoc = false;
84 | private Set reactorArtifacts;
85 |
86 | DependencyDownloader() {
87 | // Noop
88 | }
89 |
90 | /**
91 | * Initialize the DependencyDownloader
92 | *
93 | * @param buildingRequest a buildingRequest containing the maven session and Repositories to be used to download artifacts
94 | * @param reactorProjects the reactorProjects of the current build used to exclude reactor artifacts from the dependency download.
95 | * @param logger used to log infos and warnings.
96 | */
97 | public void init(ProjectBuildingRequest buildingRequest, List reactorProjects, Log logger) {
98 | this.log = logger;
99 | typeRegistry = RepositoryUtils.newArtifactTypeRegistry(artifactHandlerManager);
100 | remoteRepositories = RepositoryUtils.toRepos(buildingRequest.getRemoteRepositories());
101 | pluginRepositories = RepositoryUtils.toRepos(buildingRequest.getPluginArtifactRepositories());
102 | remoteSession = new DefaultRepositorySystemSession(buildingRequest.getRepositorySession());
103 |
104 | DependencySelector wagonExcluder = null;
105 | try {
106 | Class> wagonExcluderClass = Class.forName("org.apache.maven.plugin.internal.WagonExcluder");
107 | Constructor> wagonExcluderConstructor = wagonExcluderClass.getDeclaredConstructor();
108 | wagonExcluderConstructor.setAccessible(true);
109 | wagonExcluder = (DependencySelector) wagonExcluderConstructor.newInstance();
110 | } catch (ReflectiveOperationException e) {
111 | log.warn("Could not initialize wagonExcluder, might not be able to download plugin dependencies correctly", e);
112 | }
113 |
114 | reactorArtifacts = computeReactorArtifacts(reactorProjects);
115 | DependencySelector selector = new AndDependencySelector(new ScopeDependencySelector("system", "test", "provided"), new OptionalDependencySelector(), new ExclusionDependencySelector());
116 | remoteSession.setDependencySelector(selector);
117 |
118 | pluginSession = new DefaultRepositorySystemSession(remoteSession);
119 | remoteSession.setCache(new DefaultRepositoryCache());
120 | pluginSession.setCache(new DefaultRepositoryCache());
121 | if (wagonExcluder != null) {
122 | pluginSession.setDependencySelector(new AndDependencySelector(new ScopeDependencySelector("system", "test", "provided"), new OptionalDependencySelector(), wagonExcluder, new ExclusionDependencySelector()));
123 | }
124 | this.errors = new ArrayList<>();
125 | }
126 |
127 | /**
128 | * Enable the download of the source artifacts.
129 | */
130 | public void enableDownloadSources() {
131 | this.downloadSources = true;
132 | }
133 |
134 | /**
135 | * Enable the download of the Javadoc artifacts.
136 | */
137 | public void enableDownloadJavadoc() {
138 | this.downloadJavadoc = true;
139 | }
140 |
141 | /**
142 | * Download the collection of artifacts
143 | *
144 | * @param artifacts the collection of ReactorArtifacts that wants to be downloaded.
145 | */
146 | public void downloadArtifacts(Collection artifacts) {
147 | List mainRequests = new ArrayList<>(artifacts.size());
148 | List pluginRequests = new ArrayList<>(artifacts.size());
149 | for (ArtifactWithRepoType artifactWithRepoType : artifacts) {
150 | Artifact artifact = artifactWithRepoType.getArtifact();
151 | RepositoryType context = artifactWithRepoType.getRepositoryType();
152 |
153 | ArtifactRequest artifactRequest = new ArtifactRequest();
154 | artifactRequest.setArtifact(artifact);
155 | artifactRequest.setRepositories(context == RepositoryType.MAIN ? remoteRepositories : pluginRepositories);
156 | if (context == RepositoryType.MAIN) {
157 | artifactRequest.setRequestContext(context.getRequestContext());
158 | mainRequests.add(artifactRequest);
159 |
160 | } else {
161 | artifactRequest.setRequestContext(context.getRequestContext());
162 | pluginRequests.add(artifactRequest);
163 | }
164 | if (context == RepositoryType.MAIN && "jar".equals(artifact.getExtension())) {
165 | if (downloadSources) {
166 | Artifact sourceArtifact = new DefaultArtifact(artifact.getGroupId(), artifact.getArtifactId(), "sources", artifact.getExtension(), artifact.getVersion());
167 | mainRequests.add(new ArtifactRequest(sourceArtifact, remoteRepositories, context.getRequestContext()));
168 | }
169 | if (downloadJavadoc) {
170 | Artifact javadocArtifact = new DefaultArtifact(artifact.getGroupId(), artifact.getArtifactId(), "javadoc", artifact.getExtension(), artifact.getVersion());
171 | mainRequests.add(new ArtifactRequest(javadocArtifact, remoteRepositories, context.getRequestContext()));
172 | }
173 | }
174 | }
175 | try {
176 | repositorySystem.resolveArtifacts(remoteSession, mainRequests);
177 | } catch (ArtifactResolutionException | RuntimeException e) {
178 | log.error("Error downloading dependencies for project");
179 | handleRepositoryException(e);
180 | }
181 | try {
182 | repositorySystem.resolveArtifacts(pluginSession, pluginRequests);
183 | } catch (ArtifactResolutionException | RuntimeException e) {
184 | log.error("Error downloading plugin dependencies for project");
185 | handleRepositoryException(e);
186 | }
187 | }
188 |
189 | /**
190 | * Download all dependencies of a maven project including transitive dependencies.
191 | * Dependencies that refer to an artifact in the current reactor build are ignored.
192 | * Transitive dependencies that are marked as optional are ignored
193 | * Transitive dependencies with the scopes "test", "system" and "provided" are ignored.
194 | *
195 | * @param project the project to download the dependencies for.
196 | * @return The set of resolved ArtifactRepositoryType pairs
197 | */
198 | public Set resolveDependencies(MavenProject project) {
199 | Artifact projectArtifact = RepositoryUtils.toArtifact(project.getArtifact());
200 | CollectRequest collectRequest = new CollectRequest();
201 | collectRequest.setRepositories(remoteRepositories);
202 | collectRequest.setRootArtifact(projectArtifact);
203 | collectRequest.setRequestContext(RepositoryType.MAIN.getRequestContext());
204 |
205 | List aetherDependencies = new ArrayList<>();
206 | for (org.apache.maven.model.Dependency d : project.getDependencies()) {
207 | Dependency dependency = RepositoryUtils.toDependency(d, typeRegistry);
208 | aetherDependencies.add(dependency);
209 | }
210 |
211 | collectRequest.setDependencies(aetherDependencies);
212 |
213 | List aetherDepManagement = new ArrayList<>();
214 | DependencyManagement dependencyManagement = project.getDependencyManagement();
215 | if (dependencyManagement != null) {
216 | for (org.apache.maven.model.Dependency d : dependencyManagement.getDependencies()) {
217 | Dependency dependency = RepositoryUtils.toDependency(d, typeRegistry);
218 | aetherDepManagement.add(dependency);
219 | }
220 | }
221 | collectRequest.setManagedDependencies(aetherDepManagement);
222 |
223 | try {
224 | CollectResult collectResult = repositorySystem.collectDependencies(remoteSession, collectRequest);
225 | return getArtifactsFromCollectResult(collectResult, RepositoryType.MAIN);
226 | } catch (RepositoryException | RuntimeException e) {
227 | log.error("Error resolving dependencies for project " + project.getGroupId() + ":" + project.getArtifactId());
228 | handleRepositoryException(e);
229 | }
230 | return Collections.emptySet();
231 | }
232 |
233 | private Set getArtifactsFromCollectResult(CollectResult collectResult, RepositoryType context) {
234 | CollectAllDependenciesVisitor visitor = new CollectAllDependenciesVisitor();
235 | collectResult.getRoot().accept(visitor);
236 | Set visitorArtifacts = visitor.getArtifacts();
237 | Set artifacts = new HashSet<>();
238 | for (Artifact visitorArtifact : visitorArtifacts) {
239 | if (!isReactorArtifact(visitorArtifact)) {
240 | artifacts.add(new ArtifactWithRepoType(visitorArtifact, context));
241 | }
242 | }
243 | Artifact rootArtifact = collectResult.getRoot().getArtifact();
244 | if (!isReactorArtifact(rootArtifact)) {
245 | artifacts.add(new ArtifactWithRepoType(rootArtifact, context));
246 | }
247 | return artifacts;
248 | }
249 |
250 | /**
251 | * Download a plugin, all of its transitive dependencies and dependencies declared on the plugin declaration.
252 | *
253 | * Dependencies and plugin artifacts that refer to an artifact in the current reactor build are ignored.
254 | * Transitive dependencies that are marked as optional are ignored
255 | * Transitive dependencies with the scopes "test", "system" and "provided" are ignored.
256 | *
257 | * @param plugin the plugin to download
258 | * @return The set of resolved ArtifactRepositoryType pairs
259 | */
260 | public Set resolvePlugin(Plugin plugin) {
261 | Artifact pluginArtifact = toArtifact(plugin);
262 | Dependency pluginDependency = new Dependency(pluginArtifact, null);
263 | CollectRequest collectRequest = new CollectRequest(pluginDependency, pluginRepositories);
264 | collectRequest.setRequestContext(RepositoryType.PLUGIN.getRequestContext());
265 |
266 | List pluginDependencies = new ArrayList<>();
267 | for (org.apache.maven.model.Dependency d : plugin.getDependencies()) {
268 | Dependency dependency = RepositoryUtils.toDependency(d, typeRegistry);
269 | pluginDependencies.add(dependency);
270 | }
271 | collectRequest.setDependencies(pluginDependencies);
272 |
273 | try {
274 | CollectResult collectResult = repositorySystem.collectDependencies(pluginSession, collectRequest);
275 | return getArtifactsFromCollectResult(collectResult, RepositoryType.PLUGIN);
276 | } catch (DependencyCollectionException | RuntimeException e) {
277 | log.error("Error resolving plugin " + plugin.getGroupId() + ":" + plugin.getArtifactId());
278 | handleRepositoryException(e);
279 | }
280 | return Collections.emptySet();
281 | }
282 |
283 | /**
284 | * Download a single dependency and all of its transitive dependencies that is needed by the build without appearing in any dependency tree
285 | *
286 | * Dependencies and plugin artifacts that refer to an artifact in the current reactor build are ignored.
287 | * Transitive dependencies that are marked as optional are ignored
288 | * Transitive dependencies with the scopes "test", "system" and "provided" are ignored.
289 | *
290 | * @param dynamicDependency the dependency to download
291 | * @return The set of resolved ArtifactRepositoryType pairs
292 | */
293 | public Set resolveDynamicDependency(DynamicDependency dynamicDependency) {
294 | ArtifactType artifactType = typeRegistry.get(dynamicDependency.getType());
295 | DefaultArtifact artifact;
296 | if (artifactType == null) {
297 | artifact = new DefaultArtifact(dynamicDependency.getGroupId(), dynamicDependency.getArtifactId(), dynamicDependency.getClassifier(), dynamicDependency.getType(), dynamicDependency.getVersion());
298 | } else {
299 | artifact = new DefaultArtifact(dynamicDependency.getGroupId(), dynamicDependency.getArtifactId(), dynamicDependency.getClassifier(), artifactType.getExtension(), dynamicDependency.getVersion(), artifactType);
300 | }
301 | CollectRequest collectRequest = new CollectRequest();
302 | collectRequest.setRoot(new Dependency(artifact, null));
303 | RepositoryType repositoryType = dynamicDependency.getRepositoryType();
304 | RepositorySystemSession session;
305 | switch (repositoryType) {
306 | case MAIN:
307 | session = remoteSession;
308 | collectRequest.setRepositories(remoteRepositories);
309 | collectRequest.setRequestContext(repositoryType.getRequestContext());
310 | break;
311 | case PLUGIN:
312 | session = pluginSession;
313 | collectRequest.setRepositories(pluginRepositories);
314 | collectRequest.setRequestContext(repositoryType.getRequestContext());
315 | break;
316 | default:
317 | throw new IllegalStateException("Unknown enum val " + repositoryType);
318 |
319 | }
320 | try {
321 | CollectResult collectResult = repositorySystem.collectDependencies(session, collectRequest);
322 | return getArtifactsFromCollectResult(collectResult, repositoryType);
323 | } catch (DependencyCollectionException | RuntimeException e) {
324 | log.error("Error resolving dynamic dependency" + dynamicDependency.getGroupId() + ":" + dynamicDependency.getArtifactId());
325 | handleRepositoryException(e);
326 | }
327 | return Collections.emptySet();
328 | }
329 |
330 | /**
331 | * Returns a List of errors encountered during the downloading of artifacts since this class has been initialized.
332 | *
333 | * @return a List of errors encountered during the downloading of artifacts since this class has been initialized.
334 | */
335 | public List getErrors() {
336 | return Collections.unmodifiableList(errors);
337 | }
338 |
339 | private Set computeReactorArtifacts(List reactorProjects) {
340 | Set artifacts = new HashSet<>(reactorProjects.size());
341 | for (MavenProject p : reactorProjects) {
342 | artifacts.add(new ReactorArtifact(p.getArtifact()));
343 | }
344 | return artifacts;
345 | }
346 |
347 | private boolean isReactorArtifact(Artifact artifact) {
348 | return reactorArtifacts.contains(new ReactorArtifact(artifact));
349 | }
350 |
351 | private void handleRepositoryException(Exception e) {
352 | log.error(e.getMessage());
353 | log.debug(e);
354 | addToErrorList(e);
355 | }
356 |
357 | private synchronized void addToErrorList(Exception e) {
358 | errors.add(e);
359 | }
360 |
361 | private Artifact toArtifact(Plugin plugin) {
362 | ArtifactType artifactType = typeRegistry.get(MAVEN_PLUGIN_ARTIFACT_TYPE);
363 | return new DefaultArtifact(plugin.getGroupId(), plugin.getArtifactId(), artifactType.getClassifier(), artifactType.getExtension(), plugin.getVersion(),
364 | artifactType);
365 | }
366 |
367 | private static class CollectAllDependenciesVisitor implements DependencyVisitor {
368 |
369 | private boolean root = true;
370 | private Set artifacts = new HashSet<>();
371 |
372 | @Override
373 | public boolean visitEnter(DependencyNode node) {
374 | if (root) {
375 | root = false;
376 | return true;
377 | }
378 | return artifacts.add(node.getArtifact());
379 | }
380 |
381 | @Override
382 | public boolean visitLeave(DependencyNode node) {
383 | return true;
384 | }
385 |
386 | public Set getArtifacts() {
387 | return artifacts;
388 | }
389 | }
390 | }
391 |
--------------------------------------------------------------------------------