Skip to content

Commit

Permalink
CLI add/remove registry commands
Browse files Browse the repository at this point in the history
  • Loading branch information
aloubyansky committed Aug 24, 2021
1 parent fb575c1 commit 5f1090c
Show file tree
Hide file tree
Showing 10 changed files with 238 additions and 13 deletions.
4 changes: 3 additions & 1 deletion devtools/cli/src/main/java/io/quarkus/cli/Registry.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
import picocli.CommandLine.Unmatched;

@CommandLine.Command(name = "registry", sortOptions = false, mixinStandardHelpOptions = false, header = "Manage extension registries.", subcommands = {
RegistryListCommand.class }, headerHeading = "%n", commandListHeading = "%nCommands:%n", synopsisHeading = "%nUsage: ", optionListHeading = "%nOptions:%n")
RegistryAddCommand.class,
RegistryListCommand.class,
RegistryRemoveCommand.class }, headerHeading = "%n", commandListHeading = "%nCommands:%n", synopsisHeading = "%nUsage: ", optionListHeading = "%nOptions:%n")
public class Registry extends BaseRegistryCommand {

@Unmatched // avoids throwing errors for unmatched arguments
Expand Down
74 changes: 74 additions & 0 deletions devtools/cli/src/main/java/io/quarkus/cli/RegistryAddCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package io.quarkus.cli;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Set;
import java.util.stream.Collectors;

import io.quarkus.cli.registry.BaseRegistryCommand;
import io.quarkus.cli.registry.RegistryClientMixin;
import io.quarkus.registry.config.RegistriesConfig;
import io.quarkus.registry.config.RegistriesConfigLocator;
import io.quarkus.registry.config.RegistryConfig;
import io.quarkus.registry.config.json.JsonRegistriesConfig;
import io.quarkus.registry.config.json.JsonRegistryConfig;
import io.quarkus.registry.config.json.RegistriesConfigMapperHelper;
import picocli.CommandLine;

@CommandLine.Command(name = "add", sortOptions = false, showDefaultValues = true, mixinStandardHelpOptions = false, header = "Add a Quarkus extension registry to the registry client configuration", description = "%n"
+ "This command will add a Quarkus extension registry to the registry client configuration unless it's already present", headerHeading = "%n", commandListHeading = "%nCommands:%n", synopsisHeading = "%nUsage: ", parameterListHeading = "%n", optionListHeading = "Options:%n")
public class RegistryAddCommand extends BaseRegistryCommand {

@CommandLine.Mixin
protected RegistryClientMixin registryClient;

@CommandLine.Parameters(arity = "0..1", paramLabel = "REGISTRY-ID[,REGISTRY-ID]", description = "Registry ID to add to the registry client configuration")
String registryIds;

@CommandLine.Option(paramLabel = "CONFIG", names = { "--config" }, description = "Configuration file")
String config;

@Override
public Integer call() throws Exception {

registryClient.refreshRegistryCache(output);

Path configYaml;
if (config == null) {
configYaml = RegistriesConfigLocator.locateConfigYaml();
if (configYaml == null) {
configYaml = RegistriesConfigLocator.getDefaultConfigYamlLocation();
}
} else {
configYaml = Paths.get(config);
}

final RegistriesConfig config;
if (Files.exists(configYaml)) {
config = RegistriesConfigMapperHelper.deserialize(configYaml, JsonRegistriesConfig.class);
} else {
config = new JsonRegistriesConfig();
}

final Set<String> existingIds = config.getRegistries().stream().map(RegistryConfig::getId).collect(Collectors.toSet());
boolean persist = false;
for (String registryId : registryIds.split(",")) {
if (existingIds.add(registryId)) {
persist = true;
final JsonRegistryConfig registry = new JsonRegistryConfig();
registry.setId(registryId);
config.getRegistries().add(registry);
output.info("Registry " + registryId + " was added");
} else {
output.info("Registry " + registryId + " was skipped since it is already present");
}
}

if (persist) {
RegistriesConfigMapperHelper.serialize(config, configYaml);
}

return CommandLine.ExitCode.OK;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package io.quarkus.cli;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;

import io.quarkus.cli.registry.BaseRegistryCommand;
import io.quarkus.cli.registry.RegistryClientMixin;
import io.quarkus.registry.config.RegistriesConfig;
import io.quarkus.registry.config.RegistriesConfigLocator;
import io.quarkus.registry.config.RegistryConfig;
import io.quarkus.registry.config.json.JsonRegistriesConfig;
import io.quarkus.registry.config.json.RegistriesConfigMapperHelper;
import picocli.CommandLine;

@CommandLine.Command(name = "remove", sortOptions = false, showDefaultValues = true, mixinStandardHelpOptions = false, header = "Remove a Quarkus extension registry from the registry client configuration", description = "%n"
+ "This command will remove a Quarkus extension registry from the registry client configuration", headerHeading = "%n", commandListHeading = "%nCommands:%n", synopsisHeading = "%nUsage: ", parameterListHeading = "%n", optionListHeading = "Options:%n")
public class RegistryRemoveCommand extends BaseRegistryCommand {

@CommandLine.Mixin
protected RegistryClientMixin registryClient;

@CommandLine.Parameters(arity = "0..1", paramLabel = "REGISTRY-ID[,REGISTRY-ID]", description = "Registry ID to remove from the registry client configuration")
String registryIds;

@CommandLine.Option(paramLabel = "CONFIG", names = { "--config" }, description = "Configuration file")
String config;

@Override
public Integer call() throws Exception {

registryClient.refreshRegistryCache(output);

Path configYaml;
if (config == null) {
configYaml = RegistriesConfigLocator.locateConfigYaml();
if (configYaml == null) {
output.error("Failed to locate the registry client configuration file");
return CommandLine.ExitCode.SOFTWARE;
}
} else {
configYaml = Paths.get(config);
}

final RegistriesConfig config = RegistriesConfigMapperHelper.deserialize(configYaml, JsonRegistriesConfig.class);

final Map<String, RegistryConfig> registries = new LinkedHashMap<>(config.getRegistries().size());
config.getRegistries().forEach(r -> registries.put(r.getId(), r));
boolean persist = false;
for (String registryId : registryIds.split(",")) {
if (registries.remove(registryId) == null) {
output.info("Registry " + registryId + " was not previously configured");
} else {
output.info("Registry " + registryId + " was removed");
persist = true;
}
}

if (persist) {
final JsonRegistriesConfig jsonConfig = new JsonRegistriesConfig();
jsonConfig.setRegistries(new ArrayList<>(registries.values()));
RegistriesConfigMapperHelper.serialize(jsonConfig, configYaml);
}

return CommandLine.ExitCode.OK;
}
}
65 changes: 65 additions & 0 deletions devtools/cli/src/test/java/io/quarkus/cli/CliNonProjectTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
import org.junit.jupiter.api.Test;

import io.quarkus.devtools.testing.RegistryClientTestHelper;
import io.quarkus.registry.config.RegistriesConfig;
import io.quarkus.registry.config.RegistriesConfigLocator;
import io.quarkus.registry.config.json.JsonRegistriesConfig;
import io.quarkus.registry.config.json.RegistriesConfigMapperHelper;
import picocli.CommandLine;

public class CliNonProjectTest {
Expand Down Expand Up @@ -200,6 +204,67 @@ public void testRegistryRefresh() throws Exception {
"Should contain '- registry.quarkus.io', found: " + result.stdout);
}

@Test
public void testRegistryAddRemove() throws Exception {

CliDriver.Result result;

final Path testConfigYaml = workspaceRoot.resolve("test-registry-add-remove.yaml").toAbsolutePath();
Files.deleteIfExists(testConfigYaml);

assertThat(testConfigYaml).doesNotExist();
result = CliDriver.execute(workspaceRoot, "registry", "add", "one,two", "--config", testConfigYaml.toString());
Assertions.assertEquals(CommandLine.ExitCode.OK, result.exitCode,
"Expected OK return code." + result);

assertThat(testConfigYaml).exists();
RegistriesConfig testConfig = RegistriesConfigLocator.load(testConfigYaml);
assertThat(testConfig.getRegistries()).hasSize(2);
assertThat(testConfig.getRegistries().get(0).getId()).isEqualTo("one");
assertThat(testConfig.getRegistries().get(1).getId()).isEqualTo("two");

result = CliDriver.execute(workspaceRoot, "registry", "add", "two,three", "--config", testConfigYaml.toString());
Assertions.assertEquals(CommandLine.ExitCode.OK, result.exitCode,
"Expected OK return code." + result);

testConfig = RegistriesConfigLocator.load(testConfigYaml);
assertThat(testConfig.getRegistries()).hasSize(3);
assertThat(testConfig.getRegistries().get(0).getId()).isEqualTo("one");
assertThat(testConfig.getRegistries().get(1).getId()).isEqualTo("two");
assertThat(testConfig.getRegistries().get(2).getId()).isEqualTo("three");

result = CliDriver.execute(workspaceRoot, "registry", "remove", "one,two", "--config", testConfigYaml.toString());
Assertions.assertEquals(CommandLine.ExitCode.OK, result.exitCode,
"Expected OK return code." + result);

testConfig = RegistriesConfigLocator.load(testConfigYaml);
assertThat(testConfig.getRegistries()).hasSize(1);
assertThat(testConfig.getRegistries().get(0).getId()).isEqualTo("three");

result = CliDriver.execute(workspaceRoot, "registry", "add", "four", "--config", testConfigYaml.toString());
Assertions.assertEquals(CommandLine.ExitCode.OK, result.exitCode,
"Expected OK return code." + result);

testConfig = RegistriesConfigLocator.load(testConfigYaml);
assertThat(testConfig.getRegistries()).hasSize(2);
assertThat(testConfig.getRegistries().get(0).getId()).isEqualTo("three");
assertThat(testConfig.getRegistries().get(1).getId()).isEqualTo("four");

result = CliDriver.execute(workspaceRoot, "registry", "remove", "three,four,five", "--config",
testConfigYaml.toString());
Assertions.assertEquals(CommandLine.ExitCode.OK, result.exitCode,
"Expected OK return code." + result);

testConfig = RegistriesConfigMapperHelper.deserialize(testConfigYaml, JsonRegistriesConfig.class);
assertThat(testConfig.getRegistries()).isEmpty();

testConfig = RegistriesConfigLocator.load(testConfigYaml);
assertThat(testConfig.getRegistries()).hasSize(1);
assertThat(testConfig.getRegistries().get(0).getId()).isEqualTo("registry.quarkus.io");

Files.delete(testConfigYaml);
}

private static String getRequiredProperty(String name) {
return Objects.requireNonNull(System.getProperty(name));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ public static RegistriesConfig load(Reader configYaml) {
}
}

/**
* Returns the registry client configuration file or null, if the file could not be found.
*
* @return the registry client configuration file or null, if the file could not be found
*/
public static Path locateConfigYaml() {
final String prop = PropertiesUtil.getProperty(CONFIG_FILE_PATH_PROPERTY);
Path configYaml;
Expand All @@ -120,10 +125,19 @@ public static Path locateConfigYaml() {
if (Files.exists(configYaml)) {
return configYaml;
}
configYaml = Paths.get(PropertiesUtil.getProperty("user.home")).resolve(CONFIG_RELATIVE_PATH);
configYaml = getDefaultConfigYamlLocation();
return Files.exists(configYaml) ? configYaml : null;
}

/**
* Returns the default location of the registry client configuration file.
*
* @return the default location of the registry client configuration file
*/
public static Path getDefaultConfigYamlLocation() {
return Paths.get(PropertiesUtil.getProperty("user.home")).resolve(CONFIG_RELATIVE_PATH);
}

static RegistriesConfig completeRequiredConfig(RegistriesConfig original) {
final JsonRegistriesConfig config = new JsonRegistriesConfig();
config.setDebug(original.isDebug());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@
import io.quarkus.registry.config.RegistriesConfig;
import io.quarkus.registry.config.RegistryConfig;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

@JsonInclude(JsonInclude.Include.NON_DEFAULT)
public class JsonRegistriesConfig implements RegistriesConfig {

private boolean debug;
private List<RegistryConfig> registries = Collections.emptyList();
private List<RegistryConfig> registries = new ArrayList<>();

@Override
@JsonDeserialize(contentUsing = JsonRegistryConfigDeserializer.class)
Expand All @@ -25,13 +24,14 @@ public List<RegistryConfig> getRegistries() {
}

public void setRegistries(List<RegistryConfig> registries) {
this.registries = registries == null ? Collections.emptyList() : registries;
if (registries == null) {
this.registries.clear();
} else {
this.registries = registries;
}
}

public void addRegistry(RegistryConfig registry) {
if (registries.isEmpty()) {
registries = new ArrayList<>();
}
registries.add(registry);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public class JsonRegistryConfigSerializer extends JsonSerializer<JsonRegistryCon
@Override
public void serialize(JsonRegistryConfig value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (value.isIdOnly()) {
gen.writeString(value.getId());
// to avoid quotes it is written as a number
gen.writeNumber(value.getId());
} else {
gen.writeStartObject();
gen.writeObjectFieldStart(value.getId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
registries:
- registry.acme.org:
enabled: false
- "registry.quarkus.io"
- registry.quarkus.io
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
---
debug: true
registries:
- "registry.quarkus.io"
- registry.quarkus.io
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
---
registries:
- "registry.quarkus.io"
- "registry.other.org"
- registry.quarkus.io
- registry.other.org

0 comments on commit 5f1090c

Please sign in to comment.