Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

End2end tests for core #123

Merged
merged 2 commits into from
Apr 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public void write() throws IOException {
log.info("Starting debloating file");
logChanges();
setDependencies(analysis.getDebloatedDependencies().stream()
.map(this::toMavenDependency)
.map(this::toProviderDependency)
.collect(Collectors.toList()));

if (log.isDebugEnabled()) {
Expand All @@ -34,7 +34,7 @@ public void write() throws IOException {
writeFile();
}

protected abstract T toMavenDependency(DebloatedDependency debloatedDependency);
protected abstract T toProviderDependency(DebloatedDependency debloatedDependency);

protected abstract void setDependencies(List<T> dependencies);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,16 @@
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.apache.commons.io.FileUtils;
import org.apache.maven.plugin.logging.Log;
import org.jetbrains.annotations.Nullable;
import se.kth.depclean.core.analysis.AnalysisFailureException;
import se.kth.depclean.core.analysis.DefaultProjectDependencyAnalyzer;
import se.kth.depclean.core.analysis.ProjectDependencyAnalyzerException;
import se.kth.depclean.core.analysis.graph.DependencyGraph;
import se.kth.depclean.core.analysis.model.ProjectDependencyAnalysis;
import se.kth.depclean.core.model.ClassName;
import se.kth.depclean.core.model.Dependency;
import se.kth.depclean.core.model.ProjectContext;
import se.kth.depclean.core.model.Scope;
import se.kth.depclean.core.util.JarUtils;
import se.kth.depclean.core.wrapper.DependencyManagerWrapper;
import se.kth.depclean.core.wrapper.LogWrapper;

/**
* Runs the depclean process, regardless of a specific dependency manager.
Expand All @@ -31,6 +29,7 @@
public class DepCleanManager {

private static final String SEPARATOR = "-------------------------------------------------------";
private static final String DIRECTORY_TO_EXTRACT_DEPENDENCIES = "dependency";

private final DependencyManagerWrapper dependencyManager;
private final boolean skipDepClean;
Expand All @@ -48,27 +47,25 @@ public class DepCleanManager {
* Execute the depClean manager.
*/
@SneakyThrows
public void execute() throws AnalysisFailureException {
public ProjectDependencyAnalysis execute() throws AnalysisFailureException {
final long startTime = System.currentTimeMillis();

if (skipDepClean) {
getLog().info("Skipping DepClean plugin execution");
return;
return null;
}
printString(SEPARATOR);
getLog().info("Starting DepClean dependency analysis");

if (dependencyManager.isMaven() && dependencyManager.isPackagingPom()) {
getLog().info("Skipping because packaging type is pom.");
return;
getLog().info("Skipping because packaging type is pom");
return null;
}

dependencyManager.copyAndExtractDependencies();
extractLibClasses();

final ProjectDependencyAnalysis analysis = getAnalysis();
if (analysis == null) {
return;
}
final DefaultProjectDependencyAnalyzer projectDependencyAnalyzer = new DefaultProjectDependencyAnalyzer();
final ProjectDependencyAnalysis analysis = projectDependencyAnalyzer.analyze(buildProjectContext());
analysis.print();

/* Fail the build if there are unused direct dependencies */
Expand Down Expand Up @@ -101,6 +98,44 @@ public void execute() throws AnalysisFailureException {

final long stopTime = System.currentTimeMillis();
getLog().info("Analysis done in " + getTime(stopTime - startTime));

return analysis;
}

@SneakyThrows
private void extractLibClasses() {
final File dependencyDirectory =
dependencyManager.getBuildDirectory().resolve(DIRECTORY_TO_EXTRACT_DEPENDENCIES).toFile();
FileUtils.deleteDirectory(dependencyDirectory);
dependencyManager.dependencyGraph().allDependencies()
.forEach(jarFile -> copyDependencies(jarFile, dependencyDirectory));

// TODO remove this workaround later
if (dependencyManager.getBuildDirectory().resolve("libs").toFile().exists()) {
try {
FileUtils.copyDirectory(
dependencyManager.getBuildDirectory().resolve("libs").toFile(),
dependencyDirectory
);
} catch (IOException | NullPointerException e) {
getLog().error("Error copying directory libs to dependency");
throw new RuntimeException(e);
}
}

/* Decompress dependencies */
if (dependencyDirectory.exists()) {
JarUtils.decompress(dependencyDirectory.getAbsolutePath());
}
}

private void copyDependencies(Dependency dependency, File destFolder) {
copyDependencies(dependency.getFile(), destFolder);
}

@SneakyThrows
private void copyDependencies(File jarFile, File destFolder) {
FileUtils.copyFileToDirectory(jarFile, destFolder);
}

private void createResultJson(ProjectDependencyAnalysis analysis) {
Expand Down Expand Up @@ -144,21 +179,6 @@ private void createResultJson(ProjectDependencyAnalysis analysis) {
}
}

@Nullable
private ProjectDependencyAnalysis getAnalysis() {
/* Analyze dependencies usage status */
final ProjectContext projectContext = buildProjectContext();
final ProjectDependencyAnalysis analysis;
final DefaultProjectDependencyAnalyzer dependencyAnalyzer = new DefaultProjectDependencyAnalyzer(projectContext);
try {
analysis = dependencyAnalyzer.analyze();
} catch (ProjectDependencyAnalyzerException e) {
getLog().error("Unable to analyze dependencies.");
return null;
}
return analysis;
}

private ProjectContext buildProjectContext() {
if (ignoreTests) {
ignoreScopes.add("test");
Expand All @@ -182,16 +202,15 @@ private ProjectContext buildProjectContext() {
allUsedClasses.addAll(usedClassesFromProcessors);
allUsedClasses.addAll(usedClassesFromSource);

final DependencyGraph dependencyGraph = dependencyManager.dependencyGraph();
return new ProjectContext(
dependencyGraph,
dependencyManager.getOutputDirectory(),
dependencyManager.getTestOutputDirectory(),
dependencyManager.dependencyGraph(),
dependencyManager.getOutputDirectories(),
dependencyManager.getTestOutputDirectories(),
dependencyManager.getSourceDirectory(),
dependencyManager.getTestDirectory(),
dependencyManager.getDependenciesDirectory(),
ignoreScopes.stream().map(Scope::new).collect(Collectors.toSet()),
toDependency(dependencyGraph.allDependencies(), ignoreDependencies),
toDependency(dependencyManager.dependencyGraph().allDependencies(), ignoreDependencies),
allUsedClasses
);
}
Expand Down Expand Up @@ -227,7 +246,7 @@ private void printString(final String string) {
System.out.println(string); //NOSONAR avoid a warning of non-used logger
}

private Log getLog() {
private LogWrapper getLog() {
return dependencyManager.getLog();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import se.kth.depclean.core.analysis.asm.ASMDependencyAnalyzer;
import se.kth.depclean.core.analysis.graph.DefaultCallGraph;
Expand All @@ -36,61 +37,52 @@
public class DefaultProjectDependencyAnalyzer {

private final DependencyAnalyzer dependencyAnalyzer = new ASMDependencyAnalyzer();
private final ProjectContext projectContext;

/**
* Ctor.
*/
public DefaultProjectDependencyAnalyzer(ProjectContext projectContext) {
this.projectContext = projectContext;
}

/**
* Analyze the dependencies in a project.
*
* @param projectContext The project's context
*
* @return An object representing the analysis result.
* @throws ProjectDependencyAnalyzerException if the analysis fails.
*/
public ProjectDependencyAnalysis analyze() throws ProjectDependencyAnalyzerException {
try {
// a map of [dependency] -> [classes]
final ActualUsedClasses actualUsedClasses = new ActualUsedClasses(projectContext);

/* ******************** bytecode analysis ********************* */

// analyze project's class files
actualUsedClasses.registerClasses(getProjectDependencyClasses(projectContext.getOutputFolder()));
// analyze project's tests class files
if (!projectContext.ignoreTests()) {
log.trace("Parsing test folder");
actualUsedClasses.registerClasses(getProjectTestDependencyClasses(projectContext.getTestOutputFolder()));
}
// the set of compiled classes and tests in the project
Set<String> projectClasses = new HashSet<>(DefaultCallGraph.getProjectVertices());
// analyze dependencies' class files
actualUsedClasses.registerClasses(getProjectDependencyClasses(projectContext.getDependenciesFolder()));
// analyze extra classes (collected through static analysis of source code)
actualUsedClasses.registerClasses(projectContext.getExtraClasses());

/* ******************** usage analysis ********************* */
actualUsedClasses.registerClasses(getReferencedClassMembers(projectClasses));
public ProjectDependencyAnalysis analyze(final ProjectContext projectContext) {

/* ******************** results as statically used at the bytecode *********************** */
return new ProjectDependencyAnalysisBuilder(projectContext, actualUsedClasses).analyse();
// a map of [dependency] -> [classes]
final ActualUsedClasses actualUsedClasses = new ActualUsedClasses(projectContext);

/* ******************** bytecode analysis ********************* */

} catch (IOException exception) {
throw new ProjectDependencyAnalyzerException("Cannot analyze dependencies", exception);
// analyze project's class files
projectContext.getOutputFolders()
.forEach(folder -> actualUsedClasses.registerClasses(getProjectDependencyClasses(folder)));
// analyze project's tests class files
if (!projectContext.ignoreTests()) {
log.trace("Parsing test folder");
projectContext.getTestOutputFolders()
.forEach(folder -> actualUsedClasses.registerClasses(getProjectTestDependencyClasses(folder)));
}
// the set of compiled classes and tests in the project
Set<String> projectClasses = new HashSet<>(DefaultCallGraph.getProjectVertices());
// analyze dependencies' class files
actualUsedClasses.registerClasses(getProjectDependencyClasses(projectContext.getDependenciesFolder()));
// analyze extra classes (collected through static analysis of source code)
actualUsedClasses.registerClasses(projectContext.getExtraClasses());

/* ******************** usage analysis ********************* */
actualUsedClasses.registerClasses(getReferencedClassMembers(projectClasses));

/* ******************** results as statically used at the bytecode *********************** */
return new ProjectDependencyAnalysisBuilder(projectContext, actualUsedClasses).analyse();
}

private Iterable<ClassName> getProjectDependencyClasses(Path outputFolder) throws IOException {
@SneakyThrows
private Iterable<ClassName> getProjectDependencyClasses(Path outputFolder) {
// Analyze src classes in the project
log.trace("# getProjectDependencyClasses()");
return collectDependencyClasses(outputFolder);
}

private Iterable<ClassName> getProjectTestDependencyClasses(Path testOutputFolder) throws IOException {
@SneakyThrows
private Iterable<ClassName> getProjectTestDependencyClasses(Path testOutputFolder) {
// Analyze test classes in the project
log.trace("# getProjectTestDependencyClasses()");
return collectDependencyClasses(testOutputFolder);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,9 @@ public static Set<String> getProjectVertices() {
return projectVertices;
}

public static Set<String> getVertices() {
return directedGraph.vertexSet();
}

public static void cleanDirectedGraph() {
directedGraph.vertexSet().clear();
directedGraph.edgeSet().clear();
public static void clear() {
projectVertices.clear();
usagesPerClass.clear();
}

public static Map<String, Set<String>> getUsagesPerClass() {
Expand Down
Loading