vagrant-unbundled 2.2.6.2 → 2.2.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (287) hide show
  1. checksums.yaml +4 -4
  2. data/.hashibot.hcl +14 -0
  3. data/CHANGELOG.md +213 -2
  4. data/Gemfile +1 -1
  5. data/README.md +9 -51
  6. data/RELEASE.md +1 -1
  7. data/bin/vagrant +23 -0
  8. data/contrib/README.md +1 -0
  9. data/contrib/bash/completion.sh +13 -1
  10. data/contrib/sudoers/linux-suse +2 -2
  11. data/contrib/zsh/_vagrant +738 -0
  12. data/contrib/zsh/generate_zsh_completion.rb +165 -0
  13. data/lib/vagrant.rb +25 -4
  14. data/lib/vagrant/action.rb +8 -0
  15. data/lib/vagrant/action/builder.rb +184 -38
  16. data/lib/vagrant/action/builtin/box_add.rb +20 -8
  17. data/lib/vagrant/action/builtin/box_check_outdated.rb +12 -15
  18. data/lib/vagrant/action/builtin/cleanup_disks.rb +56 -0
  19. data/lib/vagrant/action/builtin/cloud_init_setup.rb +122 -0
  20. data/lib/vagrant/action/builtin/cloud_init_wait.rb +30 -0
  21. data/lib/vagrant/action/builtin/delayed.rb +26 -0
  22. data/lib/vagrant/action/builtin/disk.rb +52 -0
  23. data/lib/vagrant/action/builtin/handle_box.rb +3 -1
  24. data/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb +28 -9
  25. data/lib/vagrant/action/builtin/has_provisioner.rb +36 -0
  26. data/lib/vagrant/action/builtin/mixin_provisioners.rb +20 -1
  27. data/lib/vagrant/action/builtin/mixin_synced_folders.rb +20 -21
  28. data/lib/vagrant/action/builtin/set_hostname.rb +5 -1
  29. data/lib/vagrant/action/builtin/ssh_run.rb +21 -3
  30. data/lib/vagrant/action/builtin/synced_folders.rb +16 -0
  31. data/lib/vagrant/action/builtin/trigger.rb +37 -0
  32. data/lib/vagrant/action/hook.rb +76 -23
  33. data/lib/vagrant/action/runner.rb +12 -27
  34. data/lib/vagrant/action/warden.rb +28 -22
  35. data/lib/vagrant/box.rb +11 -4
  36. data/lib/vagrant/box_collection.rb +1 -1
  37. data/lib/vagrant/box_metadata.rb +17 -3
  38. data/lib/vagrant/bundler.rb +298 -59
  39. data/lib/vagrant/cli.rb +4 -2
  40. data/lib/vagrant/errors.rb +61 -1
  41. data/lib/vagrant/machine.rb +64 -11
  42. data/lib/vagrant/machine_index.rb +28 -1
  43. data/lib/vagrant/plugin/manager.rb +25 -14
  44. data/lib/vagrant/plugin/v2/command.rb +7 -2
  45. data/lib/vagrant/plugin/v2/components.rb +6 -0
  46. data/lib/vagrant/plugin/v2/manager.rb +67 -0
  47. data/lib/vagrant/plugin/v2/plugin.rb +13 -0
  48. data/lib/vagrant/plugin/v2/synced_folder.rb +50 -0
  49. data/lib/vagrant/plugin/v2/trigger.rb +64 -25
  50. data/lib/vagrant/shared_helpers.rb +36 -0
  51. data/lib/vagrant/ui.rb +51 -5
  52. data/lib/vagrant/util.rb +1 -0
  53. data/lib/vagrant/util/ansi_escape_code_remover.rb +1 -1
  54. data/lib/vagrant/util/caps.rb +48 -0
  55. data/lib/vagrant/util/credential_scrubber.rb +1 -1
  56. data/lib/vagrant/util/curl_helper.rb +8 -5
  57. data/lib/vagrant/util/directory.rb +19 -0
  58. data/lib/vagrant/util/downloader.rb +10 -5
  59. data/lib/vagrant/util/file_checksum.rb +6 -2
  60. data/lib/vagrant/util/guest_hosts.rb +68 -0
  61. data/lib/vagrant/util/guest_inspection.rb +9 -1
  62. data/lib/vagrant/util/install_cli_autocomplete.rb +118 -0
  63. data/lib/vagrant/util/io.rb +7 -27
  64. data/lib/vagrant/util/ipv4_interfaces.rb +15 -0
  65. data/lib/vagrant/util/is_port_open.rb +8 -20
  66. data/lib/vagrant/util/map_command_options.rb +33 -0
  67. data/lib/vagrant/util/mime.rb +92 -0
  68. data/lib/vagrant/util/network_ip.rb +11 -1
  69. data/lib/vagrant/util/numeric.rb +69 -0
  70. data/lib/vagrant/util/platform.rb +10 -2
  71. data/lib/vagrant/util/powershell.rb +1 -1
  72. data/lib/vagrant/util/subprocess.rb +9 -1
  73. data/lib/vagrant/util/template_renderer.rb +2 -2
  74. data/lib/vagrant/util/uploader.rb +7 -4
  75. data/lib/vagrant/vagrantfile.rb +1 -1
  76. data/plugins/commands/autocomplete/command/install.rb +49 -0
  77. data/plugins/commands/autocomplete/command/root.rb +64 -0
  78. data/plugins/commands/autocomplete/plugin.rb +18 -0
  79. data/plugins/commands/box/command/outdated.rb +14 -2
  80. data/plugins/commands/cap/command.rb +5 -1
  81. data/plugins/commands/cloud/auth/login.rb +20 -23
  82. data/plugins/commands/cloud/auth/logout.rb +2 -10
  83. data/plugins/commands/cloud/auth/middleware/add_downloader_authentication.rb +57 -0
  84. data/plugins/commands/cloud/auth/whoami.rb +18 -20
  85. data/plugins/commands/cloud/box/create.rb +33 -29
  86. data/plugins/commands/cloud/box/delete.rb +30 -24
  87. data/plugins/commands/cloud/box/show.rb +41 -31
  88. data/plugins/commands/cloud/box/update.rb +34 -26
  89. data/plugins/commands/cloud/client/client.rb +50 -81
  90. data/plugins/commands/cloud/list.rb +3 -4
  91. data/plugins/commands/cloud/locales/en.yml +10 -10
  92. data/plugins/commands/cloud/plugin.rb +10 -0
  93. data/plugins/commands/cloud/provider/create.rb +38 -28
  94. data/plugins/commands/cloud/provider/delete.rb +39 -29
  95. data/plugins/commands/cloud/provider/update.rb +37 -28
  96. data/plugins/commands/cloud/provider/upload.rb +44 -34
  97. data/plugins/commands/cloud/publish.rb +185 -108
  98. data/plugins/commands/cloud/search.rb +34 -21
  99. data/plugins/commands/cloud/util.rb +266 -162
  100. data/plugins/commands/cloud/version/create.rb +33 -28
  101. data/plugins/commands/cloud/version/delete.rb +35 -28
  102. data/plugins/commands/cloud/version/release.rb +35 -29
  103. data/plugins/commands/cloud/version/revoke.rb +36 -29
  104. data/plugins/commands/cloud/version/update.rb +29 -25
  105. data/plugins/commands/destroy/command.rb +6 -2
  106. data/plugins/commands/login/plugin.rb +0 -13
  107. data/plugins/commands/snapshot/command/save.rb +13 -8
  108. data/plugins/commands/ssh_config/command.rb +1 -1
  109. data/plugins/communicators/ssh/communicator.rb +25 -24
  110. data/plugins/communicators/winrm/config.rb +1 -1
  111. data/plugins/communicators/winrm/helper.rb +1 -1
  112. data/plugins/communicators/winrm/shell.rb +1 -1
  113. data/plugins/communicators/winssh/communicator.rb +126 -38
  114. data/plugins/communicators/winssh/config.rb +3 -7
  115. data/plugins/guests/alpine/cap/change_host_name.rb +10 -11
  116. data/plugins/guests/alpine/cap/rsync.rb +1 -1
  117. data/plugins/guests/alpine/plugin.rb +16 -0
  118. data/plugins/guests/alt/cap/change_host_name.rb +40 -53
  119. data/plugins/guests/arch/cap/change_host_name.rb +5 -14
  120. data/plugins/guests/arch/cap/configure_networks.rb +27 -10
  121. data/plugins/guests/arch/cap/smb.rb +1 -1
  122. data/plugins/guests/atomic/cap/change_host_name.rb +5 -14
  123. data/plugins/guests/centos/cap/flavor.rb +24 -0
  124. data/plugins/guests/centos/guest.rb +9 -0
  125. data/plugins/guests/centos/plugin.rb +20 -0
  126. data/plugins/guests/darwin/cap/change_host_name.rb +10 -6
  127. data/plugins/guests/darwin/cap/darwin_version.rb +40 -0
  128. data/plugins/guests/darwin/cap/mount_smb_shared_folder.rb +1 -1
  129. data/plugins/guests/darwin/cap/mount_vmware_shared_folder.rb +109 -13
  130. data/plugins/guests/darwin/plugin.rb +15 -0
  131. data/plugins/guests/debian/cap/change_host_name.rb +12 -11
  132. data/plugins/guests/debian/cap/configure_networks.rb +14 -6
  133. data/plugins/guests/esxi/cap/public_key.rb +3 -1
  134. data/plugins/guests/freebsd/cap/change_host_name.rb +10 -6
  135. data/plugins/guests/gentoo/cap/change_host_name.rb +14 -22
  136. data/plugins/guests/haiku/cap/rsync.rb +19 -0
  137. data/plugins/guests/haiku/plugin.rb +15 -0
  138. data/plugins/guests/linux/cap/change_host_name.rb +46 -0
  139. data/plugins/guests/linux/cap/halt.rb +9 -1
  140. data/plugins/guests/linux/cap/mount_smb_shared_folder.rb +25 -34
  141. data/plugins/guests/linux/cap/mount_virtualbox_shared_folder.rb +10 -11
  142. data/plugins/guests/linux/cap/persist_mount_shared_folder.rb +75 -0
  143. data/plugins/guests/linux/cap/reboot.rb +53 -0
  144. data/plugins/guests/linux/plugin.rb +20 -0
  145. data/plugins/guests/omnios/cap/change_host_name.rb +10 -16
  146. data/plugins/guests/openbsd/cap/change_host_name.rb +10 -6
  147. data/plugins/guests/photon/cap/change_host_name.rb +9 -15
  148. data/plugins/guests/pld/cap/change_host_name.rb +11 -17
  149. data/plugins/guests/redhat/cap/change_host_name.rb +14 -5
  150. data/plugins/guests/redhat/cap/flavor.rb +3 -1
  151. data/plugins/guests/redhat/cap/nfs_client.rb +2 -2
  152. data/plugins/guests/redhat/cap/smb.rb +20 -0
  153. data/plugins/guests/redhat/plugin.rb +5 -0
  154. data/plugins/guests/slackware/cap/change_host_name.rb +11 -17
  155. data/plugins/guests/solaris11/plugin.rb +5 -0
  156. data/plugins/guests/suse/cap/change_host_name.rb +31 -9
  157. data/plugins/guests/windows/cap/public_key.rb +3 -3
  158. data/plugins/guests/windows/cap/reboot.rb +10 -5
  159. data/plugins/hosts/darwin/cap/fs_iso.rb +49 -0
  160. data/plugins/hosts/darwin/cap/nfs.rb +11 -0
  161. data/plugins/hosts/darwin/plugin.rb +15 -0
  162. data/plugins/hosts/linux/cap/fs_iso.rb +49 -0
  163. data/plugins/hosts/linux/cap/nfs.rb +21 -2
  164. data/plugins/hosts/linux/cap/rdp.rb +1 -1
  165. data/plugins/hosts/linux/plugin.rb +10 -0
  166. data/plugins/hosts/windows/cap/fs_iso.rb +48 -0
  167. data/plugins/hosts/windows/cap/rdp.rb +1 -1
  168. data/plugins/hosts/windows/plugin.rb +15 -0
  169. data/plugins/kernel_v2/config/cloud_init.rb +133 -0
  170. data/plugins/kernel_v2/config/disk.rb +221 -0
  171. data/plugins/kernel_v2/config/ssh_connect.rb +24 -0
  172. data/plugins/kernel_v2/config/vm.rb +230 -15
  173. data/plugins/kernel_v2/config/vm_provisioner.rb +17 -3
  174. data/plugins/kernel_v2/config/vm_trigger.rb +6 -5
  175. data/plugins/providers/docker/action.rb +8 -17
  176. data/plugins/providers/docker/action/forwarded_ports.rb +2 -0
  177. data/plugins/providers/docker/action/prepare_forwarded_port_collision_params.rb +61 -0
  178. data/plugins/providers/docker/cap/has_communicator.rb +11 -0
  179. data/plugins/providers/docker/communicator.rb +1 -1
  180. data/plugins/providers/docker/driver.rb +73 -10
  181. data/plugins/providers/docker/errors.rb +4 -0
  182. data/plugins/providers/docker/executor/local.rb +7 -1
  183. data/plugins/providers/docker/plugin.rb +5 -0
  184. data/plugins/providers/hyperv/action.rb +3 -1
  185. data/plugins/providers/hyperv/action/configure.rb +8 -0
  186. data/plugins/providers/hyperv/action/export.rb +4 -2
  187. data/plugins/providers/hyperv/cap/cleanup_disks.rb +54 -0
  188. data/plugins/providers/hyperv/cap/configure_disks.rb +200 -0
  189. data/plugins/providers/hyperv/cap/validate_disk_ext.rb +34 -0
  190. data/plugins/providers/hyperv/config.rb +5 -0
  191. data/plugins/providers/hyperv/driver.rb +90 -9
  192. data/plugins/providers/hyperv/plugin.rb +25 -0
  193. data/plugins/providers/hyperv/scripts/attach_disk_drive.ps1 +28 -0
  194. data/plugins/providers/hyperv/scripts/dismount_vhd.ps1 +13 -0
  195. data/plugins/providers/hyperv/scripts/get_vhd.ps1 +16 -0
  196. data/plugins/providers/hyperv/scripts/get_vm_status.ps1 +1 -1
  197. data/plugins/providers/hyperv/scripts/list_hdds.ps1 +17 -0
  198. data/plugins/providers/hyperv/scripts/new_vhd.ps1 +31 -0
  199. data/plugins/providers/hyperv/scripts/remove_disk_drive.ps1 +25 -0
  200. data/plugins/providers/hyperv/scripts/resize_disk_drive.ps1 +18 -0
  201. data/plugins/providers/hyperv/scripts/set_enhanced_session_transport_type.ps1 +24 -0
  202. data/plugins/providers/hyperv/scripts/set_vm_integration_services.ps1 +3 -3
  203. data/plugins/providers/hyperv/scripts/utils/VagrantVM/VagrantVM.psm1 +14 -6
  204. data/plugins/providers/virtualbox/action.rb +14 -1
  205. data/plugins/providers/virtualbox/action/clean_machine_folder.rb +10 -1
  206. data/plugins/providers/virtualbox/action/export.rb +4 -2
  207. data/plugins/providers/virtualbox/action/forward_ports.rb +2 -2
  208. data/plugins/providers/virtualbox/action/import.rb +8 -4
  209. data/plugins/providers/virtualbox/action/prepare_clone_snapshot.rb +4 -2
  210. data/plugins/providers/virtualbox/action/snapshot_delete.rb +4 -2
  211. data/plugins/providers/virtualbox/action/snapshot_restore.rb +4 -2
  212. data/plugins/providers/virtualbox/cap/cleanup_disks.rb +85 -0
  213. data/plugins/providers/virtualbox/cap/configure_disks.rb +440 -0
  214. data/plugins/providers/virtualbox/cap/mount_options.rb +35 -0
  215. data/plugins/providers/virtualbox/cap/validate_disk_ext.rb +34 -0
  216. data/plugins/providers/virtualbox/driver/base.rb +15 -0
  217. data/plugins/providers/virtualbox/driver/meta.rb +17 -2
  218. data/plugins/providers/virtualbox/driver/version_5_0.rb +217 -2
  219. data/plugins/providers/virtualbox/driver/version_6_1.rb +39 -0
  220. data/plugins/providers/virtualbox/model/storage_controller.rb +135 -0
  221. data/plugins/providers/virtualbox/model/storage_controller_array.rb +98 -0
  222. data/plugins/providers/virtualbox/plugin.rb +38 -0
  223. data/plugins/providers/virtualbox/provider.rb +2 -1
  224. data/plugins/providers/virtualbox/synced_folder.rb +1 -0
  225. data/plugins/provisioners/ansible/cap/guest/alpine/ansible_install.rb +44 -0
  226. data/plugins/provisioners/ansible/cap/guest/arch/ansible_install.rb +20 -3
  227. data/plugins/provisioners/ansible/cap/guest/debian/ansible_install.rb +4 -5
  228. data/plugins/provisioners/ansible/cap/guest/fedora/ansible_install.rb +2 -2
  229. data/plugins/provisioners/ansible/cap/guest/freebsd/ansible_install.rb +2 -2
  230. data/plugins/provisioners/ansible/cap/guest/pip/pip.rb +8 -4
  231. data/plugins/provisioners/ansible/cap/guest/redhat/ansible_install.rb +2 -2
  232. data/plugins/provisioners/ansible/cap/guest/suse/ansible_install.rb +2 -1
  233. data/plugins/provisioners/ansible/cap/guest/ubuntu/ansible_install.rb +3 -3
  234. data/plugins/provisioners/ansible/plugin.rb +5 -0
  235. data/plugins/provisioners/ansible/provisioner/base.rb +1 -1
  236. data/plugins/provisioners/container/client.rb +203 -0
  237. data/plugins/provisioners/container/config.rb +83 -0
  238. data/plugins/provisioners/container/installer.rb +13 -0
  239. data/plugins/provisioners/container/plugin.rb +23 -0
  240. data/plugins/provisioners/container/provisioner.rb +28 -0
  241. data/plugins/provisioners/docker/cap/{redhat → centos}/docker_install.rb +10 -7
  242. data/plugins/provisioners/docker/cap/centos/docker_start_service.rb +24 -0
  243. data/plugins/provisioners/docker/client.rb +4 -175
  244. data/plugins/provisioners/docker/config.rb +2 -72
  245. data/plugins/provisioners/docker/installer.rb +3 -5
  246. data/plugins/provisioners/docker/plugin.rb +6 -6
  247. data/plugins/provisioners/docker/provisioner.rb +4 -10
  248. data/plugins/provisioners/podman/cap/centos/podman_install.rb +35 -0
  249. data/plugins/provisioners/podman/cap/linux/podman_installed.rb +13 -0
  250. data/plugins/provisioners/podman/cap/redhat/podman_install.rb +26 -0
  251. data/plugins/provisioners/podman/client.rb +12 -0
  252. data/plugins/provisioners/podman/config.rb +28 -0
  253. data/plugins/provisioners/podman/installer.rb +33 -0
  254. data/plugins/provisioners/podman/plugin.rb +38 -0
  255. data/plugins/provisioners/podman/provisioner.rb +52 -0
  256. data/plugins/provisioners/salt/provisioner.rb +4 -0
  257. data/plugins/provisioners/shell/config.rb +1 -6
  258. data/plugins/provisioners/shell/provisioner.rb +61 -26
  259. data/plugins/synced_folders/nfs/synced_folder.rb +3 -1
  260. data/plugins/synced_folders/smb/cap/default_fstab_modification.rb +11 -0
  261. data/plugins/synced_folders/smb/cap/mount_options.rb +56 -0
  262. data/plugins/synced_folders/smb/plugin.rb +20 -0
  263. data/plugins/synced_folders/smb/synced_folder.rb +2 -2
  264. data/plugins/synced_folders/unix_mount_helpers.rb +14 -0
  265. data/scripts/website_push_www.sh +1 -1
  266. data/templates/commands/init/Vagrantfile.erb +1 -1
  267. data/templates/guests/arch/{network_dhcp.erb → default_network/network_dhcp.erb} +0 -0
  268. data/templates/guests/arch/{network_static.erb → default_network/network_static.erb} +0 -0
  269. data/templates/guests/arch/{network_static6.erb → default_network/network_static6.erb} +0 -0
  270. data/templates/guests/arch/systemd_networkd/network_dhcp.erb +6 -0
  271. data/templates/guests/arch/systemd_networkd/network_static.erb +9 -0
  272. data/templates/guests/arch/systemd_networkd/network_static6.erb +9 -0
  273. data/templates/guests/linux/etc_fstab.erb +6 -0
  274. data/templates/locales/en.yml +235 -6
  275. data/templates/locales/providers_docker.yml +6 -0
  276. data/templates/nfs/exports_darwin.erb +7 -0
  277. data/vagrant.gemspec +14 -15
  278. data/version.txt +1 -1
  279. metadata +3577 -3855
  280. data/lib/vagrant/action/builtin/after_trigger.rb +0 -31
  281. data/lib/vagrant/action/builtin/before_trigger.rb +0 -28
  282. data/plugins/commands/login/client.rb +0 -253
  283. data/plugins/commands/login/command.rb +0 -137
  284. data/plugins/commands/login/errors.rb +0 -24
  285. data/plugins/commands/login/locales/en.yml +0 -49
  286. data/plugins/provisioners/docker/cap/redhat/docker_start_service.rb +0 -16
  287. data/scripts/website_push_docs.sh +0 -40
