vagrant-devcommands 0.10.1 → 0.11.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: 50085046566a6d18be96b03122e887e5a268f4fb
4
- data.tar.gz: 3cc0b7a62fd0924b5f7893f4387478d970807e3d
3
+ metadata.gz: dbb951d035fb1ae4e0101196fe520f470a328e5a
4
+ data.tar.gz: 2f1b1e9a87828c3a3d04e87b716cf29204c82896
5
5
  SHA512:
6
- metadata.gz: d06c2176f75a8ca0bb4f6e56902b3e20c727f0365fb250a44683e4f26aa2ec3c965610b1920e89f597c07a63e18cb338f148505cbb3684f8c898eb3ce3fd509f
7
- data.tar.gz: '097bf9a61bdf25a5ab7c598a9caa3c69b9f61db1bcedd3788951a320d915c5a54a9e1b2a43d0596952980138d1b5ec1dc3a91330162b62363bf8bd6ebc478bc1'
6
+ metadata.gz: fe416e3190fcefbf46795fa521cd9a04e2d4c536e831d4976e5c43b3a07ca19574452eabf11cd0d7998c1c744c42e3c32da278877942c31669abcdaf9094eaa3
7
+ data.tar.gz: feea83ec520f4fa46cbee8048b38ef9ca7ccc97ad1e02571f3ee8729efeaddfc48293be2035a57c4b1c06b943351e931d59d4495d50b1162a0ef632b2f342875
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.11.0 (2017-10-02)
4
+
5
+ - Enhancements
6
+ - Command aliases can be used to provide multiple ways to call a single
7
+ command including automatically populated arguments
8
+ - Commands can define if they need a tty by using the new `:tty` option
9
+
10
+ - Backwards incompatible changes
11
+ - By default a command does not use a tty. This potentially breaks commands
12
+ requiring one, e.g. a mysql console command
13
+
3
14
  ## v0.10.1 (2017-08-08)
4
15
 
5
16
  - Bug fixes
@@ -70,7 +81,7 @@
70
81
  - Enhancements
71
82
  - Command usage now displays the correct parameter syntax
72
83
  - Command usage always displays mandatory parameters before optional ones
73
- - Error output (i.e. "missing Commandfile") is now printed using
84
+ - Error output (e.g. "missing Commandfile") is now printed using
74
85
  the configured ui class (allows colored output)
75
86
  - Global commands can be defined using a file
76
87
  named `.vagrant.devcommands` located under `Dir.home()`
data/README.md CHANGED
@@ -35,6 +35,7 @@ command 'with_options',
35
35
  machine: :my_machine,
36
36
  desc: 'executes "hostname" on the machine "my_machine"',
37
37
  script: 'hostname',
38
+ tty: true,
38
39
  usage: 'vagrant run %<command>s',
39
40
  help: <<-eoh
40
41
  I am the help message for the command "with_options".
@@ -51,6 +52,9 @@ have to escape them using a second `%`. For example `date "+%%Y-%%m-%%d"`.
51
52
  _Note_: Spaces in command names are not supported. Definitions with spaces will
52
53
  be ignored.
53
54
 
55
+ _Note_: Please be aware that setting a custom `usage` hides the original usage
56
+ line from the help output.
57
+
54
58
  #### Commands with Parameters
55
59
 
56
60
  Passing additional parameters to a command is (minimally) supported using an
@@ -182,9 +186,6 @@ chain 'my_chain',
182
186
  help: <<-eoh
183
187
  I am the help message for the chain "my_chain".
184
188
  I get displayed when running "vagrant run help my_chain".
185
-
186
- The usage printed above the help can interpolate the name
187
- of the command name using %<command>s.
188
189
  eoh
189
190
  ```
190
191
 
@@ -234,7 +235,7 @@ chain against a specific machine using `vagrant run your_machine your_chain`.
234
235
 
235
236
  #### Chain Definitions with Specific Machines
236
237
 
237
- If required you can modify the machine a box is run on:
238
+ If required you can modify the machine a command is run on:
238
239
 
239
240
  ```ruby
240
241
  command 'chainhost',
@@ -285,6 +286,31 @@ installed plugin has a version below `1.3.3.7`.
285
286
  Please be aware that returning from a global commandfile completely skips
286
287
  evaluating a local one.
287
288
 
289
+ ### Experimental: Command Alias Definitions
290
+
291
+ For commands you want to keep generic but often call with a specific set of
292
+ parameter values you can define an alias:
293
+
294
+ ```ruby
295
+ command 'customecho',
296
+ parameters: { first: {}, second: {} },
297
+ script: 'echo %<first>s %<second>s'
298
+
299
+ command_alias 'aliasecho',
300
+ argv: ['--first="param"', '--second="param"'],
301
+ command: 'customecho',
302
+ desc: 'modified "customecho" command',
303
+ machine: 'non.default',
304
+ help: <<-eoh
305
+ I am the help message for the command alias "aliasecho".
306
+ I get displayed when running "vagrant run help aliasecho".
307
+ eoh
308
+ ```
309
+
310
+ The setting `command` is required, the other options `argv` and `machine` are
311
+ optional and used for the actual customization. Any argument configured will
312
+ take precedence over the value given to `vagrant run` itself.
313
+
288
314
  ### Experimental: Shell Completion
289
315
 
290
316
  Completion data for your shell is available via internal command:
@@ -304,7 +330,7 @@ vagrant run completion-data my-command
304
330
 
305
331
  If you are using this plugin on a Windows host system, please make sure your
