librarian-puppet 1.0.1 → 1.0.2
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.
- checksums.yaml +4 -4
- data/README.md +5 -5
- data/lib/librarian/puppet/source/forge.rb +13 -206
- data/lib/librarian/puppet/source/forge/repo.rb +182 -0
- data/lib/librarian/puppet/source/git.rb +10 -3
- data/lib/librarian/puppet/source/githubtarball.rb +9 -163
- data/lib/librarian/puppet/source/githubtarball/repo.rb +149 -0
- data/lib/librarian/puppet/source/local.rb +5 -1
- data/lib/librarian/puppet/source/repo.rb +38 -0
- data/lib/librarian/puppet/util.rb +8 -0
- data/lib/librarian/puppet/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dbe00d37667721e7a61be8fb75277e88f75dec0d
|
4
|
+
data.tar.gz: 6655c8212fe01704c529ea35fcbc7ada5ed14a1b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 41f48efc10bb44b6ab924bc2040d686264a1e74ee58f1a179bf23552e4947df3f2b94251fc92d96ad3ada0ad2fe3bada5c765a5ff7f174c2da67b1fe69f9a44e
|
7
|
+
data.tar.gz: 59f9a5784cf4c0f801806c6821cf5c7ca33fbb577022ef6fcdae428d932d24ff918e0692bee4a8aebe9cab60de901de9d2f40a90587aaf9a008475d41c3c7f4f
|
data/README.md
CHANGED
@@ -6,11 +6,11 @@
|
|
6
6
|
|
7
7
|
Librarian-puppet is a bundler for your puppet infrastructure. You can use
|
8
8
|
librarian-puppet to manage the puppet modules your infrastructure depends on,
|
9
|
-
whether the modules come from the [Puppet Forge](
|
9
|
+
whether the modules come from the [Puppet Forge](https://forge.puppetlabs.com/),
|
10
10
|
Git repositories or a just a path.
|
11
11
|
|
12
12
|
* Librarian-puppet can reuse the dependencies listed in your Modulefile
|
13
|
-
* Forge modules can be installed from [Puppetlabs Forge](
|
13
|
+
* Forge modules can be installed from [Puppetlabs Forge](https://forge.puppetlabs.com/) or an internal Forge such as [Pulp](http://www.pulpproject.org/)
|
14
14
|
* Git modules can be installed from a branch, tag or specific commit, optionally using a path inside the repository
|
15
15
|
* Modules can be installed from GitHub using tarballs, without needing Git installed
|
16
16
|
* Module dependencies are resolved transitively without needing to list all the modules explicitly
|
@@ -38,14 +38,14 @@ for which modules your puppet infrastructure repository depends goes in here.
|
|
38
38
|
|
39
39
|
This Puppetfile will download all the dependencies listed in your Modulefile from the Puppet Forge
|
40
40
|
|
41
|
-
forge "
|
41
|
+
forge "https://forge.puppetlabs.com"
|
42
42
|
|
43
43
|
modulefile
|
44
44
|
|
45
45
|
|
46
46
|
### Example Puppetfile
|
47
47
|
|
48
|
-
forge "
|
48
|
+
forge "https://forge.puppetlabs.com"
|
49
49
|
|
50
50
|
mod "puppetlabs/razor"
|
51
51
|
mod "puppetlabs/ntp", "0.0.3"
|
@@ -67,7 +67,7 @@ When fetching a module all dependencies specified in its
|
|
67
67
|
|
68
68
|
### Puppetfile Breakdown
|
69
69
|
|
70
|
-
forge "
|
70
|
+
forge "https://forge.puppetlabs.com"
|
71
71
|
|
72
72
|
This declares that we want to use the official Puppet Labs Forge as our default
|
73
73
|
source when pulling down modules. If you run your own local forge, you may
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require '
|
2
|
-
require 'open-uri'
|
1
|
+
require 'uri'
|
3
2
|
require 'librarian/puppet/util'
|
3
|
+
require 'librarian/puppet/source/forge/repo'
|
4
4
|
|
5
5
|
module Librarian
|
6
6
|
module Puppet
|
@@ -8,204 +8,6 @@ module Librarian
|
|
8
8
|
class Forge
|
9
9
|
include Librarian::Puppet::Util
|
10
10
|
|
11
|
-
class Repo
|
12
|
-
include Librarian::Puppet::Util
|
13
|
-
|
14
|
-
attr_accessor :source, :name
|
15
|
-
private :source=, :name=
|
16
|
-
|
17
|
-
def initialize(source, name)
|
18
|
-
self.source = source
|
19
|
-
self.name = name
|
20
|
-
# API returned data for this module including all versions and dependencies, indexed by module name
|
21
|
-
# from http://forge.puppetlabs.com/api/v1/releases.json?module=#{name}
|
22
|
-
@api_data = nil
|
23
|
-
# API returned data for this module and a specific version, indexed by version
|
24
|
-
# from http://forge.puppetlabs.com/api/v1/releases.json?module=#{name}&version=#{version}
|
25
|
-
@api_version_data = {}
|
26
|
-
end
|
27
|
-
|
28
|
-
def versions
|
29
|
-
return @versions if @versions
|
30
|
-
@versions = api_data(name).map { |r| r['version'] }.reverse
|
31
|
-
if @versions.empty?
|
32
|
-
info { "No versions found for module #{name}" }
|
33
|
-
else
|
34
|
-
debug { " Module #{name} found versions: #{@versions.join(", ")}" }
|
35
|
-
end
|
36
|
-
@versions
|
37
|
-
end
|
38
|
-
|
39
|
-
def dependencies(version)
|
40
|
-
api_version_data(name, version)['dependencies']
|
41
|
-
end
|
42
|
-
|
43
|
-
def manifests
|
44
|
-
versions.map do |version|
|
45
|
-
Manifest.new(source, name, version)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def install_version!(version, install_path)
|
50
|
-
if environment.local? && !vendored?(name, version)
|
51
|
-
raise Error, "Could not find a local copy of #{name} at #{version}."
|
52
|
-
end
|
53
|
-
|
54
|
-
if environment.vendor?
|
55
|
-
vendor_cache(name, version) unless vendored?(name, version)
|
56
|
-
end
|
57
|
-
|
58
|
-
cache_version_unpacked! version
|
59
|
-
|
60
|
-
if install_path.exist?
|
61
|
-
install_path.rmtree
|
62
|
-
end
|
63
|
-
|
64
|
-
unpacked_path = version_unpacked_cache_path(version).join(name.split('/').last)
|
65
|
-
|
66
|
-
unless unpacked_path.exist?
|
67
|
-
raise Error, "#{unpacked_path} does not exist, something went wrong. Try removing it manually"
|
68
|
-
else
|
69
|
-
cp_r(unpacked_path, install_path)
|
70
|
-
end
|
71
|
-
|
72
|
-
end
|
73
|
-
|
74
|
-
def environment
|
75
|
-
source.environment
|
76
|
-
end
|
77
|
-
|
78
|
-
def cache_path
|
79
|
-
@cache_path ||= source.cache_path.join(name)
|
80
|
-
end
|
81
|
-
|
82
|
-
def version_unpacked_cache_path(version)
|
83
|
-
cache_path.join('version').join(hexdigest(version.to_s))
|
84
|
-
end
|
85
|
-
|
86
|
-
def hexdigest(value)
|
87
|
-
Digest::MD5.hexdigest(value)
|
88
|
-
end
|
89
|
-
|
90
|
-
def cache_version_unpacked!(version)
|
91
|
-
path = version_unpacked_cache_path(version)
|
92
|
-
return if path.directory?
|
93
|
-
|
94
|
-
# The puppet module command is only available from puppet versions >= 2.7.13
|
95
|
-
#
|
96
|
-
# Specifying the version in the gemspec would force people to upgrade puppet while it's still usable for git
|
97
|
-
# So we do some more clever checking
|
98
|
-
#
|
99
|
-
# Executing older versions or via puppet-module tool gives an exit status = 0 .
|
100
|
-
#
|
101
|
-
check_puppet_module_options
|
102
|
-
|
103
|
-
path.mkpath
|
104
|
-
|
105
|
-
target = vendored?(name, version) ? vendored_path(name, version).to_s : name
|
106
|
-
|
107
|
-
# TODO can't pass the default forge url (http://forge.puppetlabs.com) to clients that use the v3 API (https://forgeapi.puppetlabs.com)
|
108
|
-
module_repository = source.to_s
|
109
|
-
if Forge.client_api_version() > 1 and source =~ %r{^http(s)?://forge\.puppetlabs\.com}
|
110
|
-
module_repository = "https://forgeapi.puppetlabs.com"
|
111
|
-
warn("Your Puppet client uses the Forge API v3, you should use this Forge URL: #{module_repository}")
|
112
|
-
end
|
113
|
-
|
114
|
-
command = %W{puppet module install --version #{version} --target-dir}
|
115
|
-
command.push(*[path.to_s, "--module_repository", module_repository, "--modulepath", path.to_s, "--module_working_dir", path.to_s, "--ignore-dependencies", target])
|
116
|
-
debug { "Executing puppet module install for #{name} #{version}" }
|
117
|
-
|
118
|
-
begin
|
119
|
-
Librarian::Posix.run!(command)
|
120
|
-
rescue Posix::CommandFailure => e
|
121
|
-
# Rollback the directory if the puppet module had an error
|
122
|
-
begin
|
123
|
-
path.unlink
|
124
|
-
rescue => u
|
125
|
-
warn("Unable to rollback path #{path}: #{u}")
|
126
|
-
end
|
127
|
-
tar = Dir[File.join(path.to_s, "**/*.tar.gz")]
|
128
|
-
msg = ""
|
129
|
-
if e.message =~ /Unexpected EOF in archive/ and !tar.empty?
|
130
|
-
file = tar.first
|
131
|
-
msg = " (looks like an incomplete download of #{file})"
|
132
|
-
end
|
133
|
-
raise Error, "Error executing puppet module install#{msg}:\n#{command.join(" ")}\nError:\n#{e.message}"
|
134
|
-
end
|
135
|
-
|
136
|
-
end
|
137
|
-
|
138
|
-
def check_puppet_module_options
|
139
|
-
min_version = Gem::Version.create('2.7.13')
|
140
|
-
|
141
|
-
if Librarian::Puppet.puppet_gem_version < min_version
|
142
|
-
raise Error, "To get modules from the forge, we use the puppet faces module command. For this you need at least puppet version 2.7.13 and you have #{puppet_version}"
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
def vendored?(name, version)
|
147
|
-
vendored_path(name, version).exist?
|
148
|
-
end
|
149
|
-
|
150
|
-
def vendored_path(name, version)
|
151
|
-
environment.vendor_cache.join("#{name.sub("/", "-")}-#{version}.tar.gz")
|
152
|
-
end
|
153
|
-
|
154
|
-
def vendor_cache(name, version)
|
155
|
-
info = api_version_data(name, version)
|
156
|
-
url = "#{source}#{info[name].first['file']}"
|
157
|
-
path = vendored_path(name, version).to_s
|
158
|
-
debug { "Downloading #{url} into #{path}"}
|
159
|
-
File.open(path, 'wb') do |f|
|
160
|
-
open(url, "rb") do |input|
|
161
|
-
f.write(input.read)
|
162
|
-
end
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
private
|
167
|
-
|
168
|
-
# get and cache the API data for a specific module with all its versions and dependencies
|
169
|
-
def api_data(module_name)
|
170
|
-
return @api_data[module_name] if @api_data
|
171
|
-
# call API and cache data
|
172
|
-
@api_data = api_call(module_name)
|
173
|
-
if @api_data.nil?
|
174
|
-
raise Error, "Unable to find module '#{name}' on #{source}"
|
175
|
-
end
|
176
|
-
@api_data[module_name]
|
177
|
-
end
|
178
|
-
|
179
|
-
# get and cache the API data for a specific module and version
|
180
|
-
def api_version_data(module_name, version)
|
181
|
-
# if we already got all the versions, find in cached data
|
182
|
-
return @api_data[module_name].detect{|x| x['version'] == version.to_s} if @api_data
|
183
|
-
# otherwise call the api for this version if not cached already
|
184
|
-
@api_version_data[version] = api_call(name, version) if @api_version_data[version].nil?
|
185
|
-
@api_version_data[version]
|
186
|
-
end
|
187
|
-
|
188
|
-
def api_call(module_name, version=nil)
|
189
|
-
base_url = source.uri
|
190
|
-
path = "api/v1/releases.json?module=#{module_name}"
|
191
|
-
path = "#{path}&version=#{version}" unless version.nil?
|
192
|
-
url = "#{base_url}/#{path}"
|
193
|
-
debug { "Querying Forge API for module #{name}#{" and version #{version}" unless version.nil?}: #{url}" }
|
194
|
-
|
195
|
-
begin
|
196
|
-
data = open(url) {|f| f.read}
|
197
|
-
JSON.parse(data)
|
198
|
-
rescue OpenURI::HTTPError => e
|
199
|
-
case e.io.status[0].to_i
|
200
|
-
when 404,410
|
201
|
-
nil
|
202
|
-
else
|
203
|
-
raise e, "Error requesting #{base_url}/#{path}: #{e.to_s}"
|
204
|
-
end
|
205
|
-
end
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
11
|
class << self
|
210
12
|
LOCK_NAME = 'FORGE'
|
211
13
|
|
@@ -231,8 +33,11 @@ module Librarian
|
|
231
33
|
version = 1
|
232
34
|
pe_version = Librarian::Puppet.puppet_version.match(/\(Puppet Enterprise (.+)\)/)
|
233
35
|
|
36
|
+
# Puppet 3.6.0+ uses api v3
|
37
|
+
if Librarian::Puppet::puppet_gem_version >= Gem::Version.create('3.6.0.a')
|
38
|
+
version = 3
|
234
39
|
# Puppet enterprise 3.2.0+ uses api v3
|
235
|
-
|
40
|
+
elsif pe_version and Gem::Version.create(pe_version[1].strip) >= Gem::Version.create('3.2.0')
|
236
41
|
version = 3
|
237
42
|
end
|
238
43
|
return version
|
@@ -246,12 +51,12 @@ module Librarian
|
|
246
51
|
|
247
52
|
def initialize(environment, uri, options = {})
|
248
53
|
self.environment = environment
|
249
|
-
@uri = uri
|
54
|
+
@uri = URI::parse(uri)
|
250
55
|
@cache_path = nil
|
251
56
|
end
|
252
57
|
|
253
58
|
def to_s
|
254
|
-
uri
|
59
|
+
clean_uri(uri).to_s
|
255
60
|
end
|
256
61
|
|
257
62
|
def ==(other)
|
@@ -267,11 +72,11 @@ module Librarian
|
|
267
72
|
end
|
268
73
|
|
269
74
|
def to_spec_args
|
270
|
-
[uri, {}]
|
75
|
+
[clean_uri(uri).to_s, {}]
|
271
76
|
end
|
272
77
|
|
273
78
|
def to_lock_options
|
274
|
-
{:remote => uri}
|
79
|
+
{:remote => clean_uri(uri).to_s}
|
275
80
|
end
|
276
81
|
|
277
82
|
def pinned?
|
@@ -284,6 +89,8 @@ module Librarian
|
|
284
89
|
def install!(manifest)
|
285
90
|
manifest.source == self or raise ArgumentError
|
286
91
|
|
92
|
+
debug { "Installing #{manifest}" }
|
93
|
+
|
287
94
|
name = manifest.name
|
288
95
|
version = manifest.version
|
289
96
|
install_path = install_path(name)
|
@@ -301,7 +108,7 @@ module Librarian
|
|
301
108
|
|
302
109
|
def cache_path
|
303
110
|
@cache_path ||= begin
|
304
|
-
dir =
|
111
|
+
dir = "#{uri.host}#{uri.path}".gsub(/[^0-9a-z\-_]/i, '_')
|
305
112
|
environment.cache_path.join("source/puppet/forge/#{dir}")
|
306
113
|
end
|
307
114
|
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'librarian/puppet/util'
|
4
|
+
require 'librarian/puppet/source/repo'
|
5
|
+
|
6
|
+
module Librarian
|
7
|
+
module Puppet
|
8
|
+
module Source
|
9
|
+
class Forge
|
10
|
+
class Repo < Librarian::Puppet::Source::Repo
|
11
|
+
include Librarian::Puppet::Util
|
12
|
+
|
13
|
+
def initialize(source, name)
|
14
|
+
super(source, name)
|
15
|
+
# API returned data for this module including all versions and dependencies, indexed by module name
|
16
|
+
# from http://forge.puppetlabs.com/api/v1/releases.json?module=#{name}
|
17
|
+
@api_data = nil
|
18
|
+
# API returned data for this module and a specific version, indexed by version
|
19
|
+
# from http://forge.puppetlabs.com/api/v1/releases.json?module=#{name}&version=#{version}
|
20
|
+
@api_version_data = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def versions
|
24
|
+
return @versions if @versions
|
25
|
+
@versions = api_data(name).map { |r| r['version'] }.reverse
|
26
|
+
if @versions.empty?
|
27
|
+
info { "No versions found for module #{name}" }
|
28
|
+
else
|
29
|
+
debug { " Module #{name} found versions: #{@versions.join(", ")}" }
|
30
|
+
end
|
31
|
+
@versions
|
32
|
+
end
|
33
|
+
|
34
|
+
def dependencies(version)
|
35
|
+
api_version_data(name, version)['dependencies']
|
36
|
+
end
|
37
|
+
|
38
|
+
def manifests
|
39
|
+
versions.map do |version|
|
40
|
+
Manifest.new(source, name, version)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def install_version!(version, install_path)
|
45
|
+
if environment.local? && !vendored?(name, version)
|
46
|
+
raise Error, "Could not find a local copy of #{name} at #{version}."
|
47
|
+
end
|
48
|
+
|
49
|
+
if environment.vendor?
|
50
|
+
vendor_cache(name, version) unless vendored?(name, version)
|
51
|
+
end
|
52
|
+
|
53
|
+
cache_version_unpacked! version
|
54
|
+
|
55
|
+
if install_path.exist?
|
56
|
+
install_path.rmtree
|
57
|
+
end
|
58
|
+
|
59
|
+
unpacked_path = version_unpacked_cache_path(version).join(name.split('/').last)
|
60
|
+
|
61
|
+
unless unpacked_path.exist?
|
62
|
+
raise Error, "#{unpacked_path} does not exist, something went wrong. Try removing it manually"
|
63
|
+
else
|
64
|
+
cp_r(unpacked_path, install_path)
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
def cache_version_unpacked!(version)
|
70
|
+
path = version_unpacked_cache_path(version)
|
71
|
+
return if path.directory?
|
72
|
+
|
73
|
+
# The puppet module command is only available from puppet versions >= 2.7.13
|
74
|
+
#
|
75
|
+
# Specifying the version in the gemspec would force people to upgrade puppet while it's still usable for git
|
76
|
+
# So we do some more clever checking
|
77
|
+
#
|
78
|
+
# Executing older versions or via puppet-module tool gives an exit status = 0 .
|
79
|
+
#
|
80
|
+
check_puppet_module_options
|
81
|
+
|
82
|
+
path.mkpath
|
83
|
+
|
84
|
+
target = vendored?(name, version) ? vendored_path(name, version).to_s : name
|
85
|
+
|
86
|
+
# TODO can't pass the default forge url (http://forge.puppetlabs.com) to clients that use the v3 API (https://forgeapi.puppetlabs.com)
|
87
|
+
module_repository = source.to_s
|
88
|
+
if Forge.client_api_version() > 1 and module_repository =~ %r{^http(s)?://forge\.puppetlabs\.com}
|
89
|
+
module_repository = "https://forgeapi.puppetlabs.com"
|
90
|
+
end
|
91
|
+
|
92
|
+
command = %W{puppet module install --version #{version} --target-dir}
|
93
|
+
command.push(*[path.to_s, "--module_repository", module_repository, "--modulepath", path.to_s, "--module_working_dir", path.to_s, "--ignore-dependencies", target])
|
94
|
+
debug { "Executing puppet module install for #{name} #{version}" }
|
95
|
+
|
96
|
+
begin
|
97
|
+
Librarian::Posix.run!(command)
|
98
|
+
rescue Posix::CommandFailure => e
|
99
|
+
# Rollback the directory if the puppet module had an error
|
100
|
+
begin
|
101
|
+
path.unlink
|
102
|
+
rescue => u
|
103
|
+
debug("Unable to rollback path #{path}: #{u}")
|
104
|
+
end
|
105
|
+
tar = Dir[File.join(path.to_s, "**/*.tar.gz")]
|
106
|
+
msg = ""
|
107
|
+
if e.message =~ /Unexpected EOF in archive/ and !tar.empty?
|
108
|
+
file = tar.first
|
109
|
+
msg = " (looks like an incomplete download of #{file})"
|
110
|
+
end
|
111
|
+
raise Error, "Error executing puppet module install#{msg}. Check that this command succeeds:\n#{command.join(" ")}\nError:\n#{e.message}"
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
def check_puppet_module_options
|
117
|
+
min_version = Gem::Version.create('2.7.13')
|
118
|
+
|
119
|
+
if Librarian::Puppet.puppet_gem_version < min_version
|
120
|
+
raise Error, "To get modules from the forge, we use the puppet faces module command. For this you need at least puppet version 2.7.13 and you have #{puppet_version}"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def vendor_cache(name, version)
|
125
|
+
info = api_version_data(name, version)
|
126
|
+
url = "#{source}#{info[name].first['file']}"
|
127
|
+
path = vendored_path(name, version).to_s
|
128
|
+
debug { "Downloading #{url} into #{path}"}
|
129
|
+
environment.vendor!
|
130
|
+
File.open(path, 'wb') do |f|
|
131
|
+
open(url, "rb") do |input|
|
132
|
+
f.write(input.read)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
# get and cache the API data for a specific module with all its versions and dependencies
|
140
|
+
def api_data(module_name)
|
141
|
+
return @api_data[module_name] if @api_data
|
142
|
+
# call API and cache data
|
143
|
+
@api_data = api_call(module_name)
|
144
|
+
if @api_data.nil?
|
145
|
+
raise Error, "Unable to find module '#{name}' on #{source}"
|
146
|
+
end
|
147
|
+
@api_data[module_name]
|
148
|
+
end
|
149
|
+
|
150
|
+
# get and cache the API data for a specific module and version
|
151
|
+
def api_version_data(module_name, version)
|
152
|
+
# if we already got all the versions, find in cached data
|
153
|
+
return @api_data[module_name].detect{|x| x['version'] == version.to_s} if @api_data
|
154
|
+
# otherwise call the api for this version if not cached already
|
155
|
+
@api_version_data[version] = api_call(name, version) if @api_version_data[version].nil?
|
156
|
+
@api_version_data[version]
|
157
|
+
end
|
158
|
+
|
159
|
+
def api_call(module_name, version=nil)
|
160
|
+
url = source.uri.clone
|
161
|
+
url.path += "#{'/' if url.path.empty? or url.path[-1] != '/'}api/v1/releases.json"
|
162
|
+
url.query = "module=#{module_name}"
|
163
|
+
url.query += "&version=#{version}" unless version.nil?
|
164
|
+
debug { "Querying Forge API for module #{name}#{" and version #{version}" unless version.nil?}: #{url}" }
|
165
|
+
|
166
|
+
begin
|
167
|
+
data = open(url) {|f| f.read}
|
168
|
+
JSON.parse(data)
|
169
|
+
rescue OpenURI::HTTPError => e
|
170
|
+
case e.io.status[0].to_i
|
171
|
+
when 404,410
|
172
|
+
nil
|
173
|
+
else
|
174
|
+
raise e, "Error requesting #{url}: #{e.to_s}"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
@@ -36,8 +36,14 @@ module Librarian
|
|
36
36
|
cache_in_vendor(repository.path) if environment.vendor?
|
37
37
|
end
|
38
38
|
|
39
|
+
private
|
40
|
+
|
41
|
+
def vendor_tar
|
42
|
+
environment.vendor_source.join("#{sha}.tar")
|
43
|
+
end
|
44
|
+
|
39
45
|
def vendor_tgz
|
40
|
-
environment.vendor_source
|
46
|
+
environment.vendor_source.join("#{sha}.tar.gz")
|
41
47
|
end
|
42
48
|
|
43
49
|
def vendor_cached?
|
@@ -48,13 +54,14 @@ module Librarian
|
|
48
54
|
repository.path.rmtree if repository.path.exist?
|
49
55
|
repository.path.mkpath
|
50
56
|
|
51
|
-
run!(%W{tar xzf #{vendor_tgz}}, :chdir => repository.path.to_s)
|
57
|
+
Librarian::Posix.run!(%W{tar xzf #{vendor_tgz}}, :chdir => repository.path.to_s)
|
52
58
|
|
53
59
|
repository_cached!
|
54
60
|
end
|
55
61
|
|
56
62
|
def cache_in_vendor(tmp_path)
|
57
|
-
run!(%W{git archive #{
|
63
|
+
Librarian::Posix.run!(%W{git archive -o #{vendor_tar} #{sha}}, :chdir => tmp_path.to_s)
|
64
|
+
Librarian::Posix.run!(%W{gzip #{vendor_tar}}, :chdir => tmp_path.to_s)
|
58
65
|
end
|
59
66
|
|
60
67
|
end
|
@@ -1,9 +1,6 @@
|
|
1
1
|
require 'uri'
|
2
|
-
require '
|
3
|
-
require '
|
4
|
-
require 'json'
|
5
|
-
|
6
|
-
require 'librarian/puppet/version'
|
2
|
+
require 'librarian/puppet/util'
|
3
|
+
require 'librarian/puppet/source/githubtarball/repo'
|
7
4
|
|
8
5
|
module Librarian
|
9
6
|
module Puppet
|
@@ -11,158 +8,6 @@ module Librarian
|
|
11
8
|
class GitHubTarball
|
12
9
|
include Librarian::Puppet::Util
|
13
10
|
|
14
|
-
class Repo
|
15
|
-
include Librarian::Puppet::Util
|
16
|
-
|
17
|
-
TOKEN_KEY = 'GITHUB_API_TOKEN'
|
18
|
-
|
19
|
-
attr_accessor :source, :name
|
20
|
-
private :source=, :name=
|
21
|
-
|
22
|
-
def initialize(source, name)
|
23
|
-
self.source = source
|
24
|
-
self.name = name
|
25
|
-
end
|
26
|
-
|
27
|
-
def versions
|
28
|
-
return @versions if @versions
|
29
|
-
data = api_call("/repos/#{source.uri}/tags")
|
30
|
-
if data.nil?
|
31
|
-
raise Error, "Unable to find module '#{source.uri}' on https://github.com"
|
32
|
-
end
|
33
|
-
|
34
|
-
all_versions = data.map { |r| r['name'].gsub(/^v/, '') }.sort.reverse
|
35
|
-
|
36
|
-
all_versions.delete_if do |version|
|
37
|
-
version !~ /\A\d\.\d(\.\d.*)?\z/
|
38
|
-
end
|
39
|
-
|
40
|
-
@versions = all_versions.compact
|
41
|
-
debug { " Module #{name} found versions: #{@versions.join(", ")}" }
|
42
|
-
@versions
|
43
|
-
end
|
44
|
-
|
45
|
-
def manifests
|
46
|
-
versions.map do |version|
|
47
|
-
Manifest.new(source, name, version)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def install_version!(version, install_path)
|
52
|
-
if environment.local? && !vendored?(source.uri, version)
|
53
|
-
raise Error, "Could not find a local copy of #{source.uri} at #{version}."
|
54
|
-
end
|
55
|
-
|
56
|
-
vendor_cache(source.uri, version) unless vendored?(source.uri, version)
|
57
|
-
|
58
|
-
cache_version_unpacked! version
|
59
|
-
|
60
|
-
if install_path.exist?
|
61
|
-
install_path.rmtree
|
62
|
-
end
|
63
|
-
|
64
|
-
unpacked_path = version_unpacked_cache_path(version).children.first
|
65
|
-
cp_r(unpacked_path, install_path)
|
66
|
-
end
|
67
|
-
|
68
|
-
def environment
|
69
|
-
source.environment
|
70
|
-
end
|
71
|
-
|
72
|
-
def cache_path
|
73
|
-
@cache_path ||= source.cache_path.join(name)
|
74
|
-
end
|
75
|
-
|
76
|
-
def version_unpacked_cache_path(version)
|
77
|
-
cache_path.join('version').join(hexdigest(version.to_s))
|
78
|
-
end
|
79
|
-
|
80
|
-
def hexdigest(value)
|
81
|
-
Digest::MD5.hexdigest(value)
|
82
|
-
end
|
83
|
-
|
84
|
-
def cache_version_unpacked!(version)
|
85
|
-
path = version_unpacked_cache_path(version)
|
86
|
-
return if path.directory?
|
87
|
-
|
88
|
-
path.mkpath
|
89
|
-
|
90
|
-
target = vendored?(source.uri, version) ? vendored_path(source.uri, version) : name
|
91
|
-
|
92
|
-
Librarian::Posix.run!(%W{tar xzf #{target} -C #{path}})
|
93
|
-
end
|
94
|
-
|
95
|
-
def vendored?(name, version)
|
96
|
-
vendored_path(name, version).exist?
|
97
|
-
end
|
98
|
-
|
99
|
-
def vendored_path(name, version)
|
100
|
-
environment.vendor_cache.mkpath
|
101
|
-
environment.vendor_cache.join("#{name.sub("/", "-")}-#{version}.tar.gz")
|
102
|
-
end
|
103
|
-
|
104
|
-
def vendor_cache(name, version)
|
105
|
-
clean_up_old_cached_versions(name)
|
106
|
-
|
107
|
-
url = "https://api.github.com/repos/#{name}/tarball/#{version}"
|
108
|
-
url << "?access_token=#{ENV['GITHUB_API_TOKEN']}" if ENV['GITHUB_API_TOKEN']
|
109
|
-
|
110
|
-
File.open(vendored_path(name, version).to_s, 'wb') do |f|
|
111
|
-
begin
|
112
|
-
debug { "Downloading <#{url}> to <#{f.path}>" }
|
113
|
-
open(url,
|
114
|
-
"User-Agent" => "librarian-puppet v#{Librarian::Puppet::VERSION}") do |res|
|
115
|
-
while buffer = res.read(8192)
|
116
|
-
f.write(buffer)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
rescue OpenURI::HTTPError => e
|
120
|
-
raise e, "Error requesting <#{url}>: #{e.to_s}"
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def clean_up_old_cached_versions(name)
|
126
|
-
Dir["#{environment.vendor_cache}/#{name.sub('/', '-')}*.tar.gz"].each do |old_version|
|
127
|
-
FileUtils.rm old_version
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
private
|
132
|
-
|
133
|
-
def api_call(path)
|
134
|
-
url = "https://api.github.com#{path}"
|
135
|
-
url << "?access_token=#{ENV[TOKEN_KEY]}" if ENV[TOKEN_KEY]
|
136
|
-
code, data = http_get(url, :headers => {
|
137
|
-
"User-Agent" => "librarian-puppet v#{Librarian::Puppet::VERSION}"
|
138
|
-
})
|
139
|
-
|
140
|
-
if code == 200
|
141
|
-
JSON.parse(data)
|
142
|
-
elsif code == 403
|
143
|
-
begin
|
144
|
-
message = JSON.parse(data)['message']
|
145
|
-
if message && message.include?('API rate limit exceeded')
|
146
|
-
raise Error, message + " -- increase limit by authenticating via #{TOKEN_KEY}=your-token"
|
147
|
-
end
|
148
|
-
rescue JSON::ParserError
|
149
|
-
# 403 response does not return json, skip.
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
def http_get(url, options)
|
155
|
-
uri = URI.parse(url)
|
156
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
157
|
-
http.use_ssl = true
|
158
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
159
|
-
request = Net::HTTP::Get.new(uri.request_uri)
|
160
|
-
options[:headers].each { |k, v| request.add_field k, v }
|
161
|
-
resp = http.request(request)
|
162
|
-
[resp.code.to_i, resp.body]
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
11
|
class << self
|
167
12
|
LOCK_NAME = 'GITHUBTARBALL'
|
168
13
|
|
@@ -191,12 +36,12 @@ module Librarian
|
|
191
36
|
|
192
37
|
def initialize(environment, uri, options = {})
|
193
38
|
self.environment = environment
|
194
|
-
@uri = uri
|
39
|
+
@uri = URI::parse(uri)
|
195
40
|
@cache_path = nil
|
196
41
|
end
|
197
42
|
|
198
43
|
def to_s
|
199
|
-
uri
|
44
|
+
clean_uri(uri).to_s
|
200
45
|
end
|
201
46
|
|
202
47
|
def ==(other)
|
@@ -212,11 +57,11 @@ module Librarian
|
|
212
57
|
end
|
213
58
|
|
214
59
|
def to_spec_args
|
215
|
-
[uri, {}]
|
60
|
+
[clean_uri(uri).to_s, {}]
|
216
61
|
end
|
217
62
|
|
218
63
|
def to_lock_options
|
219
|
-
{:remote => uri}
|
64
|
+
{:remote => clean_uri(uri).to_s}
|
220
65
|
end
|
221
66
|
|
222
67
|
def pinned?
|
@@ -229,6 +74,8 @@ module Librarian
|
|
229
74
|
def install!(manifest)
|
230
75
|
manifest.source == self or raise ArgumentError
|
231
76
|
|
77
|
+
debug { "Installing #{manifest}" }
|
78
|
+
|
232
79
|
name = manifest.name
|
233
80
|
version = manifest.version
|
234
81
|
install_path = install_path(name)
|
@@ -246,8 +93,7 @@ module Librarian
|
|
246
93
|
|
247
94
|
def cache_path
|
248
95
|
@cache_path ||= begin
|
249
|
-
|
250
|
-
environment.cache_path.join("source/puppet/githubtarball/#{dir}")
|
96
|
+
environment.cache_path.join("source/puppet/githubtarball/#{uri.host}#{uri.path}")
|
251
97
|
end
|
252
98
|
end
|
253
99
|
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'net/https'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
require 'librarian/puppet/version'
|
7
|
+
require 'librarian/puppet/source/repo'
|
8
|
+
|
9
|
+
module Librarian
|
10
|
+
module Puppet
|
11
|
+
module Source
|
12
|
+
class GitHubTarball
|
13
|
+
class Repo < Librarian::Puppet::Source::Repo
|
14
|
+
include Librarian::Puppet::Util
|
15
|
+
|
16
|
+
TOKEN_KEY = 'GITHUB_API_TOKEN'
|
17
|
+
|
18
|
+
def versions
|
19
|
+
return @versions if @versions
|
20
|
+
data = api_call("/repos/#{source.uri}/tags")
|
21
|
+
if data.nil?
|
22
|
+
raise Error, "Unable to find module '#{source.uri}' on https://github.com"
|
23
|
+
end
|
24
|
+
|
25
|
+
all_versions = data.map { |r| r['name'].gsub(/^v/, '') }.sort.reverse
|
26
|
+
|
27
|
+
all_versions.delete_if do |version|
|
28
|
+
version !~ /\A\d\.\d(\.\d.*)?\z/
|
29
|
+
end
|
30
|
+
|
31
|
+
@versions = all_versions.compact
|
32
|
+
debug { " Module #{name} found versions: #{@versions.join(", ")}" }
|
33
|
+
@versions
|
34
|
+
end
|
35
|
+
|
36
|
+
def manifests
|
37
|
+
versions.map do |version|
|
38
|
+
Manifest.new(source, name, version)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def install_version!(version, install_path)
|
43
|
+
if environment.local? && !vendored?(source.uri.to_s, version)
|
44
|
+
raise Error, "Could not find a local copy of #{source.uri} at #{version}."
|
45
|
+
end
|
46
|
+
|
47
|
+
vendor_cache(source.uri.to_s, version) unless vendored?(source.uri.to_s, version)
|
48
|
+
|
49
|
+
cache_version_unpacked! version
|
50
|
+
|
51
|
+
if install_path.exist?
|
52
|
+
install_path.rmtree
|
53
|
+
end
|
54
|
+
|
55
|
+
unpacked_path = version_unpacked_cache_path(version).children.first
|
56
|
+
cp_r(unpacked_path, install_path)
|
57
|
+
end
|
58
|
+
|
59
|
+
def cache_version_unpacked!(version)
|
60
|
+
path = version_unpacked_cache_path(version)
|
61
|
+
return if path.directory?
|
62
|
+
|
63
|
+
path.mkpath
|
64
|
+
|
65
|
+
target = vendored?(source.uri.to_s, version) ? vendored_path(source.uri.to_s, version) : name
|
66
|
+
|
67
|
+
Librarian::Posix.run!(%W{tar xzf #{target} -C #{path}})
|
68
|
+
end
|
69
|
+
|
70
|
+
def vendor_cache(name, version)
|
71
|
+
clean_up_old_cached_versions(name)
|
72
|
+
|
73
|
+
url = "https://api.github.com/repos/#{name}/tarball/#{version}"
|
74
|
+
url << "?access_token=#{ENV['GITHUB_API_TOKEN']}" if ENV['GITHUB_API_TOKEN']
|
75
|
+
|
76
|
+
environment.vendor!
|
77
|
+
File.open(vendored_path(name, version).to_s, 'wb') do |f|
|
78
|
+
begin
|
79
|
+
debug { "Downloading <#{url}> to <#{f.path}>" }
|
80
|
+
open(url,
|
81
|
+
"User-Agent" => "librarian-puppet v#{Librarian::Puppet::VERSION}") do |res|
|
82
|
+
while buffer = res.read(8192)
|
83
|
+
f.write(buffer)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
rescue OpenURI::HTTPError => e
|
87
|
+
raise e, "Error requesting <#{url}>: #{e.to_s}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def clean_up_old_cached_versions(name)
|
93
|
+
Dir["#{environment.vendor_cache}/#{name.sub('/', '-')}*.tar.gz"].each do |old_version|
|
94
|
+
FileUtils.rm old_version
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def api_call(path)
|
101
|
+
tags = []
|
102
|
+
url = "https://api.github.com#{path}?page=1&per_page=100"
|
103
|
+
while true do
|
104
|
+
debug { " Module #{name} getting tags at: #{url}" }
|
105
|
+
url << "&access_token=#{ENV[TOKEN_KEY]}" if ENV[TOKEN_KEY]
|
106
|
+
response = http_get(url, :headers => {
|
107
|
+
"User-Agent" => "librarian-puppet v#{Librarian::Puppet::VERSION}"
|
108
|
+
})
|
109
|
+
|
110
|
+
code, data = response.code.to_i, response.body
|
111
|
+
|
112
|
+
if code == 200
|
113
|
+
tags.concat JSON.parse(data)
|
114
|
+
else
|
115
|
+
begin
|
116
|
+
message = JSON.parse(data)['message']
|
117
|
+
if code == 403 && message && message.include?('API rate limit exceeded')
|
118
|
+
raise Error, message + " -- increase limit by authenticating via #{TOKEN_KEY}=your-token"
|
119
|
+
elsif message
|
120
|
+
raise Error, "Error fetching #{url}: [#{code}] #{message}"
|
121
|
+
end
|
122
|
+
rescue JSON::ParserError
|
123
|
+
# response does not return json
|
124
|
+
end
|
125
|
+
raise Error, "Error fetching #{url}: [#{code}] #{response.body}"
|
126
|
+
end
|
127
|
+
|
128
|
+
# next page
|
129
|
+
break if response["link"].nil?
|
130
|
+
next_link = response["link"].split(",").select{|l| l.match /rel=.*next.*/}
|
131
|
+
break if next_link.empty?
|
132
|
+
url = next_link.first.match(/<(.*)>/)[1]
|
133
|
+
end
|
134
|
+
return tags
|
135
|
+
end
|
136
|
+
|
137
|
+
def http_get(url, options)
|
138
|
+
uri = URI.parse(url)
|
139
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
140
|
+
http.use_ssl = true
|
141
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
142
|
+
options[:headers].each { |k, v| request.add_field k, v }
|
143
|
+
http.request(request)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -83,7 +83,11 @@ module Librarian
|
|
83
83
|
::Puppet::ModuleTool::ModulefileReader.evaluate(metadata, modulefile)
|
84
84
|
rescue ArgumentError, SyntaxError => error
|
85
85
|
warn { "Unable to parse #{modulefile}, ignoring: #{error}" }
|
86
|
-
metadata.version
|
86
|
+
if metadata.respond_to? :version=
|
87
|
+
metadata.version = '0.0.1' # puppet < 3.6
|
88
|
+
else
|
89
|
+
metadata.update({'version' => '0.0.1'}) # puppet >= 3.6
|
90
|
+
end
|
87
91
|
end
|
88
92
|
metadata
|
89
93
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# parent class for githubtarball and forge source Repos
|
2
|
+
module Librarian
|
3
|
+
module Puppet
|
4
|
+
module Source
|
5
|
+
class Repo
|
6
|
+
|
7
|
+
attr_accessor :source, :name
|
8
|
+
private :source=, :name=
|
9
|
+
|
10
|
+
def initialize(source, name)
|
11
|
+
self.source = source
|
12
|
+
self.name = name
|
13
|
+
end
|
14
|
+
|
15
|
+
def environment
|
16
|
+
source.environment
|
17
|
+
end
|
18
|
+
|
19
|
+
def cache_path
|
20
|
+
@cache_path ||= source.cache_path.join(name)
|
21
|
+
end
|
22
|
+
|
23
|
+
def version_unpacked_cache_path(version)
|
24
|
+
cache_path.join(version.to_s)
|
25
|
+
end
|
26
|
+
|
27
|
+
def vendored?(name, version)
|
28
|
+
vendored_path(name, version).exist?
|
29
|
+
end
|
30
|
+
|
31
|
+
def vendored_path(name, version)
|
32
|
+
environment.vendor_cache.join("#{name.sub("/", "-")}-#{version}.tar.gz")
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: librarian-puppet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Sharpe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-05-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: librarian
|
@@ -160,10 +160,13 @@ files:
|
|
160
160
|
- lib/librarian/puppet/requirement.rb
|
161
161
|
- lib/librarian/puppet/source.rb
|
162
162
|
- lib/librarian/puppet/source/forge.rb
|
163
|
+
- lib/librarian/puppet/source/forge/repo.rb
|
163
164
|
- lib/librarian/puppet/source/git.rb
|
164
165
|
- lib/librarian/puppet/source/githubtarball.rb
|
166
|
+
- lib/librarian/puppet/source/githubtarball/repo.rb
|
165
167
|
- lib/librarian/puppet/source/local.rb
|
166
168
|
- lib/librarian/puppet/source/path.rb
|
169
|
+
- lib/librarian/puppet/source/repo.rb
|
167
170
|
- lib/librarian/puppet/templates/Puppetfile
|
168
171
|
- lib/librarian/puppet/util.rb
|
169
172
|
- lib/librarian/puppet/version.rb
|