wip-runner 0.3.4 → 0.4.0

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: 5bb36ff238b91a06e9cb2788a7c2a5339dc8d2a6
4
- data.tar.gz: 4d839159e03cd18ec8e50e7f97a60b2a4adb3b25
3
+ metadata.gz: 43076f87b14007f06ce003584c7cbe366170e629
4
+ data.tar.gz: ea94ff0e8cd0384b234f6921411178d8bc781875
5
5
  SHA512:
6
- metadata.gz: 14a1d7b3f7c6051b0e07b6fe29954c29cc776bc2dd2f8004eaec9020ed093b9930822d163bfab026393fa2066fa05def72c2a1ece6f0d88783df2671a9230e1c
7
- data.tar.gz: 51026c6b225deac5efab13f9e2578c91aa6070c9aa3f816b9406e33d693d232ce8175f2965378283fddea821dfbb614b9b801b2e263d2b46f182f7a956c02143
6
+ metadata.gz: 64247802ae56cdd2c96294c402e8e6aaf7183362ef0a97fad35b5910b0640855005ad81e29d84e3c68d2345e9beb9f4d5c803b9b2d43de721381773366549b97
7
+ data.tar.gz: bb3b9642aef06a98c988b32504e82ee03f9c79d9e66b8e41dce35a2fbe5525669e17d267452e861a8a40cf89d98a7157cd5441e7a09b8a6b961b03abe769567d
@@ -18,9 +18,9 @@ module WIP
18
18
 
19
19
  def command_parser(params)
20
20
  command = params.command
21
- return CLI::Parser.new(@io) if command.nil?
21
+ return CLI::Parser.new(@ui) if command.nil?
22
22
 
23
- Commands.locate(command).new(@io).parser
23
+ Commands.locate(command).new(@ui).parser
24
24
  end
25
25
  end
26
26
  end
@@ -4,7 +4,9 @@ module WIP
4
4
  overview 'Prints version information'
5
5
 
6
6
  def execute(params, options)
7
- @io.say "#{WIP::Runner::CLI.signature} version #{WIP::Runner::CLI.namespace::VERSION}"
7
+ @ui.out {
8
+ @ui.say("#{WIP::Runner::CLI.signature} version #{WIP::Runner::CLI.namespace::VERSION}")
9
+ }
8
10
  end
9
11
  end
10
12
  end
@@ -1,5 +1,3 @@
1
- require 'highline'
2
-
3
1
  module WIP
4
2
  module Runner
5
3
  class CLI
@@ -40,10 +38,9 @@ module WIP
40
38
  end
41
39
  end
42
40
 
43
- def initialize(io = HighLine.new)
44
- @io = io
45
- @parser = Parser.new(io)
46
-
41
+ def initialize(ui = UI.new)
42
+ @ui = ui
43
+ @parser = Parser.new(ui)
47
44
  trap('INT') { quit }
48
45
  trap('TERM') { quit }
49
46
  end
@@ -57,8 +54,10 @@ module WIP
57
54
  recipient = (command(args) || @parser)
58
55
  recipient.run(args)
59
56
  rescue InvalidCommand => e
60
- @io.say(e.message)
61
- @io.newline
57
+ @ui.err {
58
+ @ui.say(e.message)
59
+ @ui.newline
60
+ }
62
61
  @parser.help
63
62
  end
64
63
 
@@ -66,12 +65,12 @@ module WIP
66
65
 
67
66
  def command(args)
68
67
  handler = Commands.locate(args.shift)
69
- handler.nil? ? nil : handler.new(@io)
68
+ handler.nil? ? nil : handler.new(@ui)
70
69
  end
71
70
 
72
71
  class Parser
73
- def initialize(io)
74
- @io = io
72
+ def initialize(ui)
73
+ @ui = ui
75
74
  end
76
75
 
77
76
  def run(args)
@@ -80,7 +79,9 @@ module WIP
80
79
  end
81
80
 
82
81
  def help
83
- @io.say(options.help)
82
+ @ui.err {
83
+ @ui.say(options.help)
84
+ }
84
85
  end
85
86
 
86
87
  private
@@ -106,7 +107,9 @@ module WIP
106
107
  parser.separator 'Options:'
107
108
 
108
109
  parser.on_tail '-h', '--help', 'Prints help messages' do
