From cae0275ae24fa8e78fda9a5830fe015dbcab25d4 Mon Sep 17 00:00:00 2001 From: Jonas Fonseca Date: Wed, 26 Nov 2008 13:01:41 +0100 Subject: [PATCH] apps/cli: add run-script subcommand and a few examples Exposes some methods of Command such as die(). --- .../cli/src/main/java/remote/apps/cli/Command.java | 6 +- .../src/main/java/remote/apps/cli/RunScript.java | 201 +++++++++++++++++++++ apps/cli/src/main/javascript/mote-exec.js | 69 +++++++ apps/cli/src/main/javascript/simple-task.js | 19 ++ .../META-INF/services/remote.apps.cli.Command | 1 + apps/cli/src/site/apt/index.apt | 17 +- 6 files changed, 309 insertions(+), 4 deletions(-) create mode 100644 apps/cli/src/main/java/remote/apps/cli/RunScript.java create mode 100644 apps/cli/src/main/javascript/mote-exec.js create mode 100644 apps/cli/src/main/javascript/simple-task.js diff --git a/apps/cli/src/main/java/remote/apps/cli/Command.java b/apps/cli/src/main/java/remote/apps/cli/Command.java index 9a3148f..753b4ea 100644 --- a/apps/cli/src/main/java/remote/apps/cli/Command.java +++ b/apps/cli/src/main/java/remote/apps/cli/Command.java @@ -171,7 +171,7 @@ public abstract class Command { * Exit the program with message. * @param msg to print to stderr. */ - protected void die(String msg) + public void die(String msg) { System.err.println(msg); System.exit(1); @@ -194,7 +194,7 @@ public abstract class Command { * that has been added by the sub command. * @return the service manager. */ - protected ServiceManager getServiceManager() + public ServiceManager getServiceManager() { return manager; } @@ -202,7 +202,7 @@ public abstract class Command { /** * Shutdown services and exit the command. */ - protected void exit() + public void exit() { running = false; } diff --git a/apps/cli/src/main/java/remote/apps/cli/RunScript.java b/apps/cli/src/main/java/remote/apps/cli/RunScript.java new file mode 100644 index 0000000..09e72b7 --- /dev/null +++ b/apps/cli/src/main/java/remote/apps/cli/RunScript.java @@ -0,0 +1,201 @@ +package remote.apps.cli; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.util.LinkedList; +import java.util.List; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.spi.FileOptionHandler; +import remote.client.spi.service.MoteAccessService; +import remote.client.spi.service.MoteConsoleService; +import remote.client.spi.service.MoteControlService; + +/** + * Command for running a script from a file. + */ +public class RunScript extends Command implements Command.Authentication { + + @Argument(index = 0, metaVar = "program", required = true, handler = FileOptionHandler.class) + private File script; + @Argument(index = 1) + private List args = new LinkedList(); + + /** + * Create a run-script command. + */ + public RunScript() + { + super("run-script", "script", "Run script from file"); + } + + protected void run() + { + int offset = script.getName().lastIndexOf(".") + 1; + String extension = offset > 0 ? script.getName().substring(offset) : null; + if (extension == null) + die("Failed to get script extension from '" + script.getName() + "'"); + + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = manager.getEngineByExtension(extension); + if (engine == null) + die("No scripting engine supports extension '" + extension + "'"); + + engine.put("command", this); + engine.put("args", args.toArray(new String[0])); + + try { + engine.eval(new FileReader(script)); + } catch (Throwable error) { + die("Script threw an exception", error); + } + } + + public Mote getMote(int id) + { + return new Mote(id); + } + + public class Mote { + + private final long[] motes; + + public Mote(long id) + { + this.motes = new long[] { id }; + } + + public int getId() + { + return (int) motes[0]; + } + + public void access(final Runnable runner) + { + getServiceManager().get(MoteAccessService.class). + getPrivileges(motes, + new MoteAccessService.Callback() { + + public void onError(Throwable caught) + { + die("Failed to get privileges", caught); + } + + public void onSuccess(Boolean[] result) + { + runner.run(); + } + + }); + } + + public void control(final Runnable runner) + { + getServiceManager().get(MoteControlService.class). + requestControl(motes, + new MoteControlService.Callback() { + + public void onError(Throwable caught) + { + die("Failed to get control", caught); + } + + public void onSuccess(Boolean[] result) + { + runner.run(); + } + + }); + } + + public void console() + { + getServiceManager().get(MoteConsoleService.class).read(motes, + new MoteConsoleService.ReadCallback() { + + public void onRead(long id, byte[] data) + { + System.out.write(data, 0, data.length); + System.out.flush(); + } + + public void onError(Throwable caught) + { + die("Failed to setup the console", caught); + } + + public void onSuccess(Void result) + { + } + + }); + } + + public void program(String program, final Runnable runner) + { + String[] args = new String[] { readFile(program) }; + + getServiceManager().get(MoteControlService.class).execute( + MoteControlService.Command.PROGRAM, motes, args, + new MoteControlService.Callback() { + + public void onError(Throwable caught) + { + die("Failed to program mote", caught); + } + + public void onSuccess(MoteControlService.Response[] result) + { + runner.run(); + } + + }); + } + + public void start(final Runnable runner) + { + String[] args = new String[] {}; + + getServiceManager().get(MoteControlService.class).execute( + MoteControlService.Command.START, motes, args, + new MoteControlService.Callback() { + + public void onError(Throwable caught) + { + die("Failed to start mote", caught); + } + + public void onSuccess(MoteControlService.Response[] result) + { + } + + }); + } + + private String readFile(String file) + { + BufferedReader reader = null; + try { + reader = new BufferedReader(new FileReader(file)); + } catch (Throwable ex) { + die("File not found", ex); + } + + StringBuilder builder = new StringBuilder(); + char[] buffer = new char[1024]; + int bytes; + try { + while ((bytes = reader.read(buffer)) > 0) + builder.append(String.valueOf(buffer, 0, bytes)); + } catch (Throwable ex) { + die("Failed to read " + file.toString()); + } + + return builder.toString(); + } + + } + +} diff --git a/apps/cli/src/main/javascript/mote-exec.js b/apps/cli/src/main/javascript/mote-exec.js new file mode 100644 index 0000000..a3aac63 --- /dev/null +++ b/apps/cli/src/main/javascript/mote-exec.js @@ -0,0 +1,69 @@ +/* + * Script that mimics the behavior of the mote-exec subcommand. + */ + +function p(msg) +{ + print(msg + "\n"); +} + +var accessDone = new java.lang.Runnable() { + + run: function() + { + p("Access granted"); + mote.control(controlDone); + } + +} + +var controlDone = new java.lang.Runnable() { + + run: function() + { + p("Control granted"); + mote.console(); + p("Starting"); + mote.program(args[1], programDone); + } + +} + +var consoleDone = new java.lang.Runnable() { + + run: function() + { + p("Console setup"); + } + +} + +var programDone = new java.lang.Runnable() { + + run: function() + { + p("Starting the program"); + mote.start(commandDone); + } + +} + +var commandDone = new java.lang.Runnable() { + + run: function() + { + p("Done"); + } + +} + +if (args[0] == undefined) + command.die("Mote ID required as the first argument"); +if (args[1] == undefined) + command.die("Mote program request as the second argument"); + +p("Using mote " + args[0]); +mote = command.getMote(args[0]); + +p("Get access"); +mote.access(accessDone); diff --git a/apps/cli/src/main/javascript/simple-task.js b/apps/cli/src/main/javascript/simple-task.js new file mode 100644 index 0000000..421e29b --- /dev/null +++ b/apps/cli/src/main/javascript/simple-task.js @@ -0,0 +1,19 @@ +/* + * Simple script that uses the service manager to execute a task. + */ + +print("Starting the script\n"); + +var service = command.getServiceManager(); +var task = new java.lang.Runnable() { + + run: function() { + print("I'm in ur task\n"); + java.lang.Thread.sleep(2); + print("Exiting ur command\n"); + command.exit(); + } + +} + +var job = service.addTask(task); diff --git a/apps/cli/src/main/resources/META-INF/services/remote.apps.cli.Command b/apps/cli/src/main/resources/META-INF/services/remote.apps.cli.Command index a632302..564a133 100644 --- a/apps/cli/src/main/resources/META-INF/services/remote.apps.cli.Command +++ b/apps/cli/src/main/resources/META-INF/services/remote.apps.cli.Command @@ -3,3 +3,4 @@ remote.apps.cli.MotePriv remote.apps.cli.Login remote.apps.cli.LsAuth remote.apps.cli.LsMotes +remote.apps.cli.RunScript diff --git a/apps/cli/src/site/apt/index.apt b/apps/cli/src/site/apt/index.apt index 4651d25..b0b184b 100644 --- a/apps/cli/src/site/apt/index.apt +++ b/apps/cli/src/site/apt/index.apt @@ -128,4 +128,19 @@ $ remote-cli mote-priv 9 +----------------------------------------------------------------------------+ $ remote-cli mote-exec 9 /path/to/program/binary.s19 -+----------------------------------------------------------------------------+ \ No newline at end of file ++----------------------------------------------------------------------------+ + +* {Run script file} + + <> remote-cli run-script [options] script [arguments] + + Runs a script in a file passing any additional arguments to the script via + a global <<>> variable. The command can be accessed as the variable + <<>>. The extension of the script determines what scripting engine + is used. By default, only the javascript language is supported. + + Example: + ++----------------------------------------------------------------------------+ +$ remote-cli run-script mote-exec.js 9 /path/to/program/binary.s19 ++----------------------------------------------------------------------------+ -- 2.11.4.GIT