306
332
  regular `vagrant ssh [machine]` succeeds. In some cases you may need to add the
307
- `ssh.exe` (i.e. from a git installation) manually to your `%PATH%`.
333
+ `ssh.exe` (e.g. from a git installation) manually to your `%PATH%`.
308
334
 
309
335
  ### Command Definition
310
336
 
@@ -2,6 +2,8 @@ module VagrantPlugins
2
2
  module DevCommands
3
3
  # Defines the executable vagrant command
4
4
  class Command < Vagrant.plugin(2, :command)
5
+ I18N_KEY = 'vagrant_devcommands.'.freeze
6
+
5
7
  def self.synopsis
6
8
  synopsis = VagrantPlugins::DevCommands::SYNOPSIS
7
9
 
@@ -58,12 +60,12 @@ module VagrantPlugins
58
60
  return false if alternatives.empty?
59
61
 
60
62
  if alternatives.length == 1
61
- display_error('Did you mean this?', true)
63
+ display_error(I18n.t("#{I18N_KEY}.did_you_mean_single"), true)
62
64
  else
63
- display_error('Did you mean one of these?', true)
65
+ display_error(I18n.t("#{I18N_KEY}.did_you_mean_multi"), true)
64
66
  end
65
67
 
66
- alternatives.sort.each { |k, _v| display_error(" #{k}") }
68
+ alternatives.sort.each { |(k, _v)| display_error(" #{k}") }
67
69
  end
68
70
 
69
71
  def display_error(msg, pre_ln = false, post_ln = false)
@@ -116,19 +118,23 @@ module VagrantPlugins
116
118
  runner.run(command, args)
117
119
  end
118
120
 
119
- def runnable_for(command)
120
- if @registry.valid_command?(command)
121
- @registry.commands[command]
121
+ def runnable_for(name)
122
+ if @registry.valid_chain?(name)
123
+ @registry.chains[name]
124
+ elsif @registry.valid_command_alias?(name)
125
+ @registry.command_aliases[name]
122
126
  else
123
- @registry.chains[command]
127
+ @registry.commands[name]
124
128
  end
125
129
  end
126
130
 
127
- def runner_for(command)
128
- if @registry.valid_command?(command)
129
- Runner::Command.new(self, @argv, @env, @registry)
130
- else
131
+ def runner_for(name)
132
+ if @registry.valid_chain?(name)
131
133
  Runner::Chain.new(self, @argv, @env, @registry)
134
+ elsif @registry.valid_command_alias?(name)
135
+ Runner::CommandAlias.new(self, @argv, @env, @registry)
136
+ else
137
+ Runner::Command.new(self, @argv, @env, @registry)
132
138
  end
133
139
  end
134
140
  end
@@ -0,0 +1,65 @@
1
+ module VagrantPlugins
2
+ module DevCommands
3
+ class Commandfile
4
+ # Converts a (commandfile) entry into a model instance
5
+ class Modeler
6
+ def model(spec)
7
+ case spec[:type]
8
+ when :chain
9
+ chain(spec[:name], spec[:options])
10
+ when :command
11
+ command(spec[:name], spec[:options])
12
+ when :command_alias
13
+ command_alias(spec[:name], spec[:options])
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def chain(name, options)
20
+ options = {} unless options.is_a?(Hash)
21
+ options[:commands] = {} unless options.key?(:commands)
22
+ options[:name] = name
23
+
24
+ raise ArgumentError, 'chain_empty' if options[:commands].empty?
25
+ raise ArgumentError, 'chain_name_space' if name.include?(' ')
26
+
27
+ VagrantPlugins::DevCommands::Model::Chain.new(options)
28
+ end
29
+
30
+ def command(name, options)
31
+ raise ArgumentError, 'command_name_space' if name.include?(' ')
32
+
33
+ options = { script: options } unless options.is_a?(Hash)
34
+ options[:name] = name
35
+
36
+ unless valid_script?(options[:script])
37
+ raise ArgumentError, 'command_no_script'
38
+ end
39
+
40
+ VagrantPlugins::DevCommands::Model::Command.new(options)
41
+ end
42
+
43
+ def command_alias(name, options)
44
+ raise ArgumentError, 'command_alias_name_space' if name.include?(' ')
45
+
46
+ options = { command: options } unless options.is_a?(Hash)
47
+ options[:name] = name
48
+
49
+ raise ArgumentError, 'command_alias_empty' unless options[:command]
50
+
51
+ VagrantPlugins::DevCommands::Model::CommandAlias.new(options)
52
+ end
53
+
54
+ def valid_script?(script)
55
+ return true if script.is_a?(Proc)
56
+
57
+ return false unless script.is_a?(String)
58
+ return false if script.empty?
59
+
60
+ true
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,56 @@
1
+ module VagrantPlugins
2
+ module DevCommands
3
+ class Commandfile
4
+ # Provides the DSL to read the contents of a Commandfile
5
+ class Reader
6
+ attr_reader :entries
7
+
8
+ def initialize(commandfile, env)
9
+ @commandfile = commandfile
10
+ @env = env
11
+
12
+ @entries = []
13
+ end
14
+
15
+ def read
16
+ global = @commandfile.path_global
17
+ local = @commandfile.path
18
+
19
+ contents = ''
20
+ contents += "\n" + global.read unless global.nil?
21
+ contents += "\n" + local.read unless local.nil?
22
+
23
+ instance_eval(contents)
24
+
25
+ @entries
26
+ end
27
+
28
+ private
29
+
30
+ def chain(name, options = nil)
31
+ @entries << {
32
+ type: :chain,
33
+ name: name.to_s,
34
+ options: options
35
+ }
36
+ end
37
+
38
+ def command(name, options = nil)
39
+ @entries << {
40
+ type: :command,
41
+ name: name.to_s,
42
+ options: options
43
+ }
44
+ end
45
+
46
+ def command_alias(name, options = nil)
47
+ @entries << {
48
+ type: :command_alias,
49
+ name: name.to_s,
50
+ options: options
51
+ }
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -3,6 +3,7 @@ module VagrantPlugins
3
3
  module HelpPrinter
