Clean up a bit
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1736006 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Activator.java b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Activator.java
index ca19dd2..d9312a9 100644
--- a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Activator.java
+++ b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Activator.java
@@ -25,7 +25,6 @@
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 @@
private ExecutorService executor;
public Activator() {
- regs = new HashSet<ServiceRegistration>();
+ regs = new HashSet<>();
}
public void start(BundleContext context) throws Exception {
@@ -87,7 +86,7 @@
}
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 @@
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));
}
diff --git a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Builtin.java b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Builtin.java
index 91dcf17..8b4556f 100644
--- a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Builtin.java
+++ b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Builtin.java
@@ -20,8 +20,11 @@
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.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 @@
"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 @@
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()]));
+ }
+ }
+ }
+ }
+
}
diff --git a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Highlighter.java b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Highlighter.java
index 7617f7b..655bab9 100644
--- a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Highlighter.java
+++ b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Highlighter.java
@@ -103,7 +103,6 @@
break;
}
if (token.start() > cur) {
-// ansi.a(buffer.substring(cur, token.start()));
cur = token.start();
}
// Find corresponding statement
@@ -153,37 +152,6 @@
}
}
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());
}
diff --git a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/IoUtils.java b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/IoUtils.java
deleted file mode 100644
index 9f14b96..0000000
--- a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/IoUtils.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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.felix.gogo.jline;
-
-import java.io.File;
-import java.nio.file.LinkOption;
-import java.nio.file.attribute.PosixFilePermission;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.sshd.common.util.OsUtils;
-
-/**
- * TODO Add javadoc
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public final class IoUtils {
-
- public static final LinkOption[] EMPTY_LINK_OPTIONS = new LinkOption[0];
-
- public static final List<String> WINDOWS_EXECUTABLE_EXTENSIONS = Collections.unmodifiableList(Arrays.asList(".bat", ".exe", ".cmd"));
-
- private static final LinkOption[] NO_FOLLOW_OPTIONS = new LinkOption[]{LinkOption.NOFOLLOW_LINKS};
-
- /**
- * Private Constructor
- */
- private IoUtils() {
- throw new UnsupportedOperationException("No instance allowed");
- }
-
- public 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}
- */
- public 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 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)
- */
- public 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;
- }
-
-}
diff --git a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/JLineCommands.java b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/JLineCommands.java
deleted file mode 100644
index 807c319..0000000
--- a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/JLineCommands.java
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * 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.felix.gogo.jline;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.nio.file.Files;
-import java.nio.file.LinkOption;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.felix.gogo.jline.Shell.Context;
-import org.apache.felix.gogo.runtime.CommandSessionImpl;
-import org.apache.felix.service.command.CommandProcessor;
-import org.apache.felix.service.command.CommandSession;
-import org.apache.felix.service.command.Function;
-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 org.jline.reader.impl.completer.completer.FileNameCompleter;
-import org.jline.terminal.Attributes;
-import org.jline.terminal.Terminal;
-import org.jline.utils.InfoCmp.Capability;
-
-public class JLineCommands {
-
- public static final String[] functions = {
- "keymap", "setopt", "unsetopt", "complete", "history",
- "less", "watch", "nano", "widget", "tmux",
- "__files", "__directories", "__usage_completion"
- };
-
- private final CommandProcessor processor;
-
- private final org.jline.builtins.Commands commands = new org.jline.builtins.Commands();
-
- public JLineCommands(CommandProcessor processor) {
- this.processor = processor;
- }
-
- public 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, terminal).gosh(newSession, new String[]{"--login"});
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- try {
- terminal.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
-
- public void nano(final CommandSession session, String[] argv) throws Exception {
- commands.nano(Shell.getTerminal(session), System.out, System.err, session.currentDir(), argv);
- }
-
- public 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();
- }
- }
-
- public void less(CommandSession session, String[] argv) throws IOException, InterruptedException {
- commands.less(Shell.getTerminal(session), System.out, System.err, session.currentDir(), argv);
- }
-
- 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()]));
- }
- }
- }
- }
-
-}
diff --git a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/JLineCompletionEnvironment.java b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/JLineCompletionEnvironment.java
deleted file mode 100644
index 93b31ef..0000000
--- a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/JLineCompletionEnvironment.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.felix.gogo.jline;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.felix.service.command.CommandSession;
-import org.jline.builtins.Completers.CompletionData;
-import org.jline.builtins.Completers.CompletionEnvironment;
-import org.jline.reader.LineReader;
-import org.jline.reader.ParsedLine;
-
-public class JLineCompletionEnvironment implements CompletionEnvironment {
-
- private final CommandSession session;
-
- public JLineCompletionEnvironment(CommandSession session) {
- this.session = session;
- }
-
- public Map<String, List<CompletionData>> getCompletions() {
- return Shell.getCompletions(session);
- }
-
- public Set<String> getCommands() {
- return Shell.getCommands(session);
- }
-
- public String resolveCommand(String command) {
- return Shell.resolve(session, command);
- }
-
- public String commandName(String command) {
- int idx = command.indexOf(':');
- return idx >= 0 ? command.substring(idx + 1) : command;
- }
-
- public Object evaluate(LineReader reader, ParsedLine line, String func) throws Exception {
- session.put(Shell.VAR_COMMAND_LINE, line);
- return session.execute(func);
- }
-}
diff --git a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Main.java b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Main.java
index 53fc716..8064192 100644
--- a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Main.java
+++ b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Main.java
@@ -49,15 +49,14 @@
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) {
diff --git a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ParsedLineImpl.java b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ParsedLineImpl.java
index 22f0cdc..fb122a6 100644
--- a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ParsedLineImpl.java
+++ b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ParsedLineImpl.java
@@ -38,7 +38,7 @@
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());
}
diff --git a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java
index d523a32..09cd5f1 100644
--- a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java
+++ b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java
@@ -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.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.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 @@
* 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 @@
}
}
+ 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 @@
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 @@
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 @@
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 @@
}
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 @@
}
}
}
- return n1 - n2;
+ return end1 - end2;
}
protected int[] getSortKey(String str, List<Integer> fields, Key key) {
@@ -882,7 +1116,6 @@
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 @@
}
}
- 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 @@
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;
- }
-
}
diff --git a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Procedural.java b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Procedural.java
index 0311f1b..d1bf87e 100644
--- a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Procedural.java
+++ b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Procedural.java
@@ -26,13 +26,13 @@
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 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 @@
return false;
if (result instanceof Boolean)
- return ((Boolean) result).booleanValue();
+ return (Boolean) result;
if (result instanceof Number) {
if (0 == ((Number) result).intValue())
diff --git a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java
index 740242d..81c612d 100644
--- a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java
+++ b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java
@@ -53,6 +53,7 @@
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 @@
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 @@
}
// 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 @@
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 @@
while (true) {
Job job = session.foregroundJob();
if (job != null) {
+ //noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (job) {
if (job.status() == Status.Foreground) {
job.wait();
@@ -420,6 +444,7 @@
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 @@
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 @@
}
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 @@
@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 @@
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];
diff --git a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellFactoryImpl.java b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellFactoryImpl.java
index ad0cc8d..ed717e2 100644
--- a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellFactoryImpl.java
+++ b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellFactoryImpl.java
@@ -257,7 +257,7 @@
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();
}
diff --git a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/Telnet.java b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/Telnet.java
index 7bba28b..f4d6537 100644
--- a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/Telnet.java
+++ b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/Telnet.java
@@ -178,7 +178,7 @@
close();
}
};
- new Shell(context, processor, terminal).gosh(session, new String[]{"--login"});
+ new Shell(context, processor).gosh(session, new String[]{"--login"});
}
@Override