@@ -34,30 +34,19 @@ module Vagrant
34
34
  environment.merge!(@lazy_globals.call) if @lazy_globals
35
35
  environment.merge!(options || {})
36
36
 
37
- if Vagrant::Util::Experimental.feature_enabled?("typed_triggers")
38
- # NOTE: Triggers are initialized later in the Action::Runer because of
39
- # how `@lazy_globals` are evaluated. Rather than trying to guess where
40
- # the `env` is coming from, we can wait until they're merged into a single
41
- # hash above.
42
- env = environment[:env]
43
- machine = environment[:machine]
44
- machine_name = machine.name if machine
37
+ # NOTE: Triggers are initialized later in the Action::Runer because of
38
+ # how `@lazy_globals` are evaluated. Rather than trying to guess where
39
+ # the `env` is coming from, we can wait until they're merged into a single
40
+ # hash above.
41
+ env = environment[:env]
42
+ machine = environment[:machine]
45
43
 
46
- ui = Vagrant::UI::Prefixed.new(env.ui, "vagrant")
47
- triggers = Vagrant::Plugin::V2::Trigger.new(env, env.vagrantfile.config.trigger, machine, ui)
48
- end
49
-
50
- # Setup the action hooks
51
- hooks = Vagrant.plugin("2").manager.action_hooks(environment[:action_name])
52
- if !hooks.empty?
53
- @logger.info("Preparing hooks for middleware sequence...")
54
- environment[:action_hooks] = hooks.map do |hook_proc|
55
- Hook.new.tap do |h|
56
- hook_proc.call(h)
57
- end
58
- end
44
+ environment[:triggers] = machine.triggers if machine
59
45
 
