Commits

Dan Boitnott committed 02ea34a

Editing and running the script from the web interface works

Comments (0)

Files changed (8)

 import argparse
+import os.path
 
 import pexpect
 import state
 argParser = argparse.ArgumentParser()
 argParser.add_argument("script")
 args = argParser.parse_args()
-state.script = scripts.parseScript(args.script)
+state.scriptPath = os.path.abspath(args.script)
+state.script = scripts.parseScript(state.scriptPath)
 
 SHELL_PATH = "/bin/bash"
 env = { "PS1"           : "prise:\\h:\\W \\u\\$ ",

src/resources/static/global.css

 
 pre {
     font-family: monospace;
+    font-size: 10pt;
+}
+
+button {
+    padding: 3px;
 }
 
 .TaskBox {
     right: 3px;
 }
 
+.taskTools a {
+    cursor: pointer;
+}
 .outputToolbar {
     position: absolute;
     top: 15px;
     width: 100%;
 }
 
+.editTask {
+}
+
+.editTask textarea {
+    width: 100%;
+    height: 5em;
+    font-family: monospace;
+    font-size: 10pt;
+}

src/resources/static/index.js

+function setDisplayById(id, val) {
+    document.getElementById(id).style.display = val;
+}
+
+function editTask(index) {
+    setDisplayById("taskTools" + index, "none");
+    setDisplayById("taskLines" + index, "none");
+    setDisplayById("editTask" + index, "block");
+}
+
+function cancelEdit(index) {
+    setDisplayById("taskTools" + index, "block");
+    setDisplayById("taskLines" + index, "block");
+    setDisplayById("editTask" + index, "none");
+}

src/resources/static/run-icon.png

Added
New image

src/resources/templates/index.mustache

 {{>stdhead}}
 
+<script src="static/index.js"></script>
+
 <h1>PRISE:{{request.server_name}}:{{dirname}}</h1>
 
 {{#tasks}}
     <div class="TaskBox {{class}} {{colorClass}}">
-        <div class="taskTools">
-            <a href="editTask"><img src="static/edit-icon.png" alt="Edit Task" title="Edit Task"/></a>
+        <div class="taskTools" id="taskTools{{index}}">
+            <a onclick="editTask({{index}});"><img src="static/edit-icon.png" alt="Edit Task" title="Edit Task"/></a>
+            {{#isCommandTask}}
+                <a href="runTask?index={{index}}&hash={{hash}}">
+                    <img src="static/run-icon.png" alt="Run Command" title="Run Command"/>
+                </a>
+            {{/isCommandTask}}
         </div>
-        <pre>{{lines}}</pre>
+        <pre id="taskLines{{index}}">{{lines}}</pre>
+        <div id="editTask{{index}}" class="editTask" style="display:none;">
+            <form method="POST" action="editTask">
+                <input type="hidden" name="hash" value="{{hash}}"/>
+                <input type="hidden" name="index" value="{{index}}"/>
+                <textarea name="lines">{{lines}}</textarea>
+                <button type="submit">Ok</button>
+                <button type="button" onclick="cancelEdit({{index}});">Cancel</button>
+            </form>
+        </div>
         {{#isCommandTask}}
             {{#hasOutput}}
                 {{#outputIsTail}}
     def joinScript(self, script):
         script.append(self)
 
+    def hash(self):
+        return util.cmdHash(self.content)
+
 class CommentTask(ScriptTask):
     multiLine = False
 
     fp.close()
     return ret
 
+def parseScriptString(s):
+    ret = []
+    for line in s.splitlines():
+        task = taskForLine(line)
+        if task:
+            task.joinScript(ret)
+    return ret
 script = None
 scriptIndex = 0
 scriptLock = threading.RLock()
+scriptPath = None
 
 # Create the run directory
 os.makedirs(runDir)
             first = False
     printToUser(out)
 
+def writeScript(path):
+    with scriptLock:
+        with open(path, 'w') as fp:
+            for task in script:
+                for line in task.getLines():
+                    print >>fp, line
+
+def backupScript():
+    with scriptLock:
+        writeScript(os.path.join(runDir, "script.%s.ise" % util.timestamp()))
+
+def saveScript():
+    with scriptLock:
+        backupScript()
+        writeScript(scriptPath)
+
+
 hotkeys = {
     hotkey.KEY_F1 : hotkeyHelp,
     hotkey.KEY_F2 : showScript,
 import traceback
 import socket
 import threading
+import cgi
+import time
 
 import pystache
 import state
         except:
             self.send_error(500, traceback.format_exc())
 
+    def do_POST(self):
+        ctype, pdict = cgi.parse_header(self.headers.getheader('content-type'))
+        if ctype == 'multipart/form-data':
+            self.postVars = cgi.parse_multipart(self.rfile, pdict)
+        elif ctype == 'application/x-www-form-urlencoded':
+            length = int(self.headers.getheader('content-length'))
+            self.postVars = cgi.parse_qs(self.rfile.read(length), keep_blank_values=1)
+        else:
+            self.postVars = {}
+
+        self.do_GET()
+
     def sendStatic(self, filename):
         fp = openResource(STATIC, filename)
         if not fp:
         self.end_headers()
         self.wfile.write(content)
 
+    def redirect(self, dest):
+        self.send_response(302)
+        self.send_header("Location", dest)
+        self.end_headers()
+
     def cmd_version(self, path, query):
         self.send_response(200)
         self.send_header("Content-type", 'text/plain')
     def cmd_index(self, path, query):
         self.log_message
         tasks = []
+        taskIndex = 0
         for task in state.script:
             times = state.getCommandOutputTimes(task)
             output = [{"ts": ts} for ts in times]
                 "isCommentTask" : type(task) is scripts.CommentTask,
                 "isCommandTask" : type(task) is scripts.CommandTask,
                 "content"       : task.content,
-                "hash"          : util.cmdHash(task.content),
+                "index"         : taskIndex,
+                "hash"          : task.hash(),
                 "lines"         : "\n".join(task.getLines()),
                 "colorClass"    : colorClass,
                 "output"        : output,
                 "outputIsTail"  : outputIsTail
             })
 
+            taskIndex += 1
+
         self.sendTemplate("index", tasks=tasks, dirname=os.path.basename(os.getcwd()))
 
+    def cmd_editTask(self, path, query):
+        idx = int(self.postVars['index'][0]);
+        hash = self.postVars['hash'][0];
+
+        with state.scriptLock:
+            if idx >= len(state.script):
+                self.send_error(500, "invalid script index: " + idx)
+                return
+
+            # Make sure there hasn't been an edit from another process.
+            origTask = state.script[idx];
+            if origTask.hash() != hash:
+                self.send_error(500, "hash mismatch")
+                return
+
+            lines = self.postVars['lines'][0].strip()
+
+            if len(lines) < 1:
+                # User has deleted the task
+                state.script = state.script[:idx] + state.script[idx + 1:]
+            else:
+                newScript = scripts.parseScriptString(lines)
+                state.script = state.script[:idx] + newScript + state.script[idx + 1:]
+
+            state.saveScript()
+
+        self.redirect("/")
+
+    def cmd_runTask(self, path, query):
+        idx = int(query['index'][0])
+        hash = query['hash'][0]
+
+        with state.scriptLock:
+            if idx >= len(state.script):
+                self.send_error(500, "invalid script index: " + idx)
+                return
+
+            # Make sure we're running the right command
+            task = state.script[idx]
+            if task.hash() != hash:
+                self.send_error(500, "hash mismatch")
+                return
+
+            state.scriptIndex = idx
+            state.runNextCmd()
+
+        # Wait one second for some output
+        time.sleep(1)
+
+        self.redirect("/")
+
 class Server(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
     def __init__(self):
         BaseHTTPServer.HTTPServer.__init__(self, ('127.0.0.1', 8088), Handler)