vagrant 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +1 -0
- data/config/default.rb +6 -6
- data/lib/vagrant.rb +6 -3
- data/lib/vagrant/action.rb +77 -0
- data/lib/vagrant/action/action_exception.rb +16 -0
- data/lib/vagrant/action/box/destroy.rb +19 -0
- data/lib/vagrant/action/box/download.rb +78 -0
- data/lib/vagrant/action/box/unpackage.rb +58 -0
- data/lib/vagrant/action/box/verify.rb +23 -0
- data/lib/vagrant/action/builder.rb +151 -0
- data/lib/vagrant/action/builtin.rb +114 -0
- data/lib/vagrant/action/env/error_halt.rb +16 -0
- data/lib/vagrant/action/env/set.rb +18 -0
- data/lib/vagrant/action/environment.rb +98 -0
- data/lib/vagrant/action/exception_catcher.rb +14 -0
- data/lib/vagrant/action/vm/boot.rb +54 -0
- data/lib/vagrant/action/vm/check_box.rb +27 -0
- data/lib/vagrant/action/vm/check_guest_additions.rb +32 -0
- data/lib/vagrant/action/vm/clean_machine_folder.rb +43 -0
- data/lib/vagrant/action/vm/clear_forwarded_ports.rb +39 -0
- data/lib/vagrant/action/vm/clear_nfs_exports.rb +20 -0
- data/lib/vagrant/action/vm/clear_shared_folders.rb +32 -0
- data/lib/vagrant/action/vm/customize.rb +21 -0
- data/lib/vagrant/action/vm/destroy.rb +20 -0
- data/lib/vagrant/action/vm/destroy_unused_network_interfaces.rb +35 -0
- data/lib/vagrant/action/vm/disable_networks.rb +26 -0
- data/lib/vagrant/action/vm/export.rb +53 -0
- data/lib/vagrant/action/vm/forward_ports.rb +121 -0
- data/lib/vagrant/action/vm/forward_ports_helpers.rb +28 -0
- data/lib/vagrant/action/vm/halt.rb +34 -0
- data/lib/vagrant/action/vm/import.rb +33 -0
- data/lib/vagrant/action/vm/match_mac_address.rb +19 -0
- data/lib/vagrant/{actions → action}/vm/network.rb +47 -55
- data/lib/vagrant/action/vm/nfs.rb +161 -0
- data/lib/vagrant/action/vm/nfs_helpers.rb +11 -0
- data/lib/vagrant/action/vm/package.rb +99 -0
- data/lib/vagrant/action/vm/persist.rb +22 -0
- data/lib/vagrant/action/vm/provision.rb +50 -0
- data/lib/vagrant/action/vm/resume.rb +20 -0
- data/lib/vagrant/{actions/vm/shared_folders.rb → action/vm/share_folders.rb} +48 -45
- data/lib/vagrant/action/vm/suspend.rb +20 -0
- data/lib/vagrant/box.rb +3 -7
- data/lib/vagrant/commands/base.rb +1 -3
- data/lib/vagrant/commands/package.rb +4 -9
- data/lib/vagrant/commands/up.rb +0 -2
- data/lib/vagrant/config.rb +15 -1
- data/lib/vagrant/downloaders/file.rb +1 -1
- data/lib/vagrant/downloaders/http.rb +2 -1
- data/lib/vagrant/environment.rb +18 -14
- data/lib/vagrant/hosts/base.rb +77 -0
- data/lib/vagrant/hosts/bsd.rb +53 -0
- data/lib/vagrant/hosts/linux.rb +52 -0
- data/lib/vagrant/provisioners/base.rb +17 -9
- data/lib/vagrant/provisioners/chef.rb +1 -1
- data/lib/vagrant/provisioners/chef_server.rb +4 -8
- data/lib/vagrant/provisioners/chef_solo.rb +1 -2
- data/lib/vagrant/ssh.rb +12 -4
- data/lib/vagrant/systems/base.rb +4 -0
- data/lib/vagrant/systems/linux.rb +12 -1
- data/lib/vagrant/util.rb +16 -0
- data/lib/vagrant/util/busy.rb +59 -0
- data/lib/vagrant/util/plain_logger.rb +11 -0
- data/lib/vagrant/util/platform.rb +18 -0
- data/lib/vagrant/util/resource_logger.rb +128 -0
- data/lib/vagrant/version.rb +6 -0
- data/lib/vagrant/vm.rb +10 -12
- data/templates/chef_solo_solo.erb +2 -1
- data/templates/nfs/exports.erb +3 -0
- data/templates/nfs/exports_linux.erb +3 -0
- data/templates/strings.yml +23 -3
- metadata +128 -198
- data/.gitignore +0 -11
- data/Gemfile +0 -18
- data/Rakefile +0 -41
- data/VERSION +0 -1
- data/bin/.gitignore +0 -0
- data/lib/vagrant/actions/base.rb +0 -130
- data/lib/vagrant/actions/box/add.rb +0 -23
- data/lib/vagrant/actions/box/destroy.rb +0 -14
- data/lib/vagrant/actions/box/download.rb +0 -67
- data/lib/vagrant/actions/box/unpackage.rb +0 -42
- data/lib/vagrant/actions/box/verify.rb +0 -32
- data/lib/vagrant/actions/collection.rb +0 -36
- data/lib/vagrant/actions/runner.rb +0 -131
- data/lib/vagrant/actions/vm/boot.rb +0 -43
- data/lib/vagrant/actions/vm/customize.rb +0 -19
- data/lib/vagrant/actions/vm/destroy.rb +0 -24
- data/lib/vagrant/actions/vm/down.rb +0 -22
- data/lib/vagrant/actions/vm/export.rb +0 -45
- data/lib/vagrant/actions/vm/forward_ports.rb +0 -134
- data/lib/vagrant/actions/vm/halt.rb +0 -24
- data/lib/vagrant/actions/vm/import.rb +0 -23
- data/lib/vagrant/actions/vm/move_hard_drive.rb +0 -51
- data/lib/vagrant/actions/vm/package.rb +0 -94
- data/lib/vagrant/actions/vm/provision.rb +0 -49
- data/lib/vagrant/actions/vm/reload.rb +0 -17
- data/lib/vagrant/actions/vm/resume.rb +0 -16
- data/lib/vagrant/actions/vm/start.rb +0 -26
- data/lib/vagrant/actions/vm/suspend.rb +0 -16
- data/lib/vagrant/actions/vm/up.rb +0 -53
- data/lib/vagrant/busy.rb +0 -79
- data/lib/vagrant/resource_logger.rb +0 -126
- data/lib/vagrant/util/error_helper.rb +0 -13
- data/lib/vagrant/util/output_helper.rb +0 -9
- data/test/test_helper.rb +0 -149
- data/test/vagrant/actions/base_test.rb +0 -32
- data/test/vagrant/actions/box/add_test.rb +0 -36
- data/test/vagrant/actions/box/destroy_test.rb +0 -17
- data/test/vagrant/actions/box/download_test.rb +0 -137
- data/test/vagrant/actions/box/unpackage_test.rb +0 -99
- data/test/vagrant/actions/box/verify_test.rb +0 -44
- data/test/vagrant/actions/collection_test.rb +0 -113
- data/test/vagrant/actions/runner_test.rb +0 -268
- data/test/vagrant/actions/vm/boot_test.rb +0 -49
- data/test/vagrant/actions/vm/customize_test.rb +0 -21
- data/test/vagrant/actions/vm/destroy_test.rb +0 -37
- data/test/vagrant/actions/vm/down_test.rb +0 -39
- data/test/vagrant/actions/vm/export_test.rb +0 -88
- data/test/vagrant/actions/vm/forward_ports_test.rb +0 -253
- data/test/vagrant/actions/vm/halt_test.rb +0 -65
- data/test/vagrant/actions/vm/import_test.rb +0 -45
- data/test/vagrant/actions/vm/move_hard_drive_test.rb +0 -106
- data/test/vagrant/actions/vm/network_test.rb +0 -291
- data/test/vagrant/actions/vm/package_test.rb +0 -254
- data/test/vagrant/actions/vm/provision_test.rb +0 -99
- data/test/vagrant/actions/vm/reload_test.rb +0 -46
- data/test/vagrant/actions/vm/resume_test.rb +0 -26
- data/test/vagrant/actions/vm/shared_folders_test.rb +0 -211
- data/test/vagrant/actions/vm/start_test.rb +0 -73
- data/test/vagrant/actions/vm/suspend_test.rb +0 -26
- data/test/vagrant/actions/vm/up_test.rb +0 -96
- data/test/vagrant/active_list_test.rb +0 -173
- data/test/vagrant/box_test.rb +0 -154
- data/test/vagrant/busy_test.rb +0 -78
- data/test/vagrant/command_test.rb +0 -53
- data/test/vagrant/commands/base_test.rb +0 -139
- data/test/vagrant/commands/box/add_test.rb +0 -34
- data/test/vagrant/commands/box/list_test.rb +0 -32
- data/test/vagrant/commands/box/remove_test.rb +0 -41
- data/test/vagrant/commands/destroy_test.rb +0 -44
- data/test/vagrant/commands/halt_test.rb +0 -50
- data/test/vagrant/commands/init_test.rb +0 -55
- data/test/vagrant/commands/package_test.rb +0 -104
- data/test/vagrant/commands/provision_test.rb +0 -60
- data/test/vagrant/commands/reload_test.rb +0 -44
- data/test/vagrant/commands/resume_test.rb +0 -44
- data/test/vagrant/commands/ssh_config_test.rb +0 -77
- data/test/vagrant/commands/ssh_test.rb +0 -129
- data/test/vagrant/commands/status_test.rb +0 -40
- data/test/vagrant/commands/suspend_test.rb +0 -44
- data/test/vagrant/commands/up_test.rb +0 -47
- data/test/vagrant/config_test.rb +0 -287
- data/test/vagrant/downloaders/base_test.rb +0 -28
- data/test/vagrant/downloaders/file_test.rb +0 -33
- data/test/vagrant/downloaders/http_test.rb +0 -62
- data/test/vagrant/environment_test.rb +0 -770
- data/test/vagrant/provisioners/base_test.rb +0 -33
- data/test/vagrant/provisioners/chef_server_test.rb +0 -176
- data/test/vagrant/provisioners/chef_solo_test.rb +0 -183
- data/test/vagrant/provisioners/chef_test.rb +0 -175
- data/test/vagrant/resource_logger_test.rb +0 -145
- data/test/vagrant/ssh_session_test.rb +0 -46
- data/test/vagrant/ssh_test.rb +0 -296
- data/test/vagrant/systems/linux_test.rb +0 -179
- data/test/vagrant/util/error_helper_test.rb +0 -5
- data/test/vagrant/util/output_helper_test.rb +0 -5
- data/test/vagrant/util/plain_logger_test.rb +0 -17
- data/test/vagrant/util/platform_test.rb +0 -18
- data/test/vagrant/util/stacked_proc_runner_test.rb +0 -43
- data/test/vagrant/util/template_renderer_test.rb +0 -144
- data/test/vagrant/util/translator_test.rb +0 -61
- data/test/vagrant/util_test.rb +0 -27
- data/test/vagrant/vm_test.rb +0 -235
- data/vagrant.gemspec +0 -291
data/README.md
CHANGED
data/config/default.rb
CHANGED
@@ -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
|
-
|
37
|
-
|
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 = '
|
42
|
-
config.package.extension = '.box'
|
42
|
+
config.package.name = 'package.box'
|
43
43
|
end
|
data/lib/vagrant.rb
CHANGED
@@ -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
|
-
|
16
|
-
|
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
|