mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
192 lines
5.5 KiB
Python
Executable File
192 lines
5.5 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
import json
|
|
import optparse
|
|
import subprocess
|
|
import time
|
|
import random
|
|
import sys
|
|
|
|
def send_to_screen(screen_name, arg0=None, command='stuff'):
|
|
args = ['screen', '-S', screen_name, '-p', '0',
|
|
'-X', command]
|
|
if arg0 is not None:
|
|
args.append(arg0)
|
|
p = subprocess.Popen(args)
|
|
p.communicate()
|
|
|
|
def load_as_transcript(f):
|
|
def add_block(clearScreen=False,noReturn=False):
|
|
# If so, add the current block after trimming leading and trailing blank
|
|
# lines.
|
|
while current_block and current_block[0].isspace():
|
|
current_block.pop(0)
|
|
while current_block and current_block[-1].isspace():
|
|
current_block.pop()
|
|
|
|
# Add the block if it is non-empty.
|
|
if current_block or comment_block:
|
|
# Form the joined script..
|
|
script = ''.join(current_block)
|
|
comment = ''.join(comment_block)
|
|
|
|
# Strip off any trailing newline.
|
|
if script.endswith('\n'):
|
|
script = script[:-1]
|
|
demo_script.append({ 'command' : script,
|
|
'comment' : comment,
|
|
'clearScreen' : clearScreen,
|
|
'noReturn' : noReturn })
|
|
|
|
# Clear the block and comment block.
|
|
del current_block[:]
|
|
del comment_block[:]
|
|
|
|
f.seek(0)
|
|
|
|
demo_script = []
|
|
current_block = []
|
|
comment_block = []
|
|
for ln in f:
|
|
# Check if this is a block delimiter.
|
|
if ln.strip() == '>>>':
|
|
add_block()
|
|
continue
|
|
|
|
# Check if this is a block delimiter
|
|
# but marked to clear the screen.
|
|
if ln.strip() == '>>>CLEAR':
|
|
add_block(clearScreen=True)
|
|
continue
|
|
|
|
# Check if this is a block delimiter
|
|
# but marked to not insert a newline.
|
|
if ln.strip() == '>>>NORETURN':
|
|
add_block(noReturn=True)
|
|
continue
|
|
|
|
# Check if the line starts with a '#'
|
|
# to indicate a prompter comment.
|
|
if ln.startswith('#'):
|
|
comment_block.append(ln)
|
|
continue
|
|
|
|
# Check for backspace.
|
|
if ln.strip() == '>>>BACKSPACE':
|
|
current_block.append('\b')
|
|
continue
|
|
|
|
# Otherwise, add the line to the current block.
|
|
current_block.append(ln)
|
|
|
|
return demo_script
|
|
|
|
def main():
|
|
parser = optparse.OptionParser("""\
|
|
usage: %%prog [options] <demo script>
|
|
|
|
Run a command line demo script using 'screen'. The script file should be either
|
|
a JSON document listing the commands to run, as in::
|
|
|
|
[
|
|
{ "command" : "ls" },
|
|
{ "command" : "echo Hello" }
|
|
]
|
|
|
|
or, alternately, it should be a text filed delimited by '>>>', as in::
|
|
|
|
>>>
|
|
ls
|
|
|
|
>>>
|
|
echo Hello
|
|
|
|
where leading and trailing blank lines around each block will be discarded.
|
|
|
|
The script requires the 'screen' session to have been started in another window,
|
|
for example::
|
|
|
|
$ screen -S demo
|
|
""")
|
|
|
|
# Determine up front if the terminal supports color.
|
|
hasColor = sys.stdout.isatty()
|
|
|
|
def prompterPrint(string):
|
|
if hasColor:
|
|
attr = [ '32', '1' ]
|
|
print '\x1b[%sm%s\x1b[0m' % (';'.join(attr), string)
|
|
else:
|
|
print string
|
|
|
|
def send(*args, **kwargs):
|
|
return send_to_screen(opts.screen_name, *args, **kwargs)
|
|
parser.add_option("-S", "--screen-name", dest="screen_name", metavar="NAME",
|
|
help="name of the screen sesison to use [%default]",
|
|
action="store", default="demo")
|
|
|
|
opts, args = parser.parse_args()
|
|
|
|
if len(args) == 1:
|
|
path, = args
|
|
else:
|
|
parser.error("invalid number of arguments")
|
|
|
|
# Read in the demo script.
|
|
with open(path) as f:
|
|
try:
|
|
demo_script = json.load(f)
|
|
except ValueError:
|
|
demo_script = load_as_transcript(f)
|
|
|
|
# Validate the entries.
|
|
for item in demo_script:
|
|
command = str(item.get('command'))
|
|
if not isinstance(command, str):
|
|
raise SystemError("error: invalid item in script: %r" % (
|
|
item,))
|
|
|
|
# Notify screen that we are starting the demo.
|
|
raw_input('press enter to begin demo...')
|
|
|
|
# Iterate over each command, sending it and waiting for user direction to
|
|
# continue.
|
|
for item in demo_script:
|
|
shouldClear = bool(item['clearScreen'])
|
|
noReturn = bool(item['noReturn'])
|
|
command = str(item['command'])
|
|
comment = str(item['comment'])
|
|
|
|
if comment:
|
|
prompterPrint(comment)
|
|
|
|
if command:
|
|
# Send the command slowly, as if it was typed.
|
|
print "sending command: %r" % (command.replace('\n', '<cr>'),)
|
|
for c in command:
|
|
send(c)
|
|
if c == "\n":
|
|
time.sleep(0.1)
|
|
else:
|
|
time.sleep(random.random() * 0.03)
|
|
|
|
if not noReturn:
|
|
# Wait for user input, then send a return.
|
|
raw_input('press enter to send return...')
|
|
send('\n')
|
|
|
|
if item is not demo_script[-1]:
|
|
raw_input('press enter to continue to next command...')
|
|
# Send the command slowly, as if it was typed.
|
|
if shouldClear:
|
|
print "clearing screen"
|
|
send(command="clear")
|
|
send('\n')
|
|
|
|
# Notify screen that the demo is over, after a small wait period.
|
|
# time.sleep(0.1)
|
|
# send('Demo session is over.', command='wall')
|
|
|
|
if __name__ == '__main__':
|
|
main()
|