-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #14309 from radcortez/config-console
Improve Config Console
- Loading branch information
Showing
5 changed files
with
207 additions
and
133 deletions.
There are no files selected for viewing
183 changes: 54 additions & 129 deletions
183
...src/main/java/io/quarkus/vertx/http/deployment/devmode/console/ConfigEditorProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,171 +1,96 @@ | ||
package io.quarkus.vertx.http.deployment.devmode.console; | ||
|
||
import static io.quarkus.runtime.LaunchMode.DEVELOPMENT; | ||
|
||
import java.io.BufferedWriter; | ||
import java.io.InputStream; | ||
import java.io.OutputStream; | ||
import java.nio.charset.StandardCharsets; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.nio.file.StandardOpenOption; | ||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.Iterator; | ||
import java.util.List; | ||
import java.util.Properties; | ||
|
||
import org.eclipse.microprofile.config.Config; | ||
import org.eclipse.microprofile.config.ConfigProvider; | ||
|
||
import io.quarkus.arc.runtime.ConfigRecorder; | ||
import io.quarkus.deployment.IsDevelopment; | ||
import io.quarkus.deployment.annotations.BuildStep; | ||
import io.quarkus.deployment.annotations.ExecutionTime; | ||
import io.quarkus.deployment.annotations.Record; | ||
import io.quarkus.deployment.builditem.ConfigDescriptionBuildItem; | ||
import io.quarkus.dev.console.DevConsoleManager; | ||
import io.quarkus.devconsole.runtime.spi.DevConsolePostHandler; | ||
import io.quarkus.devconsole.spi.DevConsoleRouteBuildItem; | ||
import io.quarkus.devconsole.spi.DevConsoleTemplateInfoBuildItem; | ||
import io.quarkus.devconsole.spi.DevConsoleRuntimeTemplateInfoBuildItem; | ||
import io.quarkus.runtime.configuration.ProfileManager; | ||
import io.quarkus.vertx.http.runtime.devmode.ConfigDescription; | ||
import io.quarkus.vertx.http.runtime.devmode.ConfigDescriptionsSupplier; | ||
import io.vertx.core.MultiMap; | ||
import io.vertx.ext.web.RoutingContext; | ||
|
||
public class ConfigEditorProcessor { | ||
|
||
@BuildStep | ||
DevConsoleTemplateInfoBuildItem config(List<ConfigDescriptionBuildItem> config) throws Exception { | ||
List<CurrentConfig> configs = new ArrayList<>(); | ||
Config current = ConfigProvider.getConfig(); | ||
|
||
Properties appProperties = new Properties(); | ||
Path appProps = null; | ||
for (Path i : DevConsoleManager.getHotReplacementContext().getResourcesDir()) { | ||
Path app = i.resolve("application.properties"); | ||
if (Files.exists(app)) { | ||
appProps = app; | ||
break; | ||
} | ||
} | ||
if (appProps != null) { | ||
try (InputStream in = Files.newInputStream(appProps)) { | ||
appProperties.load(in); | ||
} | ||
} | ||
|
||
for (ConfigDescriptionBuildItem i : config) { | ||
if (i.getPropertyName().contains("*")) { | ||
continue; //TODO: complex properties | ||
} | ||
configs.add(new CurrentConfig(i.getPropertyName(), i.getDocs(), i.getDefaultValue(), | ||
current.getOptionalValue(i.getPropertyName(), String.class).orElse(null), | ||
appProperties.getProperty(i.getPropertyName()))); | ||
@BuildStep(onlyIf = IsDevelopment.class) | ||
@Record(ExecutionTime.RUNTIME_INIT) | ||
public DevConsoleRuntimeTemplateInfoBuildItem config(ConfigRecorder recorder, | ||
List<ConfigDescriptionBuildItem> configDescriptionBuildItems) { | ||
List<ConfigDescription> configDescriptions = new ArrayList<>(); | ||
for (ConfigDescriptionBuildItem item : configDescriptionBuildItems) { | ||
configDescriptions.add( | ||
new ConfigDescription(item.getPropertyName(), item.getDocs(), item.getDefaultValue())); | ||
} | ||
Collections.sort(configs); | ||
|
||
return new DevConsoleTemplateInfoBuildItem("config", configs); | ||
return new DevConsoleRuntimeTemplateInfoBuildItem("config", new ConfigDescriptionsSupplier(configDescriptions)); | ||
} | ||
|
||
@BuildStep | ||
DevConsoleRouteBuildItem handlePost() { | ||
return new DevConsoleRouteBuildItem("config", "POST", new DevConsolePostHandler() { | ||
@Override | ||
protected void handlePost(RoutingContext event, MultiMap form) throws Exception { | ||
String key = event.request().getFormAttribute("name"); | ||
String name = event.request().getFormAttribute("name"); | ||
String value = event.request().getFormAttribute("value"); | ||
|
||
Properties appProperties = new Properties(); | ||
Path appProps = null; | ||
for (Path i : DevConsoleManager.getHotReplacementContext().getResourcesDir()) { | ||
Path app = i.resolve("application.properties"); | ||
if (Files.exists(app)) { | ||
appProps = app; | ||
List<Path> resourcesDir = DevConsoleManager.getHotReplacementContext().getResourcesDir(); | ||
if (resourcesDir.isEmpty()) { | ||
throw new IllegalStateException("Unable to manage configurations - no resource directory found"); | ||
} | ||
|
||
// In the current project only | ||
Path path = resourcesDir.get(0); | ||
Path configPath = path.resolve("application.properties"); | ||
if (!Files.exists(configPath)) { | ||
configPath = Files.createFile(path.resolve("application.properties")); | ||
} | ||
|
||
String profile = ProfileManager.getActiveProfile(); | ||
name = !profile.equals(DEVELOPMENT.getDefaultProfile()) ? "%" + profile + "." + name : name; | ||
List<String> lines = Files.readAllLines(configPath); | ||
int nameLine = -1; | ||
for (int i = 0, linesSize = lines.size(); i < linesSize; i++) { | ||
final String line = lines.get(i); | ||
if (line.startsWith(name + "=")) { | ||
nameLine = i; | ||
break; | ||
} | ||
} | ||
boolean present = false; | ||
if (appProps != null) { | ||
try (InputStream in = Files.newInputStream(appProps)) { | ||
appProperties.load(in); | ||
present = appProperties.containsKey(key); | ||
|
||
if (nameLine != -1) { | ||
if (value.isEmpty()) { | ||
lines.remove(nameLine); | ||
} else { | ||
lines.set(nameLine, name + "=" + value); | ||
} | ||
} else { | ||
// If there is no application.properties file then create a new one in the first module | ||
List<Path> resourcesDir = DevConsoleManager.getHotReplacementContext().getResourcesDir(); | ||
if (resourcesDir.isEmpty()) { | ||
throw new IllegalStateException( | ||
"Unable to create application.properties - no resource directory found"); | ||
if (!value.isEmpty()) { | ||
lines.add(name + "=" + value); | ||
} | ||
appProps = Files.createFile(resourcesDir.get(0).resolve("application.properties")); | ||
} | ||
if (!present) { | ||
try (OutputStream out = Files.newOutputStream(appProps, StandardOpenOption.APPEND)) { | ||
out.write(("\n" + key + "=" + value).getBytes(StandardCharsets.UTF_8)); //TODO: escpaing | ||
} | ||
} else { | ||
List<String> lines = Files.readAllLines(appProps); | ||
Iterator<String> it = lines.iterator(); | ||
while (it.hasNext()) { | ||
String val = it.next(); | ||
if (val.startsWith(key + "=")) { | ||
it.remove(); | ||
} | ||
} | ||
lines.add(key + "=" + value); | ||
try (BufferedWriter writer = Files.newBufferedWriter(appProps)) { | ||
for (String i : lines) { | ||
writer.write(i); | ||
writer.newLine(); | ||
} | ||
|
||
try (BufferedWriter writer = Files.newBufferedWriter(configPath)) { | ||
for (String i : lines) { | ||
writer.write(i); | ||
writer.newLine(); | ||
} | ||
} | ||
|
||
DevConsoleManager.getHotReplacementContext().doScan(true); | ||
flashMessage(event, "Configuration updated"); | ||
} | ||
}); | ||
} | ||
|
||
public static class CurrentConfig implements Comparable<CurrentConfig> { | ||
private final String propertyName; | ||
private final String description; | ||
private final String defaultValue; | ||
private final String currentValue; | ||
private final String appPropertiesValue; | ||
|
||
public CurrentConfig(String propertyName, String description, String defaultValue, String currentValue, | ||
String appPropertiesValue) { | ||
this.propertyName = propertyName; | ||
this.description = description; | ||
this.defaultValue = defaultValue; | ||
this.currentValue = currentValue; | ||
this.appPropertiesValue = appPropertiesValue; | ||
} | ||
|
||
public String getPropertyName() { | ||
return propertyName; | ||
} | ||
|
||
public String getDescription() { | ||
return description; | ||
} | ||
|
||
public String getDefaultValue() { | ||
return defaultValue; | ||
} | ||
|
||
public String getCurrentValue() { | ||
return currentValue; | ||
} | ||
|
||
public String getAppPropertiesValue() { | ||
return appPropertiesValue; | ||
} | ||
|
||
@Override | ||
public int compareTo(CurrentConfig o) { | ||
if (appPropertiesValue == null && o.appPropertiesValue != null) { | ||
return 1; | ||
} | ||
if (appPropertiesValue != null && o.appPropertiesValue == null) { | ||
return -1; | ||
} | ||
|
||
return propertyName.compareTo(o.propertyName); | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
...x-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/devmode/ConfigDescription.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package io.quarkus.vertx.http.runtime.devmode; | ||
|
||
import io.smallrye.config.ConfigValue; | ||
|
||
public class ConfigDescription implements Comparable<ConfigDescription> { | ||
private String name; | ||
private String description; | ||
private String defaultValue; | ||
private ConfigValue configValue; | ||
|
||
public ConfigDescription() { | ||
} | ||
|
||
public ConfigDescription(final String name, final String description, final String defaultValue) { | ||
this.name = name; | ||
this.description = description; | ||
this.defaultValue = defaultValue; | ||
} | ||
|
||
public ConfigDescription( | ||
final String name, | ||
final String description, | ||
final String defaultValue, | ||
final ConfigValue configValue) { | ||
this.name = name; | ||
this.description = description; | ||
this.defaultValue = defaultValue; | ||
this.configValue = configValue; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public void setName(final String name) { | ||
this.name = name; | ||
} | ||
|
||
public String getDescription() { | ||
return description; | ||
} | ||
|
||
public void setDescription(final String description) { | ||
this.description = description; | ||
} | ||
|
||
public String getDefaultValue() { | ||
return defaultValue; | ||
} | ||
|
||
public void setDefaultValue(final String defaultValue) { | ||
this.defaultValue = defaultValue; | ||
} | ||
|
||
public ConfigValue getConfigValue() { | ||
return configValue; | ||
} | ||
|
||
public void setConfigValue(final ConfigValue configValue) { | ||
this.configValue = configValue; | ||
} | ||
|
||
@Override | ||
public int compareTo(ConfigDescription o) { | ||
int ordinal = Integer.compare(o.configValue.getConfigSourceOrdinal(), this.configValue.getConfigSourceOrdinal()); | ||
if (ordinal == 0) { | ||
return this.configValue.getName().compareTo(o.configValue.getName()); | ||
} | ||
return ordinal; | ||
} | ||
} |
Oops, something went wrong.