60
- @logger.info("#{environment[:action_hooks].length} hooks defined.")
46
+ if env
47
+ ui = Vagrant::UI::Prefixed.new(env.ui, "vagrant")
48
+ environment[:triggers] ||= Vagrant::Plugin::V2::Trigger.
49
+ new(env, env.vagrantfile.config.trigger, machine, ui)
61
50
  end
62
51
 
63
52
  # Run the action chain in a busy block, marking the environment as
@@ -95,14 +84,10 @@ module Vagrant
95
84
 
96
85
  action_name = environment[:action_name]
97
86
 
98
- triggers.fire_triggers(action_name, :before, machine_name, :hook) if Vagrant::Util::Experimental.feature_enabled?("typed_triggers")
99
-
100
87
  # We place a process lock around every action that is called
101
- @logger.info("Running action: #{environment[:action_name]} #{callable_id}")
88
+ @logger.info("Running action: #{action_name} #{callable_id}")
102
89
  Util::Busy.busy(int_callback) { callable.call(environment) }
103
90
 
104
- triggers.fire_triggers(action_name, :after, machine_name, :hook) if Vagrant::Util::Experimental.feature_enabled?("typed_triggers")
105
-
106
91
  # Return the environment in case there are things in there that
107
92
  # the caller wants to use.
