Author: gnodet
Date: Mon Mar 21 16:54:22 2016
New Revision: 1736006
URL: http://svn.apache.org/viewvc?rev=1736006&view=rev
Log:
Clean up a bit
Removed:
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/IoUtils.java
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/JLineCommands.java
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/JLineCompletionEnvironment.java
Modified:
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Activator.java
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Builtin.java
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Highlighter.java
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Main.java
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ParsedLineImpl.java
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Procedural.java
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellFactoryImpl.java
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/Telnet.java
Modified:
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Activator.java
URL:
http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Activator.java?rev=1736006&r1=1736005&r2=1736006&view=diff
==============================================================================
---
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Activator.java
(original)
+++
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Activator.java
Mon Mar 21 16:54:22 2016
@@ -25,7 +25,6 @@ import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import org.apache.felix.gogo.jline.Shell.Context;
@@ -47,7 +46,7 @@ public class Activator implements Bundle
private ExecutorService executor;
public Activator() {
- regs = new HashSet<ServiceRegistration>();
+ regs = new HashSet<>();
}
public void start(BundleContext context) throws Exception {
@@ -87,7 +86,7 @@ public class Activator implements Bundle
}
private void startShell(final BundleContext context, CommandProcessor
processor) {
- Dictionary<String, Object> dict = new Hashtable<String, Object>();
+ Dictionary<String, Object> dict = new Hashtable<>();
dict.put(CommandProcessor.COMMAND_SCOPE, "gogo");
// register converters
@@ -102,21 +101,17 @@ public class Activator implements Bundle
regs.add(context.registerService(Procedural.class.getName(), new
Procedural(), dict));
dict.put(CommandProcessor.COMMAND_FUNCTION, Posix.functions);
- regs.add(context.registerService(Posix.class.getName(), new Posix(),
dict));
+ regs.add(context.registerService(Posix.class.getName(), new
Posix(processor), dict));
dict.put(CommandProcessor.COMMAND_FUNCTION, Telnet.functions);
regs.add(context.registerService(Telnet.class.getName(), new
Telnet(processor), dict));
- Shell shell = new Shell(new ShellContext(), processor, null);
+ Shell shell = new Shell(new ShellContext(), processor);
dict.put(CommandProcessor.COMMAND_FUNCTION, Shell.functions);
regs.add(context.registerService(Shell.class.getName(), shell, dict));
// start shell on a separate thread...
- executor = Executors.newSingleThreadExecutor(new ThreadFactory() {
- public Thread newThread(Runnable runnable) {
- return new Thread(runnable, "Gogo shell");
- }
- });
+ executor = Executors.newSingleThreadExecutor(runnable -> new
Thread(runnable, "Gogo shell"));
executor.submit(new StartShellJob(context, processor));
}
Modified:
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Builtin.java
URL:
http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Builtin.java?rev=1736006&r1=1736005&r2=1736006&view=diff
==============================================================================
---
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Builtin.java
(original)
+++
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Builtin.java
Mon Mar 21 16:54:22 2016
@@ -20,8 +20,11 @@ package org.apache.felix.gogo.jline;
import java.io.BufferedReader;
import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
+import java.io.PrintStream;
import java.io.StringWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
@@ -43,21 +46,39 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.apache.felix.gogo.runtime.CommandSessionImpl;
import org.apache.felix.gogo.runtime.Job;
import org.apache.felix.service.command.CommandSession;
import org.apache.felix.service.command.Converter;
+import org.apache.felix.service.command.Function;
+import org.jline.builtins.Commands;
+import org.jline.builtins.Completers.DirectoriesCompleter;
+import org.jline.builtins.Completers.FilesCompleter;
import org.jline.builtins.Options;
+import org.jline.reader.Candidate;
+import org.jline.reader.LineReader;
+import org.jline.reader.ParsedLine;
+import org.jline.reader.Widget;
+
+import static org.apache.felix.gogo.jline.Shell.*;
/**
* gosh built-in commands.
*/
public class Builtin {
- static final String[] functions = {"format", "getopt", "new", "set",
"tac", "type", "jobs", "fg", "bg"};
+ static final String[] functions = {
+ "format", "getopt", "new", "set", "tac", "type",
+ "jobs", "fg", "bg",
+ "keymap", "setopt", "unsetopt", "complete", "history", "widget",
+ "__files", "__directories", "__usage_completion"
+ };
+
+ private static final String[] packages = {"java.lang", "java.io",
"java.net", "java.util"};
- private static final String[] packages = {"java.lang", "java.io",
"java.net",
- "java.util"};
private final static Set<String> KEYWORDS = new HashSet<String>(
Arrays.asList(new String[]{"abstract", "continue", "for", "new",
"switch",
"assert", "default", "goto", "package", "synchronized",
"boolean", "do",
@@ -68,11 +89,6 @@ public class Builtin {
"finally", "long", "strictfp", "volatile", "const",
"float", "native",
"super", "while"}));
- @SuppressWarnings("unchecked")
- static Set<String> getCommands(CommandSession session) {
- return (Set<String>) session.get(".commands");
- }
-
public CharSequence format(CommandSession session) {
return format(session, session.get("_")); // last result
}
@@ -564,4 +580,133 @@ public class Builtin {
return list;
}
+ public void history(CommandSession session, String[] argv) throws
IOException {
+ Commands.history(Shell.getReader(session), System.out, System.err,
argv);
+ }
+
+ public void complete(CommandSession session, String[] argv) {
+ Commands.complete(Shell.getReader(session), System.out, System.err,
Shell.getCompletions(session), argv);
+ }
+
+ public void widget(final CommandSession session, String[] argv) throws
Exception {
+ java.util.function.Function<String, Widget> creator = func -> () -> {
+ try {
+ session.execute(func);
+ } catch (Exception e) {
+ // TODO: log exception ?
+ return false;
+ }
+ return true;
+ };
+ Commands.widget(Shell.getReader(session), System.out, System.err,
creator, argv);
+ }
+
+ public void keymap(CommandSession session, String[] argv) {
+ Commands.keymap(Shell.getReader(session), System.out, System.err,
argv);
+ }
+
+ public void setopt(CommandSession session, String[] argv) {
+ Commands.setopt(Shell.getReader(session), System.out, System.err,
argv);
+ }
+
+ public void unsetopt(CommandSession session, String[] argv) {
+ Commands.unsetopt(Shell.getReader(session), System.out, System.err,
argv);
+ }
+
+ public List<Candidate> __files(CommandSession session) {
+ ParsedLine line = Shell.getParsedLine(session);
+ LineReader reader = Shell.getReader(session);
+ List<Candidate> candidates = new ArrayList<>();
+ new FilesCompleter(session.currentDir()) {
+ @Override
+ protected String getDisplay(Path p) {
+ return getFileDisplay(session, p);
+ }
+ }.complete(reader, line, candidates);
+ return candidates;
+ }
+
+ public List<Candidate> __directories(CommandSession session) {
+ ParsedLine line = Shell.getParsedLine(session);
+ LineReader reader = Shell.getReader(session);
+ List<Candidate> candidates = new ArrayList<>();
+ new DirectoriesCompleter(session.currentDir()) {
+ @Override
+ protected String getDisplay(Path p) {
+ return getFileDisplay(session, p);
+ }
+ }.complete(reader, line, candidates);
+ return candidates;
+ }
+
+ private String getFileDisplay(CommandSession session, Path path) {
+ String type;
+ String suffix;
+ if (Files.isSymbolicLink(path)) {
+ type = "sl";
+ suffix = "@";
+ } else if (Files.isDirectory(path)) {
+ type = "dr";
+ suffix = "/";
+ } else if (Files.isExecutable(path)) {
+ type = "ex";
+ suffix = "*";
+ } else if (!Files.isRegularFile(path)) {
+ type = "ot";
+ suffix = "";
+ } else {
+ type = "";
+ suffix = "";
+ }
+ String col = Posix.getColorMap(session, "LS").get(type);
+ if (col != null && !col.isEmpty()) {
+ return "\033[" + col + "m" + path.getFileName().toString() +
"\033[m" + suffix;
+ } else {
+ return path.getFileName().toString() + suffix;
+ }
+
+ }
+
+ public void __usage_completion(CommandSession session, String command)
throws Exception {
+ Object func = session.get(command.contains(":") ? command : "*:" +
command);
+ if (func instanceof Function) {
+ ByteArrayInputStream bais = new ByteArrayInputStream(new byte[0]);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ByteArrayOutputStream baes = new ByteArrayOutputStream();
+ CommandSession ts = ((CommandSessionImpl)
session).processor().createSession(bais, new PrintStream(baos), new
PrintStream(baes));
+ ts.execute(command + " --help");
+
+ String regex = "(?x)\\s*" + "(?:-([^-]))?" + // 1: short-opt-1
+ "(?:,?\\s*-(\\w))?" + // 2: short-opt-2
+ "(?:,?\\s*--(\\w[\\w-]*)(=\\w+)?)?" + // 3: long-opt-1 and
4:arg-1
+ "(?:,?\\s*--(\\w[\\w-]*))?" + // 5: long-opt-2
+ ".*?(?:\\(default=(.*)\\))?\\s*" + // 6: default
+ "(.*)"; // 7: description
+ Pattern pattern = Pattern.compile(regex);
+ for (String l : baes.toString().split("\n")) {
+ Matcher matcher = pattern.matcher(l);
+ if (matcher.matches()) {
+ List<String> args = new ArrayList<>();
+ if (matcher.group(1) != null) {
+ args.add("--short-option");
+ args.add(matcher.group(1));
+ }
+ if (matcher.group(3) != null) {
+ args.add("--long-option");
+ args.add(matcher.group(1));
+ }
+ if (matcher.group(4) != null) {
+ args.add("--argument");
+ args.add("");
+ }
+ if (matcher.group(7) != null) {
+ args.add("--description");
+ args.add(matcher.group(7));
+ }
+ complete(session, args.toArray(new String[args.size()]));
+ }
+ }
+ }
+ }
+
}
Modified:
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Highlighter.java
URL:
http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Highlighter.java?rev=1736006&r1=1736005&r2=1736006&view=diff
==============================================================================
---
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Highlighter.java
(original)
+++
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Highlighter.java
Mon Mar 21 16:54:22 2016
@@ -103,7 +103,6 @@ public class Highlighter extends Default
break;
}
if (token.start() > cur) {
-// ansi.a(buffer.substring(cur, token.start()));
cur = token.start();
}
// Find corresponding statement
@@ -153,37 +152,6 @@ public class Highlighter extends Default
}
}
Arrays.fill(types, token.start(), Math.min(token.start() +
token.length(), types.length), type);
- /*
- String valid;
- if (token.start() + token.length() <= buffer.length()) {
- valid = token.toString();
- } else {
- valid = token.subSequence(0, buffer.length() -
token.start()).toString();
- }
- switch (type) {
- case Reserved:
- ansi.fg(Color.MAGENTA).a(valid).fg(Color.DEFAULT);
- break;
- case String:
- case Number:
- case Constant:
- ansi.fg(Color.GREEN).a(valid).fg(Color.DEFAULT);
- break;
- case Variable:
- case VariableName:
- ansi.fg(Color.CYAN).a(valid).fg(Color.DEFAULT);
- break;
- case Function:
- ansi.fg(Color.BLUE).a(valid).fg(Color.DEFAULT);
- break;
- case BadFunction:
- ansi.fg(Color.RED).a(valid).fg(Color.DEFAULT);
- break;
- default:
- ansi.a(valid);
- break;
- }
- */
cur = Math.min(token.start() + token.length(),
buffer.length());
}
Modified:
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Main.java
URL:
http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Main.java?rev=1736006&r1=1736005&r2=1736006&view=diff
==============================================================================
--- felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Main.java
(original)
+++ felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Main.java
Mon Mar 21 16:54:22 2016
@@ -49,15 +49,14 @@ public class Main {
try {
CommandProcessorImpl processor = new CommandProcessorImpl(tio);
Context context = new MyContext();
- Shell shell = new Shell(context, processor, terminal);
+ Shell shell = new Shell(context, processor);
processor.addCommand("gogo", processor, "addCommand");
processor.addCommand("gogo", processor, "removeCommand");
processor.addCommand("gogo", processor, "eval");
register(processor, new Builtin(), Builtin.functions);
register(processor, new Procedural(), Procedural.functions);
- register(processor, new Posix(), Posix.functions);
+ register(processor, new Posix(processor), Posix.functions);
register(processor, shell, Shell.functions);
- register(processor, new JLineCommands(processor),
JLineCommands.functions);
try {
register(processor, new Telnet(processor),
Telnet.functions);
} catch (Throwable t) {
Modified:
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ParsedLineImpl.java
URL:
http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ParsedLineImpl.java?rev=1736006&r1=1736005&r2=1736006&view=diff
==============================================================================
---
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ParsedLineImpl.java
(original)
+++
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ParsedLineImpl.java
Mon Mar 21 16:54:22 2016
@@ -38,7 +38,7 @@ public class ParsedLineImpl implements P
this.program = program;
this.source = line.toString();
this.cursor = cursor - line.start();
- this.tokens = new ArrayList<String>();
+ this.tokens = new ArrayList<>();
for (Token token : tokens) {
this.tokens.add(token.toString());
}
Modified:
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java
URL:
http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java?rev=1736006&r1=1736005&r2=1736006&view=diff
==============================================================================
--- felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java
(original)
+++ felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java
Mon Mar 21 16:54:22 2016
@@ -19,15 +19,19 @@
package org.apache.felix.gogo.jline;
import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.io.OutputStream;
import java.io.PrintStream;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
+import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.attribute.BasicFileAttributes;
@@ -48,6 +52,9 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.IntBinaryOperator;
import java.util.function.Predicate;
@@ -56,17 +63,22 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import org.apache.felix.gogo.jline.Shell.Context;
import org.apache.felix.gogo.runtime.Pipe;
+import org.apache.felix.service.command.CommandProcessor;
import org.apache.felix.service.command.CommandSession;
+import org.apache.sshd.common.util.OsUtils;
+import org.jline.builtins.Commands;
import org.jline.builtins.Less.Source;
import org.jline.builtins.Less.StdInSource;
import org.jline.builtins.Less.URLSource;
import org.jline.builtins.Options;
-import org.jline.reader.LineReader.Option;
+import org.jline.terminal.Attributes;
import org.jline.terminal.Terminal;
import org.jline.utils.AttributedString;
import org.jline.utils.AttributedStringBuilder;
import org.jline.utils.AttributedStyle;
+import org.jline.utils.InfoCmp.Capability;
/**
* Posix-like utilities.
@@ -75,42 +87,31 @@ import org.jline.utils.AttributedStyle;
* http://www.opengroup.org/onlinepubs/009695399/utilities/contents.html</a>
*/
public class Posix {
- static final String[] functions = {"cat", "echo", "grep", "sort", "sleep",
"cd", "pwd", "ls"};
+
+ static final String[] functions = {
+ "cat", "echo", "grep", "sort", "sleep", "cd", "pwd", "ls",
+ "less", "watch", "nano", "tmux",
+ };
public static final String DEFAULT_LS_COLORS =
"dr=1;91:ex=1;92:sl=1;96:ot=34;43";
- public void _main(CommandSession session, String[] argv) {
+ private static final LinkOption[] NO_FOLLOW_OPTIONS = new
LinkOption[]{LinkOption.NOFOLLOW_LINKS};
+ private static final List<String> WINDOWS_EXECUTABLE_EXTENSIONS =
Collections.unmodifiableList(Arrays.asList(".bat", ".exe", ".cmd"));
+ private static final LinkOption[] EMPTY_LINK_OPTIONS = new LinkOption[0];
+
+ private final CommandProcessor processor;
+
+ public Posix(CommandProcessor processor) {
+ this.processor = processor;
+ }
+
+ protected void _main(CommandSession session, String[] argv) {
if (argv == null || argv.length < 1) {
throw new IllegalArgumentException();
}
try {
argv = expand(session, argv);
- switch (argv[0]) {
- case "cat":
- cat(session, argv);
- break;
- case "echo":
- echo(session, argv);
- break;
- case "grep":
- grep(session, argv);
- break;
- case "sort":
- sort(session, argv);
- break;
- case "sleep":
- sleep(session, argv);
- break;
- case "cd":
- cd(session, argv);
- break;
- case "pwd":
- pwd(session, argv);
- break;
- case "ls":
- ls(session, argv);
- break;
- }
+ run(session, argv);
} catch (IllegalArgumentException e) {
System.err.println(e.getMessage());
Pipe.error(2);
@@ -129,6 +130,243 @@ public class Posix {
}
}
+ protected Options parseOptions(CommandSession session, String[] usage,
Object[] argv) throws Exception {
+ Options opt = Options.compile(usage, s -> get(session, s)).parse(argv,
true);
+ if (opt.isSet("help")) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ opt.usage(new PrintStream(baos));
+ throw new HelpException(baos.toString());
+ }
+ return opt;
+ }
+
+ protected String get(CommandSession session, String name) {
+ Object o = session.get(name);
+ return o != null ? o.toString() : null;
+ }
+
+ protected String[] expand(CommandSession session, String[] argv) throws
IOException {
+ String reserved = "(?<!\\\\)[*(|<\\[?]";
+ List<String> params = new ArrayList<>();
+ for (String arg : argv) {
+ if (arg.matches(".*" + reserved + ".*")) {
+ String org = arg;
+ List<String> expanded = new ArrayList<>();
+ Path currentDir = session.currentDir();
+ Path dir;
+ String pfx = arg.replaceFirst(reserved + ".*", "");
+ String prefix;
+ if (pfx.indexOf('/') >= 0) {
+ pfx = pfx.substring(0, pfx.lastIndexOf('/'));
+ arg = arg.substring(pfx.length() + 1);
+ dir = currentDir.resolve(pfx).normalize();
+ prefix = pfx + "/";
+ } else {
+ dir = currentDir;
+ prefix = "";
+ }
+ PathMatcher matcher =
dir.getFileSystem().getPathMatcher("glob:" + arg);
+ Files.walkFileTree(dir,
+ EnumSet.of(FileVisitOption.FOLLOW_LINKS),
+ Integer.MAX_VALUE,
+ new FileVisitor<Path>() {
+ @Override
+ public FileVisitResult preVisitDirectory(Path
file, BasicFileAttributes attrs) throws IOException {
+ if (file.equals(dir)) {
+ return FileVisitResult.CONTINUE;
+ }
+ if (Files.isHidden(file)) {
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+ Path r = dir.relativize(file);
+ if (matcher.matches(r)) {
+ expanded.add(prefix + r.toString());
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) throws IOException {
+ if (!Files.isHidden(file)) {
+ Path r = dir.relativize(file);
+ if (matcher.matches(r)) {
+ expanded.add(prefix + r.toString());
+ }
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFileFailed(Path file,
IOException exc) throws IOException {
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path
dir, IOException exc) throws IOException {
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ Collections.sort(expanded);
+ if (expanded.isEmpty()) {
+ throw new IOException("no matches found: " + org);
+ }
+ params.addAll(expanded);
+ } else {
+ params.add(arg);
+ }
+ }
+ return params.toArray(new String[params.size()]);
+ }
+
+ protected Object run(CommandSession session, String[] argv) throws
Exception {
+ switch (argv[0]) {
+ case "cat":
+ cat(session, argv);
+ break;
+ case "echo":
+ echo(session, argv);
+ break;
+ case "grep":
+ grep(session, argv);
+ break;
+ case "sort":
+ sort(session, argv);
+ break;
+ case "sleep":
+ sleep(session, argv);
+ break;
+ case "cd":
+ cd(session, argv);
+ break;
+ case "pwd":
+ pwd(session, argv);
+ break;
+ case "ls":
+ ls(session, argv);
+ break;
+ case "less":
+ less(session, argv);
+ break;
+ case "watch":
+ watch(session, argv);
+ break;
+ case "nano":
+ nano(session, argv);
+ break;
+ case "tmux":
+ tmux(session, argv);
+ break;
+ }
+ return null;
+ }
+
+ protected void tmux(final CommandSession session, String[] argv) throws
Exception {
+ Commands.tmux(Shell.getTerminal(session),
+ System.out, System.err,
+ () -> session.get(".tmux"),
+ t -> session.put(".tmux", t),
+ c -> startShell(session, c), argv);
+ }
+
+ private void startShell(CommandSession session, Terminal terminal) {
+ new Thread(() -> runShell(session, terminal), terminal.getName() + "
shell").start();
+ }
+
+ private void runShell(CommandSession session, Terminal terminal) {
+ InputStream in = terminal.input();
+ OutputStream out = terminal.output();
+ CommandSession newSession = processor.createSession(in, out, out);
+ newSession.put(Shell.VAR_TERMINAL, terminal);
+ newSession.put(".tmux", session.get(".tmux"));
+ Context context = new Context() {
+ public String getProperty(String name) {
+ return System.getProperty(name);
+ }
+ public void exit() throws Exception {
+ terminal.close();
+ }
+ };
+ try {
+ new Shell(context, processor).gosh(newSession, new
String[]{"--login"});
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ terminal.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ protected void nano(final CommandSession session, String[] argv) throws
Exception {
+ Commands.nano(Shell.getTerminal(session), System.out, System.err,
session.currentDir(), argv);
+ }
+
+ protected void watch(final CommandSession session, String[] argv) throws
IOException, InterruptedException {
+ final String[] usage = {
+ "watch - watches & refreshes the output of a command",
+ "Usage: watch [OPTIONS] COMMAND",
+ " -? --help Show help",
+ " -n --interval Interval between executions of
the command in seconds",
+ " -a --append The output should be appended
but not clear the console"
+ };
+ final Options opt = Options.compile(usage).parse(argv);
+ if (opt.isSet("help")) {
+ opt.usage(System.err);
+ return;
+ }
+ List<String> args = opt.args();
+ if (args.isEmpty()) {
+ System.err.println("Argument expected");
+ return;
+ }
+ ScheduledExecutorService executorService =
Executors.newSingleThreadScheduledExecutor();
+ final Terminal terminal = Shell.getTerminal(session);
+ final CommandProcessor processor = Shell.getProcessor(session);
+ try {
+ int interval = 1;
+ if (opt.isSet("interval")) {
+ interval = opt.getNumber("interval");
+ if (interval < 1) {
+ interval = 1;
+ }
+ }
+ final String cmd = String.join(" ", args);
+ Runnable task = () -> {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ PrintStream os = new PrintStream(baos);
+ InputStream is = new ByteArrayInputStream(new byte[0]);
+ if (opt.isSet("append") ||
!terminal.puts(Capability.clear_screen)) {
+ terminal.writer().println();
+ }
+ try {
+ CommandSession ns = processor.createSession(is, os, os);
+ Set<String> vars = Shell.getCommands(session);
+ for (String n : vars) {
+ ns.put(n, session.get(n));
+ }
+ ns.execute(cmd);
+ } catch (Throwable t) {
+ t.printStackTrace(os);
+ }
+ os.flush();
+ terminal.writer().print(baos.toString());
+ terminal.writer().flush();
+ };
+ executorService.scheduleAtFixedRate(task, 0, interval,
TimeUnit.SECONDS);
+ Attributes attr = terminal.enterRawMode();
+ terminal.reader().read();
+ terminal.setAttributes(attr);
+ } finally {
+ executorService.shutdownNow();
+ }
+ }
+
+ protected void less(CommandSession session, String[] argv) throws
IOException, InterruptedException {
+ Commands.less(Shell.getTerminal(session), System.out, System.err,
session.currentDir(), argv);
+ }
+
protected void sort(CommandSession session, String[] argv) throws
Exception {
final String[] usage = {
"sort - writes sorted standard input to standard output.",
@@ -403,14 +641,14 @@ public class Posix {
for (String view :
path.getFileSystem().supportedFileAttributeViews()) {
try {
Map<String, Object> ta = Files.readAttributes(path,
view + ":*",
- IoUtils.getLinkOptions(opt.isSet("L")));
+ getLinkOptions(opt.isSet("L")));
ta.entrySet().forEach(e ->
attrs.putIfAbsent(e.getKey(), e.getValue()));
} catch (IOException e) {
// Ignore
}
}
attrs.computeIfAbsent("isExecutable", s ->
Files.isExecutable(path));
- attrs.computeIfAbsent("permissions", s ->
IoUtils.getPermissionsFromFile(path.toFile()));
+ attrs.computeIfAbsent("permissions", s ->
getPermissionsFromFile(path.toFile()));
return attrs;
}
}
@@ -613,7 +851,7 @@ public class Posix {
if (before < 0) {
before = context;
}
- List<String> lines = new ArrayList<String>();
+ List<String> lines = new ArrayList<>();
boolean invertMatch = opt.isSet("invert-match");
boolean lineNumber = opt.isSet("line-number");
boolean count = opt.isSet("count");
@@ -785,10 +1023,7 @@ public class Posix {
sortFields = new ArrayList<>();
sortFields.add("1");
}
- sortKeys = new ArrayList<Key>();
- for (String f : sortFields) {
- sortKeys.add(new Key(f));
- }
+ sortKeys =
sortFields.stream().map(Key::new).collect(Collectors.toList());
}
public int compare(String o1, String o2) {
@@ -823,8 +1058,7 @@ public class Posix {
}
protected int compareRegion(String s1, int start1, int end1, String
s2, int start2, int end2, boolean caseInsensitive) {
- int n1 = end1, n2 = end2;
- for (int i1 = start1, i2 = start2; i1 < end1 && i2 < n2; i1++,
i2++) {
+ for (int i1 = start1, i2 = start2; i1 < end1 && i2 < end2; i1++,
i2++) {
char c1 = s1.charAt(i1);
char c2 = s2.charAt(i2);
if (c1 != c2) {
@@ -843,7 +1077,7 @@ public class Posix {
}
}
}
- return n1 - n2;
+ return end1 - end2;
}
protected int[] getSortKey(String str, List<Integer> fields, Key key) {
@@ -882,7 +1116,6 @@ public class Posix {
List<Integer> fields = new ArrayList<>();
if (o.length() > 0) {
if (separator == '\0') {
- int i = 0;
fields.add(0);
for (int idx = 1; idx < o.length(); idx++) {
if (Character.isWhitespace(o.charAt(idx)) &&
!Character.isWhitespace(o.charAt(idx - 1))) {
@@ -1014,74 +1247,57 @@ public class Posix {
}
}
- private String[] expand(CommandSession session, String[] argv) throws
IOException {
- String reserved = "(?<!\\\\)[*(|<\\[?]";
- List<String> params = new ArrayList<>();
- for (String arg : argv) {
- if (arg.matches(".*" + reserved + ".*")) {
- String org = arg;
- List<String> expanded = new ArrayList<>();
- Path currentDir = session.currentDir();
- Path dir;
- String pfx = arg.replaceFirst(reserved + ".*", "");
- String prefix;
- if (pfx.indexOf('/') >= 0) {
- pfx = pfx.substring(0, pfx.lastIndexOf('/'));
- arg = arg.substring(pfx.length() + 1);
- dir = currentDir.resolve(pfx).normalize();
- prefix = pfx + "/";
- } else {
- dir = currentDir;
- prefix = "";
- }
- PathMatcher matcher =
dir.getFileSystem().getPathMatcher("glob:" + arg);
- Files.walkFileTree(dir,
- EnumSet.of(FileVisitOption.FOLLOW_LINKS),
- Integer.MAX_VALUE,
- new FileVisitor<Path>() {
- @Override
- public FileVisitResult preVisitDirectory(Path file,
BasicFileAttributes attrs) throws IOException {
- if (file.equals(dir)) {
- return FileVisitResult.CONTINUE;
- }
- if (Files.isHidden(file)) {
- return FileVisitResult.SKIP_SUBTREE;
- }
- Path r = dir.relativize(file);
- if (matcher.matches(r)) {
- expanded.add(prefix + r.toString());
- }
- return FileVisitResult.CONTINUE;
- }
- @Override
- public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) throws IOException {
- if (!Files.isHidden(file)) {
- Path r = dir.relativize(file);
- if (matcher.matches(r)) {
- expanded.add(prefix + r.toString());
- }
- }
- return FileVisitResult.CONTINUE;
- }
- @Override
- public FileVisitResult visitFileFailed(Path file,
IOException exc) throws IOException {
- return FileVisitResult.CONTINUE;
- }
- @Override
- public FileVisitResult postVisitDirectory(Path dir,
IOException exc) throws IOException {
- return FileVisitResult.CONTINUE;
- }
- });
- Collections.sort(expanded);
- if (expanded.isEmpty()) {
- throw new IOException("no matches found: " + org);
- }
- params.addAll(expanded);
- } else {
- params.add(arg);
+ private static LinkOption[] getLinkOptions(boolean followLinks) {
+ if (followLinks) {
+ return EMPTY_LINK_OPTIONS;
+ } else { // return a clone that modifications to the array will not
affect others
+ return NO_FOLLOW_OPTIONS.clone();
+ }
+ }
+
+ /**
+ * @param fileName The file name to be evaluated - ignored if {@code
null}/empty
+ * @return {@code true} if the file ends in one of the {@link
#WINDOWS_EXECUTABLE_EXTENSIONS}
+ */
+ private static boolean isWindowsExecutable(String fileName) {
+ if ((fileName == null) || (fileName.length() <= 0)) {
+ return false;
+ }
+ for (String suffix : WINDOWS_EXECUTABLE_EXTENSIONS) {
+ if (fileName.endsWith(suffix)) {
+ return true;
}
}
- return params.toArray(new String[params.size()]);
+ return false;
+ }
+
+ /**
+ * @param f The {@link File} to be checked
+ * @return A {@link Set} of {@link PosixFilePermission}s based on whether
+ * the file is readable/writable/executable. If so, then <U>all</U> the
+ * relevant permissions are set (i.e., owner, group and others)
+ */
+ private static Set<PosixFilePermission> getPermissionsFromFile(File f) {
+ Set<PosixFilePermission> perms =
EnumSet.noneOf(PosixFilePermission.class);
+ if (f.canRead()) {
+ perms.add(PosixFilePermission.OWNER_READ);
+ perms.add(PosixFilePermission.GROUP_READ);
+ perms.add(PosixFilePermission.OTHERS_READ);
+ }
+
+ if (f.canWrite()) {
+ perms.add(PosixFilePermission.OWNER_WRITE);
+ perms.add(PosixFilePermission.GROUP_WRITE);
+ perms.add(PosixFilePermission.OTHERS_WRITE);
+ }
+
+ if (f.canExecute() || (OsUtils.isWin32() &&
isWindowsExecutable(f.getName()))) {
+ perms.add(PosixFilePermission.OWNER_EXECUTE);
+ perms.add(PosixFilePermission.GROUP_EXECUTE);
+ perms.add(PosixFilePermission.OTHERS_EXECUTE);
+ }
+
+ return perms;
}
public static Map<String, String> getColorMap(CommandSession session,
String name) {
@@ -1099,19 +1315,4 @@ public class Posix {
s -> s.substring(s.indexOf('=') +
1)));
}
- private Options parseOptions(CommandSession session, String[] usage,
Object[] argv) throws Exception {
- Options opt = Options.compile(usage, s -> get(session, s)).parse(argv,
true);
- if (opt.isSet("help")) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- opt.usage(new PrintStream(baos));
- throw new HelpException(baos.toString());
- }
- return opt;
- }
-
- private String get(CommandSession session, String name) {
- Object o = session.get(name);
- return o != null ? o.toString() : null;
- }
-
}
Modified:
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Procedural.java
URL:
http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Procedural.java?rev=1736006&r1=1736005&r2=1736006&view=diff
==============================================================================
---
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Procedural.java
(original)
+++
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Procedural.java
Mon Mar 21 16:54:22 2016
@@ -26,13 +26,13 @@ import org.apache.felix.service.command.
import org.apache.felix.service.command.Function;
public class Procedural {
- static final String[] functions = {"each", "if", "not", "throw", "try",
"until",
- "while"};
+
+ static final String[] functions = {"each", "if", "not", "throw", "try",
"until", "while"};
public List<Object> each(CommandSession session, Collection<Object> list,
Function closure) throws Exception {
- List<Object> args = new ArrayList<Object>();
- List<Object> results = new ArrayList<Object>();
+ List<Object> args = new ArrayList<>();
+ List<Object> results = new ArrayList<>();
args.add(null);
for (Object x : list) {
@@ -61,11 +61,8 @@ public class Procedural {
}
public boolean not(CommandSession session, Function condition) throws
Exception {
- if (null == condition) {
- return true;
- }
+ return condition == null || !isTrue(condition.execute(session, null));
- return !isTrue(condition.execute(session, null));
}
// Reflective.coerce() prefers to construct a new Throwable(String)
@@ -126,7 +123,7 @@ public class Procedural {
return false;
if (result instanceof Boolean)
- return ((Boolean) result).booleanValue();
+ return (Boolean) result;
if (result instanceof Number) {
if (0 == ((Number) result).intValue())
Modified:
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java
URL:
http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java?rev=1736006&r1=1736005&r2=1736006&view=diff
==============================================================================
--- felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java
(original)
+++ felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java
Mon Mar 21 16:54:22 2016
@@ -53,6 +53,7 @@ import org.apache.felix.service.command.
import org.apache.felix.service.command.Function;
import org.apache.felix.service.command.Parameter;
import org.jline.builtins.Completers.CompletionData;
+import org.jline.builtins.Completers.CompletionEnvironment;
import org.jline.builtins.Options;
import org.jline.reader.EndOfFileException;
import org.jline.reader.LineReader;
@@ -88,11 +89,11 @@ public class Shell {
private final Context context;
private final CommandProcessor processor;
- public Shell(Context context, CommandProcessor processor, Terminal
terminal) {
- this(context, processor, terminal, null);
+ public Shell(Context context, CommandProcessor processor) {
+ this(context, processor, null);
}
- public Shell(Context context, CommandProcessor processor, Terminal
terminal, String profile) {
+ public Shell(Context context, CommandProcessor processor, String profile) {
this.context = context;
this.processor = processor;
String baseDir = context.getProperty("gosh.home");
@@ -243,11 +244,9 @@ public class Shell {
}
// export variables starting with upper-case to newSession
- for (String key : getVariables(session)) {
- if (key.matches("[.]?[A-Z].*")) {
- newSession.put(key, session.get(key));
- }
- }
+ getVariables(session).stream()
+ .filter(key -> key.matches("[.]?[A-Z].*"))
+ .forEach(key -> newSession.put(key, session.get(key)));
Terminal terminal = getTerminal(session);
newSession.put(Shell.VAR_CONTEXT, context);
@@ -261,10 +260,34 @@ public class Shell {
LineReader reader;
if (args.isEmpty() && interactive) {
+ CompletionEnvironment completionEnvironment = new
CompletionEnvironment() {
+ @Override
+ public Map<String, List<CompletionData>> getCompletions() {
+ return Shell.getCompletions(newSession);
+ }
+ @Override
+ public Set<String> getCommands() {
+ return Shell.getCommands(session);
+ }
+ @Override
+ public String resolveCommand(String command) {
+ return Shell.resolve(session, command);
+ }
+ @Override
+ public String commandName(String command) {
+ int idx = command.indexOf(':');
+ return idx >= 0 ? command.substring(idx + 1) : command;
+ }
+ @Override
+ public Object evaluate(LineReader reader, ParsedLine line,
String func) throws Exception {
+ session.put(Shell.VAR_COMMAND_LINE, line);
+ return session.execute(func);
+ }
+ };
reader = LineReaderBuilder.builder()
.terminal(terminal)
.variables(((CommandSessionImpl)
newSession).getVariables())
- .completer(new org.jline.builtins.Completers.Completer(new
JLineCompletionEnvironment(newSession)))
+ .completer(new
org.jline.builtins.Completers.Completer(completionEnvironment))
.highlighter(new Highlighter(session))
.history(new FileHistory(new
File(System.getProperty("user.home"), ".gogo.history")))
.parser(new Parser())
@@ -357,6 +380,7 @@ public class Shell {
while (true) {
Job job = session.foregroundJob();
if (job != null) {
+ //noinspection
SynchronizationOnLocalVariableOrMethodParameter
synchronized (job) {
if (job.status() == Status.Foreground)
{
job.wait();
@@ -420,6 +444,7 @@ public class Shell {
return result;
}
+ @Descriptor("start a new shell")
public Object sh(final CommandSession session, String[] argv) throws
Exception {
return gosh(session, argv);
}
@@ -428,6 +453,7 @@ public class Shell {
context.exit();
}
+ @Descriptor("Evaluates contents of file")
public Object source(CommandSession session, String script) throws
Exception {
URI uri = session.currentDir().toUri().resolve(script);
session.put("0", uri);
@@ -439,7 +465,7 @@ public class Shell {
}
private Map<String, List<Method>> getReflectionCommands(CommandSession
session) {
- Map<String, List<Method>> commands = new TreeMap<String,
List<Method>>();
+ Map<String, List<Method>> commands = new TreeMap<>();
Set<String> names = getCommands(session);
for (String name : names) {
Function function = (Function) session.get(name);
@@ -471,9 +497,7 @@ public class Shell {
@Descriptor("displays available commands")
public void help(CommandSession session) {
Map<String, List<Method>> commands = getReflectionCommands(session);
- for (String name : commands.keySet()) {
- System.out.println(name);
- }
+ commands.keySet().forEach(System.out::println);
}
@Descriptor("displays information about a specific command")
@@ -517,7 +541,7 @@ public class Shell {
Map<String, String> flagDescs = new TreeMap<>();
Map<String, Parameter> options = new TreeMap<>();
Map<String, String> optionDescs = new TreeMap<>();
- List<String> params = new ArrayList<String>();
+ List<String> params = new ArrayList<>();
Annotation[][] anns = m.getParameterAnnotations();
for (int paramIdx = 0; paramIdx < anns.length; paramIdx++) {
Class<?> paramType = m.getParameterTypes()[paramIdx];
Modified:
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellFactoryImpl.java
URL:
http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellFactoryImpl.java?rev=1736006&r1=1736005&r2=1736006&view=diff
==============================================================================
---
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellFactoryImpl.java
(original)
+++
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellFactoryImpl.java
Mon Mar 21 16:54:22 2016
@@ -257,7 +257,7 @@ public class ShellFactoryImpl implements
destroy();
}
};
- new Shell(context, processor, terminal).gosh(session, new
String[]{"--login"});
+ new Shell(context, processor).gosh(session, new
String[]{"--login"});
} catch (Throwable t) {
t.printStackTrace();
}
Modified:
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/Telnet.java
URL:
http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/Telnet.java?rev=1736006&r1=1736005&r2=1736006&view=diff
==============================================================================
---
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/Telnet.java
(original)
+++
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/Telnet.java
Mon Mar 21 16:54:22 2016
@@ -178,7 +178,7 @@ public class Telnet {
close();
}
};
- new Shell(context, processor, terminal).gosh(session,
new String[]{"--login"});
+ new Shell(context, processor).gosh(session, new
String[]{"--login"});
}
@Override