librarian-puppet 0.0.1.pre

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.
Files changed (107) hide show
  1. data/.gitignore +1 -0
  2. data/LICENSE +20 -0
  3. data/README.md +0 -0
  4. data/bin/librarian-puppet +9 -0
  5. data/lib/librarian/puppet.rb +7 -0
  6. data/lib/librarian/puppet/cli.rb +30 -0
  7. data/lib/librarian/puppet/dsl.rb +14 -0
  8. data/lib/librarian/puppet/environment.rb +18 -0
  9. data/lib/librarian/puppet/extension.rb +9 -0
  10. data/lib/librarian/puppet/source.rb +2 -0
  11. data/lib/librarian/puppet/source/git.rb +12 -0
  12. data/lib/librarian/puppet/source/local.rb +46 -0
  13. data/lib/librarian/puppet/source/path.rb +12 -0
  14. data/lib/librarian/puppet/templates/Puppetfile +6 -0
  15. data/librarian-puppet.gemspec +126 -0
  16. data/vendor/librarian/.rspec +1 -0
  17. data/vendor/librarian/.travis.yml +6 -0
  18. data/vendor/librarian/CHANGELOG.md +168 -0
  19. data/vendor/librarian/Gemfile +4 -0
  20. data/vendor/librarian/MIT-LICENSE +20 -0
  21. data/vendor/librarian/README.md +318 -0
  22. data/vendor/librarian/Rakefile +34 -0
  23. data/vendor/librarian/bin/librarian-chef +7 -0
  24. data/vendor/librarian/bin/librarian-mock +7 -0
  25. data/vendor/librarian/config/cucumber.yaml +1 -0
  26. data/vendor/librarian/features/chef/cli/init.feature +10 -0
  27. data/vendor/librarian/features/chef/cli/install.feature +64 -0
  28. data/vendor/librarian/features/chef/cli/show.feature +65 -0
  29. data/vendor/librarian/features/chef/cli/version.feature +11 -0
  30. data/vendor/librarian/features/support/env.rb +9 -0
  31. data/vendor/librarian/lib/librarian.rb +19 -0
  32. data/vendor/librarian/lib/librarian/action.rb +5 -0
  33. data/vendor/librarian/lib/librarian/action/base.rb +22 -0
  34. data/vendor/librarian/lib/librarian/action/clean.rb +44 -0
  35. data/vendor/librarian/lib/librarian/action/ensure.rb +24 -0
  36. data/vendor/librarian/lib/librarian/action/install.rb +95 -0
  37. data/vendor/librarian/lib/librarian/action/resolve.rb +81 -0
  38. data/vendor/librarian/lib/librarian/action/update.rb +78 -0
  39. data/vendor/librarian/lib/librarian/chef.rb +1 -0
  40. data/vendor/librarian/lib/librarian/chef/cli.rb +27 -0
  41. data/vendor/librarian/lib/librarian/chef/dsl.rb +15 -0
  42. data/vendor/librarian/lib/librarian/chef/environment.rb +19 -0
  43. data/vendor/librarian/lib/librarian/chef/extension.rb +9 -0
  44. data/vendor/librarian/lib/librarian/chef/integration/knife.rb +42 -0
  45. data/vendor/librarian/lib/librarian/chef/manifest_reader.rb +47 -0
  46. data/vendor/librarian/lib/librarian/chef/source.rb +3 -0
  47. data/vendor/librarian/lib/librarian/chef/source/git.rb +12 -0
  48. data/vendor/librarian/lib/librarian/chef/source/local.rb +63 -0
  49. data/vendor/librarian/lib/librarian/chef/source/path.rb +12 -0
  50. data/vendor/librarian/lib/librarian/chef/source/site.rb +434 -0
  51. data/vendor/librarian/lib/librarian/chef/templates/Cheffile +15 -0
  52. data/vendor/librarian/lib/librarian/cli.rb +175 -0
  53. data/vendor/librarian/lib/librarian/cli/manifest_presenter.rb +79 -0
  54. data/vendor/librarian/lib/librarian/dependency.rb +95 -0
  55. data/vendor/librarian/lib/librarian/dsl.rb +105 -0
  56. data/vendor/librarian/lib/librarian/dsl/receiver.rb +48 -0
  57. data/vendor/librarian/lib/librarian/dsl/target.rb +176 -0
  58. data/vendor/librarian/lib/librarian/environment.rb +129 -0
  59. data/vendor/librarian/lib/librarian/error.rb +4 -0
  60. data/vendor/librarian/lib/librarian/helpers.rb +13 -0
  61. data/vendor/librarian/lib/librarian/helpers/debug.rb +35 -0
  62. data/vendor/librarian/lib/librarian/lockfile.rb +33 -0
  63. data/vendor/librarian/lib/librarian/lockfile/compiler.rb +70 -0
  64. data/vendor/librarian/lib/librarian/lockfile/parser.rb +104 -0
  65. data/vendor/librarian/lib/librarian/manifest.rb +140 -0
  66. data/vendor/librarian/lib/librarian/manifest_set.rb +153 -0
  67. data/vendor/librarian/lib/librarian/mock.rb +1 -0
  68. data/vendor/librarian/lib/librarian/mock/cli.rb +19 -0
  69. data/vendor/librarian/lib/librarian/mock/dsl.rb +15 -0
  70. data/vendor/librarian/lib/librarian/mock/environment.rb +24 -0
  71. data/vendor/librarian/lib/librarian/mock/extension.rb +9 -0
  72. data/vendor/librarian/lib/librarian/mock/source.rb +1 -0
  73. data/vendor/librarian/lib/librarian/mock/source/mock.rb +97 -0
  74. data/vendor/librarian/lib/librarian/mock/source/mock/registry.rb +83 -0
  75. data/vendor/librarian/lib/librarian/resolution.rb +44 -0
  76. data/vendor/librarian/lib/librarian/resolver.rb +73 -0
  77. data/vendor/librarian/lib/librarian/resolver/implementation.rb +122 -0
  78. data/vendor/librarian/lib/librarian/source.rb +2 -0
  79. data/vendor/librarian/lib/librarian/source/git.rb +150 -0
  80. data/vendor/librarian/lib/librarian/source/git/repository.rb +213 -0
  81. data/vendor/librarian/lib/librarian/source/local.rb +51 -0
  82. data/vendor/librarian/lib/librarian/source/path.rb +74 -0
  83. data/vendor/librarian/lib/librarian/spec.rb +13 -0
  84. data/vendor/librarian/lib/librarian/spec_change_set.rb +170 -0
  85. data/vendor/librarian/lib/librarian/specfile.rb +22 -0
  86. data/vendor/librarian/lib/librarian/support/abstract_method.rb +21 -0
  87. data/vendor/librarian/lib/librarian/ui.rb +64 -0
  88. data/vendor/librarian/lib/librarian/version.rb +3 -0
  89. data/vendor/librarian/librarian.gemspec +33 -0
  90. data/vendor/librarian/spec/functional/chef/source/git_spec.rb +432 -0
  91. data/vendor/librarian/spec/functional/chef/source/site_spec.rb +215 -0
  92. data/vendor/librarian/spec/unit/action/base_spec.rb +18 -0
  93. data/vendor/librarian/spec/unit/action/clean_spec.rb +102 -0
  94. data/vendor/librarian/spec/unit/action/ensure_spec.rb +37 -0
  95. data/vendor/librarian/spec/unit/action/install_spec.rb +111 -0
  96. data/vendor/librarian/spec/unit/dependency_spec.rb +30 -0
  97. data/vendor/librarian/spec/unit/dsl_spec.rb +194 -0
  98. data/vendor/librarian/spec/unit/environment_spec.rb +9 -0
  99. data/vendor/librarian/spec/unit/lockfile/parser_spec.rb +162 -0
  100. data/vendor/librarian/spec/unit/lockfile_spec.rb +65 -0
  101. data/vendor/librarian/spec/unit/manifest_set_spec.rb +202 -0
  102. data/vendor/librarian/spec/unit/manifest_spec.rb +30 -0
  103. data/vendor/librarian/spec/unit/mock/source/mock_spec.rb +22 -0
  104. data/vendor/librarian/spec/unit/resolver_spec.rb +192 -0
  105. data/vendor/librarian/spec/unit/source/git_spec.rb +29 -0
  106. data/vendor/librarian/spec/unit/spec_change_set_spec.rb +169 -0
  107. metadata +163 -0