108
93
  environment
@@ -1,7 +1,5 @@
1
1
  require "log4r"
2
2
  require 'vagrant/util/experimental'
3
- require 'vagrant/action/builtin/before_trigger'
4
- require 'vagrant/action/builtin/after_trigger'
5
3
 
6
4
  module Vagrant
7
5
  module Action
@@ -50,9 +48,9 @@ module Vagrant
50
48
  @stack.unshift(action).first.call(env)
51
49
  raise Errors::VagrantInterrupt if env[:interrupted]
52
50
  @logger.info("Calling OUT action: #{action}")
53
- rescue SystemExit
54
- # This means that an "exit" or "abort" was called. In these cases,
55
- # we just exit immediately.
51
+ rescue SystemExit, NoMemoryError
52
+ # This means that an "exit" or "abort" was called, or we have run out
53
+ # of memory. In these cases, we just exit immediately.
56
54
  raise
57
55
  rescue Exception => e
58
56
  # We guard this so that the Warden only outputs this once for
@@ -94,26 +92,34 @@ module Vagrant
94
92
  # A somewhat confusing function which simply initializes each
95
93
  # middleware properly to call the next middleware in the sequence.
96
94
  def finalize_action(action, env)
97
- klass, args, block = action
95
+ if action.is_a?(Builder::StackItem)
96
+ klass = action.middleware
97
+ args = action.arguments.parameters
98
+ keywords = action.arguments.keywords
99
+ block = action.arguments.block
100
+ else
101
+ klass = action
102
+ args = []
103
+ keywords = {}
104
+ end
98
105
 
