forked from swiftlang/swift
-
Notifications
You must be signed in to change notification settings - Fork 0
/
demo-tool
executable file
·191 lines (153 loc) · 5.54 KB
/
demo-tool
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#!/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()