vagrant-unbundled 2.2.7.0 → 2.2.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (282) hide show
  1. checksums.yaml +4 -4
  2. data/.hashibot.hcl +2 -0
  3. data/CHANGELOG.md +228 -0
  4. data/Gemfile +1 -1
  5. data/README.md +9 -51
  6. data/RELEASE.md +1 -1
  7. data/bin/vagrant +50 -1
  8. data/contrib/README.md +1 -0
  9. data/contrib/sudoers/linux-suse +2 -2
  10. data/contrib/zsh/_vagrant +738 -0
  11. data/contrib/zsh/generate_zsh_completion.rb +165 -0
  12. data/lib/vagrant.rb +28 -5
  13. data/lib/vagrant/action.rb +7 -0
  14. data/lib/vagrant/action/builder.rb +184 -38
  15. data/lib/vagrant/action/builtin/box_add.rb +24 -8
  16. data/lib/vagrant/action/builtin/box_check_outdated.rb +2 -1
  17. data/lib/vagrant/action/builtin/cleanup_disks.rb +56 -0
  18. data/lib/vagrant/action/builtin/cloud_init_setup.rb +122 -0
  19. data/lib/vagrant/action/builtin/cloud_init_wait.rb +30 -0
  20. data/lib/vagrant/action/builtin/delayed.rb +26 -0
  21. data/lib/vagrant/action/builtin/disk.rb +14 -1
  22. data/lib/vagrant/action/builtin/handle_box.rb +3 -1
  23. data/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb +28 -9
  24. data/lib/vagrant/action/builtin/has_provisioner.rb +36 -0
  25. data/lib/vagrant/action/builtin/mixin_provisioners.rb +1 -0
  26. data/lib/vagrant/action/builtin/mixin_synced_folders.rb +20 -21
  27. data/lib/vagrant/action/builtin/set_hostname.rb +5 -1
  28. data/lib/vagrant/action/builtin/synced_folders.rb +16 -0
  29. data/lib/vagrant/action/builtin/trigger.rb +37 -0
  30. data/lib/vagrant/action/hook.rb +76 -23
  31. data/lib/vagrant/action/runner.rb +12 -27
  32. data/lib/vagrant/action/warden.rb +28 -31
  33. data/lib/vagrant/box.rb +11 -4
  34. data/lib/vagrant/box_collection.rb +1 -1
  35. data/lib/vagrant/bundler.rb +310 -61
  36. data/lib/vagrant/cli.rb +4 -2
  37. data/lib/vagrant/environment.rb +1 -0
  38. data/lib/vagrant/errors.rb +69 -1
  39. data/lib/vagrant/machine.rb +64 -11
  40. data/lib/vagrant/machine_index.rb +28 -1
  41. data/lib/vagrant/patches/net-ssh.rb +186 -0
  42. data/lib/vagrant/plugin/manager.rb +45 -16
  43. data/lib/vagrant/plugin/v2/command.rb +7 -2
  44. data/lib/vagrant/plugin/v2/components.rb +6 -0
  45. data/lib/vagrant/plugin/v2/manager.rb +67 -0
  46. data/lib/vagrant/plugin/v2/plugin.rb +13 -0
  47. data/lib/vagrant/plugin/v2/synced_folder.rb +50 -0
  48. data/lib/vagrant/plugin/v2/trigger.rb +64 -25
  49. data/lib/vagrant/shared_helpers.rb +36 -0
  50. data/lib/vagrant/ui.rb +43 -2
  51. data/lib/vagrant/util.rb +2 -0
  52. data/lib/vagrant/util/ansi_escape_code_remover.rb +1 -1
  53. data/lib/vagrant/util/caps.rb +48 -0
  54. data/lib/vagrant/util/credential_scrubber.rb +1 -1
  55. data/lib/vagrant/util/curl_helper.rb +12 -8
  56. data/lib/vagrant/util/directory.rb +19 -0
  57. data/lib/vagrant/util/downloader.rb +10 -5
  58. data/lib/vagrant/util/guest_hosts.rb +68 -0
  59. data/lib/vagrant/util/guest_inspection.rb +9 -1
  60. data/lib/vagrant/util/install_cli_autocomplete.rb +118 -0
  61. data/lib/vagrant/util/io.rb +7 -27
  62. data/lib/vagrant/util/ipv4_interfaces.rb +15 -0
  63. data/lib/vagrant/util/is_port_open.rb +8 -19
  64. data/lib/vagrant/util/map_command_options.rb +33 -0
  65. data/lib/vagrant/util/mime.rb +92 -0
  66. data/lib/vagrant/util/network_ip.rb +11 -1
  67. data/lib/vagrant/util/numeric.rb +28 -0
  68. data/lib/vagrant/util/platform.rb +10 -2
  69. data/lib/vagrant/util/powershell.rb +31 -15
  70. data/lib/vagrant/util/subprocess.rb +9 -1
  71. data/lib/vagrant/util/template_renderer.rb +2 -2
  72. data/lib/vagrant/util/uploader.rb +7 -4
  73. data/lib/vagrant/vagrantfile.rb +2 -2
  74. data/plugins/commands/autocomplete/command/install.rb +49 -0
  75. data/plugins/commands/autocomplete/command/root.rb +64 -0
  76. data/plugins/commands/autocomplete/plugin.rb +18 -0
  77. data/plugins/commands/cap/command.rb +5 -1
  78. data/plugins/commands/cloud/auth/login.rb +20 -23
  79. data/plugins/commands/cloud/auth/logout.rb +2 -10
  80. data/plugins/commands/cloud/auth/middleware/add_authentication.rb +60 -31
  81. data/plugins/commands/cloud/auth/middleware/add_downloader_authentication.rb +64 -0
  82. data/plugins/commands/cloud/auth/whoami.rb +18 -20
  83. data/plugins/commands/cloud/box/create.rb +33 -29
  84. data/plugins/commands/cloud/box/delete.rb +30 -24
  85. data/plugins/commands/cloud/box/show.rb +41 -31
  86. data/plugins/commands/cloud/box/update.rb +34 -26
  87. data/plugins/commands/cloud/client/client.rb +55 -79
  88. data/plugins/commands/cloud/list.rb +3 -4
  89. data/plugins/commands/cloud/locales/en.yml +15 -11
  90. data/plugins/commands/cloud/plugin.rb +10 -0
  91. data/plugins/commands/cloud/provider/create.rb +38 -28
  92. data/plugins/commands/cloud/provider/delete.rb +39 -29
  93. data/plugins/commands/cloud/provider/update.rb +37 -28
  94. data/plugins/commands/cloud/provider/upload.rb +53 -33
  95. data/plugins/commands/cloud/publish.rb +193 -106
  96. data/plugins/commands/cloud/search.rb +34 -21
  97. data/plugins/commands/cloud/util.rb +273 -161
  98. data/plugins/commands/cloud/version/create.rb +33 -28
  99. data/plugins/commands/cloud/version/delete.rb +35 -28
  100. data/plugins/commands/cloud/version/release.rb +35 -29
  101. data/plugins/commands/cloud/version/revoke.rb +36 -29
  102. data/plugins/commands/cloud/version/update.rb +29 -25
  103. data/plugins/commands/destroy/command.rb +7 -7
  104. data/plugins/commands/login/plugin.rb +0 -13
  105. data/plugins/commands/ssh_config/command.rb +1 -1
  106. data/plugins/communicators/ssh/communicator.rb +25 -24
  107. data/plugins/communicators/winrm/config.rb +1 -1
  108. data/plugins/communicators/winrm/helper.rb +1 -1
  109. data/plugins/communicators/winrm/shell.rb +1 -1
  110. data/plugins/communicators/winssh/communicator.rb +126 -38
  111. data/plugins/communicators/winssh/config.rb +3 -7
  112. data/plugins/guests/alpine/cap/change_host_name.rb +10 -11
  113. data/plugins/guests/alpine/cap/configure_networks.rb +1 -1
  114. data/plugins/guests/alt/cap/change_host_name.rb +40 -53
  115. data/plugins/guests/arch/cap/change_host_name.rb +5 -14
  116. data/plugins/guests/arch/cap/configure_networks.rb +27 -10
  117. data/plugins/guests/arch/cap/smb.rb +1 -1
  118. data/plugins/guests/atomic/cap/change_host_name.rb +5 -14
  119. data/plugins/guests/centos/cap/flavor.rb +24 -0
  120. data/plugins/guests/centos/guest.rb +9 -0
  121. data/plugins/guests/centos/plugin.rb +20 -0
  122. data/plugins/guests/darwin/cap/change_host_name.rb +10 -6
  123. data/plugins/guests/darwin/cap/darwin_version.rb +40 -0
  124. data/plugins/guests/darwin/cap/mount_smb_shared_folder.rb +1 -1
  125. data/plugins/guests/darwin/cap/mount_vmware_shared_folder.rb +33 -10
  126. data/plugins/guests/darwin/plugin.rb +15 -0
  127. data/plugins/guests/debian/cap/change_host_name.rb +12 -11
  128. data/plugins/guests/debian/cap/configure_networks.rb +14 -6
  129. data/plugins/guests/esxi/cap/public_key.rb +3 -1
  130. data/plugins/guests/fedora/guest.rb +4 -4
  131. data/plugins/guests/freebsd/cap/change_host_name.rb +10 -6
  132. data/plugins/guests/gentoo/cap/change_host_name.rb +14 -22
  133. data/plugins/guests/haiku/cap/rsync.rb +19 -0
  134. data/plugins/guests/haiku/plugin.rb +15 -0
  135. data/plugins/guests/linux/cap/change_host_name.rb +46 -0
  136. data/plugins/guests/linux/cap/halt.rb +9 -1
  137. data/plugins/guests/linux/cap/mount_smb_shared_folder.rb +25 -34
  138. data/plugins/guests/linux/cap/mount_virtualbox_shared_folder.rb +10 -11
  139. data/plugins/guests/linux/cap/persist_mount_shared_folder.rb +74 -0
  140. data/plugins/guests/linux/cap/reboot.rb +36 -7
  141. data/plugins/guests/linux/plugin.rb +10 -0
  142. data/plugins/guests/omnios/cap/change_host_name.rb +10 -16
  143. data/plugins/guests/openbsd/cap/change_host_name.rb +10 -6
  144. data/plugins/guests/openwrt/cap/change_host_name.rb +19 -0
  145. data/plugins/guests/openwrt/cap/halt.rb +16 -0
  146. data/plugins/guests/openwrt/cap/insert_public_key.rb +20 -0
  147. data/plugins/guests/openwrt/cap/remove_public_key.rb +22 -0
  148. data/plugins/guests/openwrt/cap/rsync.rb +35 -0
  149. data/plugins/guests/openwrt/guest.rb +23 -0
  150. data/plugins/guests/openwrt/plugin.rb +61 -0
  151. data/plugins/guests/photon/cap/change_host_name.rb +9 -15
  152. data/plugins/guests/pld/cap/change_host_name.rb +11 -17
  153. data/plugins/guests/redhat/cap/change_host_name.rb +14 -5
  154. data/plugins/guests/redhat/cap/flavor.rb +3 -1
  155. data/plugins/guests/redhat/cap/smb.rb +20 -0
  156. data/plugins/guests/redhat/plugin.rb +5 -0
  157. data/plugins/guests/slackware/cap/change_host_name.rb +11 -17
  158. data/plugins/guests/solaris11/plugin.rb +5 -0
  159. data/plugins/guests/suse/cap/change_host_name.rb +31 -9
  160. data/plugins/guests/windows/cap/public_key.rb +3 -3
  161. data/plugins/guests/windows/cap/reboot.rb +10 -5
  162. data/plugins/hosts/darwin/cap/fs_iso.rb +49 -0
  163. data/plugins/hosts/darwin/plugin.rb +10 -0
  164. data/plugins/hosts/linux/cap/fs_iso.rb +49 -0
  165. data/plugins/hosts/linux/cap/nfs.rb +1 -0
  166. data/plugins/hosts/linux/cap/rdp.rb +1 -1
  167. data/plugins/hosts/linux/plugin.rb +10 -0
  168. data/plugins/hosts/windows/cap/fs_iso.rb +48 -0
  169. data/plugins/hosts/windows/cap/rdp.rb +1 -1
  170. data/plugins/hosts/windows/plugin.rb +15 -0
  171. data/plugins/kernel_v2/config/cloud_init.rb +133 -0
  172. data/plugins/kernel_v2/config/disk.rb +67 -14
  173. data/plugins/kernel_v2/config/ssh_connect.rb +24 -0
  174. data/plugins/kernel_v2/config/vm.rb +155 -21
  175. data/plugins/kernel_v2/config/vm_provisioner.rb +13 -2
  176. data/plugins/kernel_v2/config/vm_trigger.rb +6 -5
  177. data/plugins/providers/docker/action.rb +8 -17
  178. data/plugins/providers/docker/action/forwarded_ports.rb +2 -0
  179. data/plugins/providers/docker/action/prepare_forwarded_port_collision_params.rb +61 -0
  180. data/plugins/providers/docker/cap/has_communicator.rb +11 -0
  181. data/plugins/providers/docker/communicator.rb +1 -1
  182. data/plugins/providers/docker/driver.rb +58 -7
  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 +13 -1
  205. data/plugins/providers/virtualbox/action/export.rb +4 -2
  206. data/plugins/providers/virtualbox/action/forward_ports.rb +2 -2
  207. data/plugins/providers/virtualbox/action/import.rb +8 -4
  208. data/plugins/providers/virtualbox/action/network.rb +12 -5
  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 +40 -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 +16 -2
  218. data/plugins/providers/virtualbox/driver/version_5_0.rb +217 -2
  219. data/plugins/providers/virtualbox/driver/version_6_1.rb +23 -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 +42 -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/freebsd/ansible_install.rb +1 -1
  227. data/plugins/provisioners/ansible/plugin.rb +5 -0
  228. data/plugins/provisioners/ansible/provisioner/base.rb +1 -1
  229. data/plugins/provisioners/container/client.rb +203 -0
  230. data/plugins/provisioners/container/config.rb +83 -0
  231. data/plugins/provisioners/container/installer.rb +13 -0
  232. data/plugins/provisioners/container/plugin.rb +23 -0
  233. data/plugins/provisioners/container/provisioner.rb +28 -0
  234. data/plugins/provisioners/docker/cap/{redhat → centos}/docker_install.rb +10 -7
  235. data/plugins/provisioners/docker/cap/centos/docker_start_service.rb +24 -0
  236. data/plugins/provisioners/docker/client.rb +4 -175
  237. data/plugins/provisioners/docker/config.rb +2 -72
  238. data/plugins/provisioners/docker/installer.rb +3 -5
  239. data/plugins/provisioners/docker/plugin.rb +6 -6
  240. data/plugins/provisioners/docker/provisioner.rb +4 -10
  241. data/plugins/provisioners/podman/cap/centos/podman_install.rb +35 -0
  242. data/plugins/provisioners/podman/cap/linux/podman_installed.rb +13 -0
  243. data/plugins/provisioners/podman/cap/redhat/podman_install.rb +26 -0
  244. data/plugins/provisioners/podman/client.rb +12 -0
  245. data/plugins/provisioners/podman/config.rb +28 -0
  246. data/plugins/provisioners/podman/installer.rb +33 -0
  247. data/plugins/provisioners/podman/plugin.rb +38 -0
  248. data/plugins/provisioners/podman/provisioner.rb +52 -0
  249. data/plugins/provisioners/salt/bootstrap-salt.sh +7 -4
  250. data/plugins/provisioners/salt/provisioner.rb +4 -0
  251. data/plugins/provisioners/shell/config.rb +1 -6
  252. data/plugins/provisioners/shell/provisioner.rb +61 -26
  253. data/plugins/synced_folders/nfs/synced_folder.rb +3 -1
  254. data/plugins/synced_folders/smb/cap/default_fstab_modification.rb +11 -0
  255. data/plugins/synced_folders/smb/cap/mount_options.rb +56 -0
  256. data/plugins/synced_folders/smb/plugin.rb +20 -0
  257. data/plugins/synced_folders/smb/synced_folder.rb +2 -2
  258. data/plugins/synced_folders/unix_mount_helpers.rb +14 -0
  259. data/scripts/website_push_www.sh +1 -1
  260. data/templates/commands/init/Vagrantfile.min.erb +3 -0
  261. data/templates/guests/arch/{network_dhcp.erb → default_network/network_dhcp.erb} +0 -0
  262. data/templates/guests/arch/{network_static.erb → default_network/network_static.erb} +0 -0
  263. data/templates/guests/arch/{network_static6.erb → default_network/network_static6.erb} +0 -0
  264. data/templates/guests/arch/systemd_networkd/network_dhcp.erb +6 -0
  265. data/templates/guests/arch/systemd_networkd/network_static.erb +9 -0
  266. data/templates/guests/arch/systemd_networkd/network_static6.erb +9 -0
  267. data/templates/guests/linux/etc_fstab.erb +6 -0
  268. data/templates/guests/nixos/network.erb +5 -6
  269. data/templates/locales/en.yml +221 -5
  270. data/templates/locales/providers_docker.yml +4 -0
  271. data/templates/nfs/exports_darwin.erb +1 -1
  272. data/vagrant.gemspec +14 -20
  273. data/version.txt +1 -1
  274. metadata +5092 -8978
  275. data/lib/vagrant/action/builtin/after_trigger.rb +0 -31
  276. data/lib/vagrant/action/builtin/before_trigger.rb +0 -28
  277. data/plugins/commands/login/client.rb +0 -253
  278. data/plugins/commands/login/command.rb +0 -137
  279. data/plugins/commands/login/errors.rb +0 -24
  280. data/plugins/commands/login/locales/en.yml +0 -49
  281. data/plugins/provisioners/docker/cap/redhat/docker_start_service.rb +0 -16
  282. data/scripts/website_push_docs.sh +0 -40