4
4
  # Prints help for a command chain
5
5
  class Chain
6
+ I18N_KEY = 'vagrant_devcommands.internal.help'.freeze
6
7
  UTIL = VagrantPlugins::DevCommands::Util
7
8
  MESSAGES = VagrantPlugins::DevCommands::Messages
8
9
 
@@ -33,15 +34,20 @@ module VagrantPlugins
33
34
  def commands(chain)
34
35
  info('Chained commands (in order):', true)
35
36
 
36
- chain.commands.each do |cmd, _options|
37
+ chain.commands.each do |cmd|
37
38
  info(UTIL.padded_columns(0, chain_help_line(cmd)))
38
39
  end
39
40
  end
40
41
 
41
42
  def header(chain)
42
- usage = "vagrant run [machine] #{chain.name}"
43
+ usage =
44
+ if chain.usage.nil?
45
+ I18n.t("#{I18N_KEY}.usage_default", what: chain.name)
46
+ else
47
+ format(chain.usage, chain: chain.name)
48
+ end
43
49
 
44
- info(I18n.t('vagrant_devcommands.internal.help.usage', what: usage))
50
+ info(I18n.t("#{I18N_KEY}.usage", what: usage))
45
51
  end
46
52
 
47
53
  def info(msg, pre_ln = false)
@@ -3,6 +3,7 @@ module VagrantPlugins
3
3
  module HelpPrinter
4
4
  # Prints help for a command
5
5
  class Command
6
+ I18N_KEY = 'vagrant_devcommands.internal.help'.freeze
6
7
  UTIL = VagrantPlugins::DevCommands::Util
7
8
  MESSAGES = VagrantPlugins::DevCommands::Messages
8
9
 
@@ -41,14 +42,17 @@ module VagrantPlugins
41
42
  end
42
43
 
43
44
  def header(command)
44
- usage = "vagrant run [machine] #{command.name}"
45
- usage = usage_params(usage, command)
45
+ usage =
46
+ if command.usage.nil?
47
+ usage_params(
48
+ I18n.t("#{I18N_KEY}.usage_default", what: command.name),
49
+ command
50
+ )
51
+ else
52
+ format(command.usage, command: command.name)
53
+ end
46
54
 
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))
55
+ info(I18n.t("#{I18N_KEY}.usage", what: usage))
52
56
  end
53
57
 
54
58
  def info(msg, pre_ln = false)
@@ -0,0 +1,56 @@
1
+ module VagrantPlugins
2
+ module DevCommands
3
+ module HelpPrinter
4
+ # Prints help for a command alias
5
+ class CommandAlias
6
+ I18N_KEY = 'vagrant_devcommands.internal.help'.freeze
7
+ UTIL = VagrantPlugins::DevCommands::Util
8
+ MESSAGES = VagrantPlugins::DevCommands::Messages
9
+
10
+ def initialize(env)
11
+ @env = env
12
+ end
13
+
14
+ def output(command_alias)
15
+ header(command_alias)
16
+ body(command_alias.help)
17
+ end
18
+
19
+ private
20
+
21
+ def body(help)
22
+ return message(:command_alias_no_help, true) if help.nil?
23
+
24
+ info(help.strip, true)
25
+ end
26
+
27
+ def header(command_alias)
28
+ usage =
29
+ if command_alias.usage.nil?
30
+ I18n.t("#{I18N_KEY}.usage_default", what: command_alias.name)
31
+ else
32
+ format(command_alias.usage, command_alias: command_alias.name)
33
+ end
34
+
35
+ alias_for = [command_alias.command, command_alias.argv].join(' ')
36
+
37
+ info(I18n.t("#{I18N_KEY}.usage", what: usage))
38
+ info(I18n.t("#{I18N_KEY}.alias_for", what: alias_for), true)
39
+ end
40
+
41
+ def info(msg, pre_ln = false)
42
+ @env.ui.info '' if pre_ln
43
+ @env.ui.info msg
44
+ end
45
+
46
+ def message(msg, pre_ln = false)
47
+ if pre_ln
48
+ MESSAGES.pre_ln(msg, &@env.ui.method(:info))
49
+ else
50
+ MESSAGES.public_send(msg, &@env.ui.method(:info))
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -36,6 +36,7 @@ module VagrantPlugins
36
36
  (
37
37
  @registry.chains.keys +
38
38
  @registry.commands.keys +
39
+ @registry.command_aliases.keys +
39
40
  VagrantPlugins::DevCommands::Registry::RESERVED_COMMANDS
40
41
  ).sort.join(' ')
41
42
  end
@@ -3,6 +3,7 @@ module VagrantPlugins
3
3
  module InternalCommand
4
4
  # Internal "help" command
5
5
  class Help
6
+ I18N_KEY = 'vagrant_devcommands.internal.help'.freeze
6
7
  UTIL = VagrantPlugins::DevCommands::Util
