linecook 1.2.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/{History → History.rdoc} +3 -2
- data/README.rdoc +93 -0
- data/bin/linecook +32 -56
- data/bin/linecook_run +19 -6
- data/bin/linecook_scp +12 -4
- data/doc/vm_setup.rdoc +75 -0
- data/lib/linecook.rb +3 -2
- data/lib/linecook/attributes.rb +33 -8
- data/lib/linecook/command.rb +61 -0
- data/lib/linecook/command_set.rb +85 -0
- data/lib/linecook/command_utils.rb +20 -0
- data/lib/linecook/commands/build.rb +108 -57
- data/lib/linecook/commands/compile.rb +181 -0
- data/lib/linecook/commands/{helper.rb → compile_helper.rb} +123 -94
- data/lib/linecook/commands/run.rb +43 -39
- data/lib/linecook/commands/snapshot.rb +24 -24
- data/lib/linecook/commands/ssh.rb +7 -7
- data/lib/linecook/commands/start.rb +10 -10
- data/lib/linecook/commands/state.rb +7 -7
- data/lib/linecook/commands/stop.rb +3 -3
- data/lib/linecook/commands/{vbox_command.rb → virtual_box_command.rb} +31 -29
- data/lib/linecook/cookbook.rb +149 -131
- data/lib/linecook/executable.rb +28 -0
- data/lib/linecook/package.rb +177 -361
- data/lib/linecook/proxy.rb +4 -10
- data/lib/linecook/recipe.rb +289 -369
- data/lib/linecook/test.rb +114 -98
- data/lib/linecook/utils.rb +31 -41
- data/lib/linecook/version.rb +2 -6
- metadata +120 -68
- data/HowTo/Control Virtual Machines +0 -106
- data/HowTo/Generate Scripts +0 -268
- data/HowTo/Run Scripts +0 -87
- data/HowTo/Setup Virtual Machines +0 -76
- data/README +0 -117
- data/lib/linecook/commands.rb +0 -11
- data/lib/linecook/commands/command.rb +0 -58
- data/lib/linecook/commands/command_error.rb +0 -12
- data/lib/linecook/commands/env.rb +0 -89
- data/lib/linecook/commands/init.rb +0 -86
- data/lib/linecook/commands/package.rb +0 -57
- data/lib/linecook/template.rb +0 -17
- data/lib/linecook/test/command_parser.rb +0 -75
- data/lib/linecook/test/file_test.rb +0 -197
- data/lib/linecook/test/regexp_escape.rb +0 -86
- data/lib/linecook/test/shell_test.rb +0 -177
- data/lib/linecook/test/shim.rb +0 -71
- data/templates/Gemfile +0 -3
- data/templates/Rakefile +0 -146
- data/templates/_gitignore +0 -4
- data/templates/attributes/project_name.rb +0 -3
- data/templates/config/ssh +0 -14
- data/templates/cookbook +0 -10
- data/templates/files/example.txt +0 -1
- data/templates/helpers/project_name/echo.erb +0 -4
- data/templates/packages/abox.yml +0 -2
- data/templates/project_name.gemspec +0 -30
- data/templates/recipes/abox.rb +0 -16
- data/templates/templates/example.erb +0 -1
- data/templates/test/project_name_test.rb +0 -24
- data/templates/test/test_helper.rb +0 -14
@@ -1,8 +1,8 @@
|
|
1
|
-
require 'linecook/commands/
|
1
|
+
require 'linecook/commands/virtual_box_command'
|
2
2
|
|
3
3
|
module Linecook
|
4
4
|
module Commands
|
5
|
-
|
5
|
+
|
6
6
|
# :startdoc::desc take a vm snapshop
|
7
7
|
#
|
8
8
|
# Takes the specified snapshot of one or more VirtualBox virtual machines.
|
@@ -20,14 +20,14 @@ module Linecook
|
|
20
20
|
#
|
21
21
|
# To reset:
|
22
22
|
#
|
23
|
-
#
|
23
|
+
# linecook snapshot --reset CURRENT
|
24
24
|
#
|
25
25
|
# After which there will only be a single 'CURRENT' snapshot, which
|
26
26
|
# corresponds to the original snapshot.
|
27
27
|
#
|
28
|
-
class Snapshot <
|
29
|
-
config :reset, false,
|
30
|
-
|
28
|
+
class Snapshot < VirtualBoxCommand
|
29
|
+
config :reset, false # -r, --reset : reset a snapshot
|
30
|
+
|
31
31
|
def process(snapshot, *hosts)
|
32
32
|
vm_names = resolve_vm_names(hosts)
|
33
33
|
each_vm_name(vm_names) do |vm_name|
|
@@ -38,75 +38,75 @@ module Linecook
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
def parse_snapshots(vm_name)
|
43
43
|
info = `VBoxManage -q showvminfo #{vm_name}`
|
44
44
|
snapshots = {}
|
45
|
-
|
45
|
+
|
46
46
|
stack = [{}]
|
47
47
|
parent = nil
|
48
|
-
|
48
|
+
|
49
49
|
info.each_line do |line|
|
50
50
|
next unless line =~ /^(\s+)Name\: (.*?) \(/
|
51
51
|
depth = $1.length / 3
|
52
52
|
name = $2
|
53
|
-
|
53
|
+
|
54
54
|
if depth > stack.length
|
55
55
|
stack.push stack.last[parent]
|
56
56
|
elsif depth < stack.length
|
57
57
|
stack.pop
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
snapshot = {}
|
61
61
|
snapshots[name] = snapshot
|
62
62
|
stack.last[name] = snapshot
|
63
63
|
parent = name
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
snapshots
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
69
|
def reset_snapshot(vm_name, snapshot)
|
70
70
|
stop(vm_name) if running?(vm_name)
|
71
|
-
|
71
|
+
|
72
72
|
snapshot = snapshot.upcase
|
73
73
|
restore(vm_name, snapshot)
|
74
|
-
|
74
|
+
|
75
75
|
snapshots = parse_snapshots(vm_name)
|
76
76
|
parent = snapshots.keys.select {|key| key =~ /\A#{snapshot}(?:_\d+)\z/ }.first
|
77
77
|
parent ||= snapshot
|
78
|
-
|
78
|
+
|
79
79
|
children = snapshots[parent]
|
80
80
|
children.each do |key, value|
|
81
81
|
inside_out_each(key, value) do |child|
|
82
82
|
sh! "VBoxManage -q snapshot #{vm_name} delete #{child}"
|
83
83
|
end
|
84
84
|
end
|
85
|
-
|
85
|
+
|
86
86
|
unless parent == snapshot
|
87
87
|
sh! "VBoxManage -q snapshot #{vm_name} edit #{parent} --name #{snapshot}"
|
88
88
|
end
|
89
89
|
end
|
90
|
-
|
90
|
+
|
91
91
|
def snapshot(vm_name, snapshot)
|
92
92
|
snapshot = snapshot.upcase
|
93
93
|
snapshots = parse_snapshots(vm_name)
|
94
|
-
|
94
|
+
|
95
95
|
count = snapshots.keys.grep(/\A#{snapshot}(?:_|\z)/).length
|
96
96
|
if count > 0
|
97
97
|
sh! "VBoxManage -q snapshot #{vm_name} edit #{snapshot} --name #{snapshot}_#{count - 1}"
|
98
98
|
end
|
99
|
-
|
100
|
-
sh! "VBoxManage -q snapshot #{vm_name} take #{snapshot}"
|
99
|
+
|
100
|
+
sh! "VBoxManage -q snapshot #{vm_name} take #{snapshot} --pause"
|
101
101
|
end
|
102
|
-
|
102
|
+
|
103
103
|
private
|
104
|
-
|
104
|
+
|
105
105
|
def inside_out_each(key, value, &block) # :nodoc:
|
106
106
|
value.each_pair do |k, v|
|
107
107
|
inside_out_each(k, v, &block)
|
108
108
|
end
|
109
|
-
|
109
|
+
|
110
110
|
yield(key)
|
111
111
|
end
|
112
112
|
end
|
@@ -1,24 +1,24 @@
|
|
1
|
-
require 'linecook/commands/
|
1
|
+
require 'linecook/commands/virtual_box_command'
|
2
2
|
|
3
3
|
module Linecook
|
4
4
|
module Commands
|
5
|
-
|
5
|
+
|
6
6
|
# :startdoc::desc ssh to a vm
|
7
7
|
#
|
8
8
|
# Connects to a virtual machine using ssh, as configured in config/ssh.
|
9
|
-
#
|
10
|
-
class Ssh <
|
9
|
+
#
|
10
|
+
class Ssh < VirtualBoxCommand
|
11
11
|
undef_config :names
|
12
|
-
|
12
|
+
|
13
13
|
def default_host
|
14
14
|
load_hosts(ssh_config_file).collect {|host, vm_name| host }.first
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def process(host=default_host)
|
18
18
|
if host.to_s.strip.empty?
|
19
19
|
raise CommandError.new("no host specified")
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
ssh = "ssh -F '#{ssh_config_file}' '#{host}' --"
|
23
23
|
|
24
24
|
# Patterned after vagrant/ssh.rb (circa 0.6.6)
|
@@ -1,18 +1,18 @@
|
|
1
|
-
require 'linecook/commands/
|
1
|
+
require 'linecook/commands/virtual_box_command'
|
2
2
|
|
3
3
|
module Linecook
|
4
4
|
module Commands
|
5
|
-
|
5
|
+
|
6
6
|
# :startdoc::desc start a vm
|
7
7
|
#
|
8
8
|
# Starts one or more VirtualBox virtual machines, and resets to a snapshot
|
9
9
|
# if provided. By default all virtual machines configured in config/ssh
|
10
10
|
# will be reset and started in this way.
|
11
|
-
class Start <
|
12
|
-
config :type, 'headless'
|
13
|
-
config :snapshot, ''
|
14
|
-
config :
|
15
|
-
|
11
|
+
class Start < VirtualBoxCommand
|
12
|
+
config :type, 'headless' # vm type (headless|gui)
|
13
|
+
config :snapshot, '' # start snapshot
|
14
|
+
config :use_master_socket, false # -m, --master-socket : use a master socket
|
15
|
+
|
16
16
|
def process(*hosts)
|
17
17
|
vm_names = resolve_vm_names(hosts)
|
18
18
|
each_vm_name(vm_names) do |vm_name|
|
@@ -20,13 +20,13 @@ module Linecook
|
|
20
20
|
stop(vm_name)
|
21
21
|
sleep 0.5
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
unless snapshot.empty?
|
25
25
|
restore(vm_name, snapshot)
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
start(vm_name, type)
|
29
|
-
start_ssh_socket(vm_name) if
|
29
|
+
start_ssh_socket(vm_name) if use_master_socket
|
30
30
|
end
|
31
31
|
end
|
32
32
|
end
|
@@ -1,20 +1,20 @@
|
|
1
|
-
require 'linecook/commands/
|
1
|
+
require 'linecook/commands/virtual_box_command'
|
2
2
|
|
3
3
|
module Linecook
|
4
4
|
module Commands
|
5
|
-
|
6
|
-
# :startdoc::desc print
|
5
|
+
|
6
|
+
# :startdoc::desc print a vm state
|
7
7
|
#
|
8
8
|
# Prints the state of one or more VirtualBox virtual machines. By default
|
9
9
|
# all virtual machines configured in config/ssh will print their state.
|
10
10
|
#
|
11
|
-
class State <
|
12
|
-
config :hosts, false,
|
13
|
-
|
11
|
+
class State < VirtualBoxCommand
|
12
|
+
config :hosts, false # -s, --hosts : print state by host
|
13
|
+
|
14
14
|
def state(vm_name)
|
15
15
|
`VBoxManage showvminfo #{vm_name}` =~ /^State:\s+(.*)$/ ? $1 : 'unknown'
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
def process(*hosts)
|
19
19
|
vm_names = resolve_vm_names(hosts)
|
20
20
|
if hosts
|
@@ -1,14 +1,14 @@
|
|
1
|
-
require 'linecook/commands/
|
1
|
+
require 'linecook/commands/virtual_box_command'
|
2
2
|
|
3
3
|
module Linecook
|
4
4
|
module Commands
|
5
|
-
|
5
|
+
|
6
6
|
# :startdoc::desc stop a vm
|
7
7
|
#
|
8
8
|
# Stops one or more VirtualBox virtual machines using 'poweroff'. By
|
9
9
|
# default all virtual machines configured in config/ssh will be stopped.
|
10
10
|
#
|
11
|
-
class Stop <
|
11
|
+
class Stop < VirtualBoxCommand
|
12
12
|
def process(*hosts)
|
13
13
|
vm_names = resolve_vm_names(hosts)
|
14
14
|
each_vm_name(vm_names) do |vm_name|
|
@@ -1,14 +1,16 @@
|
|
1
|
-
require 'linecook/
|
1
|
+
require 'linecook/command'
|
2
|
+
require 'linecook/command_utils'
|
2
3
|
|
3
4
|
module Linecook
|
4
5
|
module Commands
|
5
|
-
class
|
6
|
-
|
7
|
-
|
8
|
-
config :ssh_config_file, 'config/ssh',
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
class VirtualBoxCommand < Command
|
7
|
+
include CommandUtils
|
8
|
+
|
9
|
+
config :ssh_config_file, 'config/ssh', { # -F FILE : the ssh config file
|
10
|
+
:writer => :ssh_config_file=
|
11
|
+
}
|
12
|
+
config :names, false # -n, --names : use vm names
|
13
|
+
|
12
14
|
# Matches a host declaration in a ssh config file. After the match:
|
13
15
|
#
|
14
16
|
# $1:: The host name
|
@@ -17,7 +19,7 @@ module Linecook
|
|
17
19
|
# (ex: 'Host name # [vm_name]' => 'vm_name')
|
18
20
|
#
|
19
21
|
HOST_REGEXP = /^\s*Host\s+([^\s#]+)(?:\s*#\s*\[(.*?)\])?/
|
20
|
-
|
22
|
+
|
21
23
|
# Returns a hash of (host, vm_name) pairs as declared in a ssh config
|
22
24
|
# file. Basically this means parsing out the name in each config like:
|
23
25
|
#
|
@@ -30,7 +32,7 @@ module Linecook
|
|
30
32
|
#
|
31
33
|
def load_hosts(ssh_config_file)
|
32
34
|
hosts = []
|
33
|
-
|
35
|
+
|
34
36
|
File.open(ssh_config_file) do |io|
|
35
37
|
io.each_line do |line|
|
36
38
|
next unless line =~ HOST_REGEXP
|
@@ -38,90 +40,90 @@ module Linecook
|
|
38
40
|
hosts << [$1, $2 || $1]
|
39
41
|
end
|
40
42
|
end
|
41
|
-
|
43
|
+
|
42
44
|
hosts
|
43
45
|
end
|
44
|
-
|
46
|
+
|
45
47
|
def ssh_config_file=(ssh_config_file)
|
46
48
|
@ssh_config_file = ssh_config_file
|
47
49
|
@host_list = nil
|
48
50
|
@host_map = nil
|
49
51
|
end
|
50
|
-
|
52
|
+
|
51
53
|
def host_list
|
52
54
|
@host_list ||= load_hosts(ssh_config_file)
|
53
55
|
end
|
54
|
-
|
56
|
+
|
55
57
|
def host_map
|
56
58
|
@host_map ||= Hash[*host_list.flatten]
|
57
59
|
end
|
58
|
-
|
60
|
+
|
59
61
|
def resolve_vm_names(hosts)
|
60
62
|
names ? hosts : hosts.collect {|host| host_map[host] || host }
|
61
63
|
end
|
62
|
-
|
64
|
+
|
63
65
|
def each_host(hosts=[])
|
64
66
|
if hosts.empty?
|
65
67
|
hosts = host_list.collect {|host, vm_name| host }
|
66
68
|
hosts.delete('*')
|
67
69
|
end
|
68
|
-
|
70
|
+
|
69
71
|
hosts.uniq.each do |host|
|
70
72
|
yield(host)
|
71
73
|
end
|
72
74
|
end
|
73
|
-
|
75
|
+
|
74
76
|
def each_vm_name(vm_names=[])
|
75
77
|
if vm_names.empty?
|
76
78
|
vm_names = host_list.collect {|host, vm_name| vm_name }
|
77
79
|
vm_names.delete('*')
|
78
80
|
end
|
79
|
-
|
81
|
+
|
80
82
|
vm_names.uniq.each do |vm_name|
|
81
83
|
yield(vm_name)
|
82
84
|
end
|
83
85
|
end
|
84
|
-
|
86
|
+
|
85
87
|
def ssh(host, cmd)
|
86
88
|
sh "ssh -q -F '#{ssh_config_file}' '#{host}' -- #{cmd}"
|
87
89
|
end
|
88
|
-
|
90
|
+
|
89
91
|
def ssh!(host, cmd)
|
90
92
|
unless ssh(host, cmd)
|
91
93
|
raise CommandError, "non-zero exit status: #{$?.exitstatus}"
|
92
94
|
end
|
93
95
|
end
|
94
|
-
|
96
|
+
|
95
97
|
def running?(vm_name)
|
96
98
|
`VBoxManage -q list runningvms`.include?(vm_name)
|
97
99
|
end
|
98
|
-
|
100
|
+
|
99
101
|
def start(vm_name, type='headless')
|
100
102
|
sh! "VBoxManage -q startvm #{vm_name} --type #{type}"
|
101
103
|
end
|
102
|
-
|
104
|
+
|
103
105
|
def stop(vm_name)
|
104
106
|
sh! "VBoxManage -q controlvm #{vm_name} poweroff"
|
105
107
|
end
|
106
|
-
|
108
|
+
|
107
109
|
def restore(vm_name, snapshot)
|
108
110
|
sh! "VBoxManage -q snapshot #{vm_name} restore #{snapshot.upcase}"
|
109
111
|
end
|
110
|
-
|
112
|
+
|
111
113
|
def discardstate(vm_name)
|
112
114
|
sh! "VBoxManage discardstate #{vm_name}"
|
113
115
|
end
|
114
|
-
|
116
|
+
|
115
117
|
def share(vm_name, name, local_dir, remote_dir)
|
116
118
|
share_dir = "#{local_dir}/#{vm_name}"
|
117
119
|
FileUtils.mkdir_p(share_dir) unless File.exists?(share_dir)
|
118
|
-
|
120
|
+
|
119
121
|
ssh vm_name, "sudo umount '#{remote_dir}' > /dev/null 2>&1"
|
120
122
|
sh "VBoxManage sharedfolder remove '#{vm_name}' --name '#{name}' --transient > /dev/null 2>&1"
|
121
123
|
sh! "VBoxManage sharedfolder add '#{vm_name}' --name '#{name}' --hostpath '#{share_dir}' --transient"
|
122
124
|
ssh! vm_name, "sudo mount -t vboxsf -o uid=1000,gid=100 '#{name}' '#{remote_dir}'"
|
123
125
|
end
|
124
|
-
|
126
|
+
|
125
127
|
def start_ssh_socket(vm_name)
|
126
128
|
sh "ssh -MNf -F '#{ssh_config_file}' '#{vm_name}' >/dev/null 2>&1 </dev/null"
|
127
129
|
end
|
data/lib/linecook/cookbook.rb
CHANGED
@@ -1,160 +1,178 @@
|
|
1
|
-
require 'linecook/utils'
|
2
|
-
require 'lazydoc'
|
3
|
-
|
4
1
|
module Linecook
|
5
2
|
class Cookbook
|
6
3
|
class << self
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
config[PATHS_KEY] ||= [project_dir]
|
17
|
-
config[GEMS_KEY] ||= gems
|
18
|
-
|
19
|
-
new(config, project_dir)
|
4
|
+
attr_writer :default_path_map
|
5
|
+
def default_path_map
|
6
|
+
@default_path_map ||= {
|
7
|
+
:attributes => ['attributes'],
|
8
|
+
:files => ['files'],
|
9
|
+
:templates => ['templates'],
|
10
|
+
:recipes => ['recipes']
|
11
|
+
}
|
20
12
|
end
|
21
|
-
|
22
|
-
|
23
|
-
|
13
|
+
|
14
|
+
attr_writer :default_file_name
|
15
|
+
def default_file_name
|
16
|
+
@default_file_name ||= 'cookbook.yml'
|
24
17
|
end
|
25
|
-
|
26
|
-
def
|
18
|
+
|
19
|
+
def gemspecs(latest=true)
|
27
20
|
return [] unless Object.const_defined?(:Gem)
|
28
|
-
|
29
|
-
Gem.source_index
|
30
|
-
|
31
|
-
|
32
|
-
|
21
|
+
|
22
|
+
index = Gem.source_index
|
23
|
+
specs = latest ? index.latest_specs : index.gems.values
|
24
|
+
|
25
|
+
specs.select do |spec|
|
26
|
+
cookbook_file = File.expand_path(default_file_name, spec.full_gem_path)
|
27
|
+
File.exists?(cookbook_file)
|
33
28
|
end
|
34
29
|
end
|
35
30
|
end
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
attr_reader :project_dir
|
50
|
-
attr_reader :config
|
51
|
-
|
52
|
-
def initialize(config={}, project_dir='.')
|
53
|
-
@project_dir = project_dir
|
54
|
-
@config = config
|
55
|
-
end
|
56
|
-
|
57
|
-
def paths
|
58
|
-
Utils.arrayify config[PATHS_KEY]
|
59
|
-
end
|
60
|
-
|
61
|
-
def gems
|
62
|
-
Utils.arrayify config[GEMS_KEY]
|
63
|
-
end
|
64
|
-
|
65
|
-
def rewrites
|
66
|
-
config[REWRITE_KEY]
|
31
|
+
|
32
|
+
attr_reader :registry
|
33
|
+
|
34
|
+
def initialize(*project_dirs)
|
35
|
+
@registry = {}
|
36
|
+
project_dirs.each do |dir|
|
37
|
+
case dir
|
38
|
+
when String then add(dir)
|
39
|
+
when Hash then add('.', dir)
|
40
|
+
else add(*dir)
|
41
|
+
end
|
42
|
+
end
|
67
43
|
end
|
68
|
-
|
69
|
-
|
70
|
-
|
44
|
+
|
45
|
+
# Returns an array of directories comprising the path for type.
|
46
|
+
def path(type)
|
47
|
+
registry[type] || []
|
71
48
|
end
|
72
|
-
|
73
|
-
def
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
gems.collect do |name|
|
78
|
-
spec = specs[name] or raise "no such gem: #{name.inspect}"
|
79
|
-
spec.full_gem_path
|
49
|
+
|
50
|
+
def add(dir, path_map=nil)
|
51
|
+
resolve_path_map(dir, path_map).each_pair do |type, paths|
|
52
|
+
(registry[type] ||= []).concat(paths)
|
80
53
|
end
|
81
54
|
end
|
82
|
-
|
83
|
-
def
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
replacements[key] = replacement
|
55
|
+
|
56
|
+
def rm(dir, path_map=nil)
|
57
|
+
resolve_path_map(dir, path_map).each_pair do |type, paths|
|
58
|
+
if current = registry[type]
|
59
|
+
current = current - paths
|
60
|
+
if current.empty?
|
61
|
+
registry.delete(type)
|
62
|
+
else
|
63
|
+
registry[type] = current
|
64
|
+
end
|
93
65
|
end
|
94
|
-
end if rewrites
|
95
|
-
|
96
|
-
replacements.each do |key, replacement|
|
97
|
-
manifest[replacement] = manifest.delete(key)
|
98
66
|
end
|
99
|
-
|
100
|
-
manifest
|
101
67
|
end
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
manifest[type][name] = full_path
|
68
|
+
|
69
|
+
# Same as find but returns nil if no file can be found.
|
70
|
+
def _find_(type, filename, extnames=nil)
|
71
|
+
if type.nil? || filename.nil?
|
72
|
+
return nil
|
73
|
+
end
|
74
|
+
|
75
|
+
if absolute?(filename)
|
76
|
+
return File.exists?(filename) ? filename : nil
|
77
|
+
end
|
78
|
+
|
79
|
+
path(type).each do |dir|
|
80
|
+
each_full_path(dir, filename, extnames) do |full_path|
|
81
|
+
if File.exists?(full_path) && subpath?(dir, full_path)
|
82
|
+
return full_path
|
118
83
|
end
|
119
84
|
end
|
120
85
|
end
|
121
|
-
|
122
|
-
|
86
|
+
|
87
|
+
nil
|
88
|
+
end
|
89
|
+
|
90
|
+
# Searches for a file by expanding filename vs each directory in the path
|
91
|
+
# for type. The first existing full path is returned. If an array of
|
92
|
+
# extnames is provided, then each extname is tried for each directory,
|
93
|
+
# much as with Kernal.require. Absolute paths that exists are returned
|
94
|
+
# directly. Raises an error if the file cannot be found.
|
95
|
+
def find(type, source_name, extnames=nil)
|
96
|
+
_find_(type, source_name, extnames) or begin
|
97
|
+
case
|
98
|
+
when type.nil?
|
99
|
+
raise "could not find file: #{source_name.inspect} (nil type specified)"
|
100
|
+
when source_name.nil?
|
101
|
+
raise "could not find file: #{source_name.inspect}"
|
102
|
+
when absolute?(source_name)
|
103
|
+
raise "no such file: #{source_name.inspect}"
|
104
|
+
else
|
105
|
+
try_string = try_extnames?(source_name, extnames) ? " (tried #{extnames.join(', ')})" : nil
|
106
|
+
raise "could not find file: #{source_name.inspect}#{try_string}"
|
107
|
+
end
|
108
|
+
end
|
123
109
|
end
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
110
|
+
|
111
|
+
protected
|
112
|
+
|
113
|
+
if Dir.pwd[0] == ?/
|
114
|
+
def absolute?(path)
|
115
|
+
path && path[0] == ?/
|
130
116
|
end
|
131
|
-
|
132
|
-
|
133
|
-
|
117
|
+
else
|
118
|
+
def absolute?(path)
|
119
|
+
path && path =~ /^[A-z]:\//
|
134
120
|
end
|
135
|
-
|
136
|
-
manifest
|
137
121
|
end
|
138
|
-
|
139
|
-
def
|
140
|
-
|
141
|
-
|
142
|
-
|
122
|
+
|
123
|
+
def subpath?(dir, full_path)
|
124
|
+
full_path.index(dir) == 0
|
125
|
+
end
|
126
|
+
|
127
|
+
def try_extnames?(path, extnames)
|
128
|
+
extnames && File.extname(path).empty?
|
129
|
+
end
|
130
|
+
|
131
|
+
def each_full_path(dir, path, extnames=nil)
|
132
|
+
full_path = File.expand_path(path, dir)
|
133
|
+
yield full_path
|
134
|
+
|
135
|
+
if try_extnames?(path, extnames)
|
136
|
+
extnames.each do |extname|
|
137
|
+
full_path = File.expand_path("#{path}#{extname}", dir)
|
138
|
+
yield full_path
|
139
|
+
end
|
140
|
+
end
|
143
141
|
end
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
142
|
+
|
143
|
+
def resolve_path_map(dir, path_map=nil)
|
144
|
+
path_map ||= self.class.default_file_name
|
145
|
+
|
146
|
+
case path_map
|
147
|
+
when Hash
|
148
|
+
expand_path_map(dir, path_map)
|
149
|
+
when String
|
150
|
+
cookbook_file = File.expand_path(path_map, dir)
|
151
|
+
path_map = File.exists?(cookbook_file) ? YAML.load_file(cookbook_file) : nil
|
152
|
+
path_map ||= self.class.default_path_map
|
153
|
+
|
154
|
+
unless path_map.kind_of?(Hash)
|
155
|
+
raise "could not load path map: #{cookbook_file.inspect} (does not load a Hash)"
|
156
|
+
end
|
157
|
+
|
158
|
+
expand_path_map(dir, path_map)
|
159
|
+
else
|
160
|
+
raise "could not resolve path map: #{path_map.inspect} (must be String, Hash, or nil)"
|
161
|
+
end
|
150
162
|
end
|
151
|
-
|
152
|
-
def
|
153
|
-
|
154
|
-
|
155
|
-
|
163
|
+
|
164
|
+
def expand_path_map(dir, path_map)
|
165
|
+
results = Hash.new {|hash, key| hash[key] = [] }
|
166
|
+
|
167
|
+
path_map.each_pair do |type, paths|
|
168
|
+
unless paths.kind_of?(Array)
|
169
|
+
paths = [paths]
|
170
|
+
end
|
171
|
+
paths.each do |path|
|
172
|
+
results[type.to_sym] << File.expand_path(path, dir)
|
173
|
+
end
|
156
174
|
end
|
157
|
-
|
175
|
+
results
|
158
176
|
end
|
159
177
|
end
|
160
178
|
end
|