Skip to content

Commit

Permalink
feat: plug mgr uses registries for jbang discovery
Browse files Browse the repository at this point in the history
  • Loading branch information
iocanel committed Mar 22, 2023
1 parent 941730e commit eb177d3
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 32 deletions.
16 changes: 13 additions & 3 deletions devtools/cli/src/main/java/io/quarkus/cli/QuarkusCli.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
import io.quarkus.cli.plugin.Plugin;
import io.quarkus.cli.plugin.PluginCommandFactory;
import io.quarkus.cli.plugin.PluginManager;
import io.quarkus.cli.plugin.PluginManagerSettings;
import io.quarkus.cli.registry.RegistryClientMixin;
import io.quarkus.cli.utils.Registries;
import io.quarkus.devtools.utils.Prompt;
import io.quarkus.runtime.QuarkusApplication;
import picocli.CommandLine;
Expand Down Expand Up @@ -48,6 +51,9 @@ public class QuarkusCli implements QuarkusApplication, Callable<Integer> {
@Inject
CommandLine.IFactory factory;

@CommandLine.Mixin
protected RegistryClientMixin registryClient;

@CommandLine.Mixin
protected HelpOption helpOption;

Expand Down Expand Up @@ -80,7 +86,7 @@ public int run(String... args) throws Exception {
missing.ifPresent(m -> {
Map<String, Plugin> installable = pluginManager.getInstallablePlugins();
if (installable.containsKey(m)) {
if (Prompt.yesOrNo(true,
if (!output.isCliTest() && Prompt.yesOrNo(true,
"Command %s is not installed, but a matching plugin is available. Would you like to install it now ?",
args)) {
pluginManager.addPlugin(m).ifPresent(added -> plugins.put(added.getName(), added));
Expand Down Expand Up @@ -220,8 +226,12 @@ private static Optional<Path> getProjectRoot(OutputOptionMixin output) {
return Optional.ofNullable(projectRoot);
}

private static PluginManager pluginManager(OutputOptionMixin output) {
return new PluginManager(output, Optional.ofNullable(Paths.get(System.getProperty("user.home"))),
private PluginManager pluginManager(OutputOptionMixin output) {
PluginManagerSettings settings = PluginManagerSettings.defaultSettings()
.withCatalogs(Registries.getRegistries(registryClient, "quarkusio"))
.withTestMode(output.isCliTest());

return new PluginManager(settings, output, Optional.ofNullable(Paths.get(System.getProperty("user.home"))),
getProjectRoot(output), Optional.empty(), p -> true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
import java.util.Set;

import io.quarkus.cli.build.BaseBuildCommand;
import io.quarkus.cli.common.TargetQuarkusPlatformGroup;
import io.quarkus.cli.utils.Registries;
import io.quarkus.devtools.project.QuarkusProject;
import picocli.CommandLine;

Expand Down Expand Up @@ -35,7 +37,12 @@ public Optional<QuarkusProject> quarkusProject() {
}

public PluginManager pluginManager() {
return new PluginManager(output,
Set<String> registries = Registries.getRegistries(registryClient, "quarkusio");
PluginManagerSettings settings = PluginManagerSettings.defaultSettings()
.withCatalogs(registries)
.withTestMode(output.isCliTest());

return new PluginManager(settings, output,
catalogOptions.userDirectory.or(() -> Optional.ofNullable(Paths.get(System.getProperty("user.home")))),
catalogOptions.user ? Optional.empty() : Optional.ofNullable(projectRoot()),
catalogOptions.user ? Optional.empty() : quarkusProject(),
Expand Down
31 changes: 31 additions & 0 deletions devtools/cli/src/main/java/io/quarkus/cli/utils/Registries.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.quarkus.cli.utils;

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;

import io.quarkus.cli.registry.RegistryClientMixin;
import io.quarkus.registry.RegistryResolutionException;
import io.quarkus.registry.config.RegistryConfig;

public final class Registries {

private Registries() {
//Utility class
}

public static Set<String> getRegistries(RegistryClientMixin client, String... additionalRegistires) {
Set<String> registries = new LinkedHashSet<>();
try {
for (RegistryConfig c : client.resolveConfig().getRegistries()) {
registries.add(c.getId());
}
for (String r : additionalRegistires) {
registries.add(r);
}
return registries;
} catch (RegistryResolutionException e) {
return new HashSet<>();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,33 @@ public class JBangCatalogService extends CatalogService<JBangCatalog> {
private static final String PATH_REGEX = "^\\s*\\((?<path>.*)\\)\\s*$";
private static final Pattern PATH = Pattern.compile(PATH_REGEX);

private final MessageWriter output;
private final boolean testMode;
private final String pluginPrefix;
private final String remoteCatalog;
private final String[] remoteCatalogs;
private final JBangSupport jbang;

public JBangCatalogService(MessageWriter output) {
this(output, "quarkus", "quarkusio");
}

public JBangCatalogService(MessageWriter output, String pluginPrefix, String remoteCatalog) {
public JBangCatalogService(MessageWriter output, String pluginPrefix, String... remoteCatalogs) {
this(false, output, pluginPrefix, remoteCatalogs);
}

public JBangCatalogService(boolean testModeEnabled, MessageWriter output, String pluginPrefix, String... remoteCatalogs) {
super(JBangCatalog.class, GIT_ROOT, RELATIVE_PLUGIN_CATALOG);
this.output = output;
this.testMode = testModeEnabled;
this.pluginPrefix = pluginPrefix;
this.remoteCatalog = remoteCatalog;
this.remoteCatalogs = remoteCatalogs;
this.jbang = new JBangSupport(output);
}

@Override
public JBangCatalog readCatalog(Path path) {
if (!jbang.isAvailable() && testMode) {
return new JBangCatalog();
}

JBangCatalog catalog = super.readCatalog(path);
return new JBangCatalog(catalog.getCatalogs(),
catalog.getAliases().entrySet().stream().filter(e -> e.getKey().startsWith(pluginPrefix + "-"))
Expand All @@ -54,30 +62,38 @@ public JBangCatalog readCatalog(Path path) {
* @return the catalog
*/
public JBangCatalog readCombinedCatalog(Optional<Path> projectDir, Optional<Path> userDir) {
if (!jbang.isAvailable() && testMode) {
return new JBangCatalog();
}

Map<String, JBangCatalog> catalogs = new HashMap<>();
Map<String, JBangAlias> aliases = new HashMap<>();

Optional<JBangCatalog> projectCatalog = readProjectCatalog(projectDir);
Optional<JBangCatalog> userCatalog = readUserCatalog(userDir);

userCatalog.ifPresent(u -> {
//Read local
aliases.putAll(u.getAliases());
List<String> lines = jbang.execute("alias", "list", "--verbose", remoteCatalog);
aliases.putAll(readAliases(lines));

});

projectCatalog.ifPresent(p -> {
//Read local
aliases.putAll(p.getAliases());

Optional<String> catalogFile = projectDir.map(d -> RELATIVE_PLUGIN_CATALOG.apply(d).toAbsolutePath().toString());
Optional<String> catalogFile = projectDir
.map(d -> RELATIVE_PLUGIN_CATALOG.apply(d).toAbsolutePath().toString());
catalogFile.ifPresent(f -> {
List<String> lines = jbang.execute("alias", "list", "-f", f, "--verbose", remoteCatalog);
List<String> lines = jbang.execute("alias", "list", "-f", f, "--verbose");
aliases.putAll(readAliases(lines));
});
});

for (String remoteCatalog : remoteCatalogs) {
List<String> lines = jbang.execute("alias", "list", "--verbose", remoteCatalog);
aliases.putAll(readAliases(lines).entrySet()
.stream()
.filter(e -> !aliases.containsKey(e.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
}
return new JBangCatalog(catalogs, aliases, Optional.empty(), Optional.empty());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public class JBangSupport {
private static final String[] windowsWrapper = { "jbang.cmd", "jbang.ps1" };
private static final String otherWrapper = "jbang";

private final boolean cliTestMode;
private final MessageWriter output;
private Path workingDirectory;

Expand All @@ -43,6 +44,11 @@ public JBangSupport(MessageWriter output) {
}

public JBangSupport(MessageWriter output, Path workingDirectory) {
this(false, output, workingDirectory);
}

public JBangSupport(boolean testModeEnabled, MessageWriter output, Path workingDirectory) {
this.cliTestMode = testModeEnabled;
this.output = output;
this.workingDirectory = workingDirectory;
}
Expand Down Expand Up @@ -76,7 +82,8 @@ public Optional<File> getOptionalExecutable() {
.or(() -> findExecutableInLocalJbang())
.or(() -> {
try {
if (promptForInstallation && Prompt.yesOrNo(true,
// We don't want to prompt users for input when running tests.
if (!cliTestMode && promptForInstallation && Prompt.yesOrNo(true,
"JBang is needed to list / run jbang plugins, would you like to install it now ?")) {
installJBang();
return findExecutableInLocalJbang();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@ public class PluginManager {

public PluginManager(MessageWriter output, Optional<Path> userHome, Optional<Path> projectRoot,
Optional<QuarkusProject> quarkusProject, Predicate<Plugin> pluginFilter) {
this(PluginManagerSettings.defaultSettings(), output, userHome, projectRoot, quarkusProject, pluginFilter);
}

public PluginManager(PluginManagerSettings settings, MessageWriter output, Optional<Path> userHome,
Optional<Path> projectRoot, Optional<QuarkusProject> quarkusProject, Predicate<Plugin> pluginFilter) {
this.output = output;
this.settings = PluginManagerSettings.defaultSettings();
this.settings = settings;
this.util = PluginManagerUtil.getUtil(settings);
this.state = new PluginMangerState(settings, output, userHome, projectRoot, quarkusProject, pluginFilter);
}
Expand Down Expand Up @@ -209,6 +214,9 @@ public boolean sync() {
* Sync happens weekly or when project files are updated.
*/
public boolean syncIfNeeded() {
if (settings.isTestMode()) {
return false;
}
PluginCatalog catalog = state.getCombinedCatalog();
if (PluginUtil.shouldSync(state.getProjectRoot(), catalog)) {
output.info("Plugin catalog last updated on: " + catalog.getLastUpdate() + ". Syncing!");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.quarkus.cli.plugin;

import java.nio.file.Path;
import java.util.Set;
import java.util.function.Function;

/**
Expand All @@ -12,27 +13,43 @@
public class PluginManagerSettings {

public static String DEFAULT_PLUGIN_PREFIX = "quarkus";
public static String DEFAULT_REMOTE_JBANG_CATALOG = "quarkusio";
public static String[] DEFAULT_REMOTE_JBANG_CATALOGS = new String[] { "quarkusio" };
public static Function<Path, Path> DEFAULT_RELATIVE_PATH_FUNC = p -> p.resolve(".quarkus").resolve("cli").resolve("plugins")
.resolve("quarkus-cli-catalog.json");

private final boolean testMode;
private final String pluginPrefix;
private final String remoteJBangCatalog;
private final String[] remoteJBangCatalogs;
private final Function<Path, Path> toRelativePath;

public PluginManagerSettings(String pluginPrefix, String remoteJBangCatalog, Function<Path, Path> toRelativePath) {
public PluginManagerSettings(boolean testMode, String pluginPrefix, String[] remoteJBangCatalogs,
Function<Path, Path> toRelativePath) {
this.testMode = testMode;
this.pluginPrefix = pluginPrefix;
this.remoteJBangCatalog = remoteJBangCatalog;
this.remoteJBangCatalogs = remoteJBangCatalogs;
this.toRelativePath = toRelativePath;
}

public static PluginManagerSettings defaultSettings() {
return new PluginManagerSettings(DEFAULT_PLUGIN_PREFIX, DEFAULT_REMOTE_JBANG_CATALOG, DEFAULT_RELATIVE_PATH_FUNC);
return new PluginManagerSettings(false, DEFAULT_PLUGIN_PREFIX, DEFAULT_REMOTE_JBANG_CATALOGS,
DEFAULT_RELATIVE_PATH_FUNC);
}

public static PluginManagerSettings create(String name, String remoteJbangCatalog) {
return new PluginManagerSettings(name, remoteJbangCatalog,
p -> p.resolve("." + name).resolve("cli").resolve("plugins").resolve(name + "-cli-catalog.json"));
public PluginManagerSettings withPluignPrefix(String pluginPrefix) {
return new PluginManagerSettings(testMode, pluginPrefix, remoteJBangCatalogs, toRelativePath);
}

public PluginManagerSettings withCatalogs(Set<String> remoteJBangCatalogs) {
return new PluginManagerSettings(testMode, pluginPrefix,
remoteJBangCatalogs.toArray(new String[remoteJBangCatalogs.size()]), toRelativePath);
}

public PluginManagerSettings withCatalogs(String... remoteJBangCatalogs) {
return new PluginManagerSettings(testMode, pluginPrefix, remoteJBangCatalogs, toRelativePath);
}

public PluginManagerSettings withTestMode(boolean testMode) {
return new PluginManagerSettings(testMode, pluginPrefix, remoteJBangCatalogs, toRelativePath);
}

/**
Expand All @@ -47,12 +64,16 @@ public String getPluginPrefix() {
}

/**
* The name of the JBang catalog to get plugins from.
* The names of the JBang catalogs to get plugins from.
*
* @return the name of the catalog.
*/
public String getRemoteJBangCatalog() {
return remoteJBangCatalog;
public String[] getRemoteJBangCatalogs() {
return remoteJBangCatalogs;
}

public boolean isTestMode() {
return testMode;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ class PluginMangerState {
//Inferred
this.projectRoot = projectRoot.or(() -> quarkusProject.map(QuarkusProject::getProjectDirPath))
.filter(p -> !p.equals(userHome.orElse(null)));
this.jbangCatalogService = new JBangCatalogService(output, settings.getPluginPrefix(),
settings.getRemoteJBangCatalog());
this.jbangCatalogService = new JBangCatalogService(settings.isTestMode(), output, settings.getPluginPrefix(),
settings.getRemoteJBangCatalogs());
this.pluginCatalogService = new PluginCatalogService(settings.getToRelativePath());
this.util = PluginManagerUtil.getUtil(settings);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ public void shouldGetNameFromLocation() {
//No replacement here
assertEquals("something-cli2", util.getName("something-cli2@quarkusio"));

PluginManagerSettings customSetttings = PluginManagerSettings.create("awesomeoss", "awesomeossio");
PluginManagerSettings customSetttings = PluginManagerSettings.defaultSettings()
.withPluignPrefix("awesomeoss")
.withCatalogs("awesomeossio");
util = PluginManagerUtil.getUtil(customSetttings);

assertEquals("my", util.getName("http://shomehost/some/path/my.jar"));
Expand Down

0 comments on commit eb177d3

Please sign in to comment.