109
- @io.say(parser)
110
+ @ui.err {
111
+ @ui.say(parser)
112
+ }
110
113
  end
111
114
  end
112
115
  end
@@ -45,9 +45,9 @@ module WIP
45
45
 
46
46
  attr_reader :parser # TODO(?)... :arguments, :options
47
47
 
48
- def initialize(io)
49
- @io = io
50
- @parser = WIP::Runner::Parser.new(@io, self.class)
48
+ def initialize(ui)
49
+ @ui = ui
50
+ @parser = WIP::Runner::Parser.new(@ui, self.class)
51
51
  end
52
52
 
53
53
  def run(argv = [])
@@ -82,7 +82,7 @@ module WIP
82
82
  def validate!(arguments)
83
83
  unless parser.arguments.empty? || parser.config.no_validate
84
84
  missing = parser.arguments.keys.inject({}) do |memo, key|
85
- memo[key] = nil if arguments[key].nil?
85
+ memo[key] = nil if arguments[key].nil? || arguments[key].empty?
86
86
  memo
87
87
  end
88
88
  raise InvalidArguments, missing unless missing.empty?
@@ -92,13 +92,15 @@ module WIP
92
92
  private
93
93
 
94
94
  def delegate(command, argv)
95
- target = Commands.locate(command, self.class).new(@io)
95
+ target = Commands.locate(command, self.class).new(@ui)
96
96
  target.run(argv)
97
97
  end
98
98
 
99
99
  def print_error(e)
100
- @io.say(e.message)
101
- @io.newline
100
+ @ui.err {
101
+ @ui.say(e.message)
102
+ @ui.newline
103
+ }
102
104
  parser.help
103
105
  end
104
106
  end
@@ -3,6 +3,10 @@ require 'ostruct'
3
3
  module WIP
4
4
  module Runner
5
5
  class Options < OpenStruct
6
+ def to_hash
7
+ self.to_h
8
+ end
9
+
6
10
  def each(&block)
7
11
  self.to_h.each(&block)
8
12
  end
@@ -14,6 +18,10 @@ module WIP
14
18
  def values
15
19
  self.to_h.values
16
20
  end
21
+
22
+ def merge(other)
23
+ Options.new(self.to_h.merge(other.to_h))
24
+ end
17
25
  end
18
26
  end
19
27
  end
@@ -5,8 +5,8 @@ module WIP
5
5
  class Parser
6
6
  attr_reader :config
7
7
 
8
- def initialize(io, command)
9
- @io = io
8
+ def initialize(ui, command)
9
+ @ui = ui
10
10
  @command = command
11
11
  @config = WIP::Runner::Options.new
12
12
  end
@@ -21,7 +21,12 @@ module WIP
21
21
 
22
22
  @args = WIP::Runner::Options.new.tap do |opts|
23
23
  arguments.keys.each_with_index do |key, index|
24
- opts[key] = remaining[index]
24
+ if arguments[key].multiple
25
+ opts[key] = remaining[index..-1]
26
+ break
27
+ else
28
+ opts[key] = remaining[index]
29
+ end
25
30
  end
26
31
  end
27
32
 
@@ -30,7 +35,9 @@ module WIP
30
35
  end
31
36
 
32
37
  def help
33
- @io.say(options.help)
38
+ @ui.err {
39
+ @ui.say(options.help)
40
+ }
34
41
  end
35
42
 
36
43
  def options
@@ -87,6 +94,7 @@ module WIP
87
94
  pairs.each do |name, definition|
88
95
  padding = ' ' * (parser.summary_width - name.length + 1)
89
96
  overview = definition[:overview]
97
+ overview << ' [multiple]' if definition[:multiple]
90
98
  parser.separator [parser.summary_indent, name, padding, overview].join('')
91
99
  end
92
100
  end
@@ -10,8 +10,13 @@ module WIP
10
10
  instance_exec(&block) if block_given?
11
11
  end
12
12
 
13
- def description
14
- raise NotImplementedError
13
+ def content(format = :text)
14
+ case format
15
+ when :markdown
16
+ "```\n#{@content}\n```"
17
+ else
18
+ @content
19
+ end
15
20
  end
16
21
 
17
22
  def execute(io, env, &block)
