karmi (owner)

Revisions

gist: 200739 Download_button fork
public
Description:
Replay a sequence of commands, with fake typing, output printing, wait points, and all. Because dead code on slides is stupid
Public Clone URL: git://gist.github.com/200739.git
Embed All Files: show embed
demo.sh #
1
2
3
4
5
6
7
8
# A demo
ls -la
# ---
# Let's create some file
touch somefile
# ---
ls -la
 
replay #
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
#!/usr/bin/env ruby
 
# Replay a sequence of commands, with fake typing, output printing, wait points, and all
# Because dead code on slides is stupid
 
# Supposed you have a file with commands:
#
# $ cat /tmp/demo.sh
# # A demo
# ls -la
# # ---
# # Let's create some file
# touch somefile
# # ---
# ls -la
#
# Then you can:
# $ replay /tmp/demo.sh
 
# Wait points are marked with "# wait" or "# ---". Use p, n or space and [ENTER] to continue. Blank lines are skipped
# Use --nowait options to skip wait points
# Use --verbose to print out comments
 
require 'optparse'
options = {}
OptionParser.new do |opts|
  opts.banner = "\e[1mUsage: replay path/to/commands.sh\e[0m"
  opts.on("-W", "--nowait", "Do not respect wait points") { |v| options[:nowait] = true }
  opts.on("-f", "--fast", "Do not fake typing") { |v| options[:fast] = true }
  opts.on("-v", "--verbose", "Print also comment lines") { |v| options[:verbose] = true }
end.parse!
 
class String
  def each_char
    self.split('').each { |c| yield c }
  end unless method_defined?(:each_char)
  def comment?
    self =~ /^#\s{0,1}.+$/
  end
  def continue?
    self =~ /^p$|^n$|^ $/
  end
  def finish?
    self =~ /^!/
  end
  def wait?
    self =~ /^#\s*wait$|^#\s*-+/
  end
end
 
if ARGV.empty?
  puts "\e[31;1m[!]\e[0m Usage: replay path/to/commands.sh"; exit(1)
end
 
begin
  commands = ARGF.read
rescue Errno::ENOENT
  puts "\e[31;1m[!]\e[0m Usage: replay path/to/commands.sh"; exit(1)
end
 
commands.each_line do |line|
  next if line.chomp.empty? # Skip blank lines right away
  unless line.wait? && !@finish && !options[:nowait]
    next if line.comment? && !options[:verbose] # Skip comment lines unless verbose
    unless line.comment?
      STDOUT.print "\e[32;1m▹\e[0m \e[1m"
      unless options[:fast]
        line.each_char do |letter|
          STDOUT.print letter
          STDOUT.flush
          sleep 0.05 unless line.comment?
        end
      else
        STDOUT.print line
      end
      STDOUT.print "\e[0m"
      if chdir = line[/^cd (.+)[ \n]$/, 1]; Dir.chdir(chdir); end # Follow `cd` commands
      STDOUT.print `#{line}` # Execute the shell command
    else
      STDOUT.print "\e[1m#{line}\e[0m" unless line.wait?
    end
  else # ... process wait line
    puts "\n\e[1mWaiting...\e[0m\n\n"
    trap(:INT, proc { puts "\n"+('-'*80)+"\n\n"; exit } ) # Exit nicely from Ctrl+C
    while input = STDIN.gets.chomp
      if input.finish? # Finish all without waiting
        puts "\n\e[1mFinishing all\e[0m\n"
        @finish = true
        break
      end
      break if input.continue? # Continue processing commands in queue...
      STDOUT.print `#{input}` unless input.empty? # ... or execute input
    end
  end
end