cmds 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 746aa0ec8697ab254e151c8000620c7a3a6d8c52
4
- data.tar.gz: d15e1589321da1a22ad00d98cb12875d71a0ea7b
3
+ metadata.gz: 327a49d0895e5e91d1d35c9ab352357a4a577f65
4
+ data.tar.gz: f2f7bd60a0b9bcdfca5a7e50a28ac386f329d33a
5
5
  SHA512:
6
- metadata.gz: 186e86b834c8d38aa58b624c394acc850848fff6faac92ff10ecd3336992beff7a6b9d3a139baaec9148b12e1fe036c04a29bf954dde6c27a14309cf69304f98
7
- data.tar.gz: de1c715943e12a45f003e5e9a4b0c9b63f8443c8c42a64a35d983f6d742404d82b28eddc06ad238d1777e3aaf20bb1b95ccc4871abfce1090d3b52c822e7846b
6
+ metadata.gz: c22d98773434a8c16df0420d599222e00df2f5fcca68e448f889f16671d35db3ab441faa8d6194419c690f435b60e28b1992cc2cbddb0614c79f26fa378e5033
7
+ data.tar.gz: ca4371971382c85c6438bafac00c40f637a9e7dbeb2e232838ea9ae2e11ffdc7de5f6989ccd76560f2d09cac452d7da5438e291a29b1baa24dc64e93e8abbacb
data/Rakefile CHANGED
@@ -1 +1,153 @@
1
+ require 'thread'
2
+ require 'pastel'
3
+ require 'json'
4
+ require 'pp'
5
+ require 'tempfile'
6
+
1
7
  require "bundler/gem_tasks"
8
+
9
+ Bundler.require
10
+
11
+ def configure_logger
12
+ logger = Logger.new $stderr
13
+
14
+ logger.level = case ENV['log']
15
+ when 'debug'
16
+ Logger::DEBUG
17
+ when 'info'
18
+ Logger::INFO
19
+ when 'warn'
20
+ Logger::WARN
21
+ when 'error'
22
+ Logger::ERROR
23
+ else
24
+ Logger::INFO
25
+ end
26
+
27
+ logger.formatter = proc do |severity, datetime, progname, msg|
28
+ formatted = if Thread.current[:name]
29
+ "[rake #{ severity } - #{ Thread.current[:name ] }] #{msg}\n"
30
+ else
31
+ "[rake #{ severity }] #{msg}\n"
32
+ end
33
+
34
+ if severity == 'DEBUG'
35
+ formatted = Pastel.new.cyan(formatted)
36
+ end
37
+
38
+ formatted
39
+ end
40
+ logger
41
+ end
42
+
43
+ def log
44
+ $logger ||= configure_logger
45
+ end
46
+
47
+ namespace :debug do
48
+ desc "turn debug logging on"
49
+ task :conf do
50
+ ENV['log'] ||= 'debug'
51
+ Cmds.enable_debug
52
+ end
53
+
54
+ task :proxy => :conf do
55
+ Cmds.new("./test/questions.rb").proxy
56
+ end
57
+
58
+ namespace :capture do
59
+ desc "capture with io-like input with debugging enabled"
60
+ task :io_input => :conf do
61
+ File.open "./test/lines.txt" do |f|
62
+ Cmds.new("./test/echo_cmd.rb", input: f).capture
63
+ end
64
+ end
65
+ end # ns capture
66
+
67
+ namespace :stream do
68
+ input = NRSER.dedent <<-BLOCK
69
+ one
70
+ two
71
+ three
72
+ BLOCK
73
+
74
+ desc "output to blocks"
75
+ task :blocks => :conf do
76
+ Cmds.stream "ls" do |io|
77
+ io.on_out do |line|
78
+ puts "line: #{ line.inspect }"
79
+ end
80
+ end
81
+ end
82
+
83
+ desc "use a file as output"
84
+ task :file_out => :conf do
85
+ f = Tempfile.new "blah"
86
+ Cmds.stream "echo here" do |io|
87
+ io.out = f
88
+ end
89
+
90
+ f.rewind
91
+ puts f.read
92
+ f.close
93
+ f.unlink
94
+ end
95
+
96
+ desc "input block value"
97
+ task :value => :conf do
98
+ Cmds.stream "wc -l" do
99
+ input
100
+ end
101
+ end
102
+
103
+ desc "input block hanlder"
104
+ task :handler => :conf do
105
+ Cmds.stream "wc -l" do |io|
106
+ io.on_in do
107
+ end
108
+ end
109
+ end
110
+
111
+ desc "input io"
112
+ task :io => :conf do
113
+ File.open "./test/lines.txt" do |f|
114
+ Cmds.stream("wc -l") { f }
115
+ end
116
+ end
117
+
118
+ # this was a vauge idea that doesn't yet work, and may never
119
+ # need a better understanding probably, so gonna punt for now
120
+ desc "play with questions"
121
+ task :questions => :conf do
122
+ q = nil
123
+ a = nil
124
+
125
+ as = {
126
+ "what is your name?" => 'nrser',
127
+ "what is your quest?" => 'make this shit work somehow',
128
+ "what is you favorite color?" => 'blue',
129
+ }
130
+
131
+ Cmds.stream "./test/questions.rb" do |io|
132
+ io.on_out do |line|
133
+ puts "on_out called"
134
+ q = line
135
+ puts "questions asked: #{ q }"
136
+ a = as[q]
137
+ raise "unknown question: #{ q }" unless a
138
+ puts "setting answer to #{ a }..."
139
+ end
140
+
141
+ io.on_in do |f|
142
+ puts "on_in called"
143
+ if a
144
+ puts "responding with #{ a }."
145
+ f.write a
146
+ else
147
+ puts "no response ready."
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end # namespace stream
153
+ end # namespace debug
data/ansible/dev.yml CHANGED
@@ -10,6 +10,11 @@
10
10
  version: master
