1
module Puppet::ModuleTool::Shared
3
include Puppet::ModuleTool::Errors
5
def get_local_constraints
6
@local = Hash.new { |h,k| h[k] = { } }
7
@conditions = Hash.new { |h,k| h[k] = [] }
8
@installed = Hash.new { |h,k| h[k] = [] }
10
@environment.modules_by_path.values.flatten.each do |mod|
11
mod_name = (mod.forge_name || mod.name).gsub('/', '-')
12
@installed[mod_name] << mod
13
d = @local["#{mod_name}@#{mod.version}"]
14
(mod.dependencies || []).each do |hash|
15
name, conditions = hash['name'], hash['version_requirement']
16
name = name.gsub('/', '-')
18
@conditions[name] << {
20
:version => mod.version,
21
:dependency => conditions
27
def get_remote_constraints
28
@remote = Hash.new { |h,k| h[k] = { } }
30
@versions = Hash.new { |h,k| h[k] = [] }
32
Puppet.notice "Downloading from #{Puppet::Forge.repository.uri} ..."
33
author, modname = Puppet::ModuleTool.username_and_modname_from(@module_name)
34
info = Puppet::Forge.remote_dependency_info(author, modname, @options[:version])
36
mod_name, releases = pair
37
mod_name = mod_name.gsub('/', '-')
38
releases.each do |rel|
39
semver = SemVer.new(rel['version'] || '0.0.0') rescue SemVer.MIN
40
@versions[mod_name] << { :vstring => rel['version'], :semver => semver }
41
@versions[mod_name].sort! { |a, b| a[:semver] <=> b[:semver] }
42
@urls["#{mod_name}@#{rel['version']}"] = rel['file']
43
d = @remote["#{mod_name}@#{rel['version']}"]
44
(rel['dependencies'] || []).each do |name, conditions|
45
d[name.gsub('/', '-')] = conditions
51
def implicit_version(mod)
52
return :latest if @conditions[mod].empty?
53
if @conditions[mod].all? { |c| c[:queued] || c[:module] == :you }
59
def annotated_version(mod, versions)
61
return implicit_version(mod)
63
return "#{implicit_version(mod)}: #{versions.last}"
67
def resolve_constraints(dependencies, source = [{:name => :you}], seen = {}, action = @action)
68
dependencies = dependencies.map do |mod, range|
69
source.last[:dependency] = range
72
:module => source.last[:name],
73
:version => source.last[:version],
79
range = SemVer[@version] rescue SemVer['>= 0.0.0']
81
range = (@conditions[mod]).map do |r|
82
SemVer[r[:dependency]] rescue SemVer['>= 0.0.0']
86
if @action == :install && seen.include?(mod)
87
next if range === seen[mod][:semver]
89
req_module = @module_name
90
req_versions = @versions["#{@module_name}"].map { |v| v[:semver] }
91
raise InvalidDependencyCycleError,
93
:source => (source + [{ :name => mod, :version => source.last[:dependency] }]),
94
:requested_module => req_module,
95
:requested_version => @version || annotated_version(req_module, req_versions),
96
:conditions => @conditions
99
if !(@force || @installed[mod].empty? || source.last[:name] == :you)
100
next if range === SemVer.new(@installed[mod].first.version)
102
elsif @installed[mod].empty?
106
if action == :upgrade
107
@conditions.each { |_, conds| conds.delete_if { |c| c[:module] == mod } }
110
valid_versions = @versions["#{mod}"].select { |h| range === h[:semver] }
112
unless version = valid_versions.last
113
req_module = @module_name
114
req_versions = @versions["#{@module_name}"].map { |v| v[:semver] }
115
raise NoVersionsSatisfyError,
116
:requested_name => req_module,
117
:requested_version => @version || annotated_version(req_module, req_versions),
118
:installed_version => @installed[@module_name].empty? ? nil : @installed[@module_name].first.version,
119
:dependency_name => mod,
120
:conditions => @conditions[mod],
130
:previous_version => @installed[mod].empty? ? nil : @installed[mod].first.version,
131
:file => @urls["#{mod}@#{version[:vstring]}"],
132
:path => action == :install ? @options[:target_dir] : (@installed[mod].empty? ? @options[:target_dir] : @installed[mod].first.modulepath),
136
dependencies.each do |mod|
137
deps = @remote["#{mod[:module]}@#{mod[:version][:vstring]}"].sort_by(&:first)
138
mod[:dependencies] = resolve_constraints(deps, source + [{ :name => mod[:module], :version => mod[:version][:vstring] }], seen, :install)
139
end unless @ignore_dependencies
143
def download_tarballs(graph, default_path)
144
graph.map do |release|
147
cache_path = Pathname(release[:tarball])
149
cache_path = Puppet::Forge.repository.retrieve(release[:file])
151
rescue OpenURI::HTTPError => e
152
raise RuntimeError, "Could not download module: #{e.message}"
156
{ (release[:path] ||= default_path) => cache_path},
157
*download_tarballs(release[:dependencies], default_path)