vagrant-devcommands 0.10.1 → 0.11.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: 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