7
8
  MESSAGES = VagrantPlugins::DevCommands::Messages
8
9
  PRINTER = VagrantPlugins::DevCommands::HelpPrinter
@@ -28,6 +29,10 @@ module VagrantPlugins
28
29
  def help(command)
29
30
  if @registry.valid_chain?(command)
30
31
  PRINTER::Chain.new(@env).output(@registry.chains[command])
32
+ elsif @registry.valid_command_alias?(command)
33
+ PRINTER::CommandAlias.new(@env).output(
34
+ @registry.command_aliases[command]
35
+ )
31
36
  else
32
37
  PRINTER::Command.new(@env).output(@registry.commands[command])
33
38
  end
@@ -53,7 +58,14 @@ module VagrantPlugins
53
58
  spec = internal_commands[command]
54
59
  usage = format(spec.usage, command: command)
55
60
 
56
- info(I18n.t('vagrant_devcommands.internal.help.usage', what: usage))
61
+ info(I18n.t("#{I18N_KEY}.usage", what: usage))
62
+ end
63
+
64
+ def list_pad_to
65
+ UTIL.max_pad([internal_commands,
66
+ @registry.chains,
67
+ @registry.command_aliases,
68
+ @registry.commands])
57
69
  end
58
70
 
59
71
  def message(msg, pre_ln = false)
@@ -65,21 +77,20 @@ module VagrantPlugins
65
77
  end
66
78
 
67
79
  def plugin_help(command)
68
- message(:plugin_usage) unless command == '--commands'
80
+ plugin_help_header(command) unless command == '--commands'
69
81
 
70
- pad_to = UTIL.max_pad([internal_commands,
71
- @registry.commands,
72
- @registry.chains])
82
+ pad_to = list_pad_to
73
83
 
74
- plugin_help_commands('Available', @registry.commands, pad_to)
84
+ plugin_help_commands('available', @registry.commands, pad_to)
75
85
  plugin_help_chains(@registry.chains, pad_to)
76
- plugin_help_commands('Internal', internal_commands, pad_to)
86
+ plugin_help_command_aliases(@registry.command_aliases, pad_to)
87
+ plugin_help_commands('internal', internal_commands, pad_to)
77
88
  end
78
89
 
79
90
  def plugin_help_chains(chains, pad_to)
80
91
  return if chains.empty?
81
92
 
82
- info('Command chains:', true)
93
+ info(I18n.t("#{I18N_KEY}.list.chains"), true)
83
94
 
84
95
  chains.sort.each do |name, chain|
85
96
  info(UTIL.padded_columns(pad_to, name, chain.desc))
@@ -89,12 +100,30 @@ module VagrantPlugins
89
100
  def plugin_help_commands(type, commands, pad_to)
90
101
  return if commands.empty?
91
102
 
92
- info("#{type} commands:", true)
103
+ info(I18n.t("#{I18N_KEY}.list.commands_#{type}"), true)
93
104
 
94
105
  commands.sort.each do |name, command|
95
106
  info(UTIL.padded_columns(pad_to, name, command.desc))
96
107
  end
97
108
  end
109
+
110
+ def plugin_help_command_aliases(command_aliases, pad_to)
111
+ return if command_aliases.empty?
112
+
113
+ info(I18n.t("#{I18N_KEY}.list.command_aliases"), true)
114
+
115
+ command_aliases.sort.each do |name, command_alias|
116
+ info(UTIL.padded_columns(pad_to, name, command_alias.desc))
117
+ end
118
+ end
119
+
120
+ def plugin_help_header(command)
121
+ if command.nil?
122
+ message(:plugin_usage)
123
+ else
124
+ @env.ui.error I18n.t("#{I18N_KEY}.invalid_command", what: command)
125
+ end
126
+ end
98
127
  end
99
128
  end
100
129
  end
@@ -10,15 +10,19 @@ module VagrantPlugins
10
10
  out.call I18n.t("#{I18N_KEY}.chain_no_help")
11
11
  end
12
12
 
13
- def self.deprecated_box_config(&out)
14
- out.call I18n.t("#{I18N_KEY}.deprecated_box_config")
15
- out.call ''
13
+ def self.command_alias_no_help(&out)
14
+ out.call I18n.t("#{I18N_KEY}.command_alias_no_help")
16
15
  end
17
16
 
18
17
  def self.command_no_help(&out)
19
18
  out.call I18n.t("#{I18N_KEY}.command_no_help")
20
19
  end
21
20
 
21
+ def self.deprecated_box_config(&out)
22
+ out.call I18n.t("#{I18N_KEY}.deprecated_box_config")
23
+ out.call ''
24
+ end
25
+
22
26
  def self.missing_commandfile(&out)
23
27
  out.call I18n.t("#{I18N_KEY}.missing_commandfile")
24
28
  end
@@ -28,7 +32,7 @@ module VagrantPlugins
28
32
  end
29
33
 
30
34
  def self.plugin_readme(&out)
31
- curdir = File.expand_path(File.dirname(__FILE__))
35
+ curdir = File.expand_path(__dir__)
32
36
  readme = File.expand_path(File.join(curdir, '../../../README.md'))
33
37
 
34
38
  out.call I18n.t("#{I18N_KEY}.plugin_readme", readme: readme)
@@ -8,13 +8,15 @@ module VagrantPlugins
8
8
 
9
9
  attr_reader :desc
10
10
  attr_reader :help
11
+ attr_reader :usage
11
12
 
12
13
  def initialize(spec)