data/lib/vagrant/box.rb CHANGED
@@ -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
@@ -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,19 @@ 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
192
+ # @return [Array<Gem::Specification>, nil] List of builtin specs
193
+ attr_accessor :builtin_specs
39
194
 
40
195
  def initialize
196
+ @builtin_specs = []
41
197
  @plugin_gem_path = Vagrant.user_data_path.join("gems", RUBY_VERSION).freeze
42
198
  @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
199
  end
58
200
 
59
201
  # Enable Vagrant environment specific plugins at given data path
@@ -61,12 +203,39 @@ module Vagrant
61
203
  # @param [Pathname] Path to Vagrant::Environment data directory
62
204
  # @return [Pathname] Path to environment specific gem directory
63
205
  def environment_path=(env_data_path)
206
+ if !env_data_path.is_a?(Pathname)
207
+ raise TypeError, "Expected `Pathname` but received `#{env_data_path.class}`"
208
+ end
64
209
  @env_plugin_gem_path = env_data_path.join("plugins", "gems", RUBY_VERSION).freeze
210
+ @environment_data_path = env_data_path
211
+ end
212
+
213
+ # Use the given options to create a solution file instance
214
+ # for use during initialization. When a Vagrant environment
215
+ # is in use, solution files will be stored within the environment's
216
+ # data directory. This is because the solution for loading global
217
+ # plugins is dependent on any solution generated for local plugins.
218
+ # When no Vagrant environment is in use (running Vagrant without a
219
+ # Vagrantfile), the Vagrant user data path will be used for solution
220
+ # storage since only the global plugins will be used.
221
+ #
222
+ # @param [Hash] opts Options passed to #init!
223
+ # @return [SolutionFile]
224
+ def load_solution_file(opts={})
225
+ return if !opts[:local] && !opts[:global]
226
+ return if opts[:local] && opts[:global]
227
+ return if opts[:local] && environment_data_path.nil?
228
+ solution_path = (environment_data_path || Vagrant.user_data_path) + "bundler"
229
+ solution_path += opts[:local] ? "local.sol" : "global.sol"
230
+ SolutionFile.new(
231
+ plugin_file: opts[:local] || opts[:global],
232
+ solution_file: solution_path
233
+ )
65
234
  end
