vagrantup 0.4.3.dev → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (175) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -0
  3. data/config/default.rb +6 -6
  4. data/lib/vagrant.rb +6 -3
  5. data/lib/vagrant/action.rb +77 -0
  6. data/lib/vagrant/action/action_exception.rb +16 -0
  7. data/lib/vagrant/action/box/destroy.rb +19 -0
  8. data/lib/vagrant/action/box/download.rb +78 -0
  9. data/lib/vagrant/action/box/unpackage.rb +58 -0
  10. data/lib/vagrant/action/box/verify.rb +23 -0
  11. data/lib/vagrant/action/builder.rb +151 -0
  12. data/lib/vagrant/action/builtin.rb +114 -0
  13. data/lib/vagrant/action/env/error_halt.rb +16 -0
  14. data/lib/vagrant/action/env/set.rb +18 -0
  15. data/lib/vagrant/action/environment.rb +98 -0
  16. data/lib/vagrant/action/exception_catcher.rb +14 -0
  17. data/lib/vagrant/action/vm/boot.rb +54 -0
  18. data/lib/vagrant/action/vm/check_box.rb +27 -0
  19. data/lib/vagrant/action/vm/check_guest_additions.rb +32 -0
  20. data/lib/vagrant/action/vm/clean_machine_folder.rb +43 -0
  21. data/lib/vagrant/action/vm/clear_forwarded_ports.rb +39 -0
  22. data/lib/vagrant/action/vm/clear_nfs_exports.rb +20 -0
  23. data/lib/vagrant/action/vm/clear_shared_folders.rb +32 -0
  24. data/lib/vagrant/action/vm/customize.rb +21 -0
  25. data/lib/vagrant/action/vm/destroy.rb +20 -0
  26. data/lib/vagrant/action/vm/destroy_unused_network_interfaces.rb +35 -0
  27. data/lib/vagrant/action/vm/disable_networks.rb +26 -0
  28. data/lib/vagrant/action/vm/export.rb +53 -0
  29. data/lib/vagrant/action/vm/forward_ports.rb +121 -0
  30. data/lib/vagrant/action/vm/forward_ports_helpers.rb +28 -0
  31. data/lib/vagrant/action/vm/halt.rb +34 -0
  32. data/lib/vagrant/action/vm/import.rb +33 -0
  33. data/lib/vagrant/action/vm/match_mac_address.rb +19 -0
  34. data/lib/vagrant/{actions → action}/vm/network.rb +47 -55
  35. data/lib/vagrant/action/vm/nfs.rb +161 -0
  36. data/lib/vagrant/action/vm/nfs_helpers.rb +11 -0
  37. data/lib/vagrant/action/vm/package.rb +99 -0
  38. data/lib/vagrant/action/vm/persist.rb +22 -0
  39. data/lib/vagrant/action/vm/provision.rb +50 -0
  40. data/lib/vagrant/action/vm/resume.rb +20 -0
  41. data/lib/vagrant/{actions/vm/shared_folders.rb → action/vm/share_folders.rb} +48 -45
  42. data/lib/vagrant/action/vm/suspend.rb +20 -0
  43. data/lib/vagrant/box.rb +3 -7
  44. data/lib/vagrant/commands/base.rb +1 -3
  45. data/lib/vagrant/commands/package.rb +4 -9
  46. data/lib/vagrant/commands/up.rb +0 -2
  47. data/lib/vagrant/config.rb +15 -1
  48. data/lib/vagrant/downloaders/file.rb +1 -1
  49. data/lib/vagrant/downloaders/http.rb +2 -1
  50. data/lib/vagrant/environment.rb +18 -14
  51. data/lib/vagrant/hosts/base.rb +77 -0
  52. data/lib/vagrant/hosts/bsd.rb +53 -0
  53. data/lib/vagrant/hosts/linux.rb +52 -0
  54. data/lib/vagrant/provisioners/base.rb +17 -9
  55. data/lib/vagrant/provisioners/chef.rb +1 -1
  56. data/lib/vagrant/provisioners/chef_server.rb +4 -8
  57. data/lib/vagrant/provisioners/chef_solo.rb +1 -2
  58. data/lib/vagrant/ssh.rb +12 -4
  59. data/lib/vagrant/systems/base.rb +4 -0
  60. data/lib/vagrant/systems/linux.rb +12 -1
  61. data/lib/vagrant/util.rb +16 -0
  62. data/lib/vagrant/util/busy.rb +59 -0
  63. data/lib/vagrant/util/plain_logger.rb +11 -0
  64. data/lib/vagrant/util/platform.rb +18 -0
  65. data/lib/vagrant/util/resource_logger.rb +128 -0
  66. data/lib/vagrant/version.rb +6 -0
  67. data/lib/vagrant/vm.rb +10 -12
  68. data/templates/chef_solo_solo.erb +2 -1
  69. data/templates/nfs/exports.erb +3 -0
  70. data/templates/nfs/exports_linux.erb +3 -0
  71. data/templates/strings.yml +23 -3
  72. metadata +121 -196
  73. data/.gitignore +0 -11
  74. data/Gemfile +0 -18
  75. data/Rakefile +0 -41
  76. data/VERSION +0 -1
  77. data/bin/.gitignore +0 -0
  78. data/lib/vagrant/actions/base.rb +0 -130
  79. data/lib/vagrant/actions/box/add.rb +0 -23
  80. data/lib/vagrant/actions/box/destroy.rb +0 -14
  81. data/lib/vagrant/actions/box/download.rb +0 -67
  82. data/lib/vagrant/actions/box/unpackage.rb +0 -42
  83. data/lib/vagrant/actions/box/verify.rb +0 -32
  84. data/lib/vagrant/actions/collection.rb +0 -36
  85. data/lib/vagrant/actions/runner.rb +0 -131
  86. data/lib/vagrant/actions/vm/boot.rb +0 -43
  87. data/lib/vagrant/actions/vm/customize.rb +0 -19
  88. data/lib/vagrant/actions/vm/destroy.rb +0 -24
  89. data/lib/vagrant/actions/vm/down.rb +0 -22
  90. data/lib/vagrant/actions/vm/export.rb +0 -45
  91. data/lib/vagrant/actions/vm/forward_ports.rb +0 -134
  92. data/lib/vagrant/actions/vm/halt.rb +0 -24
  93. data/lib/vagrant/actions/vm/import.rb +0 -23
  94. data/lib/vagrant/actions/vm/move_hard_drive.rb +0 -51
  95. data/lib/vagrant/actions/vm/package.rb +0 -94
  96. data/lib/vagrant/actions/vm/provision.rb +0 -49
  97. data/lib/vagrant/actions/vm/reload.rb +0 -17
  98. data/lib/vagrant/actions/vm/resume.rb +0 -16
  99. data/lib/vagrant/actions/vm/start.rb +0 -26
  100. data/lib/vagrant/actions/vm/suspend.rb +0 -16
  101. data/lib/vagrant/actions/vm/up.rb +0 -53
  102. data/lib/vagrant/busy.rb +0 -79
  103. data/lib/vagrant/resource_logger.rb +0 -126
  104. data/lib/vagrant/util/error_helper.rb +0 -13
  105. data/lib/vagrant/util/output_helper.rb +0 -9
  106. data/test/test_helper.rb +0 -149
  107. data/test/vagrant/actions/base_test.rb +0 -32
  108. data/test/vagrant/actions/box/add_test.rb +0 -36
  109. data/test/vagrant/actions/box/destroy_test.rb +0 -17
  110. data/test/vagrant/actions/box/download_test.rb +0 -137
  111. data/test/vagrant/actions/box/unpackage_test.rb +0 -99
  112. data/test/vagrant/actions/box/verify_test.rb +0 -44
  113. data/test/vagrant/actions/collection_test.rb +0 -113
  114. data/test/vagrant/actions/runner_test.rb +0 -268
  115. data/test/vagrant/actions/vm/boot_test.rb +0 -49
  116. data/test/vagrant/actions/vm/customize_test.rb +0 -21
  117. data/test/vagrant/actions/vm/destroy_test.rb +0 -37
  118. data/test/vagrant/actions/vm/down_test.rb +0 -39
  119. data/test/vagrant/actions/vm/export_test.rb +0 -88
  120. data/test/vagrant/actions/vm/forward_ports_test.rb +0 -253
  121. data/test/vagrant/actions/vm/halt_test.rb +0 -65
  122. data/test/vagrant/actions/vm/import_test.rb +0 -45
  123. data/test/vagrant/actions/vm/move_hard_drive_test.rb +0 -106
  124. data/test/vagrant/actions/vm/network_test.rb +0 -291
  125. data/test/vagrant/actions/vm/package_test.rb +0 -254
  126. data/test/vagrant/actions/vm/provision_test.rb +0 -99
  127. data/test/vagrant/actions/vm/reload_test.rb +0 -46
  128. data/test/vagrant/actions/vm/resume_test.rb +0 -26
  129. data/test/vagrant/actions/vm/shared_folders_test.rb +0 -211
  130. data/test/vagrant/actions/vm/start_test.rb +0 -73
  131. data/test/vagrant/actions/vm/suspend_test.rb +0 -26
  132. data/test/vagrant/actions/vm/up_test.rb +0 -96
  133. data/test/vagrant/active_list_test.rb +0 -173
  134. data/test/vagrant/box_test.rb +0 -154
  135. data/test/vagrant/busy_test.rb +0 -78
  136. data/test/vagrant/command_test.rb +0 -53
  137. data/test/vagrant/commands/base_test.rb +0 -139
  138. data/test/vagrant/commands/box/add_test.rb +0 -34
  139. data/test/vagrant/commands/box/list_test.rb +0 -32
  140. data/test/vagrant/commands/box/remove_test.rb +0 -41
  141. data/test/vagrant/commands/destroy_test.rb +0 -44
  142. data/test/vagrant/commands/halt_test.rb +0 -50
  143. data/test/vagrant/commands/init_test.rb +0 -55
  144. data/test/vagrant/commands/package_test.rb +0 -104
  145. data/test/vagrant/commands/provision_test.rb +0 -60
  146. data/test/vagrant/commands/reload_test.rb +0 -44
  147. data/test/vagrant/commands/resume_test.rb +0 -44
  148. data/test/vagrant/commands/ssh_config_test.rb +0 -77
  149. data/test/vagrant/commands/ssh_test.rb +0 -129
  150. data/test/vagrant/commands/status_test.rb +0 -40
  151. data/test/vagrant/commands/suspend_test.rb +0 -44
  152. data/test/vagrant/commands/up_test.rb +0 -47
  153. data/test/vagrant/config_test.rb +0 -287
  154. data/test/vagrant/downloaders/base_test.rb +0 -28
  155. data/test/vagrant/downloaders/file_test.rb +0 -33
  156. data/test/vagrant/downloaders/http_test.rb +0 -62
  157. data/test/vagrant/environment_test.rb +0 -770
  158. data/test/vagrant/provisioners/base_test.rb +0 -33
  159. data/test/vagrant/provisioners/chef_server_test.rb +0 -176
  160. data/test/vagrant/provisioners/chef_solo_test.rb +0 -183
  161. data/test/vagrant/provisioners/chef_test.rb +0 -175
  162. data/test/vagrant/resource_logger_test.rb +0 -145
  163. data/test/vagrant/ssh_session_test.rb +0 -46
  164. data/test/vagrant/ssh_test.rb +0 -296
  165. data/test/vagrant/systems/linux_test.rb +0 -179
  166. data/test/vagrant/util/error_helper_test.rb +0 -5
  167. data/test/vagrant/util/output_helper_test.rb +0 -5
  168. data/test/vagrant/util/plain_logger_test.rb +0 -17
  169. data/test/vagrant/util/platform_test.rb +0 -18
  170. data/test/vagrant/util/stacked_proc_runner_test.rb +0 -43
  171. data/test/vagrant/util/template_renderer_test.rb +0 -144
  172. data/test/vagrant/util/translator_test.rb +0 -61
  173. data/test/vagrant/util_test.rb +0 -27
  174. data/test/vagrant/vm_test.rb +0 -235
  175. data/vagrant.gemspec +0 -291
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4d485f02b4c6701bc3480af690f847ca1b6a774f
4
- data.tar.gz: 3d77d7c1035b7488ce588a2831b539fae889bca6
3
+ metadata.gz: b5919826f09f53bdfac384281bed18f97fc4967d
4
+ data.tar.gz: d5832323003e80dd65689d28c8247e362d399946
5
5
  SHA512:
6
- metadata.gz: 1b7cafe48f0ca5431eda69e78afc18b8da67824b817b0f95bc4a3a3fa8eee128313cfd94d343536ba62f619184042eece42ba5f987114c07952a35bbdba0f302
7
- data.tar.gz: 81fb6df77278bf24dbaa0165b4aefe14633df1fa020bea1678e33b441324ccb1ab9b728a30f51e77f3ed97815bece5e0f9d1d9e6e430ebccc7443c57025ea534
6
+ metadata.gz: 4aca6e7ce3d461cba9e9aae477d09516441ae9562141a49c6d77aa77796987374cc509a2d088be6ce8e1ed8829c4b77c7b14a287a2d51ac5f33bcd1659d10d70
7
+ data.tar.gz: 5036c5c3487329e82f3cb4d8c67b362e07221eb33512b7231d8bcb63424cbfed150a331e9f704dfe9ea3125d5999c4ae1c565d6fface8103ced08c061fe2e6b0
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Vagrant
2
2
 
3
3
  * Website: [http://vagrantup.com](http://vagrantup.com)
4
+ * Source: [http://github.com/mitchellh/vagrant](http://github.com/mitchellh/vagrant)
4
5
  * IRC: `#vagrant` on Freenode
5
6
  * Mailng list: [Google Groups](http://groups.google.com/group/vagrant-up)
6
7
 
@@ -3,6 +3,7 @@ Vagrant::Config.run do |config|
3
3
  config.vagrant.log_output = STDOUT
4
4
  config.vagrant.dotfile_name = ".vagrant"
5
5
  config.vagrant.home = "~/.vagrant"
6
+ config.vagrant.host = :detect
6
7
 
7
8
  config.ssh.username = "vagrant"
8
9
  config.ssh.host = "localhost"
@@ -11,9 +12,11 @@ Vagrant::Config.run do |config|
11
12
  config.ssh.max_tries = 10
12
13
  config.ssh.timeout = 30
13
14
  config.ssh.private_key_path = File.join(PROJECT_ROOT, 'keys', 'vagrant')
15
+ config.ssh.forward_agent = false
14
16
 
15
17
  config.vm.auto_port_range = (2200..2250)
16
18
  config.vm.box_ovf = "box.ovf"
19
+ config.vm.box_url = nil
17
20
  config.vm.base_mac = "0800279C2E42"
18
21
  config.vm.forward_port("ssh", 22, 2222, :auto => true)
19
22
  config.vm.disk_image_format = 'VMDK'
@@ -33,11 +36,8 @@ Vagrant::Config.run do |config|
33
36
  config.unison.crontab_entry_file = "/tmp/vagrant-unison-crontab"
34
37
  config.unison.log_file = "/tmp/v-unison-log-%s"
35
38
 
36
- # TODO fix these
37
- # config.vm.sync_opts = "-terse -group -owner -batch -silent"
38
- # config.vm.sync_script = "/tmp/sync"
39
- # config.vm.sync_crontab_entry_file = "/tmp/crontab-entry"
39
+ config.nfs.map_uid = :auto
40
+ config.nfs.map_gid = :auto
40
41
 
41
- config.package.name = 'vagrant'
42
- config.package.extension = '.box'
42
+ config.package.name = 'package.box'
43
43
  end
@@ -11,6 +11,9 @@ end
11
11
  require File.expand_path("util/glob_loader", libdir)
12
12
 
13
13
  # Load them up
14
- Vagrant::GlobLoader.glob_require(libdir, %w{util/stacked_proc_runner
15
- actions/base downloaders/base actions/collection actions/runner config
16
- provisioners/base provisioners/chef systems/base commands/base commands/box})
14
+ Vagrant::GlobLoader.glob_require(libdir, %w{util util/stacked_proc_runner
15
+ downloaders/base config provisioners/base provisioners/chef systems/base
16
+ commands/base commands/box action/exception_catcher hosts/base})
17
+
18
+ # Initialize the built-in actions
19
+ Vagrant::Action.builtin!
@@ -0,0 +1,77 @@
1
+ module Vagrant
2
+ # Manages action running and registration. Every Vagrant environment
3
+ # has an instance of {Action} to allow for running in the context of
4
+ # the environment.
5
+ class Action
6
+ include Util
7
+
8
+ class << self
9
+ # Returns the list of registered actions.
10
+ def actions
11
+ @actions ||= {}
12
+ end
13
+
14
+ # Registers an action and associates it with a symbol. This
15
+ # symbol can then be referenced in other action builds and
16
+ # callbacks can be registered on that symbol.
17
+ #
18
+ # @param [Symbol] key
19
+ def register(key, callable)
20
+ actions[key] = callable
21
+ end
22
+
23
+ # Retrieves a registered action by key.
24
+ def [](key)
25
+ actions[key]
26
+ end
27
+ end
28
+
29
+ # The environment to run the actions in.
30
+ attr_reader :env
31
+
32
+ # Initializes the action with the given environment which the actions
33
+ # will be run in.
34
+ #
35
+ # @param [Environment] env
36
+ def initialize(env)
37
+ @env = env
38
+ end
39
+
40
+ # Runs the given callable object in the context of the environment.
41
+ # If a symbol is given as the `callable` parameter, then it is looked
42
+ # up in the registered actions list which are registered with {register}.
43
+ #
44
+ # @param [Object] callable An object which responds to `call`.
45
+ def run(callable, options=nil)
46
+ callable = Builder.new.use(callable) if callable.kind_of?(Class)
47
+ callable = self.class.actions[callable] if callable.kind_of?(Symbol)
48
+
49
+ action_environment = Action::Environment.new(env)
50
+ action_environment.merge!(options || {})
51
+
52
+ # Run the action chain in a busy block, marking the environment as
53
+ # interrupted if a SIGINT occurs, and exiting cleanly once the
54
+ # chain has been run.
55
+ int_callback = lambda do
56
+ if action_environment.interrupted?
57
+ env.logger.info "Exiting immediately!"
58
+ abort
59
+ end
60
+
61
+ env.logger.info "Waiting for cleanup before exiting..."
62
+ action_environment.error!(:interrupt)
63
+ end
64
+
65
+ Busy.busy(int_callback) { callable.call(action_environment) }
66
+ exit if action_environment.interrupted?
67
+
68
+ if action_environment.error?
69
+ # Erroneous environment resulted. Properly display error
70
+ # message.
71
+ key, options = action_environment.error
72
+ error_and_exit(key, options)
73
+ return false
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,16 @@
1
+ module Vagrant
2
+ class Action
3
+ class ActionException < Exception
4
+ attr_reader :key
5
+ attr_reader :data
6
+
7
+ def initialize(key, data = {})
8
+ @key = key
9
+ @data = data
10
+
11
+ message = Vagrant::Util::Translator.t(key, data)
12
+ super(message)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ module Vagrant
2
+ class Action
3
+ module Box
4
+ class Destroy
5
+ def initialize(app, env)
6
+ @app = app
7
+ @env = env
8
+ end
9
+
10
+ def call(env)
11
+ env.logger.info "Deleting box directory..."
12
+ FileUtils.rm_rf(env["box"].directory)
13
+
14
+ @app.call(env)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,78 @@
1
+ module Vagrant
2
+ class Action
3
+ module Box
4
+ class Download
5
+ BASENAME = "box"
6
+
7
+ include Util
8
+
9
+ attr_reader :temp_path
10
+
11
+ def initialize(app, env)
12
+ @app = app
13
+ @env = env
14
+ @env["download.classes"] ||= []
15
+ @env["download.classes"] += [Downloaders::HTTP, Downloaders::File]
16
+ end
17
+
18
+ def call(env)
19
+ @env = env
20
+
21
+ download if instantiate_downloader
22
+ return if env.error?
23
+
24
+ @app.call(@env)
25
+
26
+ cleanup
27
+ end
28
+
29
+ def instantiate_downloader
30
+ @env["download.classes"].each do |klass|
31
+ if klass.match?(@env["box"].uri)
32
+ @env.logger.info "Downloading with #{klass}..."
33
+ @downloader = klass.new(@env)
34
+ end
35
+ end
36
+
37
+ if !@downloader
38
+ @env.error!(:box_download_unknown_type)
39
+ return false
40
+ end
41
+
42
+ @downloader.prepare(@env["box"].uri)
43
+ true
44
+ end
45
+
46
+ def download
47
+ with_tempfile do |tempfile|
48
+ download_to(tempfile)
49
+ @temp_path = @env["download.temp_path"] = tempfile.path
50
+ end
51
+ end
52
+
53
+ def cleanup
54
+ if temp_path && File.exist?(temp_path)
55
+ @env.logger.info "Cleaning up downloaded box..."
56
+ File.unlink(temp_path)
57
+ end
58
+ end
59
+
60
+ def with_tempfile
61
+ @env.logger.info "Creating tempfile for storing box file..."
62
+ File.open(box_temp_path, Platform.tar_file_options) do |tempfile|
63
+ yield tempfile
64
+ end
65
+ end
66
+
67
+ def box_temp_path
68
+ File.join(@env.env.tmp_path, BASENAME + Time.now.to_i.to_s)
69
+ end
70
+
71
+ def download_to(f)
72
+ @env.logger.info "Copying box to temporary location..."
73
+ @downloader.download!(@env["box"].uri, f)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,58 @@
1
+ module Vagrant
2
+ class Action
3
+ module Box
4
+ # Unpackages a downloaded box to a given directory with a given
5
+ # name.
6
+ #
7
+ # # Required Variables
8
+ #
9
+ # * `download.temp_path` - A location for the downloaded box. This is
10
+ # set by the {Download} action.
11
+ # * `box` - A {Vagrant::Box} object.
12
+ #
13
+ class Unpackage
14
+ attr_reader :box_directory
15
+
16
+ def initialize(app, env)
17
+ @app = app
18
+ @env = env
19
+ end
20
+
21
+ def call(env)
22
+ @env = env
23
+
24
+ return if !setup_box_directory
25
+ decompress
26
+
27
+ @app.call(@env)
28
+
29
+ cleanup if @env.error?
30
+ end
31
+
32
+ def cleanup
33
+ if File.directory?(box_directory)
34
+ FileUtils.rm_rf(box_directory)
35
+ end
36
+ end
37
+
38
+ def setup_box_directory
39
+ if File.directory?(@env["box"].directory)
40
+ @env.error!(:box_already_exists, :box_name => @env["box"].name)
41
+ return false
42
+ end
43
+
44
+ FileUtils.mkdir_p(@env["box"].directory)
45
+ @box_directory = @env["box"].directory
46
+ true
47
+ end
48
+
49
+ def decompress
50
+ Dir.chdir(@env["box"].directory) do
51
+ @env.logger.info "Extracting box to #{@env["box"].directory}..."
52
+ Archive::Tar::Minitar.unpack(@env["download.temp_path"], @env["box"].directory)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,23 @@
1
+ module Vagrant
2
+ class Action
3
+ module Box
4
+ class Verify
5
+ def initialize(app, env)
6
+ @app = app
7
+ @env = env
8
+ end
9
+
10
+ def call(env)
11
+ begin
12
+ env.logger.info "Verifying box..."
13
+ VirtualBox::Appliance.new(env["box"].ovf_file)
14
+ rescue Exception
15
+ return env.error!(:box_verification_failed)
16
+ end
17
+
18
+ @app.call(env)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,151 @@
1
+ module Vagrant
2
+ class Action
3
+ # Action builder which provides a nice DSL for building up
4
+ # a middleware sequence for Vagrant actions. This code is based
5
+ # heavily off of `Rack::Builder` and `ActionDispatch::MiddlewareStack`
6
+ # in Rack and Rails, respectively.
7
+ #
8
+ # Usage
9
+ #
10
+ # Building an action sequence is very easy:
11
+ #
12
+ # app = Vagrant::Action::Builder.new do
13
+ # use MiddlewareA
14
+ # use MiddlewareB
15
+ # end
16
+ #
17
+ # Vagrant::Action.run(app)
18
+ #
19
+ class Builder
20
+ # Initializes the builder. An optional block can be passed which
21
+ # will be evaluated in the context of the instance.
22
+ def initialize(&block)
23
+ instance_eval(&block) if block_given?
24
+ end
25
+
26
+ # Returns the current stack of middlewares. You probably won't
27
+ # need to use this directly, and its recommended that you don't.
28
+ #
29
+ # @return [Array]
30
+ def stack
31
+ @stack ||= []
32
+ end
33
+
34
+ # Returns a mergeable version of the builder. If `use` is called with
35
+ # the return value of this method, then the stack will merge, instead
36
+ # of being treated as a separate single middleware.
37
+ def flatten
38
+ lambda do |env|
39
+ self.call(env)
40
+ end
41
+ end
42
+
43
+ # Adds a middleware class to the middleware stack. Any additional
44
+ # args and a block, if given, are saved and passed to the initializer
45
+ # of the middleware.
46
+ #
47
+ # @param [Class] middleware The middleware class
48
+ def use(middleware, *args, &block)
49
+ if middleware.kind_of?(Builder)
50
+ # Prepend with a environment setter if args are given
51
+ self.use(Env::Set, *args, &block) if !args.empty? && args.first.is_a?(Hash)
52
+
53
+ # Merge in the other builder's stack into our own
54
+ self.stack.concat(middleware.stack)
55
+ else
56
+ self.stack << [middleware, args, block]
57
+ end
58
+
59
+ self
60
+ end
61
+
62
+ # Inserts a middleware at the given index or directly before the
63
+ # given middleware object.
64
+ def insert(index, middleware, *args, &block)
65
+ index = self.index(index) unless index.is_a?(Integer)
66
+ stack.insert(index, [middleware, args, block])
67
+ end
68
+
69
+ alias_method :insert_before, :insert
70
+
71
+ # Inserts a middleware after the given index or middleware object.
72
+ def insert_after(index, middleware, *args, &block)
73
+ index = self.index(index) unless index.is_a?(Integer)
74
+ raise "no such middleware to insert after: #{index.inspect}" unless index
75
+ insert(index + 1, middleware, *args, &block)
76
+ end
77
+
78
+ # Swaps out the given middlware object or index with the new
79
+ # middleware.
80
+ def swap(index, middleware, *args, &block)
81
+ if index.is_a?(Integer)
82
+ delete(index)
83
+ insert(index, middleware, *args, &block)
84
+ else
85
+ insert_before(index, middleware, *args, &block)
86
+ delete(index)
87
+ end
88
+ end
89
+
90
+ # Deletes the given middleware object or index
91
+ def delete(index)
92
+ index = self.index(index) unless index.is_a?(Integer)
93
+ stack.delete_at(index)
94
+ end
95
+
96
+ # Returns the numeric index for the given middleware object.
97
+ #
98
+ # @param [Object] object The item to find the index for
99
+ # @return [Integer]
100
+ def index(object)
101
+ stack.each_with_index do |item, i|
102
+ return i if item[0] == object
103
+ end
104
+
105
+ nil
106
+ end
107
+
108
+ # Converts the builder stack to a runnable action sequence.
109
+ #
110
+ # @param [Vagrant::Action::Environment] env The action environment
111
+ # @return [Object] A callable object
112
+ def to_app(env)
113
+ # Prepend the error halt task so errneous environments are halted
114
+ # before the chain even begins.
115
+ items = stack.dup.unshift([Env::ErrorHalt, [], nil])
116
+
117
+ # Convert each middleware into a lambda which takes the next
118
+ # middleware.
119
+ items = items.collect do |item|
120
+ klass, args, block = item
121
+
122
+ lambda do |app|
123
+ if klass.is_a?(Class)
124
+ # A middleware klass which is to be instantiated with the
125
+ # app, env, and any arguments given
126
+ klass.new(app, env, *args, &block)
127
+ elsif klass.respond_to?(:call)
128
+ # Make it a lambda which calls the item then forwards
129
+ # up the chain
130
+ lambda do |e|
131
+ klass.call(e)
132
+ app.call(e)
133
+ end
134
+ else
135
+ raise "Invalid middleware: #{item.inspect}"
136
+ end
137
+ end
138
+ end
139
+
140
+ # Append the final step and convert into flattened call chain.
141
+ items << lambda { |env| }
142
+ items[0...-1].reverse.inject(items.last) { |a,e| e.call(a) }
143
+ end
144
+
145
+ # Runs the builder stack with the given environment.
146
+ def call(env)
147
+ to_app(env).call(env)
148
+ end
149
+ end
150
+ end
151
+ end