@@ -0,0 +1 @@
1
+ require 'librarian/chef/extension'
@@ -0,0 +1,27 @@
1
+ require 'librarian/helpers'
2
+
3
+ require 'librarian/cli'
4
+ require 'librarian/chef'
5
+
6
+ module Librarian
7
+ module Chef
8
+ class Cli < Librarian::Cli
9
+
10
+ module Particularity
11
+ def root_module
12
+ Chef
13
+ end
14
+ end
15
+
16
+ include Particularity
17
+ extend Particularity
18
+
19
+ source_root Pathname.new(__FILE__).dirname.join("templates")
20
+
21
+ def init
22
+ copy_file environment.specfile_name
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ require 'librarian/dsl'
2
+ require 'librarian/chef/source'
3
+
4
+ module Librarian
5
+ module Chef
6
+ class Dsl < Librarian::Dsl
7
+
8
+ dependency :cookbook
9
+
10
+ source :site => Source::Site
11
+ source :git => Source::Git
12
+ source :path => Source::Path
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ require "librarian/environment"
2
+ require "librarian/chef/dsl"
3
+ require "librarian/chef/source"
4
+
5
+ module Librarian
6
+ module Chef
7
+ class Environment < Environment
8
+
9
+ def adapter_name
10
+ "chef"
11
+ end
12
+
13
+ def install_path
14
+ project_path.join("cookbooks")
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ require 'librarian/chef/environment'
2
+
3
+ module Librarian
4
+ module Chef
5
+ extend self
6
+ extend Librarian
7
+
8
+ end
9
+ end
@@ -0,0 +1,42 @@
1
+ require 'pathname'
2
+ require 'securerandom'
3
+ require 'highline'
4
+
5
+ require 'librarian'
6
+ require 'librarian/action/install'
7
+ require 'librarian/chef'
8
+
9
+ module Librarian
10
+ module Chef
11
+
12
+ class Environment
13
+ def install_path
14
+ @install_path ||= begin
15
+ has_home = ENV["HOME"] && File.directory?(ENV["HOME"])
16
+ tmp_dir = Pathname.new(has_home ? "~/.librarian/tmp" : "/tmp/librarian").expand_path
17
+ enclosing = tmp_dir.join("chef/integration/knife/install")
18
+ enclosing.mkpath unless enclosing.exist?
19
+ dir = enclosing.join(SecureRandom.hex(16))
20
+ dir.mkpath
21
+ at_exit { dir.rmtree }
22
+ dir
23
+ end
24
+ end
25
+ end
26
+
27
+ def install_path
28
+ environment.install_path
29
+ end
30
+
31
+ hl = HighLine.new
32
+
33
+ begin
34
+ Action::Install.new(environment).run
35
+ rescue Error => e
36
+ message = hl.color(e.message, HighLine::RED)
37
+ hl.say(message)
38
+ Process.exit!(1)
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,47 @@
1
+ require 'json'
2
+ require 'yaml'
3
+
4
+ require 'librarian/manifest'
5
+
6
+ module Librarian
7
+ module Chef
8
+ module ManifestReader
9
+ extend self
10
+
11
+ MANIFESTS = %w(metadata.json metadata.yml metadata.yaml metadata.rb)
12
+
13
+ def manifest_path(path)
14
+ MANIFESTS.map{|s| path.join(s)}.find{|s| s.exist?}
15
+ end
16
+
17
+ def read_manifest(name, manifest_path)
18
+ case manifest_path.extname
19
+ when ".json" then JSON.parse(manifest_path.read)
20
+ when ".yml", ".yaml" then YAML.load(manifest_path.read)
21
+ when ".rb" then compile_manifest(name, manifest_path.dirname)
22
+ end
23
+ end
24
+
25
+ def compile_manifest(name, path)
26
+ # Inefficient, if there are many cookbooks with uncompiled metadata.
27
+ require 'chef/json_compat'
28
+ require 'chef/cookbook/metadata'
29
+ md = ::Chef::Cookbook::Metadata.new
30
+ md.name(name)
31
+ md.from_file(path.join('metadata.rb').to_s)
32
+ {"name" => md.name, "version" => md.version, "dependencies" => md.dependencies}
33
+ end
34
+
35
+ def manifest?(name, path)
36
+ path = Pathname.new(path)
37
+ !!manifest_path(path)
38
+ end
39
+
40
+ def check_manifest(name, manifest_path)
41
+ manifest = read_manifest(name, manifest_path)
42
+ manifest["name"] == name
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,3 @@
1
+ require 'librarian/chef/source/path'
2
+ require 'librarian/chef/source/git'
3
+ require 'librarian/chef/source/site'
@@ -0,0 +1,12 @@
1
+ require 'librarian/source/git'
2
+ require 'librarian/chef/source/local'
3
+
4
+ module Librarian
5
+ module Chef
6
+ module Source
7
+ class Git < Librarian::Source::Git
8
+ include Local
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,63 @@
1
+ require 'librarian/chef/manifest_reader'
2
+
3
+ module Librarian
4
+ module Chef
5
+ module Source
6
+ module Local
7
+
8
+ def install!(manifest)
9
+ manifest.source == self or raise ArgumentError
10
+
11
+ debug { "Installing #{manifest}" }
12
+
13
+ name, version = manifest.name, manifest.version
14
+ found_path = found_path(name)
15
+
16
+ install_path = environment.install_path.join(name)
17
+ if install_path.exist?
18
+ debug { "Deleting #{relative_path_to(install_path)}" }
19
+ install_path.rmtree
20
+ end
21
+
22
+ debug { "Copying #{relative_path_to(found_path)} to #{relative_path_to(install_path)}" }
23
+ FileUtils.cp_r(found_path, install_path)
24
+ end
25
+
26
+ def fetch_version(name, extra)
27
+ manifest_data(name)["version"]
28
+ end
29
+
30
+ def fetch_dependencies(name, version, extra)
31
+ manifest_data(name)["dependencies"]
32
+ end
33
+
34
+ private
35
+
36
+ def manifest_data(name)
37
+ @manifest_data ||= { }
38
+ @manifest_data[name] ||= fetch_manifest_data(name)
39
+ end
40
+
41
+ def fetch_manifest_data(name)
42
+ expect_manifest!(name)
43
+
44
+ found_path = found_path(name)
45
+ manifest_path = ManifestReader.manifest_path(found_path)
46
+ ManifestReader.read_manifest(name, manifest_path)
47
+ end
48
+
49
+ def manifest?(name, path)
50
+ ManifestReader.manifest?(name, path)
51
+ end
52
+
53
+ def expect_manifest!(name)
54
+ found_path = found_path(name)
55
+ return if found_path && ManifestReader.manifest_path(found_path)
56
+
57
+ raise Error, "No metadata file found for #{name} from #{self}! If this should be a cookbook, you might consider contributing a metadata file upstream or forking the cookbook to add your own metadata file."
58
+ end
59
+
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,12 @@
1
+ require 'librarian/source/path'
2
+ require 'librarian/chef/source/local'
3
+
4
+ module Librarian
5
+ module Chef
6
+ module Source
7
+ class Path < Librarian::Source::Path
8
+ include Local
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,434 @@
1
+ require 'fileutils'
2
+ require 'pathname'
3
+ require 'uri'
4
+ require 'net/http'
5
+ require 'json'
6
+ require 'digest'
7
+ require 'zlib'
8
+ require 'securerandom'
9
+ require 'archive/tar/minitar'
10
+
11
+ require 'librarian/helpers/debug'
12
+
13
+ require 'librarian/chef/manifest_reader'
14
+
15
+ module Librarian
16
+ module Chef
17
+ module Source
18
+ class Site
19
+
20
+ include Helpers::Debug
21
+
22
+ class Line
23
+
24
+ include Helpers::Debug
25
+
26
+ attr_accessor :source, :name
27
+ private :source=, :name=
28
+
29
+ def initialize(source, name)
30
+ self.source = source
31
+ self.name = name
32
+ end
33
+
34
+ def install_version!(version, install_path)
35
+ cache_version_unpacked! version
36
+
37
+ if install_path.exist?
38
+ debug { "Deleting #{relative_path_to(install_path)}" }
39
+ install_path.rmtree
40
+ end
41
+
42
+ unpacked_path = version_unpacked_cache_path(version)
43
+
44
+ debug { "Copying #{relative_path_to(unpacked_path)} to #{relative_path_to(install_path)}" }
45
+ FileUtils.cp_r(unpacked_path, install_path)
46
+ end
47
+
48
+ def manifests
49
+ version_uris.map do |version_uri|
50
+ Manifest.new(source, name, version_uri)
51
+ end
52
+ end
53
+
54
+ def to_version(version_uri)
55
+ version_uri_metadata(version_uri)["version"]
56
+ end
57
+
58
+ def version_dependencies(version)
59
+ version_manifest(version)["dependencies"]
60
+ end
61
+
62
+ private
63
+
64
+ attr_accessor :metadata_cached
65
+ alias metadata_cached? metadata_cached
66
+
67
+ def environment
68
+ source.environment
69
+ end
70
+
71
+ def uri
72
+ @uri ||= URI.parse("#{source.uri}/cookbooks/#{name}")
73
+ end
74
+
75
+ def version_uris
76
+ metadata["versions"]
77
+ end
78
+
79
+ def version_metadata(version)
80
+ version_uri = to_version_uri(version)
81
+ version_uri_metadata(version_uri)
82
+ end
83
+
84
+ def version_uri_metadata(version_uri)
85
+ @version_uri_metadata ||= { }
86
+ @version_uri_metadata[version_uri.to_s] ||= begin
87
+ cache_version_uri_metadata! version_uri
88
+ parse_local_json(version_uri_metadata_cache_path(version_uri))
89
+ end
90
+ end
91
+
92
+ def version_manifest(version)
93
+ version_uri = to_version_uri(version)
94
+ version_uri_manifest(version_uri)
95
+ end
96
+
97
+ def version_uri_manifest(version_uri)
98
+ @version_uri_manifest ||= { }
99
+ @version_uri_manifest[version_uri.to_s] ||= begin
100
+ cache_version_uri_unpacked! version_uri
101
+ unpacked_path = version_uri_unpacked_cache_path(version_uri)
102
+ manifest_path = ManifestReader.manifest_path(unpacked_path)
103
+ ManifestReader.read_manifest(name, manifest_path)
104
+ end
105
+ end
106
+
107
+ def metadata
108
+ @metadata ||= begin
109
+ cache_metadata!
110
+ parse_local_json(metadata_cache_path)
111
+ end
112
+ end
113
+
114
+ def to_version_uri(version)
115
+ @to_version_uri ||= { }
116
+ @to_version_uri[version.to_s] ||= begin
117
+ cache_version! version
118
+ version_cache_path(version).read
119
+ end
120
+ end
121
+
122
+ def metadata_cached!
123
+ self.metadata_cached = true
124
+ end
125
+
126
+ def cache_path
127
+ @cache_path ||= source.cache_path.join(name)
128
+ end
129
+
130
+ def metadata_cache_path
131
+ @metadata_cache_path ||= cache_path.join("metadata.json")
132
+ end
133
+
134
+ def version_cache_path(version)
135
+ @version_cache_path ||= { }
136
+ @version_cache_path[version.to_s] ||= begin
137
+ cache_path.join("version").join(version.to_s)
138
+ end
139
+ end
140
+
141
+ def version_uri_cache_path(version_uri)
142
+ @version_uri_cache_path ||= { }
143
+ @version_uri_cache_path[version_uri.to_s] ||= begin
144
+ cache_path.join("version-uri").join(hexdigest(version_uri))
145
+ end
146
+ end
147
+
148
+ def version_metadata_cache_path(version)
149
+ version_uri = to_version_uri(version)
150
+ version_uri_metadata_cache_path(version_uri)
151
+ end
152
+
153
+ def version_uri_metadata_cache_path(version_uri)
154
+ @version_uri_metadata_cache_path ||= { }
155
+ @version_uri_metadata_cache_path[version_uri.to_s] ||= begin
156
+ version_uri_cache_path(version_uri).join("metadata.json")
157
+ end
158
+ end
159
+
160
+ def version_package_cache_path(version)
161
+ version_uri = to_version_uri(version)
162
+ version_uri_package_cache_path(version_uri)
163
+ end
164
+
165
+ def version_uri_package_cache_path(version_uri)
166
+ @version_uri_package_cache_path ||= { }
167
+ @version_uri_package_cache_path[version_uri.to_s] ||= begin
168
+ version_uri_cache_path(version_uri).join("package.tar.gz")
169
+ end
170
+ end
171
+
172
+ def version_unpacked_cache_path(version)
173
+ version_uri = to_version_uri(version)
174
+ version_uri_unpacked_cache_path(version_uri)
175
+ end
176
+
177
+ def version_uri_unpacked_cache_path(version_uri)
178
+ @version_uri_unpacked_cache_path ||= { }
179
+ @version_uri_unpacked_cache_path[version_uri.to_s] ||= begin
180
+ version_uri_cache_path(version_uri).join("package")
181
+ end
182
+ end
183
+
184
+ def cache_metadata!
185
+ metadata_cached? and return or metadata_cached!
186
+ cache_remote_json! metadata_cache_path, uri
187
+ end
188
+
189
+ def cache_version_uri_metadata!(version_uri)
190
+ path = version_uri_metadata_cache_path(version_uri)
191
+ path.file? and return
192
+
193
+ cache_remote_json! path, version_uri
194
+ end
195
+
196
+ def cache_version!(version)
197
+ path = version_cache_path(version)
198
+ path.file? and return
199
+
200
+ version_uris.each do |version_uri|
201
+ m = version_uri_metadata(version_uri)
202
+ v = m["version"]
203
+ if version.to_s == v
204
+ write! path, version_uri.to_s
205
+ break
206
+ end
207
+ end
208
+ end
209
+
210
+ def cache_version_package!(version)
211
+ version_uri = to_version_uri(version)
212
+ cache_version_uri_package! version_uri
213
+ end
214
+
215
+ def cache_version_uri_package!(version_uri)
216
+ path = version_uri_package_cache_path(version_uri)
217
+ path.file? and return
218
+
219
+ file_uri = version_uri_metadata(version_uri)["file"]
220
+ cache_remote_object! path, file_uri
221
+ end
222
+
223
+ def cache_version_unpacked!(version)
224
+ version_uri = to_version_uri(version)
225
+ cache_version_uri_unpacked! version_uri
226
+ end
227
+
228
+ def cache_version_uri_unpacked!(version_uri)
229
+ cache_version_uri_package!(version_uri)
230
+
231
+ path = version_uri_unpacked_cache_path(version_uri)
232
+ path.directory? and return
233
+
234
+ package_path = version_uri_package_cache_path(version_uri)
235
+ unpacked_path = version_uri_unpacked_cache_path(version_uri)
236
+
237
+ unpack_package! unpacked_path, package_path
238
+ end
239
+
240
+ def cache_remote_json!(path, uri)
241
+ path = Pathname(path)
242
+ uri = to_uri(uri)
243
+
244
+ path.dirname.mkpath unless path.dirname.directory?
245
+
246
+ debug { "Caching #{uri} to #{path}" }
247
+
248
+ http = Net::HTTP.new(uri.host, uri.port)
249
+ request = Net::HTTP::Get.new(uri.path)
250
+ response = http.start{|http| http.request(request)}
251
+ unless Net::HTTPSuccess === response
252
+ raise Error, "Could not get #{uri} because #{response.code} #{response.message}!"
253
+ end
254
+ json = response.body
255
+ JSON.parse(json) # verify that it's really JSON.
256
+ write! path, json
257
+ end
258
+
259
+ def cache_remote_object!(path, uri)
260
+ path = Pathname(path)
261
+ uri = to_uri(uri)
262
+
263
+ path.dirname.mkpath unless path.dirname.directory?
264
+
265
+ debug { "Caching #{uri} to #{path}" }
266
+
267
+ http = Net::HTTP.new(uri.host, uri.port)
268
+ request = Net::HTTP::Get.new(uri.path)
269
+ response = http.start{|http| http.request(request)}
270
+ unless Net::HTTPSuccess === response
271
+ raise Error, "Could not get #{uri} because #{response.code} #{response.message}!"
272
+ end
273
+ write! path, response.body
274
+ end
275
+
276
+ def write!(path, bytes)
277
+ path.dirname.mkpath
278
+ path.open("wb"){|f| f.write(bytes)}
279
+ end
280
+
281
+ def unpack_package!(path, source)
282
+ path = Pathname(path)
283
+ source = Pathname(source)
284
+
285
+ temp = environment.scratch_path.join(SecureRandom.hex(16))
286
+ temp.mkpath
287
+
288
+ debug { "Unpacking #{relative_path_to(source)} to #{relative_path_to(temp)}" }
289
+ Zlib::GzipReader.open(source) do |input|
290
+ Archive::Tar::Minitar.unpack(input, temp.to_s)
291
+ end
292
+
293
+ # Cookbook files, as pulled from Opscode Community Site API, are
294
+ # embedded in a subdirectory of the tarball, and the subdirectory's
295
+ # name is equal to the name of the cookbook.
296
+ subtemp = temp.join(name)
297
+ debug { "Moving #{relative_path_to(subtemp)} to #{relative_path_to(path)}" }
298
+ FileUtils.mv(subtemp, path)
299
+ ensure
300
+ temp.rmtree if temp && temp.exist?
301
+ end
302
+
303
+ def parse_local_json(path)
304
+ JSON.parse(path.read)
305
+ end
306
+
307
+ def hexdigest(bytes)
308
+ Digest::MD5.hexdigest(bytes)
309
+ end
310
+
311
+ def to_uri(uri)
312
+ uri = URI(uri) unless URI === uri
313
+ uri
314
+ end
315
+
316
+ end
317
+
318
+ class << self
319
+
320
+ LOCK_NAME = 'SITE'
321
+
322
+ def lock_name
323
+ LOCK_NAME
324
+ end
325
+
326
+ def from_lock_options(environment, options)
327
+ new(environment, options[:remote], options.reject{|k, v| k == :remote})
328
+ end
329
+
330
+ def from_spec_args(environment, uri, options)
331
+ recognized_options = []
332
+ unrecognized_options = options.keys - recognized_options
333
+ unrecognized_options.empty? or raise Error, "unrecognized options: #{unrecognized_options.join(", ")}"
334
+
335
+ new(environment, uri, options)
336
+ end
337
+
338
+ end
339
+
340
+ attr_accessor :environment
341
+ private :environment=
342
+ attr_reader :uri
343
+
344
+ attr_accessor :_metadata_cache
345
+ private :_metadata_cache, :_metadata_cache=
346
+
347
+ def initialize(environment, uri, options = {})
348
+ self.environment = environment
349
+ @uri = uri
350
+ @cache_path = nil
351
+ self._metadata_cache = { }
352
+ end
353
+
354
+ def to_s
355
+ uri
356
+ end
357
+
358
+ def ==(other)
359
+ other &&
360
+ self.class == other.class &&
361
+ self.uri == other.uri
362
+ end
363
+
364
+ def to_spec_args
365
+ [uri, {}]
366
+ end
367
+
368
+ def to_lock_options
369
+ {:remote => uri}
370
+ end
371
+
372
+ def pinned?
373
+ false
374
+ end
375
+
376
+ def unpin!
377
+ end
378
+
379
+ def install!(manifest)
380
+ manifest.source == self or raise ArgumentError
381
+
382
+ name = manifest.name
383
+ version = manifest.version
384
+ install_path = install_path(name)
385
+ line = line(name)
386
+
387
+ debug { "Installing #{manifest}" }
388
+
389
+ line.install_version! version, install_path
390
+ end
391
+
392
+ # NOTE:
393
+ # Assumes the Opscode Site API responds with versions in reverse sorted order
394
+ def manifests(name)
395
+ line(name).manifests
396
+ end
397
+
398
+ def manifest(name, version, dependencies)
399
+ manifest = Manifest.new(self, name)
400
+ manifest.version = version
401
+ manifest.dependencies = dependencies
402
+ manifest
403
+ end
404
+
405
+ def cache_path
406
+ @cache_path ||= begin
407
+ dir = Digest::MD5.hexdigest(uri)
408
+ environment.cache_path.join("source/chef/site/#{dir}")
409
+ end
410
+ end
411
+
412
+ def install_path(name)
413
+ environment.install_path.join(name)
414
+ end
415
+
416
+ def fetch_version(name, version_uri)
417
+ line(name).to_version(version_uri)
418
+ end
419
+
420
+ def fetch_dependencies(name, version, version_uri)
421
+ line(name).version_dependencies(version).map{|k, v| Dependency.new(k, v, nil)}
422
+ end
423
+
424
+ private
425
+
426
+ def line(name)
427
+ @line ||= { }
428
+ @line[name] ||= Line.new(self, name)
429
+ end
430
+
431
+ end
432
+ end
433
+ end
434
+ end