66
235
 
67
236
  # Initializes Bundler and the various gem paths so that we can begin
68
237
  # loading gems.
69
- def init!(plugins, repair=false)
238
+ def init!(plugins, repair=false, **opts)
70
239
  if !@initial_specifications
71
240
  @initial_specifications = Gem::Specification.find_all{true}
72
241
  else
@@ -74,45 +243,83 @@ module Vagrant
74
243
  Gem::Specification.reset
75
244
  end
76
245
 
77
- # Add HashiCorp RubyGems source
78
- if !Gem.sources.include?(HASHICORP_GEMSTORE)
79
- sources = [HASHICORP_GEMSTORE] + Gem.sources.sources
80
- Gem.sources.replace(sources)
246
+ solution_file = load_solution_file(opts)
247
+ @logger.debug("solution file in use for init: #{solution_file}")
248
+
249
+ solution = nil
250
+ composed_set = generate_vagrant_set
251
+
252
+ # Force the composed set to allow prereleases
253
+ if Vagrant.allow_prerelease_dependencies?
254
+ @logger.debug("enabling prerelease dependency matching due to user request")
255
+ composed_set.prerelease = true
81
256
  end
82
257
 
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'])
258
+ if solution_file&.valid?
259
+ @logger.debug("loading cached solution set")
260
+ solution = solution_file.dependency_list.map do |dep|
261
+ spec = composed_set.find_all(dep).first
262
+ if !spec
263
+ @logger.warn("failed to locate specification for dependency - #{dep}")
264
+ @logger.warn("invalidating solution file - #{solution_file}")
265
+ solution_file.invalidate!
266
+ break
267
+ end
268
+ dep_r = Gem::Resolver::DependencyRequest.new(dep, nil)
269
+ Gem::Resolver::ActivationRequest.new(spec, dep_r)
270
+ end
86
271
  end