99
- # Default the arguments to an empty array. Otherwise in Ruby 1.8
100
- # a `nil` args will actually pass `nil` into the class.
101
- args ||= []
106
+ args = nil if args.empty?
107
+ keywords = nil if keywords.empty?
102
108
 
103
109
  if klass.is_a?(Class)
104
- # A action klass which is to be instantiated with the
105
- # app, env, and any arguments given
106
-
107
- # We wrap the action class in two Trigger method calls so that
108
- # action triggers can fire before and after each given action in the stack.
109
- klass_name = klass.name
110
- [Vagrant::Action::Builtin::BeforeTriggerAction.new(self, env,
111
- klass_name,
112
- @triggers),
113
- klass.new(self, env, *args, &block),
114
- Vagrant::Action::Builtin::AfterTriggerAction.new(self, env,
115
- klass_name,
116
- @triggers)]
110
+ # NOTE: We need to detect if we are passing args and/or
111
+ # keywords and do it explicitly. Earlier versions
112
+ # are not as lax about splatting keywords when the
113
+ # target method is not expecting them.
114
+ if args && keywords
115
+ klass.new(self, env, *args, **keywords, &block)
116
+ elsif args
117
+ klass.new(self, env, *args, &block)
118
+ elsif keywords
119
+ klass.new(self, env, **keywords, &block)
120
+ else
121
+ klass.new(self, env, &block)
122
+ end
117
123
  elsif klass.respond_to?(:call)
118
124
  # Make it a lambda which calls the item then forwards
119
125
  # up the chain
@@ -57,12 +57,15 @@ module Vagrant
57
57
  # @param [Symbol] provider The provider that this box implements.
58
58
  # @param [Pathname] directory The directory where this box exists on
59
59
  # disk.
60
- def initialize(name, provider, version, directory, **opts)
60
+ # @param [String] metadata_url Metadata URL for box
61
+ # @param [Hook] hook A hook to apply to the box downloader, for example, for authentication
62
+ def initialize(name, provider, version, directory, metadata_url: nil, hook: nil)
61
63
  @name = name
62
64
  @version = version
63
65
  @provider = provider
64
66
  @directory = directory
65
- @metadata_url = opts[:metadata_url]
67
+ @metadata_url = metadata_url
68
+ @hook = hook
66
69
 
67
70
  metadata_file = directory.join("metadata.json")
68
71
  raise Errors::BoxMetadataFileNotFound, name: @name if !metadata_file.file?
@@ -120,7 +123,7 @@ module Vagrant
120
123
  #
121
124
  # @param [Hash] download_options Options to pass to the downloader.
122
125
  # @return [BoxMetadata]
123
- def load_metadata(**download_options)
126
+ def load_metadata(download_options={})
124
127
  tf = Tempfile.new("vagrant-load-metadata")
125
128
  tf.close
126
129
 
@@ -132,7 +135,11 @@ module Vagrant
132
135
  end
133
136
 
134
137
  opts = { headers: ["Accept: application/json"] }.merge(download_options)
135
- Util::Downloader.new(url, tf.path, **opts).download!
138
+ d = Util::Downloader.new(url, tf.path, opts)
139
+ if @hook
140
+ @hook.call(:authenticate_box_downloader, downloader: d)
141
+ end
142
+ d.download!
136
143
  BoxMetadata.new(File.open(tf.path, "r"))
137
144
  rescue Errors::DownloaderError => e
138
145
  raise Errors::BoxMetadataDownloadError,
@@ -325,7 +325,7 @@ module Vagrant
325
325
 
326
326
  return Box.new(
327
327
  name, provider, version_dir_map[v.to_s], provider_dir,
328
- metadata_url: metadata_url,
328
+ metadata_url: metadata_url, hook: @hook
329
329
  )
330
330
  end
331
331
  end
@@ -68,11 +68,25 @@ module Vagrant
68
68
 
69
69
  # Returns all the versions supported by this metadata. These
70
70
  # versions are sorted so the last element of the list is the
71
- # latest version.
71
+ # latest version. Optionally filter versions by a matching
72
+ # provider.
72
73
  #
73
74
  # @return[Array<String>]
74
- def versions
75
- @version_map.keys.sort.map(&:to_s)
75
+ def versions(**opts)
76
+ provider = nil
77
+ provider = opts[:provider].to_sym if opts[:provider]
78
+
79
+ if provider
80
+ @version_map.select do |version, raw|
81
+ if raw["providers"]
82
+ raw["providers"].detect do |p|
83
+ p["name"].to_sym == provider
84
+ end
85
+ end
86
+ end.keys.sort.map(&:to_s)
87
+ else
88
+ @version_map.keys.sort.map(&:to_s)
89
+ end
76
90
  end
77
91
 
78
92
  # Represents a single version within the metadata.
@@ -18,6 +18,155 @@ module Vagrant
18
18
  # Bundler as a way to properly resolve all dependencies of Vagrant and
19
19
  # all Vagrant-installed plugins.
20
20
  class Bundler