13
14
  @name = spec[:name]
14
15
  @commands = spec[:commands]
15
16
 
16
- @desc = spec[:desc]
17
- @help = spec[:help]
17
+ @desc = spec[:desc]
18
+ @help = spec[:help]
19
+ @usage = spec[:usage]
18
20
 
19
21
  @break_on_error = spec[:break_on_error] != false
20
22
  end
@@ -10,6 +10,7 @@ module VagrantPlugins
10
10
  attr_reader :flags
11
11
  attr_reader :parameters
12
12
  attr_reader :script
13
+ attr_reader :tty
13
14
 
14
15
  attr_reader :machine
15
16
  attr_reader :desc
@@ -18,12 +19,14 @@ module VagrantPlugins
18
19
 
19
20
  attr_reader :deprecated_box_config
20
21
 
22
+ # rubocop:disable Metrics/AbcSize
21
23
  def initialize(spec)
22
24
  @name = spec[:name]
23
25
 
24
26
  @flags = spec[:flags] || {}
25
27
  @parameters = spec[:parameters] || {}
26
28
  @script = spec[:script]
29
+ @tty = spec[:tty] == true
27
30
 
28
31
  @machine = spec[:machine] || spec[:box]
29
32
  @desc = spec[:desc]
@@ -32,6 +35,7 @@ module VagrantPlugins
32
35
 
33
36
  @deprecated_box_config = spec.key?(:box)
34
37
  end
38
+ # rubocop:enable Metrics/AbcSize
35
39
 
36
40
  def run_script(argv)
37
41
  script = @script
@@ -82,7 +86,7 @@ module VagrantPlugins
82
86
  end
83
87
  end
84
88
 
85
- @parameters.each do |key, _conf|
89
+ @parameters.each_key do |key|
86
90
  opts.on("--#{key} OPTION", "Parameter: #{key}") do |o|
87
91
  params[key] = o
88
92
  end
@@ -0,0 +1,28 @@
1
+ require 'optparse'
2
+
3
+ module VagrantPlugins
4
+ module DevCommands
5
+ module Model
6
+ # Definition of a command alias
7
+ class CommandAlias
8
+ attr_reader :name
9
+
10
+ attr_reader :argv
11
+ attr_reader :command
12
+ attr_reader :desc
13
+ attr_reader :help
14
+ attr_reader :usage
15
+
16
+ def initialize(spec)
17
+ @name = spec[:name]
18
+
19
+ @argv = spec[:argv] || []
20
+ @command = spec[:command]
21
+ @desc = spec[:desc]
22
+ @help = spec[:help]
23
+ @usage = spec[:usage]
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,30 @@
1
+ module VagrantPlugins
2
+ module DevCommands
3
+ class Registry
4
+ # Generic registry message printer
5
+ class Messager
6
+ I18N_KEY = 'vagrant_devcommands.registry'.freeze
7
+
8
+ def initialize(env)
9
+ @env = env
10
+ end
11
+
12
+ def chain_ignored(message, name)
13
+ @env.ui.warn I18n.t("#{I18N_KEY}.#{message}", name: name)
14
+ @env.ui.warn I18n.t("#{I18N_KEY}.chain_ignored")
15
+ end
16
+
17
+ def command_alias_ignored(message, name)
18
+ @env.ui.warn I18n.t("#{I18N_KEY}.#{message}", name: name)
19
+ @env.ui.warn I18n.t("#{I18N_KEY}.command_alias_ignored")
20
+ end
21
+
22
+ def def_ignored(message, args)
23
+ @env.ui.warn I18n.t("#{I18N_KEY}.#{message}", args)
24
+ @env.ui.warn I18n.t("#{I18N_KEY}.def_ignored")
25
+ @env.ui.warn ''
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,66 @@
1
+ module VagrantPlugins
2
+ module DevCommands
3
+ class Registry
4
+ # Registry conflict resolver
5
+ class Resolver
6
+ def initialize(messager)
7
+ @messager = messager
8
+ end
9
+
10
+ def resolve_naming_conflicts(registry)
11
+ resolve_command_naming_conflicts(registry)
12
+ resolve_chain_naming_conflicts(registry)
13
+ resolve_command_alias_naming_conflicts(registry)
14
+ end
15
+
16
+ private
17
+
18
+ def resolve_chain_naming_conflicts(registry)
19
+ registry.chains.each_key do |name|
20
+ next unless registry.valid_command?(name)
21
+
22
+ i18n_msg = 'chain_conflict_command'
23
+
24
+ if registry.reserved_command?(name)
25
+ i18n_msg = 'chain_conflict_internal'
26
+ end
27
+
28
+ @messager.chain_ignored(i18n_msg, name)
29
+
30
+ registry.chains.delete(name)
31
+ end
32
+ end
33
+
34
+ def resolve_command_naming_conflicts(registry)
35
+ registry.commands.each_key do |name|
36
+ next unless registry.reserved_command?(name)
37
+
38
+ @messager.def_ignored('command_reserved', name: name)
39
+
40
+ registry.commands.delete(name)
41
+ end
42
+ end
43
+
44
+ # rubocop:disable Metrics/MethodLength
45
+ def resolve_command_alias_naming_conflicts(registry)
46
+ registry.command_aliases.each_key do |name|
47
+ unless registry.valid_command?(name) || registry.valid_chain?(name)
48
+ next
49
+ end
50
+
51
+ i18n_key = 'command'
52
+ i18n_key = 'chain' if registry.valid_chain?(name)
53
+ i18n_key = 'internal' if registry.reserved_command?(name)
54
+
55
+ i18n_msg = "command_alias_conflict_#{i18n_key}"
56
+
57
+ @messager.command_alias_ignored(i18n_msg, name)
58
+
59
+ registry.command_aliases.delete(name)
60
+ end
61
+ end
62
+ # rubocop:enable Metrics/MethodLength
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,52 @@
1
+ module VagrantPlugins
2
+ module DevCommands
3
+ class Registry
4
+ # Registry entry validator
5
+ class Validator
6
+ def initialize(messager)
7
+ @messager = messager
8
+ end
9
+
10
+ def validate_entries(registry)
11
+ validate_chains(registry)
12
+ validate_command_aliases(registry)
13
+ end
14
+
15
+ private
16
+
17
+ # rubocop:disable Metrics/MethodLength
18
+ def validate_chains(registry)
19
+ registry.chains.all? do |chain, chain_def|
20
+ chain_def.commands.each do |element|
21
+ next unless element.is_a?(Hash)
22
+ next if registry.valid_command?(element[:command])
23
+
24
+ @messager.def_ignored('chain_missing_command',
25
+ chain: chain,
26
+ command: element)
27
+
28
+ registry.chains.delete(chain)
29
+
30
+ break
31
+ end
32
+ end
33
+ end
34
+ # rubocop:enable Metrics/MethodLength
35
+
36
+ def validate_command_aliases(registry)
37
+ registry.command_aliases.all? do |command_alias, command_alias_def|
38
+ cmd = command_alias_def.command
39
+
40
+ next if registry.valid_command?(cmd) || registry.valid_chain?(cmd)
41
+
42
+ @messager.def_ignored('command_alias_missing_command',
43
+ command_alias: command_alias,
44
+ command: cmd)
45
+
46
+ registry.command_aliases.delete(command_alias)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -1,34 +1,31 @@
1
1
  module VagrantPlugins
