You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by gn...@apache.org on 2016/03/21 17:53:07 UTC
svn commit: r1735995 [2/4] - in /felix/trunk/gogo: ./ jline/ jline/doc/
jline/src/ jline/src/main/ jline/src/main/java/ jline/src/main/java/org/
jline/src/main/java/org/apache/ jline/src/main/java/org/apache/felix/
jline/src/main/java/org/apache/felix/...
Added: 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=1735995&view=auto
==============================================================================
--- felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Main.java (added)
+++ felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Main.java Mon Mar 21 16:53:06 2016
@@ -0,0 +1,113 @@
+/*
+ * 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.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+
+import org.apache.felix.gogo.jline.Shell.Context;
+import org.apache.felix.gogo.jline.ssh.Ssh;
+import org.apache.felix.gogo.jline.telnet.Telnet;
+import org.apache.felix.gogo.runtime.CommandProcessorImpl;
+import org.apache.felix.gogo.runtime.threadio.ThreadIOImpl;
+import org.apache.felix.service.command.CommandSession;
+import org.jline.terminal.Terminal;
+import org.jline.terminal.TerminalBuilder;
+
+public class Main {
+
+ public static void main(String[] args) throws IOException {
+ InputStream sin = System.in;
+ PrintStream sout = System.out;
+ PrintStream serr = System.err;
+
+ try (Terminal terminal = TerminalBuilder.builder()
+ .name("gogo")
+ .type(System.getenv("TERM"))
+ .system(true)
+ .streams(sin, sout)
+ .build()) {
+ ThreadIOImpl tio = new ThreadIOImpl();
+ tio.start();
+ try {
+ CommandProcessorImpl processor = new CommandProcessorImpl(tio);
+ Context context = new MyContext();
+ Shell shell = new Shell(context, processor, terminal);
+ 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, shell, Shell.functions);
+ register(processor, new JLineCommands(processor), JLineCommands.functions);
+ try {
+ register(processor, new Telnet(processor), Telnet.functions);
+ } catch (Throwable t) {
+ // ignore
+ }
+ try {
+ register(processor, new Ssh(processor), Ssh.functions);
+ } catch (Throwable t) {
+ // ignore
+ }
+ PrintStream pout = new PrintStream(terminal.output());
+ CommandSession session = processor.createSession(terminal.input(), pout, pout);
+ session.put(Shell.VAR_CONTEXT, context);
+ session.put(Shell.VAR_TERMINAL, terminal);
+ try {
+ String[] argv = new String[args.length + 1];
+ argv[0] = "--login";
+ System.arraycopy(args, 0, argv, 1, args.length);
+ shell.gosh(session, argv);
+ } catch (Exception e) {
+ Object loc = session.get(".location");
+ if (null == loc || !loc.toString().contains(":")) {
+ loc = "gogo";
+ }
+
+ System.err.println(loc + ": " + e.getClass().getSimpleName() + ": " + e.getMessage());
+ e.printStackTrace();
+ } finally {
+ session.close();
+ }
+ } finally {
+ tio.stop();
+ }
+ }
+ }
+
+ static void register(CommandProcessorImpl processor, Object target, String[] functions) {
+ for (String function : functions) {
+ processor.addCommand("gogo", target, function);
+ }
+ }
+
+ private static class MyContext implements Context {
+
+ public String getProperty(String name) {
+ return System.getProperty(name);
+ }
+
+ public void exit() throws Exception {
+ System.exit(0);
+ }
+ }
+}
Added: 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=1735995&view=auto
==============================================================================
--- felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ParsedLineImpl.java (added)
+++ felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ParsedLineImpl.java Mon Mar 21 16:53:06 2016
@@ -0,0 +1,97 @@
+/*
+ * 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.ArrayList;
+import java.util.List;
+
+import org.apache.felix.gogo.runtime.Parser.Program;
+import org.apache.felix.gogo.runtime.Token;
+import org.jline.reader.ParsedLine;
+
+public class ParsedLineImpl implements ParsedLine {
+
+ private final Program program;
+ private final String source;
+ private final int cursor;
+ private final List<String> tokens;
+ private final int wordIndex;
+ private final int wordCursor;
+
+ public ParsedLineImpl(Program program, Token line, int cursor, List<Token> tokens) {
+ this.program = program;
+ this.source = line.toString();
+ this.cursor = cursor - line.start();
+ this.tokens = new ArrayList<String>();
+ for (Token token : tokens) {
+ this.tokens.add(token.toString());
+ }
+ int wi = tokens.size();
+ int wc = 0;
+ if (cursor >= 0) {
+ for (int i = 0; i < tokens.size(); i++) {
+ Token t = tokens.get(i);
+ if (t.start() > cursor) {
+ wi = i;
+ wc = 0;
+ this.tokens.add(i, "");
+ break;
+ }
+ if (t.start() + t.length() >= cursor) {
+ wi = i;
+ wc = cursor - t.start();
+ break;
+ }
+ }
+ }
+ if (wi == tokens.size()) {
+ this.tokens.add("");
+ }
+ wordIndex = wi;
+ wordCursor = wc;
+ }
+
+ public String word() {
+ return tokens.get(wordIndex());
+ }
+
+ public int wordCursor() {
+ return wordCursor;
+ }
+
+ public int wordIndex() {
+ return wordIndex;
+ }
+
+ public List<String> words() {
+ return tokens;
+ }
+
+ public String line() {
+ return source;
+ }
+
+ public int cursor() {
+ return cursor;
+ }
+
+ public Program program() {
+ return program;
+ }
+}
Added: felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Parser.java
URL: http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Parser.java?rev=1735995&view=auto
==============================================================================
--- felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Parser.java (added)
+++ felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Parser.java Mon Mar 21 16:53:06 2016
@@ -0,0 +1,71 @@
+/*
+ * 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.Collections;
+import java.util.List;
+
+import org.apache.felix.gogo.runtime.EOFError;
+import org.apache.felix.gogo.runtime.Parser.Program;
+import org.apache.felix.gogo.runtime.Parser.Statement;
+import org.apache.felix.gogo.runtime.SyntaxError;
+import org.apache.felix.gogo.runtime.Token;
+import org.jline.reader.ParsedLine;
+
+public class Parser implements org.jline.reader.Parser {
+
+ public ParsedLine parse(String line, int cursor) throws org.jline.reader.SyntaxError {
+ try {
+ return doParse(line, cursor);
+ } catch (EOFError e) {
+ throw new org.jline.reader.EOFError(e.line(), e.column(), e.getMessage(), e.missing());
+ } catch (SyntaxError e) {
+ throw new org.jline.reader.SyntaxError(e.line(), e.column(), e.getMessage());
+ }
+ }
+
+ private ParsedLine doParse(CharSequence line, int cursor) throws SyntaxError {
+ org.apache.felix.gogo.runtime.Parser parser = new org.apache.felix.gogo.runtime.Parser(line);
+ Program program = parser.program();
+ List<Statement> statements = parser.statements();
+ // Find corresponding statement
+ Statement statement = null;
+ for (int i = statements.size() - 1; i >= 0; i--) {
+ Statement s = statements.get(i);
+ if (s.start() <= cursor) {
+ boolean isOk = true;
+ // check if there are only spaces after the previous statement
+ if (s.start() + s.length() < cursor) {
+ for (int j = s.start() + s.length(); isOk && j < cursor; j++) {
+ isOk = Character.isWhitespace(line.charAt(j));
+ }
+ }
+ statement = s;
+ break;
+ }
+ }
+ if (statement != null) {
+ return new ParsedLineImpl(program, statement, cursor, statement.tokens());
+ } else {
+ // TODO:
+ return new ParsedLineImpl(program, program, cursor, Collections.<Token>singletonList(program));
+ }
+ }
+
+}
Added: 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=1735995&view=auto
==============================================================================
--- felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java (added)
+++ felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java Mon Mar 21 16:53:06 2016
@@ -0,0 +1,816 @@
+/*
+ * 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.BufferedReader;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.felix.service.command.CommandSession;
+import org.jline.builtins.Options;
+
+/**
+ * Posix-like utilities.
+ *
+ * @see <a href="http://www.opengroup.org/onlinepubs/009695399/utilities/contents.html">
+ * 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 CWD = "_cwd";
+
+ public static File _pwd(CommandSession session) {
+ try {
+ File cwd = (File) session.get(CWD);
+ if (cwd == null) {
+ cwd = new File(".").getCanonicalFile();
+ session.put(CWD, cwd);
+ }
+ return cwd;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static void sort(CommandSession session, String[] argv) throws IOException {
+ final String[] usage = {
+ "sort - writes sorted standard input to standard output.",
+ "Usage: sort [OPTIONS] [FILES]",
+ " -? --help show help",
+ " -f --ignore-case fold lower case to upper case characters",
+ " -r --reverse reverse the result of comparisons",
+ " -u --unique output only the first of an equal run",
+ " -t --field-separator=SEP use SEP instead of non-blank to blank transition",
+ " -b --ignore-leading-blanks ignore leading blancks",
+ " --numeric-sort compare according to string numerical value",
+ " -k --key=KEY fields to use for sorting separated by whitespaces"};
+
+ Options opt = Options.compile(usage).parse(argv);
+
+ if (opt.isSet("help")) {
+ opt.usage(System.err);
+ return;
+ }
+
+ List<String> args = opt.args();
+
+ List<String> lines = new ArrayList<String>();
+ if (!args.isEmpty()) {
+ for (String filename : args) {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(
+ Shell.cwd(session).resolve(filename).toURL().openStream()));
+ try {
+ read(reader, lines);
+ } finally {
+ reader.close();
+ }
+ }
+ } else {
+ BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
+ read(r, lines);
+ }
+
+ String separator = opt.get("field-separator");
+ boolean caseInsensitive = opt.isSet("ignore-case");
+ boolean reverse = opt.isSet("reverse");
+ boolean ignoreBlanks = opt.isSet("ignore-leading-blanks");
+ boolean numeric = opt.isSet("numeric-sort");
+ boolean unique = opt.isSet("unique");
+ List<String> sortFields = opt.getList("key");
+
+ char sep = (separator == null || separator.length() == 0) ? '\0' : separator.charAt(0);
+ Collections.sort(lines, new SortComparator(caseInsensitive, reverse, ignoreBlanks, numeric, sep, sortFields));
+ String last = null;
+ for (String s : lines) {
+ if (!unique || last == null || !s.equals(last)) {
+ System.out.println(s);
+ }
+ last = s;
+ }
+ }
+
+ protected static void read(BufferedReader r, List<String> lines) throws IOException {
+ for (String s = r.readLine(); s != null; s = r.readLine()) {
+ lines.add(s);
+ }
+ }
+
+ public static List<String> parseSubstring(String value) {
+ List<String> pieces = new ArrayList<String>();
+ StringBuilder ss = new StringBuilder();
+ // int kind = SIMPLE; // assume until proven otherwise
+ boolean wasStar = false; // indicates last piece was a star
+ boolean leftstar = false; // track if the initial piece is a star
+ boolean rightstar = false; // track if the final piece is a star
+
+ int idx = 0;
+
+ // We assume (sub)strings can contain leading and trailing blanks
+ boolean escaped = false;
+ loop:
+ for (; ; ) {
+ if (idx >= value.length()) {
+ if (wasStar) {
+ // insert last piece as "" to handle trailing star
+ rightstar = true;
+ } else {
+ pieces.add(ss.toString());
+ // accumulate the last piece
+ // note that in the case of
+ // (cn=); this might be
+ // the string "" (!=null)
+ }
+ ss.setLength(0);
+ break loop;
+ }
+
+ // Read the next character and account for escapes.
+ char c = value.charAt(idx++);
+ if (!escaped && ((c == '(') || (c == ')'))) {
+ throw new IllegalArgumentException(
+ "Illegal value: " + value);
+ } else if (!escaped && (c == '*')) {
+ if (wasStar) {
+ // encountered two successive stars;
+ // I assume this is illegal
+ throw new IllegalArgumentException("Invalid filter string: " + value);
+ }
+ if (ss.length() > 0) {
+ pieces.add(ss.toString()); // accumulate the pieces
+ // between '*' occurrences
+ }
+ ss.setLength(0);
+ // if this is a leading star, then track it
+ if (pieces.size() == 0) {
+ leftstar = true;
+ }
+ wasStar = true;
+ } else if (!escaped && (c == '\\')) {
+ escaped = true;
+ } else {
+ escaped = false;
+ wasStar = false;
+ ss.append(c);
+ }
+ }
+ if (leftstar || rightstar || pieces.size() > 1) {
+ // insert leading and/or trailing "" to anchor ends
+ if (rightstar) {
+ pieces.add("");
+ }
+ if (leftstar) {
+ pieces.add(0, "");
+ }
+ }
+ return pieces;
+ }
+
+ public static boolean compareSubstring(List<String> pieces, String s) {
+ // Walk the pieces to match the string
+ // There are implicit stars between each piece,
+ // and the first and last pieces might be "" to anchor the match.
+ // assert (pieces.length > 1)
+ // minimal case is <string>*<string>
+
+ boolean result = true;
+ int len = pieces.size();
+
+ int index = 0;
+
+ loop:
+ for (int i = 0; i < len; i++) {
+ String piece = pieces.get(i);
+
+ // If this is the first piece, then make sure the
+ // string starts with it.
+ if (i == 0) {
+ if (!s.startsWith(piece)) {
+ result = false;
+ break loop;
+ }
+ }
+
+ // If this is the last piece, then make sure the
+ // string ends with it.
+ if (i == len - 1) {
+ if (s.endsWith(piece)) {
+ result = true;
+ } else {
+ result = false;
+ }
+ break loop;
+ }
+
+ // If this is neither the first or last piece, then
+ // make sure the string contains it.
+ if ((i > 0) && (i < (len - 1))) {
+ index = s.indexOf(piece, index);
+ if (index < 0) {
+ result = false;
+ break loop;
+ }
+ }
+
+ // Move string index beyond the matching piece.
+ index += piece.length();
+ }
+
+ return result;
+ }
+
+ private static void cat(final BufferedReader reader, boolean displayLineNumbers) throws IOException {
+ String line;
+ int lineno = 1;
+ try {
+ while ((line = reader.readLine()) != null) {
+ if (displayLineNumbers) {
+ System.out.print(String.format("%6d ", lineno++));
+ }
+ System.out.println(line);
+ }
+ } finally {
+ reader.close();
+ }
+ }
+
+ private static <T> void addAll(List<? super T> list, T[] array) {
+ if (array != null) {
+ Collections.addAll(list, array);
+ }
+ }
+
+ public File pwd(CommandSession session, String[] argv) throws IOException {
+ final String[] usage = {
+ "pwd - get current directory",
+ "Usage: pwd [OPTIONS]",
+ " -? --help show help"
+ };
+ Options opt = Options.compile(usage).parse(argv);
+ if (opt.isSet("help")) {
+ opt.usage(System.err);
+ return null;
+ }
+ if (!opt.args().isEmpty()) {
+ System.err.println("usage: pwd");
+ return null;
+ }
+ File cwd = (File) session.get(CWD);
+ if (cwd == null) {
+ cwd = new File(".").getCanonicalFile();
+ session.put(CWD, cwd);
+ }
+ return cwd;
+ }
+
+ public File cd(CommandSession session, String[] argv)
+ throws IOException {
+ final String[] usage = {
+ "cd - get current directory",
+ "Usage: cd [OPTIONS] DIRECTORY",
+ " -? --help show help"
+ };
+ Options opt = Options.compile(usage).parse(argv);
+ if (opt.isSet("help")) {
+ opt.usage(System.err);
+ return null;
+ }
+ if (opt.args().size() != 1) {
+ System.err.println("usage: cd DIRECTORY");
+ return null;
+ }
+ File cwd = pwd(session, new String[0]);
+ String dir = opt.args().get(0);
+
+ URI curUri = cwd.toURI();
+ URI newUri = curUri.resolve(dir);
+
+ cwd = new File(newUri);
+ if (!cwd.exists()) {
+ throw new IOException("Directory does not exist");
+ } else if (!cwd.isDirectory()) {
+ throw new IOException("Target is not a directory");
+ }
+ session.put(CWD, cwd.getCanonicalFile());
+ return cwd;
+ }
+
+ public Collection<File> ls(CommandSession session, String[] argv) throws IOException {
+ final String[] usage = {
+ "ls - list files",
+ "Usage: ls [OPTIONS] PATTERNS...",
+ " -? --help show help"
+ };
+ Options opt = Options.compile(usage).parse(argv);
+ if (opt.isSet("help")) {
+ opt.usage(System.err);
+ return null;
+ }
+ if (opt.args().isEmpty()) {
+ opt.args().add("*");
+ }
+ opt.args().remove(0);
+ List<File> files = new ArrayList<File>();
+ for (String pattern : opt.args()) {
+ pattern = ((pattern == null) || (pattern.length() == 0)) ? "." : pattern;
+ pattern = ((pattern.charAt(0) != File.separatorChar) && (pattern.charAt(0) != '.'))
+ ? "./" + pattern : pattern;
+ int idx = pattern.lastIndexOf(File.separatorChar);
+ String parent = (idx < 0) ? "." : pattern.substring(0, idx + 1);
+ String target = (idx < 0) ? pattern : pattern.substring(idx + 1);
+
+ File actualParent = ((parent.charAt(0) == File.separatorChar)
+ ? new File(parent)
+ : new File(pwd(session, new String[0]), parent)).getCanonicalFile();
+
+ idx = target.indexOf(File.separatorChar, idx);
+ boolean isWildcarded = (target.indexOf('*', idx) >= 0);
+ if (isWildcarded) {
+ if (!actualParent.exists()) {
+ throw new IOException("File does not exist");
+ }
+ final List<String> pieces = parseSubstring(target);
+ addAll(files, actualParent.listFiles(new FileFilter() {
+ public boolean accept(File pathname) {
+ return compareSubstring(pieces, pathname.getName());
+ }
+ }));
+ } else {
+ File actualTarget = new File(actualParent, target).getCanonicalFile();
+ if (!actualTarget.exists()) {
+ throw new IOException("File does not exist");
+ }
+ if (actualTarget.isDirectory()) {
+ addAll(files, actualTarget.listFiles());
+ } else {
+ files.add(actualTarget);
+ }
+ }
+ }
+ return files;
+ }
+
+ public void cat(CommandSession session, String[] argv) throws Exception {
+ final String[] usage = {
+ "cat - concatenate and print FILES",
+ "Usage: cat [OPTIONS] [FILES]",
+ " -? --help show help",
+ " -n number the output lines, starting at 1"
+ };
+
+ Options opt = Options.compile(usage).parse(argv);
+
+ if (opt.isSet("help")) {
+ opt.usage(System.err);
+ return;
+ }
+
+ List<String> args = opt.args();
+ if (args.isEmpty()) {
+ args = Collections.singletonList("-");
+ }
+
+ URI cwd = Shell.cwd(session);
+ for (String arg : args) {
+ InputStream is;
+ if ("-".equals(arg)) {
+ is = System.in;
+
+ } else {
+ is = cwd.resolve(arg).toURL().openStream();
+ }
+ cat(new BufferedReader(new InputStreamReader(is)), opt.isSet("n"));
+ }
+ }
+
+ public void echo(Object[] argv) {
+ final String[] usage = {
+ "echo - echoes or prints ARGUMENT to standard output",
+ "Usage: echo [OPTIONS] [ARGUMENTS]",
+ " -? --help show help",
+ " -n no trailing new line"
+ };
+
+ Options opt = Options.compile(usage).parse(argv);
+
+ if (opt.isSet("help")) {
+ opt.usage(System.err);
+ return;
+ }
+
+ List<String> args = opt.args();
+ StringBuilder buf = new StringBuilder();
+ if (args != null) {
+ for (String arg : args) {
+ if (buf.length() > 0)
+ buf.append(' ');
+ buf.append(arg);
+ }
+ }
+ if (opt.isSet("n")) {
+ System.out.print(buf);
+ } else {
+ System.out.println(buf);
+ }
+ }
+
+ public boolean grep(CommandSession session, String[] argv) throws IOException {
+ final String[] usage = {
+ "grep - search for PATTERN in each FILE or standard input.",
+ "Usage: grep [OPTIONS] PATTERN [FILES]",
+ " -? --help show help",
+ " -i --ignore-case ignore case distinctions",
+ " -n --line-number prefix each line with line number within its input file",
+ " -q --quiet, --silent suppress all normal output",
+ " -v --invert-match select non-matching lines"};
+
+ Options opt = Options.compile(usage).parse(argv);
+
+ if (opt.isSet("help")) {
+ opt.usage(System.err);
+ return true;
+ }
+
+ List<String> args = opt.args();
+
+ if (args.isEmpty()) {
+ throw opt.usageError("no pattern supplied.");
+ }
+
+ String regex = args.remove(0);
+ if (opt.isSet("ignore-case")) {
+ regex = "(?i)" + regex;
+ }
+
+ if (args.isEmpty()) {
+ args.add(null);
+ }
+
+ StringBuilder buf = new StringBuilder();
+
+ if (args.size() > 1) {
+ buf.append("%1$s:");
+ }
+
+ if (opt.isSet("line-number")) {
+ buf.append("%2$s:");
+ }
+
+ buf.append("%3$s");
+ String format = buf.toString();
+
+ Pattern pattern = Pattern.compile(regex);
+ boolean status = true;
+ boolean match = false;
+
+ for (String arg : args) {
+ InputStream in = null;
+
+ try {
+ URI cwd = Shell.cwd(session);
+ in = (arg == null) ? System.in : cwd.resolve(arg).toURL().openStream();
+
+ BufferedReader rdr = new BufferedReader(new InputStreamReader(in));
+ int line = 0;
+ String s;
+ while ((s = rdr.readLine()) != null) {
+ line++;
+ Matcher matcher = pattern.matcher(s);
+ if (!(matcher.find() ^ !opt.isSet("invert-match"))) {
+ match = true;
+ if (opt.isSet("quiet"))
+ break;
+
+ System.out.println(String.format(format, arg, line, s));
+ }
+ }
+
+ if (match && opt.isSet("quiet")) {
+ break;
+ }
+ } catch (IOException e) {
+ System.err.println("grep: " + e.getMessage());
+ status = false;
+ } finally {
+ if (arg != null && in != null) {
+ in.close();
+ }
+ }
+ }
+
+ return match && status;
+ }
+
+ public void sleep(String[] argv) throws InterruptedException {
+ final String[] usage = {
+ "sleep - suspend execution for an interval of time",
+ "Usage: sleep seconds",
+ " -? --help show help"};
+
+ Options opt = Options.compile(usage).parse(argv);
+
+ if (opt.isSet("help")) {
+ opt.usage(System.err);
+ return;
+ }
+
+ List<String> args = opt.args();
+ if (args.size() != 1) {
+ System.err.println("usage: sleep seconds");
+ } else {
+ int s = Integer.parseInt(args.get(0));
+ Thread.sleep(s * 1000);
+ }
+ }
+
+ public static class SortComparator implements Comparator<String> {
+
+ private static Pattern fpPattern;
+
+ static {
+ final String Digits = "(\\p{Digit}+)";
+ final String HexDigits = "(\\p{XDigit}+)";
+ final String Exp = "[eE][+-]?" + Digits;
+ final String fpRegex = "([\\x00-\\x20]*[+-]?(NaN|Infinity|(((" + Digits + "(\\.)?(" + Digits + "?)(" + Exp + ")?)|(\\.(" + Digits + ")(" + Exp + ")?)|(((0[xX]" + HexDigits + "(\\.)?)|(0[xX]" + HexDigits + "?(\\.)" + HexDigits + "))[pP][+-]?" + Digits + "))" + "[fFdD]?))[\\x00-\\x20]*)(.*)";
+ fpPattern = Pattern.compile(fpRegex);
+ }
+
+ private boolean caseInsensitive;
+ private boolean reverse;
+ private boolean ignoreBlanks;
+ private boolean numeric;
+ private char separator;
+ private List<Key> sortKeys;
+
+ public SortComparator(boolean caseInsensitive,
+ boolean reverse,
+ boolean ignoreBlanks,
+ boolean numeric,
+ char separator,
+ List<String> sortFields) {
+ this.caseInsensitive = caseInsensitive;
+ this.reverse = reverse;
+ this.separator = separator;
+ this.ignoreBlanks = ignoreBlanks;
+ this.numeric = numeric;
+ if (sortFields == null || sortFields.size() == 0) {
+ sortFields = new ArrayList<String>();
+ sortFields.add("1");
+ }
+ sortKeys = new ArrayList<Key>();
+ for (String f : sortFields) {
+ sortKeys.add(new Key(f));
+ }
+ }
+
+ public int compare(String o1, String o2) {
+ int res = 0;
+
+ List<Integer> fi1 = getFieldIndexes(o1);
+ List<Integer> fi2 = getFieldIndexes(o2);
+ for (Key key : sortKeys) {
+ int[] k1 = getSortKey(o1, fi1, key);
+ int[] k2 = getSortKey(o2, fi2, key);
+ if (key.numeric) {
+ Double d1 = getDouble(o1, k1[0], k1[1]);
+ Double d2 = getDouble(o2, k2[0], k2[1]);
+ res = d1.compareTo(d2);
+ } else {
+ res = compareRegion(o1, k1[0], k1[1], o2, k2[0], k2[1], key.caseInsensitive);
+ }
+ if (res != 0) {
+ if (key.reverse) {
+ res = -res;
+ }
+ break;
+ }
+ }
+ return res;
+ }
+
+ protected Double getDouble(String s, int start, int end) {
+ Matcher m = fpPattern.matcher(s.substring(start, end));
+ m.find();
+ return new Double(s.substring(0, m.end(1)));
+ }
+
+ 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++) {
+ char c1 = s1.charAt(i1);
+ char c2 = s2.charAt(i2);
+ if (c1 != c2) {
+ if (caseInsensitive) {
+ c1 = Character.toUpperCase(c1);
+ c2 = Character.toUpperCase(c2);
+ if (c1 != c2) {
+ c1 = Character.toLowerCase(c1);
+ c2 = Character.toLowerCase(c2);
+ if (c1 != c2) {
+ return c1 - c2;
+ }
+ }
+ } else {
+ return c1 - c2;
+ }
+ }
+ }
+ return n1 - n2;
+ }
+
+ protected int[] getSortKey(String str, List<Integer> fields, Key key) {
+ int start;
+ int end;
+ if (key.startField * 2 <= fields.size()) {
+ start = fields.get((key.startField - 1) * 2);
+ if (key.ignoreBlanksStart) {
+ while (start < fields.get((key.startField - 1) * 2 + 1) && Character.isWhitespace(str.charAt(start))) {
+ start++;
+ }
+ }
+ if (key.startChar > 0) {
+ start = Math.min(start + key.startChar - 1, fields.get((key.startField - 1) * 2 + 1));
+ }
+ } else {
+ start = 0;
+ }
+ if (key.endField > 0 && key.endField * 2 <= fields.size()) {
+ end = fields.get((key.endField - 1) * 2);
+ if (key.ignoreBlanksEnd) {
+ while (end < fields.get((key.endField - 1) * 2 + 1) && Character.isWhitespace(str.charAt(end))) {
+ end++;
+ }
+ }
+ if (key.endChar > 0) {
+ end = Math.min(end + key.endChar - 1, fields.get((key.endField - 1) * 2 + 1));
+ }
+ } else {
+ end = str.length();
+ }
+ return new int[]{start, end};
+ }
+
+ protected List<Integer> getFieldIndexes(String o) {
+ List<Integer> fields = new ArrayList<Integer>();
+ 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))) {
+ fields.add(idx - 1);
+ fields.add(idx);
+ }
+ }
+ fields.add(o.length() - 1);
+ } else {
+ int last = -1;
+ for (int idx = o.indexOf(separator); idx >= 0; idx = o.indexOf(separator, idx + 1)) {
+ if (last >= 0) {
+ fields.add(last);
+ fields.add(idx - 1);
+ } else if (idx > 0) {
+ fields.add(0);
+ fields.add(idx - 1);
+ }
+ last = idx + 1;
+ }
+ if (last < o.length()) {
+ fields.add(last < 0 ? 0 : last);
+ fields.add(o.length() - 1);
+ }
+ }
+ }
+ return fields;
+ }
+
+ public class Key {
+ int startField;
+ int startChar;
+ int endField;
+ int endChar;
+ boolean ignoreBlanksStart;
+ boolean ignoreBlanksEnd;
+ boolean caseInsensitive;
+ boolean reverse;
+ boolean numeric;
+
+ public Key(String str) {
+ boolean modifiers = false;
+ boolean startPart = true;
+ boolean inField = true;
+ boolean inChar = false;
+ for (char c : str.toCharArray()) {
+ switch (c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (!inField && !inChar) {
+ throw new IllegalArgumentException("Bad field syntax: " + str);
+ }
+ if (startPart) {
+ if (inChar) {
+ startChar = startChar * 10 + (c - '0');
+ } else {
+ startField = startField * 10 + (c - '0');
+ }
+ } else {
+ if (inChar) {
+ endChar = endChar * 10 + (c - '0');
+ } else {
+ endField = endField * 10 + (c - '0');
+ }
+ }
+ break;
+ case '.':
+ if (!inField) {
+ throw new IllegalArgumentException("Bad field syntax: " + str);
+ }
+ inField = false;
+ inChar = true;
+ break;
+ case 'n':
+ inField = false;
+ inChar = false;
+ modifiers = true;
+ numeric = true;
+ break;
+ case 'f':
+ inField = false;
+ inChar = false;
+ modifiers = true;
+ caseInsensitive = true;
+ break;
+ case 'r':
+ inField = false;
+ inChar = false;
+ modifiers = true;
+ reverse = true;
+ break;
+ case 'b':
+ inField = false;
+ inChar = false;
+ modifiers = true;
+ if (startPart) {
+ ignoreBlanksStart = true;
+ } else {
+ ignoreBlanksEnd = true;
+ }
+ break;
+ case ',':
+ inField = true;
+ inChar = false;
+ startPart = false;
+ break;
+ default:
+ throw new IllegalArgumentException("Bad field syntax: " + str);
+ }
+ }
+ if (!modifiers) {
+ ignoreBlanksStart = ignoreBlanksEnd = SortComparator.this.ignoreBlanks;
+ reverse = SortComparator.this.reverse;
+ caseInsensitive = SortComparator.this.caseInsensitive;
+ numeric = SortComparator.this.numeric;
+ }
+ if (startField < 1) {
+ throw new IllegalArgumentException("Bad field syntax: " + str);
+ }
+ }
+ }
+ }
+
+}
Added: 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=1735995&view=auto
==============================================================================
--- felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Procedural.java (added)
+++ felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Procedural.java Mon Mar 21 16:53:06 2016
@@ -0,0 +1,149 @@
+/*
+ * 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.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.felix.service.command.CommandSession;
+import org.apache.felix.service.command.Function;
+
+public class Procedural {
+ 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>();
+ args.add(null);
+
+ for (Object x : list) {
+ checkInterrupt();
+ args.set(0, x);
+ results.add(closure.execute(session, args));
+ }
+
+ return results;
+ }
+
+ public Object _if(CommandSession session, Function[] fns) throws Exception {
+ int length = fns.length;
+ if (length < 2) {
+ throw new IllegalArgumentException(
+ "Usage: if {condition} {if-action} ... {else-action}");
+ }
+
+ for (int i = 0; i < length; ++i) {
+ if (i == length - 1 || isTrue(fns[i++].execute(session, null))) {
+ return fns[i].execute(session, null);
+ }
+ }
+
+ return null;
+ }
+
+ public boolean not(CommandSession session, Function condition) throws Exception {
+ if (null == condition) {
+ return true;
+ }
+
+ return !isTrue(condition.execute(session, null));
+ }
+
+ // Reflective.coerce() prefers to construct a new Throwable(String)
+ // than to call this method directly.
+ public void _throw(String message) {
+ throw new IllegalArgumentException(message);
+ }
+
+ public void _throw(Exception e) throws Exception {
+ throw e;
+ }
+
+ public void _throw(CommandSession session) throws Throwable {
+ Object exception = session.get("exception");
+ if (exception instanceof Throwable)
+ throw (Throwable) exception;
+ else
+ throw new IllegalArgumentException("exception not set or not Throwable.");
+ }
+
+ public Object _try(CommandSession session, Function func) throws Exception {
+ try {
+ return func.execute(session, null);
+ } catch (Exception e) {
+ session.put("exception", e);
+ return null;
+ }
+ }
+
+ public Object _try(CommandSession session, Function func, Function error)
+ throws Exception {
+ try {
+ return func.execute(session, null);
+ } catch (Exception e) {
+ session.put("exception", e);
+ return error.execute(session, null);
+ }
+ }
+
+ public void _while(CommandSession session, Function condition, Function ifTrue)
+ throws Exception {
+ while (isTrue(condition.execute(session, null))) {
+ ifTrue.execute(session, null);
+ }
+ }
+
+ public void until(CommandSession session, Function condition, Function ifTrue)
+ throws Exception {
+ while (!isTrue(condition.execute(session, null))) {
+ ifTrue.execute(session, null);
+ }
+ }
+
+ private boolean isTrue(Object result) throws InterruptedException {
+ checkInterrupt();
+
+ if (result == null)
+ return false;
+
+ if (result instanceof Boolean)
+ return ((Boolean) result).booleanValue();
+
+ if (result instanceof Number) {
+ if (0 == ((Number) result).intValue())
+ return false;
+ }
+
+ if ("".equals(result))
+ return false;
+
+ if ("0".equals(result))
+ return false;
+
+ return true;
+ }
+
+ private void checkInterrupt() throws InterruptedException {
+ if (Thread.currentThread().isInterrupted())
+ throw new InterruptedException("loop interrupted");
+ }
+}
Added: 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=1735995&view=auto
==============================================================================
--- felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java (added)
+++ felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java Mon Mar 21 16:53:06 2016
@@ -0,0 +1,537 @@
+/*
+ * 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.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.CharBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.apache.felix.gogo.runtime.Closure;
+import org.apache.felix.gogo.runtime.CommandProxy;
+import org.apache.felix.gogo.runtime.CommandSessionImpl;
+import org.apache.felix.gogo.runtime.Expander;
+import org.apache.felix.gogo.runtime.Reflective;
+import org.apache.felix.service.command.CommandProcessor;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.felix.service.command.Converter;
+import org.apache.felix.service.command.Descriptor;
+import org.apache.felix.service.command.Function;
+import org.apache.felix.service.command.Parameter;
+import org.jline.builtins.Completers.CompletionData;
+import org.jline.builtins.Options;
+import org.jline.reader.EndOfFileException;
+import org.jline.reader.LineReader;
+import org.jline.reader.LineReaderBuilder;
+import org.jline.reader.ParsedLine;
+import org.jline.reader.UserInterruptException;
+import org.jline.reader.impl.history.history.FileHistory;
+import org.jline.terminal.Terminal;
+
+public class Shell {
+
+ public static final String VAR_COMPLETIONS = ".completions";
+ public static final String VAR_COMMAND_LINE = ".commandLine";
+ public static final String VAR_READER = ".reader";
+ public static final String VAR_SESSION = ".session";
+ public static final String VAR_PROCESSOR = ".processor";
+ public static final String VAR_TERMINAL = ".terminal";
+ public static final String VAR_EXCEPTION = "exception";
+ public static final String VAR_LOCATION = ".location";
+ public static final String VAR_PROMPT = "prompt";
+ public static final String VAR_RPROMPT = "rprompt";
+ public static final String VAR_SCOPE = "SCOPE";
+ public static final String VAR_CONTEXT = org.apache.felix.gogo.runtime.activator.Activator.CONTEXT;
+
+ static final String[] functions = {"gosh", "sh", "source", "help"};
+
+ private final URI baseURI;
+ private final String profile;
+ 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, Terminal terminal, String profile) {
+ this.context = context;
+ this.processor = processor;
+ String baseDir = context.getProperty("gosh.home");
+ baseDir = (baseDir == null) ? context.getProperty("user.dir") : baseDir;
+ this.baseURI = new File(baseDir).toURI();
+ this.profile = profile != null ? profile : "gosh_profile";
+ }
+
+ public static Terminal getTerminal(CommandSession session) {
+ return (Terminal) session.get(VAR_TERMINAL);
+ }
+
+ public static LineReader getReader(CommandSession session) {
+ return (LineReader) session.get(VAR_READER);
+ }
+
+ public static CommandProcessor getProcessor(CommandSession session) {
+ return (CommandProcessor) session.get(VAR_PROCESSOR);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Map<String, List<CompletionData>> getCompletions(CommandSession session) {
+ return (Map) session.get(VAR_COMPLETIONS);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Set<String> getCommands(CommandSession session) {
+ return (Set<String>) session.get(CommandSessionImpl.COMMANDS);
+ }
+
+ public static ParsedLine getParsedLine(CommandSession session) {
+ return (ParsedLine) session.get(VAR_COMMAND_LINE);
+ }
+
+ public static String getPrompt(CommandSession session) {
+ return expand(session, VAR_PROMPT, "gl! ");
+ }
+
+ public static String getRPrompt(CommandSession session) {
+ return expand(session, VAR_RPROMPT, null);
+ }
+
+ public static String expand(CommandSession session, String name, String def) {
+ Object prompt = session.get(name);
+ if (prompt != null) {
+ try {
+ Object o = Expander.expand(
+ prompt.toString(),
+ new Closure((CommandSessionImpl) session, null, null));
+ if (o != null) {
+ return o.toString();
+ }
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ return def;
+ }
+
+ public static String resolve(CommandSession session, String command) {
+ String resolved = command;
+ if (command.indexOf(':') < 0) {
+ Set<String> commands = getCommands(session);
+ Object path = session.get(VAR_SCOPE);
+ String scopePath = (null == path ? "*" : path.toString());
+ for (String scope : scopePath.split(":")) {
+ for (String entry : commands) {
+ if ("*".equals(scope) && entry.endsWith(":" + command)
+ || entry.equals(scope + ":" + command)) {
+ resolved = entry;
+ break;
+ }
+ }
+ }
+ }
+ return resolved;
+ }
+
+ public static CharSequence readScript(URI script) throws Exception {
+ URLConnection conn = script.toURL().openConnection();
+ int length = conn.getContentLength();
+
+ if (length == -1) {
+ System.err.println("eek! unknown Contentlength for: " + script);
+ length = 10240;
+ }
+
+ InputStream in = conn.getInputStream();
+ CharBuffer cbuf = CharBuffer.allocate(length);
+ Reader reader = new InputStreamReader(in);
+ reader.read(cbuf);
+ in.close();
+ cbuf.rewind();
+
+ return cbuf;
+ }
+
+ @SuppressWarnings("unchecked")
+ static Set<String> getVariables(CommandSession session) {
+ return (Set<String>) session.get(".variables");
+ }
+
+ static URI cwd(CommandSession session) {
+ return Posix._pwd(session).toURI(); // _cwd is set by felixcommands:cd
+ }
+
+ private static <T extends Annotation> T findAnnotation(Annotation[] anns,
+ Class<T> clazz) {
+ for (int i = 0; (anns != null) && (i < anns.length); i++) {
+ if (clazz.isInstance(anns[i])) {
+ return clazz.cast(anns[i]);
+ }
+ }
+ return null;
+ }
+
+ public Object gosh(final CommandSession session, String[] argv) throws Exception {
+ final String[] usage = {
+ "gosh - execute script with arguments in a new session",
+ " args are available as session variables $1..$9 and $args.",
+ "Usage: gosh [OPTIONS] [script-file [args..]]",
+ " -c --command pass all remaining args to sub-shell",
+ " --nointeractive don't start interactive session",
+ " --login login shell (same session, reads etc/gosh_profile)",
+ " -s --noshutdown don't shutdown framework when script completes",
+ " -x --xtrace echo commands before execution",
+ " -? --help show help",
+ "If no script-file, an interactive shell is started, type $D to exit."};
+
+ Options opt = Options.compile(usage).setOptionsFirst(true).parse(argv);
+ List<String> args = opt.args();
+
+ boolean login = opt.isSet("login");
+ boolean interactive = !opt.isSet("nointeractive");
+
+ if (opt.isSet("help")) {
+ opt.usage(System.err);
+ if (login && !opt.isSet("noshutdown")) {
+ shutdown();
+ }
+ return null;
+ }
+
+ if (opt.isSet("command") && args.isEmpty()) {
+ throw opt.usageError("option --command requires argument(s)");
+ }
+
+ CommandSession newSession = (login ? session : processor.createSession(
+ session.getKeyboard(), session.getConsole(), System.err));
+
+ if (opt.isSet("xtrace")) {
+ newSession.put("echo", true);
+ }
+
+ // export variables starting with upper-case to newSession
+ for (String key : getVariables(session)) {
+ if (key.matches("[.]?[A-Z].*")) {
+ newSession.put(key, session.get(key));
+ }
+ }
+
+ Terminal terminal = getTerminal(session);
+ newSession.put(Shell.VAR_CONTEXT, context);
+ newSession.put(Shell.VAR_TERMINAL, terminal);
+ newSession.put(Shell.VAR_PROCESSOR, processor);
+ newSession.put(Shell.VAR_SESSION, session);
+ newSession.put("#TERM", (Function) (s, arguments) -> terminal.getType());
+ newSession.put("#COLUMNS", (Function) (s, arguments) -> terminal.getWidth());
+ newSession.put("#LINES", (Function) (s, arguments) -> terminal.getHeight());
+
+ LineReader reader = null;
+ if (args.isEmpty() && interactive) {
+ reader = LineReaderBuilder.builder()
+ .terminal(terminal)
+ .variables(((CommandSessionImpl) newSession).getVariables())
+ .completer(new org.jline.builtins.Completers.Completer(new JLineCompletionEnvironment(newSession)))
+ .highlighter(new Highlighter(session))
+ .history(new FileHistory(new File(System.getProperty("user.home"), ".gogo.history")))
+ .parser(new Parser())
+ .build();
+ newSession.put(Shell.VAR_READER, reader);
+ newSession.put(Shell.VAR_COMPLETIONS, new HashMap());
+ }
+
+ if (login || interactive) {
+ URI uri = baseURI.resolve("etc/" + profile);
+ if (!new File(uri).exists()) {
+ URL url = getClass().getResource("/ext/" + profile);
+ if (url == null) {
+ url = getClass().getResource("/" + profile);
+ }
+ uri = (url == null) ? null : url.toURI();
+ }
+ if (uri != null) {
+ source(newSession, uri.toString());
+ }
+ }
+
+ Object result = null;
+
+ if (args.isEmpty()) {
+ if (interactive) {
+ while (true) {
+ try {
+ reader.readLine(Shell.getPrompt(session), Shell.getRPrompt(session), null, null);
+ ParsedLine parsedLine = reader.getParsedLine();
+ if (parsedLine == null) {
+ throw new EndOfFileException();
+ }
+ try {
+ result = session.execute(((ParsedLineImpl) parsedLine).program());
+ session.put("_", result); // set $_ to last result
+
+ if (result != null && !Boolean.FALSE.equals(session.get(".Gogo.format"))) {
+ System.out.println(session.format(result, Converter.INSPECT));
+ }
+ } catch (Exception e) {
+ session.put(Shell.VAR_EXCEPTION, e);
+ Object loc = session.get(Shell.VAR_LOCATION);
+
+ if (null == loc || !loc.toString().contains(":")) {
+ loc = "gogo";
+ }
+ System.out.println(loc + ": " + e.getClass().getSimpleName() + ": "
+ + e.getMessage());
+ }
+
+ } catch (UserInterruptException e) {
+ // continue;
+ } catch (EndOfFileException e) {
+ try {
+ reader.getHistory().flush();
+ } catch (IOException e1) {
+ e.addSuppressed(e1);
+ }
+ break;
+ }
+ }
+ }
+ } else {
+ CharSequence program;
+
+ if (opt.isSet("command")) {
+ StringBuilder buf = new StringBuilder();
+ for (String arg : args) {
+ if (buf.length() > 0) {
+ buf.append(' ');
+ }
+ buf.append(arg);
+ }
+ program = buf;
+ } else {
+ URI script = cwd(session).resolve(args.remove(0));
+
+ // set script arguments
+ newSession.put("0", script);
+ newSession.put("args", args);
+
+ for (int i = 0; i < args.size(); ++i) {
+ newSession.put(String.valueOf(i + 1), args.get(i));
+ }
+
+ program = readScript(script);
+ }
+
+ result = newSession.execute(program);
+ }
+
+ if (login && interactive && !opt.isSet("noshutdown")) {
+ System.out.println("gosh: stopping framework");
+ shutdown();
+ }
+
+ return result;
+ }
+
+ public Object sh(final CommandSession session, String[] argv) throws Exception {
+ return gosh(session, argv);
+ }
+
+ private void shutdown() throws Exception {
+ context.exit();
+ }
+
+ public Object source(CommandSession session, String script) throws Exception {
+ URI uri = cwd(session).resolve(script);
+ session.put("0", uri);
+ try {
+ return session.execute(readScript(uri));
+ } finally {
+ session.put("0", null); // API doesn't support remove
+ }
+ }
+
+ private Map<String, List<Method>> getReflectionCommands(CommandSession session) {
+ Map<String, List<Method>> commands = new TreeMap<String, List<Method>>();
+ Set<String> names = getCommands(session);
+ for (String name : names) {
+ Function function = (Function) session.get(name);
+ if (function instanceof CommandProxy) {
+ Object target = ((CommandProxy) function).getTarget();
+ List<Method> methods = new ArrayList<>();
+ String func = name.substring(name.indexOf(':') + 1).toLowerCase();
+ List<String> funcs = new ArrayList<>();
+ funcs.add("is" + func);
+ funcs.add("get" + func);
+ funcs.add("set" + func);
+ if (Reflective.KEYWORDS.contains(func)) {
+ funcs.add("_" + func);
+ } else {
+ funcs.add(func);
+ }
+ for (Method method : target.getClass().getMethods()) {
+ if (funcs.contains(method.getName().toLowerCase())) {
+ methods.add(method);
+ }
+ }
+ commands.put(name, methods);
+ ((CommandProxy) function).ungetTarget();
+ }
+ }
+ return commands;
+ }
+
+ @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);
+ }
+ }
+
+ @Descriptor("displays information about a specific command")
+ public void help(CommandSession session, @Descriptor("target command") String name) {
+ Map<String, List<Method>> commands = getReflectionCommands(session);
+
+ List<Method> methods = null;
+
+ // If the specified command doesn't have a scope, then
+ // search for matching methods by ignoring the scope.
+ int scopeIdx = name.indexOf(':');
+ if (scopeIdx < 0) {
+ for (Entry<String, List<Method>> entry : commands.entrySet()) {
+ String k = entry.getKey().substring(entry.getKey().indexOf(':') + 1);
+ if (name.equals(k)) {
+ name = entry.getKey();
+ methods = entry.getValue();
+ break;
+ }
+ }
+ }
+ // Otherwise directly look up matching methods.
+ else {
+ methods = commands.get(name);
+ }
+
+ if ((methods != null) && (methods.size() > 0)) {
+ for (Method m : methods) {
+ Descriptor d = m.getAnnotation(Descriptor.class);
+ if (d == null) {
+ System.out.println("\n" + m.getName());
+ } else {
+ System.out.println("\n" + m.getName() + " - " + d.value());
+ }
+
+ System.out.println(" scope: " + name.substring(0, name.indexOf(':')));
+
+ // Get flags and options.
+ Class<?>[] paramTypes = m.getParameterTypes();
+ Map<String, Parameter> flags = new TreeMap<>();
+ Map<String, String> flagDescs = new TreeMap<>();
+ Map<String, Parameter> options = new TreeMap<>();
+ Map<String, String> optionDescs = new TreeMap<>();
+ List<String> params = new ArrayList<String>();
+ Annotation[][] anns = m.getParameterAnnotations();
+ for (int paramIdx = 0; paramIdx < anns.length; paramIdx++) {
+ Class<?> paramType = m.getParameterTypes()[paramIdx];
+ if (paramType == CommandSession.class) {
+ /* Do not bother the user with a CommandSession. */
+ continue;
+ }
+ Parameter p = findAnnotation(anns[paramIdx], Parameter.class);
+ d = findAnnotation(anns[paramIdx], Descriptor.class);
+ if (p != null) {
+ if (p.presentValue().equals(Parameter.UNSPECIFIED)) {
+ options.put(p.names()[0], p);
+ if (d != null) {
+ optionDescs.put(p.names()[0], d.value());
+ }
+ } else {
+ flags.put(p.names()[0], p);
+ if (d != null) {
+ flagDescs.put(p.names()[0], d.value());
+ }
+ }
+ } else if (d != null) {
+ params.add(paramTypes[paramIdx].getSimpleName());
+ params.add(d.value());
+ } else {
+ params.add(paramTypes[paramIdx].getSimpleName());
+ params.add("");
+ }
+ }
+
+ // Print flags and options.
+ if (flags.size() > 0) {
+ System.out.println(" flags:");
+ for (Entry<String, Parameter> entry : flags.entrySet()) {
+ // Print all aliases.
+ String[] names = entry.getValue().names();
+ System.out.print(" " + names[0]);
+ for (int aliasIdx = 1; aliasIdx < names.length; aliasIdx++) {
+ System.out.print(", " + names[aliasIdx]);
+ }
+ System.out.println(" " + flagDescs.get(entry.getKey()));
+ }
+ }
+ if (options.size() > 0) {
+ System.out.println(" options:");
+ for (Entry<String, Parameter> entry : options.entrySet()) {
+ // Print all aliases.
+ String[] names = entry.getValue().names();
+ System.out.print(" " + names[0]);
+ for (int aliasIdx = 1; aliasIdx < names.length; aliasIdx++) {
+ System.out.print(", " + names[aliasIdx]);
+ }
+ System.out.println(" "
+ + optionDescs.get(entry.getKey())
+ + ((entry.getValue().absentValue() == null) ? ""
+ : " [optional]"));
+ }
+ }
+ if (params.size() > 0) {
+ System.out.println(" parameters:");
+ for (Iterator<String> it = params.iterator(); it.hasNext(); ) {
+ System.out.println(" " + it.next() + " " + it.next());
+ }
+ }
+ }
+ }
+ }
+
+ public interface Context {
+ String getProperty(String name);
+
+ void exit() throws Exception;
+ }
+
+}
Added: felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellCommand.java
URL: http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellCommand.java?rev=1735995&view=auto
==============================================================================
--- felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellCommand.java (added)
+++ felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellCommand.java Mon Mar 21 16:53:06 2016
@@ -0,0 +1,145 @@
+/*
+ * 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.ssh;
+
+import java.io.CharArrayWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.Reader;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.felix.service.command.CommandProcessor;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.Environment;
+import org.apache.sshd.server.ExitCallback;
+import org.apache.sshd.server.SessionAware;
+import org.apache.sshd.server.session.ServerSession;
+
+public class ShellCommand implements Command, Runnable, SessionAware {
+
+ public static final String SHELL_INIT_SCRIPT = "karaf.shell.init.script";
+ public static final String EXEC_INIT_SCRIPT = "karaf.exec.init.script";
+
+ private static final Logger LOGGER = Logger.getLogger(ShellCommand.class.getName());
+
+ private String command;
+ private InputStream in;
+ private OutputStream out;
+ private OutputStream err;
+ private ExitCallback callback;
+ private ServerSession session;
+ private CommandProcessor processor;
+ private Environment env;
+
+ public ShellCommand(CommandProcessor processor, String command) {
+ this.processor = processor;
+ this.command = command;
+ }
+
+ public void setInputStream(InputStream in) {
+ this.in = in;
+ }
+
+ public void setOutputStream(OutputStream out) {
+ this.out = out;
+ }
+
+ public void setErrorStream(OutputStream err) {
+ this.err = err;
+ }
+
+ public void setExitCallback(ExitCallback callback) {
+ this.callback = callback;
+ }
+
+ public void setSession(ServerSession session) {
+ this.session = session;
+ }
+
+ public void start(final Environment env) throws IOException {
+ this.env = env;
+ new Thread(this).start();
+ }
+
+ public void run() {
+ int exitStatus = 0;
+ try {
+ final CommandSession session = processor.createSession(in, new PrintStream(out), new PrintStream(err));
+ for (Map.Entry<String, String> e : env.getEnv().entrySet()) {
+ session.put(e.getKey(), e.getValue());
+ }
+ try {
+ String scriptFileName = System.getProperty(EXEC_INIT_SCRIPT);
+ if (scriptFileName == null) {
+ scriptFileName = System.getProperty(SHELL_INIT_SCRIPT);
+ }
+ executeScript(scriptFileName, session);
+ session.execute(command);
+ } catch (Throwable t) {
+ exitStatus = 1;
+ t.printStackTrace();
+ }
+ } catch (Exception e) {
+ exitStatus = 1;
+ LOGGER.log(Level.SEVERE, "Unable to start shell", e);
+ } finally {
+ ShellFactoryImpl.close(in, out, err);
+ callback.onExit(exitStatus);
+ }
+ }
+
+ public void destroy() {
+ }
+
+ private void executeScript(String scriptFileName, CommandSession session) {
+ if (scriptFileName != null) {
+ Reader r = null;
+ try {
+ File scriptFile = new File(scriptFileName);
+ r = new InputStreamReader(new FileInputStream(scriptFile));
+ CharArrayWriter w = new CharArrayWriter();
+ int n;
+ char[] buf = new char[8192];
+ while ((n = r.read(buf)) > 0) {
+ w.write(buf, 0, n);
+ }
+ session.execute(new String(w.toCharArray()));
+ } catch (Exception e) {
+ LOGGER.log(Level.FINE, "Error in initialization script", e);
+ } finally {
+ if (r != null) {
+ try {
+ r.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+ }
+ }
+
+}
Added: felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellCommandFactory.java
URL: http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellCommandFactory.java?rev=1735995&view=auto
==============================================================================
--- felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellCommandFactory.java (added)
+++ felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellCommandFactory.java Mon Mar 21 16:53:06 2016
@@ -0,0 +1,37 @@
+/*
+ * 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.ssh;
+
+import org.apache.felix.service.command.CommandProcessor;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.CommandFactory;
+
+public class ShellCommandFactory implements CommandFactory {
+
+ private CommandProcessor processor;
+
+ public ShellCommandFactory(CommandProcessor processor) {
+ this.processor = processor;
+ }
+
+ public Command createCommand(String command) {
+ return new ShellCommand(processor, command);
+ }
+
+}