87
272
 
88
- @logger.debug("Current generated plugin dependency list: #{plugin_deps}")
273
+ if !solution_file&.valid?
274
+ @logger.debug("generating solution set for configured plugins")
275
+ # Add HashiCorp RubyGems source
276
+ if !Gem.sources.include?(HASHICORP_GEMSTORE)
277
+ sources = [HASHICORP_GEMSTORE] + Gem.sources.sources
278
+ Gem.sources.replace(sources)
279
+ end
89
280
 
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
281
+ # Generate dependencies for all registered plugins
282
+ plugin_deps = plugins.map do |name, info|
283
+ Gem::Dependency.new(name, info['installed_gem_version'].to_s.empty? ? '> 0' : info['installed_gem_version'])
284
+ end
94
285
 
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
286
+ @logger.debug("Current generated plugin dependency list: #{plugin_deps}")
287
+
288
+ # Load dependencies into a request set for resolution
289
+ request_set = Gem::RequestSet.new(*plugin_deps)
290
+ # Never allow dependencies to be remotely satisfied during init
291
+ request_set.remote = false
292
+
293
+ begin
294
+ @logger.debug("resolving solution from available specification set")
295
+ # Resolve the request set to ensure proper activation order
296
+ solution = request_set.resolve(composed_set)
297
+ @logger.debug("solution set for configured plugins has been resolved")
298
+ rescue Gem::UnsatisfiableDependencyError => failure
299
+ if repair
300
+ raise failure if @init_retried
301
+ @logger.debug("Resolution failed but attempting to repair. Failure: #{failure}")
302
+ install(plugins)
303
+ @init_retried = true
304
+ retry
305
+ else
306
+ raise
307
+ end
110
308
  end
