vagrant 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -4
- data/Rakefile +3 -3
- data/VERSION +1 -1
- data/bin/vagrant +5 -13
- data/config/default.rb +1 -0
- data/keys/README.md +8 -1
- data/keys/vagrant.ppk +26 -0
- data/lib/vagrant.rb +3 -3
- data/lib/vagrant/actions/base.rb +15 -4
- data/lib/vagrant/actions/box/add.rb +1 -1
- data/lib/vagrant/actions/box/download.rb +72 -66
- data/lib/vagrant/actions/box/unpackage.rb +1 -4
- data/lib/vagrant/actions/runner.rb +1 -1
- data/lib/vagrant/actions/vm/boot.rb +5 -7
- data/lib/vagrant/actions/vm/customize.rb +2 -2
- data/lib/vagrant/actions/vm/destroy.rb +2 -2
- data/lib/vagrant/actions/vm/down.rb +7 -0
- data/lib/vagrant/actions/vm/export.rb +10 -4
- data/lib/vagrant/actions/vm/forward_ports.rb +5 -15
- data/lib/vagrant/actions/vm/halt.rb +5 -3
- data/lib/vagrant/actions/vm/import.rb +10 -3
- data/lib/vagrant/actions/vm/move_hard_drive.rb +1 -3
- data/lib/vagrant/actions/vm/package.rb +33 -10
- data/lib/vagrant/actions/vm/provision.rb +4 -4
- data/lib/vagrant/actions/vm/reload.rb +1 -1
- data/lib/vagrant/actions/vm/resume.rb +1 -1
- data/lib/vagrant/actions/vm/shared_folders.rb +7 -7
- data/lib/vagrant/actions/vm/start.rb +3 -2
- data/lib/vagrant/actions/vm/suspend.rb +2 -2
- data/lib/vagrant/actions/vm/up.rb +7 -17
- data/lib/vagrant/active_list.rb +52 -45
- data/lib/vagrant/box.rb +18 -11
- data/lib/vagrant/busy.rb +7 -0
- data/lib/vagrant/command.rb +27 -0
- data/lib/vagrant/commands/base.rb +163 -0
- data/lib/vagrant/commands/box.rb +16 -0
- data/lib/vagrant/commands/box/add.rb +24 -0
- data/lib/vagrant/commands/box/list.rb +30 -0
- data/lib/vagrant/commands/box/remove.rb +31 -0
- data/lib/vagrant/commands/destroy.rb +23 -0
- data/lib/vagrant/commands/down.rb +16 -0
- data/lib/vagrant/commands/halt.rb +23 -0
- data/lib/vagrant/commands/init.rb +32 -0
- data/lib/vagrant/commands/package.rb +46 -0
- data/lib/vagrant/commands/reload.rb +22 -0
- data/lib/vagrant/commands/resume.rb +22 -0
- data/lib/vagrant/commands/ssh.rb +22 -0
- data/lib/vagrant/commands/ssh_config.rb +30 -0
- data/lib/vagrant/commands/status.rb +58 -0
- data/lib/vagrant/commands/suspend.rb +23 -0
- data/lib/vagrant/commands/up.rb +26 -0
- data/lib/vagrant/config.rb +21 -11
- data/lib/vagrant/downloaders/file.rb +5 -5
- data/lib/vagrant/downloaders/http.rb +10 -15
- data/lib/vagrant/environment.rb +259 -0
- data/lib/vagrant/provisioners/base.rb +7 -0
- data/lib/vagrant/provisioners/chef.rb +24 -9
- data/lib/vagrant/provisioners/chef_server.rb +23 -48
- data/lib/vagrant/provisioners/chef_solo.rb +48 -22
- data/lib/vagrant/ssh.rb +95 -46
- data/lib/vagrant/util.rb +2 -2
- data/lib/vagrant/util/errors.rb +36 -0
- data/lib/vagrant/util/platform.rb +12 -0
- data/lib/vagrant/util/progress_meter.rb +33 -0
- data/lib/vagrant/util/stacked_proc_runner.rb +35 -0
- data/lib/vagrant/util/template_renderer.rb +83 -0
- data/lib/vagrant/vm.rb +1 -0
- data/templates/{Vagrantfile → Vagrantfile.erb} +2 -2
- data/templates/chef_server_client.erb +16 -0
- data/templates/chef_solo_solo.erb +4 -0
- data/templates/errors.yml +157 -0
- data/templates/package_Vagrantfile.erb +11 -0
- data/templates/ssh_config.erb +7 -0
- data/test/test_helper.rb +12 -15
- data/test/vagrant/actions/box/add_test.rb +1 -2
- data/test/vagrant/actions/box/destroy_test.rb +0 -1
- data/test/vagrant/actions/box/download_test.rb +40 -15
- data/test/vagrant/actions/box/unpackage_test.rb +2 -3
- data/test/vagrant/actions/collection_test.rb +8 -5
- data/test/vagrant/actions/runner_test.rb +8 -6
- data/test/vagrant/actions/vm/boot_test.rb +12 -11
- data/test/vagrant/actions/vm/customize_test.rb +2 -3
- data/test/vagrant/actions/vm/destroy_test.rb +2 -3
- data/test/vagrant/actions/vm/down_test.rb +16 -3
- data/test/vagrant/actions/vm/export_test.rb +4 -5
- data/test/vagrant/actions/vm/forward_ports_test.rb +6 -5
- data/test/vagrant/actions/vm/halt_test.rb +8 -2
- data/test/vagrant/actions/vm/import_test.rb +5 -5
- data/test/vagrant/actions/vm/move_hard_drive_test.rb +4 -6
- data/test/vagrant/actions/vm/package_test.rb +60 -22
- data/test/vagrant/actions/vm/provision_test.rb +7 -16
- data/test/vagrant/actions/vm/reload_test.rb +3 -2
- data/test/vagrant/actions/vm/resume_test.rb +0 -1
- data/test/vagrant/actions/vm/shared_folders_test.rb +17 -12
- data/test/vagrant/actions/vm/start_test.rb +10 -3
- data/test/vagrant/actions/vm/suspend_test.rb +1 -2
- data/test/vagrant/actions/vm/up_test.rb +19 -11
- data/test/vagrant/active_list_test.rb +148 -129
- data/test/vagrant/box_test.rb +26 -14
- data/test/vagrant/busy_test.rb +15 -6
- data/test/vagrant/command_test.rb +53 -0
- data/test/vagrant/commands/base_test.rb +118 -0
- data/test/vagrant/commands/box/add_test.rb +34 -0
- data/test/vagrant/commands/box/list_test.rb +32 -0
- data/test/vagrant/commands/box/remove_test.rb +41 -0
- data/test/vagrant/commands/destroy_test.rb +32 -0
- data/test/vagrant/commands/down_test.rb +17 -0
- data/test/vagrant/commands/halt_test.rb +28 -0
- data/test/vagrant/commands/init_test.rb +55 -0
- data/test/vagrant/commands/package_test.rb +84 -0
- data/test/vagrant/commands/reload_test.rb +28 -0
- data/test/vagrant/commands/resume_test.rb +33 -0
- data/test/vagrant/commands/ssh_config_test.rb +54 -0
- data/test/vagrant/commands/ssh_test.rb +32 -0
- data/test/vagrant/commands/status_test.rb +20 -0
- data/test/vagrant/commands/suspend_test.rb +33 -0
- data/test/vagrant/commands/up_test.rb +41 -0
- data/test/vagrant/config_test.rb +42 -17
- data/test/vagrant/downloaders/file_test.rb +7 -0
- data/test/vagrant/downloaders/http_test.rb +12 -0
- data/test/vagrant/environment_test.rb +595 -0
- data/test/vagrant/provisioners/base_test.rb +7 -1
- data/test/vagrant/provisioners/chef_server_test.rb +41 -51
- data/test/vagrant/provisioners/chef_solo_test.rb +93 -62
- data/test/vagrant/provisioners/chef_test.rb +61 -15
- data/test/vagrant/ssh_test.rb +166 -38
- data/test/vagrant/util/errors_test.rb +57 -0
- data/test/vagrant/util/progress_meter_test.rb +33 -0
- data/test/vagrant/{stacked_proc_runner_test.rb → util/stacked_proc_runner_test.rb} +3 -3
- data/test/vagrant/util/template_renderer_test.rb +138 -0
- data/test/vagrant/vm_test.rb +3 -2
- data/vagrant.gemspec +88 -33
- metadata +94 -51
- data/bin/vagrant-box +0 -34
- data/bin/vagrant-down +0 -27
- data/bin/vagrant-halt +0 -28
- data/bin/vagrant-init +0 -27
- data/bin/vagrant-package +0 -29
- data/bin/vagrant-reload +0 -29
- data/bin/vagrant-resume +0 -27
- data/bin/vagrant-ssh +0 -27
- data/bin/vagrant-status +0 -29
- data/bin/vagrant-suspend +0 -27
- data/bin/vagrant-up +0 -29
- data/lib/vagrant/commands.rb +0 -234
- data/lib/vagrant/env.rb +0 -189
- data/lib/vagrant/stacked_proc_runner.rb +0 -33
- data/test/vagrant/commands_test.rb +0 -269
- data/test/vagrant/env_test.rb +0 -418
@@ -4,6 +4,7 @@ module Vagrant
|
|
4
4
|
class ChefSolo < Chef
|
5
5
|
def prepare
|
6
6
|
share_cookbook_folders
|
7
|
+
share_role_folders
|
7
8
|
end
|
8
9
|
|
9
10
|
def provision!
|
@@ -15,24 +16,28 @@ module Vagrant
|
|
15
16
|
|
16
17
|
def share_cookbook_folders
|
17
18
|
host_cookbook_paths.each_with_index do |cookbook, i|
|
18
|
-
|
19
|
+
env.config.vm.share_folder("v-csc-#{i}", cookbook_path(i), cookbook)
|
19
20
|
end
|
20
21
|
end
|
21
22
|
|
22
|
-
def
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
def share_role_folders
|
24
|
+
host_role_paths.each_with_index do |role, i|
|
25
|
+
env.config.vm.share_folder("v-csr-#{i}", role_path(i), role)
|
26
|
+
end
|
27
|
+
end
|
27
28
|
|
28
|
-
|
29
|
-
|
29
|
+
def setup_solo_config
|
30
|
+
setup_config("chef_solo_solo", "solo.rb", {
|
31
|
+
:provisioning_path => env.config.chef.provisioning_path,
|
32
|
+
:cookbooks_path => cookbooks_path,
|
33
|
+
:roles_path => roles_path
|
34
|
+
})
|
30
35
|
end
|
31
36
|
|
32
37
|
def run_chef_solo
|
33
38
|
logger.info "Running chef-solo..."
|
34
|
-
|
35
|
-
ssh.exec!("cd #{
|
39
|
+
env.ssh.execute do |ssh|
|
40
|
+
ssh.exec!("cd #{env.config.chef.provisioning_path} && sudo chef-solo -c solo.rb -j dna.json") do |channel, data, stream|
|
36
41
|
# TODO: Very verbose. It would be easier to save the data and only show it during
|
37
42
|
# an error, or when verbosity level is set high
|
38
43
|
logger.info("#{stream}: #{data}")
|
@@ -40,28 +45,49 @@ solo
|
|
40
45
|
end
|
41
46
|
end
|
42
47
|
|
43
|
-
def
|
44
|
-
|
45
|
-
cookbooks = [cookbooks] unless cookbooks.is_a?(Array)
|
46
|
-
cookbooks.collect! { |cookbook| File.expand_path(cookbook, Env.root_path) }
|
47
|
-
return cookbooks
|
48
|
+
def host_folder_paths(paths)
|
49
|
+
[paths].flatten.collect { |path| File.expand_path(path, env.root_path) }
|
48
50
|
end
|
49
51
|
|
50
|
-
def
|
51
|
-
File.join(
|
52
|
+
def folder_path(folder, i)
|
53
|
+
File.join(env.config.chef.provisioning_path, "#{folder}-#{i}")
|
52
54
|
end
|
53
55
|
|
54
|
-
def
|
56
|
+
def folders_path(folders, folder)
|
55
57
|
result = []
|
56
|
-
|
57
|
-
result <<
|
58
|
+
folders.each_with_index do |host_path, i|
|
59
|
+
result << folder_path(folder, i)
|
58
60
|
end
|
59
61
|
|
60
62
|
# We're lucky that ruby's string and array syntax for strings is the
|
61
63
|
# same as JSON, so we can just convert to JSON here and use that
|
62
|
-
result = result.to_s if result.length == 1
|
64
|
+
result = result[0].to_s if result.length == 1
|
63
65
|
result.to_json
|
64
66
|
end
|
67
|
+
|
68
|
+
def host_cookbook_paths
|
69
|
+
host_folder_paths(env.config.chef.cookbooks_path)
|
70
|
+
end
|
71
|
+
|
72
|
+
def host_role_paths
|
73
|
+
host_folder_paths(env.config.chef.roles_path)
|
74
|
+
end
|
75
|
+
|
76
|
+
def cookbook_path(i)
|
77
|
+
folder_path("cookbooks", i)
|
78
|
+
end
|
79
|
+
|
80
|
+
def role_path(i)
|
81
|
+
folder_path("roles", i)
|
82
|
+
end
|
83
|
+
|
84
|
+
def cookbooks_path
|
85
|
+
folders_path(host_cookbook_paths, "cookbooks")
|
86
|
+
end
|
87
|
+
|
88
|
+
def roles_path
|
89
|
+
folders_path(host_role_paths, "roles")
|
90
|
+
end
|
65
91
|
end
|
66
92
|
end
|
67
|
-
end
|
93
|
+
end
|
data/lib/vagrant/ssh.rb
CHANGED
@@ -1,68 +1,117 @@
|
|
1
1
|
module Vagrant
|
2
|
+
# Manages SSH access to a specific environment. Allows an environment to
|
3
|
+
# replace the process with SSH itself, run a specific set of commands,
|
4
|
+
# upload files, or even check if a host is up.
|
2
5
|
class SSH
|
3
6
|
include Vagrant::Util
|
4
7
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
# Reference back up to the environment which this SSH object belongs
|
9
|
+
# to
|
10
|
+
attr_accessor :env
|
11
|
+
|
12
|
+
def initialize(environment)
|
13
|
+
@env = environment
|
14
|
+
end
|
11
15
|
|
12
|
-
|
16
|
+
# Connects to the environment's virtual machine, replacing the ruby
|
17
|
+
# process with an SSH process. This method optionally takes a hash
|
18
|
+
# of options which override the configuration values.
|
19
|
+
def connect(opts={})
|
20
|
+
if Mario::Platform.windows?
|
21
|
+
error_and_exit(:ssh_unavailable_windows,
|
22
|
+
:key_path => env.config.ssh.private_key_path,
|
23
|
+
:ssh_port => port(opts))
|
13
24
|
end
|
14
25
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
opts.merge( :port => port,
|
19
|
-
:keys => [Vagrant.config.ssh.private_key_path])) do |ssh|
|
20
|
-
yield ssh
|
21
|
-
end
|
26
|
+
options = {}
|
27
|
+
[:host, :username, :private_key_path].each do |param|
|
28
|
+
options[param] = opts[param] || env.config.ssh.send(param)
|
22
29
|
end
|
23
30
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
31
|
+
check_key_permissions(options[:private_key_path])
|
32
|
+
|
33
|
+
# Some hackery going on here. On Mac OS X Leopard (10.5), exec fails
|
34
|
+
# (GH-51). As a workaround, we fork and wait. On all other platforms,
|
35
|
+
# we simply exec.
|
36
|
+
pid = nil
|
37
|
+
pid = fork if Util::Platform.leopard?
|
38
|
+
Kernel.exec "ssh -p #{port(opts)} -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i #{options[:private_key_path]} #{options[:username]}@#{options[:host]}".strip if pid.nil?
|
39
|
+
Process.wait(pid) if pid
|
40
|
+
end
|
41
|
+
|
42
|
+
# Opens an SSH connection to this environment's virtual machine and yields
|
43
|
+
# a Net::SSH object which can be used to execute remote commands.
|
44
|
+
def execute(opts={})
|
45
|
+
Net::SSH.start(env.config.ssh.host,
|
46
|
+
env.config[:ssh][:username],
|
47
|
+
opts.merge( :port => port,
|
48
|
+
:keys => [env.config.ssh.private_key_path])) do |ssh|
|
49
|
+
yield ssh
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Uploads a file from `from` to `to`. `from` is expected to be a filename
|
54
|
+
# or StringIO, and `to` is expected to be a path. This method simply forwards
|
55
|
+
# the arguments to `Net::SCP#upload!` so view that for more information.
|
56
|
+
def upload!(from, to)
|
57
|
+
execute do |ssh|
|
58
|
+
scp = Net::SCP.new(ssh)
|
59
|
+
scp.upload!(from, to)
|
29
60
|
end
|
61
|
+
end
|
30
62
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
63
|
+
# Checks if this environment's machine is up (i.e. responding to SSH).
|
64
|
+
#
|
65
|
+
# @return [Boolean]
|
66
|
+
def up?
|
67
|
+
check_thread = Thread.new do
|
68
|
+
begin
|
69
|
+
Thread.current[:result] = false
|
70
|
+
execute(:timeout => env.config.ssh.timeout) do |ssh|
|
71
|
+
Thread.current[:result] = true
|
40
72
|
end
|
73
|
+
rescue Errno::ECONNREFUSED, Net::SSH::Disconnect
|
74
|
+
# False, its defaulted above
|
41
75
|
end
|
76
|
+
end
|
42
77
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
the two most common are: private key path is incorrect or you're using a box
|
49
|
-
which was built for Vagrant 0.1.x.
|
78
|
+
check_thread.join(env.config.ssh.timeout)
|
79
|
+
return check_thread[:result]
|
80
|
+
rescue Net::SSH::AuthenticationFailed
|
81
|
+
error_and_exit(:vm_ssh_auth_failed)
|
82
|
+
end
|
50
83
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
84
|
+
# Checks the file permissions for the private key, resetting them
|
85
|
+
# if needed, or on failure erroring.
|
86
|
+
def check_key_permissions(key_path)
|
87
|
+
# TODO: This only works on unix based systems for now. Windows
|
88
|
+
# systems will need to be investigated further.
|
89
|
+
stat = File.stat(key_path)
|
55
90
|
|
56
|
-
|
91
|
+
if stat.owned? && file_perms(key_path) != "600"
|
92
|
+
logger.info "Permissions on private key incorrect, fixing..."
|
93
|
+
File.chmod(0600, key_path)
|
57
94
|
|
58
|
-
|
59
|
-
the path to the private key is incorrect. Check your `config.ssh.private_key_path`.
|
60
|
-
msg
|
95
|
+
error_and_exit(:ssh_bad_permissions, :key_path => key_path) if file_perms(key_path) != "600"
|
61
96
|
end
|
97
|
+
rescue Errno::EPERM
|
98
|
+
# This shouldn't happen since we verify we own the file, but just
|
99
|
+
# in case.
|
100
|
+
error_and_exit(:ssh_bad_permissions, :key_path => key_path)
|
101
|
+
end
|
62
102
|
|
63
|
-
|
64
|
-
|
65
|
-
|
103
|
+
# Returns the file permissions of a given file. This is fairly unix specific
|
104
|
+
# and probably doesn't belong in this class. Will be refactored out later.
|
105
|
+
def file_perms(path)
|
106
|
+
perms = sprintf("%o", File.stat(path).mode)
|
107
|
+
perms.reverse[0..2].reverse
|
108
|
+
end
|
109
|
+
|
110
|
+
# Returns the port which is either given in the options hash or taken from
|
111
|
+
# the config by finding it in the forwarded ports hash based on the
|
112
|
+
# `config.ssh.forwarded_port_key`
|
113
|
+
def port(opts={})
|
114
|
+
opts[:port] || env.config.vm.forwarded_ports[env.config.ssh.forwarded_port_key][:hostport]
|
66
115
|
end
|
67
116
|
end
|
68
117
|
end
|
data/lib/vagrant/util.rb
CHANGED
@@ -10,12 +10,12 @@ module Vagrant
|
|
10
10
|
puts "====================================================================="
|
11
11
|
end
|
12
12
|
|
13
|
-
def error_and_exit(
|
13
|
+
def error_and_exit(key, data = {})
|
14
14
|
abort <<-error
|
15
15
|
=====================================================================
|
16
16
|
Vagrant experienced an error!
|
17
17
|
|
18
|
-
#{
|
18
|
+
#{Errors.error_string(key, data).chomp}
|
19
19
|
=====================================================================
|
20
20
|
error
|
21
21
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Vagrant
|
4
|
+
module Util
|
5
|
+
# This class is responsible for outputting errors. It retrieves the errors,
|
6
|
+
# based on their key, from the error file, and then outputs it.
|
7
|
+
class Errors
|
8
|
+
@@errors = nil
|
9
|
+
|
10
|
+
class <<self
|
11
|
+
# Resets the internal errors hash to nil, forcing a reload on the next
|
12
|
+
# access of {errors}.
|
13
|
+
def reset!
|
14
|
+
@@errors = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns the hash of errors from the error YML files. This only loads once,
|
18
|
+
# then returns a cached value until {reset!} is called.
|
19
|
+
#
|
20
|
+
# @return [Hash]
|
21
|
+
def errors
|
22
|
+
@@errors ||= YAML.load_file(File.join(PROJECT_ROOT, "templates", "errors.yml"))
|
23
|
+
end
|
24
|
+
|
25
|
+
# Renders the error with the given key and data parameters and returns
|
26
|
+
# the rendered result.
|
27
|
+
#
|
28
|
+
# @return [String]
|
29
|
+
def error_string(key, data = {})
|
30
|
+
template = errors[key] || "Unknown error key: #{key}"
|
31
|
+
TemplateRenderer.render_string(template, data)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module Util
|
3
|
+
# A mixin which allows any class to be able to show a "progress meter"
|
4
|
+
# to standard out. The progress meter shows the progress of an operation
|
5
|
+
# with console-animated text in stdout.
|
6
|
+
module ProgressMeter
|
7
|
+
# Updates the progress meter with the given progress amount and total.
|
8
|
+
# This method will do the math to figure out a percentage and show it
|
9
|
+
# within stdout.
|
10
|
+
#
|
11
|
+
# @param [Float] progress Progress
|
12
|
+
# @param [Float] total Total
|
13
|
+
def update_progress(progress, total, show_parts=true)
|
14
|
+
percent = (progress.to_f / total.to_f) * 100
|
15
|
+
print "#{cl_reset}Progress: #{percent.to_i}%"
|
16
|
+
print " (#{progress} / #{total})" if show_parts
|
17
|
+
$stdout.flush
|
18
|
+
end
|
19
|
+
|
20
|
+
# Completes the progress meter by resetting it off of the screen.
|
21
|
+
def complete_progress
|
22
|
+
# Just clear the line back out
|
23
|
+
print "#{cl_reset}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def cl_reset
|
27
|
+
reset = "\r"
|
28
|
+
reset += "\e[0K" unless Mario::Platform.windows?
|
29
|
+
reset
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module Util
|
3
|
+
# Represents the "stacked proc runner" behavior which is used a
|
4
|
+
# couple places within Vagrant. This allows procs to "stack" on
|
5
|
+
# each other, then all execute in a single action. An example of
|
6
|
+
# its uses can be seen in the {Config} class.
|
7
|
+
module StackedProcRunner
|
8
|
+
# Returns the proc stack. This should always be called as the
|
9
|
+
# accessor of the stack. The instance variable itself should _never_
|
10
|
+
# be used.
|
11
|
+
#
|
12
|
+
# @return [Array<Proc>]
|
13
|
+
def proc_stack
|
14
|
+
@_proc_stack ||= []
|
15
|
+
end
|
16
|
+
|
17
|
+
# Adds (pushes) a proc to the stack. The actual proc added here is
|
18
|
+
# not executed, but merely stored.
|
19
|
+
#
|
20
|
+
# @param [Proc] block
|
21
|
+
def push_proc(&block)
|
22
|
+
proc_stack << block
|
23
|
+
end
|
24
|
+
|
25
|
+
# Executes all the procs on the stack, passing in the given arguments.
|
26
|
+
# The stack is not cleared afterwords. It is up to the user of this
|
27
|
+
# mixin to clear the stack by calling `proc_stack.clear`.
|
28
|
+
def run_procs!(*args)
|
29
|
+
proc_stack.each do |proc|
|
30
|
+
proc.call(*args)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'erb'
|
3
|
+
|
4
|
+
module Vagrant
|
5
|
+
module Util
|
6
|
+
# This class is used to render the ERB templates in the
|
7
|
+
# `GEM_ROOT/templates` directory.
|
8
|
+
class TemplateRenderer < OpenStruct
|
9
|
+
class <<self
|
10
|
+
# Render a given template and return the result. This method optionally
|
11
|
+
# takes a block which will be passed the renderer prior to rendering, which
|
12
|
+
# allows the caller to set any view variables within the renderer itself.
|
13
|
+
#
|
14
|
+
# @return [String] Rendered template
|
15
|
+
def render(*args)
|
16
|
+
render_with(:render, *args)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Render a given string and return the result. This method optionally
|
20
|
+
# takes a block which will be passed the renderer prior to rendering, which
|
21
|
+
# allows the caller to set any view variables within the renderer itself.
|
22
|
+
#
|
23
|
+
# @param [String] template The template data string.
|
24
|
+
# @return [String] Rendered template
|
25
|
+
def render_string(*args)
|
26
|
+
render_with(:render_string, *args)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Method used internally to DRY out the other renderers. This method
|
30
|
+
# creates and sets up the renderer before calling a specified method on it.
|
31
|
+
def render_with(method, template, data={})
|
32
|
+
renderer = new(template, data)
|
33
|
+
yield renderer if block_given?
|
34
|
+
renderer.send(method.to_sym)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize(template, data = {})
|
39
|
+
super()
|
40
|
+
|
41
|
+
data[:template] = template
|
42
|
+
data.each do |key, value|
|
43
|
+
send("#{key}=", value)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Renders the template using the class intance as the binding. Because the
|
48
|
+
# renderer inherits from `OpenStruct`, additional view variables can be
|
49
|
+
# added like normal accessors.
|
50
|
+
#
|
51
|
+
# @return [String]
|
52
|
+
def render
|
53
|
+
# TODO: Seems like a pretty dirty way to do this. Perhaps refactor this
|
54
|
+
old_template = template
|
55
|
+
result = nil
|
56
|
+
File.open(full_template_path, 'r') do |f|
|
57
|
+
self.template = f.read
|
58
|
+
result = render_string
|
59
|
+
end
|
60
|
+
|
61
|
+
result
|
62
|
+
ensure
|
63
|
+
self.template = old_template
|
64
|
+
end
|
65
|
+
|
66
|
+
# Renders a template, handling the template as a string, but otherwise
|
67
|
+
# acting the same way as {#render}.
|
68
|
+
#
|
69
|
+
# @return [String]
|
70
|
+
def render_string
|
71
|
+
ERB.new(template).result(binding)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns the full path to the template, taking into accoun the gem directory
|
75
|
+
# and adding the `.erb` extension to the end.
|
76
|
+
#
|
77
|
+
# @return [String]
|
78
|
+
def full_template_path
|
79
|
+
File.join(PROJECT_ROOT, 'templates', "#{template}.erb")
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|