21
+ class SolutionFile
22
+ # @return [Pathname] path to plugin file
23
+ attr_reader :plugin_file
24
+ # @return [Pathname] path to solution file
25
+ attr_reader :solution_file
26
+ # @return [Array<Gem::Resolver::DependencyRequest>] list of required dependencies
27
+ attr_reader :dependency_list
28
+
29
+ # @param [Pathname] plugin_file Path to plugin file
30
+ # @param [Pathname] solution_file Custom path to solution file
31
+ def initialize(plugin_file:, solution_file: nil)
32
+ @logger = Log4r::Logger.new("vagrant::bundler::solution_file")
33
+ @plugin_file = Pathname.new(plugin_file.to_s)
34
+ if solution_file
35
+ @solution_file = Pathname.new(solution_file.to_s)
36
+ else
37
+ @solution_file = Pathname.new(@plugin_file.to_s + ".sol")
38
+ end
39
+ @valid = false
40
+ @dependency_list = [].freeze
41
+ @logger.debug("new solution file instance plugin_file=#{plugin_file} " \
42
+ "solution_file=#{solution_file}")
43
+ load
44
+ end
45
+
46
+ # Set the list of dependencies for this solution
47
+ #
48
+ # @param [Array<Gem::Dependency>] dependency_list List of dependencies for the solution
49
+ # @return [Array<Gem::Resolver::DependencyRequest>]
50
+ def dependency_list=(dependency_list)
51
+ Array(dependency_list).each do |d|
52
+ if !d.is_a?(Gem::Dependency)
53
+ raise TypeError, "Expected `Gem::Dependency` but received `#{d.class}`"
54
+ end
55
+ end
56
+ @dependency_list = dependency_list.map do |d|
57
+ Gem::Resolver::DependencyRequest.new(d, nil).freeze
58
+ end.freeze
59
+ end
60
+
61
+ # @return [Boolean] contained solution is valid
62
+ def valid?
63
+ @valid
64
+ end
65
+
66
+ # @return [FalseClass] invalidate this solution file
67
+ def invalidate!
68
+ @valid = false
69
+ @logger.debug("manually invalidating solution file #{self}")
70
+ @valid
71
+ end
72
+
73
+ # Delete the solution file
74
+ #
75
+ # @return [Boolean] true if file was deleted
76
+ def delete!
77
+ if !solution_file.exist?
78
+ @logger.debug("solution file does not exist. nothing to delete.")
79
+ return false
80
+ end
81
+ @logger.debug("deleting solution file - #{solution_file}")
82
+ solution_file.delete
83
+ true
84
+ end
85
+
86
+ # Store the solution file
87
+ def store!
88
+ if !plugin_file.exist?
89
+ @logger.debug("plugin file does not exist, not storing solution")
90
+ return
91
+ end
92
+ if !solution_file.dirname.exist?
93
+ @logger.debug("creating directory for solution file: #{solution_file.dirname}")
94
+ solution_file.dirname.mkpath
95
+ end
96
+ @logger.debug("writing solution file contents to disk")
97
+ solution_file.write({
98
+ dependencies: dependency_list.map { |d|
99
+ [d.dependency.name, d.dependency.requirements_list]
100
+ },
101
+ checksum: plugin_file_checksum,
102
+ vagrant_version: Vagrant::VERSION
103
+ }.to_json)
104
+ @valid = true
105
+ end
106
+
107
+ def to_s # :nodoc:
108
+ "<Vagrant::Bundler::SolutionFile:#{plugin_file}:" \
109
+ "#{solution_file}:#{valid? ? "valid" : "invalid"}>"
110
+ end
111
+
112
+ protected
113
+
114
+ # Load the solution file for the plugin path provided
115
+ # if it exists. Validate solution is still applicable
116
+ # before injecting dependencies.
117
+ def load
118
+ if !plugin_file.exist? || !solution_file.exist?
119
+ @logger.debug("missing file so skipping loading")
120
+ return
121
+ end
122
+ solution = read_solution || return
123
+ return if !valid_solution?(
124
+ checksum: solution[:checksum],
125
+ version: solution[:vagrant_version]
126
+ )
127
+ @logger.debug("loading solution dependency list")
128
+ @dependency_list = Array(solution[:dependencies]).map do |name, requirements|
129
+ gd = Gem::Dependency.new(name, requirements)
130
+ Gem::Resolver::DependencyRequest.new(gd, nil).freeze
131
+ end.freeze
132
+ @logger.debug("solution dependency list: #{dependency_list}")
133
+ @valid = true
134
+ end
135
+
136
+ # Validate the given checksum matches the plugin file
137
+ # checksum
138
+ #
139
+ # @param [String] checksum Checksum value to validate
140
+ # @return [Boolean]
141
+ def valid_solution?(checksum:, version:)
142
+ file_checksum = plugin_file_checksum
143
+ @logger.debug("solution validation check CHECKSUM #{file_checksum} <-> #{checksum}" \
144
+ " VERSION #{Vagrant::VERSION} <-> #{version}")
145
+ plugin_file_checksum == checksum &&
146
+ Vagrant::VERSION == version
147
+ end
148
+
149
+ # @return [String] checksum of plugin file
150
+ def plugin_file_checksum
151
+ digest = Digest::SHA256.new
152
+ digest.file(plugin_file.to_s)
153
+ digest.hexdigest
154
+ end
155
+
156
+ # Read contents of solution file and parse
157
+ #
158
+ # @return [Hash]
159
+ def read_solution
160
+ @logger.debug("reading solution file - #{solution_file}")
161
+ begin
162
+ hash = JSON.load(solution_file.read)
163
+ Vagrant::Util::HashWithIndifferentAccess.new(hash)
164
+ rescue => err
165
+ @logger.warn("failed to load solution file, ignoring (error: #{err})")
166
+ nil
167
+ end
168
+ end
169
+ end
21
170
 
22
171
  # Location of HashiCorp gem repository
23
172
  HASHICORP_GEMSTORE = "https://gems.hashicorp.com/".freeze
@@ -34,26 +183,16 @@ module Vagrant
34
183
 
35
184
  # @return [Pathname] Global plugin path
36
185
  attr_reader :plugin_gem_path
186
+ # @return [Pathname] Global plugin solution set path
187
+ attr_reader :plugin_solution_path
37
188
  # @return [Pathname] Vagrant environment specific plugin path
38
189
  attr_reader :env_plugin_gem_path
190
+ # @return [Pathname] Vagrant environment data path
191
+ attr_reader :environment_data_path
39
192
 
40
193
  def initialize
41
194
  @plugin_gem_path = Vagrant.user_data_path.join("gems", RUBY_VERSION).freeze
42
195
  @logger = Log4r::Logger.new("vagrant::bundler")
43
-
44
- # TODO: Remove fix when https://github.com/rubygems/rubygems/pull/2735
45
- # gets merged and released
46
- #
47
- # Because of a rubygems bug, we need to set the gemrc file path
48
- # through this method rather than relying on the environment varible
49
- # GEMRC. On windows, that path gets split on `:`: and `;`, which means
50
- # the drive letter gets treated as its own path. If that path exists locally,
51
- # (like having a random folder called `c` where the library was invoked),
52
- # it fails thinking the folder `c` is a gemrc file.
53
- gemrc_val = ENV["GEMRC"]
54
- ENV["GEMRC"] = ""
55
- Gem.configuration = Gem::ConfigFile.new(["--config-file", gemrc_val])
56
- ENV["GEMRC"] = gemrc_val
57
196
  end
58
197
 
59
198
  # Enable Vagrant environment specific plugins at given data path
@@ -61,12 +200,39 @@ module Vagrant
61
200
  # @param [Pathname] Path to Vagrant::Environment data directory
62
201
  # @return [Pathname] Path to environment specific gem directory
63
202
  def environment_path=(env_data_path)
203
+ if !env_data_path.is_a?(Pathname)
204
+ raise TypeError, "Expected `Pathname` but received `#{env_data_path.class}`"
205
+ end
64
206
  @env_plugin_gem_path = env_data_path.join("plugins", "gems", RUBY_VERSION).freeze