111
309
  end
112
310
 
113
311
  # Activate the gems
312
+ @logger.debug("activating solution set")
114
313
  activate_solution(solution)
115
314
 
315
+ if solution_file && !solution_file.valid?
316
+ solution_file.dependency_list = solution.map do |activation|
317
+ activation.request.dependency
318
+ end
319
+ solution_file.store!
320
+ @logger.debug("solution set stored to - #{solution_file}")
321
+ end
322
+
116
323
  full_vagrant_spec_list = @initial_specifications +
117
324
  solution.map(&:full_spec)
118
325
 
@@ -287,7 +494,7 @@ module Vagrant
287
494
  if update[:gems] == true || (update[:gems].respond_to?(:include?) && update[:gems].include?(name))
288
495
  if Gem::Requirement.new(gem_version).exact?
289
496
  gem_version = "> 0"
290
- @logger.debug("Detected exact version match for `#{name}` plugin update. Reset to loose constraint #{gem_version.inspect}.")
497
+ @logger.debug("Detected exact version match for `#{name}` plugin update. Reset to loosen constraint #{gem_version.inspect}.")
291
498
  end
292
499
  skips << name
293
500
  end
@@ -309,6 +516,9 @@ module Vagrant
309
516
  @logger.debug("Enabling strict dependency enforcement")