2
2
  module DevCommands
3
- # Vagrant command registry
3
+ # Registry for definitions from the Commandfile
4
4
  class Registry
5
- I18N_KEY = 'vagrant_devcommands.registry'.freeze
6
5
  RESERVED_COMMANDS = %w[completion-data help version].freeze
7
6
 
8
7
  attr_accessor :chains
9
8
  attr_accessor :commands
9
+ attr_accessor :command_aliases
10
10
 
11
11
  def initialize(env)
12
- @chains = {}
13
- @commands = {}
14
12
  @env = env
13
+ @messager = Registry::Messager.new(@env)
14
+
15
+ @chains = {}
16
+ @commands = {}
17
+ @command_aliases = {}
15
18
  end
16
19
 
17
20
  def available?(name)
18
- valid_command?(name) || valid_chain?(name)
21
+ valid_chain?(name) || valid_command?(name) || valid_command_alias?(name)
19
22
  end
20
23
 
21
24
  def read_commandfile(commandfile)
22
- global = commandfile.path_global
23
- local = commandfile.path
24
-
25
- contents = ''
26
- contents += "\n" + global.read unless global.nil?
27
- contents += "\n" + local.read unless local.nil?
25
+ register(Commandfile::Reader.new(commandfile, @env).read)
28
26
 
29
- instance_eval(contents)
30
- resolve_naming_conflicts
31
- validate_chains
27
+ Registry::Resolver.new(@messager).resolve_naming_conflicts(self)
28
+ Registry::Validator.new(@messager).validate_entries(self)
32
29
  end
33
30
 
34
31
  def reserved_command?(command)
@@ -43,88 +40,28 @@ module VagrantPlugins
43
40
  @commands.include?(command) || reserved_command?(command)
44
41
  end
45
42
 
46
- private
47
-
48
- def chain(name, options = nil)
49
- options = {} unless options.is_a?(Hash)
50
- options[:commands] = {} unless options.key?(:commands)
51
- options[:name] = name
52
-
53
- if options[:commands].empty?
54
- return warn_def_ignored('chain_empty', name: name)
55
- end
56
-
57
- if name.include?(' ')
58
- return warn_def_ignored('chain_name_space', name: name)
59
- end
60
-
61
- @chains[name] = Model::Chain.new(options)
62
- end
63
-
64
- # rubocop:disable Metrics/MethodLength
65
- def command(name, options = nil)
66
- if reserved_command?(name)
67
- return warn_def_ignored('command_reserved', name: name)
68
- end
69
-
70
- if name.include?(' ')
71
- return warn_def_ignored('command_name_space', name: name)
72
- end
73
-
74
- options = { script: options } unless options.is_a?(Hash)
75
- options[:name] = name
76
-
77
- unless valid_script?(options[:script])
78
- return warn_def_ignored('command_no_script', name: name)
79
- end
80
-
81
- @commands[name] = Model::Command.new(options)
82
- end
83
- # rubocop:enable Metrics/MethodLength
84
-
85
- def resolve_naming_conflicts
86
- @chains.keys.each do |chain|
87
- next unless valid_command?(chain)
88
-
89
- i18n_msg = 'conflict_command'
90
- i18n_msg = 'conflict_internal' if reserved_command?(chain)
91
-
92
- @env.ui.warn I18n.t("#{I18N_KEY}.#{i18n_msg}", name: chain)
93
- @env.ui.warn I18n.t("#{I18N_KEY}.chain_ignored")
94
-
95
- @chains.delete(chain)
96
- end
43
+ def valid_command_alias?(name)
44
+ @command_aliases.include?(name)
97
45
  end
