anthill-librarian-puppet 3.0.0

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.
@@ -0,0 +1,158 @@
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 versions
14
+ return @versions if @versions
15
+ @versions = get_versions
16
+ if @versions.empty?
17
+ info { "No versions found for module #{name}" }
18
+ else
19
+ debug { " Module #{name} found versions: #{@versions.join(", ")}" }
20
+ end
21
+ @versions
22
+ end
23
+
24
+ # fetch list of versions ordered for newer to older
25
+ def get_versions
26
+ # implement in subclasses
27
+ end
28
+
29
+ # return map with dependencies in the form {module_name => version,...}
30
+ # version: Librarian::Manifest::Version
31
+ def dependencies(version)
32
+ # implement in subclasses
33
+ end
34
+
35
+ # return the url for a specific version tarball
36
+ # version: Librarian::Manifest::Version
37
+ def url(name, version)
38
+ # implement in subclasses
39
+ end
40
+
41
+ def manifests
42
+ versions.map do |version|
43
+ Manifest.new(source, name, version)
44
+ end
45
+ end
46
+
47
+ def install_version!(version, install_path)
48
+ if environment.local? && !vendored?(name, version)
49
+ raise Error, "Could not find a local copy of #{name} at #{version}."
50
+ end
51
+
52
+ if environment.vendor?
53
+ vendor_cache(name, version) unless vendored?(name, version)
54
+ end
55
+
56
+ cache_version_unpacked! version
57
+
58
+ if install_path.exist? && rsync? != true
59
+ install_path.rmtree
60
+ end
61
+
62
+ unpacked_path = version_unpacked_cache_path(version).join(module_name(name))
63
+
64
+ unless unpacked_path.exist?
65
+ raise Error, "#{unpacked_path} does not exist, something went wrong. Try removing it manually"
66
+ else
67
+ cp_r(unpacked_path, install_path)
68
+ end
69
+
70
+ end
71
+
72
+ def cache_version_unpacked!(version)
73
+ path = version_unpacked_cache_path(version)
74
+ return if path.directory?
75
+
76
+ # The puppet module command is only available from puppet versions >= 2.7.13
77
+ #
78
+ # Specifying the version in the gemspec would force people to upgrade puppet while it's still usable for git
79
+ # So we do some more clever checking
80
+ #
81
+ # Executing older versions or via puppet-module tool gives an exit status = 0 .
82
+ #
83
+ check_puppet_module_options
84
+
85
+ path.mkpath
86
+
87
+ target = vendored?(name, version) ? vendored_path(name, version).to_s : name
88
+
89
+ # can't pass the default v3 forge url (http://forgeapi.puppetlabs.com)
90
+ # to clients that use the v1 API (https://forge.puppet.com)
91
+ # nor the other way around
92
+ module_repository = source.to_s
93
+
94
+ if Forge.client_api_version() > 1 and module_repository =~ %r{^http(s)?://forge\.puppetlabs\.com}
95
+ module_repository = "https://forgeapi.puppetlabs.com"
96
+ warn { "Replacing Puppet Forge API URL to use v3 #{module_repository} as required by your client version #{Librarian::Puppet.puppet_version}" }
97
+ end
98
+
99
+ m = module_repository.match(%r{^http(s)?://forge(api)?\.puppetlabs\.com})
100
+ if Forge.client_api_version() == 1 and m
101
+ ssl = m[1]
102
+ # Puppet 2.7 can't handle the 302 returned by the https url, so stick to http
103
+ if ssl and Librarian::Puppet::puppet_gem_version < Gem::Version.create('3.0.0')
104
+ warn { "Using plain http as your version of Puppet #{Librarian::Puppet::puppet_gem_version} can't download from forge.puppetlabs.com using https" }
105
+ ssl = nil
106
+ end
107
+ module_repository = "http#{ssl}://forge.puppetlabs.com"
108
+ end
109
+
110
+ command = %W{puppet module install --version #{version} --target-dir}
111
+ command.push(*[path.to_s, "--module_repository", module_repository, "--modulepath", path.to_s, "--module_working_dir", path.to_s, "--ignore-dependencies", target])
112
+ debug { "Executing puppet module install for #{name} #{version}: #{command.join(" ")}" }
113
+
114
+ begin
115
+ Librarian::Posix.run!(command)
116
+ rescue Posix::CommandFailure => e
117
+ # Rollback the directory if the puppet module had an error
118
+ begin
119
+ path.unlink
120
+ rescue => u
121
+ debug("Unable to rollback path #{path}: #{u}")
122
+ end
123
+ tar = Dir[File.join(path.to_s, "**/*.tar.gz")]
124
+ msg = ""
125
+ if e.message =~ /Unexpected EOF in archive/ and !tar.empty?
126
+ file = tar.first
127
+ msg = " (looks like an incomplete download of #{file})"
128
+ end
129
+ raise Error, "Error executing puppet module install#{msg}. Check that this command succeeds:\n#{command.join(" ")}\nError:\n#{e.message}"
130
+ end
131
+
132
+ end
133
+
134
+ def check_puppet_module_options
135
+ min_version = Gem::Version.create('2.7.13')
136
+
137
+ if Librarian::Puppet.puppet_gem_version < min_version
138
+ 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 #{Librarian::Puppet.puppet_version}"
139
+ end
140
+ end
141
+
142
+ def vendor_cache(name, version)
143
+ url = url(name, version)
144
+ path = vendored_path(name, version).to_s
145
+ debug { "Downloading #{url} into #{path}"}
146
+ environment.vendor!
147
+ File.open(path, 'wb') do |f|
148
+ open(url, "rb") do |input|
149
+ f.write(input.read)
150
+ end
151
+ end
152
+ end
153
+
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,92 @@
1
+ require 'json'
2
+ require 'open-uri'
3
+ require 'librarian/puppet/source/forge/repo'
4
+
5
+ module Librarian
6
+ module Puppet
7
+ module Source
8
+ class Forge
9
+ class RepoV1 < Librarian::Puppet::Source::Forge::Repo
10
+
11
+ def initialize(source, name)
12
+ super(source, name)
13
+ # API returned data for this module including all versions and dependencies, indexed by module name
14
+ # from https://forge.puppetlabs.com/api/v1/releases.json?module=#{name}
15
+ @api_data = nil
16
+ # API returned data for this module and a specific version, indexed by version
17
+ # from https://forge.puppetlabs.com/api/v1/releases.json?module=#{name}&version=#{version}
18
+ @api_version_data = {}
19
+ end
20
+
21
+ def get_versions
22
+ api_data(name).map { |r| r['version'] }.reverse
23
+ end
24
+
25
+ def dependencies(version)
26
+ api_version_data(name, version)['dependencies']
27
+ end
28
+
29
+ def url(name, version)
30
+ info = api_version_data(name, version)
31
+ "#{source}#{info[name].first['file']}"
32
+ end
33
+
34
+ private
35
+
36
+ # convert organization/modulename to organization-modulename
37
+ def normalize_dependencies(data)
38
+ return nil if data.nil?
39
+ # convert organization/modulename to organization-modulename
40
+ data.keys.each do |m|
41
+ if m =~ %r{.*/.*}
42
+ data[normalize_name(m)] = data[m]
43
+ data.delete(m)
44
+ end
45
+ end
46
+ data
47
+ end
48
+
49
+ # get and cache the API data for a specific module with all its versions and dependencies
50
+ def api_data(module_name)
51
+ return @api_data[module_name] if @api_data
52
+ # call API and cache data
53
+ @api_data = normalize_dependencies(api_call(module_name))
54
+ if @api_data.nil?
55
+ raise Error, "Unable to find module '#{name}' on #{source}"
56
+ end
57
+ @api_data[module_name]
58
+ end
59
+
60
+ # get and cache the API data for a specific module and version
61
+ def api_version_data(module_name, version)
62
+ # if we already got all the versions, find in cached data
63
+ return @api_data[module_name].detect{|x| x['version'] == version.to_s} if @api_data
64
+ # otherwise call the api for this version if not cached already
65
+ @api_version_data[version] = normalize_dependencies(api_call(name, version)) if @api_version_data[version].nil?
66
+ @api_version_data[version]
67
+ end
68
+
69
+ def api_call(module_name, version=nil)
70
+ url = source.uri.clone
71
+ url.path += "#{'/' if url.path.empty? or url.path[-1] != '/'}api/v1/releases.json"
72
+ url.query = "module=#{module_name.sub('-','/')}" # v1 API expects "organization/module"
73
+ url.query += "&version=#{version}" unless version.nil?
74
+ debug { "Querying Forge API for module #{name}#{" and version #{version}" unless version.nil?}: #{url}" }
75
+
76
+ begin
77
+ data = open(url) {|f| f.read}
78
+ JSON.parse(data)
79
+ rescue OpenURI::HTTPError => e
80
+ case e.io.status[0].to_i
81
+ when 404,410
82
+ nil
83
+ else
84
+ raise e, "Error requesting #{url}: #{e.to_s}"
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,62 @@
1
+ require 'librarian/puppet/source/forge/repo'
2
+ require 'puppet_forge'
3
+ require 'librarian/puppet/version'
4
+
5
+ module Librarian
6
+ module Puppet
7
+ module Source
8
+ class Forge
9
+ class RepoV3 < Librarian::Puppet::Source::Forge::Repo
10
+
11
+ PuppetForge.user_agent = "librarian-puppet/#{Librarian::Puppet::VERSION}"
12
+
13
+ def initialize(source, name)
14
+ PuppetForge.host = source.uri.clone
15
+ super(source, name)
16
+ end
17
+
18
+ def get_versions
19
+ get_module.releases.select{|r| r.deleted_at.nil?}.map{|r| r.version}
20
+ end
21
+
22
+ def dependencies(version)
23
+ array = get_release(version).metadata[:dependencies].map{|d| [d[:name], d[:version_requirement]]}
24
+ Hash[*array.flatten(1)]
25
+ end
26
+
27
+ def url(name, version)
28
+ if name == "#{get_module().owner.username}/#{get_module().name}"
29
+ release = get_release(version)
30
+ else
31
+ # should never get here as we use one repo object for each module (to be changed in the future)
32
+ debug { "Looking up url for #{name}@#{version}" }
33
+ release = PuppetForge::V3::Release.find("#{name}-#{version}")
34
+ end
35
+ "#{source}#{release.file_uri}"
36
+ end
37
+
38
+ private
39
+
40
+ def get_module
41
+ begin
42
+ @module ||= PuppetForge::V3::Module.find(name)
43
+ rescue Faraday::ResourceNotFound => e
44
+ raise(Error, "Unable to find module '#{name}' on #{source}")
45
+ end
46
+ @module
47
+ end
48
+
49
+ def get_release(version)
50
+ release = get_module.releases.find{|r| r.version == version.to_s}
51
+ if release.nil?
52
+ versions = get_module.releases.map{|r| r.version}
53
+ raise Error, "Unable to find version '#{version}' for module '#{name}' on #{source} amongst #{versions}"
54
+ end
55
+ release
56
+ end
57
+
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,74 @@
1
+ require 'librarian/source/git'
2
+ require 'librarian/puppet/source/local'
3
+
4
+ module Librarian
5
+ module Source
6
+ class Git
7
+ class Repository
8
+ def hash_from(remote, reference)
9
+ branch_names = remote_branch_names[remote]
10
+ if branch_names.include?(reference)
11
+ reference = "#{remote}/#{reference}"
12
+ end
13
+
14
+ command = %W(rev-parse #{reference}^{commit} --quiet)
15
+ run!(command, :chdir => true).strip
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ module Puppet
22
+ module Source
23
+ class Git < Librarian::Source::Git
24
+ include Local
25
+ include Librarian::Puppet::Util
26
+
27
+ def cache!
28
+ return vendor_checkout! if vendor_cached?
29
+
30
+ if environment.local?
31
+ raise Error, "Could not find a local copy of #{uri}#{" at #{sha}" unless sha.nil?}."
32
+ end
33
+
34
+ begin
35
+ super
36
+ rescue Librarian::Posix::CommandFailure => e
37
+ raise Error, "Could not checkout #{uri}#{" at #{sha}" unless sha.nil?}: #{e}"
38
+ end
39
+
40
+ cache_in_vendor(repository.path) if environment.vendor?
41
+ end
42
+
43
+ private
44
+
45
+ def vendor_tar
46
+ environment.vendor_source.join("#{sha}.tar")
47
+ end
48
+
49
+ def vendor_tgz
50
+ environment.vendor_source.join("#{sha}.tar.gz")
51
+ end
52
+
53
+ def vendor_cached?
54
+ vendor_tgz.exist?
55
+ end
56
+
57
+ def vendor_checkout!
58
+ repository.path.rmtree if repository.path.exist?
59
+ repository.path.mkpath
60
+
61
+ Librarian::Posix.run!(%W{tar xzf #{vendor_tgz}}, :chdir => repository.path.to_s)
62
+
63
+ repository_cached!
64
+ end
65
+
66
+ def cache_in_vendor(tmp_path)
67
+ Librarian::Posix.run!(%W{git archive -o #{vendor_tar} #{sha}}, :chdir => tmp_path.to_s)
68
+ Librarian::Posix.run!(%W{gzip #{vendor_tar}}, :chdir => tmp_path.to_s)
69
+ end
70
+
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,130 @@
1
+ require 'uri'
2
+ require 'librarian/puppet/util'
3
+ require 'librarian/puppet/source/githubtarball/repo'
4
+
5
+ module Librarian
6
+ module Puppet
7
+ module Source
8
+ class GitHubTarball
9
+ include Librarian::Puppet::Util
10
+
11
+ class << self
12
+ LOCK_NAME = 'GITHUBTARBALL'
13
+
14
+ def lock_name
15
+ LOCK_NAME
16
+ end
17
+
18
+ def from_lock_options(environment, options)
19
+ new(environment, options[:remote], options.reject { |k, v| k == :remote })
20
+ end
21
+
22
+ def from_spec_args(environment, uri, options)
23
+ recognised_options = []
24
+ unrecognised_options = options.keys - recognised_options
25
+ unless unrecognised_options.empty?
26
+ raise Error, "unrecognised options: #{unrecognised_options.join(", ")}"
27
+ end
28
+
29
+ new(environment, uri, options)
30
+ end
31
+ end
32
+
33
+ attr_accessor :environment
34
+ private :environment=
35
+ attr_reader :uri
36
+
37
+ def initialize(environment, uri, options = {})
38
+ self.environment = environment
39
+ @uri = URI::parse(uri)
40
+ @cache_path = nil
41
+ end
42
+
43
+ def to_s
44
+ clean_uri(uri).to_s
45
+ end
46
+
47
+ def ==(other)
48
+ other &&
49
+ self.class == other.class &&
50
+ self.uri == other.uri
51
+ end
52
+
53
+ alias :eql? :==
54
+
55
+ def hash
56
+ self.to_s.hash
57
+ end
58
+
59
+ def to_spec_args
60
+ [clean_uri(uri).to_s, {}]
61
+ end
62
+
63
+ def to_lock_options
64
+ {:remote => clean_uri(uri).to_s}
65
+ end
66
+
67
+ def pinned?
68
+ false
69
+ end
70
+
71
+ def unpin!
72
+ end
73
+
74
+ def install!(manifest)
75
+ manifest.source == self or raise ArgumentError
76
+
77
+ debug { "Installing #{manifest}" }
78
+
79
+ name = manifest.name
80
+ version = manifest.version
81
+ install_path = install_path(name)
82
+ repo = repo(name)
83
+
84
+ repo.install_version! version, install_path
85
+ end
86
+
87
+ def manifest(name, version, dependencies)
88
+ manifest = Manifest.new(self, name)
89
+ manifest.version = version
90
+ manifest.dependencies = dependencies
91
+ manifest
92
+ end
93
+
94
+ def cache_path
95
+ @cache_path ||= begin
96
+ environment.cache_path.join("source/puppet/githubtarball/#{uri.host}#{uri.path}")
97
+ end
98
+ end
99
+
100
+ def install_path(name)
101
+ environment.install_path.join(module_name(name))
102
+ end
103
+
104
+ def fetch_version(name, version_uri)
105
+ versions = repo(name).versions
106
+ if versions.include? version_uri
107
+ version_uri
108
+ else
109
+ versions.first
110
+ end
111
+ end
112
+
113
+ def fetch_dependencies(name, version, version_uri)
114
+ {}
115
+ end
116
+
117
+ def manifests(name)
118
+ repo(name).manifests
119
+ end
120
+
121
+ private
122
+
123
+ def repo(name)
124
+ @repo ||= {}
125
+ @repo[name] ||= Repo.new(self, name)
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end