310
517
  plugin_deps += vagrant_internal_specs.map do |spec|
311
518
  next if system_plugins.include?(spec.name)
519
+ # If this spec is for a default plugin included in
520
+ # the ruby stdlib, ignore it
521
+ next if spec.default_gem?
312
522
  # If we are not running within the installer and
313
523
  # we are not within a bundler environment then we
314
524
  # only want activated specs
@@ -363,17 +573,25 @@ module Vagrant
363
573
  generate_builtin_set(system_plugins),
364
574
  generate_plugin_set(skips)
365
575
  )
576
+
577
+ if Vagrant.allow_prerelease_dependencies?
578
+ @logger.debug("enabling prerelease dependency matching based on user request")
579
+ request_set.prerelease = true
580
+ installer_set.prerelease = true
581
+ end
582
+
366
583
  @logger.debug("Generating solution set for installation.")
367
584
 
368
585
  # Generate the required solution set for new plugins
369
586
  solution = request_set.resolve(installer_set)
587
+
370
588
  activate_solution(solution)
371
589
 
372
590
  # 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})")
591
+ request_set.sorted_requests.delete_if do |act_req|
592
+ rs = act_req.spec
593
+ if vagrant_internal_specs.detect{ |i| i.name == rs.name && i.version == rs.version }
594
+ @logger.debug("Removing activation request from install. Already installed. (#{rs.spec.full_name})")
377
595
  true