@@ -15,17 +15,8 @@ module WIP
15
15
  super
16
16
  end
17
17
 
18
- def description(format = :text)
19
- case format
20
- when :markdown
21
- "```\n#{@content}\n```"
22
- else
23
- @content
24
- end
25
- end
26
-
27
- def execute(io, env, &block)
28
- prompts.empty? ? simplex!(io, env, &block) : complex!(io, env, &block)
18
+ def execute(ui, env, &block)
19
+ prompts.empty? ? simplex!(ui, env, &block) : complex!(ui, env, &block)
29
20
  end
30
21
 
31
22
  def name(value)
@@ -46,7 +37,7 @@ module WIP
46
37
  ([@name] + @args).join(' ')
47
38
  end
48
39
 
49
- def simplex!(io, env, &block)
40
+ def simplex!(ui, env, &block)
50
41
  Open3.popen2e(env, "#{executable} #{arguments}") do |stdin, stdoe, thread|
51
42
  while line = stdoe.gets
52
43
  block.call(line)
@@ -56,11 +47,11 @@ module WIP
56
47
  end
57
48
  end
58
49
 
59
- def complex!(io, env, &block)
50
+ def complex!(ui, env, &block)
60
51
  Open3.popen2e(env, "#{executable} #{arguments}") do |stdin, stdoe, thread|
61
52
  prompts.each do |term, options|
62
53
  stdoe.expect(term) do |result|
63
- stdin.puts io.ask(term) do |q|
54
+ stdin.puts ui.ask(term) do |q|
64
55
  options.each { |k, v| q.send(:"#{k}=", v) }
65
56
  end
66
57
  stdoe.gets
@@ -3,11 +3,6 @@ module WIP
3
3
  module Shell
4
4
  module Handlers
5
5
  class System < Base
6
- def description
7
- # @description ||= "```\n#{@content}\n```"
8
- @description ||= @content
9
- end
10
-
11
6
  def execute(io, env, &block)
12
7
  IO.popen(env, executable, 'r') do |pipe|
13
8
  pipe.each(&block)
@@ -6,150 +6,155 @@ module WIP
6
6
  class Runner
7
7
  attr_reader :arguments, :options
8
8
 
9
- def initialize(io, tasks, env = {})
10
- @io = io
11
- @tasks = tasks
12
- @env = env
13
- @io.indent_size = 2
9
+ # TODO: enforce env keys as String OR Symbol
10
+ def initialize(ui, env = {})
11
+ @ui = ui
12
+ @env = env
14
13
  end
15
14
 
16
- def run(arguments, options)
15
+ # TODO: custom proc for UI???
16
+ def run(tasks, arguments, options, &block)
17
17
  @arguments = arguments
18
- @options = options
19
-
20
- if markdown?
21
- @io.indent do
22
- @tasks.each do |task|
23
- evaluate(task)
24
- end
25
- end
18
+ @options = default(:options).merge(options)
19
+
20
+ if format == :markdown
21
+ raise 'TODO'
22
+ # @ui.out {
23
+ # @ui.indent do
24
+ # [tasks].flatted.each do |task|
25
+ # evaluate(task)
26
+ # end
27
+ # end
28
+ # }
26
29
  else
27
- @tasks.each do |task|
28
- evaluate(task)
30
+ [tasks].flatten.each do |task|
31
+ evaluate(task, &block)
29
32
  end
30
33
  end
31
34
  end
32
35
 
33
36
  private
34
37
 
35
- def evaluate(task)
38
+ def default(setting)
39
+ @defaults ||= {
40
+ :options => Options.new({
41
+ :echo => true,
42
+ :format => :text,
43
+ :interactive => true,
44
+ :mode => :execute
45
+ }),
46
+ :procs => {
47
+ :execute => Proc.new { |line| @ui.out { @ui.say("> #{line.rstrip}") } },
48
+ :silent => Proc.new { |line| }
49
+ }
50
+ }
51
+
52
+ @defaults[setting]
53
+ end
54
+
55
+ def evaluate(task, &block)
36
56
  task.build(arguments, options)
37
- prefix = options.preview ? :preview : :execute
38
57
 