207
+ @environment_data_path = env_data_path
208
+ end
209
+
210
+ # Use the given options to create a solution file instance
211
+ # for use during initialization. When a Vagrant environment
212
+ # is in use, solution files will be stored within the environment's
213
+ # data directory. This is because the solution for loading global
214
+ # plugins is dependent on any solution generated for local plugins.
215
+ # When no Vagrant environment is in use (running Vagrant without a
216
+ # Vagrantfile), the Vagrant user data path will be used for solution
217
+ # storage since only the global plugins will be used.
218
+ #
219
+ # @param [Hash] opts Options passed to #init!
220
+ # @return [SolutionFile]
221
+ def load_solution_file(opts={})
222
+ return if !opts[:local] && !opts[:global]
223
+ return if opts[:local] && opts[:global]
224
+ return if opts[:local] && environment_data_path.nil?
225
+ solution_path = (environment_data_path || Vagrant.user_data_path) + "bundler"
226
+ solution_path += opts[:local] ? "local.sol" : "global.sol"
227
+ SolutionFile.new(
228
+ plugin_file: opts[:local] || opts[:global],
229
+ solution_file: solution_path
230
+ )
65
231
  end
66
232
 
67
233
  # Initializes Bundler and the various gem paths so that we can begin
68
234
  # loading gems.
69
- def init!(plugins, repair=false)
235
+ def init!(plugins, repair=false, **opts)
70
236
  if !@initial_specifications
71
237
  @initial_specifications = Gem::Specification.find_all{true}
72
238
  else
@@ -74,45 +240,84 @@ module Vagrant
74
240
  Gem::Specification.reset
75
241
  end
76
242
 
77
- # Add HashiCorp RubyGems source
78
- if !Gem.sources.include?(HASHICORP_GEMSTORE)
79
- sources = [HASHICORP_GEMSTORE] + Gem.sources.sources
80
- Gem.sources.replace(sources)
243
+ solution_file = load_solution_file(opts)
244
+ @logger.debug("solution file in use for init: #{solution_file}")
245
+
246
+ solution = nil
247
+ composed_set = generate_vagrant_set
248
+
249
+ # Force the composed set to allow prereleases
250
+ if Vagrant.allow_prerelease_dependencies?
251
+ @logger.debug("enabling prerelease dependency matching due to user request")
252
+ composed_set.prerelease = true
81
253
  end
82
254
 
83
- # Generate dependencies for all registered plugins
84
- plugin_deps = plugins.map do |name, info|
85
- Gem::Dependency.new(name, info['installed_gem_version'].to_s.empty? ? '> 0' : info['installed_gem_version'])
255
+ if solution_file&.valid?
256
+ @logger.debug("loading cached solution set")
257
+ solution = solution_file.dependency_list.map do |dep|
258
+ spec = composed_set.find_all(dep).first
259
+ if !spec
260
+ @logger.warn("failed to locate specification for dependency - #{dep}")
261
+ @logger.warn("invalidating solution file - #{solution_file}")
262
+ solution_file.invalidate!
263
+ break
264
+ end
265
+ dep_r = Gem::Resolver::DependencyRequest.new(dep, nil)
266
+ Gem::Resolver::ActivationRequest.new(spec, dep_r)
267
+ end
86
268
  end
87
269
 
88
- @logger.debug("Current generated plugin dependency list: #{plugin_deps}")
270
+ if !solution_file&.valid?
271
+ @logger.debug("generating solution set for configured plugins")
272
+ # Add HashiCorp RubyGems source
273
+ if !Gem.sources.include?(HASHICORP_GEMSTORE)
274
+ sources = [HASHICORP_GEMSTORE] + Gem.sources.sources
275
+ Gem.sources.replace(sources)
276
+ end
277
+
278
+ # Generate dependencies for all registered plugins
279
+ plugin_deps = plugins.map do |name, info|
280
+ Gem::Dependency.new(name, info['installed_gem_version'].to_s.empty? ? '> 0' : info['installed_gem_version'])
281
+ end
89
282
 
90
- # Load dependencies into a request set for resolution
91
- request_set = Gem::RequestSet.new(*plugin_deps)
92
- # Never allow dependencies to be remotely satisfied during init
93
- request_set.remote = false
283
+ @logger.debug("Current generated plugin dependency list: #{plugin_deps}")
94
284
 
95
- repair_result = nil
96
- begin
97
- # Compose set for resolution
98
- composed_set = generate_vagrant_set
99
- # Resolve the request set to ensure proper activation order
100
- solution = request_set.resolve(composed_set)
101
- rescue Gem::UnsatisfiableDependencyError => failure
102
- if repair
103
- raise failure if @init_retried
104
- @logger.debug("Resolution failed but attempting to repair. Failure: #{failure}")
105
- install(plugins)
106
- @init_retried = true
107
- retry
108
- else
109
- raise
285
+ # Load dependencies into a request set for resolution
286
+ request_set = Gem::RequestSet.new(*plugin_deps)
287
+ # Never allow dependencies to be remotely satisfied during init
288
+ request_set.remote = false
289
+
290
+ repair_result = nil
291
+ begin
292
+ @logger.debug("resolving solution from available specification set")
293
+ # Resolve the request set to ensure proper activation order
294
+ solution = request_set.resolve(composed_set)
295
+ @logger.debug("solution set for configured plugins has been resolved")
296
+ rescue Gem::UnsatisfiableDependencyError => failure
297
+ if repair
298
+ raise failure if @init_retried
299
+ @logger.debug("Resolution failed but attempting to repair. Failure: #{failure}")
300
+ install(plugins)
301
+ @init_retried = true
302
+ retry
303
+ else
304
+ raise
305
+ end
110
306
  end
111
307
  end
112
308
 
113
309
  # Activate the gems
310
+ @logger.debug("activating solution set")
114
311
  activate_solution(solution)
115
312
 
313
+ if solution_file && !solution_file.valid?
314
+ solution_file.dependency_list = solution.map do |activation|
315
+ activation.request.dependency
316
+ end
317
+ solution_file.store!
318
+ @logger.debug("solution set stored to - #{solution_file}")
319
+ end
320
+
116
321
  full_vagrant_spec_list = @initial_specifications +
117
322
  solution.map(&:full_spec)
118
323
 
@@ -287,7 +492,7 @@ module Vagrant
287
492
  if update[:gems] == true || (update[:gems].respond_to?(:include?) && update[:gems].include?(name))
288
493
  if Gem::Requirement.new(gem_version).exact?
289
494
  gem_version = "> 0"
290
- @logger.debug("Detected exact version match for `#{name}` plugin update. Reset to loose constraint #{gem_version.inspect}.")
495
+ @logger.debug("Detected exact version match for `#{name}` plugin update. Reset to loosen constraint #{gem_version.inspect}.")
291
496
  end