378
596
  end
379
597
  end
@@ -387,9 +605,11 @@ module Vagrant
387
605
  install_path = extra[:env_local] ? env_plugin_gem_path : plugin_gem_path
388
606
  result = request_set.install_into(install_path.to_s, true,
389
607
  ignore_dependencies: true,
390
- prerelease: Vagrant.prerelease?,
391
- wrappers: true
608
+ prerelease: Vagrant.prerelease? || Vagrant.allow_prerelease_dependencies?,
609
+ wrappers: true,
610
+ document: []
392
611
  )
612
+
393
613
  result = result.map(&:full_spec)
394
614
  result.each do |spec|
395
615
  existing_paths = $LOAD_PATH.find_all{|s| s.include?(spec.full_name) }
@@ -421,15 +641,35 @@ module Vagrant
421
641
  def vagrant_internal_specs
422
642
  # activate any dependencies up front so we can always
423
643
  # 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 }
644
+ self_spec = Gem::Specification.find { |s| s.name == "vagrant-unbundled" && s.activated? }
645
+ if !self_spec
646
+ @logger.warn("Failed to locate activated vagrant specification. Activating...")
647
+ self_spec = Gem::Specification.find { |s| s.name == "vagrant-unbundled" }
648
+ if !self_spec
649
+ @logger.error("Failed to locate Vagrant RubyGem specification")
650
+ raise Vagrant::Errors::SourceSpecNotFound
651
+ end
652
+ self_spec.activate
653
+ @logger.info("Activated vagrant specification version - #{self_spec.version}")
654
+ end
426
655
  # discover all the gems we have available
