vagrant-devcommands 0.7.2 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2286eb231a9e6537418f0a60167b17b3022f386c
4
- data.tar.gz: 9faa6c649189f8626c622441c4ff9bb26a37a67c
3
+ metadata.gz: 32211b187c89aedb28b7e3b084553e07030fa971
4
+ data.tar.gz: 2be8cec37c79264056981c70acdd490ebdeb4d18
5
5
  SHA512:
6
- metadata.gz: f993ab2fff187f77800617b595e443ff15e3a7b4376bd8a733a0e7c2e30589475fa6790f29ee2d2cc6df910f015a7a7e52758f234966d100a93988096c0ccff6
7
- data.tar.gz: 3c2ae42e63a90567cb49085f5646143f115db29ec960def9eacce7b0b1704c0c3b717bc5d3c219544c07cfe274fb6923129448ea8fff653b1a76cbf61cfa2e8f
6
+ metadata.gz: a6a418391c08c271c88d3c334a88c1ad02173725fe2300bc81523ce9302b3344068769cdf52c23da6fd869a307bf8ba01f0a78855aca86afbaa2a42de384e858
7
+ data.tar.gz: cabdfa5024114480df1ae410ddfd7d78928a62099672fd6909838260fa0e314f708a73abd00d08e01d57917b14fe203a1149217aeefec1735cb1aca91466af37
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.8.0 (2017-04-19)
4
+
5
+ - Enhancements
6
+ - Chains can be defined to execute multiple commands in order
7
+ - Commands can define flags (always optional!) for script interpolation
8
+
3
9
  ## v0.7.2 (2017-03-12)
4
10
 
5
11
  - Bug fixes
data/README.md CHANGED
@@ -22,6 +22,8 @@ vagrant run your_command
22
22
  vagrant run your_box your_command
23
23
  ```
24
24
 
25
+ This runs commands or alternatively a command chain with the passed name.
26
+
25
27
  ### Command Definition
26
28
 
27
29
  Add to a `Commandfile` besides your `Vagrantfile`:
@@ -30,11 +32,11 @@ Add to a `Commandfile` besides your `Vagrantfile`:
30
32
  command 'basic', 'hostname'
31
33
 
32
34
  command 'with_options',
33
- box: :my_box,
34
- desc: 'executes "hostname" on the box "my_box"',
35
- script: 'hostname',
36
- usage: 'vagrant run %{command}',
37
- help: <<-eoh
35
+ box: :my_box,
36
+ desc: 'executes "hostname" on the box "my_box"',
37
+ script: 'hostname',
38
+ usage: 'vagrant run %{command}',
39
+ help: <<-eoh
38
40
  I am the help message for the command "with_options".
39
41
  I get displayed when running "vagrant run help with_options".
40
42
 
@@ -97,6 +99,36 @@ Escaping rules are defined as `{ "char_to_escape": "char_to_use_as_escape" }`.
97
99
  These are applied prior to interpolation into the command. Regular ruby escaping
98
100
  rules apply.
99
101
 
102
+ #### Commands with Flags
103
+
104
+ Every command can be associated with (by definition optional) flags available
105
+ for later command interpolation:
106
+
107
+ ```ruby
108
+ command 'with_flags',
109
+ flags: {
110
+ f_standard: { desc: "standard flag" },
111
+ f_valued: { value: "--f_modified" }
112
+ },
113
+ script: 'echo "flags: %{f_standard}"'
114
+ ```
115
+
116
+ This definition allows the following executions:
117
+
118
+ ```shell
119
+ # will execute 'echo "flags: "'
120
+ vagrant run with_flags
121
+
122
+ # will execute 'echo "flags: --f_standard"'
123
+ vagrant run with_flags --f_standard
124
+
125
+ # will execute 'echo "flags: --f_modified"'
126
+ vagrant run with_flags --f_valued
127
+ ```
128
+
129
+ By default a flag gets interpolated as "--#{flagname}". If a value is defined
130
+ this value will be interpolated unmodified.
131
+
100
132
  #### Commands defined by Lambda/Proc
101
133
 
102
134
  You can (more or less) dynamically generate your scripts by defining the
@@ -111,8 +143,7 @@ These will be evaluated when running the command.
111
143
 
112
144
  Every rule from regular scripts (parameters, escaping "%", ...) still apply.
113
145
 
114
-
115
- ### Experimental: global command definitions
146
+ ### Global Command Definitions
116
147
 
117
148
  To have commands available even wihout a `Commandfile` you can define the
118
149
  globally. To do this just create a file named `.vagrant.devcommands` in your
@@ -126,7 +157,70 @@ ruby -e "require 'pathname'; puts Pathname.new(Dir.home).join('.vagrant.devcomma
126
157
 
127
158
  Any commands defined there will silently be overwritten by a local definition.
128
159
 
129
- ### Abort parsing inside Commandfile
160
+ ### Experimental: Chain Definitions
161
+
162
+ You can define command chains to execute multiple commands in order:
163
+
164
+ ```ruby
165
+ chain 'my_chain',
166
+ break_on_error: false,
167
+ commands: [
168
+ { command: 'first' },
169
+ { command: 'second' },
170
+ { command: 'third' }
171
+ ],
172
+ desc: 'Command chain for three commands.',
173
+ help: <<-eoh
174
+ I am the help message for the chain "my_chain".
175
+ I get displayed when running "vagrant run help my_chain".
176
+
177
+ The usage printed above the help can interpolate the name
178
+ of the command name using %{command}.
179
+ eoh
180
+ ```
181
+
182
+ The configured commands will be executed in the order defined.
183
+
184
+ If one or more of your commands requires parameters all of them have to be
185
+ passed to the chain execution.
186
+
187
+ By default a chain breaks upon the first non-zero return value of any
188
+ configured command. To deactivate this behaviour you can set `:break_on_error`
189
+ to `false`. Any value other than `false` will stick to the default.
190
+
191
+ #### Chain Definitions with Pre-Defined Parameters
192
+
193
+ If required you can modify the arguments given to each chain element by setting
194
+ additional/custom argv values for a single chain element:
195
+
196
+ ```ruby
197
+ command 'chainecho',
198
+ parameters: { first: {}, second: {} },
199
+ script: 'echo %{first} %{second}'
200
+
201
+ chain 'my_customized_chain',
202
+ commands: [
203
+ { command: 'chainecho', argv: ['--first="param"'] },
204
+ { command: 'chainecho' },
205
+ { command: 'chainecho', argv: ['--first="param"', '--second="param"'] }
206
+ ]
207
+ ```
208
+
209
+ Running the chain will execute the following commands:
210
+
211
+ ```shell
212
+ > vagrant run my_customized_chain --first="initial" --second="initial"
213
+
214
+ vagrant run chainecho --first="param" --second="initial"
215
+ vagrant run chainecho --first="initial" --second="initial"
216
+ vagrant run chainecho --first="param" --second="param"
217
+ ```
218
+
219
+ By default every command will be executed using the box defined by the command
220
+ itself or the only one available. You can, however, run the complete chain
221
+ against a specific box using `vagrant run your_box your_chain`.
222
+
223
+ ### Abort Parsing inside Commandfile
130
224
 
131
225
  If you, for whatever reasons, want to abort further parsing of a `Commandfile`
132
226
  you can simple return from it:
@@ -166,10 +260,10 @@ a sigil notation like the following:
166
260
 
167
261
  ```ruby