292
497
  skips << name
293
498
  end
@@ -363,17 +568,25 @@ module Vagrant
363
568
  generate_builtin_set(system_plugins),
364
569
  generate_plugin_set(skips)
365
570
  )
571
+
572
+ if Vagrant.allow_prerelease_dependencies?
573
+ @logger.debug("enabling prerelease dependency matching based on user request")
574
+ request_set.prerelease = true
575
+ installer_set.prerelease = true
576
+ end
577
+
366
578
  @logger.debug("Generating solution set for installation.")
367
579
 
368
580
  # Generate the required solution set for new plugins
369
581
  solution = request_set.resolve(installer_set)
582
+
370
583
  activate_solution(solution)
371
584
 
372
585
  # Remove gems which are already installed
373
- request_set.sorted_requests.delete_if do |activation_req|
374
- rs_spec = activation_req.spec
375
- if vagrant_internal_specs.detect{|ispec| ispec.name == rs_spec.name && ispec.version == rs_spec.version }
376
- @logger.debug("Removing activation request from install. Already installed. (#{rs_spec.spec.full_name})")
586
+ request_set.sorted_requests.delete_if do |act_req|
587
+ rs = act_req.spec
588
+ if vagrant_internal_specs.detect{ |i| i.name == rs.name && i.version == rs.version }
589
+ @logger.debug("Removing activation request from install. Already installed. (#{rs.spec.full_name})")
377
590
  true
378
591
  end
379
592
  end
@@ -387,9 +600,11 @@ module Vagrant
387
600
  install_path = extra[:env_local] ? env_plugin_gem_path : plugin_gem_path
388
601
  result = request_set.install_into(install_path.to_s, true,
389
602
  ignore_dependencies: true,
390
- prerelease: Vagrant.prerelease?,
391
- wrappers: true
603
+ prerelease: Vagrant.prerelease? || Vagrant.allow_prerelease_dependencies?,
604
+ wrappers: true,
605
+ document: []
392
606
  )
607
+
393
608
  result = result.map(&:full_spec)
394
609
  result.each do |spec|
395
610
  existing_paths = $LOAD_PATH.find_all{|s| s.include?(spec.full_name) }
@@ -421,15 +636,30 @@ module Vagrant
421
636
  def vagrant_internal_specs
422
637
  # activate any dependencies up front so we can always
423
638
  # pin them when resolving
424
- Gem::Specification.find { |s| s.name == "vagrant-unbundled" && s.activated? }.
425
- runtime_dependencies.each { |d| gem d.name, *d.requirement.as_list }
639
+ self_spec = Gem::Specification.find { |s| s.name == "vagrant-unbundled" && s.activated? }
640
+ if !self_spec
641
+ @logger.warn("Failed to locate activated vagrant specification. Activating...")
642
+ self_spec = Gem::Specification.find { |s| s.name == "vagrant-unbundled" }
643
+ if !self_spec
644
+ @logger.error("Failed to locate Vagrant RubyGem specification")
645
+ raise Vagrant::Errors::SourceSpecNotFound
646
+ end
647
+ self_spec.activate
648
+ @logger.info("Activated vagrant specification version - #{self_spec.version}")
649
+ end
650
+ self_spec.runtime_dependencies.each { |d| gem d.name, *d.requirement.as_list }
426
651
  # discover all the gems we have available
427
652
  list = {}
428
- directories = [Gem::Specification.default_specifications_dir]
653
+ if Gem.respond_to?(:default_specifications_dir)
654
+ spec_dir = Gem.default_specifications_dir
655
+ else
656
+ spec_dir = Gem::Specification.default_specifications_dir
657
+ end
658
+ directories = [spec_dir]
429
659
  Gem::Specification.find_all{true}.each do |spec|
430
660
  list[spec.full_name] = spec
431
661
  end
432
- if(!defined?(::Bundler))
662
+ if(!Object.const_defined?(:Bundler))
433
663
  directories += Gem::Specification.dirs.find_all do |path|
434
664
  !path.start_with?(Gem.user_dir)
435
665
  end
@@ -528,7 +758,6 @@ module Vagrant
528
758
  request.name == matcher["gem_name"]
529
759
  end
530
760
  if desired_activation_request && !desired_activation_request.full_spec.activated?
531
- activation_request = desired_activation_request
532
761
  @logger.warn("Found misordered activation request for #{desired_activation_request.full_name}. Moving to solution HEAD.")
533
762
  solution.delete(desired_activation_request)
534
763
  solution.unshift(desired_activation_request)
@@ -600,12 +829,22 @@ module Vagrant
600
829
  end
601
830
 
602
831
  def find_all(req)
603
- @specs.select do |spec|
604
- allow_prerelease = spec.name == "vagrant-unbundled" && Vagrant.prerelease?
605
- req.match?(spec, allow_prerelease)
832
+ r = @specs.select do |spec|
833
+ # When matching requests against builtin specs, we _always_ enable
834
+ # prerelease matching since any prerelease that's found in this
835
+ # set has been added explicitly and should be available for all
836
+ # plugins to resolve against. This includes Vagrant itself since
837
+ # it is considered a prerelease when in development mode
838
+ req.match?(spec, true)
606
839
  end.map do |spec|
607
840
  Gem::Resolver::InstalledSpecification.new(self, spec)
608
841
  end
842
+ # If any of the results are a prerelease, we need to mark the request
843
+ # to allow prereleases so the solution can be properly fulfilled
844
+ if r.any? { |x| x.version.prerelease? }
845
+ req.dependency.prerelease = true
846
+ end
847
+ r
609
848
  end
610
849
  end
611
850
 
@@ -639,7 +878,7 @@ module Vagrant
639
878
  # DependencyRequest +req+.
640
879
  def find_all(req)
641
880
  @specs.values.flatten.select do |spec|
642
- req.match?(spec)
881
+ req.match?(spec, prerelease)
643
882
  end.map do |spec|
644
883
  source = Gem::Source::Vendor.new(@directories[spec])
645
884
  Gem::Resolver::VendorSpecification.new(self, spec, source)
@@ -649,7 +888,7 @@ module Vagrant
649
888
  ##
650
889
  # Loads a spec with the given +name+. +version+, +platform+ and +source+ are
651
890
  # ignored.
652
- def load_spec (name, version, platform, source)
891
+ def load_spec(name, version, platform, source)
653
892
  version = Gem::Version.new(version) if !version.is_a?(Gem::Version)
654
893
  @specs.fetch(name, []).detect{|s| s.name == name && s.version == version}
655
894
  end