11
11
  dir_name: rails
12
12
 
13
+ - owner: ruby
14
+ name: ruby
15
+ version: v2_2_2
16
+ dir_name: ruby-v2_2_2
17
+
13
18
  tasks:
14
19
 
15
20
  - name: install gems
data/cmds.gemspec CHANGED
@@ -24,4 +24,5 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency "bundler", "~> 1.5"
25
25
  spec.add_development_dependency "rake"
26
26
  spec.add_development_dependency "rspec"
27
+ spec.add_development_dependency "pastel"
27
28
  end
@@ -0,0 +1,47 @@
1
+ class Cmds
2
+ # invokes the command and returns a Result with the captured outputs
3
+ def capture *subs, &input_block
4
+ Cmds.debug "entering Cmds#capture",
5
+ subs: subs,
6
+ input_block: input_block
7
+
8
+ # merge any stored args and kwds and replace input if provided
9
+ options = merge_options subs, input_block
10
+ Cmds.debug "merged options:",
11
+ options: options
12
+
13
+ # build the command string
14
+ cmd = Cmds.sub @template, options[:args], options[:kwds]
15
+ Cmds.debug "built command string: #{ cmd.inspect }"
16
+
17
+ out = ''
18
+ err = ''
19
+
20
+ Cmds.debug "calling Cmds#really_stream..."
21
+ status = really_stream cmd, options do |io|
22
+ # send the input to stream, which sends it to spawn
23
+ io.in = options[:input]
24
+
25
+ # and concat the output lines as they come in
26
+ io.on_out do |line|
27
+ out += line
28
+ end
29
+
30
+ io.on_err do |line|
31
+ err += line
32
+ end
33
+ end
34
+ Cmds.debug "Cmds#really_stream completed",
35
+ status: status
36
+
37
+ # build a Result
38
+ # result = Cmds::Result.new cmd, status, out_reader.value, err_reader.value
39
+ result = Cmds::Result.new cmd, status, out, err
40
+
41
+ # tell the Result to assert if the Cmds has been told to, which will
42
+ # raise a SystemCallError with the exit status if it was non-zero
43
+ result.assert if @assert
44
+
45
+ return result
46
+ end # #capture
47
+ end
data/lib/cmds/debug.rb ADDED
@@ -0,0 +1,101 @@
1
+ require 'logger'
2
+
3
+ # debug logging stuff
4
+ class Cmds
5
+
6
+ module Debug
7
+ # constants
8
+
9
+ # change the color of debug output by thread name (if present)
10
+ THREAD_COLORS = {
11
+ 'INPUT' => :cyan,
12
+ 'OUTPUT' => :green,
13
+ 'ERROR' => :red,
14
+ }
15
+ # available Pastel styles:
16
+ #
17
+ # clear, reset, bold, dark, dim, italic, underline, underscore, inverse, hidden, strikethrough,
18
+ # black, red, green, yellow, blue, magenta, cyan, white,
19
+ # on_black, on_red, on_green, on_yellow, on_blue, on_magenta, on_cyan, on_white,
20
+ # bright_black, bright_red, bright_green, bright_yellow, bright_blue, bright_magenta, bright_cyan, bright_white,
21
+ # on_bright_black, on_bright_red, on_bright_green, on_bright_yellow, on_bright_blue, on_bright_magenta, on_bright_cyan, on_bright_white
22
+ #
23
+
24
+ # class variables
25
+ @@on = false
26
+ @@logger = nil
27
+
28
+ # class methods
29
+ # =============
30
+
31
+ # get the Logger instance. may be `nil`.
32
+ def self.logger
33
+ @@logger
34
+ end
35
+
36
+ # test if the logger is configured.
37
+ def self.configured?
38
+ !! @@logger
39
+ end
40
+
41
+ # configure the Logger with optional destination
42
+ def self.configure dest = $stdout
43
+ require 'pastel'
44
+ @@pastel = Pastel.new
45
+
46
+ @@logger = Logger.new dest
47
+ @@logger.level = Logger::DEBUG
48
+ @@logger.formatter = proc do |severity, datetime, progname, msg|
49
+ if Thread.current[:name]
50
+ msg = "[Cmds #{ severity } - #{ Thread.current[:name ] }] #{msg}\n"
51
+
52
+ if color = THREAD_COLORS[Thread.current[:name]]
53
+ msg = @@pastel.method(color).call msg
54
+ end
55
+
56
+ msg
57
+ else
58
+ "[Cmds #{ severity }] #{msg}\n"
59
+ end
60
+ end
61
+ end
62
+
63
+ # turn debug logging on. if you provide a block it will turn debug logging
64
+ # on for that block and off at the end.
65
+ def self.on &block
66
+ configure unless configured?
67
+ @@on = true
68
+ if block
69
+ yield
70
+ off
71
+ end
72
+ end
73
+
74
+ # turn debug logging off.
75
+ def self.off
76
+ @@on = false
77
+ end
78
+
79
+ # test if debug logging is on.
80
+ def self.on?
81
+ @@on
82
+ end
83
+
84
+ # format a debug message with optional key / values to print
85
+ def self.format msg, values = {}
86
+ if values.empty?
87
+ msg
88
+ else
89
+ msg + "\n" + values.map {|k, v| " #{ k }: #{ v.inspect }" }.join("\n")
90
+ end
91
+ end
92
+
93
+ end # module Debug
94
+
95
+ # log a debug message along with an optional hash of values.
96
+ def self.debug msg, values = {}
97
+ # don't even bother unless debug logging is turned on
98
+ return unless Debug.on?
99
+ Debug.logger.debug Debug.format(msg, values)
100
+ end
101
+ end # class Cmds
@@ -0,0 +1,30 @@
1
+ class Cmds
2
+ class ERBContext < BasicObject
3
+ def initialize args, kwds
4
+ @args = args
5
+ @kwds = kwds
6
+ @arg_index = 0
7
+ end
8
+
9
+ def method_missing sym, *args, &block
10
+ if args.empty? && block.nil?
11
+ if sym.to_s[-1] == '?'
12
+ key = sym.to_s[0...-1].to_sym
13
+ @kwds[key]
14
+ else
15
+ @kwds.fetch sym
16
+ end
17
+ else
18
+ super
19
+ end
20
+ end
21
+
22
+ def get_binding
23
+ ::Kernel.send :binding
24
+ end
25
+
26
+ def arg
27
+ @args.fetch(@arg_index).tap {@arg_index += 1}
28
+ end
29
+ end # end ERBContext
30
+ end # class Cmds
@@ -0,0 +1,76 @@
1
+ class Cmds
2
+ class IOHandler
3
+ attr_accessor :in, :out, :err
4
+
5
+ def initialize
6
+ @queue = Queue.new
7
+ @in = nil
8
+ @out = $stdout
9
+ @err = $stderr
10
+ end
11
+
12
+ def on_out &block
13
+ @out = block
14
+ end
15
+
16
+ # called in seperate thread handling process IO
17
+ def thread_send_out line
18
+ @queue << [:out, line]
19
+ end
20
+
21
+ def on_err &block
22
+ @err = block
23
+ end
24
+
25
+ # called in seperate thread handling process IO
26
+ def thread_send_err line
27
+ @queue << [:err, line]
28
+ end
29
+
30
+ def thread_send_line sym, line
31
+ @queue << [sym, line]
32
+ end
33
+
34
+ def start
35
+ # if out is a proc, it's not done
36
+ out_done = ! @out.is_a?(Proc)
37
+ # same for err
38
+ err_done = ! @err.is_a?(Proc)
39
+
40
+ until out_done && err_done
41
+ key, line = @queue.pop
42
+
43
+ case key
44
+ when :out
45
+ if line.nil?
46
+ out_done = true
47
+ else
48
+ handle_line @out, line
49
+ end
50
+
51
+ when :err
52
+ if line.nil?
53
+ err_done = true
54
+ else
55
+ handle_line @err, line
56
+ end
57
+
58
+ else
59
+ raise "bad key: #{ key.inspect }"
60
+ end
61
+ end
62
+ end #start
63
+
64
+ private
65
+
66
+ def handle_line dest, line
67
+ if dest.is_a? Proc
68
+ dest.call line
69
+ else
70
+ dest.puts line
71
+ end
72
+ end
73
+
74
+ # end private
75
+ end # end IOHandler
76
+ end # class Cmds
data/lib/cmds/pipe.rb ADDED
@@ -0,0 +1,13 @@
1
+ class Cmds
2
+ # stupid little wrapper around IO.pipe that can have some extra info
3
+ # attached to it
4
+ class Pipe
5
+ attr_reader :name, :sym, :r, :w
6
+
7
+ def initialize name, sym
8
+ @name = name
9
+ @sym = sym
10
+ @r, @w = IO.pipe
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,34 @@
1
+ class Cmds
2
+ class Result
3
+ attr_reader :cmd, :status, :out, :err
4
+
5
+ def initialize cmd, status, out, err
6
+ @cmd = cmd
7
+ @status = status
8
+ @out = out
9
+ @err = err
10
+ end
11
+
12
+ def ok?
13
+ @status == 0
14
+ end
15
+
16
+ def error?
17
+ ! ok?
18
+ end
19
+
20
+ # raises an error if there was one
21
+ # returns the Result so that it can be chained
22
+ def assert
23
+ if error?
24
+ msg = NRSER.squish <<-BLOCK
25
+ command `#{ @cmd }` exited with status #{ @status }
26
+ and stderr #{ err.inspect }
27
+ BLOCK
28
+
29
+ raise SystemCallError.new msg, @status
30
+ end
31
+ self
32
+ end # raise_error
33
+ end
34
+ end # class Cmds
@@ -0,0 +1,11 @@
1
+ require 'erubis'
2
+
3
+ class Cmds
4
+ # extension of Erubis' EscapedEruby (which auto-escapes `<%= %>` and
5
+ # leaves `<%== %>` raw) that calls `Cmds.expand_sub` on the value
6
+ class ShellEruby < Erubis::EscapedEruby
7
+ def escaped_expr code
8
+ "::Cmds.expand_sub(#{code.strip})"
9
+ end
10
+ end
11
+ end # class Cmds