98
46
 
99
- def valid_script?(script)
100
- return true if script.is_a?(Proc)
101
-
102
- return false unless script.is_a?(String)
103
- return false if script.empty?
104
-
105
- true
106
- end
107
-
108
- def validate_chains
109
- @chains.all? do |chain, chain_def|
110
- chain_def.commands.each do |element|
111
- next unless element.is_a?(Hash)
112
- next if valid_command?(element[:command])
113
-
114
- warn_def_ignored('chain_missing_command',
115
- chain: chain, command: element)
47
+ private
116
48
 
117
- @chains.delete(chain)
49
+ def register(commandfile_entries)
50
+ modeler = Commandfile::Modeler.new
118
51
 
119
- break
52
+ commandfile_entries.each do |entry|
53
+ begin
54
+ register_model(modeler.model(entry))
55
+ rescue ArgumentError => e
56
+ @messager.def_ignored(e.message, name: entry[:name])
120
57
  end
121
58
  end
122
59
  end
123
60
 
124
- def warn_def_ignored(message, args)
125
- @env.ui.warn I18n.t("#{I18N_KEY}.#{message}", args)
126
- @env.ui.warn I18n.t("#{I18N_KEY}.def_ignored")
127
- @env.ui.warn ''
61
+ def register_model(model)
62
+ @chains[model.name] = model if model.is_a?(Model::Chain)
63
+ @commands[model.name] = model if model.is_a?(Model::Command)
64
+ @command_aliases[model.name] = model if model.is_a?(Model::CommandAlias)
128
65
  end
129
66
  end
130
67
  end
@@ -24,7 +24,7 @@ module VagrantPlugins
24
24
  env = vm.action(:ssh_run,
25
25
  ssh_run_command: script,
26
26
  ssh_opts: { extra_args: ['-q'] },
27
- tty: true)
27
+ tty: command.tty)
28
28
 
29
29
  return env[:ssh_run_exit_status] || 0
30
30
  end
@@ -0,0 +1,42 @@
1
+ module VagrantPlugins
2
+ module DevCommands
3
+ module Runner
4
+ # Command alias runner
5
+ class CommandAlias
6
+ UTIL = VagrantPlugins::DevCommands::Util
7
+
8
+ def initialize(plugin, argv, env, registry)
9
+ @plugin = plugin
10
+ @argv = argv
11
+ @env = env
12
+ @registry = registry
13
+ end
14
+
15
+ def run(command_alias)
16
+ runnable = runnable_for(command_alias)
17
+ runnable_argv = argv_for(command_alias)
18
+
19
+ Command.new(@plugin, runnable_argv, @env, @registry).run(runnable)
20
+ end
21
+
22
+ private
23
+
24
+ def argv_for(command_alias)
25
+ argv = @argv.dup
26
+ index = 0
27
+ index = 1 if UTIL.machine_name?(argv[0].to_s, @env.machine_index)
28
+
29
+ argv[index] = command_alias.command
30
+
31
+ return argv unless command_alias.argv.is_a?(Array)
32
+
33
+ argv + command_alias.argv
34
+ end
35
+
36
+ def runnable_for(command_alias)
37
+ @registry.commands[command_alias.command]
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,6 +1,6 @@
1
1
  module VagrantPlugins
2
2
  # Defines the current plugin version
3
3
  module DevCommands
4
- VERSION = '0.10.1'.freeze
4
+ VERSION = '0.11.0'.freeze
5
5
  end
6
6
  end
@@ -13,18 +13,26 @@ require 'vagrant/devcommands/util'
13
13
 
14
14
  require 'vagrant/devcommands/model/chain'
15
15
  require 'vagrant/devcommands/model/command'
16
+ require 'vagrant/devcommands/model/command_alias'
16
17
 
17
18
  require 'vagrant/devcommands/help_printer/chain'
18
19
  require 'vagrant/devcommands/help_printer/command'
20
+ require 'vagrant/devcommands/help_printer/command_alias'
19
21
  require 'vagrant/devcommands/internal_command/completion_data'
20
22
  require 'vagrant/devcommands/internal_command/help'
21
23
  require 'vagrant/devcommands/internal_command/version'
22
24
 
23
25
  require 'vagrant/devcommands/runner/chain'
24
26
  require 'vagrant/devcommands/runner/command'
27
+ require 'vagrant/devcommands/runner/command_alias'
25
28
  require 'vagrant/devcommands/runner/internal_command'
26
29
 
27
30
  require 'vagrant/devcommands/command'
28
31
  require 'vagrant/devcommands/commandfile'
32
+ require 'vagrant/devcommands/commandfile/modeler'
33
+ require 'vagrant/devcommands/commandfile/reader'
29
34
  require 'vagrant/devcommands/plugin'
30
35
  require 'vagrant/devcommands/registry'
36
+ require 'vagrant/devcommands/registry/messager'
37
+ require 'vagrant/devcommands/registry/resolver'
38
+ require 'vagrant/devcommands/registry/validator'
data/locales/en.yml CHANGED
@@ -1,21 +1,33 @@
1
1
  en:
2
2
  vagrant_devcommands:
3
+ did_you_mean_multi: Did you mean one of these?
4
+ did_you_mean_single: Did you mean this?
5
+
3
6
  internal:
4
7
  completion-data:
5
8
  desc: provides shell completion data
6
9
  help: Returns a list of all defined commands separated using spaces.
7
10
  help:
