lib/librarian/puppet/source/forge.rb in librarian-puppet-0.9.10 vs lib/librarian/puppet/source/forge.rb in librarian-puppet-0.9.11
- old
+ new
@@ -1,35 +1,44 @@
-require 'uri'
-require 'net/http'
require 'json'
+require 'open-uri'
module Librarian
module Puppet
module Source
class Forge
+ include Librarian::Puppet::Util
+
class Repo
+ include Librarian::Puppet::Util
attr_accessor :source, :name
private :source=, :name=
def initialize(source, name)
self.source = source
self.name = name
+ # API returned data for this module including all versions and dependencies, indexed by module name
+ # from http://forge.puppetlabs.com/api/v1/releases.json?module=#{name}
+ @api_data = nil
+ # API returned data for this module and a specific version, indexed by version
+ # from http://forge.puppetlabs.com/api/v1/releases.json?module=#{name}&version=#{version}
+ @api_version_data = {}
end
def versions
- data = api_call("#{name}.json")
- if data.nil?
- raise Error, "Unable to find module '#{name}' on #{source}"
+ return @versions if @versions
+ @versions = api_data(name).map { |r| r['version'] }.reverse
+ if @versions.empty?
+ info { "No versions found for module #{name}" }
+ else
+ debug { " Module #{name} found versions: #{@versions.join(", ")}" }
end
-
- data['releases'].map { |r| r['version'] }.sort.reverse
+ @versions
end
def dependencies(version)
- data = api_call("api/v1/releases.json?module=#{name}&version=#{version}")
- data[name].first['dependencies']
+ api_version_data(name, version)['dependencies']
end
def manifests
versions.map do |version|
Manifest.new(source, name, version)
@@ -54,11 +63,11 @@
unpacked_path = version_unpacked_cache_path(version).join(name.split('/').last)
unless unpacked_path.exist?
raise Error, "#{unpacked_path} does not exist, something went wrong. Try removing it manually"
else
- FileUtils.cp_r(unpacked_path, install_path)
+ cp_r(unpacked_path, install_path)
end
end
def environment
@@ -93,11 +102,12 @@
path.mkpath
target = vendored?(name, version) ? vendored_path(name, version) : name
- command = "puppet module install --target-dir '#{path}' --module_repository '#{source}' --modulepath '#{path}' --ignore-dependencies '#{target}'"
+ command = "puppet module install --version #{version} --target-dir '#{path}' --module_repository '#{source}' --modulepath '#{path}' --ignore-dependencies '#{target}'"
+ debug { "Executing puppet module install for #{name} #{version}" }
output = `#{command}`
# Check for bad exit code
unless $? == 0
# Rollback the directory if the puppet module had an error
@@ -107,11 +117,11 @@
end
def check_puppet_module_options
min_version = Gem::Version.create('2.7.13')
- puppet_version = Gem::Version.create(`puppet --version`.split(' ').first.strip.gsub('-', '.'))
+ puppet_version = Gem::Version.create(PUPPET_VERSION.gsub('-', '.'))
if puppet_version < min_version
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}"
end
end
@@ -123,42 +133,59 @@
def vendored_path(name, version)
environment.vendor_cache.join("#{name.sub("/", "-")}-#{version}.tar.gz")
end
def vendor_cache(name, version)
- File.open(vendored_path(name, version).to_s, 'w') do |f|
- download(name, version) do |data|
- f << data
+ info = api_version_data(name, version)
+ url = "#{source}#{info[name].first['file']}"
+ path = vendored_path(name, version).to_s
+ debug { "Downloading #{url} into #{path}"}
+ File.open(path, 'wb') do |f|
+ open(url, "rb") do |input|
+ f.write(input.read)
end
end
end
- def download(name, version, &block)
- data = api_call("api/v1/releases.json?module=#{name}&version=#{version}")
+ private
- info = data[name].detect {|h| h['version'] == version.to_s }
-
- stream(info['file'], &block)
+ # get and cache the API data for a specific module with all its versions and dependencies
+ def api_data(module_name)
+ return @api_data[module_name] if @api_data
+ # call API and cache data
+ @api_data = api_call(module_name)
+ if @api_data.nil?
+ raise Error, "Unable to find module '#{name}' on #{source}"
+ end
+ @api_data[module_name]
end
- def stream(file, &block)
- Net::HTTP.get_response(URI.parse("#{source}#{file}")) do |res|
- res.code
-
- res.read_body(&block)
- end
+ # get and cache the API data for a specific module and version
+ def api_version_data(module_name, version)
+ # if we already got all the versions, find in cached data
+ return @api_data[module_name].detect{|x| x['version'] == version.to_s} if @api_data
+ # otherwise call the api for this version if not cached already
+ @api_version_data[version] = api_call(name, version) if @api_version_data[version].nil?
+ @api_version_data[version]
end
- private
-
- def api_call(path)
- base_url = source.to_s
- resp = Net::HTTP.get_response(URI.parse("#{base_url}/#{path}"))
- if resp.code.to_i != 200
- nil
- else
- data = resp.body
+ def api_call(module_name, version=nil)
+ base_url = source.uri
+ path = "api/v1/releases.json?module=#{module_name}"
+ path = "#{path}&version=#{version}" unless version.nil?
+ url = "#{base_url}/#{path}"
+ debug { "Querying Forge API for module #{name}#{" and version #{version}" unless version.nil?}: #{url}" }
+
+ begin
+ data = open(url) {|f| f.read}
JSON.parse(data)
+ rescue OpenURI::HTTPError => e
+ case e.io.status[0].to_i
+ when 404,410
+ nil
+ else
+ raise e, "Error requesting #{base_url}/#{path}: #{e.to_s}"
+ end
end
end
end
class << self