librarian-puppet 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1984f0b83258ba54c8f1d62a2d6804dd29d75065
4
- data.tar.gz: e64114a525b0f92e74d4d09277b9f0dd5f76e0c6
3
+ metadata.gz: dbe00d37667721e7a61be8fb75277e88f75dec0d
4
+ data.tar.gz: 6655c8212fe01704c529ea35fcbc7ada5ed14a1b
5
5
  SHA512:
6
- metadata.gz: c5a3794a4677ae67769338e469d2eb9c646b1497cdf4b6ef6ad81a11e525350e0e397f7bf8d9a81202e33aa24c311aa6e81f3d400e1eb1729725287aceafd289
7
- data.tar.gz: afb5509325ef53d0d24334c9ddb3c2607ba35823024a96f1ce285b2306002ea0ba46fcb7a59cb937512c047b131ccd0813c71b0c4966f80819d762f7480e6f8c
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](http://forge.puppetlabs.com/),
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](http://forge.puppetlabs.com/) or an internal Forge such as [Pulp](http://www.pulpproject.org/)
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 "http://forge.puppetlabs.com"
41
+ forge "https://forge.puppetlabs.com"
42
42
 
43
43
  modulefile
44
44
 
45
45
 
46
46
  ### Example Puppetfile
47
47
 
48
- forge "http://forge.puppetlabs.com"
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 "http://forge.puppetlabs.com"
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 'json'
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
- if pe_version and Gem::Version.create(pe_version[1].strip) >= Gem::Version.create('3.2.0')
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 = Digest::MD5.hexdigest(uri)
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 + "#{sha}.tar.gz"
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 #{sha} | gzip > #{vendor_tgz}}, :chdir => tmp_path.to_s)
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 'net/https'
3
- require 'open-uri'
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
- dir = Digest::MD5.hexdigest(uri)
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 = '0.0.1'
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
@@ -25,6 +25,14 @@ module Librarian
25
25
  FileUtils.cp_r(src, dest)
26
26
  end
27
27
  end
28
+
29
+ # Remove user and password from a URI object
30
+ def clean_uri(uri)
31
+ new_uri = uri.clone
32
+ new_uri.user = nil
33
+ new_uri.password = nil
34
+ new_uri
35
+ end
28
36
  end
29
37
  end
30
38
  end
@@ -1,5 +1,5 @@
1
1
  module Librarian
2
2
  module Puppet
3
- VERSION = "1.0.1"
3
+ VERSION = "1.0.2"
4
4
  end
5
5
  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.1
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-04-12 00:00:00.000000000 Z
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