berkshelf 0.1.1
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/.gitignore +20 -0
- data/.rbenv-version +1 -0
- data/Gemfile +3 -0
- data/Guardfile +23 -0
- data/LICENSE +22 -0
- data/README.rdoc +102 -0
- data/Thorfile +47 -0
- data/berkshelf.gemspec +39 -0
- data/features/config.sample.yml +3 -0
- data/features/init_command.feature +40 -0
- data/features/install.feature +55 -0
- data/features/lockfile.feature +22 -0
- data/features/step_definitions/chef_server_steps.rb +13 -0
- data/features/step_definitions/cli_steps.rb +56 -0
- data/features/step_definitions/filesystem_steps.rb +79 -0
- data/features/support/env.rb +55 -0
- data/features/update.feature +23 -0
- data/features/upload_command.feature +43 -0
- data/features/without.feature +25 -0
- data/lib/berkshelf.rb +90 -0
- data/lib/berkshelf/berksfile.rb +170 -0
- data/lib/berkshelf/cached_cookbook.rb +253 -0
- data/lib/berkshelf/cookbook_source.rb +139 -0
- data/lib/berkshelf/cookbook_source/git_location.rb +54 -0
- data/lib/berkshelf/cookbook_source/path_location.rb +27 -0
- data/lib/berkshelf/cookbook_source/site_location.rb +206 -0
- data/lib/berkshelf/cookbook_store.rb +77 -0
- data/lib/berkshelf/core_ext.rb +3 -0
- data/lib/berkshelf/core_ext/file.rb +14 -0
- data/lib/berkshelf/core_ext/kernel.rb +33 -0
- data/lib/berkshelf/core_ext/pathname.rb +24 -0
- data/lib/berkshelf/downloader.rb +92 -0
- data/lib/berkshelf/dsl.rb +39 -0
- data/lib/berkshelf/errors.rb +20 -0
- data/lib/berkshelf/generator_files/Berksfile.erb +3 -0
- data/lib/berkshelf/generator_files/chefignore +44 -0
- data/lib/berkshelf/git.rb +70 -0
- data/lib/berkshelf/init_generator.rb +38 -0
- data/lib/berkshelf/lockfile.rb +42 -0
- data/lib/berkshelf/resolver.rb +176 -0
- data/lib/berkshelf/tx_result.rb +12 -0
- data/lib/berkshelf/tx_result_set.rb +37 -0
- data/lib/berkshelf/uploader.rb +153 -0
- data/lib/berkshelf/version.rb +3 -0
- data/lib/chef/knife/berks_init.rb +29 -0
- data/lib/chef/knife/berks_install.rb +27 -0
- data/lib/chef/knife/berks_update.rb +23 -0
- data/lib/chef/knife/berks_upload.rb +39 -0
- data/spec/fixtures/Berksfile +3 -0
- data/spec/fixtures/cookbooks/example_cookbook-0.5.0/README.md +12 -0
- data/spec/fixtures/cookbooks/example_cookbook-0.5.0/metadata.rb +6 -0
- data/spec/fixtures/cookbooks/example_cookbook-0.5.0/recipes/default.rb +8 -0
- data/spec/fixtures/cookbooks/example_cookbook/README.md +12 -0
- data/spec/fixtures/cookbooks/example_cookbook/metadata.rb +6 -0
- data/spec/fixtures/cookbooks/example_cookbook/recipes/default.rb +8 -0
- data/spec/fixtures/cookbooks/invalid_ruby_files-1.0.0/recipes/default.rb +1 -0
- data/spec/fixtures/cookbooks/invalid_template_files-1.0.0/templates/default/broken.erb +1 -0
- data/spec/fixtures/cookbooks/nginx-0.100.5/README.md +77 -0
- data/spec/fixtures/cookbooks/nginx-0.100.5/attributes/default.rb +65 -0
- data/spec/fixtures/cookbooks/nginx-0.100.5/definitions/nginx_site.rb +35 -0
- data/spec/fixtures/cookbooks/nginx-0.100.5/files/default/mime.types +73 -0
- data/spec/fixtures/cookbooks/nginx-0.100.5/files/ubuntu/mime.types +73 -0
- data/spec/fixtures/cookbooks/nginx-0.100.5/libraries/nginxlib.rb +1 -0
- data/spec/fixtures/cookbooks/nginx-0.100.5/metadata.rb +91 -0
- data/spec/fixtures/cookbooks/nginx-0.100.5/providers/defprovider.rb +1 -0
- data/spec/fixtures/cookbooks/nginx-0.100.5/recipes/default.rb +59 -0
- data/spec/fixtures/cookbooks/nginx-0.100.5/resources/defresource.rb +1 -0
- data/spec/fixtures/cookbooks/nginx-0.100.5/templates/default/nginx.pill.erb +15 -0
- data/spec/fixtures/cookbooks/nginx-0.100.5/templates/default/plugins/nginx.rb.erb +66 -0
- data/spec/fixtures/lockfile_spec/with_lock/Berksfile +1 -0
- data/spec/fixtures/lockfile_spec/without_lock/Berksfile.lock +5 -0
- data/spec/spec_helper.rb +92 -0
- data/spec/support/chef_api.rb +27 -0
- data/spec/support/matchers/file_system_matchers.rb +115 -0
- data/spec/support/matchers/filepath_matchers.rb +19 -0
- data/spec/unit/berkshelf/cached_cookbook_spec.rb +420 -0
- data/spec/unit/berkshelf/cookbook_source/git_location_spec.rb +59 -0
- data/spec/unit/berkshelf/cookbook_source/path_location_spec.rb +34 -0
- data/spec/unit/berkshelf/cookbook_source/site_location_spec.rb +166 -0
- data/spec/unit/berkshelf/cookbook_source_spec.rb +194 -0
- data/spec/unit/berkshelf/cookbook_store_spec.rb +71 -0
- data/spec/unit/berkshelf/cookbookfile_spec.rb +160 -0
- data/spec/unit/berkshelf/downloader_spec.rb +82 -0
- data/spec/unit/berkshelf/dsl_spec.rb +42 -0
- data/spec/unit/berkshelf/git_spec.rb +63 -0
- data/spec/unit/berkshelf/init_generator_spec.rb +52 -0
- data/spec/unit/berkshelf/lockfile_spec.rb +25 -0
- data/spec/unit/berkshelf/resolver_spec.rb +126 -0
- data/spec/unit/berkshelf/tx_result_set_spec.rb +77 -0
- data/spec/unit/berkshelf/tx_result_spec.rb +21 -0
- data/spec/unit/berkshelf/uploader_spec.rb +71 -0
- data/spec/unit/berkshelf_spec.rb +29 -0
- metadata +411 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
require 'chef/checksum_cache'
|
|
2
|
+
require 'chef/cookbook/syntax_check'
|
|
3
|
+
|
|
4
|
+
module Berkshelf
|
|
5
|
+
# @author Jamie Winsor <jamie@vialstudios.com>
|
|
6
|
+
class CachedCookbook
|
|
7
|
+
class << self
|
|
8
|
+
# @param [String] path
|
|
9
|
+
# a path on disk to the location of a Cookbook downloaded by the Downloader
|
|
10
|
+
#
|
|
11
|
+
# @return [CachedCookbook]
|
|
12
|
+
# an instance of CachedCookbook initialized by the contents found at the
|
|
13
|
+
# given path.
|
|
14
|
+
def from_path(path)
|
|
15
|
+
matchdata = File.basename(path.to_s).match(DIRNAME_REGEXP)
|
|
16
|
+
return nil if matchdata.nil?
|
|
17
|
+
|
|
18
|
+
cached_name = matchdata[1]
|
|
19
|
+
|
|
20
|
+
metadata = Chef::Cookbook::Metadata.new
|
|
21
|
+
|
|
22
|
+
if path.join("metadata.rb").exist?
|
|
23
|
+
metadata.from_file(path.join("metadata.rb").to_s)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
new(cached_name, path, metadata)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# @param [String] filepath
|
|
30
|
+
# a path on disk to the location of a file to checksum
|
|
31
|
+
#
|
|
32
|
+
# @return [String]
|
|
33
|
+
# a checksum that can be used to uniquely identify the file understood
|
|
34
|
+
# by a Chef Server.
|
|
35
|
+
def checksum(filepath)
|
|
36
|
+
Chef::ChecksumCache.generate_md5_checksum_for_file(filepath)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
DIRNAME_REGEXP = /^(.+)-(\d+\.\d+\.\d+)$/
|
|
41
|
+
CHEF_TYPE = "cookbook_version".freeze
|
|
42
|
+
CHEF_JSON_CLASS = "Chef::CookbookVersion".freeze
|
|
43
|
+
|
|
44
|
+
extend Forwardable
|
|
45
|
+
|
|
46
|
+
attr_reader :cookbook_name
|
|
47
|
+
attr_reader :path
|
|
48
|
+
attr_reader :metadata
|
|
49
|
+
|
|
50
|
+
# @return [Mash]
|
|
51
|
+
# a Mash containing Cookbook file category names as keys and an Array of Hashes
|
|
52
|
+
# containing metadata about the files belonging to that category. This is used
|
|
53
|
+
# to communicate what a Cookbook looks like when uploading to a Chef Server.
|
|
54
|
+
#
|
|
55
|
+
# example:
|
|
56
|
+
# {
|
|
57
|
+
# :recipes => [
|
|
58
|
+
# {
|
|
59
|
+
# name: "default.rb",
|
|
60
|
+
# path: "recipes/default.rb",
|
|
61
|
+
# checksum: "fb1f925dcd5fc4ebf682c4442a21c619",
|
|
62
|
+
# specificity: "default"
|
|
63
|
+
# }
|
|
64
|
+
# ]
|
|
65
|
+
# ...
|
|
66
|
+
# ...
|
|
67
|
+
# }
|
|
68
|
+
attr_reader :manifest
|
|
69
|
+
|
|
70
|
+
def_delegators :@metadata, :version
|
|
71
|
+
|
|
72
|
+
def initialize(name, path, metadata)
|
|
73
|
+
@cookbook_name = name
|
|
74
|
+
@path = path
|
|
75
|
+
@metadata = metadata
|
|
76
|
+
@files = Array.new
|
|
77
|
+
@manifest = Mash.new(
|
|
78
|
+
recipes: Array.new,
|
|
79
|
+
definitions: Array.new,
|
|
80
|
+
libraries: Array.new,
|
|
81
|
+
attributes: Array.new,
|
|
82
|
+
files: Array.new,
|
|
83
|
+
templates: Array.new,
|
|
84
|
+
resources: Array.new,
|
|
85
|
+
providers: Array.new,
|
|
86
|
+
root_files: Array.new
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
load_files
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @return [String]
|
|
93
|
+
# the name of the cookbook and the version number separated by a dash (-).
|
|
94
|
+
#
|
|
95
|
+
# example:
|
|
96
|
+
# "nginx-0.101.2"
|
|
97
|
+
def name
|
|
98
|
+
"#{cookbook_name}-#{version}"
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# @return [Hash]
|
|
102
|
+
# an hash containing the checksums and expanded file paths of all of the
|
|
103
|
+
# files found in the instance of CachedCookbook
|
|
104
|
+
#
|
|
105
|
+
# example:
|
|
106
|
+
# {
|
|
107
|
+
# "da97c94bb6acb2b7900cbf951654fea3" => "/Users/reset/.berkshelf/nginx-0.101.2/README.md"
|
|
108
|
+
# }
|
|
109
|
+
def checksums
|
|
110
|
+
{}.tap do |checksums|
|
|
111
|
+
files.each do |file|
|
|
112
|
+
checksums[self.class.checksum(file)] = file
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# @param [Symbol] category
|
|
118
|
+
# the category of file to generate metadata about
|
|
119
|
+
# @param [String] target
|
|
120
|
+
# the filepath to the file to get metadata information about
|
|
121
|
+
#
|
|
122
|
+
# @return [Hash]
|
|
123
|
+
# a Hash containing a name, path, checksum, and specificity key representing the
|
|
124
|
+
# metadata about a file contained in a Cookbook. This metadata is used when
|
|
125
|
+
# uploading a Cookbook's files to a Chef Server.
|
|
126
|
+
#
|
|
127
|
+
# example:
|
|
128
|
+
# {
|
|
129
|
+
# name: "default.rb",
|
|
130
|
+
# path: "recipes/default.rb",
|
|
131
|
+
# checksum: "fb1f925dcd5fc4ebf682c4442a21c619",
|
|
132
|
+
# specificity: "default"
|
|
133
|
+
# }
|
|
134
|
+
def file_metadata(category, target)
|
|
135
|
+
target = Pathname.new(target)
|
|
136
|
+
|
|
137
|
+
{
|
|
138
|
+
name: target.basename.to_s,
|
|
139
|
+
path: target.relative_path_from(path).to_s,
|
|
140
|
+
checksum: self.class.checksum(target),
|
|
141
|
+
specificity: file_specificity(category, target)
|
|
142
|
+
}
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Validates that this instance of CachedCookbook points to a valid location on disk that
|
|
146
|
+
# contains a cookbook which passes a Ruby and template syntax check. Raises an error if
|
|
147
|
+
# these assertions are not true.
|
|
148
|
+
#
|
|
149
|
+
# @return [Boolean]
|
|
150
|
+
# returns true if Cookbook is valid
|
|
151
|
+
def validate!
|
|
152
|
+
raise CookbookNotFound, "No Cookbook found at: #{path}" unless path.exist?
|
|
153
|
+
|
|
154
|
+
unless quietly { syntax_checker.validate_ruby_files }
|
|
155
|
+
raise CookbookSyntaxError, "Invalid ruby files in cookbook: #{name} (#{version})."
|
|
156
|
+
end
|
|
157
|
+
unless quietly { syntax_checker.validate_templates }
|
|
158
|
+
raise CookbookSyntaxError, "Invalid template files in cookbook: #{name} (#{version})."
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
true
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def to_hash
|
|
165
|
+
result = manifest.dup
|
|
166
|
+
result['chef_type'] = 'cookbook_version'
|
|
167
|
+
result['name'] = name
|
|
168
|
+
result['cookbook_name'] = cookbook_name
|
|
169
|
+
result['version'] = version
|
|
170
|
+
result['metadata'] = metadata
|
|
171
|
+
result.to_hash
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def to_json(*a)
|
|
175
|
+
result = self.to_hash
|
|
176
|
+
result['json_class'] = chef_json_class
|
|
177
|
+
result['frozen?'] = false
|
|
178
|
+
result.to_json(*a)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
private
|
|
182
|
+
|
|
183
|
+
attr_reader :files
|
|
184
|
+
|
|
185
|
+
def chef_type
|
|
186
|
+
CHEF_TYPE
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def chef_json_class
|
|
190
|
+
CHEF_JSON_CLASS
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def syntax_checker
|
|
194
|
+
@syntax_checker ||= Chef::Cookbook::SyntaxCheck.new(path.to_s)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def load_files
|
|
198
|
+
load_shallow(:recipes, 'recipes', '*.rb')
|
|
199
|
+
load_shallow(:definitions, 'definitions', '*.rb')
|
|
200
|
+
load_shallow(:libraries, 'libraries', '*.rb')
|
|
201
|
+
load_shallow(:attributes, 'attributes', '*.rb')
|
|
202
|
+
load_recursively(:files, "files", "*")
|
|
203
|
+
load_recursively(:templates, "templates", "*")
|
|
204
|
+
load_recursively(:resources, "resources", "*.rb")
|
|
205
|
+
load_recursively(:providers, "providers", "*.rb")
|
|
206
|
+
load_root
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def load_root
|
|
210
|
+
[].tap do |files|
|
|
211
|
+
Dir.glob(path.join('*'), File::FNM_DOTMATCH).each do |file|
|
|
212
|
+
next if File.directory?(file)
|
|
213
|
+
@files << file
|
|
214
|
+
@manifest[:root_files] << file_metadata(:root_files, file)
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def load_recursively(category, category_dir, glob)
|
|
220
|
+
[].tap do |files|
|
|
221
|
+
file_spec = path.join(category_dir, '**', glob)
|
|
222
|
+
Dir.glob(file_spec, File::FNM_DOTMATCH).each do |file|
|
|
223
|
+
next if File.directory?(file)
|
|
224
|
+
@files << file
|
|
225
|
+
@manifest[category] << file_metadata(category, file)
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def load_shallow(category, *path_glob)
|
|
231
|
+
[].tap do |files|
|
|
232
|
+
Dir[path.join(*path_glob)].each do |file|
|
|
233
|
+
@files << file
|
|
234
|
+
@manifest[category] << file_metadata(category, file)
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# @param [Symbol] category
|
|
240
|
+
# @param [Pathname] target
|
|
241
|
+
#
|
|
242
|
+
# @return [String]
|
|
243
|
+
def file_specificity(category, target)
|
|
244
|
+
case category
|
|
245
|
+
when :files, :templates
|
|
246
|
+
relpath = target.relative_path_from(path).to_s
|
|
247
|
+
relpath.slice(/(.+)\/(.+)\/.+/, 2)
|
|
248
|
+
else
|
|
249
|
+
'default'
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
end
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
module Berkshelf
|
|
2
|
+
# @author Jamie Winsor <jamie@vialstudios.com>
|
|
3
|
+
class CookbookSource
|
|
4
|
+
module Location
|
|
5
|
+
attr_reader :name
|
|
6
|
+
|
|
7
|
+
def initialize(name)
|
|
8
|
+
@name = name
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def download(destination)
|
|
12
|
+
raise NotImplementedError, "Function must be implemented on includer"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
autoload :SiteLocation, 'berkshelf/cookbook_source/site_location'
|
|
17
|
+
autoload :GitLocation, 'berkshelf/cookbook_source/git_location'
|
|
18
|
+
autoload :PathLocation, 'berkshelf/cookbook_source/path_location'
|
|
19
|
+
|
|
20
|
+
LOCATION_KEYS = [:git, :path, :site]
|
|
21
|
+
|
|
22
|
+
attr_reader :name
|
|
23
|
+
attr_reader :version_constraint
|
|
24
|
+
attr_reader :groups
|
|
25
|
+
attr_reader :location
|
|
26
|
+
attr_reader :local_path
|
|
27
|
+
|
|
28
|
+
# TODO: describe how the options on this function work.
|
|
29
|
+
#
|
|
30
|
+
# @param [String] name
|
|
31
|
+
# @param [String] version_constraint (optional)
|
|
32
|
+
# @param [Hash] options (optional)
|
|
33
|
+
def initialize(*args)
|
|
34
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
|
35
|
+
name, constraint = args
|
|
36
|
+
|
|
37
|
+
@name = name
|
|
38
|
+
@version_constraint = DepSelector::VersionConstraint.new(constraint)
|
|
39
|
+
@groups = []
|
|
40
|
+
@local_path = nil
|
|
41
|
+
|
|
42
|
+
if (options.keys & LOCATION_KEYS).length > 1
|
|
43
|
+
raise ArgumentError, "Only one location key (#{LOCATION_KEYS.join(', ')}) may be specified"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
options[:version_constraint] = version_constraint if version_constraint
|
|
47
|
+
|
|
48
|
+
@location = case
|
|
49
|
+
when options[:git]
|
|
50
|
+
GitLocation.new(name, options)
|
|
51
|
+
when options[:path]
|
|
52
|
+
loc = PathLocation.new(name, options)
|
|
53
|
+
set_local_path loc.path
|
|
54
|
+
loc
|
|
55
|
+
when options[:site]
|
|
56
|
+
SiteLocation.new(name, options)
|
|
57
|
+
else
|
|
58
|
+
SiteLocation.new(name, options)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
@locked_version = DepSelector::Version.new(options[:locked_version]) if options[:locked_version]
|
|
62
|
+
|
|
63
|
+
add_group(options[:group]) if options[:group]
|
|
64
|
+
add_group(:default) if groups.empty?
|
|
65
|
+
set_downloaded_status(false)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def add_group(*groups)
|
|
69
|
+
groups = groups.first if groups.first.is_a?(Array)
|
|
70
|
+
groups.each do |group|
|
|
71
|
+
group = group.to_sym
|
|
72
|
+
@groups << group unless @groups.include?(group)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# @param [String] destination
|
|
77
|
+
# destination to download to
|
|
78
|
+
#
|
|
79
|
+
# @return [Array]
|
|
80
|
+
# An array containing the status at index 0 and local path or error message in index 1
|
|
81
|
+
#
|
|
82
|
+
# Example:
|
|
83
|
+
# [ :ok, "/tmp/nginx" ]
|
|
84
|
+
# [ :error, "Cookbook 'sparkle_motion' not found at site: http://cookbooks.opscode.com/api/v1/cookbooks" ]
|
|
85
|
+
def download(destination)
|
|
86
|
+
set_local_path location.download(destination)
|
|
87
|
+
[ :ok, local_path ]
|
|
88
|
+
rescue CookbookNotFound => e
|
|
89
|
+
set_local_path = nil
|
|
90
|
+
[ :error, e.message ]
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def downloaded?
|
|
94
|
+
!local_path.nil?
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def metadata
|
|
98
|
+
return nil unless local_path
|
|
99
|
+
|
|
100
|
+
cookbook_metadata = Chef::Cookbook::Metadata.new
|
|
101
|
+
cookbook_metadata.from_file(File.join(local_path, "metadata.rb"))
|
|
102
|
+
cookbook_metadata
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def to_s
|
|
106
|
+
name
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def has_group?(group)
|
|
110
|
+
groups.include?(group.to_sym)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def dependencies
|
|
114
|
+
return nil unless metadata
|
|
115
|
+
|
|
116
|
+
metadata.dependencies
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def local_version
|
|
120
|
+
return nil unless metadata
|
|
121
|
+
|
|
122
|
+
metadata.version
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def locked_version
|
|
126
|
+
@locked_version || local_version
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
private
|
|
130
|
+
|
|
131
|
+
def set_downloaded_status(state)
|
|
132
|
+
@downloaded_state = state
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def set_local_path(path)
|
|
136
|
+
@local_path = path
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Berkshelf
|
|
2
|
+
class CookbookSource
|
|
3
|
+
# @author Jamie Winsor <jamie@vialstudios.com>
|
|
4
|
+
class GitLocation
|
|
5
|
+
include Location
|
|
6
|
+
|
|
7
|
+
attr_accessor :uri
|
|
8
|
+
attr_accessor :branch
|
|
9
|
+
|
|
10
|
+
def initialize(name, options)
|
|
11
|
+
@name = name
|
|
12
|
+
@uri = options[:git]
|
|
13
|
+
@branch = options[:branch] || options[:ref] || options[:tag]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def download(destination)
|
|
17
|
+
tmp_clone = Dir.mktmpdir
|
|
18
|
+
::Berkshelf::Git.clone(uri, tmp_clone)
|
|
19
|
+
::Berkshelf::Git.checkout(tmp_clone, branch) if branch
|
|
20
|
+
unless branch
|
|
21
|
+
self.branch = ::Berkshelf::Git.rev_parse(tmp_clone)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
unless File.chef_cookbook?(tmp_clone)
|
|
25
|
+
msg = "Cookbook '#{name}' not found at git: #{uri}"
|
|
26
|
+
msg << " with branch '#{branch}'" if branch
|
|
27
|
+
raise CookbookNotFound, msg
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
cb_path = File.join(destination, "#{self.name}-#{self.branch}")
|
|
31
|
+
|
|
32
|
+
FileUtils.mv(tmp_clone, cb_path, :force => true)
|
|
33
|
+
|
|
34
|
+
cb_path
|
|
35
|
+
rescue Berkshelf::GitError
|
|
36
|
+
msg = "Cookbook '#{name}' not found at git: #{uri}"
|
|
37
|
+
msg << " with branch '#{branch}'" if branch
|
|
38
|
+
raise CookbookNotFound, msg
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def to_s
|
|
42
|
+
s = "git: '#{uri}'"
|
|
43
|
+
s << " with branch '#{branch}" if branch
|
|
44
|
+
s
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def git
|
|
50
|
+
@git ||= Berkshelf::Git.new(uri)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Berkshelf
|
|
2
|
+
class CookbookSource
|
|
3
|
+
# @author Jamie Winsor <jamie@vialstudios.com>
|
|
4
|
+
class PathLocation
|
|
5
|
+
include Location
|
|
6
|
+
|
|
7
|
+
attr_accessor :path
|
|
8
|
+
|
|
9
|
+
def initialize(name, options = {})
|
|
10
|
+
@name = name
|
|
11
|
+
@path = File.expand_path(options[:path])
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def download(destination)
|
|
15
|
+
unless File.chef_cookbook?(path)
|
|
16
|
+
raise CookbookNotFound, "Cookbook '#{name}' not found at path: '#{path}'"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
path
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def to_s
|
|
23
|
+
"path: '#{path}'"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|