-package org.ibex.xt;
-
-import java.io.*;
-import java.net.*;
-import java.util.*;
-import java.util.regex.*;
-
-import org.ibex.util.*;
-import org.ibex.util.Collections;
-import org.ibex.js.*;
-
-public class Shell {
-
- public static void main(String[] args) throws Exception {
- if (args.length == 0 || args.length > 2|| !args[0].startsWith("http://")) {
- printUsage(); return;
- }
- Shell shell = new Shell(new URL(args[0]));
-
- if (args.length == 2) {
- // FIXME
- } else {
- shell.listen(new InputStreamReader(System.in), new OutputStreamWriter(System.out));
- }
- }
-
- private static void printUsage() {
- System.out.println("Usage: xish url [command]");
- }
-
- protected Command[] commands = new Command[] {
- new LsCommand(),
- new PwdCommand(),
- new CdCommand(),
- new RmCommand(),
- new HelpCommand()
- };
-
- /** URL of server. */
- protected URL server;
-
- /** Current JS path using '.' as a seperator. */
- protected String pwd = ".";
-
- /** Create a new Shell using the given url for the server. */
- public Shell(URL url) { server = url; }
-
- public void listen(Reader r, Writer w) throws IOException {
- LineNumberReader in = new LineNumberReader(r);
- PrintWriter out = new PrintWriter(w);
-
- out.println("ibex xt shell: type help or exit");
- out.print("xt: ");
- out.flush();
-
- String line;
- String buffer = "";
- while ((line = in.readLine()) != null) {
- if (line.length() > 0) {
- if (line.startsWith("exit")) return;
- if (line.charAt(line.length() - 1) == '\\') {
- buffer += line.substring(0, line.length() - 1);
- out.print('>');
- out.flush(); continue;
- }
-
- buffer += line;
- }
-
- if (buffer.length() > 0) {
- String[] c = buffer.split(" ");
- int i=0; while (i < commands.length) {
- if (commands[i].name().equals(c[0])) {
- commands[i].execute(out, c); break;
- }
- i++;
- }
- if (i == commands.length) {
- out.write(c[0]);
- w.write(": command not found\n");
- }
- buffer = "";
- }
- out.print("xt: ");
- out.flush();
- }
- }
-
- /** Returns a path, based on console input. */
- private String path(String c) {
- if (c.equals("") || c.equals(".") || c.equals("/")) {
- c = ".";
- } else if (c.equals("..")) {
- c = c.substring(0, c.lastIndexOf('.'));
- if (c.equals("")) c = ".";
- } else {
- if (c.charAt(0) != '/') c = pwd + c;
- c = c.replaceAll("/+", ".");
- if (c.length() > 1 && c.charAt(c.length() - 1) == '.')
- c = c.substring(0, c.length() - 1);
- }
-
- return c;
- }
-
- private String cookie = null;
- public Object send(Request request) throws IOException {
- URLConnection c = server.openConnection();
- ((HttpURLConnection)c).setRequestMethod("POST");
- c.setDoOutput(true);
- if (cookie != null) c.setRequestProperty("Cookie", cookie);
-
- c.connect();
-
- ObjectOutputStream out = new ObjectOutputStream(c.getOutputStream());
- out.writeObject(request);
- out.close();
-
- String cook = c.getHeaderField("Set-Cookie");
- if (cook != null && !cook.equals("")) cookie = cook.substring(0, cook.indexOf(';'));
-
- try {
- return new ObjectInputStream(c.getInputStream()).readObject();
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- throw new IOException("unexpected ClassNotFoundException");
- }
- }
-
- public abstract class Command {
- /** Returns the command name. */
- public abstract String name();
-
- /** Returns single-line of usage information, eg. <tt>pattern]</tt> */
- public abstract String usage();
-
- /** Returns single-line description of command. */
- public abstract String summary();
-
- /** Returns multi-line description. */
- public abstract String help();
-
- /** Writes result of execution, even if result is an error. */
- public abstract void execute(Writer w, String[] args) throws IOException;
- }
-
- /** Returns the command matching the given name. */
- protected Command command(String name) {
- for (int i=0; i < commands.length; i++)
- if (commands[i].name().equals(name)) return commands[i];
- return null;
- }
-
- public class HelpCommand extends Command {
- public String name() { return "help"; }
- public String usage() { return "[command name]"; }
- public String summary() { return "Lists available commands."; }
- public String help() { return ""; }
-
- public void execute(Writer w, String[] c) throws IOException {
- if (c.length > 1) {
- Command cmd = command(c[1]);
- if (c == null) {
- w.write("help: ");
- w.write(c[1]);
- w.write(": command not found\n");
- } else {
- w.write("usage: ");
- w.write(cmd.name());
- w.write(" ");
- w.write(cmd.usage());
- w.write("\n\n");
- w.write(cmd.help());
- w.write("\n");
- }
- } else {
- int len = 3;
- for (int i=0; i < commands.length; i++)
- len = Math.max(commands[i].name().length(), len);
-
- w.write("Available commands:\n");
- for (int i=0; i < commands.length; i++) {
- Command cmd = commands[i];
- w.write(" ");
- w.write(cmd.name());
- for (int j=len - cmd.name().length(); j >= 0; j--) w.write(" ");
- w.write(" - ");
- w.write(cmd.summary());
- w.write("\n");
- }
- w.write("\nFor usage details, type help [command name].\n");
- }
- }
- }
-
- public class LsCommand extends Command {
- public String name() { return "ls"; }
- public String usage() { return "[path]"; }
- public String summary() { return "List object entries."; }
- public String help() { return
- "Lists the keys in an object. Modelled after the UNIX ls command.";
- }
-
- public void execute(Writer w, String[] c) throws IOException {
- if (c.length > 2) { w.write(usage()); return; }
-
- Object ret = send(new KeyRequest(path(c[1])));
- if (ret == null) {
- w.write("error: (unexpected) returned object is null\n");
- } else if (ret instanceof JSExn) {
- String e = ((JSExn)ret).getMessage();
- // FIXME: messy way to get info from server
- if (e.endsWith("does not exist")) {
- w.write("ls ");
- w.write(c[1]);
- w.write(": no such path\n");
- } else {
- w.write("error: ");
- w.write(e);
- w.write("\n");
- }
- } else if (ret instanceof List) {
- List l = (List)ret; Collections.sort(l);
- Iterator i = l.iterator(); while (i.hasNext()) {
- w.write(i.next().toString());
- w.write("\n");
- }
- } else {
- w.write("error: (unexpected) returned object is of unknown type: ");
- w.write(ret.getClass().getName());
- w.write("\n");
- }
- }
- }
-
- public class PwdCommand extends Command {
- public String name() { return "pwd"; }
- public String usage() { return ""; }
- public String summary() { return "Path to current object."; }
- public String help() { return "Print the path to the current object."; }
- public void execute(Writer w, String[] c) throws IOException {
- w.write(c.length == 1 ? pwd.replace('.', '/') : usage());
- w.write("\n");
- }
- }
-
- public class CdCommand extends Command {
- public String name() { return "cd"; }
- public String usage() { return "[path]"; }
- public String summary() { return "Change current object."; }
- public String help() { return
- "Chnages the current object that all other commands use "+
- "as the base for running.\n Pass either a relative path "+
- "(e.g. in /prevalent, type cd myob, now in /prevalent/myob) "+
- "or an absolute path (e.g. cd /prevalent/myob).\n\n" +
- "To go up one level, cd .. can be used.";
- }
- public void execute(Writer w, String[] c) throws IOException {
- if (c.length > 2) w.write(usage());
- else if (c.length == 1 || c[1].equals("") || c[1].equals("/")) pwd = ".";
- else if (c[1].equals("..")) {
- String n = pwd.substring(0, pwd.lastIndexOf('.'));
- pwd = n.equals("") ? "." : n;
- } else {
- String n = path(c[1]);
- Object ret = send(new KeyRequest(n));
-
- if (ret == null) {
- w.write("error: (unexpected) server returned null\n");
- } else if (ret instanceof List && ((List)ret).size() == 1) {
- pwd = n;
- } else if (ret instanceof JSExn ||
- (ret instanceof List && ((List)ret).size() == 0)) {
- w.write("cd ");
- w.write(c[1]);
- w.write(": no such path\n");
- } else {
- w.write("error: (unexpected) server returned ");
- w.write(ret.toString());
- w.write("\n");
- }
- }
- }
- }
-
- public class RmCommand extends Command {
- public String name() { return "rm"; }
- public String usage() { return "[options] [path]"; }
- public String summary() { return "Removes objects."; }
- public String help() { return "Removes objects."; } // FIXME
- public void execute(Writer w, String[] c) throws IOException {
- if (c.length == 1) { w.write(usage()); }
-
- String[] r = new String[c.length - 1];
- for (int i=0; i < r.length; i++) r[i] = path(c[i + 1]);
- // Object ret = send(new KeyRequest( FIXME: CompositeRequest
- }
- }
-
- public static abstract class Request implements Serializable {
- public abstract Object process(JSScope root) throws JSExn;
- }
-
- public static class KeyRequest extends Request {
- private String path, matcher;
- public KeyRequest() {}
- public KeyRequest(String c) {
- int pos = c.lastIndexOf('.');
- path = c.substring(0, pos);
- matcher = c.substring(pos + 1).replaceAll("\\*+", ".*");
- }
- public KeyRequest(String path, String matcher) {
- this.path = path; this.matcher = matcher;
- }
-
- /** Returns a List. */
- public Object process(JSScope root) throws JSExn {
- String p = path == null ? "" : path.replaceAll("\\.+", "\\.");
- if (p.length() > 0 && p.charAt(0) == '.') p = p.substring(1);
- if (p.length() > 0 && p.charAt(p.length() - 1) == '.') p = p.substring(0, p.length() - 1);
- System.out.println("searching path '"+p+"' for pattern '"+matcher+"'");
-
- Object o = p.equals("") ? root : root.get(p);
- if (o == null || o instanceof JSDate ||
- o instanceof JSArray ||
- !(o instanceof JS)) {
- System.out.println("hit bad object: "+o+", class="+
- (o == null ? null : o.getClass().getName()));
- throw new JSExn("path /" + p + " does not exist");
- } else {
- Pattern pat = Pattern.compile(matcher);
- List keys = new ArrayList();
-
- Iterator i = ((JS)o).keys().iterator(); while(i.hasNext()) {
- String k = i.next().toString();
- if (pat.matcher(k).matches()) keys.add(k);
- }
-
- return keys;
- }
- }
- }
-
- public static class ExecRequest extends Request {
- private JS exec;
- public ExecRequest() {}
- public ExecRequest(JS exec) { this.exec = exec; }
- public ExecRequest(String source) throws IOException, JSExn {
- this(new StringReader(source));
- }
- public ExecRequest(Reader source) throws IOException, JSExn {
- exec = JS.fromReader("xsh", 0, source);
- }
-
- /** Returns the result of <tt>JS.eval()</tt>. */
- public Object process(JSScope root) throws JSExn {
- return JS.eval(JS.cloneWithNewParentScope(exec, root));
- }
- }
-}