vagrant-devcommands 0.8.0 → 0.9.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: 32211b187c89aedb28b7e3b084553e07030fa971
4
- data.tar.gz: 2be8cec37c79264056981c70acdd490ebdeb4d18
3
+ metadata.gz: 1cdd09f90d6b080675f4b15e4fb9ec4ce3101cf2
4
+ data.tar.gz: 9968d30256b15ce9247ad33c39e1e1c39a3b6daf
5
5
  SHA512:
6
- metadata.gz: a6a418391c08c271c88d3c334a88c1ad02173725fe2300bc81523ce9302b3344068769cdf52c23da6fd869a307bf8ba01f0a78855aca86afbaa2a42de384e858
7
- data.tar.gz: cabdfa5024114480df1ae410ddfd7d78928a62099672fd6909838260fa0e314f708a73abd00d08e01d57917b14fe203a1149217aeefec1735cb1aca91466af37
6
+ metadata.gz: aa62d03f315aab6378feb9f9ffff8d7c3f3f22930c2b7ab177ab7afea46e34761a7cab7a5c08c4ce249cff2d6e51e288fb6a1d274663ff21b529c5d242bed272
7
+ data.tar.gz: 6581d21c82f57b249c645844f4e64a5cebe36c4e5171a2992e1a9a9ba914fb4ae710b3d5ae7bfcbe56deb021e5f273910071acfdf655eedf3219d99b85419533
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.9.0 (2017-05-20)
4
+
5
+ - Enhancements
6
+ - Every command in a chain can specify the machine to be used
7
+ - If an unknown command is requested a possible alternative
8
+ is suggested based on the calculated
9
+ [Jaro-Winkler distance](https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance)
10
+
11
+ - Deprecations
12
+ - The configuration parameter `:box` has been renamed to `:machine` to
13
+ match the vagrant naming. Support for the old configuration will be
14
+ dropped in a future version
15
+
3
16
  ## v0.8.0 (2017-04-19)
4
17
 
5
18
  - Enhancements
data/README.md CHANGED
@@ -15,11 +15,11 @@ vagrant run
15
15
 
16
16
  ```shell
17
17
  # single-vm environment
18
- # or multi-vm environment with :box option
18
+ # or multi-vm environment with :machine option
19
19
  vagrant run your_command
20
20
 
21
21
  # multi-vm environment
22
- vagrant run your_box your_command
22
+ vagrant run your_machine your_command
23
23
  ```
24
24
 
25
25
  This runs commands or alternatively a command chain with the passed name.
@@ -32,8 +32,8 @@ Add to a `Commandfile` besides your `Vagrantfile`:
32
32
  command 'basic', 'hostname'
33
33
 
34
34
  command 'with_options',
35
- box: :my_box,
36
- desc: 'executes "hostname" on the box "my_box"',
35
+ machine: :my_machine,
36
+ desc: 'executes "hostname" on the machine "my_machine"',
37
37
  script: 'hostname',
38
38
  usage: 'vagrant run %{command}',
39
39
  help: <<-eoh
@@ -216,9 +216,37 @@ vagrant run chainecho --first="initial" --second="initial"
216
216
  vagrant run chainecho --first="param" --second="param"
