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);
+    }
+
+}