427
656
  list = {}
428
- directories = [Gem::Specification.default_specifications_dir]
429
- Gem::Specification.find_all{true}.each do |spec|
430
- list[spec.full_name] = spec
657
+ if Gem.respond_to?(:default_specifications_dir)
658
+ spec_dir = Gem.default_specifications_dir
659
+ else
660
+ spec_dir = Gem::Specification.default_specifications_dir
431
661
  end
432
- if(!defined?(::Bundler))
662
+ directories = [spec_dir]
663
+ if Vagrant.in_bundler?
664
+ Gem::Specification.find_all{true}.each do |spec|
665
+ list[spec.full_name] = spec
666
+ end
667
+ else
668
+ builtin_specs.each do |spec|
669
+ list[spec.full_name] = spec
670
+ end
671
+ end
672
+ if Vagrant.in_installer?
433
673
  directories += Gem::Specification.dirs.find_all do |path|
434
674
  !path.start_with?(Gem.user_dir)
435
675
  end
@@ -528,7 +768,6 @@ module Vagrant
528
768
  request.name == matcher["gem_name"]
529
769
  end
530
770
  if desired_activation_request && !desired_activation_request.full_spec.activated?
531
- activation_request = desired_activation_request
532
771
  @logger.warn("Found misordered activation request for #{desired_activation_request.full_name}. Moving to solution HEAD.")
533
772
  solution.delete(desired_activation_request)
534
773
  solution.unshift(desired_activation_request)
@@ -600,12 +839,22 @@ module Vagrant
600
839
  end
601
840
 
602
841
  def find_all(req)
603
- @specs.select do |spec|
604
- allow_prerelease = spec.name == "vagrant-unbundled" && Vagrant.prerelease?
605
- req.match?(spec, allow_prerelease)
842
+ r = @specs.select do |spec|
843
+ # When matching requests against builtin specs, we _always_ enable
844
+ # prerelease matching since any prerelease that's found in this
845
+ # set has been added explicitly and should be available for all
846
+ # plugins to resolve against. This includes Vagrant itself since
847
+ # it is considered a prerelease when in development mode
848
+ req.match?(spec, true)
606
849
  end.map do |spec|
607
850
  Gem::Resolver::InstalledSpecification.new(self, spec)
608
851
  end
852
+ # If any of the results are a prerelease, we need to mark the request
853
+ # to allow prereleases so the solution can be properly fulfilled
854
+ if r.any? { |x| x.version.prerelease? }
855
+ req.dependency.prerelease = true
856
+ end
857
+ r
609
858
  end
610
859
  end
611
860
 
@@ -639,7 +888,7 @@ module Vagrant
639
888
  # DependencyRequest +req+.
640
889
  def find_all(req)
641
890
  @specs.values.flatten.select do |spec|
642
- req.match?(spec)
891
+ req.match?(spec, prerelease)
643
892
  end.map do |spec|
644
893
  source = Gem::Source::Vendor.new(@directories[spec])
645
894
  Gem::Resolver::VendorSpecification.new(self, spec, source)
@@ -649,7 +898,7 @@ module Vagrant
649
898
  ##
650
899
  # Loads a spec with the given +name+. +version+, +platform+ and +source+ are
651
900
  # ignored.
652
- def load_spec (name, version, platform, source)
901
+ def load_spec(name, version, platform, source)
653
902
  version = Gem::Version.new(version) if !version.is_a?(Gem::Version)
654
903
  @specs.fetch(name, []).detect{|s| s.name == name && s.version == version}
655
904
  end