Compare commits
32 Commits
Author | SHA1 | Date | |
---|---|---|---|
80068ef209 | |||
a7480c3d85 | |||
034b319172 | |||
65009df10b | |||
8df2d5bd03 | |||
0edac4fc37 | |||
f837e5d1c0 | |||
78e34d85e9 | |||
6e2a701c0d | |||
08498d4224 | |||
1c7997d85c | |||
9116d4bfd9 | |||
9874ed9543 | |||
eeb7a84698 | |||
ca8913e558 | |||
4c1c4d412d | |||
fc5e0c6bd1 | |||
2a1523012b | |||
d41d73fa1c | |||
a9aa47d412 | |||
47fd07247d | |||
cfb13f3170 | |||
75f8175a1c | |||
f2c93eec50 | |||
58eb0ec013 | |||
dec181aa71 | |||
51f5d6d0a3 | |||
24d69c3715 | |||
fe10e53fb4 | |||
b6c7323203 | |||
9644bbe154 | |||
9a0b7207c0 |
60
README.md
60
README.md
@@ -5,7 +5,9 @@ This is a maven plugin that allows for developers and organizations to ban Maven
|
||||
|
||||
## Usage
|
||||
|
||||
Here is an example of the primary reason why this plugin is useful.
|
||||
### Prevent Banned Artifacts
|
||||
|
||||
Here is a pseudo-code example of all the options this plugin provides.
|
||||
|
||||
```xml
|
||||
<project>
|
||||
@@ -21,6 +23,7 @@ Here is an example of the primary reason why this plugin is useful.
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<import>
|
||||
<file>project-file.xml</file>
|
||||
<url>https://host:port/path/file.xml</url>
|
||||
<artifact>groupId:artifactId:version</artifact>
|
||||
</import>
|
||||
@@ -54,9 +57,11 @@ Here is an example of the primary reason why this plugin is useful.
|
||||
</project>
|
||||
```
|
||||
|
||||
The `extensions` elements is critical. Without it, the plugin does nothing for banning artifacts/dependencies. With it, the plugin is able to not only detect ban artifacts, but do it before they are downloaded. This keeps libraries from even reaching your local Maven repository cache.
|
||||
The `extensions` elements is critical. Without it, the plugin does nothing as far as banning artifacts/dependencies. With it, the plugin is able to not only detect banned artifacts, but do it before they are downloaded. This works with both dependencies and plugins. This keeps libraries from even reaching your local Maven repository cache.
|
||||
|
||||
Here is an example of the non-extension use case for the plugin:
|
||||
### Purge Banned Artifacts
|
||||
|
||||
Here is an example of the non-extension use case for the plugin. You could use the same plugin for both preventing banned artifacts and cleaning up previously downloaded ones. Just set `extensions` to `true` in those cases, as highlighted in the previous section.
|
||||
|
||||
```xml
|
||||
<project>
|
||||
@@ -69,7 +74,6 @@ Here is an example of the non-extension use case for the plugin:
|
||||
<groupId>com.inteligr8</groupId>
|
||||
<artifactId>ban-maven-plugin</artifactId>
|
||||
<version>...</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
...
|
||||
</configuration>
|
||||
@@ -91,11 +95,25 @@ Here is an example of the non-extension use case for the plugin:
|
||||
|
||||
The `purge-repo` goal will remove all banned artifacts from your local Maven cache. It does not support `groupIdRegex` or blank `groupId` specifications. So any of those will not be purged/removed.
|
||||
|
||||
For instance, you can use the following and expect it to work for preventing and purging banned dependencies and plugins:
|
||||
|
||||
```xml
|
||||
<include>
|
||||
<artifact>
|
||||
<groupId>...<groupId>
|
||||
<artifactId>...<artifactId>
|
||||
<version>...</version>
|
||||
</artifact>
|
||||
<artifact>com.inteligr8:ban-maven-plugin:[,1.0.0)</artifact>
|
||||
<artifact>log4j:log4j</artifact>
|
||||
</include>
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
If no `includes` are provided, then no artifacts will be banned. An *included* artifact is a banned artifact. An *excluded* artifact is not banned. It is the opposite of what you may think. If no `excludes` are provided, then no banned artifacts are granted an exception.
|
||||
|
||||
The `artifact` element supports the descriptive `groupId`/`artifactId`/`version` elements or the abbreviated colon-based notation. When using the colon-based notation, the group ID and artifact ID are treated as `groupIdRegex` and `artifactIdRegex` (see below).
|
||||
The `artifact` element supports the descriptive `groupId`/`artifactId`/`version` elements or the abbreviated colon-based notation. When using the colon-based notation, the group ID and artifact ID may be treated as `groupIdRegex` and `artifactIdRegex` (see below). If you only use acceptable `groupId` and `artifactId` characters (letters/numbers/dashes/underscores/dots), it will not. But if you include any other characters, like `\.` or `*`, then it will be treated as regex. How it is treated will impact the functionality of `purge-repo` goal, if you are using it.
|
||||
|
||||
If `groupId` or `artifactId` or `version` are not provided, they are ignored in the matching process. So it will match all applicable artifacts and the constraint will be only for what was specified. This means that `<includes><artifact>:</artifact></includes>` will ban every artifact and all their versions.
|
||||
|
||||
@@ -118,3 +136,35 @@ You can create a Maven `pom` packaging type project that deploys a configuration
|
||||
The `import` elements supports multiple `url` or `artifact` declarations. All imported and directly specified include specifications are processed before all exclude specifications. You cannot change an include when importing, but you can add new ones, that may cover more versions; and you can exclude versions that may have been included by the import.
|
||||
|
||||
The `excludes` element is a way to provide project-by-project exceptions to imported banned artifacts where warranted.
|
||||
|
||||
## Examples
|
||||
|
||||
The recommended us of this plugin is for its use across whole organizations. First, you will want a simple Maven project that is referenced by all other Maven projects. That simple project will declare the banned artifacts and potentially purge existing ones. See the `examples/ban-config` project for a full example.
|
||||
|
||||
```xml
|
||||
<configuration>
|
||||
<includes>
|
||||
<!-- CVE-2019-17571 -->
|
||||
<artifact>org.apache.logging.log4j::[,2.17.1)</artifact>
|
||||
<artifact>log4j:log4j</artifact>
|
||||
</includes>
|
||||
</configuration>
|
||||
```
|
||||
|
||||
Deploying that project will result in the publication of the `ban-config.xml` to your Maven repository. That is where it can be picked up by all other projects so they can enforce the ban. If you do not have a local Maven repository, then you will have to upload the `ban-config.xml` to some other URL-accessible location by some other means.
|
||||
|
||||
Once you have that in place, you will want to add the following to every single Maven project that should be governed by the aforementioned `ban-config`. See the `examples/governed-artifact` project for a full example.
|
||||
|
||||
```xml
|
||||
<plugin>
|
||||
<groupId>com.inteligr8</groupId>
|
||||
<artifactId>ban-maven-plugin</artifactId>
|
||||
<version>1.3.6</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<import>
|
||||
<artifact>com.inteligr8:ban-config:[2025.03,)</artifact>
|
||||
</import>
|
||||
</configuration>
|
||||
</plugin>
|
||||
```
|
||||
|
8
examples/ban-config/ban-config.xml
Normal file
8
examples/ban-config/ban-config.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<includes>
|
||||
<!-- CVE-2019-17571 -->
|
||||
<artifact>org.apache.logging.log4j::[,2.17.1)</artifact>
|
||||
<artifact>log4j:log4j</artifact>
|
||||
</includes>
|
||||
</configuration>
|
39
examples/ban-config/pom.xml
Normal file
39
examples/ban-config/pom.xml
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.inteligr8</groupId>
|
||||
<artifactId>ban-config</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<!-- A monthly cadence is reasonable at most organizations -->
|
||||
<version>2025.03</version>
|
||||
|
||||
<name>Banned Artifact Configuration</name>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.inteligr8</groupId>
|
||||
<artifactId>ban-maven-plugin</artifactId>
|
||||
<version>1.3.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>purge-maven-repo</id>
|
||||
<phase>clean</phase>
|
||||
<goals><goal>purge-repo</goal></goals>
|
||||
<configuration>
|
||||
<import>
|
||||
<file>ban-config.xml</file>
|
||||
</import>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
31
examples/governed-artifact/pom.xml
Normal file
31
examples/governed-artifact/pom.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.inteligr8</groupId>
|
||||
<artifactId>governed-artifact</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Any Governed Artifact</name>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.inteligr8</groupId>
|
||||
<artifactId>ban-maven-plugin</artifactId>
|
||||
<version>1.3.6</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<import>
|
||||
<artifact>com.inteligr8:ban-config:[2025.03,)</artifact>
|
||||
</import>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
32
pom.xml
32
pom.xml
@@ -7,7 +7,7 @@
|
||||
|
||||
<groupId>com.inteligr8</groupId>
|
||||
<artifactId>ban-maven-plugin</artifactId>
|
||||
<version>1.2.2</version>
|
||||
<version>1.4.0</version>
|
||||
<packaging>maven-plugin</packaging>
|
||||
|
||||
<name>Ban Dependencies Maven Plugin</name>
|
||||
@@ -43,14 +43,14 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<maven.version>3.9.0</maven.version>
|
||||
<maven.version>3.9.9</maven.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.4</version>
|
||||
<version>3.17.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.shared</groupId>
|
||||
@@ -66,7 +66,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.plugin-tools</groupId>
|
||||
<artifactId>maven-plugin-annotations</artifactId>
|
||||
<version>3.7.1</version>
|
||||
<version>3.15.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -90,22 +90,36 @@
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<version>4.13.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-plugin-plugin</artifactId>
|
||||
<version>3.15.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-invoker-plugin</artifactId>
|
||||
<version>3.9.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-plugin-plugin</artifactId>
|
||||
<version>3.7.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-descriptor</id>
|
||||
<goals>
|
||||
<goal>descriptor</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<goalPrefix>ban</goalPrefix>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>help-descriptor</id>
|
||||
@@ -131,7 +145,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.plexus</groupId>
|
||||
<artifactId>plexus-component-metadata</artifactId>
|
||||
<version>2.1.1</version>
|
||||
<version>2.2.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
@@ -142,7 +156,6 @@
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-invoker-plugin</artifactId>
|
||||
<version>3.4.0</version>
|
||||
<configuration>
|
||||
<projectsDirectory>${basedir}/src/it</projectsDirectory>
|
||||
<cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
|
||||
@@ -178,7 +191,6 @@
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-invoker-plugin</artifactId>
|
||||
<version>3.2.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>run-its</id>
|
||||
@@ -237,7 +249,7 @@
|
||||
<plugin>
|
||||
<groupId>org.sonatype.plugins</groupId>
|
||||
<artifactId>nexus-staging-maven-plugin</artifactId>
|
||||
<version>1.6.13</version>
|
||||
<version>1.7.0</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<serverId>ossrh</serverId>
|
||||
|
@@ -30,9 +30,14 @@ import org.codehaus.plexus.util.xml.Xpp3Dom;
|
||||
import org.eclipse.aether.artifact.Artifact;
|
||||
import org.eclipse.aether.artifact.DefaultArtifact;
|
||||
import org.eclipse.aether.impl.ArtifactResolver;
|
||||
import org.eclipse.aether.impl.VersionRangeResolver;
|
||||
import org.eclipse.aether.resolution.ArtifactRequest;
|
||||
import org.eclipse.aether.resolution.ArtifactResolutionException;
|
||||
import org.eclipse.aether.resolution.ArtifactResult;
|
||||
import org.eclipse.aether.resolution.VersionRangeRequest;
|
||||
import org.eclipse.aether.resolution.VersionRangeResolutionException;
|
||||
import org.eclipse.aether.resolution.VersionRangeResult;
|
||||
import org.eclipse.aether.version.Version;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -42,17 +47,19 @@ public abstract class AbstractBanConfiguration implements BanConfiguration {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
private final Pattern artifactPattern = Pattern.compile("^([^:]*):([^:]*)(:([^:]+))?$");
|
||||
private final Pattern notRegexPattern = Pattern.compile("^[A-Za-z0-9_\\.]*$");
|
||||
private final Pattern notRegexPattern = Pattern.compile("^[A-Za-z0-9_\\-\\.]*$");
|
||||
|
||||
protected final List<ArtifactFilter> includeArtifacts = new LinkedList<>();
|
||||
protected final List<ArtifactFilter> excludeArtifacts = new LinkedList<>();
|
||||
|
||||
private final ArtifactResolver artifactResolver;
|
||||
private final VersionRangeResolver versionRangeResolver;
|
||||
private final MavenSession session;
|
||||
|
||||
public AbstractBanConfiguration(MavenSession session, ArtifactResolver artifactResolver) {
|
||||
public AbstractBanConfiguration(MavenSession session, ArtifactResolver artifactResolver, VersionRangeResolver versionRangeResolver) {
|
||||
this.session = session;
|
||||
this.artifactResolver = artifactResolver;
|
||||
this.versionRangeResolver = versionRangeResolver;
|
||||
}
|
||||
|
||||
public void init(Xpp3Dom rootDom) throws IOException, MojoFailureException {
|
||||
@@ -68,20 +75,31 @@ public abstract class AbstractBanConfiguration implements BanConfiguration {
|
||||
private void processImports(Xpp3Dom importDom) throws IOException, MojoFailureException {
|
||||
for (Xpp3Dom child : importDom.getChildren()) {
|
||||
BanConfigurationDownloader downloader = null;
|
||||
if (child.getName().equals("url")) {
|
||||
String url = StringUtils.trimToNull(importDom.getValue());
|
||||
downloader = new BanConfigurationDownloader(this.session, this.artifactResolver, url);
|
||||
if (child.getName().equals("file")) {
|
||||
File file = new File(StringUtils.trimToNull(child.getValue()));
|
||||
downloader = new BanConfigurationDownloader(this.session, this.artifactResolver, this.versionRangeResolver, file);
|
||||
} else if (child.getName().equals("url")) {
|
||||
String url = StringUtils.trimToNull(child.getValue());
|
||||
downloader = new BanConfigurationDownloader(this.session, this.artifactResolver, this.versionRangeResolver, url);
|
||||
} else if (child.getName().equals("artifact")) {
|
||||
Artifact artifact = new DefaultArtifact(child.getValue());
|
||||
ArtifactRequest request = new ArtifactRequest(artifact, this.session.getCurrentProject().getRemoteProjectRepositories(), null);
|
||||
if (!"xml".equals(artifact.getExtension()))
|
||||
artifact = new DefaultArtifact(artifact.getGroupId(), artifact.getArtifactId(), artifact.getClassifier(), "xml", artifact.getVersion());
|
||||
|
||||
try {
|
||||
ArtifactResult result = this.artifactResolver.resolveArtifact(this.session.getRepositorySession(), request);
|
||||
File file = result.getArtifact().getFile();
|
||||
downloader = new BanConfigurationDownloader(this.session, this.artifactResolver, file);
|
||||
} catch (ArtifactResolutionException are) {
|
||||
this.logger.warn("The artifact could not be resolved; skipping: {}", child.getValue());
|
||||
Version latestLocalVersion = this.findLatestLocalVersion(artifact, child.getValue());
|
||||
Artifact latestArtifact = this.findLatestArtifact(artifact, child.getValue());
|
||||
if (latestArtifact == null && latestLocalVersion != null) {
|
||||
this.logger.debug("A latest version was found locally, but could not resolve the artifact; trying to resolve the artifact with the specific version: {}: {}", latestLocalVersion, child.getValue());
|
||||
artifact = artifact.setVersion(latestLocalVersion.toString());
|
||||
latestArtifact = this.findLatestArtifact(artifact, child.getValue());
|
||||
}
|
||||
|
||||
if (artifact != null) {
|
||||
File file = artifact.getFile();
|
||||
downloader = new BanConfigurationDownloader(this.session, this.artifactResolver, this.versionRangeResolver, file);
|
||||
}
|
||||
} else {
|
||||
this.logger.debug("Unrecognized configuration element ignored: {}: {}", child.getName(), child.getValue());
|
||||
}
|
||||
|
||||
if (downloader != null) {
|
||||
@@ -91,6 +109,37 @@ public abstract class AbstractBanConfiguration implements BanConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
private Version findLatestLocalVersion(Artifact artifact, String logId) {
|
||||
this.logger.trace("Inspecting the local repository to select the version to import: {}", logId);
|
||||
VersionRangeRequest vrrequest = new VersionRangeRequest(artifact, this.session.getCurrentProject().getRemoteProjectRepositories(), null);
|
||||
try {
|
||||
VersionRangeResult vrresult = this.versionRangeResolver.resolveVersionRange(this.session.getRepositorySession(), vrrequest);
|
||||
if (vrresult.getVersions().isEmpty()) {
|
||||
this.logger.info("The artifact version range could not be resolved locally; trying remote: {}", logId);
|
||||
return null;
|
||||
} else {
|
||||
this.logger.debug("The artifact version discovered locally: {}; trying remote: {}", vrresult.getHighestVersion(), logId);
|
||||
return vrresult.getHighestVersion();
|
||||
}
|
||||
} catch (VersionRangeResolutionException vrre) {
|
||||
this.logger.error("The artifact version range could not be resolved; skipping: {}", logId);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Artifact findLatestArtifact(Artifact artifact, String logId) {
|
||||
this.logger.trace("Inspecting the local/remote repositories to select the artifact to import: {}", logId);
|
||||
ArtifactRequest arequest = new ArtifactRequest(artifact, this.session.getCurrentProject().getRemoteProjectRepositories(), null);
|
||||
try {
|
||||
ArtifactResult aresult = this.artifactResolver.resolveArtifact(this.session.getRepositorySession(), arequest);
|
||||
this.logger.debug("This artifact version discovered remotely: {}: {}", aresult.getArtifact().getVersion(), logId);
|
||||
return aresult.getArtifact();
|
||||
} catch (ArtifactResolutionException are) {
|
||||
this.logger.warn("The artifact could not be resolved; skipping: {}", artifact);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void processIncludesExcludes(Xpp3Dom rootDom) {
|
||||
Xpp3Dom includesDom = rootDom.getChild("includes");
|
||||
if (includesDom != null)
|
||||
|
@@ -27,6 +27,7 @@ import org.codehaus.plexus.util.xml.Xpp3Dom;
|
||||
import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
|
||||
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
|
||||
import org.eclipse.aether.impl.ArtifactResolver;
|
||||
import org.eclipse.aether.impl.VersionRangeResolver;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -34,8 +35,8 @@ public class BanConfigurationDownloader extends AbstractBanConfiguration {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
public BanConfigurationDownloader(MavenSession session, ArtifactResolver artifactResolver, String url) throws IOException, MojoFailureException {
|
||||
super(session, artifactResolver);
|
||||
public BanConfigurationDownloader(MavenSession session, ArtifactResolver artifactResolver, VersionRangeResolver versionRangeResolver, String url) throws IOException, MojoFailureException {
|
||||
super(session, artifactResolver, versionRangeResolver);
|
||||
|
||||
try {
|
||||
Xpp3Dom rootDom = this.load(new URL(url));
|
||||
@@ -45,8 +46,8 @@ public class BanConfigurationDownloader extends AbstractBanConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
public BanConfigurationDownloader(MavenSession session, ArtifactResolver artifactResolver, File file) throws IOException, MojoFailureException {
|
||||
super(session, artifactResolver);
|
||||
public BanConfigurationDownloader(MavenSession session, ArtifactResolver artifactResolver, VersionRangeResolver versionRangeResolver, File file) throws IOException, MojoFailureException {
|
||||
super(session, artifactResolver, versionRangeResolver);
|
||||
|
||||
try {
|
||||
Xpp3Dom rootDom = this.load(file);
|
||||
|
@@ -21,11 +21,12 @@ import org.apache.maven.model.Plugin;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
import org.codehaus.plexus.util.xml.Xpp3Dom;
|
||||
import org.eclipse.aether.impl.ArtifactResolver;
|
||||
import org.eclipse.aether.impl.VersionRangeResolver;
|
||||
|
||||
public class BanConfigurationParser extends AbstractBanConfiguration {
|
||||
|
||||
public BanConfigurationParser(MavenSession session, ArtifactResolver artifactResolver, Plugin plugin) throws IOException, MojoFailureException {
|
||||
super(session, artifactResolver);
|
||||
public BanConfigurationParser(MavenSession session, ArtifactResolver artifactResolver, VersionRangeResolver versionRangeResolver, Plugin plugin) throws IOException, MojoFailureException {
|
||||
super(session, artifactResolver, versionRangeResolver);
|
||||
|
||||
Xpp3Dom rootDom = (Xpp3Dom) plugin.getConfiguration();
|
||||
this.init(rootDom);
|
||||
|
@@ -29,6 +29,7 @@ import org.apache.maven.model.Plugin;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
import org.apache.maven.plugin.PluginResolutionException;
|
||||
import org.apache.maven.plugin.internal.PluginDependenciesResolver;
|
||||
import org.apache.maven.plugins.annotations.Parameter;
|
||||
import org.apache.maven.project.DefaultDependencyResolutionRequest;
|
||||
import org.apache.maven.project.DependencyResolutionException;
|
||||
import org.apache.maven.project.DependencyResolutionResult;
|
||||
@@ -40,9 +41,12 @@ import org.eclipse.aether.graph.Dependency;
|
||||
import org.eclipse.aether.graph.DependencyFilter;
|
||||
import org.eclipse.aether.graph.DependencyNode;
|
||||
import org.eclipse.aether.impl.ArtifactResolver;
|
||||
import org.eclipse.aether.impl.VersionRangeResolver;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.inteligr8.maven.ban.model.ImportConfig;
|
||||
|
||||
@Named("ban")
|
||||
@Singleton
|
||||
public class BanExtension extends AbstractMavenLifecycleParticipant {
|
||||
@@ -56,12 +60,27 @@ public class BanExtension extends AbstractMavenLifecycleParticipant {
|
||||
@Inject
|
||||
private ArtifactResolver artifactResolver;
|
||||
|
||||
@Inject
|
||||
private VersionRangeResolver versionRangeResolver;
|
||||
|
||||
@Inject
|
||||
private ProjectDependenciesResolver projDepResolver;
|
||||
|
||||
@Inject
|
||||
private PluginDependenciesResolver pluginDepResolver;
|
||||
|
||||
/**
|
||||
* The configuration is parsed manually. This is here to prevent warning messages with IDEs and builders.
|
||||
*/
|
||||
@Parameter(name = "import")
|
||||
private ImportConfig importConfig;
|
||||
|
||||
@Parameter(name = "includes")
|
||||
private List<String> includes;
|
||||
|
||||
@Parameter(name = "excludes")
|
||||
private List<String> excludes;
|
||||
|
||||
@Override
|
||||
public void afterProjectsRead(MavenSession session) throws MavenExecutionException {
|
||||
BanConfiguration config = this.getConfiguration(session);
|
||||
@@ -113,7 +132,7 @@ public class BanExtension extends AbstractMavenLifecycleParticipant {
|
||||
return null;
|
||||
} else {
|
||||
try {
|
||||
return new BanConfigurationParser(session, this.artifactResolver, plugin);
|
||||
return new BanConfigurationParser(session, this.artifactResolver, this.versionRangeResolver, plugin);
|
||||
} catch (IOException | MojoFailureException e) {
|
||||
throw new MavenExecutionException(e.getMessage(), project.getFile());
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@ package com.inteligr8.maven.ban;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.DirectoryNotEmptyException;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.FileVisitor;
|
||||
import java.nio.file.Files;
|
||||
@@ -23,6 +24,7 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@@ -45,6 +47,7 @@ import org.apache.maven.plugins.annotations.Parameter;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.codehaus.plexus.component.annotations.Component;
|
||||
import org.eclipse.aether.impl.ArtifactResolver;
|
||||
import org.eclipse.aether.impl.VersionRangeResolver;
|
||||
|
||||
import com.inteligr8.maven.model.ArtifactFilter;
|
||||
|
||||
@@ -58,6 +61,9 @@ public class PurgeRepoMojo extends AbstractMojo {
|
||||
@Inject
|
||||
private ArtifactResolver artifactResolver;
|
||||
|
||||
@Inject
|
||||
private VersionRangeResolver versionRangeResolver;
|
||||
|
||||
@Parameter(name = "skip", defaultValue = "false")
|
||||
private boolean skip = false;
|
||||
|
||||
@@ -90,10 +96,13 @@ public class PurgeRepoMojo extends AbstractMojo {
|
||||
continue;
|
||||
}
|
||||
|
||||
Path groupPath = this.getGroupPath(afilter);
|
||||
List<Path> artifactPaths = this.getArtifactPaths(groupPath, afilter);
|
||||
Path groupPath = this.resolveGroupPath(afilter);
|
||||
if (groupPath == null)
|
||||
continue;
|
||||
|
||||
List<Path> artifactPaths = this.resolveArtifactPaths(groupPath, afilter);
|
||||
for (Path artifactPath : artifactPaths)
|
||||
includePaths.addAll(this.getVersionPaths(artifactPath, afilter.getVersionRange()));
|
||||
includePaths.addAll(this.resolveVersionPaths(artifactPath, afilter.getVersionRange()));
|
||||
}
|
||||
|
||||
this.getLog().debug("May be purging all files in " + includePaths.size() + " paths");
|
||||
@@ -105,7 +114,7 @@ public class PurgeRepoMojo extends AbstractMojo {
|
||||
StringBuilder regex = new StringBuilder();
|
||||
|
||||
if (afilter.getGroupId() != null) {
|
||||
regex.append('^').append(this.getGroupPath(afilter));
|
||||
regex.append('^').append(this.resolveGroupPath(afilter));
|
||||
} else if (afilter.getGroupIdRegex() != null) {
|
||||
regex.append(afilter.getGroupIdRegex().replace("\\.", regexDirectorySeparator));
|
||||
if (regex.charAt(0) != '^')
|
||||
@@ -150,14 +159,14 @@ public class PurgeRepoMojo extends AbstractMojo {
|
||||
this.getLog().info("DRYRUN: Would have deleted certain paths from local Maven cache: " + repoPath);
|
||||
this.getLog().info("DRYRUN: Would have deleted these paths: " + includePaths);
|
||||
} else {
|
||||
for (Path path : includePaths) {
|
||||
Path fullpath = repoPath.resolve(path);
|
||||
if (Files.exists(fullpath)) {
|
||||
this.getLog().info("Deleting version from Maven cache: " + path);
|
||||
Files.walkFileTree(fullpath, new DeleteDirectoryVisitor());
|
||||
for (Path versionPath : includePaths) {
|
||||
Path fullVersionPath = repoPath.resolve(versionPath);
|
||||
if (Files.exists(fullVersionPath)) {
|
||||
this.getLog().info("Deleting version from Maven cache: " + versionPath);
|
||||
Files.walkFileTree(fullVersionPath, new DeleteNonMetadataVisitor());
|
||||
} else {
|
||||
// this will probably never happen
|
||||
this.getLog().debug("Maven cache does not exist: " + path);
|
||||
this.getLog().debug("Maven cache does not exist: " + versionPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,23 +177,42 @@ public class PurgeRepoMojo extends AbstractMojo {
|
||||
Plugin plugin = project.getPlugin(BanExtension.THIS_PLUGIN_KEY);
|
||||
if (plugin == null)
|
||||
throw new MojoFailureException("The plugin is executing but it cannot be found");
|
||||
return new BanConfigurationParser(this.session, this.artifactResolver, plugin);
|
||||
return new BanConfigurationParser(this.session, this.artifactResolver, this.versionRangeResolver, plugin);
|
||||
}
|
||||
|
||||
private Path getGroupPath(ArtifactFilter afilter) {
|
||||
private Path resolveGroupPath(ArtifactFilter afilter) {
|
||||
if (afilter.getGroupId() == null)
|
||||
return null;
|
||||
|
||||
String[] pathElements = afilter.getGroupId().split("\\.");
|
||||
Path groupPath = Paths.get("");
|
||||
for (String pathElement : pathElements)
|
||||
groupPath = groupPath.resolve(pathElement);
|
||||
|
||||
Path fullGroupPath = this.getRepositoryPath().resolve(groupPath);
|
||||
if (!Files.exists(fullGroupPath)) {
|
||||
this.getLog().debug("The group path does not exist, so nothing to purge: " + fullGroupPath);
|
||||
return null;
|
||||
}
|
||||
|
||||
return groupPath;
|
||||
}
|
||||
|
||||
private List<Path> getArtifactPaths(Path groupPath, ArtifactFilter afilter) throws IOException {
|
||||
if (afilter.getArtifactId() != null)
|
||||
return Arrays.asList(groupPath.resolve(afilter.getArtifactId()));
|
||||
private List<Path> resolveArtifactPaths(Path groupPath, ArtifactFilter afilter) throws IOException {
|
||||
Path repoPath = this.getRepositoryPath();
|
||||
|
||||
if (afilter.getArtifactId() != null) {
|
||||
Path artifactPath = groupPath.resolve(afilter.getArtifactId());
|
||||
Path fullArtifactPath = repoPath.resolve(artifactPath);
|
||||
if (Files.exists(fullArtifactPath)) {
|
||||
return Arrays.asList(artifactPath);
|
||||
} else {
|
||||
this.getLog().debug("The artifact path does not exist, so nothing to purge: " + fullArtifactPath);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
Pattern artifactPattern = afilter.getArtifactIdRegex() == null ? null : Pattern.compile(afilter.getArtifactIdRegex());
|
||||
Path repoPath = this.getRepositoryPath();
|
||||
List<Path> paths = new LinkedList<>();
|
||||
|
||||
if (artifactPattern == null)
|
||||
@@ -192,14 +220,27 @@ public class PurgeRepoMojo extends AbstractMojo {
|
||||
|
||||
Files.list(repoPath.resolve(groupPath)).forEach(new Consumer<Path>() {
|
||||
@Override
|
||||
public void accept(Path t) {
|
||||
public void accept(Path fullArtifactPath) {
|
||||
if (artifactPattern == null) {
|
||||
paths.add(repoPath.relativize(t));
|
||||
// these may include sub-groups and not just artifacts
|
||||
// which will lead to paths with artifacts as versions
|
||||
// so we are looping through versions to see if it is indeed an artifact
|
||||
try {
|
||||
Files.list(fullArtifactPath).findFirst().ifPresent(new Consumer<Path>() {
|
||||
@Override
|
||||
public void accept(Path fullVersionPath) {
|
||||
if (Files.exists(fullVersionPath.resolve("_remote.repositories")))
|
||||
paths.add(repoPath.relativize(fullArtifactPath));
|
||||
}
|
||||
});
|
||||
} catch (IOException ie) {
|
||||
getLog().error(ie.getMessage(), ie);
|
||||
}
|
||||
} else {
|
||||
Matcher matcher = artifactPattern.matcher(t.getFileName().toString());
|
||||
Matcher matcher = artifactPattern.matcher(fullArtifactPath.getFileName().toString());
|
||||
if (matcher.matches()) {
|
||||
getLog().debug("The artifact directory '" + t.getFileName() + "' qualifies as included");
|
||||
paths.add(repoPath.relativize(t));
|
||||
getLog().debug("The artifact directory '" + fullArtifactPath.getFileName() + "' qualifies as included");
|
||||
paths.add(repoPath.relativize(fullArtifactPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -208,7 +249,7 @@ public class PurgeRepoMojo extends AbstractMojo {
|
||||
return paths;
|
||||
}
|
||||
|
||||
private List<Path> getVersionPaths(Path artifactPath, VersionRange versionRange) throws IOException {
|
||||
private List<Path> resolveVersionPaths(Path artifactPath, VersionRange versionRange) throws IOException {
|
||||
Path repoPath = this.getRepositoryPath();
|
||||
List<Path> paths = new LinkedList<>();
|
||||
|
||||
@@ -239,7 +280,9 @@ public class PurgeRepoMojo extends AbstractMojo {
|
||||
|
||||
|
||||
|
||||
private class DeleteDirectoryVisitor implements FileVisitor<Path> {
|
||||
private class DeleteNonMetadataVisitor implements FileVisitor<Path> {
|
||||
|
||||
private final Pattern versionPathPattern = Pattern.compile("/([^/]+)/([^/]+)/[^/]+$");
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
|
||||
@@ -248,12 +291,33 @@ public class PurgeRepoMojo extends AbstractMojo {
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
if (attrs.isDirectory()) {
|
||||
getLog().warn("An unexpected directory was found: " + file);
|
||||
return FileVisitResult.SKIP_SUBTREE;
|
||||
}
|
||||
|
||||
Matcher matcher = this.versionPathPattern.matcher(file.toString());
|
||||
if (!matcher.find()) {
|
||||
getLog().debug("Ignoring file from purge: " + file);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
String artifactId = matcher.group(1);
|
||||
String version = matcher.group(2);
|
||||
String includeName = artifactId + "-" + version;
|
||||
String excludeName = artifactId + "-" + version + ".pom";
|
||||
getLog().debug("artifact-version: " + includeName);
|
||||
|
||||
if (file.getFileName().toString().startsWith(includeName) &&
|
||||
!file.getFileName().toString().startsWith(excludeName)) {
|
||||
try {
|
||||
if (!attrs.isDirectory())
|
||||
getLog().info("Deleting artifact: " + file);
|
||||
Files.delete(file);
|
||||
} catch (IOException ie) {
|
||||
getLog().debug(ie);
|
||||
getLog().warn("The file failed to delete: " + file);
|
||||
return FileVisitResult.SKIP_SIBLINGS;
|
||||
}
|
||||
}
|
||||
|
||||
return FileVisitResult.CONTINUE;
|
||||
@@ -268,6 +332,8 @@ public class PurgeRepoMojo extends AbstractMojo {
|
||||
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
|
||||
try {
|
||||
Files.delete(dir);
|
||||
} catch (DirectoryNotEmptyException dnee) {
|
||||
getLog().debug("The folder will not be deleted as it is not empty: " + dir);
|
||||
} catch (IOException ie) {
|
||||
getLog().debug(ie);
|
||||
getLog().warn("The folder failed to delete: " + dir);
|
||||
|
11
src/main/java/com/inteligr8/maven/ban/model/Config.java
Normal file
11
src/main/java/com/inteligr8/maven/ban/model/Config.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package com.inteligr8.maven.ban.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Config {
|
||||
|
||||
public ImportConfig importConfigs;
|
||||
public List<String> includes;
|
||||
public List<String> excludes;
|
||||
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
package com.inteligr8.maven.ban.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ImportConfig {
|
||||
|
||||
public List<String> url;
|
||||
public List<String> artifact;
|
||||
|
||||
}
|
Reference in New Issue
Block a user