217
217
  ```
218
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`.
219
+ By default every command will be executed using the machine defined by the
220
+ command itself or the only one available. You can, however, run the complete
221
+ chain against a specific machine using `vagrant run your_machine your_chain`.
222
+
223
+ #### Chain Definitions with Specific Machines
224
+
225
+ If required you can modify the machine a box is run on:
226
+
227
+ ```ruby
228
+ command 'chainhost',
229
+ script: 'hostname'
230
+
231
+ chain 'customized_chain_machine',
232
+ commands: [
233
+ { command: 'chainhost' },
234
+ { command: 'chainecho', machine: 'secondary' },
235
+ { command: 'chainecho', machine: 'tertiary' }
236
+ ]
237
+
238
+ Running the chain will execute the following commands:
239
+
240
+ ```shell
241
+ > vagrant run customized_chain_machine
242
+
243
+ vagrant run chainhost
244
+ vagrant run secondary chainhost
245
+ vagrant run tertiary chainhost
246
+ ```
247
+
248
+ This configuration can itself be modified by passing a machine name to run
249
+ all chain commands on using using `vagrant run your_machine your_chain`.
222
250
 
223
251
  ### Abort Parsing inside Commandfile
224
252
 
@@ -250,7 +278,7 @@ evaluating a local one.
250
278
  ### SSH
251
279
 
252
280
  If you are using this plugin on a Windows host system, please make sure your
253
- regular `vagrant ssh [box]` succeeds. In some cases you may need to add the
281
+ regular `vagrant ssh [machine]` succeeds. In some cases you may need to add the
254
282
  `ssh.exe` (i.e. from a git installation) manually to your `%PATH%`.
255
283
 
256
284
  ### Command Definition
@@ -8,6 +8,7 @@ require 'vagrant/devcommands/version'
8
8
 
9
9
  require 'vagrant/devcommands/internal_spec'
10
10
  require 'vagrant/devcommands/messages'
11
+ require 'vagrant/devcommands/util/jaro_winkler'
11
12
  require 'vagrant/devcommands/util'
12
13
 
13
14
  require 'vagrant/devcommands/model/chain'
@@ -4,6 +4,7 @@ module VagrantPlugins
4
4
  class Command < Vagrant.plugin(2, :command)
5
5
  NAMESPACE_RUNNER = VagrantPlugins::DevCommands::Runner
6
6
  MESSAGES = VagrantPlugins::DevCommands::Messages
7
+ UTIL = VagrantPlugins::DevCommands::Util
7
8
 
8
9
  def self.synopsis
9
10
  synopsis = VagrantPlugins::DevCommands::SYNOPSIS
@@ -20,6 +21,8 @@ module VagrantPlugins
20
21
  def execute
21
22
  return 127 unless read_commandfile
22
23
 
24
+ deprecated_box_config?
25
+
23
26
  command = Util.argv_command(@argv, @env)
24
27
 
25
28
  return 127 unless non_empty?(command)
@@ -40,13 +43,27 @@ module VagrantPlugins
40
43
  def available?(command)
41
44
  unless @registry.available?(command)
42
45
  display_error("Invalid command \"#{command}\"!")
46
+ did_you_mean(command)
43
47
  run_internal('help', ['--commands'])
44
48
  end
45
49
 
46
50
  @registry.available?(command)
47
51
  end
48
52
 
49
- def display_error(msg, post_ln = false)
53
+ def deprecated_box_config?
54
+ return unless @registry.commands.values.any?(&:deprecated_box_config)
55
+
56
+ MESSAGES.deprecated_box_config(&@env.ui.method(:warn))
57
+ end
58
+
59
+ def did_you_mean(command)
60
+ alternative, score = Util.did_you_mean(command, @registry)
61
+
62
+ display_error("Did you mean #{alternative}?", true) if 0.8 < score
63
+ end
64
+
65
+ def display_error(msg, pre_ln = false, post_ln = false)
66
+ @env.ui.error '' if pre_ln
50
67
  @env.ui.error msg
51
68
  @env.ui.error '' if post_ln
52
69
  end
@@ -81,7 +98,7 @@ module VagrantPlugins
81
98
 
82
99
  runner.run(runnable)
83
100
  rescue RuntimeError => e
84
- display_error(e.message, true)
101
+ display_error(e.message, false, true)
85
102
  run_internal('help', [command])
86
103
 
87
104
  nil
@@ -39,7 +39,7 @@ module VagrantPlugins
39
39
  end
40
40
 
41
41
  def header(chain)
42
- usage = "vagrant run [box] #{chain.name}"
42
+ usage = "vagrant run [machine] #{chain.name}"
43
43
 
44
44
  info(I18n.t('vagrant_devcommands.internal.help.usage', what: usage))
45
45
  end
@@ -41,7 +41,7 @@ module VagrantPlugins
41
41
  end
42
42
 
43
43
  def header(command)
44
- usage = "vagrant run [box] #{command.name}"
44
+ usage = "vagrant run [machine] #{command.name}"
45
45
  usage = usage_params(usage, command)
46
46
 
47
47
  unless command.usage.nil?
@@ -7,7 +7,7 @@ module VagrantPlugins
7
7
  @env = env
8
8
  end
9
9
 
10
- def execute(_args)
10
+ def execute(_argv)
11
11
  @env.ui.info "vagrant-devcommands, version #{VERSION}"
12
12
  end
13
13
  end
@@ -10,6 +10,11 @@ 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 ''
16
+ end
17
+
13
18
  def self.command_no_help(&out)
14
19
  out.call I18n.t("#{I18N_KEY}.command_no_help")
15
20
  end
@@ -11,11 +11,13 @@ module VagrantPlugins
11
11
  attr_reader :parameters
12
12
  attr_reader :script
13
13
 
14
- attr_reader :box
14
+ attr_reader :machine
15
15
  attr_reader :desc
16
16
  attr_reader :help
17
17
  attr_reader :usage
18
18
 
19
+ attr_reader :deprecated_box_config
20
+
19
21
  def initialize(spec)
20
22
  @name = spec[:name]
21
23
 
@@ -23,10 +25,12 @@ module VagrantPlugins
23
25
  @parameters = spec[:parameters]
24
26
  @script = spec[:script]
25
27
 
26
- @box = spec[:box]
27
- @desc = spec[:desc]
28
- @help = spec[:help]
29
- @usage = spec[:usage]
28
+ @machine = spec[:machine] || spec[:box]
29
+ @desc = spec[:desc]
30
+ @help = spec[:help]
31
+ @usage = spec[:usage]
32
+
33
+ @deprecated_box_config = spec.key?(:box)
30
34
  end
31
35
 
32
36
  def run_script(argv)
@@ -87,6 +91,7 @@ module VagrantPlugins
87
91
 
88
92
  wrap_option_values(escape_option_values(options))
89
93
  end
94
+ # rubocop:enable Metrics/MethodLength
90
95
 
91
96
  def wrap_option_values(options)
92
97
  (@parameters || {}).each do |key, conf|
@@ -3,6 +3,8 @@ module VagrantPlugins
3
3
  module Runner
4
4
  # Chain runner
5
5
  class Chain
6
+ UTIL = VagrantPlugins::DevCommands::Util
7
+
6
8
  def initialize(plugin, argv, env, registry)
7
9
  @plugin = plugin
8
10
  @argv = argv
@@ -29,10 +31,22 @@ module VagrantPlugins
29
31
  private
30
32
 
31
33
  def argv_for(command_def)
32
- return @argv unless command_def.key?(:argv)
33
- return @argv unless command_def[:argv].is_a?(Array)
34
+ argv = patch_machine(@argv.dup, command_def)
35
+
36
+ return argv unless command_def.key?(:argv)
37
+ return argv unless command_def[:argv].is_a?(Array)
38
+
39
+ argv + command_def[:argv]
40
+ end
41
+
42
+ def patch_machine(argv, command_def)
43
+ return argv unless command_def.key?(:machine)
34
44
 
35
- @argv + command_def[:argv]
45
+ if UTIL.machine_name?(argv[0].to_s, @env.machine_index)
46
+ argv
47
+ else
48
+ [command_def[:machine].to_s] + argv
49
+ end
36
50
  end
37
51
 
38
52
  def runnable_for(command_def)
@@ -13,13 +13,13 @@ module VagrantPlugins
13
13
  end
14
14
 
15
15
  def run(command)
16
- argv = run_argv
17
- box = run_box(command)
18
- script = run_script(command, argv)
16
+ argv = run_argv
17
+ machine = run_machine(command)
18
+ script = run_script(command, argv)
19
19
 
20
20
  return 2 unless script
21
21
 
22
- @plugin.proxy_with_target_vms(box, single_target: true) do |vm|
22
+ @plugin.proxy_with_target_vms(machine, single_target: true) do |vm|
23
23
  env = vm.action(:ssh_run,
24
24
  ssh_opts: { extra_args: ['-q'] },
25
25
  ssh_run_command: script)
@@ -38,13 +38,13 @@ module VagrantPlugins
38
38
  argv
39
39
  end
40
40
 
41
- def run_box(cmd)
42
- box = nil
43
- box = cmd.box.to_s if cmd.box
44
- box = @argv[0] if UTIL.machine_name?(@argv[0].to_s,
45
- @env.machine_index)
41
+ def run_machine(cmd)
42
+ machine = nil
43
+ machine = cmd.machine.to_s if cmd.machine
44
+ machine = @argv[0] if UTIL.machine_name?(@argv[0].to_s,
45
+ @env.machine_index)
46
46
 
47
- box
47
+ machine
48
48
  end
49
49
 
50
50
  def run_script(command, argv)
@@ -2,6 +2,8 @@ module VagrantPlugins
2
2
  module DevCommands
3
3
  # Utility module
4
4
  class Util
5
+ JARO_WINKLER = VagrantPlugins::DevCommands::Util::JaroWinkler
6
+
5
7
  def self.argv_command(argv, env)
6
8
  return nil if argv.empty?
7
9
 
@@ -29,6 +31,18 @@ module VagrantPlugins
29
31
  end
30
32
  end
31
33
 
34
+ def self.did_you_mean(command, registry)
35
+ alternatives = registry.commands.keys + registry.chains.keys
36
+ distances = {}
37
+
38
+ alternatives.each do |alternative|
39
+ calculator = JARO_WINKLER.new(command, alternative)
40
+ distances[alternative] = calculator.distance
41
+ end
42
+
43
+ distances.max_by { |_k, v| v }
44
+ end
45
+
32
46
  def self.machine_name?(name, machine_index)
33
47
  machine_index.any? { |machine| name == machine.name }
34
48
  end
@@ -0,0 +1,126 @@
1
+ module VagrantPlugins
2
+ module DevCommands
3
+ class Util
4
+ # Jaro Winkler string distance
5
+ #
6
+ # Adapted from:
7
+ # https://github.com/bbatsov/rubocop/blob/ec3123fc3454b080e1100e35480c6466d1240fff/lib/rubocop/string_util.rb
8
+ class JaroWinkler
9
+ BOOST_THRESHOLD = 0.7
10
+ MAX_COMMON_PREFIX_LENGTH = 4
11
+ SCALING_FACTOR = 0.1
12
+
13
+ def initialize(left, right)
14
+ @left = left.to_s
15
+ @right = right.to_s
16
+
17
+ if @left.size < @right.size
18
+ @shorter = @left
19
+ @longer = @right
20
+ else
21
+ @shorter = @right
22
+ @longer = @left
23
+ end
24
+ end
25
+
26
+ def distance
27
+ jaro_distance = compute_distance
28
+
29
+ if jaro_distance >= BOOST_THRESHOLD
30
+ jaro_distance += (
31
+ limited_common_prefix_length.to_f *
32
+ SCALING_FACTOR.to_f *
33
+ (1.0 - jaro_distance)
34
+ )
35
+ end
36
+
37
+ jaro_distance
38
+ end
39
+
40
+ private
41
+
42
+ def common_prefix_length
43
+ @shorter.size.times do |index|
44
+ return index unless @shorter[index] == @longer[index]
45
+ end
46
+
47
+ @shorter.size
48
+ end
49
+
50
+ def compute_distance
51
+ common_chars_a, common_chars_b = find_common_characters
52
+ matched_count = common_chars_a.size
53
+
54
+ return 0.0 if matched_count.zero?
55
+
56
+ transposition_count = count_transpositions(common_chars_a,
57
+ common_chars_b)
58
+
59
+ compute_non_zero_distance(matched_count.to_f, transposition_count)
60
+ end
61
+
62
+ def compute_non_zero_distance(matched_count, transposition_count)
63
+ sum = (matched_count / @shorter.size.to_f) +
64
+ (matched_count / @longer.size.to_f) +
65
+ ((matched_count - transposition_count / 2) / matched_count)
66
+
67
+ sum / 3.0
68
+ end
69
+
70
+ def count_transpositions(common_chars_a, common_chars_b)
71
+ common_chars_a.size.times.count do |index|
72
+ common_chars_a[index] != common_chars_b[index]
73
+ end
74
+ end
75
+
76
+ # rubocop:disable Metrics/MethodLength
77
+ def find_common_characters
78
+ common_chars_of_shorter = Array.new(@shorter.size)
79
+ common_chars_of_longer = Array.new(@longer.size)
80
+
81
+ @shorter.each_char.with_index do |shorter_char, shorter_index|
82
+ matching_index_range(shorter_index).each do |longer_index|
83
+ longer_char = @longer.chars[longer_index]
84
+
85
+ next unless shorter_char == longer_char
86
+
87
+ common_chars_of_shorter[shorter_index] = shorter_char
88
+ common_chars_of_longer[longer_index] = longer_char
89
+
90
+ # Mark the matching character as already used
91
+ @longer.chars[longer_index] = nil
92
+
93
+ break
94
+ end
95
+ end
96
+
97
+ [common_chars_of_shorter, common_chars_of_longer].map(&:compact)
98
+ end
99
+ # rubocop:enable Metrics/MethodLength
100
+
101
+ def limited_common_prefix_length
102
+ length = common_prefix_length
103
+
104
+ if length > MAX_COMMON_PREFIX_LENGTH
105
+ MAX_COMMON_PREFIX_LENGTH
106
+ else
107
+ length
108
+ end
109
+ end
110
+
111
+ def matching_index_range(origin)
112
+ min = origin - matching_window
113
+ min = 0 if min < 0
114
+
115
+ max = origin + matching_window
116
+
117
+ min..max
118
+ end
119
+
120
+ def matching_window
121
+ @matching_window ||= (@longer.size / 2).to_i - 1
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -1,6 +1,6 @@
1
1
  module VagrantPlugins
2
2
  # Defines the current plugin version
3
3
  module DevCommands
4
- VERSION = '0.8.0'.freeze
4
+ VERSION = '0.9.0'.freeze
5
5
  end
6
6
  end
data/locales/en.yml CHANGED
@@ -7,7 +7,6 @@ en:
7
7
  Display the help of the command given as the first argument if defined.
8
8
  Just like this help for the help command!
9
9
  usage: "Usage: %{what}"
10
-
11
10
  version:
12
11
  desc: "get currently installed plugin version"
13
12
  help: "Displays the currently installed version of the plugin you are using right now."
@@ -15,6 +14,10 @@ en:
15
14
  message:
16
15
  chain_no_help: "No detailed help for this chain available."
17
16
  command_no_help: "No detailed help for this command available."
17
+ deprecated_box_config: |-
18
+ At least one of your commands is configured with the deprecated
19
+ option ':box'. This option has been renamed to ':machine' and will
20
+ stop working in a future version. Please update your Commandfile.
18
21
  missing_commandfile: "Missing Commandfile"
19
22
  no_commands: "No commands defined!"
20
23
  plugin_readme: |-
@@ -24,7 +27,7 @@ en:
24
27
  A copy of this file should be locally available at:
25
28
  >>> %{readme}
26
29
  plugin_usage: |-
27
- Usage: vagrant run [box] <command>
30
+ Usage: vagrant run [machine] <command>
28
31
  Help: vagrant run help <command>
29
32
 
30
33
  registry:
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.8.0
4
+ version: 0.9.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-04-19 00:00:00.000000000 Z
11
+ date: 2017-05-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: coveralls
@@ -95,6 +95,7 @@ files:
95
95
  - lib/vagrant/devcommands/runner/internal_command.rb
96
96
  - lib/vagrant/devcommands/synopsis.rb
97
97
  - lib/vagrant/devcommands/util.rb
98
+ - lib/vagrant/devcommands/util/jaro_winkler.rb
98
99
  - lib/vagrant/devcommands/version.rb
99
100
  - locales/en.yml
100
101
  homepage: https://github.com/mneudert/vagrant-devcommands