Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MNG-8587] mvnsh navigation #2117

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cling.invoker;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.function.Supplier;

import org.apache.maven.api.annotations.Nonnull;

import static java.util.Objects.requireNonNull;

/**
* A thin wrapper for a {@link Path} that serves as "current working directory" value. Hence, this class
* is mutable (as CWD may be changed), but allows transition only to existing directories.
*/
public final class CWD implements Supplier<Path> {
/**
* Creates instance out of {@link Path}.
*/
public static CWD create(Path path) {
return new CWD(Utils.getCanonicalPath(path));
}

private Path directory;

private CWD(Path directory) {
this.directory = directory;
}

@Nonnull
@Override
public Path get() {
return directory;
}

/**
* Resolves against current cwd, resulting path is normalized.
*
* @throws NullPointerException if {@code seg} is {@code null}.
*/
@Nonnull
public Path resolve(String seg) {
requireNonNull(seg, "seg");
return directory.resolve(seg).normalize();
}

/**
* Changes current cwd, if the new path is existing directory.
*
* @throws NullPointerException if {@code seg} is {@code null}.
* @throws IllegalArgumentException if {@code seg} leads to non-existent directory.
*/
public void change(String seg) {
requireNonNull(seg, "seg");
Path newCwd = directory.resolve(seg);
if (Files.isDirectory(newCwd)) {
this.directory = newCwd;
} else {
throw new IllegalArgumentException("Directory '" + directory + "' does not exist");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;

import org.apache.maven.api.ProtoSession;
import org.apache.maven.api.cli.InvokerException;
Expand All @@ -46,9 +45,9 @@
@SuppressWarnings("VisibilityModifier")
public class LookupContext implements AutoCloseable {
public final InvokerRequest invokerRequest;
public final Function<String, Path> cwdResolver;
public final Function<String, Path> installationResolver;
public final Function<String, Path> userResolver;
public final CWD cwd;
public final Path installationDirectory;
public final Path userDirectory;
public final boolean containerCapsuleManaged;

public LookupContext(InvokerRequest invokerRequest) {
Expand All @@ -57,11 +56,9 @@ public LookupContext(InvokerRequest invokerRequest) {

public LookupContext(InvokerRequest invokerRequest, boolean containerCapsuleManaged) {
this.invokerRequest = requireNonNull(invokerRequest);
this.cwdResolver = s -> invokerRequest.cwd().resolve(s).normalize().toAbsolutePath();
this.installationResolver = s ->
invokerRequest.installationDirectory().resolve(s).normalize().toAbsolutePath();
this.userResolver =
s -> invokerRequest.userHomeDirectory().resolve(s).normalize().toAbsolutePath();
this.cwd = CWD.create(invokerRequest.cwd());
this.installationDirectory = Utils.getCanonicalPath(invokerRequest.installationDirectory());
this.userDirectory = Utils.getCanonicalPath(invokerRequest.userHomeDirectory());
this.containerCapsuleManaged = containerCapsuleManaged;
this.logger = invokerRequest.parserRequest().logger();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ protected Consumer<String> determineWriter(C context) {
protected Consumer<String> doDetermineWriter(C context) {
Options options = context.invokerRequest.options();
if (options.logFile().isPresent()) {
Path logFile = context.cwdResolver.apply(options.logFile().get());
Path logFile = context.cwd.resolve(options.logFile().get());
try {
PrintWriter printWriter = new PrintWriter(Files.newBufferedWriter(logFile), true);
context.closeables.add(printWriter);
Expand Down Expand Up @@ -507,10 +507,9 @@ protected void lookup(C context) throws Exception {
}

protected void init(C context) throws Exception {
InvokerRequest invokerRequest = context.invokerRequest;
Map<String, Object> data = new HashMap<>();
data.put("plexus", context.lookup.lookup(PlexusContainer.class));
data.put("workingDirectory", invokerRequest.cwd().toString());
data.put("workingDirectory", context.cwd.get().toString());
data.put("systemProperties", toProperties(context.protoSession.getSystemProperties()));
data.put("userProperties", toProperties(context.protoSession.getUserProperties()));
data.put("versionProperties", CLIReportingUtils.getBuildProperties());
Expand Down Expand Up @@ -567,7 +566,7 @@ protected Runnable settings(C context, boolean emitSettingsWarnings, SettingsBui
Path userSettingsFile = null;
if (mavenOptions.altUserSettings().isPresent()) {
userSettingsFile =
context.cwdResolver.apply(mavenOptions.altUserSettings().get());
context.cwd.resolve(mavenOptions.altUserSettings().get());

if (!Files.isRegularFile(userSettingsFile)) {
throw new FileNotFoundException("The specified user settings file does not exist: " + userSettingsFile);
Expand All @@ -576,14 +575,15 @@ protected Runnable settings(C context, boolean emitSettingsWarnings, SettingsBui
String userSettingsFileStr =
context.protoSession.getUserProperties().get(Constants.MAVEN_USER_SETTINGS);
if (userSettingsFileStr != null) {
userSettingsFile = context.userResolver.apply(userSettingsFileStr);
userSettingsFile =
context.userDirectory.resolve(userSettingsFileStr).normalize();
}
}

Path projectSettingsFile = null;
if (mavenOptions.altProjectSettings().isPresent()) {
projectSettingsFile =
context.cwdResolver.apply(mavenOptions.altProjectSettings().get());
context.cwd.resolve(mavenOptions.altProjectSettings().get());

if (!Files.isRegularFile(projectSettingsFile)) {
throw new FileNotFoundException(
Expand All @@ -593,14 +593,14 @@ protected Runnable settings(C context, boolean emitSettingsWarnings, SettingsBui
String projectSettingsFileStr =
context.protoSession.getUserProperties().get(Constants.MAVEN_PROJECT_SETTINGS);
if (projectSettingsFileStr != null) {
projectSettingsFile = context.cwdResolver.apply(projectSettingsFileStr);
projectSettingsFile = context.cwd.resolve(projectSettingsFileStr);
}
}

Path installationSettingsFile = null;
if (mavenOptions.altInstallationSettings().isPresent()) {
installationSettingsFile = context.cwdResolver.apply(
mavenOptions.altInstallationSettings().get());
installationSettingsFile =
context.cwd.resolve(mavenOptions.altInstallationSettings().get());

if (!Files.isRegularFile(installationSettingsFile)) {
throw new FileNotFoundException(
Expand All @@ -610,7 +610,9 @@ protected Runnable settings(C context, boolean emitSettingsWarnings, SettingsBui
String installationSettingsFileStr =
context.protoSession.getUserProperties().get(Constants.MAVEN_INSTALLATION_SETTINGS);
if (installationSettingsFileStr != null) {
installationSettingsFile = context.installationResolver.apply(installationSettingsFileStr);
installationSettingsFile = context.installationDirectory
.resolve(installationSettingsFileStr)
.normalize();
}
}

Expand Down Expand Up @@ -716,17 +718,18 @@ protected Path localRepositoryPath(C context) {
}
}
if (userDefinedLocalRepo != null) {
return context.cwdResolver.apply(userDefinedLocalRepo);
return context.cwd.resolve(userDefinedLocalRepo);
}
// settings
userDefinedLocalRepo = context.effectiveSettings.getLocalRepository();
if (userDefinedLocalRepo != null && !userDefinedLocalRepo.isEmpty()) {
return context.userResolver.apply(userDefinedLocalRepo);
return context.userDirectory.resolve(userDefinedLocalRepo).normalize();
}
// defaults
return context.userResolver
.apply(context.protoSession.getUserProperties().get(Constants.MAVEN_USER_CONF))
.resolve("repository");
return context.userDirectory
.resolve(context.protoSession.getUserProperties().get(Constants.MAVEN_USER_CONF))
.resolve("repository")
.normalize();
}

protected void populateRequest(C context, Lookup lookup, MavenExecutionRequest request) throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ protected List<Path> parseExtClasspath(C context) throws Exception {
ArrayList<Path> jars = new ArrayList<>();
if (extClassPath != null && !extClassPath.isEmpty()) {
for (String jar : extClassPath.split(File.pathSeparator)) {
Path file = context.cwdResolver.apply(jar);
Path file = context.cwd.resolve(jar);
context.logger.debug(" included '" + file + "'");
jars.add(file);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ protected void postCommands(MavenContext context) throws Exception {
protected void toolchains(MavenContext context, MavenExecutionRequest request) throws Exception {
Path userToolchainsFile = null;
if (context.invokerRequest.options().altUserToolchains().isPresent()) {
userToolchainsFile = context.cwdResolver.apply(
userToolchainsFile = context.cwd.resolve(
context.invokerRequest.options().altUserToolchains().get());

if (!Files.isRegularFile(userToolchainsFile)) {
Expand All @@ -153,13 +153,13 @@ protected void toolchains(MavenContext context, MavenExecutionRequest request) t
String userToolchainsFileStr =
context.protoSession.getUserProperties().get(Constants.MAVEN_USER_TOOLCHAINS);
if (userToolchainsFileStr != null) {
userToolchainsFile = context.cwdResolver.apply(userToolchainsFileStr);
userToolchainsFile = context.cwd.resolve(userToolchainsFileStr);
}
}

Path installationToolchainsFile = null;
if (context.invokerRequest.options().altInstallationToolchains().isPresent()) {
installationToolchainsFile = context.cwdResolver.apply(
installationToolchainsFile = context.cwd.resolve(
context.invokerRequest.options().altInstallationToolchains().get());

if (!Files.isRegularFile(installationToolchainsFile)) {
Expand All @@ -170,7 +170,9 @@ protected void toolchains(MavenContext context, MavenExecutionRequest request) t
String installationToolchainsFileStr =
context.protoSession.getUserProperties().get(Constants.MAVEN_INSTALLATION_TOOLCHAINS);
if (installationToolchainsFileStr != null) {
installationToolchainsFile = context.cwdResolver.apply(installationToolchainsFileStr);
installationToolchainsFile = context.installationDirectory
.resolve(installationToolchainsFileStr)
.normalize();
}
}

Expand Down Expand Up @@ -311,10 +313,10 @@ protected void populateRequest(MavenContext context, Lookup lookup, MavenExecuti
}

protected Path determinePom(MavenContext context, Lookup lookup) {
Path current = context.invokerRequest.cwd();
Path current = context.cwd.get();
MavenOptions options = (MavenOptions) context.invokerRequest.options();
if (options.alternatePomFile().isPresent()) {
current = context.cwdResolver.apply(options.alternatePomFile().get());
current = context.cwd.resolve(options.alternatePomFile().get());
}
ModelProcessor modelProcessor =
lookup.lookupOptional(ModelProcessor.class).orElse(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
import org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder;
import org.jline.reader.MaskingCallback;
import org.jline.reader.Parser;
import org.jline.reader.Reference;
import org.jline.reader.UserInterruptException;
import org.jline.reader.impl.DefaultHighlighter;
Expand Down Expand Up @@ -67,9 +66,8 @@ protected LookupContext createContext(InvokerRequest invokerRequest) {
@Override
protected int execute(LookupContext context) throws Exception {
// set up JLine built-in commands
ConfigurationPath configPath =
new ConfigurationPath(context.invokerRequest.cwd(), context.invokerRequest.cwd());
Builtins builtins = new Builtins(context.invokerRequest::cwd, configPath, null);
ConfigurationPath configPath = new ConfigurationPath(context.cwd.get(), context.cwd.get());
Builtins builtins = new Builtins(context.cwd, configPath, null);
builtins.rename(Builtins.Command.TTOP, "top");
builtins.alias("zle", "widget");
builtins.alias("bindkey", "keymap");
Expand All @@ -84,7 +82,8 @@ protected int execute(LookupContext context) throws Exception {
holder.addCommandRegistry(entry.getValue().createShellCommandRegistry(context));
}

Parser parser = new DefaultParser();
DefaultParser parser = new DefaultParser();
parser.setRegexCommand("[:]{0,1}[a-zA-Z!]{1,}\\S*"); // change default regex to support shell commands

String banner =
"""
Expand All @@ -104,10 +103,15 @@ protected int execute(LookupContext context) throws Exception {

try (holder) {
SimpleSystemRegistryImpl systemRegistry =
new SimpleSystemRegistryImpl(parser, context.terminal, context.invokerRequest::cwd, configPath);
new SimpleSystemRegistryImpl(parser, context.terminal, context.cwd, configPath) {
@Override
public boolean isCommandOrScript(String command) {
return command.startsWith("!") || super.isCommandOrScript(command);
}
};
systemRegistry.setCommandRegistries(holder.getCommandRegistries());

Path history = context.userResolver.apply(".mvnsh_history");
Path history = context.userDirectory.resolve(".mvnsh_history");
LineReader reader = LineReaderBuilder.builder()
.terminal(context.terminal)
.history(new DefaultHistory())
Expand All @@ -127,15 +131,16 @@ protected int execute(LookupContext context) throws Exception {
KeyMap<Binding> keyMap = reader.getKeyMaps().get("main");
keyMap.bind(new Reference("tailtip-toggle"), KeyMap.alt("s"));

String prompt = "mvnsh> ";
String rightPrompt = null;

// start the shell and process input until the user quits with Ctrl-D
String line;
while (true) {
try {
systemRegistry.cleanUp();
line = reader.readLine(prompt, rightPrompt, (MaskingCallback) null, null);
line = reader.readLine(
context.cwd.get().getFileName().toString() + " mvnsh> ",
null,
(MaskingCallback) null,
null);
systemRegistry.execute(line);
} catch (UserInterruptException e) {
// Ignore
Expand Down
Loading