librarian 0.0.25 → 0.0.26
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 +4 -0
- data/CHANGELOG.md +21 -0
- data/README.md +6 -1
- data/lib/librarian/action/persist_resolution_mixin.rb +51 -0
- data/lib/librarian/action/resolve.rb +3 -38
- data/lib/librarian/action/update.rb +4 -38
- data/lib/librarian/chef/dsl.rb +1 -0
- data/lib/librarian/chef/source.rb +1 -0
- data/lib/librarian/chef/source/github.rb +27 -0
- data/lib/librarian/chef/source/site.rb +51 -51
- data/lib/librarian/cli.rb +31 -23
- data/lib/librarian/cli/manifest_presenter.rb +36 -22
- data/lib/librarian/dependency.rb +60 -0
- data/lib/librarian/environment.rb +13 -1
- data/lib/librarian/linter/source_linter.rb +55 -0
- data/lib/librarian/lockfile/parser.rb +39 -16
- data/lib/librarian/manifest.rb +8 -0
- data/lib/librarian/manifest_set.rb +5 -7
- data/lib/librarian/mock/source/mock.rb +4 -21
- data/lib/librarian/resolution.rb +1 -1
- data/lib/librarian/resolver.rb +15 -12
- data/lib/librarian/resolver/implementation.rb +166 -75
- data/lib/librarian/source/basic_api.rb +45 -0
- data/lib/librarian/source/git.rb +4 -22
- data/lib/librarian/source/git/repository.rb +1 -1
- data/lib/librarian/source/local.rb +0 -7
- data/lib/librarian/source/path.rb +4 -22
- data/lib/librarian/version.rb +1 -1
- data/librarian.gemspec +3 -3
- data/spec/functional/chef/source/site_spec.rb +150 -100
- data/spec/functional/source/git/repository_spec.rb +2 -1
- data/spec/{functional → integration}/chef/source/git_spec.rb +12 -3
- data/spec/integration/chef/source/site_spec.rb +217 -0
- data/spec/support/cli_macro.rb +4 -12
- data/spec/support/method_patch_macro.rb +30 -0
- data/spec/unit/config/database_spec.rb +8 -0
- data/spec/unit/dependency_spec.rb +176 -0
- data/spec/unit/environment_spec.rb +76 -7
- data/spec/unit/resolver_spec.rb +2 -2
- metadata +52 -46
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 0.0.26
|
4
|
+
|
5
|
+
* \#112. Prevent the git source being confused in certain cases by colorized
|
6
|
+
output from git. HT: @ericpp.
|
7
|
+
|
8
|
+
* \#115, \#116. Accommodate cookbook archives generated by `git archive`.
|
9
|
+
HT: @taqtiqa-mark.
|
10
|
+
|
11
|
+
* \#119. Support NO_PROXY, a modifier on HTTP_PROXY and friends. HT: @databus23.
|
12
|
+
|
13
|
+
* \#121. A github pseudosource. HT: @alno.
|
14
|
+
|
15
|
+
* \#122. Follow http redirect responses in the chef site source. HT: @Fleurer.
|
16
|
+
|
17
|
+
* Improve the resolver performance by detecting conflicts earlier and
|
18
|
+
backtracking more quickly. This will help avoid certain cases of long
|
19
|
+
resolutions caused by conflicts; the conflicts will still be there, but will
|
20
|
+
be detected more quickly and the resolution terminated more quickly. This
|
21
|
+
changes the resolution algorithm, and new resolutions may differ from older
|
22
|
+
resolutions.
|
23
|
+
|
3
24
|
## 0.0.25
|
4
25
|
|
5
26
|
* \#71. Fix an error, given certain locale settings, with reading cookbook
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Librarian [](http://travis-ci.org/applicationsonline/librarian)
|
1
|
+
Librarian [](http://travis-ci.org/applicationsonline/librarian) [](https://codeclimate.com/github/applicationsonline/librarian)
|
2
2
|
=========
|
3
3
|
|
4
4
|
Librarian is a framework for writing bundlers, which are tools that resolve,
|
@@ -136,6 +136,11 @@ we vendored it in our repository into the `cookbooks/` directory for us.
|
|
136
136
|
The `:path =>` source won't be confused with the `:git =>` source's `:path =>`
|
137
137
|
option.
|
138
138
|
|
139
|
+
Also, there is shortcut for cookbooks hosted on GitHub, so we may write:
|
140
|
+
|
141
|
+
cookbook "rvm",
|
142
|
+
:github => "fnichol/chef-rvm"
|
143
|
+
|
139
144
|
### How to Use
|
140
145
|
|
141
146
|
Install Librarian-Chef:
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "librarian/error"
|
2
|
+
require "librarian/spec_change_set"
|
3
|
+
|
4
|
+
module Librarian
|
5
|
+
module Action
|
6
|
+
module PersistResolutionMixin
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def persist_resolution(resolution)
|
11
|
+
resolution.correct? or raise Error,
|
12
|
+
"Could not resolve the dependencies."
|
13
|
+
|
14
|
+
lockfile_text = lockfile.save(resolution)
|
15
|
+
debug { "Bouncing #{lockfile_name}" }
|
16
|
+
bounced_lockfile_text = lockfile.save(lockfile.load(lockfile_text))
|
17
|
+
unless bounced_lockfile_text == lockfile_text
|
18
|
+
debug { "lockfile_text: \n#{lockfile_text}" }
|
19
|
+
debug { "bounced_lockfile_text: \n#{bounced_lockfile_text}" }
|
20
|
+
raise Error, "Cannot bounce #{lockfile_name}!"
|
21
|
+
end
|
22
|
+
lockfile_path.open('wb') { |f| f.write(lockfile_text) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def specfile_name
|
26
|
+
environment.specfile_name
|
27
|
+
end
|
28
|
+
|
29
|
+
def lockfile_name
|
30
|
+
environment.lockfile_name
|
31
|
+
end
|
32
|
+
|
33
|
+
def specfile_path
|
34
|
+
environment.specfile_path
|
35
|
+
end
|
36
|
+
|
37
|
+
def lockfile_path
|
38
|
+
environment.lockfile_path
|
39
|
+
end
|
40
|
+
|
41
|
+
def specfile
|
42
|
+
environment.specfile
|
43
|
+
end
|
44
|
+
|
45
|
+
def lockfile
|
46
|
+
environment.lockfile
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -1,11 +1,12 @@
|
|
1
|
-
require "librarian/error"
|
2
1
|
require "librarian/resolver"
|
3
2
|
require "librarian/spec_change_set"
|
4
3
|
require "librarian/action/base"
|
4
|
+
require "librarian/action/persist_resolution_mixin"
|
5
5
|
|
6
6
|
module Librarian
|
7
7
|
module Action
|
8
8
|
class Resolve < Base
|
9
|
+
include PersistResolutionMixin
|
9
10
|
|
10
11
|
def run
|
11
12
|
if force? || !lockfile_path.exist?
|
@@ -23,19 +24,7 @@ module Librarian
|
|
23
24
|
end
|
24
25
|
|
25
26
|
resolution = resolver.resolve(spec, manifests)
|
26
|
-
|
27
|
-
raise Error, "Could not resolve the dependencies."
|
28
|
-
else
|
29
|
-
lockfile_text = lockfile.save(resolution)
|
30
|
-
debug { "Bouncing #{lockfile_name}" }
|
31
|
-
bounced_lockfile_text = lockfile.save(lockfile.load(lockfile_text))
|
32
|
-
unless bounced_lockfile_text == lockfile_text
|
33
|
-
debug { "lockfile_text: \n#{lockfile_text}"}
|
34
|
-
debug { "bounced_lockfile_text: \n#{bounced_lockfile_text}"}
|
35
|
-
raise Error, "Cannot bounce #{lockfile_name}!"
|
36
|
-
end
|
37
|
-
lockfile_path.open('wb') { |f| f.write(lockfile_text) }
|
38
|
-
end
|
27
|
+
persist_resolution(resolution)
|
39
28
|
end
|
40
29
|
|
41
30
|
private
|
@@ -44,30 +33,6 @@ module Librarian
|
|
44
33
|
options[:force]
|
45
34
|
end
|
46
35
|
|
47
|
-
def specfile_name
|
48
|
-
environment.specfile_name
|
49
|
-
end
|
50
|
-
|
51
|
-
def lockfile_name
|
52
|
-
environment.lockfile_name
|
53
|
-
end
|
54
|
-
|
55
|
-
def specfile_path
|
56
|
-
environment.specfile_path
|
57
|
-
end
|
58
|
-
|
59
|
-
def lockfile_path
|
60
|
-
environment.lockfile_path
|
61
|
-
end
|
62
|
-
|
63
|
-
def specfile
|
64
|
-
environment.specfile
|
65
|
-
end
|
66
|
-
|
67
|
-
def lockfile
|
68
|
-
environment.lockfile
|
69
|
-
end
|
70
|
-
|
71
36
|
def resolver
|
72
37
|
Resolver.new(environment)
|
73
38
|
end
|
@@ -1,12 +1,13 @@
|
|
1
|
-
require "librarian/error"
|
2
1
|
require "librarian/manifest_set"
|
3
2
|
require "librarian/resolver"
|
4
3
|
require "librarian/spec_change_set"
|
5
4
|
require "librarian/action/base"
|
5
|
+
require "librarian/action/persist_resolution_mixin"
|
6
6
|
|
7
7
|
module Librarian
|
8
8
|
module Action
|
9
9
|
class Update < Base
|
10
|
+
include PersistResolutionMixin
|
10
11
|
|
11
12
|
def run
|
12
13
|
unless lockfile_path.exist?
|
@@ -19,20 +20,9 @@ module Librarian
|
|
19
20
|
partial_manifests = ManifestSet.deep_strip(manifests, dependency_names)
|
20
21
|
unpinnable_sources = previous_resolution.sources - partial_manifests.map(&:source)
|
21
22
|
unpinnable_sources.each(&:unpin!)
|
23
|
+
|
22
24
|
resolution = resolver.resolve(spec, partial_manifests)
|
23
|
-
|
24
|
-
raise Error, "Could not resolve the dependencies."
|
25
|
-
else
|
26
|
-
lockfile_text = lockfile.save(resolution)
|
27
|
-
debug { "Bouncing #{lockfile_name}" }
|
28
|
-
bounced_lockfile_text = lockfile.save(lockfile.load(lockfile_text))
|
29
|
-
unless bounced_lockfile_text == lockfile_text
|
30
|
-
debug { "lockfile_text: \n#{lockfile_text}"}
|
31
|
-
debug { "bounced_lockfile_text: \n#{bounced_lockfile_text}"}
|
32
|
-
raise Error, "Cannot bounce #{lockfile_name}!"
|
33
|
-
end
|
34
|
-
lockfile_path.open('wb') { |f| f.write(lockfile_text) }
|
35
|
-
end
|
25
|
+
persist_resolution(resolution)
|
36
26
|
end
|
37
27
|
|
38
28
|
private
|
@@ -41,30 +31,6 @@ module Librarian
|
|
41
31
|
options[:names]
|
42
32
|
end
|
43
33
|
|
44
|
-
def specfile_name
|
45
|
-
environment.specfile_name
|
46
|
-
end
|
47
|
-
|
48
|
-
def lockfile_name
|
49
|
-
environment.lockfile_name
|
50
|
-
end
|
51
|
-
|
52
|
-
def specfile_path
|
53
|
-
environment.specfile_path
|
54
|
-
end
|
55
|
-
|
56
|
-
def lockfile_path
|
57
|
-
environment.lockfile_path
|
58
|
-
end
|
59
|
-
|
60
|
-
def specfile
|
61
|
-
environment.specfile
|
62
|
-
end
|
63
|
-
|
64
|
-
def lockfile
|
65
|
-
environment.lockfile
|
66
|
-
end
|
67
|
-
|
68
34
|
def resolver
|
69
35
|
Resolver.new(environment)
|
70
36
|
end
|
data/lib/librarian/chef/dsl.rb
CHANGED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'librarian/chef/source/git'
|
2
|
+
|
3
|
+
module Librarian
|
4
|
+
module Chef
|
5
|
+
module Source
|
6
|
+
class Github
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def lock_name
|
11
|
+
Git.lock_name
|
12
|
+
end
|
13
|
+
|
14
|
+
def from_lock_options(environment, options)
|
15
|
+
Git.from_lock_options(environment, options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def from_spec_args(environment, uri, options)
|
19
|
+
Git.from_spec_args(environment, "https://github.com/#{uri}", options)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -8,6 +8,7 @@ require 'zlib'
|
|
8
8
|
require 'securerandom'
|
9
9
|
require 'archive/tar/minitar'
|
10
10
|
|
11
|
+
require 'librarian/source/basic_api'
|
11
12
|
require 'librarian/chef/manifest_reader'
|
12
13
|
|
13
14
|
module Librarian
|
@@ -76,8 +77,7 @@ module Librarian
|
|
76
77
|
end
|
77
78
|
|
78
79
|
def version_uri_metadata(version_uri)
|
79
|
-
|
80
|
-
@version_uri_metadata[version_uri.to_s] ||= begin
|
80
|
+
memo(__method__, version_uri.to_s) do
|
81
81
|
cache_version_uri_metadata! version_uri
|
82
82
|
parse_local_json(version_uri_metadata_cache_path(version_uri))
|
83
83
|
end
|
@@ -89,8 +89,7 @@ module Librarian
|
|
89
89
|
end
|
90
90
|
|
91
91
|
def version_uri_manifest(version_uri)
|
92
|
-
|
93
|
-
@version_uri_manifest[version_uri.to_s] ||= begin
|
92
|
+
memo(__method__, version_uri.to_s) do
|
94
93
|
cache_version_uri_unpacked! version_uri
|
95
94
|
unpacked_path = version_uri_unpacked_cache_path(version_uri)
|
96
95
|
manifest_path = ManifestReader.manifest_path(unpacked_path)
|
@@ -106,8 +105,7 @@ module Librarian
|
|
106
105
|
end
|
107
106
|
|
108
107
|
def to_version_uri(version)
|
109
|
-
|
110
|
-
@to_version_uri[version.to_s] ||= begin
|
108
|
+
memo(__method__, version.to_s) do
|
111
109
|
cache_version! version
|
112
110
|
version_cache_path(version).read
|
113
111
|
end
|
@@ -126,15 +124,13 @@ module Librarian
|
|
126
124
|
end
|
127
125
|
|
128
126
|
def version_cache_path(version)
|
129
|
-
|
130
|
-
@version_cache_path[version.to_s] ||= begin
|
127
|
+
memo(__method__, version.to_s) do
|
131
128
|
cache_path.join("version").join(version.to_s)
|
132
129
|
end
|
133
130
|
end
|
134
131
|
|
135
132
|
def version_uri_cache_path(version_uri)
|
136
|
-
|
137
|
-
@version_uri_cache_path[version_uri.to_s] ||= begin
|
133
|
+
memo(__method__, version_uri.to_s) do
|
138
134
|
cache_path.join("version-uri").join(hexdigest(version_uri))
|
139
135
|
end
|
140
136
|
end
|
@@ -145,8 +141,7 @@ module Librarian
|
|
145
141
|
end
|
146
142
|
|
147
143
|
def version_uri_metadata_cache_path(version_uri)
|
148
|
-
|
149
|
-
@version_uri_metadata_cache_path[version_uri.to_s] ||= begin
|
144
|
+
memo(__method__, version_uri.to_s) do
|
150
145
|
version_uri_cache_path(version_uri).join("metadata.json")
|
151
146
|
end
|
152
147
|
end
|
@@ -157,8 +152,7 @@ module Librarian
|
|
157
152
|
end
|
158
153
|
|
159
154
|
def version_uri_package_cache_path(version_uri)
|
160
|
-
|
161
|
-
@version_uri_package_cache_path[version_uri.to_s] ||= begin
|
155
|
+
memo(__method__, version_uri.to_s) do
|
162
156
|
version_uri_cache_path(version_uri).join("package.tar.gz")
|
163
157
|
end
|
164
158
|
end
|
@@ -169,8 +163,7 @@ module Librarian
|
|
169
163
|
end
|
170
164
|
|
171
165
|
def version_uri_unpacked_cache_path(version_uri)
|
172
|
-
|
173
|
-
@version_uri_unpacked_cache_path[version_uri.to_s] ||= begin
|
166
|
+
memo(__method__, version_uri.to_s) do
|
174
167
|
version_uri_cache_path(version_uri).join("package")
|
175
168
|
end
|
176
169
|
end
|
@@ -243,9 +236,6 @@ module Librarian
|
|
243
236
|
debug { "Caching #{uri} to #{path}" }
|
244
237
|
|
245
238
|
response = http_get(uri)
|
246
|
-
unless Net::HTTPSuccess === response
|
247
|
-
raise Error, "Could not get #{uri} because #{response.code} #{response.message}!"
|
248
|
-
end
|
249
239
|
|
250
240
|
object = response.body
|
251
241
|
case type
|
@@ -273,9 +263,11 @@ module Librarian
|
|
273
263
|
end
|
274
264
|
|
275
265
|
# Cookbook files, as pulled from Opscode Community Site API, are
|
276
|
-
# embedded in a subdirectory of the tarball.
|
266
|
+
# embedded in a subdirectory of the tarball. If created by git archive they
|
267
|
+
# can include the subfolder `pax_global_header`, which is ignored.
|
277
268
|
subtemps = temp.children
|
278
269
|
subtemps.empty? and raise "The package archive was empty!"
|
270
|
+
subtemps.delete_if{|pth| pth.to_s[/pax_global_header/]}
|
279
271
|
subtemps.size > 1 and raise "The package archive has too many children!"
|
280
272
|
subtemp = subtemps.first
|
281
273
|
debug { "Moving #{relative_path_to(subtemp)} to #{relative_path_to(path)}" }
|
@@ -306,40 +298,55 @@ module Librarian
|
|
306
298
|
end
|
307
299
|
|
308
300
|
def http(uri)
|
309
|
-
environment.net_http_class.new(uri.host, uri.port)
|
301
|
+
environment.net_http_class(uri.host).new(uri.host, uri.port)
|
310
302
|
end
|
311
303
|
|
312
304
|
def http_get(uri)
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
305
|
+
max_redirects = 10
|
306
|
+
redirects = []
|
307
|
+
|
308
|
+
loop do
|
309
|
+
debug { "Performing http-get for #{uri}" }
|
310
|
+
http = http(uri)
|
311
|
+
request = Net::HTTP::Get.new(uri.path)
|
312
|
+
response = http.start{|http| http.request(request)}
|
313
|
+
|
314
|
+
case response
|
315
|
+
when Net::HTTPSuccess
|
316
|
+
debug { "Responded with success" }
|
317
|
+
return response
|
318
|
+
when Net::HTTPRedirection
|
319
|
+
location = response["Location"]
|
320
|
+
debug { "Responded with redirect to #{uri}" }
|
321
|
+
redirects.size > max_redirects and raise Error,
|
322
|
+
"Could not get #{uri} because too many redirects!"
|
323
|
+
redirects.include?(location) and raise Error,
|
324
|
+
"Could not get #{uri} because redirect cycle!"
|
325
|
+
redirects << location
|
326
|
+
uri = URI.parse(location)
|
327
|
+
# continue the loop
|
328
|
+
else
|
329
|
+
raise Error, "Could not get #{uri} because #{response.code} #{response.message}!"
|
330
|
+
end
|
331
|
+
end
|
318
332
|
end
|
319
333
|
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
def lock_name
|
327
|
-
LOCK_NAME
|
328
|
-
end
|
334
|
+
def memo(method, *path)
|
335
|
+
ivar = "@#{method}".to_sym
|
336
|
+
unless memo = instance_variable_get(ivar)
|
337
|
+
memo = instance_variable_set(ivar, { })
|
338
|
+
end
|
329
339
|
|
330
|
-
|
331
|
-
|
340
|
+
memo.key?(path) or memo[path] = yield
|
341
|
+
memo[path]
|
332
342
|
end
|
333
343
|
|
334
|
-
|
335
|
-
recognized_options = []
|
336
|
-
unrecognized_options = options.keys - recognized_options
|
337
|
-
unrecognized_options.empty? or raise Error, "unrecognized options: #{unrecognized_options.join(", ")}"
|
344
|
+
end
|
338
345
|
|
339
|
-
|
340
|
-
end
|
346
|
+
include Librarian::Source::BasicApi
|
341
347
|
|
342
|
-
|
348
|
+
lock_name 'SITE'
|
349
|
+
spec_options []
|
343
350
|
|
344
351
|
attr_accessor :environment, :uri
|
345
352
|
private :environment=, :uri=
|
@@ -395,13 +402,6 @@ module Librarian
|
|
395
402
|
line(name).manifests
|
396
403
|
end
|
397
404
|
|
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
405
|
def cache_path
|
406
406
|
@cache_path ||= begin
|
407
407
|
dir = Digest::MD5.hexdigest(uri)
|