8
- desc: get some plugin help
11
+ alias_for: "Alias for: vagrant run [machine] %<what>s"
12
+ desc: get some plugin or command help
9
13
  help: |-
10
14
  Display the help of the command given as the first argument if defined.
11
15
  Just like this help for the help command!
16
+ invalid_command: "Invalid command '%<what>s'!"
17
+ list:
18
+ chains: "Command chains:"
19
+ command_aliases: "Command aliases:"
20
+ commands_available: "Available commands:"
21
+ commands_internal: "Internal commands:"
12
22
  usage: "Usage: %<what>s"
23
+ usage_default: "vagrant run [machine] %<what>s"
13
24
  version:
14
25
  desc: get currently installed plugin version
15
26
  help: Displays the currently installed version of the plugin you are using right now.
16
27
 
17
28
  message:
18
29
  chain_no_help: No detailed help for this chain available.
30
+ command_alias_no_help: No detailed help for this command alias available.
19
31
  command_no_help: No detailed help for this command available.
20
32
  deprecated_box_config: |-
21
33
  At least one of your commands is configured with the deprecated
@@ -34,15 +46,20 @@ en:
34
46
  Help: vagrant run help <command>
35
47
 
36
48
  registry:
49
+ chain_conflict_command: "The name '%<name>s' is used for both a command and a chain."
50
+ chain_conflict_internal: "The name '%<name>s' is used for both an internal command and a chain."
37
51
  chain_empty: "The chain '%<name>s' has no commands associated."
38
52
  chain_ignored: Your chain definition will be ignored in favor of the command.
39
53
  chain_missing_command: "The chain '%<chain>s' is using at least one unknown command ('%<command>s')."
40
54
  chain_name_space: "The chain '%<name>s' contains spaces in it's name."
55
+ command_alias_conflict_chain: "The name '%<name>s' is used for both a chain and a command alias."
56
+ command_alias_conflict_command: "The name '%<name>s' is used for both a command and a command alias."
57
+ command_alias_conflict_internal: "The name '%<name>s' is used for both an internal command and a command alias."
58
+ command_alias_empty: "The command alias '%<name>s' has no command associated."
59
+ command_alias_missing_command: "The command alias '%<command_alias>s' is using an unknown command ('%<command>s')."
41
60
  command_name_space: "The command '%<name>s' contains spaces in it's name."
42
61
  command_no_script: "The command '%<name>s' has no script defined to execute."
43
62
  command_reserved: "The command name '%<name>s' is reserved for internal usage."
44
- conflict_command: "The name '%<name>s' is used for both a command and a chain."
45
- conflict_internal: "The name '%<name>s' is used for both an internal command and a chain."
46
63
  def_ignored: Your definition of it will be ignored.
47
64
 
48
65
  runner:
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vagrant-devcommands
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.1
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marc Neudert
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-08-08 00:00:00.000000000 Z
11
+ date: 2017-10-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: coveralls
@@ -30,42 +30,42 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '12.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '12.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '3.3'
47
+ version: '3.6'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '3.3'
54
+ version: '3.6'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rubocop
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0.34'
61
+ version: '0.50'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0.34'
68
+ version: '0.50'
69
69
  description: Vagrant plugin to run commands specified in a Commandfile inside one
70
70
  of your vagrant boxes
71
71
  email:
@@ -80,8 +80,11 @@ files:
80
80
  - lib/vagrant/devcommands.rb
81
81
  - lib/vagrant/devcommands/command.rb
82
82
  - lib/vagrant/devcommands/commandfile.rb
83
+ - lib/vagrant/devcommands/commandfile/modeler.rb
84
+ - lib/vagrant/devcommands/commandfile/reader.rb
83
85
  - lib/vagrant/devcommands/help_printer/chain.rb
84
86
  - lib/vagrant/devcommands/help_printer/command.rb
87
+ - lib/vagrant/devcommands/help_printer/command_alias.rb
85
88
  - lib/vagrant/devcommands/internal_command/completion_data.rb
86
89
  - lib/vagrant/devcommands/internal_command/help.rb
87
90
  - lib/vagrant/devcommands/internal_command/version.rb
@@ -89,10 +92,15 @@ files:
89
92
  - lib/vagrant/devcommands/messages.rb
90
93
  - lib/vagrant/devcommands/model/chain.rb
91
94
  - lib/vagrant/devcommands/model/command.rb
95
+ - lib/vagrant/devcommands/model/command_alias.rb
92
96
  - lib/vagrant/devcommands/plugin.rb
93
97
  - lib/vagrant/devcommands/registry.rb
98
+ - lib/vagrant/devcommands/registry/messager.rb
99
+ - lib/vagrant/devcommands/registry/resolver.rb
100
+ - lib/vagrant/devcommands/registry/validator.rb
94
101
  - lib/vagrant/devcommands/runner/chain.rb
95
102
  - lib/vagrant/devcommands/runner/command.rb
103
+ - lib/vagrant/devcommands/runner/command_alias.rb
96
104
  - lib/vagrant/devcommands/runner/internal_command.rb
97
105
  - lib/vagrant/devcommands/synopsis.rb
98
106
  - lib/vagrant/devcommands/util.rb
@@ -120,7 +128,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
128
  version: '0'
121
129
  requirements: []
122
130
  rubyforge_project:
123
- rubygems_version: 2.6.11
131
+ rubygems_version: 2.6.13
124
132
  signing_key:
125
133
  specification_version: 4
126
134
  summary: Runs vagrant commands from a Commandfile