Skip to content

Commit

Permalink
[env-manager] enable to use env with an inlinerc file content
Browse files Browse the repository at this point in the history
  • Loading branch information
rmannibucau committed Feb 9, 2024
1 parent 538d6e8 commit 3541027
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public Delete(final Conf conf,
@Override
public void run() {
try {
registry.findByToolVersionAndProvider(conf.tool(), conf.version(), conf.provider(), false)
registry.findByToolVersionAndProvider(conf.tool(), conf.version(), conf.provider(), false, false)
.thenAccept(matched -> {
matched.provider().delete(conf.tool(), matched.version().identifier());
logger.info(() -> "Deleted " + messageHelper.formatToolNameAndVersion(matched.candidate(), conf.tool(), matched.version().version()));
Expand Down
114 changes: 74 additions & 40 deletions env-manager/src/main/java/io/yupiik/dev/command/Env.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,13 @@
import io.yupiik.fusion.framework.build.api.configuration.Property;
import io.yupiik.fusion.framework.build.api.configuration.RootConfiguration;

import java.io.IOException;
import java.io.StringReader;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.function.Predicate;
import java.util.logging.Handler;
Expand Down Expand Up @@ -67,7 +71,15 @@ public void run() {
}

final var tools = rc.loadPropertiesFrom(conf.rc(), conf.defaultRc());
if (tools == null || tools.isEmpty()) { // nothing to do
final var inlineProps = new Properties();
if (conf.inlineRc() != null && !conf.inlineRc().isBlank()) {
try (final var reader = new StringReader(conf.inlineRc().replace("\\n", "\n"))) {
inlineProps.load(reader);
} catch (final IOException e) {
throw new IllegalStateException(e);
}
}
if (tools == null || (inlineProps.isEmpty() && tools.global().isEmpty() && tools.local().isEmpty())) { // nothing to do
return;
}

Expand Down Expand Up @@ -103,45 +115,8 @@ public void close() throws SecurityException {
logger.addHandler(tempHandler);

try {
rc.toToolProperties(tools).thenAccept(resolved -> {
final var toolVars = resolved.stream()
.flatMap(e -> Stream.of(
export + e.properties().envPathVarName() + "=" + quote + quoted(e.path()) + quote + ";",
export + e.properties().envVersionVarName() + "=" + quote + e.properties().version() + quote + ";"))
.sorted()
.collect(joining("\n", "", "\n"));

final var pathBase = ofNullable(System.getenv("YEM_ORIGINAL_PATH"))
.or(() -> ofNullable(System.getenv(pathName)))
.orElse("");
final var pathsSeparator = hasTerm ? ":" : pathSeparator;
final var pathVars = resolved.stream().map(RcService.MatchedPath::properties).anyMatch(RcService.ToolProperties::addToPath) ?
export + "YEM_ORIGINAL_PATH=" + quote + pathBase + quote + ";\n" +
export + pathName + "=" + quote + resolved.stream()
.filter(r -> r.properties().addToPath())
.map(r -> quoted(rc.toBin(r.path())))
.collect(joining(pathsSeparator, "", pathsSeparator)) + pathVar + quote + ";\n" :
"";
final var home = System.getProperty("user.home", "");
final var echos = Boolean.parseBoolean(tools.getProperty("echo", "true")) ?
resolved.stream()
// don't log too much, if it does not change, don't re-log it
.filter(Predicate.not(it -> Objects.equals(it.path().toString(), System.getenv(it.properties().envPathVarName()))))
.map(e -> "echo \"[yem] Resolved " + messageHelper.formatToolNameAndVersion(
e.candidate(), e.properties().toolName(), e.properties().version()) + " to '" +
e.path().toString().replace(home, "~") + "'\";")
.collect(joining("\n", "", "\n")) :
"";

final var script = messages.stream().map(m -> "echo \"[yem] " + m.replace("\"", "\"\\\"\"") + "\";").collect(joining("\n", "", "\n\n")) +
pathVars + toolVars + echos + "\n" +
comment + "To load a .yemrc configuration run:\n" +
comment + "[ -f .yemrc ] && eval $(yem env --env-file .yemrc)\n" +
comment + "\n" +
comment + "See https://www.yupiik.io/tools-maven-plugin/yem.html#autopath for details\n" +
"\n";
System.out.println(script);
})
rc.match(inlineProps, tools.local(), tools.global())
.thenAccept(resolved -> createScript(resolved, export, quote, pathName, hasTerm, pathVar, tools, messages, comment))
.toCompletableFuture()
.get();
} catch (final InterruptedException e) {
Expand All @@ -155,6 +130,64 @@ public void close() throws SecurityException {
}
}

private void createScript(final List<RcService.MatchedPath> rawResolved,
final String export,
final String quote, final String pathName, final boolean hasTerm, final String pathVar,
final RcService.Props tools, final List<String> messages, final String comment) {
final var resolved = rawResolved.stream()
// ignore manually overriden vars
.filter(it -> {
final var overridenEnvVar = rc.toOverridenEnvVar(it.properties());
if (System.getenv(overridenEnvVar) != null) {
logger.finest(() -> "Ignoring '" + it.properties().envPathVarName() + "' because '" + overridenEnvVar + "' is defined");
return false;
}
return true;
})
.toList();
final var toolVars = resolved.stream()
.flatMap(e -> Stream.concat(
Stream.of(
export + e.properties().envPathVarName() + "=" + quote + quoted(e.path()) + quote + ";",
export + e.properties().envVersionVarName() + "=" + quote + e.properties().version() + quote + ";"),
e.properties().index() == 0 /* custom override */ ?
Stream.of(export + rc.toOverridenEnvVar(e.properties()) + "=" + quote + e.properties().version() + quote + ";") :
Stream.empty()))
.sorted()
.collect(joining("\n", "", "\n"));

final var pathBase = ofNullable(System.getenv("YEM_ORIGINAL_PATH"))
.or(() -> ofNullable(System.getenv(pathName)))
.orElse("");
final var pathsSeparator = hasTerm ? ":" : pathSeparator;
final var pathVars = resolved.stream().map(RcService.MatchedPath::properties).anyMatch(RcService.ToolProperties::addToPath) ?
export + "YEM_ORIGINAL_PATH=" + quote + pathBase + quote + ";\n" +
export + pathName + "=" + quote + resolved.stream()
.filter(r -> r.properties().addToPath())
.map(r -> quoted(rc.toBin(r.path())))
.collect(joining(pathsSeparator, "", pathsSeparator)) + pathVar + quote + ";\n" :
"";
final var home = System.getProperty("user.home", "");
final var echos = Boolean.parseBoolean(tools.global().getProperty("echo", tools.local().getProperty("echo", "true"))) ?
resolved.stream()
// don't log too much, if it does not change, don't re-log it
.filter(Predicate.not(it -> Objects.equals(it.path().toString(), System.getenv(it.properties().envPathVarName()))))
.map(e -> "echo \"[yem] Resolved " + messageHelper.formatToolNameAndVersion(
e.candidate(), e.properties().toolName(), e.properties().version()) + " to '" +
e.path().toString().replace(home, "~") + "'\";")
.collect(joining("\n", "", "\n")) :
"";

final var script = messages.stream().map(m -> "echo \"[yem] " + m.replace("\"", "\"\\\"\"") + "\";").collect(joining("\n", "", "\n\n")) +
pathVars + toolVars + echos + "\n" +
comment + "To load a .yemrc configuration run:\n" +
comment + "[ -f .yemrc ] && eval $(yem env --env-file .yemrc)\n" +
comment + "\n" +
comment + "See https://www.yupiik.io/tools-maven-plugin/yem.html#autopath for details\n" +
"\n";
System.out.println(script);
}

private String quoted(final Path path) {
return path
.toAbsolutePath()
Expand All @@ -181,6 +214,7 @@ private void resetOriginalPath(final String export, final String pathName, final
public record Conf(
@Property(documentation = "By default if `YEM_ORIGINAL_PATH` exists in the environment variables it is used as `PATH` base to not keep appending path to the `PATH` indefinively. This can be disabled setting this property to `false`", defaultValue = "false") boolean skipReset,
@Property(documentation = "Should `~/.yupiik/yem/rc` be ignored or not. If present it defines default versions and uses the same syntax than `yemrc`.", defaultValue = "System.getProperty(\"user.home\") + \"/.yupiik/yem/rc\"") String defaultRc,
@Property(documentation = "Enables to set inline a rc file, ex: `eval $(yem env --inlineRc 'java.version=17.0.9')`, you can use EOL too: `eval $(yem env --inlineRc 'java.version=17.\\njava.relaxed = true')`. Note that to persist the change even if you automatically switch from the global `yemrc` file the context, we set `YEM_$TOOLPATHVARNAME_OVERRIDEN` environment variable. To reset the value to the global configuration just `unset` this variable (ex: `unset YEM_JAVA_PATH_OVERRIDEN`)") String inlineRc,
@Property(documentation = "Env file location to read to generate the script. Note that `auto` will try to pick `.yemrc` and if not there will use `.sdkmanrc` if present.", defaultValue = "\"auto\"") String rc) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public Install(final Conf conf,
@Override
public void run() {
try {
registry.findByToolVersionAndProvider(conf.tool(), conf.version(), conf.provider(), conf.relaxed())
registry.findByToolVersionAndProvider(conf.tool(), conf.version(), conf.provider(), conf.relaxed(), true)
.thenCompose(matched -> matched.provider()
.install(conf.tool(), matched.version().identifier(), Boolean.parseBoolean(System.getenv("CI")) ? NOOP : this::onProgress)
.thenAccept(result -> logger.info(() -> "Installed " + messageHelper.formatToolNameAndVersion(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public Resolve(final Conf conf,
@Override
public void run() {
try {
registry.findByToolVersionAndProvider(conf.tool(), conf.version(), conf.provider(), false)
registry.findByToolVersionAndProvider(conf.tool(), conf.version(), conf.provider(), false, false)
.thenAccept(matched -> {
final var resolved = matched.provider().resolve(conf.tool(), matched.version().identifier())
.orElseThrow(() -> new IllegalArgumentException("No matching instance for " + conf.tool() + "@" + conf.version() + ", ensure to install it before resolving it."));
Expand Down
5 changes: 3 additions & 2 deletions env-manager/src/main/java/io/yupiik/dev/command/Run.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public Run(final Conf conf, final RcService rc, final Os os, final Args args) {
public void run() {
final var tools = rc.loadPropertiesFrom(conf.rc(), conf.defaultRc());
try {
rc.toToolProperties(tools).thenAccept(resolved -> {
rc.match(tools.local(), tools.global()).thenAccept(resolved -> {
final int idx = args.args().indexOf("--");
final var command = new ArrayList<String>(8);
if (idx > 0) {
Expand All @@ -70,7 +70,8 @@ public void run() {
}

if (!command.isEmpty()) { // handle aliasing
final var alias = tools.getProperty(command.get(0) + ".alias");
final var aliasKey = command.get(0) + ".alias";
final var alias = tools.local().getProperty(aliasKey, tools.global().getProperty(aliasKey));
if (alias != null) {
command.remove(0);
command.addAll(0, parseArgs(alias));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ public List<Provider> providers() {
}

public CompletionStage<MatchedVersion> findByToolVersionAndProvider(final String tool, final String version, final String provider,
final boolean relaxed) {
return tryFindByToolVersionAndProvider(tool, version, provider, relaxed, new Cache(new ConcurrentHashMap<>(), new ConcurrentHashMap<>()))
final boolean relaxed, final boolean canBeRemote) {
return tryFindByToolVersionAndProvider(tool, version, provider, relaxed, canBeRemote, new Cache(new ConcurrentHashMap<>(), new ConcurrentHashMap<>()))
.thenApply(found -> found.orElseThrow(() -> new IllegalArgumentException(
"No provider for tool " + tool + "@" + version + "', available tools:\n" +
providers().stream()
Expand Down Expand Up @@ -103,7 +103,7 @@ public CompletionStage<MatchedVersion> findByToolVersionAndProvider(final String

public CompletionStage<Optional<MatchedVersion>> tryFindByToolVersionAndProvider(
final String tool, final String version, final String provider, final boolean relaxed,
final Cache cache) {
final boolean testRemote, final Cache cache) {
final var result = new CompletableFuture<Optional<MatchedVersion>>();
final var promises = providers().stream()
.filter(it -> provider == null ||
Expand All @@ -122,18 +122,20 @@ public CompletionStage<Optional<MatchedVersion>> tryFindByToolVersionAndProvider
.findFirst()
.map(Optional::of)
.map(CompletableFuture::completedFuture)
.orElseGet(() -> findRemoteVersions(tool, cache, it)
.thenApply(all -> all.stream()
.filter(v -> matchVersion(v, version, relaxed))
.findFirst()
.map(v -> new MatchedVersion(
it,
candidates.stream()
.filter(c -> Objects.equals(c.tool(), tool))
.findFirst()
.orElse(null),
v)))
.toCompletableFuture()));
.orElseGet(() -> testRemote ?
findRemoteVersions(tool, cache, it)
.thenApply(all -> all.stream()
.filter(v -> matchVersion(v, version, relaxed))
.findFirst()
.map(v -> new MatchedVersion(
it,
candidates.stream()
.filter(c -> Objects.equals(c.tool(), tool))
.findFirst()
.orElse(null),
v)))
.toCompletableFuture() :
completedFuture(empty())));
}
return completedFuture(Optional.empty());
}))
Expand Down

0 comments on commit 3541027

Please sign in to comment.