2
0
Fork 0
mirror of https://github.com/ethauvin/rife2.git synced 2025-04-30 10:38:12 -07:00

Added support for the purge command and operation.

This commit is contained in:
Geert Bevin 2023-03-18 16:48:13 -04:00
parent 195c17de0c
commit 1d623b049c
6 changed files with 624 additions and 26 deletions

View file

@ -101,6 +101,12 @@ public class Project extends BuildExecutor {
new JarOperation().fromProject(this).execute();
}
@BuildCommand(help = PurgeHelp.class)
public void purge()
throws Exception {
new PurgeOperation().fromProject(this).execute();
}
@BuildCommand(help = RunHelp.class)
public void run()
throws Exception {

View file

@ -259,6 +259,38 @@ public class DependencyResolver {
return dependency_;
}
/**
* Retrieves all the potential artifact download URLs for the dependency
* within the provided repositories.
*
* @return a list of potential download URLs
* @since 1.5
*/
public List<String> getDownloadUrls() {
final var version = resolveVersion();
final VersionNumber pom_version;
if (version.qualifier().equals("SNAPSHOT")) {
var metadata = getSnapshotMavenMetadata();
pom_version = metadata.getSnapshot();
} else {
pom_version = version;
}
return getArtifactUrls().stream().map(s -> {
var result = new StringBuilder(s);
result.append(version).append("/").append(dependency_.artifactId()).append("-").append(pom_version);
if (!dependency_.classifier().isEmpty()) {
result.append("-").append(dependency_.classifier());
}
var type = dependency_.type();
if (type == null) {
type = "jar";
}
result.append(".").append(type);
return result.toString();
}).toList();
}
private Dependency convertPomDependency(PomDependency pomDependency) {
return new Dependency(
pomDependency.groupId(),
@ -425,29 +457,4 @@ public class DependencyResolver {
return xml;
}
private List<String> getDownloadUrls() {
final var version = resolveVersion();
final VersionNumber pom_version;
if (version.qualifier().equals("SNAPSHOT")) {
var metadata = getSnapshotMavenMetadata();
pom_version = metadata.getSnapshot();
} else {
pom_version = version;
}
return getArtifactUrls().stream().map(s -> {
var result = new StringBuilder(s);
result.append(version).append("/").append(dependency_.artifactId()).append("-").append(pom_version);
if (!dependency_.classifier().isEmpty()) {
result.append("-").append(dependency_.classifier());
}
var type = dependency_.type();
if (type == null) {
type = "jar";
}
result.append(".").append(type);
return result.toString();
}).toList();
}
}

View file

@ -0,0 +1,26 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the purge command.
*
* @since 1.5
*/
public class PurgeHelp implements CommandHelp {
public String getSummary() {
return "Purges all unused artifacts from the project";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Purges all the unused dependency artifacts from the project
Usage : ${topic}""", "${topic}", topic);
}
}

View file

@ -0,0 +1,265 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.operations;
import rife.bld.Project;
import rife.bld.dependencies.*;
import java.io.File;
import java.util.*;
/**
* Transitively checks all the artifacts for dependencies in the directories
* that are separated out by scope, any files that aren't required will be deleted.
* <p>
* If a directory is not provided, no purge will occur for that
* dependency scope.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class PurgeOperation {
private final List<Repository> repositories_ = new ArrayList<>();
private final DependencyScopes dependencies_ = new DependencyScopes();
private File libCompileDirectory_;
private File libRuntimeDirectory_;
private File libStandaloneDirectory_;
private File libTestDirectory_;
/**
* Performs the purge operation.
*
* @since 1.5
*/
public void execute() {
executePurgeCompileDependencies();
executePurgeRuntimeDependencies();
executePurgeStandaloneDependencies();
executePurgeTestDependencies();
}
/**
* Part of the {@link #execute} operation, purge the {@code compile} scope artifacts.
*
* @since 1.5
*/
public void executePurgeCompileDependencies() {
executePurgeScopedDependencies(Scope.compile, libCompileDirectory(), Scope.compile);
}
/**
* Part of the {@link #execute} operation, purge the {@code runtime} scope artifacts.
*
* @since 1.5
*/
public void executePurgeRuntimeDependencies() {
executePurgeScopedDependencies(Scope.runtime, libRuntimeDirectory(), Scope.runtime);
}
/**
* Part of the {@link #execute} operation, purge the {@code standalone} scope artifacts.
*
* @since 1.5
*/
public void executePurgeStandaloneDependencies() {
executePurgeScopedDependencies(Scope.standalone, libStandaloneDirectory(), Scope.compile, Scope.runtime);
}
/**
* Part of the {@link #execute} operation, purge the {@code test} scope artifacts.
*
* @since 1.5
*/
public void executePurgeTestDependencies() {
executePurgeScopedDependencies(Scope.test, libTestDirectory(), Scope.compile, Scope.runtime);
}
/**
* Part of the {@link #execute} operation, purge the artifacts for a particular dependency scope.
*
* @param scope the scope whose artifacts should be purged
* @param destinationDirectory the directory from which the artifacts should be purged
* @param transitiveScopes the scopes to use to resolve the transitive dependencies
* @since 1.5
*/
public void executePurgeScopedDependencies(Scope scope, File destinationDirectory, Scope... transitiveScopes) {
if (destinationDirectory == null) {
return;
}
var scoped_dependencies = dependencies().get(scope);
if (scoped_dependencies != null) {
var all_dependencies = new DependencySet();
for (var dependency : scoped_dependencies) {
all_dependencies.addAll(new DependencyResolver(repositories(), dependency).getAllDependencies(transitiveScopes));
}
var filenames = new HashSet<String>();
for (var dependency : all_dependencies) {
for (var url : new DependencyResolver(repositories(), dependency).getDownloadUrls()) {
filenames.add(url.substring(url.lastIndexOf("/") + 1));
}
}
for (var file : destinationDirectory.listFiles()) {
if (!filenames.contains(file.getName())) {
System.out.println("Deleting : " + file.getName());
file.delete();
}
}
}
}
/**
* Configures a compile operation from a {@link Project}.
*
* @param project the project to configure the compile operation from
* @since 1.5
*/
public PurgeOperation fromProject(Project project) {
return repositories(project.repositories())
.dependencies(project.dependencies())
.libCompileDirectory(project.libCompileDirectory())
.libRuntimeDirectory(project.libRuntimeDirectory())
.libStandaloneDirectory(project.libStandaloneDirectory())
.libTestDirectory(project.libTestDirectory());
}
/**
* Provides repositories to resolve the dependencies against.
*
* @param repositories the repositories against which dependencies will be resolved
* @return this operation instance
* @since 1.5
*/
public PurgeOperation repositories(List<Repository> repositories) {
repositories_.addAll(repositories);
return this;
}
/**
* Provides scoped dependencies for artifact purge.
*
* @param dependencies the dependencies that will be resolved for artifact purge
* @return this operation instance
* @since 1.5
*/
public PurgeOperation dependencies(DependencyScopes dependencies) {
dependencies_.include(dependencies);
return this;
}
/**
* Provides the {@code compile} scope purge directory.
*
* @param directory the directory to purge the {@code compile} scope artifacts from
* @return this operation instance
* @since 1.5
*/
public PurgeOperation libCompileDirectory(File directory) {
libCompileDirectory_ = directory;
return this;
}
/**
* Provides the {@code runtime} scope purge directory.
*
* @param directory the directory to purge the {@code runtime} scope artifacts from
* @return this operation instance
* @since 1.5
*/
public PurgeOperation libRuntimeDirectory(File directory) {
libRuntimeDirectory_ = directory;
return this;
}
/**
* Provides the {@code standalone} scope purge directory.
*
* @param directory the directory to purge the {@code standalone} scope artifacts from
* @return this operation instance
* @since 1.5
*/
public PurgeOperation libStandaloneDirectory(File directory) {
libStandaloneDirectory_ = directory;
return this;
}
/**
* Provides the {@code test} scope purge directory.
*
* @param directory the directory to purge the {@code test} scope artifacts from
* @return this operation instance
* @since 1.5
*/
public PurgeOperation libTestDirectory(File directory) {
libTestDirectory_ = directory;
return this;
}
/**
* Retrieves the repositories in which the dependencies will be resolved.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the repositories used for dependency resolution
* @since 1.5
*/
public List<Repository> repositories() {
return repositories_;
}
/**
* Retrieves the scoped dependencies that will be used for artifact purge.
* <p>
* This is a modifiable structure that can be retrieved and changed.
*
* @return the scoped dependencies
* @since 1.5
*/
public DependencyScopes dependencies() {
return dependencies_;
}
/**
* Retrieves the {@code compile} scope purge directory.
*
* @return the {@code compile} scope purge directory
* @since 1.5
*/
public File libCompileDirectory() {
return libCompileDirectory_;
}
/**
* Retrieves the {@code runtime} scope purge directory.
*
* @return the {@code runtime} scope purge directory
* @since 1.5
*/
public File libRuntimeDirectory() {
return libRuntimeDirectory_;
}
/**
* Retrieves the {@code standalone} scope purge directory.
*
* @return the {@code standalone} scope purge directory
* @since 1.5
*/
public File libStandaloneDirectory() {
return libStandaloneDirectory_;
}
/**
* Retrieves the {@code test} scope purge directory.
*
* @return the {@code test} scope purge directory
* @since 1.5
*/
public File libTestDirectory() {
return libTestDirectory_;
}
}

View file

@ -5,7 +5,6 @@
package rife.bld.operations;
import org.junit.jupiter.api.Test;
import rife.bld.dependencies.DependencyScopes;
import rife.bld.WebProject;
import rife.bld.dependencies.*;
import rife.tools.FileUtils;

View file

@ -0,0 +1,295 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.operations;
import org.junit.jupiter.api.Test;
import rife.bld.WebProject;
import rife.bld.dependencies.*;
import rife.tools.FileUtils;
import java.io.File;
import java.nio.file.Files;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
public class TestPurgeOperation {
@Test
void testInstantiation() {
var operation = new PurgeOperation();
assertTrue(operation.dependencies().isEmpty());
assertTrue(operation.repositories().isEmpty());
assertNull(operation.libCompileDirectory());
assertNull(operation.libRuntimeDirectory());
assertNull(operation.libStandaloneDirectory());
assertNull(operation.libTestDirectory());
}
@Test
void testPopulation() {
var repository1 = new Repository("repository1");
var repository2 = new Repository("repository2");
var dependency1 = new Dependency("group1", "artifact1");
var dependency2 = new Dependency("group2", "artifact2");
var dir1 = new File("dir1");
var dir2 = new File("dir2");
var dir3 = new File("dir3");
var dir4 = new File("dir4");
var operation1 = new PurgeOperation()
.repositories(List.of(repository1, repository2))
.libCompileDirectory(dir1)
.libRuntimeDirectory(dir2)
.libStandaloneDirectory(dir3)
.libTestDirectory(dir4);
var dependency_scopes = new DependencyScopes();
dependency_scopes.scope(Scope.compile).include(dependency1).include(dependency2);
operation1.dependencies(dependency_scopes);
assertTrue(operation1.repositories().contains(repository1));
assertTrue(operation1.repositories().contains(repository2));
assertTrue(operation1.dependencies().scope(Scope.compile).contains(dependency1));
assertTrue(operation1.dependencies().scope(Scope.compile).contains(dependency2));
assertEquals(dir1, operation1.libCompileDirectory());
assertEquals(dir2, operation1.libRuntimeDirectory());
assertEquals(dir3, operation1.libStandaloneDirectory());
assertEquals(dir4, operation1.libTestDirectory());
var operation2 = new PurgeOperation()
.libCompileDirectory(dir1)
.libRuntimeDirectory(dir2)
.libStandaloneDirectory(dir3)
.libTestDirectory(dir4);
operation2.repositories().add(repository1);
operation2.repositories().add(repository2);
operation2.dependencies().scope(Scope.compile).include(dependency1).include(dependency2);
operation2.dependencies(dependency_scopes);
assertTrue(operation2.repositories().contains(repository1));
assertTrue(operation2.repositories().contains(repository2));
assertTrue(operation2.dependencies().scope(Scope.compile).contains(dependency1));
assertTrue(operation2.dependencies().scope(Scope.compile).contains(dependency2));
assertEquals(dir1, operation2.libCompileDirectory());
assertEquals(dir2, operation2.libRuntimeDirectory());
assertEquals(dir3, operation2.libStandaloneDirectory());
assertEquals(dir4, operation2.libTestDirectory());
}
@Test
void testExecution()
throws Exception {
var tmp = Files.createTempDirectory("test").toFile();
try {
var dir1 = new File(tmp, "dir1");
var dir2 = new File(tmp, "dir2");
var dir3 = new File(tmp, "dir3");
var dir4 = new File(tmp, "dir4");
dir1.mkdirs();
dir2.mkdirs();
dir3.mkdirs();
dir4.mkdirs();
var operation_download1 = new DownloadOperation()
.repositories(List.of(Repository.MAVEN_CENTRAL))
.libCompileDirectory(dir1)
.libRuntimeDirectory(dir2)
.libStandaloneDirectory(dir3)
.libTestDirectory(dir4);
operation_download1.dependencies().scope(Scope.compile)
.include(new Dependency("org.apache.commons", "commons-lang3", new VersionNumber(3, 1)));
operation_download1.dependencies().scope(Scope.runtime)
.include(new Dependency("org.apache.commons", "commons-collections4", new VersionNumber(4, 3)));
operation_download1.dependencies().scope(Scope.standalone)
.include(new Dependency("org.slf4j", "slf4j-simple", new VersionNumber(2, 0, 0)));
operation_download1.dependencies().scope(Scope.test)
.include(new Dependency("org.apache.httpcomponents.client5", "httpclient5", new VersionNumber(5, 0)));
operation_download1.execute();
var operation_download2 = new DownloadOperation()
.repositories(List.of(Repository.MAVEN_CENTRAL))
.libCompileDirectory(dir1)
.libRuntimeDirectory(dir2)
.libStandaloneDirectory(dir3)
.libTestDirectory(dir4);
operation_download2.dependencies().scope(Scope.compile)
.include(new Dependency("org.apache.commons", "commons-lang3", new VersionNumber(3, 12, 0)));
operation_download2.dependencies().scope(Scope.runtime)
.include(new Dependency("org.apache.commons", "commons-collections4", new VersionNumber(4, 4)));
operation_download2.dependencies().scope(Scope.standalone)
.include(new Dependency("org.slf4j", "slf4j-simple", new VersionNumber(2, 0, 6)));
operation_download2.dependencies().scope(Scope.test)
.include(new Dependency("org.apache.httpcomponents.client5", "httpclient5", new VersionNumber(5, 2, 1)));
operation_download2.execute();
assertEquals("""
/dir1
/dir1/commons-lang3-3.1.jar
/dir1/commons-lang3-3.12.0.jar
/dir2
/dir2/commons-collections4-4.3.jar
/dir2/commons-collections4-4.4.jar
/dir3
/dir3/slf4j-api-2.0.0.jar
/dir3/slf4j-api-2.0.6.jar
/dir3/slf4j-simple-2.0.0.jar
/dir3/slf4j-simple-2.0.6.jar
/dir4
/dir4/commons-codec-1.13.jar
/dir4/httpclient5-5.0.jar
/dir4/httpclient5-5.2.1.jar
/dir4/httpcore5-5.0.jar
/dir4/httpcore5-5.2.jar
/dir4/httpcore5-h2-5.0.jar
/dir4/httpcore5-h2-5.2.jar
/dir4/slf4j-api-1.7.25.jar
/dir4/slf4j-api-1.7.36.jar""",
FileUtils.generateDirectoryListing(tmp));
var operation_purge = new PurgeOperation()
.repositories(List.of(Repository.MAVEN_CENTRAL))
.libCompileDirectory(dir1)
.libRuntimeDirectory(dir2)
.libStandaloneDirectory(dir3)
.libTestDirectory(dir4);
operation_purge.dependencies().scope(Scope.compile)
.include(new Dependency("org.apache.commons", "commons-lang3", new VersionNumber(3, 12, 0)));
operation_purge.dependencies().scope(Scope.runtime)
.include(new Dependency("org.apache.commons", "commons-collections4", new VersionNumber(4, 4)));
operation_purge.dependencies().scope(Scope.standalone)
.include(new Dependency("org.slf4j", "slf4j-simple", new VersionNumber(2, 0, 6)));
operation_purge.dependencies().scope(Scope.test)
.include(new Dependency("org.apache.httpcomponents.client5", "httpclient5", new VersionNumber(5, 2, 1)));
operation_purge.execute();
assertEquals("""
/dir1
/dir1/commons-lang3-3.12.0.jar
/dir2
/dir2/commons-collections4-4.4.jar
/dir3
/dir3/slf4j-api-2.0.6.jar
/dir3/slf4j-simple-2.0.6.jar
/dir4
/dir4/httpclient5-5.2.1.jar
/dir4/httpcore5-5.2.jar
/dir4/httpcore5-h2-5.2.jar
/dir4/slf4j-api-1.7.36.jar""",
FileUtils.generateDirectoryListing(tmp));
} finally {
FileUtils.deleteDirectory(tmp);
}
}
@Test
void testFromProject()
throws Exception {
var tmp = Files.createTempDirectory("test").toFile();
try {
var project1 = new WebProject();
project1.workDirectory = tmp;
project1.pkg = "test.pkg";
project1.createProjectStructure();
project1.repositories().add(Repository.MAVEN_CENTRAL);
project1.dependencies().scope(Scope.compile)
.include(new Dependency("org.apache.commons", "commons-lang3", new VersionNumber(3, 1)));
project1.dependencies().scope(Scope.runtime)
.include(new Dependency("org.apache.commons", "commons-collections4", new VersionNumber(4, 3)));
project1.dependencies().scope(Scope.standalone)
.include(new Dependency("org.slf4j", "slf4j-simple", new VersionNumber(2, 0, 0)));
project1.dependencies().scope(Scope.test)
.include(new Dependency("org.apache.httpcomponents.client5", "httpclient5", new VersionNumber(5, 0)));
var project2 = new WebProject();
project2.workDirectory = tmp;
project2.pkg = "test.pkg";
project2.createProjectStructure();
project2.repositories().add(Repository.MAVEN_CENTRAL);
project2.dependencies().scope(Scope.compile)
.include(new Dependency("org.apache.commons", "commons-lang3", new VersionNumber(3, 12, 0)));
project2.dependencies().scope(Scope.runtime)
.include(new Dependency("org.apache.commons", "commons-collections4", new VersionNumber(4, 4)));
project2.dependencies().scope(Scope.standalone)
.include(new Dependency("org.slf4j", "slf4j-simple", new VersionNumber(2, 0, 6)));
project2.dependencies().scope(Scope.test)
.include(new Dependency("org.apache.httpcomponents.client5", "httpclient5", new VersionNumber(5, 2, 1)));
new DownloadOperation()
.fromProject(project1)
.execute();
new DownloadOperation()
.fromProject(project2)
.execute();
assertEquals("""
/lib
/lib/bld
/lib/compile
/lib/compile/commons-lang3-3.1.jar
/lib/compile/commons-lang3-3.12.0.jar
/lib/runtime
/lib/runtime/commons-collections4-4.3.jar
/lib/runtime/commons-collections4-4.4.jar
/lib/standalone
/lib/standalone/slf4j-api-2.0.0.jar
/lib/standalone/slf4j-api-2.0.6.jar
/lib/standalone/slf4j-simple-2.0.0.jar
/lib/standalone/slf4j-simple-2.0.6.jar
/lib/test
/lib/test/commons-codec-1.13.jar
/lib/test/httpclient5-5.0.jar
/lib/test/httpclient5-5.2.1.jar
/lib/test/httpcore5-5.0.jar
/lib/test/httpcore5-5.2.jar
/lib/test/httpcore5-h2-5.0.jar
/lib/test/httpcore5-h2-5.2.jar
/lib/test/slf4j-api-1.7.25.jar
/lib/test/slf4j-api-1.7.36.jar
/src
/src/bld
/src/bld/java
/src/main
/src/main/java
/src/main/resources
/src/main/resources/templates
/src/test
/src/test/java""",
FileUtils.generateDirectoryListing(tmp));
new PurgeOperation()
.fromProject(project2)
.execute();
assertEquals("""
/lib
/lib/bld
/lib/compile
/lib/compile/commons-lang3-3.12.0.jar
/lib/runtime
/lib/runtime/commons-collections4-4.4.jar
/lib/standalone
/lib/standalone/slf4j-api-2.0.6.jar
/lib/standalone/slf4j-simple-2.0.6.jar
/lib/test
/lib/test/httpclient5-5.2.1.jar
/lib/test/httpcore5-5.2.jar
/lib/test/httpcore5-h2-5.2.jar
/lib/test/slf4j-api-1.7.36.jar
/src
/src/bld
/src/bld/java
/src/main
/src/main/java
/src/main/resources
/src/main/resources/templates
/src/test
/src/test/java""",
FileUtils.generateDirectoryListing(tmp));
} finally {
FileUtils.deleteDirectory(tmp);
}
}
}