mirror of
https://github.com/apache/nifi.git
synced 2025-02-28 06:29:25 +00:00
NIFI-11048 This closes #6858. Added FileNameCompleter to avoid style parsing failures
- Added StandardFileNameCompleter with static LS_COLORS to avoid parsing environment variables in Styles.lsStyle() Signed-off-by: Joe Witt <joewitt@apache.org>
This commit is contained in:
parent
4d78ebc487
commit
a37887305c
@ -24,7 +24,7 @@
|
||||
<description>Tooling to make tls configuration easier</description>
|
||||
|
||||
<properties>
|
||||
<jline.version>3.21.0</jline.version>
|
||||
<jline.version>3.22.0</jline.version>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
|
@ -21,7 +21,7 @@ import org.apache.nifi.toolkit.cli.api.CommandGroup;
|
||||
import org.apache.nifi.toolkit.cli.impl.command.CommandOption;
|
||||
import org.apache.nifi.toolkit.cli.impl.command.session.SessionCommandGroup;
|
||||
import org.apache.nifi.toolkit.cli.impl.session.SessionVariable;
|
||||
import org.jline.builtins.Completers;
|
||||
import org.apache.nifi.toolkit.cli.impl.util.StandardFileNameCompleter;
|
||||
import org.jline.reader.Candidate;
|
||||
import org.jline.reader.Completer;
|
||||
import org.jline.reader.LineReader;
|
||||
@ -77,6 +77,8 @@ public class CLICompleter implements Completer {
|
||||
*/
|
||||
private final Map<String, List<String>> commandOptionsMap;
|
||||
|
||||
private final Completer fileNameCompleter = new StandardFileNameCompleter();
|
||||
|
||||
/**
|
||||
* Initializes the completer based on the top-level commands and command groups.
|
||||
*
|
||||
@ -185,7 +187,6 @@ public class CLICompleter implements Completer {
|
||||
final String currWord = line.word();
|
||||
final String prevWord = line.words().get(line.wordIndex() - 1);
|
||||
if (FILE_COMPLETION_VARS.contains(prevWord)) {
|
||||
final Completers.FileNameCompleter fileNameCompleter = new Completers.FileNameCompleter();
|
||||
fileNameCompleter.complete(reader, new ArgumentCompleter.ArgumentLine(currWord, currWord.length()), candidates);
|
||||
}
|
||||
}
|
||||
@ -196,7 +197,6 @@ public class CLICompleter implements Completer {
|
||||
|
||||
// determine if the word before the current is an arg that needs file completion, otherwise return all args
|
||||
if (FILE_COMPLETION_ARGS.contains(prevWord)) {
|
||||
final Completers.FileNameCompleter fileNameCompleter = new Completers.FileNameCompleter();
|
||||
fileNameCompleter.complete(reader, new ArgumentCompleter.ArgumentLine(currWord, currWord.length()), candidates);
|
||||
} else {
|
||||
final List<String> options = commandOptionsMap.get(secondLevel);
|
||||
|
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.nifi.toolkit.cli.impl.util;
|
||||
|
||||
import org.jline.builtins.Completers;
|
||||
import org.jline.builtins.Styles;
|
||||
import org.jline.reader.Candidate;
|
||||
import org.jline.reader.LineReader;
|
||||
import org.jline.reader.ParsedLine;
|
||||
import org.jline.utils.StyleResolver;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Standard File Name Completer overriding references to Styles.lsStyle() to avoid parsing issues with LS_COLORS
|
||||
*/
|
||||
public class StandardFileNameCompleter extends Completers.FileNameCompleter {
|
||||
private static final String STANDARD_LS_COLORS = "di=1;91:ex=1;92:ln=1;96:fi=";
|
||||
|
||||
private static final String HOME_DIRECTORY_ALIAS = "~";
|
||||
|
||||
private static final String EMPTY = "";
|
||||
|
||||
private static final StyleResolver STYLE_RESOLVER = Styles.style(STANDARD_LS_COLORS);
|
||||
|
||||
/**
|
||||
* Complete file names based on JLine 3.22.0 without calling Styles.lsStyle()
|
||||
*
|
||||
* @param reader Line Reader
|
||||
* @param commandLine Parsed Command
|
||||
* @param candidates Candidates to be populated
|
||||
*/
|
||||
@Override
|
||||
public void complete(final LineReader reader, final ParsedLine commandLine, final List<Candidate> candidates) {
|
||||
assert commandLine != null;
|
||||
assert candidates != null;
|
||||
|
||||
final String buffer = commandLine.word().substring(0, commandLine.wordCursor());
|
||||
|
||||
final Path current;
|
||||
final String curBuf;
|
||||
final String sep = getSeparator(reader.isSet(LineReader.Option.USE_FORWARD_SLASH));
|
||||
final int lastSep = buffer.lastIndexOf(sep);
|
||||
try {
|
||||
if (lastSep >= 0) {
|
||||
curBuf = buffer.substring(0, lastSep + 1);
|
||||
if (curBuf.startsWith(HOME_DIRECTORY_ALIAS)) {
|
||||
if (curBuf.startsWith(HOME_DIRECTORY_ALIAS + sep)) {
|
||||
current = getUserHome().resolve(curBuf.substring(2));
|
||||
} else {
|
||||
current = getUserHome().getParent().resolve(curBuf.substring(1));
|
||||
}
|
||||
} else {
|
||||
current = getUserDir().resolve(curBuf);
|
||||
}
|
||||
} else {
|
||||
curBuf = EMPTY;
|
||||
current = getUserDir();
|
||||
}
|
||||
|
||||
try (final DirectoryStream<Path> directory = Files.newDirectoryStream(current, this::accept)) {
|
||||
directory.forEach(path -> {
|
||||
final String value = curBuf + path.getFileName().toString();
|
||||
if (Files.isDirectory(path)) {
|
||||
candidates.add(
|
||||
new Candidate(
|
||||
value + (reader.isSet(LineReader.Option.AUTO_PARAM_SLASH) ? sep : EMPTY),
|
||||
getDisplay(reader.getTerminal(), path, STYLE_RESOLVER, sep),
|
||||
null,
|
||||
null,
|
||||
reader.isSet(LineReader.Option.AUTO_REMOVE_SLASH) ? sep : null,
|
||||
null,
|
||||
false
|
||||
)
|
||||
);
|
||||
} else {
|
||||
candidates.add(
|
||||
new Candidate(
|
||||
value,
|
||||
getDisplay(reader.getTerminal(), path, STYLE_RESOLVER, sep),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (final IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
@ -40,11 +40,14 @@ import org.junit.jupiter.api.condition.DisabledOnOs;
|
||||
import org.junit.jupiter.api.condition.OS;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
@ -52,6 +55,9 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
@DisabledOnOs(OS.WINDOWS)
|
||||
public class TestCLICompleter {
|
||||
|
||||
private static final String TEST_RESOURCES_DIRECTORY = "src/test/resources";
|
||||
private static final String TEST_PROPERTIES = "test.properties";
|
||||
|
||||
private static CLICompleter completer;
|
||||
private static LineReader lineReader;
|
||||
|
||||
@ -158,21 +164,13 @@ public class TestCLICompleter {
|
||||
final String topCommand = NiFiRegistryCommandGroup.REGISTRY_COMMAND_GROUP;
|
||||
final String subCommand = "list-buckets";
|
||||
|
||||
final ParsedLine parsedLine = new TestParsedLine(Arrays.asList(topCommand, subCommand, "-p", "src/test/resources/"), 3);
|
||||
final String testResourcesDirectory = getTestResourcesDirectory();
|
||||
final ParsedLine parsedLine = new TestParsedLine(Arrays.asList(topCommand, subCommand, "-p", testResourcesDirectory), 3);
|
||||
|
||||
final List<Candidate> candidates = new ArrayList<>();
|
||||
completer.complete(lineReader, parsedLine, candidates);
|
||||
assertTrue(candidates.size() > 0);
|
||||
|
||||
boolean found = false;
|
||||
for (Candidate candidate : candidates) {
|
||||
if (candidate.value().equals("src/test/resources/test.properties")) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assertTrue(found);
|
||||
assertTestPropertiesFound(candidates);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -193,27 +191,30 @@ public class TestCLICompleter {
|
||||
final String topCommand = "session";
|
||||
final String subCommand = "set";
|
||||
|
||||
final String testResourcesDirectory = getTestResourcesDirectory();
|
||||
final ParsedLine parsedLine = new TestParsedLine(
|
||||
Arrays.asList(
|
||||
topCommand,
|
||||
subCommand,
|
||||
SessionVariable.NIFI_CLIENT_PROPS.getVariableName(),
|
||||
"src/test/resources/"),
|
||||
testResourcesDirectory),
|
||||
3);
|
||||
|
||||
final List<Candidate> candidates = new ArrayList<>();
|
||||
completer.complete(lineReader, parsedLine, candidates);
|
||||
assertTrue(candidates.size() > 0);
|
||||
|
||||
boolean found = false;
|
||||
for (Candidate candidate : candidates) {
|
||||
if (candidate.value().equals("src/test/resources/test.properties")) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTestPropertiesFound(candidates);
|
||||
}
|
||||
|
||||
assertTrue(found);
|
||||
private String getTestResourcesDirectory() {
|
||||
return Paths.get(TEST_RESOURCES_DIRECTORY).toAbsolutePath() + File.separator;
|
||||
}
|
||||
|
||||
private void assertTestPropertiesFound(final List<Candidate> candidates) {
|
||||
final Optional<Candidate> candidateFound = candidates.stream()
|
||||
.filter(candidate -> candidate.value().endsWith(TEST_PROPERTIES))
|
||||
.findFirst();
|
||||
assertTrue(candidateFound.isPresent());
|
||||
}
|
||||
|
||||
private static class TestParsedLine implements ParsedLine {
|
||||
|
Loading…
x
Reference in New Issue
Block a user