39
- section('Config') do
40
- # @io.newline
41
- # @io.say '```'
42
- task.configs.each do |term, options|
43
- send(:"#{prefix}_config", term, options)
58
+ section(task.heading) do
59
+ if interactive? && ! task.configs.empty?
60
+ task.configs.each do |term, options, b|
61
+ evaluate_config(term, options, &b)
62
+ end
63
+ @ui.err { @ui.newline }
44
64
  end
45
- # @io.say '```'
46
- end unless task.configs.empty?
47
65
 
48
- task.shells.each do |shell|
49
- section("Shell #{shell.type.downcase}") do
50
- send(:"#{prefix}_shell", shell)
51
- @io.newline
66
+ task.shells.each do |shell|
67
+ send(:"#{mode}_shell", shell, &block)
52
68
  end
53
- end
54
69
 
55
- # p task.children
56
- task.children.each do |child|
57
- section('Task') do
58
- evaluate(child)
70
+ task.steps.each do |step|
71
+ evaluate(step, &block)
59
72
  end
60
73
  end
61
74
  end
62
75
 
63
- # ---
64
-
65
- # class Execute
66
- # end
67
- #
68
- # class Preview
69
- # end
76
+ def default_config(term, options = {})
77
+ options[:default] || @env[term] || ENV[term]
78
+ end
70
79
 
71
- def execute_config(term, options = {})
80
+ def evaluate_config(term, options = {})
72
81
  query = options[:required] ? "#{term} (*)" : term
73
- answer = @io.ask("- #{query}: ") do |q|
74
- q.default = (options[:default] || ENV[term]) unless options[:password]
75
- q.echo = false if options[:password]
76
- q.validate = /^.+$/ if options[:required]
82
+ answer = @ui.err do
83
+ @ui.ask("- #{query}: ") do |q|
84
+ q.default = default_config(term, options) unless options[:password]
85
+ q.echo = false if options[:password]
86
+ q.validate = /^.+$/ if options[:required]
87
+ end
77
88
  end
78
- @env[term] = answer unless answer.empty?
79
- @env[term] ||= ENV[term]
80
- end
81
-
82
- def execute_shell(shell)
83
- preview_shell(shell)
84
89
 
85
- if approved?
86
- @io.newline
87
- result = shell.execute(@io, @env) do |line|
88
- # @io.say "> `#{line.rstrip}`<br>"
89
- @io.say "> #{line.rstrip}"
90
- # puts "#{@io.indentation}> `#{line.rstrip}` "
91
- # @io.instance_variable_get(:@output).puts "> `#{line.rstrip}` "
92
-
93
- # @io.send((action || :say), line)
94
- end
95
- @io.newline
90
+ if block_given?
91
+ yield answer
92
+ else
93
+ @env[term] = answer unless answer.empty?
94
+ @env[term] ||= ENV[term]
95
+ end
96
+ end
96
97
 
97
- # TODO: raise instead of exit.
98
- exit 1 unless result.success?
98
+ def display_shell(shell, &block)
99
+ if block_given?
100
+ block.call(shell.content)
99
101
  else
100
- @io.newline
101
- @io.say '> (skipped)'
102
+ @ui.out {
103
+ @ui.say(shell.content)
104
+ }
102
105
  end
103
106
  end
104
107
 
105
- def preview_config(term, options = {})
106
- message = options[:required] ? "#{term} (*)" : term
107
- @io.say "- #{message}"
108
+ def execute_shell(shell, &block)
109
+ display_shell(shell) unless (mode == :silent) || ! echo?
110
+
111
+ @ui.out {
112
+ if approved?
113
+ if block_given?
114
+ result = shell.execute(@ui, @env, &block)
115
+ else
116
+ @ui.newline
117
+ result = shell.execute(@ui, @env, &default(:procs)[mode])
118
+ @ui.newline
119
+ end
120
+
121
+ # TODO: raise instead of exit.
122
+ exit 1 unless result.success?
123
+ else
124
+ if block_given?
125
+ block.call('> (skipped)')
126
+ else
127
+ @ui.newline
128
+ @ui.say('> (skipped)')
129
+ end
130
+ end
131
+ }
108
132
  end
109
133
 
110
- def preview_shell(shell)
111
- @io.say shell.description
134
+ def silent_shell(shell)
135
+ execute_shell(shell)
112
136
  end
113
137
 
114
138
  # ---
115
139
 
