Skip to content

Commit

Permalink
refactor: Apply dependency injection
Browse files Browse the repository at this point in the history
* chore: Add Dagger to dependencies and build
* refactor: Split Cli class
* feat: Rewrite custom command class factory to Dagger implementation
* feat: Setup Dagger modules and components
* feat: Boot app with Dagger
* refactor: Extract state from command handler
* refactor: Add convenience constructor
* refactor: Follow-up
* test: Rewrite tests
* test: Make test independent of user timezone
* chore: Formatting

Closes #498, #192.
  • Loading branch information
mthmulders committed Feb 25, 2025
1 parent 4bab717 commit 390bf3d
Show file tree
Hide file tree
Showing 31 changed files with 873 additions and 424 deletions.
11 changes: 11 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
<maven.compiler.release>17</maven.compiler.release>

<assert-j.version>3.27.3</assert-j.version>
<dagger.version>2.55</dagger.version>
<jackson-jr.version>2.18.2</jackson-jr.version>
<junit-jupiter.version>5.11.4</junit-jupiter.version>
<picocli.version>4.7.6</picocli.version>
Expand Down Expand Up @@ -71,6 +72,11 @@
<artifactId>packageurl-java</artifactId>
<version>${packageurl.version}</version>
</dependency>
<dependency>
<groupId>com.google.dagger</groupId>
<artifactId>dagger</artifactId>
<version>${dagger.version}</version>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
Expand Down Expand Up @@ -238,6 +244,11 @@
<artifactId>picocli-codegen</artifactId>
<version>${picocli.version}</version>
</path>
<path>
<groupId>com.google.dagger</groupId>
<artifactId>dagger-compiler</artifactId>
<version>${dagger.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-Aproject=${project.groupId}/${project.artifactId}</arg>
Expand Down
19 changes: 8 additions & 11 deletions src/main/java/it/mulders/mcs/App.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package it.mulders.mcs;

import it.mulders.mcs.cli.Cli;
import it.mulders.mcs.cli.CommandClassFactory;
import it.mulders.mcs.cli.SystemPropertyLoader;
import it.mulders.mcs.common.McsExecutionExceptionHandler;
import it.mulders.mcs.dagger.Application;
import it.mulders.mcs.dagger.DaggerApplication;
import java.net.URI;
import java.net.URISyntaxException;
import picocli.CommandLine;
Expand All @@ -15,20 +13,19 @@ public static void main(final String... args) {

// Visible for testing
static int doMain(final String... originalArgs) {
return doMain(new Cli(), new SystemPropertyLoader(), originalArgs);
}
final Application components = DaggerApplication.create();

static int doMain(final Cli cli, final SystemPropertyLoader systemPropertyLoader, final String... originalArgs) {
var systemPropertyLoader = components.systemPropertyLoader();
System.setProperties(systemPropertyLoader.getProperties());
setUpProxy();
var program = new CommandLine(cli, new CommandClassFactory(cli))
.setExecutionExceptionHandler(new McsExecutionExceptionHandler());

var args = isInvocationWithoutSearchCommand(program, originalArgs)
var commandLine = components.commandLine();

var args = isInvocationWithoutSearchCommand(commandLine, originalArgs)
? prependSearchCommandToArgs(originalArgs)
: originalArgs;

return program.execute(args);
return commandLine.execute(args);
}

private static void setUpProxy() {
Expand Down
59 changes: 59 additions & 0 deletions src/main/java/it/mulders/mcs/cli/ClassSearchCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package it.mulders.mcs.cli;

import it.mulders.mcs.search.SearchCommandHandler;
import it.mulders.mcs.search.SearchQuery;
import jakarta.inject.Inject;
import java.util.concurrent.Callable;
import picocli.CommandLine;

@CommandLine.Command(
name = "class-search",
description = "Search artifacts in Maven Central by class name",
usageHelpAutoWidth = true)
public class ClassSearchCommand implements Callable<Integer> {
@CommandLine.Parameters(
arity = "1",
description = {
"The class name to search for.",
})
private String query;

@CommandLine.Option(
names = {"-f", "--full-name"},
negatable = true,
arity = "0",
description = "Class name includes package")
private boolean fullName;

@CommandLine.Option(
names = {"-l", "--limit"},
description = "Show <count> results",
paramLabel = "<count>")
private Integer limit;

private final SearchCommandHandler searchCommandHandler;

@Inject
public ClassSearchCommand(final SearchCommandHandler searchCommandHandler) {
this.searchCommandHandler = searchCommandHandler;
}

// Visible for testing
ClassSearchCommand(final SearchCommandHandler searchCommandHandler, String query, Integer limit, boolean fullName) {
this(searchCommandHandler);
this.fullName = fullName;
this.limit = limit;
this.query = query;
}

@Override
public Integer call() {
System.out.printf("Searching for artifacts containing %s...%n", query);
var searchQuery = SearchQuery.classSearch(this.query)
.isFullyQualified(this.fullName)
.withLimit(limit)
.build();
searchCommandHandler.search(searchQuery, "maven", false);
return 0;
}
}
106 changes: 4 additions & 102 deletions src/main/java/it/mulders/mcs/cli/Cli.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
package it.mulders.mcs.cli;

import it.mulders.mcs.search.FormatType;
import it.mulders.mcs.search.SearchCommandHandler;
import it.mulders.mcs.search.SearchQuery;
import it.mulders.mcs.search.printer.CoordinatePrinter;
import java.util.concurrent.Callable;
import jakarta.inject.Inject;
import picocli.CommandLine;

@CommandLine.Command(
name = "mcs",
subcommands = {Cli.SearchCommand.class, Cli.ClassSearchCommand.class},
subcommands = {SearchCommand.class, ClassSearchCommand.class},
usageHelpAutoWidth = true,
versionProvider = ClasspathVersionProvider.class)
public class Cli {
Expand All @@ -27,100 +23,6 @@ public class Cli {
usageHelp = true)
private boolean usageHelpRequested;

public SearchCommand createSearchCommand() {
return new SearchCommand();
}

public ClassSearchCommand createClassSearchCommand() {
return new ClassSearchCommand();
}

@CommandLine.Command(
name = "search",
description = "Search artifacts in Maven Central by coordinates",
usageHelpAutoWidth = true)
public class SearchCommand implements Callable<Integer> {
@CommandLine.Parameters(
arity = "1..n",
description = {
"What to search for.",
"If the search term contains a colon ( : ), it is considered a literal groupId and artifactId",
"Otherwise, the search term is considered a wildcard search"
})
private String[] query;

@CommandLine.Option(
names = {"-l", "--limit"},
description = "Show <count> results",
paramLabel = "<count>")
private Integer limit;

@CommandLine.Option(
names = {"-f", "--format"},
description =
"""
Show result in <type> format
Supported types are:
maven, gradle, gradle-short, gradle-kotlin, sbt, ivy, grape, leiningen, buildr, jbang, gav
""",
paramLabel = "<type>")
private String responseFormat;

@CommandLine.Option(
names = {"-s", "--show-vulnerabilities"},
description = "Show reported security vulnerabilities",
paramLabel = "<vulnerabilities>")
private boolean showVulnerabilities;

@Override
public Integer call() {
var combinedQuery = String.join(" ", query);
System.out.printf("Searching for %s...%n", combinedQuery);
var searchQuery =
SearchQuery.search(combinedQuery).withLimit(this.limit).build();

CoordinatePrinter coordinatePrinter = FormatType.providePrinter(responseFormat);
var searchCommandHandler = new SearchCommandHandler(coordinatePrinter, showVulnerabilities);
searchCommandHandler.search(searchQuery);
return 0;
}
}

@CommandLine.Command(
name = "class-search",
description = "Search artifacts in Maven Central by class name",
usageHelpAutoWidth = true)
public class ClassSearchCommand implements Callable<Integer> {
@CommandLine.Parameters(
arity = "1",
description = {
"The class name to search for.",
})
private String query;

@CommandLine.Option(
names = {"-f", "--full-name"},
negatable = true,
arity = "0",
description = "Class name includes package")
private boolean fullName;

@CommandLine.Option(
names = {"-l", "--limit"},
description = "Show <count> results",
paramLabel = "<count>")
private Integer limit;

@Override
public Integer call() {
System.out.printf("Searching for artifacts containing %s...%n", query);
var searchQuery = SearchQuery.classSearch(this.query)
.isFullyQualified(this.fullName)
.withLimit(limit)
.build();
var searchCommandHandler = new SearchCommandHandler();
searchCommandHandler.search(searchQuery);
return 0;
}
}
@Inject
public Cli() {}
}
28 changes: 0 additions & 28 deletions src/main/java/it/mulders/mcs/cli/CommandClassFactory.java

This file was deleted.

77 changes: 77 additions & 0 deletions src/main/java/it/mulders/mcs/cli/SearchCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package it.mulders.mcs.cli;

import it.mulders.mcs.search.SearchCommandHandler;
import it.mulders.mcs.search.SearchQuery;
import jakarta.inject.Inject;
import java.util.concurrent.Callable;
import picocli.CommandLine;

@CommandLine.Command(
name = "search",
description = "Search artifacts in Maven Central by coordinates",
usageHelpAutoWidth = true)
public class SearchCommand implements Callable<Integer> {
@CommandLine.Parameters(
arity = "1..n",
description = {
"What to search for.",
"If the search term contains a colon ( : ), it is considered a literal groupId and artifactId",
"Otherwise, the search term is considered a wildcard search"
})
private String[] query;

@CommandLine.Option(
names = {"-l", "--limit"},
description = "Show <count> results",
paramLabel = "<count>")
private Integer limit;

@CommandLine.Option(
names = {"-f", "--format"},
description =
"""
Show result in <type> format
Supported types are:
maven, gradle, gradle-short, gradle-kotlin, sbt, ivy, grape, leiningen, buildr, jbang, gav
""",
paramLabel = "<type>")
private String responseFormat;

@CommandLine.Option(
names = {"-s", "--show-vulnerabilities"},
description = "Show reported security vulnerabilities",
paramLabel = "<vulnerabilities>")
private boolean showVulnerabilities;

private final SearchCommandHandler searchCommandHandler;

@Inject
public SearchCommand(final SearchCommandHandler searchCommandHandler) {
this.searchCommandHandler = searchCommandHandler;
}

// Visible for testing
SearchCommand(
SearchCommandHandler searchCommandHandler,
String[] query,
Integer limit,
String responseFormat,
boolean showVulnerabilities) {
this(searchCommandHandler);
this.limit = limit;
this.query = query;
this.responseFormat = responseFormat;
this.showVulnerabilities = showVulnerabilities;
}

@Override
public Integer call() {
var combinedQuery = String.join(" ", query);
System.out.printf("Searching for %s...%n", combinedQuery);
var searchQuery =
SearchQuery.search(combinedQuery).withLimit(this.limit).build();

searchCommandHandler.search(searchQuery, responseFormat, showVulnerabilities);
return 0;
}
}
3 changes: 2 additions & 1 deletion src/main/java/it/mulders/mcs/cli/SystemPropertyLoader.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package it.mulders.mcs.cli;

import jakarta.inject.Inject;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
Expand All @@ -17,8 +18,8 @@ public class SystemPropertyLoader {
private static final Path MCS_PROPERTIES_FILE = Paths.get(System.getProperty("user.home"), ".mcs", "mcs.config");

private final Properties properties = new Properties();
;

@Inject
public SystemPropertyLoader() {
this(MCS_PROPERTIES_FILE);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package it.mulders.mcs.common;

import jakarta.inject.Inject;
import picocli.CommandLine;

public class McsExecutionExceptionHandler implements CommandLine.IExecutionExceptionHandler {
@Inject
public McsExecutionExceptionHandler() {}

@Override
public int handleExecutionException(Exception ex, CommandLine commandLine, CommandLine.ParseResult parseResult) {
var message =
Expand Down
Loading

0 comments on commit 390bf3d

Please sign in to comment.