168
262
  command 'long_running_task',
169
- script: %(cd /path/to/somewhere \
170
- && echo "starting long running task" \
171
- && ./long_running_task.sh \
172
- && echo "finished long running task")
263
+ script: %(cd /path/to/somewhere \
264
+ && echo "starting long running task" \
265
+ && ./long_running_task.sh \
266
+ && echo "finished long running task")
173
267
  ```
174
268
 
175
269
  Using a quote delimited command definition might otherwise result in not that
@@ -2,10 +2,13 @@ module VagrantPlugins
2
2
  module DevCommands
3
3
  # Defines the executable vagrant command
4
4
  class Command < Vagrant.plugin(2, :command)
5
- UTIL = VagrantPlugins::DevCommands::Util
5
+ NAMESPACE_RUNNER = VagrantPlugins::DevCommands::Runner
6
+ MESSAGES = VagrantPlugins::DevCommands::Messages
6
7
 
7
8
  def self.synopsis
8
- 'runs vagrant commands from a Commandfile'
9
+ synopsis = VagrantPlugins::DevCommands::SYNOPSIS
10
+
11
+ synopsis[0, 1].downcase + synopsis[1..-1]
9
12
  end
10
13
 
11
14
  def initialize(argv, env)
@@ -17,55 +20,52 @@ module VagrantPlugins
17
20
  def execute
18
21
  return 127 unless read_commandfile
19
22
 
20
- command = argv_command
23
+ command = Util.argv_command(@argv, @env)
21
24
 
22
- return 127 unless check_command(command)
25
+ return 127 unless non_empty?(command)
26
+ return 127 unless available?(command)
23
27
 
24
28
  return run_internal(command) if @registry.reserved_command?(command)
25
29
 
26
- run @registry.commands[command]
30
+ run command
27
31
  end
28
32
 
29
- private
30
-
31
- attr_accessor :registry
33
+ def proxy_with_target_vms(names = nil, options = nil, &block)
34
+ # allows public access to protected method with_target_vms
35
+ with_target_vms(names, options, &block)
36
+ end
32
37
 
33
- def check_command(command)
34
- unless command
35
- run_internal('help')
36
- return false
37
- end
38
+ private
38
39
 
39
- unless @registry.valid_command?(command)
40
+ def available?(command)
41
+ unless @registry.available?(command)
40
42
  display_error("Invalid command \"#{command}\"!")
41
43
  run_internal('help', ['--commands'])
42
-
43
- return false
44
44
  end
45
45
 
46
- true
46
+ @registry.available?(command)
47
47
  end
48
48
 
49
- def argv_command
50
- return nil if @argv.empty?
51
-
52
- command = @argv[0].to_s
53
- command = @argv[1].to_s if UTIL.machine_name?(@argv[1].to_s,
54
- @env.machine_index)
55
-
56
- command
49
+ def display_error(msg, post_ln = false)
50
+ @env.ui.error msg
51
+ @env.ui.error '' if post_ln
57
52
  end
58
53
 
59
- def display_error(msg)
60
- @env.ui.error msg
61
- @env.ui.error ''
54
+ def non_empty?(command)
55
+ unless command
56
+ run_internal('help')
57
+ return false
58
+ end
59
+
60
+ true
62
61
  end
63
62
 
64
63
  def read_commandfile
65
- commandfile = CommandFile.new(@env)
64
+ commandfile = Commandfile.new(@env)
66
65
 
67
66
  unless commandfile.exist?
68
- @env.ui.error 'Missing Commandfile'
67
+ MESSAGES.missing_commandfile(&@env.ui.method(:error))
68
+ MESSAGES.pre_ln(:plugin_readme, &@env.ui.method(:info))
69
69
 
70
70
  return false
71
71
  end
@@ -76,56 +76,39 @@ module VagrantPlugins
76
76
  end
77
77
 
78
78
  def run(command)
79
- argv = run_argv
80
- box = run_box(command)
81
- script = run_script(command, argv)
82
-
83
- return 2 unless script
84
-
85
- with_target_vms(box, single_target: true) do |vm|
86
- env = vm.action(:ssh_run,
87
- ssh_opts: { extra_args: ['-q'] },
88
- ssh_run_command: script)
89
-
90
- return env[:ssh_run_exit_status] || 0
91
- end
92
- end
93
-
94
- def run_argv
95
- argv = @argv.dup
96
-
97
- argv.shift if UTIL.machine_name?(argv[0].to_s, @env.machine_index)
98
- argv.shift
99
- argv
100
- end
79
+ runner = runner_for(command)
80
+ runnable = runnable_for(command)
101
81
 
102
- def run_box(cmd)
103
- box = nil
104
- box = cmd.box.to_s if cmd.box
105
- box = @argv[0] if UTIL.machine_name?(@argv[0].to_s, @env.machine_index)
82
+ runner.run(runnable)
83
+ rescue RuntimeError => e
84
+ display_error(e.message, true)
85
+ run_internal('help', [command])
106
86
 
107
- box
87
+ nil
108
88
  end
109
89
 
110
90
  def run_internal(command, args = nil)
111
- Internal.new(@env, @registry).run(command, args || run_argv)
112
- end
91
+ runner = NAMESPACE_RUNNER::InternalCommand.new(
92
+ self, @argv, @env, @registry
93
+ )
113
94
 
114
- def run_script(command, argv)
115
- command.run_script(argv)
116
- rescue KeyError => e
117
- param = e.message.match(/{(.+)}/).captures.first
118
-
119
- run_script_error(command.name, "missing parameter '#{param}'")
120
- rescue OptionParser::InvalidOption => e
121
- run_script_error(command.name, "invalid parameter '#{e.args.first}'")
95
+ runner.run(command, args)
122
96
  end
123
97
 
124
- def run_script_error(command, error)
125
- display_error("Could not execute #{command}: #{error}!")
126
- run_internal('help', [command])
98
+ def runnable_for(command)
99
+ if @registry.valid_command?(command)
100
+ @registry.commands[command]
101
+ else
102
+ @registry.chains[command]
103
+ end
104
+ end
127
105
 
128
- nil
106
+ def runner_for(command)
107
+ if @registry.valid_command?(command)
108
+ NAMESPACE_RUNNER::Command.new(self, @argv, @env, @registry)
109
+ else
110
+ NAMESPACE_RUNNER::Chain.new(self, @argv, @env, @registry)
111
+ end
129
112
  end
130
113
  end
131
114
  end
@@ -3,7 +3,7 @@ require 'pathname'
3
3
  module VagrantPlugins
4
4
  module DevCommands
5
5
  # Loads and handles the Commandfile
6
- class CommandFile
6
+ class Commandfile
7
7
  def initialize(env)
8
8
  @env = env
9
9
  end
@@ -26,12 +26,10 @@ module VagrantPlugins
26
26
 
27
27
  private
28
28
 
29
- attr_accessor :env
30
-
31
29
  def find_commandfile
32
30
  return nil unless @env.root_path
33
31
 
34
- %w(Commandfile commandfile).each do |commandfile|
32
+ %w[Commandfile commandfile].each do |commandfile|
35
33
  current_path = @env.root_path.join(commandfile)
36
34
 
37
35
  return current_path if current_path.file?
@@ -0,0 +1,62 @@
1
+ module VagrantPlugins
2
+ module DevCommands
3
+ module HelpPrinter
4
+ # Prints help for a command chain
5
+ class Chain
6
+ UTIL = VagrantPlugins::DevCommands::Util
7
+ MESSAGES = VagrantPlugins::DevCommands::Messages
8
+
9
+ def initialize(env)
10
+ @env = env
11
+ end
12
+
13
+ def output(chain)
14
+ header(chain)
15
+ commands(chain)
16
+ body(chain.help)
17
+ end
18
+
19
+ private
20
+
21
+ def body(help)
22
+ return message(:chain_no_help, true) if help.nil?
23
+
24
+ info(help.strip, true)
25
+ end
26
+
27
+ def chain_help_line(cmd)
28
+ return cmd[:command] unless cmd.key?(:argv)
29
+
30
+ "#{cmd[:command]} #{cmd[:argv]}"
31
+ end
32
+
33
+ def commands(chain)
34
+ info('Chained commands (in order):', true)
35
+
36
+ chain.commands.each do |cmd, _options|
37
+ info(UTIL.padded_columns(0, chain_help_line(cmd)))
38
+ end
39
+ end
40
+
41
+ def header(chain)
42
+ usage = "vagrant run [box] #{chain.name}"
43
+
44
+ info(I18n.t('vagrant_devcommands.internal.help.usage', what: usage))
45
+ end
46
+
47
+ def info(msg, pre_ln = false)
48
+ @env.ui.info '' if pre_ln
49
+ @env.ui.info msg
50
+ end
51
+
52
+ def message(msg, pre_ln = false)
53
+ if pre_ln
54
+ MESSAGES.pre_ln(msg, &@env.ui.method(:info))
55
+ else
56
+ MESSAGES.public_send(msg, &@env.ui.method(:info))
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,78 @@
1
+ module VagrantPlugins
2
+ module DevCommands
3
+ module HelpPrinter
4
+ # Prints help for a command
5
+ class Command
6
+ UTIL = VagrantPlugins::DevCommands::Util
7
+ MESSAGES = VagrantPlugins::DevCommands::Messages
8
+
9
+ def initialize(env)
10
+ @env = env
11
+ end
12
+
13
+ def output(command)
14
+ header(command)
15
+ arguments(command.parameters, 'Parameters')
16
+ arguments(command.flags, 'Flags')
17
+ body(command.help)
18
+ end
19
+
20
+ private
21
+
22
+ def arguments(arguments, title)
23
+ return if arguments.nil?
24
+
25
+ info("#{title}:", true)
26
+ arguments_body(arguments)
27
+ end
28
+
29
+ def arguments_body(arguments)
30
+ pad_to = UTIL.pad_to(arguments)
31
+
32
+ arguments.sort.each do |name, options|
33
+ info(UTIL.padded_columns(pad_to, name, options[:desc]))
34
+ end
35
+ end
36
+
37
+ def body(help)
38
+ return message(:command_no_help, true) if help.nil?
39
+
40
+ info(help.strip, true)
41
+ end
42
+
43
+ def header(command)
44
+ usage = "vagrant run [box] #{command.name}"
45
+ usage = usage_params(usage, command)
46
+
47
+ unless command.usage.nil?
48
+ usage = format(command.usage, command: command)
49
+ end
50
+
51
+ info(I18n.t('vagrant_devcommands.internal.help.usage', what: usage))
52
+ end
53
+
54
+ def info(msg, pre_ln = false)
55
+ @env.ui.info '' if pre_ln
56
+ @env.ui.info msg
57
+ end
58
+
59
+ def message(msg, pre_ln = false)
60
+ if pre_ln
61
+ MESSAGES.pre_ln(msg, &@env.ui.method(:info))
62
+ else
63
+ MESSAGES.public_send(msg, &@env.ui.method(:info))
64
+ end
65
+ end
66
+
67
+ def usage_params(usage, command)
68
+ [
69
+ usage,
70
+ UTIL.collect_mandatory_params(command.parameters || {}),
71
+ UTIL.collect_optional_params(command.parameters || {}),
72
+ UTIL.collect_flags(command.flags || {})
73
+ ].flatten.compact.join(' ').strip
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end