116
140
  def section(heading, &block)
117
- if markdown?
118
- @io.say "- [ ] #{heading}..."
119
- @io.indent(&block)
141
+ if format == :markdown
142
+ @ui.out {
143
+ @ui.say("- [ ] #{heading}")
144
+ @ui.indent(&block)
145
+ }
120
146
  else
121
- yield
147
+ @ui.err {
148
+ if heading
149
+ @ui.say(heading)
150
+ @ui.newline
151
+ end
152
+ yield
153
+ @ui.newline
154
+ }
122
155
  end
123
156
  end
124
157
 
125
- def format
126
- @options.format ? @options.format.intern : :text
127
- end
128
-
129
- def markdown?
130
- format == :markdown
131
- end
132
-
133
- # $ wip-runner x --format=markdown
134
- # $ wip-runner x --log=out.md # log format determined by extension
135
- #
136
- # @formatter = Formatter::Markdown.new(@io)
137
- #
138
- # def item(text)
139
- # formatter.item(text)
140
- # end
141
- #
142
- # class Formatter::Markdown
143
- # def item(text, check = true)
144
- # @io.say check ? "- [ ] #{text}" : "- #{text}"
145
- # end
146
- # end
147
- #
148
- # class Formatter::Plain
149
- # class Formatter::Color
150
- # class Formatter::HTML
151
- # class Formatter::JSON
152
-
153
158
  # ---
154
159
 
155
160
  def approved?
@@ -159,6 +164,22 @@ module WIP
159
164
  # when 'yes'
160
165
  # end
161
166
  end
167
+
168
+ def echo?
169
+ !! options.echo
170
+ end
171
+
172
+ def format
173
+ options.format
174
+ end
175
+
176
+ def interactive?
177
+ options.interactive
178
+ end
179
+
180
+ def mode
181
+ options.mode
182
+ end
162
183
  end
163
184
  end
164
185
  end
@@ -2,30 +2,35 @@ module WIP
2
2
  module Runner
3
3
  module Shell
4
4
  class Task
5
- attr_reader :configs, :shells, :children
6
-
7
- def initialize(command, &block)
8
- @command = command
9
- @configs = []
10
- @shells = []
11
- @children = []
12
- @block = block
5
+ attr_reader :heading, :configs, :shells, :steps
6
+
7
+ def initialize(command, *args, &block)
8
+ @command = command
9
+ @configs = []
10
+ @shells = []
11
+ @steps = []
12
+ @heading = args.first unless args.empty?
13
+ @block = block
13
14
  end
14
15
 
15
16
  def build(arguments, options)
16
17
  self.instance_exec(arguments, options, &@block) ; self
17
18
  end
18
19
 
19
- def config(term, options = {})
20
- @configs << [term.to_s, options] # Config.new(...)
20
+ def heading?
21
+ !! @heading
22
+ end
23
+
24
+ def config(term, options = {}, &block)
25
+ @configs << [term.to_s, options, block] # Config.new(...)
21
26
  end
22
27
 
23
28
  def shell(handler, content, &block)
24
29
  shells << Handlers.locate(handler).new(content, &block)
25
30
  end
26
31
 
27
- def task(&block)
28
- children << Task.new(@command, &block)
32
+ def task(*args, &block)
33
+ steps << Task.new(@command, *args, &block)
29
34
  end
30
35
 
31
36
  protected
@@ -34,7 +39,6 @@ module WIP
34
39
  if @command.respond_to?(method_name)
35
40
  @command.send(method_name, *args, &block)
36
41
  else
37
- # super
38
42
  @command.instance_eval {
39
43
  method_missing(method_name, *args, &block)
40
44
  }
@@ -13,7 +13,7 @@ module WIP
13
13
  end
14
14
 
15
15
  def example_command(implementation)
16
- ExampleCommands.const_get(implementation).new(io)
16
+ ExampleCommands.const_get(implementation).new(ui)
17
17
  end
18
18
 
19
19
  module ExampleCommands
@@ -56,7 +56,9 @@ module WIP
56
56
 
57
57
  def execute(args, options)
58
58
  super
59
- @io.say 'running nested command...'
59
+ @ui.out {
60
+ @ui.say('running nested command...')
61
+ }
60
62
  end
61
63
  end
62
64
  end