linecook 0.6.2 → 1.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 +139 -0
- data/HowTo/Control Virtual Machines +106 -0
- data/HowTo/Generate Scripts +263 -0
- data/HowTo/Run Scripts +87 -0
- data/HowTo/Setup Virtual Machines +76 -0
- data/License.txt +1 -1
- data/README +78 -59
- data/bin/linecook +12 -5
- data/bin/linecook_run +45 -0
- data/bin/linecook_scp +50 -0
- data/lib/linecook.rb +1 -3
- data/lib/linecook/attributes.rb +49 -12
- data/lib/linecook/commands.rb +9 -4
- data/lib/linecook/commands/build.rb +69 -0
- data/lib/linecook/commands/command.rb +13 -3
- data/lib/linecook/commands/command_error.rb +6 -0
- data/lib/linecook/commands/env.rb +74 -8
- data/lib/linecook/commands/helper.rb +271 -24
- data/lib/linecook/commands/init.rb +10 -6
- data/lib/linecook/commands/package.rb +36 -18
- data/lib/linecook/commands/run.rb +66 -0
- data/lib/linecook/commands/snapshot.rb +114 -0
- data/lib/linecook/commands/ssh.rb +39 -0
- data/lib/linecook/commands/start.rb +34 -0
- data/lib/linecook/commands/state.rb +32 -0
- data/lib/linecook/commands/stop.rb +22 -0
- data/lib/linecook/commands/vbox_command.rb +130 -0
- data/lib/linecook/cookbook.rb +112 -55
- data/lib/linecook/package.rb +293 -109
- data/lib/linecook/proxy.rb +19 -0
- data/lib/linecook/recipe.rb +321 -62
- data/lib/linecook/template.rb +7 -101
- data/lib/linecook/test.rb +196 -141
- data/lib/linecook/test/command_parser.rb +75 -0
- data/lib/linecook/test/file_test.rb +153 -35
- data/lib/linecook/test/shell_test.rb +176 -0
- data/lib/linecook/utils.rb +25 -7
- data/lib/linecook/version.rb +4 -4
- data/templates/Rakefile +44 -47
- data/templates/_gitignore +1 -1
- data/templates/attributes/project_name.rb +4 -4
- data/templates/config/ssh +15 -0
- data/templates/files/help.txt +1 -0
- data/templates/helpers/project_name/assert_content_equal.erb +15 -0
- data/templates/helpers/project_name/create_dir.erb +9 -0
- data/templates/helpers/project_name/create_file.erb +8 -0
- data/templates/helpers/project_name/install_file.erb +8 -0
- data/templates/packages/abox.yml +4 -0
- data/templates/recipes/abox.rb +22 -0
- data/templates/recipes/abox_test.rb +14 -0
- data/templates/templates/todo.txt.erb +3 -0
- data/templates/test/project_name_test.rb +19 -0
- data/templates/test/test_helper.rb +14 -0
- metadata +43 -41
- data/cookbook +0 -0
- data/lib/linecook/commands/helpers.rb +0 -28
- data/lib/linecook/commands/vbox.rb +0 -85
- data/lib/linecook/helper.rb +0 -117
- data/lib/linecook/shell.rb +0 -11
- data/lib/linecook/shell/posix.rb +0 -145
- data/lib/linecook/shell/test.rb +0 -254
- data/lib/linecook/shell/unix.rb +0 -117
- data/lib/linecook/shell/utils.rb +0 -138
- data/templates/README +0 -90
- data/templates/files/file.txt +0 -1
- data/templates/helpers/project_name/echo.erb +0 -5
- data/templates/recipes/project_name.rb +0 -20
- data/templates/scripts/project_name.yml +0 -7
- data/templates/templates/template.txt.erb +0 -3
- data/templates/vbox/setup/virtual_box +0 -86
- data/templates/vbox/ssh/id_rsa +0 -27
- data/templates/vbox/ssh/id_rsa.pub +0 -1
data/lib/linecook/cookbook.rb
CHANGED
@@ -1,18 +1,26 @@
|
|
1
|
-
require 'linecook/
|
2
|
-
require '
|
1
|
+
require 'linecook/utils'
|
2
|
+
require 'lazydoc'
|
3
3
|
|
4
4
|
module Linecook
|
5
5
|
class Cookbook
|
6
6
|
class << self
|
7
|
-
def config_file(
|
8
|
-
Dir.glob(File.join(
|
7
|
+
def config_file(project_dir='.')
|
8
|
+
Dir.glob(File.join(project_dir, '{C,c}ookbook')).first
|
9
9
|
end
|
10
|
+
|
11
|
+
def setup(config={}, project_dir='.')
|
12
|
+
unless config.kind_of?(Hash)
|
13
|
+
config = Utils.load_config(config)
|
14
|
+
end
|
10
15
|
|
11
|
-
|
12
|
-
|
13
|
-
config = path ? YAML.load_file(path) : nil
|
16
|
+
config[PATHS_KEY] ||= [project_dir]
|
17
|
+
config[GEMS_KEY] ||= gems
|
14
18
|
|
15
|
-
new(
|
19
|
+
new(config, project_dir)
|
20
|
+
end
|
21
|
+
|
22
|
+
def init(project_dir='.')
|
23
|
+
setup config_file(project_dir), project_dir
|
16
24
|
end
|
17
25
|
|
18
26
|
def gems
|
@@ -26,65 +34,44 @@ module Linecook
|
|
26
34
|
end
|
27
35
|
end
|
28
36
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
37
|
+
MANIFEST_KEY = 'manifest'
|
38
|
+
PATHS_KEY = 'paths'
|
39
|
+
GEMS_KEY = 'gems'
|
40
|
+
REWRITE_KEY = 'rewrite'
|
41
|
+
|
42
|
+
PATTERNS = {
|
43
|
+
'attributes' => ['attributes', '.rb'],
|
44
|
+
'files' => ['files'],
|
45
|
+
'recipes' => ['recipes', '.rb'],
|
46
|
+
'templates' => ['templates', '.erb']
|
47
|
+
}
|
35
48
|
|
36
|
-
attr_reader :
|
49
|
+
attr_reader :project_dir
|
37
50
|
attr_reader :config
|
38
51
|
|
39
|
-
def initialize(
|
40
|
-
@
|
41
|
-
@config =
|
42
|
-
'manifest' => {},
|
43
|
-
'paths' => ['.'],
|
44
|
-
'gems' => self.class.gems
|
45
|
-
}.merge(config)
|
52
|
+
def initialize(config={}, project_dir='.')
|
53
|
+
@project_dir = project_dir
|
54
|
+
@config = config
|
46
55
|
end
|
47
56
|
|
48
|
-
def
|
49
|
-
|
50
|
-
manifest = {}
|
51
|
-
|
52
|
-
paths = split config['paths']
|
53
|
-
gems = split config['gems']
|
54
|
-
gems = resolve gems
|
55
|
-
|
56
|
-
(gems + paths).each do |path|
|
57
|
-
path = File.expand_path(path, dir)
|
58
|
-
start = path.length + 1
|
59
|
-
|
60
|
-
PATTERNS.each do |pattern|
|
61
|
-
Dir.glob(File.join(path, pattern)).each do |full_path|
|
62
|
-
next unless File.file?(full_path)
|
63
|
-
|
64
|
-
rel_path = full_path[start, full_path.length - start]
|
65
|
-
manifest[rel_path] = full_path
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
overrides = config['manifest']
|
71
|
-
manifest.merge!(overrides)
|
72
|
-
manifest
|
73
|
-
end
|
57
|
+
def paths
|
58
|
+
Utils.arrayify config[PATHS_KEY]
|
74
59
|
end
|
75
60
|
|
76
|
-
def
|
77
|
-
|
61
|
+
def gems
|
62
|
+
Utils.arrayify config[GEMS_KEY]
|
78
63
|
end
|
79
64
|
|
80
|
-
|
65
|
+
def rewrites
|
66
|
+
config[REWRITE_KEY]
|
67
|
+
end
|
81
68
|
|
82
|
-
def
|
83
|
-
|
69
|
+
def overrides
|
70
|
+
config[MANIFEST_KEY]
|
84
71
|
end
|
85
72
|
|
86
|
-
def
|
87
|
-
return
|
73
|
+
def full_gem_paths
|
74
|
+
return [] if gems.empty?
|
88
75
|
specs = latest_specs
|
89
76
|
|
90
77
|
gems.collect do |name|
|
@@ -93,6 +80,76 @@ module Linecook
|
|
93
80
|
end
|
94
81
|
end
|
95
82
|
|
83
|
+
def rewrite(manifest)
|
84
|
+
replacements = {}
|
85
|
+
|
86
|
+
rewrites.each_pair do |pattern, substitution|
|
87
|
+
manifest.keys.each do |key|
|
88
|
+
replacement = key.sub(pattern, substitution)
|
89
|
+
next if key == replacement
|
90
|
+
raise "multiple replacements for: #{key}" if replacements.has_key?(key)
|
91
|
+
|
92
|
+
replacements[key] = replacement
|
93
|
+
end
|
94
|
+
end if rewrites
|
95
|
+
|
96
|
+
replacements.each do |key, replacement|
|
97
|
+
manifest[replacement] = manifest.delete(key)
|
98
|
+
end
|
99
|
+
|
100
|
+
manifest
|
101
|
+
end
|
102
|
+
|
103
|
+
def glob(*paths)
|
104
|
+
manifest = Hash.new {|hash, key| hash[key] = {} }
|
105
|
+
|
106
|
+
paths.each do |path|
|
107
|
+
PATTERNS.each_pair do |type, (dirname, extname)|
|
108
|
+
resource_dir = File.expand_path(File.join(path, dirname), project_dir)
|
109
|
+
|
110
|
+
pattern = File.join(resource_dir, "**/*#{extname}")
|
111
|
+
|
112
|
+
Dir.glob(pattern).each do |full_path|
|
113
|
+
next unless File.file?(full_path)
|
114
|
+
|
115
|
+
name = relative_path(resource_dir, full_path)
|
116
|
+
name.chomp!(extname) if extname
|
117
|
+
|
118
|
+
manifest[type][name] = full_path
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
manifest
|
124
|
+
end
|
125
|
+
|
126
|
+
def manifest
|
127
|
+
manifest = glob(*(full_gem_paths + paths))
|
128
|
+
|
129
|
+
if overrides
|
130
|
+
manifest = Utils.deep_merge(manifest, overrides)
|
131
|
+
end
|
132
|
+
|
133
|
+
manifest.each_key do |key|
|
134
|
+
manifest[key] = rewrite manifest[key]
|
135
|
+
end
|
136
|
+
|
137
|
+
manifest
|
138
|
+
end
|
139
|
+
|
140
|
+
def merge(config={})
|
141
|
+
duplicate = dup
|
142
|
+
dup.config.merge!(config)
|
143
|
+
dup
|
144
|
+
end
|
145
|
+
|
146
|
+
private
|
147
|
+
|
148
|
+
def relative_path(dir, path) # :nodoc:
|
149
|
+
start = dir.length + 1
|
150
|
+
path[start, path.length - start]
|
151
|
+
end
|
152
|
+
|
96
153
|
def latest_specs # :nodoc:
|
97
154
|
latest = {}
|
98
155
|
Gem.source_index.latest_specs.each do |spec|
|
data/lib/linecook/package.rb
CHANGED
@@ -1,137 +1,344 @@
|
|
1
|
-
require 'linecook/
|
1
|
+
require 'linecook/cookbook'
|
2
|
+
require 'linecook/recipe'
|
3
|
+
require 'linecook/template'
|
2
4
|
require 'tempfile'
|
3
5
|
|
4
6
|
module Linecook
|
5
7
|
class Package
|
6
8
|
class << self
|
7
|
-
def
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
def setup(env, cookbook=nil)
|
10
|
+
unless env.kind_of?(Hash)
|
11
|
+
env = Utils.load_config(env)
|
12
|
+
end
|
13
|
+
|
14
|
+
package = new(env)
|
15
|
+
|
16
|
+
if cookbook
|
17
|
+
manifest = package.manifest
|
18
|
+
manifest.replace cookbook.manifest
|
19
|
+
end
|
20
|
+
|
21
|
+
package
|
15
22
|
end
|
16
23
|
|
17
|
-
def init(
|
18
|
-
|
24
|
+
def init(package_file=nil, project_dir=nil)
|
25
|
+
cookbook = Cookbook.init(project_dir)
|
26
|
+
package = setup(package_file, cookbook)
|
27
|
+
|
28
|
+
if package_file
|
29
|
+
package.context[PACKAGE_KEY] ||= begin
|
30
|
+
name = File.basename(package_file).chomp(File.extname(package_file))
|
31
|
+
{'recipes' => { 'run' => name }}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
package
|
19
36
|
end
|
20
37
|
end
|
21
38
|
|
22
|
-
|
39
|
+
CONTEXT_KEY = 'linecook'
|
40
|
+
COOKBOOK_KEY = 'cookbook'
|
23
41
|
MANIFEST_KEY = 'manifest'
|
42
|
+
PACKAGE_KEY = 'package'
|
24
43
|
REGISTRY_KEY = 'registry'
|
25
|
-
|
44
|
+
|
26
45
|
FILES_KEY = 'files'
|
27
46
|
TEMPLATES_KEY = 'templates'
|
28
47
|
RECIPES_KEY = 'recipes'
|
29
|
-
PATHS_KEY = 'paths'
|
30
|
-
GEMS_KEY = 'gems'
|
31
48
|
|
49
|
+
# The package environment
|
32
50
|
attr_reader :env
|
33
51
|
|
52
|
+
# An array of tempfiles generated by self (used to cleanup on close)
|
53
|
+
attr_reader :tempfiles
|
54
|
+
|
55
|
+
# A hash of counters used by variable.
|
56
|
+
attr_reader :counters
|
57
|
+
|
58
|
+
# A hash of callbacks registered with self
|
59
|
+
attr_reader :callbacks
|
60
|
+
|
34
61
|
def initialize(env={})
|
35
62
|
@env = env
|
63
|
+
@tempfiles = []
|
64
|
+
@counters = Hash.new(0)
|
65
|
+
@callbacks = Hash.new {|hash, key| hash[key] = StringIO.new }
|
36
66
|
end
|
37
67
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
def cache
|
43
|
-
config[CACHE_KEY] ||= {}
|
68
|
+
# Returns the linecook context in env, as keyed by CONTEXT_KEY. Defaults
|
69
|
+
# to an empty hash.
|
70
|
+
def context
|
71
|
+
env[CONTEXT_KEY] ||= {}
|
44
72
|
end
|
45
73
|
|
74
|
+
# Returns the manifest in config, as keyed by MANIFEST_KEY. Defaults to an
|
75
|
+
# empty hash.
|
46
76
|
def manifest
|
47
|
-
|
77
|
+
context[MANIFEST_KEY] ||= {}
|
48
78
|
end
|
49
79
|
|
80
|
+
# Returns the registry in config, as keyed by REGISTRY_KEY. Defaults to an
|
81
|
+
# empty hash. A hash of (target_name, source_path) pairs identifying
|
82
|
+
# files that should be included in a package
|
50
83
|
def registry
|
51
|
-
|
84
|
+
context[REGISTRY_KEY] ||= {}
|
52
85
|
end
|
53
86
|
|
54
|
-
|
55
|
-
|
87
|
+
# Returns the linecook configs in env, as keyed by CONFIG_KEY. Defaults
|
88
|
+
# to an empty hash.
|
89
|
+
def config
|
90
|
+
context[PACKAGE_KEY] ||= {}
|
56
91
|
end
|
57
92
|
|
58
|
-
|
59
|
-
|
93
|
+
# Returns the hash of (source, target) pairs identifying which of the
|
94
|
+
# files will be built into self by build. Files are identified by
|
95
|
+
# FILES_KEY in config, and normalized the same way as recipes.
|
96
|
+
def files
|
97
|
+
config[FILES_KEY] = Utils.hashify(config[FILES_KEY])
|
60
98
|
end
|
61
99
|
|
62
|
-
|
100
|
+
# Returns the hash of (source, target) pairs identifying which templates
|
101
|
+
# will be built into self by build. Templates are identified by
|
102
|
+
# TEMPLATES_KEY in config, and normalized the same way as recipes.
|
103
|
+
def templates
|
104
|
+
config[TEMPLATES_KEY] = Utils.hashify(config[TEMPLATES_KEY])
|
105
|
+
end
|
106
|
+
|
107
|
+
# Returns the hash of (source, target) pairs identifying which recipes
|
108
|
+
# will be built into self by build. Recipes are identified by RECIPES_KEY
|
109
|
+
# in config.
|
110
|
+
#
|
111
|
+
# Non-hash recipes are normalized by expanding arrays into a redundant
|
112
|
+
# hash, such that each entry has the same source and target (more
|
113
|
+
# concretely, the 'example' recipe is registered as the 'example' script).
|
114
|
+
# Strings are split along colons into an array and then expanded.
|
115
|
+
#
|
116
|
+
# For example:
|
117
|
+
#
|
118
|
+
# package = Package.new('linecook' => {'package' => {'recipes' => 'a:b:c'}})
|
119
|
+
# package.recipes # => {'a' => 'a', 'b' => 'b', 'c' => 'c'}
|
120
|
+
#
|
121
|
+
def recipes
|
122
|
+
config[RECIPES_KEY] = Utils.hashify(config[RECIPES_KEY])
|
123
|
+
end
|
124
|
+
|
125
|
+
# Registers the source_path to target_name in the registry and
|
126
|
+
# revese_registry. Raises an error if the source_path is already
|
127
|
+
# registered.
|
128
|
+
def register(target_name, source_path, mode=0600)
|
63
129
|
source_path = File.expand_path(source_path)
|
64
|
-
build_path ||= File.basename(source_path)
|
65
130
|
|
131
|
+
if registry.has_key?(target_name) && registry[target_name] != [source_path, mode]
|
132
|
+
raise "already registered: #{target_name} (%s, %o)" % registry[target_name]
|
133
|
+
end
|
134
|
+
|
135
|
+
registry[target_name] = [source_path, mode]
|
136
|
+
target_name
|
137
|
+
end
|
138
|
+
|
139
|
+
# Increments target_name until an unregistered name is found and returns
|
140
|
+
# the result.
|
141
|
+
def next_target_name(target_name='file')
|
66
142
|
count = 0
|
67
|
-
registry.each_key do |
|
68
|
-
if
|
143
|
+
registry.each_key do |key|
|
144
|
+
if key.index(target_name) == 0
|
69
145
|
count += 1
|
70
146
|
end
|
71
147
|
end
|
72
148
|
|
73
149
|
if count > 0
|
74
|
-
|
150
|
+
target_name = "#{target_name}.#{count}"
|
75
151
|
end
|
76
152
|
|
77
|
-
|
78
|
-
|
153
|
+
target_name
|
154
|
+
end
|
155
|
+
|
156
|
+
# Returns a package-unique variable with base 'name'.
|
157
|
+
def next_variable_name(context)
|
158
|
+
context = context.to_s
|
79
159
|
|
80
|
-
|
160
|
+
count = counters[context]
|
161
|
+
counters[context] += 1
|
162
|
+
|
163
|
+
"#{context}#{count}"
|
81
164
|
end
|
82
165
|
|
83
|
-
|
84
|
-
|
85
|
-
|
166
|
+
# Returns true if there is a path for the specified resource in manifest.
|
167
|
+
def resource?(type, path)
|
168
|
+
resources = manifest[type]
|
169
|
+
resources && resources.has_key?(path)
|
170
|
+
end
|
171
|
+
|
172
|
+
# Returns the path to the resource in manfiest. Raises an error if there
|
173
|
+
# is no such resource.
|
174
|
+
def resource_path(type, path)
|
175
|
+
resources = manifest[type]
|
176
|
+
resource_path = resources ? resources[path] : nil
|
177
|
+
resource_path or raise "no such resource in manifest: #{type.inspect} #{path.inspect}"
|
178
|
+
end
|
179
|
+
|
180
|
+
# Returns the resource_path the named attributes file (ex 'attributes/name.rb').
|
181
|
+
def attributes_path(attributes_name)
|
182
|
+
resource_path('attributes', attributes_name)
|
183
|
+
end
|
184
|
+
|
185
|
+
# Returns the resource_path the named file (ex 'files/name')
|
186
|
+
def file_path(file_name)
|
187
|
+
resource_path('files', file_name)
|
188
|
+
end
|
189
|
+
|
190
|
+
# Returns the resource_path the named template file (ex 'templates/name.erb').
|
191
|
+
def template_path(template_name)
|
192
|
+
resource_path('templates', template_name)
|
86
193
|
end
|
87
194
|
|
88
|
-
|
89
|
-
|
195
|
+
# Returns the resource_path the named recipe file (ex 'recipes/name.rb').
|
196
|
+
def recipe_path(recipe_name)
|
197
|
+
resource_path('recipes', recipe_name)
|
90
198
|
end
|
91
199
|
|
200
|
+
# Loads the attributes file with the specified name and evaluates in the
|
201
|
+
# context of Attributes. Returns the new Attributes object.
|
202
|
+
def load_attributes(attributes_name=nil)
|
203
|
+
attributes = Attributes.new
|
204
|
+
|
205
|
+
if attributes_name
|
206
|
+
path = attributes_path(attributes_name)
|
207
|
+
attributes.instance_eval(File.read(path), path)
|
208
|
+
end
|
209
|
+
|
210
|
+
attributes
|
211
|
+
end
|
212
|
+
|
213
|
+
# Load the template file with the specified name and wraps as a Template.
|
214
|
+
# Returns the new Template object.
|
215
|
+
def load_template(template_name)
|
216
|
+
Template.new template_path(template_name)
|
217
|
+
end
|
218
|
+
|
219
|
+
# Loads and returns the helper constant specified by helper_name. The
|
220
|
+
# helper_name is underscored to determine a require path and camelized to
|
221
|
+
# determine the constant name.
|
222
|
+
def load_helper(helper_name)
|
223
|
+
require Utils.underscore(helper_name)
|
224
|
+
Utils.constantize(helper_name)
|
225
|
+
end
|
226
|
+
|
227
|
+
# Returns a recipe bound to self.
|
228
|
+
def setup_recipe(target_name = next_target_name, mode=0700)
|
229
|
+
Recipe.new(self, target_name, mode)
|
230
|
+
end
|
231
|
+
|
232
|
+
# Generates a tempfile for the target path and registers it with self. As
|
233
|
+
# with register, the target_name will be incremented as needed. Returns
|
234
|
+
# the open tempfile.
|
235
|
+
def setup_tempfile(target_name = next_target_name, mode=0600)
|
236
|
+
tempfile = Tempfile.new File.basename(target_name)
|
237
|
+
|
238
|
+
register(target_name, tempfile.path, mode)
|
239
|
+
tempfiles << tempfile
|
240
|
+
|
241
|
+
tempfile
|
242
|
+
end
|
243
|
+
|
244
|
+
# Returns true if the source_path is for a tempfile generated by self.
|
92
245
|
def tempfile?(source_path)
|
93
|
-
tempfiles.
|
246
|
+
tempfiles.any? {|tempfile| tempfile.path == source_path }
|
94
247
|
end
|
95
248
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
249
|
+
# Looks up the file with the specified name using file_path and registers
|
250
|
+
# it to target_name. Raises an error if the target is already registered.
|
251
|
+
def build_file(target_name, file_name=target_name, mode=0600)
|
252
|
+
register target_name, file_path(file_name), mode
|
253
|
+
self
|
254
|
+
end
|
255
|
+
|
256
|
+
# Looks up the template with the specified name using template_path,
|
257
|
+
# builds, and registers it to target_name. The locals will be set for
|
258
|
+
# access in the template context. Raises an error if the target is
|
259
|
+
# already registered. Returns self.
|
260
|
+
def build_template(target_name, template_name=target_name, mode=0600, locals={'attrs' => env})
|
261
|
+
content = load_template(template_name).build(locals)
|
262
|
+
|
263
|
+
target = setup_tempfile(target_name, mode)
|
264
|
+
target << content
|
265
|
+
target.close
|
266
|
+
self
|
267
|
+
end
|
268
|
+
|
269
|
+
# Looks up the recipe with the specified name using recipe_path, evaluates
|
270
|
+
# it, and registers the result to target_name. Raises an error if the
|
271
|
+
# target is already registered. Returns self.
|
272
|
+
def build_recipe(target_name, recipe_name=target_name, mode=0700)
|
273
|
+
path = recipe_path(recipe_name)
|
274
|
+
recipe = setup_recipe(target_name, mode)
|
275
|
+
recipe.instance_eval(File.read(path), path)
|
276
|
+
recipe.close
|
277
|
+
|
278
|
+
self
|
279
|
+
end
|
280
|
+
|
281
|
+
# Builds the files, templates, and recipes for self. Returns self.
|
282
|
+
def build
|
283
|
+
files.each do |target_name, file_name|
|
284
|
+
build_file(target_name, *file_name)
|
285
|
+
end
|
286
|
+
|
287
|
+
templates.each do |target_name, template_name|
|
288
|
+
build_template(target_name, *template_name)
|
289
|
+
end
|
290
|
+
|
291
|
+
recipes.each do |target_name, recipe_name|
|
292
|
+
build_recipe(target_name, *recipe_name)
|
111
293
|
end
|
294
|
+
|
295
|
+
self
|
112
296
|
end
|
113
297
|
|
114
|
-
|
115
|
-
|
116
|
-
|
298
|
+
# Returns the content of the source_path for target_name, as registered in
|
299
|
+
# self. Returns nil if the target is not registered.
|
300
|
+
def content(target_name, length=nil, offset=nil)
|
301
|
+
path = source_path(target_name)
|
302
|
+
path ? File.read(path, length, offset) : nil
|
117
303
|
end
|
118
304
|
|
119
|
-
|
120
|
-
|
305
|
+
# Returns the source_path for target_name, as registered in self. Returns
|
306
|
+
# nil if the target is not registered.
|
307
|
+
def source_path(target_name)
|
308
|
+
entry = registry[target_name]
|
309
|
+
entry ? entry[0] : nil
|
121
310
|
end
|
122
311
|
|
123
|
-
|
124
|
-
|
312
|
+
# Returns the mode for target_name, as registered in self. Returns nil if
|
313
|
+
# the target is not registered.
|
314
|
+
def mode(target_name)
|
315
|
+
entry = registry[target_name]
|
316
|
+
entry ? entry[1] : nil
|
125
317
|
end
|
126
318
|
|
127
|
-
|
128
|
-
|
319
|
+
# Closes all tempfiles and returns self.
|
320
|
+
def close
|
321
|
+
tempfiles.each do |tempfile|
|
322
|
+
tempfile.close unless tempfile.closed?
|
323
|
+
end
|
324
|
+
self
|
129
325
|
end
|
130
326
|
|
131
|
-
|
132
|
-
|
327
|
+
# Closes and clears all tempfiles, the registry, callbacks, and counters.
|
328
|
+
def reset
|
329
|
+
close
|
330
|
+
registry.clear
|
331
|
+
tempfiles.clear
|
332
|
+
callbacks.clear
|
333
|
+
counters.clear
|
334
|
+
self
|
133
335
|
end
|
134
336
|
|
337
|
+
# Closes self and exports the registry to dir by copying or moving the
|
338
|
+
# registered source paths to the target path under dir. By default
|
339
|
+
# tempfiles are moved while all other files are copied.
|
340
|
+
#
|
341
|
+
# Returns registry, which is re-written to reflect the new source paths.
|
135
342
|
def export(dir, options={})
|
136
343
|
close
|
137
344
|
|
@@ -141,57 +348,34 @@ module Linecook
|
|
141
348
|
|
142
349
|
allow_move = options[:allow_move]
|
143
350
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
351
|
+
if File.exists?(dir)
|
352
|
+
FileUtils.rm_r(dir)
|
353
|
+
end
|
354
|
+
|
355
|
+
registry.each_key do |target_name|
|
356
|
+
export_path = File.join(dir, target_name)
|
357
|
+
export_dir = File.dirname(export_path)
|
358
|
+
source_path, mode = registry[target_name]
|
359
|
+
|
360
|
+
next if source_path == export_path
|
148
361
|
|
149
|
-
unless File.exists?(
|
150
|
-
FileUtils.mkdir_p(
|
362
|
+
unless File.exists?(export_dir)
|
363
|
+
FileUtils.mkdir_p(export_dir)
|
151
364
|
end
|
152
365
|
|
153
366
|
if allow_move && tempfile?(source_path)
|
154
|
-
FileUtils.mv(source_path,
|
367
|
+
FileUtils.mv(source_path, export_path)
|
155
368
|
else
|
156
|
-
FileUtils.cp(source_path,
|
369
|
+
FileUtils.cp(source_path, export_path)
|
157
370
|
end
|
158
371
|
|
159
|
-
|
160
|
-
end
|
161
|
-
results
|
162
|
-
end
|
163
|
-
|
164
|
-
def close
|
165
|
-
tempfiles.each do |tempfile|
|
166
|
-
tempfile.close unless tempfile.closed?
|
167
|
-
end
|
168
|
-
self
|
169
|
-
end
|
170
|
-
|
171
|
-
private
|
172
|
-
|
173
|
-
def normalize(key)
|
174
|
-
obj = config[key]
|
175
|
-
|
176
|
-
case obj
|
177
|
-
when Hash
|
178
|
-
obj
|
179
|
-
|
180
|
-
when nil
|
181
|
-
config[key] = {}
|
372
|
+
FileUtils.chmod(mode, export_path)
|
182
373
|
|
183
|
-
|
184
|
-
hash = {}
|
185
|
-
obj.each {|entry| hash[entry] = entry }
|
186
|
-
config[key] = hash
|
187
|
-
|
188
|
-
when String
|
189
|
-
config[key] = obj.split(':')
|
190
|
-
normalize(key)
|
191
|
-
|
192
|
-
else
|
193
|
-
raise "invalid #{key}: #{obj.inspect}"
|
374
|
+
registry[target_name] = [export_path, mode]
|
194
375
|
end
|
376
|
+
|
377
|
+
tempfiles.clear
|
378
|
+
registry
|
195
379
|
end
|
196
380
|
end
|
197
381
|
end
|