r10k 3.6.0 → 3.9.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/docker.yml +4 -1
- data/.github/workflows/release.yml +3 -2
- data/.github/workflows/rspec_tests.yml +81 -0
- data/.github/workflows/stale.yml +19 -0
- data/.travis.yml +8 -1
- data/CHANGELOG.mkd +33 -0
- data/CODEOWNERS +2 -2
- data/README.mkd +2 -2
- data/doc/common-patterns.mkd +1 -0
- data/doc/dynamic-environments/configuration.mkd +123 -42
- data/doc/dynamic-environments/usage.mkd +12 -11
- data/doc/puppetfile.mkd +23 -3
- data/docker/Gemfile +1 -1
- data/docker/Makefile +4 -3
- data/docker/docker-compose.yml +18 -0
- data/docker/r10k/Dockerfile +1 -1
- data/docker/r10k/docker-entrypoint.sh +0 -1
- data/docker/r10k/release.Dockerfile +1 -1
- data/docker/spec/dockerfile_spec.rb +26 -32
- data/integration/tests/git_source/git_source_repeated_remote.rb +2 -2
- data/integration/tests/user_scenario/basic_workflow/multi_env_custom_forge_git_module.rb +2 -1
- data/integration/tests/user_scenario/basic_workflow/multi_env_custom_forge_git_module_static.rb +2 -1
- data/integration/tests/user_scenario/basic_workflow/multi_source_custom_forge_git_module.rb +1 -1
- data/integration/tests/user_scenario/basic_workflow/single_env_custom_forge_git_module.rb +2 -1
- data/integration/tests/user_scenario/complex_workflow/multi_env_add_change_remove.rb +1 -1
- data/integration/tests/user_scenario/complex_workflow/multi_env_remove_re-add.rb +1 -1
- data/integration/tests/user_scenario/complex_workflow/multi_env_unamanaged.rb +1 -1
- data/lib/r10k/action/base.rb +10 -0
- data/lib/r10k/action/deploy/display.rb +49 -10
- data/lib/r10k/action/deploy/environment.rb +102 -51
- data/lib/r10k/action/deploy/module.rb +55 -30
- data/lib/r10k/action/puppetfile/check.rb +3 -1
- data/lib/r10k/action/puppetfile/install.rb +20 -23
- data/lib/r10k/action/puppetfile/purge.rb +8 -2
- data/lib/r10k/action/runner.rb +34 -0
- data/lib/r10k/cli/deploy.rb +14 -7
- data/lib/r10k/cli/puppetfile.rb +5 -5
- data/lib/r10k/content_synchronizer.rb +83 -0
- data/lib/r10k/deployment.rb +1 -1
- data/lib/r10k/environment/base.rb +30 -3
- data/lib/r10k/environment/git.rb +17 -5
- data/lib/r10k/environment/name.rb +22 -4
- data/lib/r10k/environment/svn.rb +11 -4
- data/lib/r10k/environment/with_modules.rb +46 -30
- data/lib/r10k/git.rb +1 -0
- data/lib/r10k/git/cache.rb +11 -1
- data/lib/r10k/git/rugged/credentials.rb +39 -2
- data/lib/r10k/initializers.rb +2 -0
- data/lib/r10k/module.rb +1 -1
- data/lib/r10k/module/base.rb +17 -1
- data/lib/r10k/module/forge.rb +29 -11
- data/lib/r10k/module/git.rb +50 -27
- data/lib/r10k/module/local.rb +2 -1
- data/lib/r10k/module/svn.rb +24 -18
- data/lib/r10k/puppetfile.rb +66 -83
- data/lib/r10k/settings.rb +29 -2
- data/lib/r10k/source/base.rb +9 -0
- data/lib/r10k/source/git.rb +18 -7
- data/lib/r10k/source/hash.rb +5 -5
- data/lib/r10k/source/svn.rb +5 -3
- data/lib/r10k/util/cleaner.rb +21 -0
- data/lib/r10k/util/setopts.rb +33 -12
- data/lib/r10k/version.rb +1 -1
- data/locales/r10k.pot +98 -82
- data/r10k.gemspec +1 -1
- data/spec/fixtures/unit/action/r10k_creds.yaml +9 -0
- data/spec/r10k-mocks/mock_source.rb +1 -1
- data/spec/shared-examples/puppetfile-action.rb +7 -7
- data/spec/shared-examples/subprocess-runner.rb +11 -5
- data/spec/unit/action/deploy/display_spec.rb +35 -5
- data/spec/unit/action/deploy/environment_spec.rb +207 -37
- data/spec/unit/action/deploy/module_spec.rb +173 -26
- data/spec/unit/action/puppetfile/check_spec.rb +2 -2
- data/spec/unit/action/puppetfile/install_spec.rb +31 -10
- data/spec/unit/action/puppetfile/purge_spec.rb +25 -5
- data/spec/unit/action/runner_spec.rb +48 -1
- data/spec/unit/environment/git_spec.rb +19 -2
- data/spec/unit/environment/name_spec.rb +28 -0
- data/spec/unit/environment/svn_spec.rb +12 -0
- data/spec/unit/environment/with_modules_spec.rb +74 -0
- data/spec/unit/git/cache_spec.rb +10 -0
- data/spec/unit/git/rugged/credentials_spec.rb +79 -2
- data/spec/unit/git_spec.rb +3 -3
- data/spec/unit/module/forge_spec.rb +21 -13
- data/spec/unit/module/git_spec.rb +64 -1
- data/spec/unit/module_spec.rb +60 -10
- data/spec/unit/puppetfile_spec.rb +63 -60
- data/spec/unit/settings_spec.rb +12 -0
- data/spec/unit/source/git_spec.rb +15 -3
- data/spec/unit/util/purgeable_spec.rb +2 -8
- data/spec/unit/util/setopts_spec.rb +25 -1
- metadata +11 -11
- data/azure-pipelines.yml +0 -87
data/lib/r10k/git.rb
CHANGED
data/lib/r10k/git/cache.rb
CHANGED
@@ -16,7 +16,17 @@ class R10K::Git::Cache
|
|
16
16
|
|
17
17
|
include R10K::Settings::Mixin
|
18
18
|
|
19
|
-
|
19
|
+
#@api private
|
20
|
+
def self.determine_cache_root
|
21
|
+
if R10K::Util::Platform.windows?
|
22
|
+
File.join(ENV['LOCALAPPDATA'], 'r10k', 'git')
|
23
|
+
else
|
24
|
+
File.expand_path(ENV['HOME'] ? '~/.r10k/git': '/root/.r10k/git')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
private_class_method :determine_cache_root
|
28
|
+
|
29
|
+
def_setting_attr :cache_root, determine_cache_root
|
20
30
|
|
21
31
|
@instance_cache = R10K::InstanceCache.new(self)
|
22
32
|
|
@@ -61,11 +61,48 @@ class R10K::Git::Rugged::Credentials
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def get_plaintext_credentials(url, username_from_url)
|
64
|
-
|
65
|
-
|
64
|
+
per_repo_oauth_token = nil
|
65
|
+
if per_repo_settings = R10K::Git.get_repo_settings(url)
|
66
|
+
per_repo_oauth_token = per_repo_settings[:oauth_token]
|
67
|
+
end
|
68
|
+
|
69
|
+
if token_path = per_repo_oauth_token || R10K::Git.settings[:oauth_token]
|
70
|
+
@oauth_token ||= extract_token(token_path, url)
|
71
|
+
|
72
|
+
user = 'x-oauth-token'
|
73
|
+
password = @oauth_token
|
74
|
+
else
|
75
|
+
user = get_git_username(url, username_from_url)
|
76
|
+
password = URI.parse(url).password || ''
|
77
|
+
end
|
66
78
|
Rugged::Credentials::UserPassword.new(username: user, password: password)
|
67
79
|
end
|
68
80
|
|
81
|
+
def extract_token(token_path, url)
|
82
|
+
if token_path == '-'
|
83
|
+
token = $stdin.read.strip
|
84
|
+
logger.debug2 _("Using OAuth token from stdin for URL %{url}") % { url: url }
|
85
|
+
elsif File.readable?(token_path)
|
86
|
+
token = File.read(token_path).strip
|
87
|
+
logger.debug2 _("Using OAuth token from %{token_path} for URL %{url}") % { token_path: token_path, url: url }
|
88
|
+
else
|
89
|
+
raise R10K::Git::GitError, _("%{path} is missing or unreadable, cannot load OAuth token") % { path: token_path }
|
90
|
+
end
|
91
|
+
|
92
|
+
unless valid_token?(token)
|
93
|
+
raise R10K::Git::GitError, _("Supplied OAuth token contains invalid characters.")
|
94
|
+
end
|
95
|
+
|
96
|
+
token
|
97
|
+
end
|
98
|
+
|
99
|
+
# This regex is the only real requirement for OAuth token format,
|
100
|
+
# per https://www.oauth.com/oauth2-servers/access-tokens/access-token-response/
|
101
|
+
# Bitbucket's tokens also can include an underscore, so that is added here.
|
102
|
+
def valid_token?(token)
|
103
|
+
return token =~ /^[\w\-\.~_\+\/]+$/
|
104
|
+
end
|
105
|
+
|
69
106
|
def get_default_credentials(url, username_from_url)
|
70
107
|
Rugged::Credentials::Default.new
|
71
108
|
end
|
data/lib/r10k/initializers.rb
CHANGED
@@ -44,6 +44,7 @@ module R10K
|
|
44
44
|
class DeployInitializer < BaseInitializer
|
45
45
|
def call
|
46
46
|
with_setting(:puppet_path) { |value| R10K::Settings.puppet_path = value }
|
47
|
+
with_setting(:puppet_conf) { |value| R10K::Settings.puppet_conf = value }
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
@@ -54,6 +55,7 @@ module R10K
|
|
54
55
|
with_setting(:private_key) { |value| R10K::Git.settings[:private_key] = value }
|
55
56
|
with_setting(:proxy) { |value| R10K::Git.settings[:proxy] = value }
|
56
57
|
with_setting(:repositories) { |value| R10K::Git.settings[:repositories] = value }
|
58
|
+
with_setting(:oauth_token) { |value| R10K::Git.settings[:oauth_token] = value }
|
57
59
|
end
|
58
60
|
end
|
59
61
|
|
data/lib/r10k/module.rb
CHANGED
@@ -17,7 +17,7 @@ module R10K::Module
|
|
17
17
|
#
|
18
18
|
# @param [String] name The unique name of the module
|
19
19
|
# @param [String] basedir The root to install the module in
|
20
|
-
# @param [
|
20
|
+
# @param [Hash] args An arbitary Hash that specifies the implementation
|
21
21
|
# @param [R10K::Environment] environment Optional environment that this module is a part of
|
22
22
|
#
|
23
23
|
# @return [Object < R10K::Module] A member of the implementing subclass
|
data/lib/r10k/module/base.rb
CHANGED
@@ -51,7 +51,11 @@ class R10K::Module::Base
|
|
51
51
|
@owner, @name = parse_title(@title)
|
52
52
|
@path = Pathname.new(File.join(@dirname, @name))
|
53
53
|
@environment = environment
|
54
|
+
@overrides = args.delete(:overrides) || {}
|
54
55
|
@origin = 'external' # Expect Puppetfile or R10k::Environment to set this to a specific value
|
56
|
+
|
57
|
+
@requested_modules = @overrides.dig(:modules, :requested_modules) || []
|
58
|
+
@should_sync = (@requested_modules.empty? || @requested_modules.include?(@name))
|
55
59
|
end
|
56
60
|
|
57
61
|
# @deprecated
|
@@ -61,11 +65,22 @@ class R10K::Module::Base
|
|
61
65
|
end
|
62
66
|
|
63
67
|
# Synchronize this module with the indicated state.
|
64
|
-
# @
|
68
|
+
# @param [Hash] opts Deprecated
|
65
69
|
def sync(opts={})
|
66
70
|
raise NotImplementedError
|
67
71
|
end
|
68
72
|
|
73
|
+
def should_sync?
|
74
|
+
if @should_sync
|
75
|
+
logger.info _("Deploying module to %{path}") % {path: path}
|
76
|
+
true
|
77
|
+
else
|
78
|
+
logger.debug1(_("Only updating modules %{modules}, skipping module %{name}") % {modules: @requested_modules.inspect, name: name})
|
79
|
+
false
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
|
69
84
|
# Return the desired version of this module
|
70
85
|
# @abstract
|
71
86
|
def version
|
@@ -87,6 +102,7 @@ class R10K::Module::Base
|
|
87
102
|
raise NotImplementedError
|
88
103
|
end
|
89
104
|
|
105
|
+
# Deprecated
|
90
106
|
def accept(visitor)
|
91
107
|
visitor.visit(:module, self)
|
92
108
|
end
|
data/lib/r10k/module/forge.rb
CHANGED
@@ -13,7 +13,12 @@ class R10K::Module::Forge < R10K::Module::Base
|
|
13
13
|
R10K::Module.register(self)
|
14
14
|
|
15
15
|
def self.implement?(name, args)
|
16
|
-
|
16
|
+
args[:type].to_s == 'forge' ||
|
17
|
+
(!!
|
18
|
+
((args.keys & %i{git svn type}).empty? &&
|
19
|
+
args.has_key?(:version) &&
|
20
|
+
name.match(%r[\w+[/-]\w+]) &&
|
21
|
+
valid_version?(args[:version])))
|
17
22
|
end
|
18
23
|
|
19
24
|
def self.valid_version?(expected_version)
|
@@ -32,24 +37,37 @@ class R10K::Module::Forge < R10K::Module::Base
|
|
32
37
|
|
33
38
|
include R10K::Logging
|
34
39
|
|
35
|
-
|
40
|
+
include R10K::Util::Setopts
|
41
|
+
|
42
|
+
def initialize(title, dirname, opts, environment=nil)
|
36
43
|
super
|
37
44
|
|
38
45
|
@metadata_file = R10K::Module::MetadataFile.new(path + 'metadata.json')
|
39
46
|
@metadata = @metadata_file.read
|
40
47
|
|
41
|
-
|
48
|
+
setopts(opts, {
|
49
|
+
# Standard option interface
|
50
|
+
:version => :expected_version,
|
51
|
+
:source => ::R10K::Util::Setopts::Ignore,
|
52
|
+
:type => ::R10K::Util::Setopts::Ignore,
|
53
|
+
})
|
54
|
+
|
55
|
+
@expected_version ||= current_version || :latest
|
56
|
+
|
42
57
|
@v3_module = PuppetForge::V3::Module.new(:slug => @title)
|
43
58
|
end
|
44
59
|
|
60
|
+
# @param [Hash] opts Deprecated
|
45
61
|
def sync(opts={})
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
62
|
+
if should_sync?
|
63
|
+
case status
|
64
|
+
when :absent
|
65
|
+
install
|
66
|
+
when :outdated
|
67
|
+
upgrade
|
68
|
+
when :mismatched
|
69
|
+
reinstall
|
70
|
+
end
|
53
71
|
end
|
54
72
|
end
|
55
73
|
|
@@ -171,7 +189,7 @@ class R10K::Module::Forge < R10K::Module::Base
|
|
171
189
|
if (match = title.match(/\A(\w+)[-\/](\w+)\Z/))
|
172
190
|
[match[1], match[2]]
|
173
191
|
else
|
174
|
-
raise ArgumentError, _("Forge module names must match 'owner/modulename'")
|
192
|
+
raise ArgumentError, _("Forge module names must match 'owner/modulename', instead got #{title}")
|
175
193
|
end
|
176
194
|
end
|
177
195
|
end
|
data/lib/r10k/module/git.rb
CHANGED
@@ -8,7 +8,7 @@ class R10K::Module::Git < R10K::Module::Base
|
|
8
8
|
R10K::Module.register(self)
|
9
9
|
|
10
10
|
def self.implement?(name, args)
|
11
|
-
args.
|
11
|
+
args.has_key?(:git) || args[:type].to_s == 'git'
|
12
12
|
rescue
|
13
13
|
false
|
14
14
|
end
|
@@ -28,16 +28,50 @@ class R10K::Module::Git < R10K::Module::Base
|
|
28
28
|
# @return [String]
|
29
29
|
attr_reader :default_ref
|
30
30
|
|
31
|
-
|
32
|
-
|
31
|
+
# @!attribute [r] default_override_ref
|
32
|
+
# @api private
|
33
|
+
# @return [String]
|
34
|
+
attr_reader :default_override_ref
|
35
|
+
|
36
|
+
include R10K::Util::Setopts
|
37
|
+
|
38
|
+
def initialize(title, dirname, opts, environment=nil)
|
33
39
|
|
34
|
-
|
40
|
+
super
|
41
|
+
setopts(opts, {
|
42
|
+
# Standard option interface
|
43
|
+
:version => :desired_ref,
|
44
|
+
:source => :remote,
|
45
|
+
:type => ::R10K::Util::Setopts::Ignore,
|
46
|
+
|
47
|
+
# Type-specific options
|
48
|
+
:branch => :desired_ref,
|
49
|
+
:tag => :desired_ref,
|
50
|
+
:commit => :desired_ref,
|
51
|
+
:ref => :desired_ref,
|
52
|
+
:git => :remote,
|
53
|
+
:default_branch => :default_ref,
|
54
|
+
:default_branch_override => :default_override_ref,
|
55
|
+
})
|
56
|
+
|
57
|
+
force = @overrides.dig(:modules, :force)
|
58
|
+
@force = force == false ? false : true
|
59
|
+
|
60
|
+
@desired_ref ||= 'master'
|
61
|
+
|
62
|
+
if @desired_ref == :control_branch
|
63
|
+
if @environment && @environment.respond_to?(:ref)
|
64
|
+
@desired_ref = @environment.ref
|
65
|
+
else
|
66
|
+
logger.warn _("Cannot track control repo branch for content '%{name}' when not part of a git-backed environment, will use default if available." % {name: name})
|
67
|
+
end
|
68
|
+
end
|
35
69
|
|
36
70
|
@repo = R10K::Git::StatefulRepository.new(@remote, @dirname, @name)
|
37
71
|
end
|
38
72
|
|
39
73
|
def version
|
40
|
-
validate_ref(@desired_ref, @default_ref)
|
74
|
+
validate_ref(@desired_ref, @default_ref, @default_override_ref)
|
41
75
|
end
|
42
76
|
|
43
77
|
def properties
|
@@ -48,9 +82,10 @@ class R10K::Module::Git < R10K::Module::Base
|
|
48
82
|
}
|
49
83
|
end
|
50
84
|
|
85
|
+
# @param [Hash] opts Deprecated
|
51
86
|
def sync(opts={})
|
52
|
-
force = opts
|
53
|
-
@repo.sync(version, force)
|
87
|
+
force = opts[:force] || @force
|
88
|
+
@repo.sync(version, force) if should_sync?
|
54
89
|
end
|
55
90
|
|
56
91
|
def status
|
@@ -63,9 +98,11 @@ class R10K::Module::Git < R10K::Module::Base
|
|
63
98
|
|
64
99
|
private
|
65
100
|
|
66
|
-
def validate_ref(desired, default)
|
101
|
+
def validate_ref(desired, default, default_override)
|
67
102
|
if desired && desired != :control_branch && @repo.resolve(desired)
|
68
103
|
return desired
|
104
|
+
elsif default_override && @repo.resolve(default_override)
|
105
|
+
return default_override
|
69
106
|
elsif default && @repo.resolve(default)
|
70
107
|
return default
|
71
108
|
else
|
@@ -81,6 +118,11 @@ class R10K::Module::Git < R10K::Module::Base
|
|
81
118
|
msg << "Could not determine desired ref"
|
82
119
|
end
|
83
120
|
|
121
|
+
if default_override
|
122
|
+
msg << "or resolve the default branch override '%{default_override}',"
|
123
|
+
vars[:default_override] = default_override
|
124
|
+
end
|
125
|
+
|
84
126
|
if default
|
85
127
|
msg << "or resolve default ref '%{default}'"
|
86
128
|
vars[:default] = default
|
@@ -91,23 +133,4 @@ class R10K::Module::Git < R10K::Module::Base
|
|
91
133
|
raise ArgumentError, _(msg.join(' ')) % vars
|
92
134
|
end
|
93
135
|
end
|
94
|
-
|
95
|
-
def parse_options(options)
|
96
|
-
ref_opts = [:branch, :tag, :commit, :ref]
|
97
|
-
known_opts = [:git, :default_branch] + ref_opts
|
98
|
-
|
99
|
-
unhandled = options.keys - known_opts
|
100
|
-
unless unhandled.empty?
|
101
|
-
raise ArgumentError, _("Unhandled options %{unhandled} specified for %{class}") % {unhandled: unhandled, class: self.class}
|
102
|
-
end
|
103
|
-
|
104
|
-
@remote = options[:git]
|
105
|
-
|
106
|
-
@desired_ref = ref_opts.find { |key| break options[key] if options.has_key?(key) } || 'master'
|
107
|
-
@default_ref = options[:default_branch]
|
108
|
-
|
109
|
-
if @desired_ref == :control_branch && @environment && @environment.respond_to?(:ref)
|
110
|
-
@desired_ref = @environment.ref
|
111
|
-
end
|
112
|
-
end
|
113
136
|
end
|
data/lib/r10k/module/local.rb
CHANGED
@@ -9,7 +9,7 @@ class R10K::Module::Local < R10K::Module::Base
|
|
9
9
|
R10K::Module.register(self)
|
10
10
|
|
11
11
|
def self.implement?(name, args)
|
12
|
-
args.is_a?(Hash) && args[:local]
|
12
|
+
args.is_a?(Hash) && (args[:local] || args[:type].to_s == 'local')
|
13
13
|
end
|
14
14
|
|
15
15
|
include R10K::Logging
|
@@ -30,6 +30,7 @@ class R10K::Module::Local < R10K::Module::Base
|
|
30
30
|
:insync
|
31
31
|
end
|
32
32
|
|
33
|
+
# @param [Hash] opts Deprecated
|
33
34
|
def sync(opts={})
|
34
35
|
logger.debug1 _("Module %{title} is a local module, always indicating synced.") % {title: title}
|
35
36
|
end
|
data/lib/r10k/module/svn.rb
CHANGED
@@ -7,7 +7,7 @@ class R10K::Module::SVN < R10K::Module::Base
|
|
7
7
|
R10K::Module.register(self)
|
8
8
|
|
9
9
|
def self.implement?(name, args)
|
10
|
-
args.
|
10
|
+
args.has_key?(:svn) || args[:type].to_s == 'svn'
|
11
11
|
end
|
12
12
|
|
13
13
|
# @!attribute [r] expected_revision
|
@@ -36,18 +36,21 @@ class R10K::Module::SVN < R10K::Module::Base
|
|
36
36
|
|
37
37
|
include R10K::Util::Setopts
|
38
38
|
|
39
|
-
INITIALIZE_OPTS = {
|
40
|
-
:svn => :url,
|
41
|
-
:rev => :expected_revision,
|
42
|
-
:revision => :expected_revision,
|
43
|
-
:username => :self,
|
44
|
-
:password => :self
|
45
|
-
}
|
46
|
-
|
47
39
|
def initialize(name, dirname, opts, environment=nil)
|
48
40
|
super
|
49
|
-
|
50
|
-
|
41
|
+
setopts(opts, {
|
42
|
+
# Standard option interface
|
43
|
+
:source => :url,
|
44
|
+
:version => :expected_revision,
|
45
|
+
:type => ::R10K::Util::Setopts::Ignore,
|
46
|
+
|
47
|
+
# Type-specific options
|
48
|
+
:svn => :url,
|
49
|
+
:rev => :expected_revision,
|
50
|
+
:revision => :expected_revision,
|
51
|
+
:username => :self,
|
52
|
+
:password => :self
|
53
|
+
})
|
51
54
|
|
52
55
|
@working_dir = R10K::SVN::WorkingDir.new(@path, :username => @username, :password => @password)
|
53
56
|
end
|
@@ -66,14 +69,17 @@ class R10K::Module::SVN < R10K::Module::Base
|
|
66
69
|
end
|
67
70
|
end
|
68
71
|
|
72
|
+
# @param [Hash] opts Deprecated
|
69
73
|
def sync(opts={})
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
74
|
+
if should_sync?
|
75
|
+
case status
|
76
|
+
when :absent
|
77
|
+
install
|
78
|
+
when :mismatched
|
79
|
+
reinstall
|
80
|
+
when :outdated
|
81
|
+
update
|
82
|
+
end
|
77
83
|
end
|
78
84
|
end
|
79
85
|
|
data/lib/r10k/puppetfile.rb
CHANGED
@@ -3,6 +3,7 @@ require 'pathname'
|
|
3
3
|
require 'r10k/module'
|
4
4
|
require 'r10k/util/purgeable'
|
5
5
|
require 'r10k/errors'
|
6
|
+
require 'r10k/content_synchronizer'
|
6
7
|
|
7
8
|
module R10K
|
8
9
|
class Puppetfile
|
@@ -42,28 +43,37 @@ class Puppetfile
|
|
42
43
|
# @return [Boolean] Overwrite any locally made changes
|
43
44
|
attr_accessor :force
|
44
45
|
|
45
|
-
# @!attribute [r]
|
46
|
-
# @
|
47
|
-
|
48
|
-
attr_reader :modules_by_vcs_cachedir
|
46
|
+
# @!attribute [r] overrides
|
47
|
+
# @return [Hash] Various settings overridden from normal configs
|
48
|
+
attr_reader :overrides
|
49
49
|
|
50
50
|
# @param [String] basedir
|
51
|
-
# @param [String]
|
52
|
-
#
|
53
|
-
# @param [String]
|
54
|
-
# @param [
|
55
|
-
|
51
|
+
# @param [Hash, String, nil] options_or_moduledir The directory to install the modules or a Hash of options.
|
52
|
+
# Usage as moduledir is deprecated. Only use as options, defaults to nil
|
53
|
+
# @param [String, nil] puppetfile_path Deprecated - The path to the Puppetfile, defaults to nil
|
54
|
+
# @param [String, nil] puppetfile_name Deprecated - The name of the Puppetfile, defaults to nil
|
55
|
+
# @param [Boolean, nil] force Deprecated - Shall we overwrite locally made changes?
|
56
|
+
def initialize(basedir, options_or_moduledir = nil, deprecated_path_arg = nil, deprecated_name_arg = nil, deprecated_force_arg = nil)
|
56
57
|
@basedir = basedir
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
if options_or_moduledir.is_a? Hash
|
59
|
+
options = options_or_moduledir
|
60
|
+
deprecated_moduledir_arg = nil
|
61
|
+
else
|
62
|
+
options = {}
|
63
|
+
deprecated_moduledir_arg = options_or_moduledir
|
64
|
+
end
|
65
|
+
|
66
|
+
@force = deprecated_force_arg || options.delete(:force) || false
|
67
|
+
@moduledir = deprecated_moduledir_arg || options.delete(:moduledir) || File.join(basedir, 'modules')
|
68
|
+
@puppetfile_name = deprecated_name_arg || options.delete(:puppetfile_name) || 'Puppetfile'
|
69
|
+
@puppetfile_path = deprecated_path_arg || options.delete(:puppetfile_path) || File.join(basedir, @puppetfile_name)
|
70
|
+
|
71
|
+
@overrides = options.delete(:overrides) || {}
|
61
72
|
|
62
73
|
logger.info _("Using Puppetfile '%{puppetfile}'") % {puppetfile: @puppetfile_path}
|
63
74
|
|
64
75
|
@modules = []
|
65
76
|
@managed_content = {}
|
66
|
-
@modules_by_vcs_cachedir = {}
|
67
77
|
@forge = 'forgeapi.puppetlabs.com'
|
68
78
|
|
69
79
|
@loaded = false
|
@@ -83,7 +93,7 @@ class Puppetfile
|
|
83
93
|
|
84
94
|
dsl = R10K::Puppetfile::DSL.new(self)
|
85
95
|
dsl.instance_eval(puppetfile_contents, @puppetfile_path)
|
86
|
-
|
96
|
+
|
87
97
|
validate_no_duplicate_names(@modules)
|
88
98
|
@loaded = true
|
89
99
|
rescue SyntaxError, LoadError, ArgumentError, NameError => e
|
@@ -123,29 +133,44 @@ class Puppetfile
|
|
123
133
|
end
|
124
134
|
|
125
135
|
# @param [String] name
|
126
|
-
# @param [
|
136
|
+
# @param [Hash, String, Symbol] args Calling with anything but a Hash is
|
137
|
+
# deprecated. The DSL will now convert String and Symbol versions to
|
138
|
+
# Hashes of the shape
|
139
|
+
# { version: <String or Symbol> }
|
140
|
+
#
|
127
141
|
def add_module(name, args)
|
128
|
-
if args.is_a?(Hash)
|
142
|
+
if !args.is_a?(Hash)
|
143
|
+
args = { version: args }
|
144
|
+
end
|
145
|
+
|
146
|
+
args[:overrides] = @overrides
|
147
|
+
|
148
|
+
if install_path = args.delete(:install_path)
|
129
149
|
install_path = resolve_install_path(install_path)
|
130
150
|
validate_install_path(install_path, name)
|
131
151
|
else
|
132
152
|
install_path = @moduledir
|
133
153
|
end
|
134
154
|
|
135
|
-
if
|
136
|
-
args[:
|
155
|
+
if @default_branch_override != nil
|
156
|
+
args[:default_branch_override] = @default_branch_override
|
137
157
|
end
|
138
158
|
|
139
|
-
# Keep track of all the content this Puppetfile is managing to enable purging.
|
140
|
-
@managed_content[install_path] = Array.new unless @managed_content.has_key?(install_path)
|
141
159
|
|
142
160
|
mod = R10K::Module.new(name, install_path, args, @environment)
|
143
|
-
mod.origin =
|
161
|
+
mod.origin = :puppetfile
|
162
|
+
|
163
|
+
# Do not load modules if they would conflict with the attached
|
164
|
+
# environment
|
165
|
+
if environment && environment.module_conflicts?(mod)
|
166
|
+
mod = nil
|
167
|
+
return @modules
|
168
|
+
end
|
144
169
|
|
170
|
+
# Keep track of all the content this Puppetfile is managing to enable purging.
|
171
|
+
@managed_content[install_path] = Array.new unless @managed_content.has_key?(install_path)
|
145
172
|
@managed_content[install_path] << mod.name
|
146
|
-
|
147
|
-
@modules_by_vcs_cachedir[cachedir] ||= []
|
148
|
-
@modules_by_vcs_cachedir[cachedir] << mod
|
173
|
+
|
149
174
|
@modules << mod
|
150
175
|
end
|
151
176
|
|
@@ -183,70 +208,22 @@ class Puppetfile
|
|
183
208
|
def accept(visitor)
|
184
209
|
pool_size = self.settings[:pool_size]
|
185
210
|
if pool_size > 1
|
186
|
-
concurrent_accept(visitor, pool_size)
|
211
|
+
R10K::ContentSynchronizer.concurrent_accept(modules, visitor, self, pool_size, logger)
|
187
212
|
else
|
188
|
-
serial_accept(visitor)
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
private
|
193
|
-
|
194
|
-
def serial_accept(visitor)
|
195
|
-
visitor.visit(:puppetfile, self) do
|
196
|
-
modules.each do |mod|
|
197
|
-
mod.accept(visitor)
|
198
|
-
end
|
213
|
+
R10K::ContentSynchronizer.serial_accept(modules, visitor, self)
|
199
214
|
end
|
200
215
|
end
|
201
216
|
|
202
|
-
def
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
# If any threads raise an exception the deployment is considered a failure.
|
209
|
-
# In that event clear the queue, wait for other threads to finish their
|
210
|
-
# current work, then re-raise the first exception caught.
|
211
|
-
begin
|
212
|
-
thread_pool.each(&:join)
|
213
|
-
rescue => e
|
214
|
-
logger.error _("Error during concurrent deploy of a module: %{message}") % {message: e.message}
|
215
|
-
mods_queue.clear
|
216
|
-
thread_exception ||= e
|
217
|
-
retry
|
218
|
-
ensure
|
219
|
-
raise thread_exception unless thread_exception.nil?
|
217
|
+
def sync
|
218
|
+
pool_size = self.settings[:pool_size]
|
219
|
+
if pool_size > 1
|
220
|
+
R10K::ContentSynchronizer.concurrent_sync(modules, pool_size, logger)
|
221
|
+
else
|
222
|
+
R10K::ContentSynchronizer.serial_sync(modules)
|
220
223
|
end
|
221
224
|
end
|
222
225
|
|
223
|
-
|
224
|
-
Queue.new.tap do |queue|
|
225
|
-
visitor.visit(:puppetfile, self) do
|
226
|
-
modules_by_cachedir = modules_by_vcs_cachedir.clone
|
227
|
-
modules_without_vcs_cachedir = modules_by_cachedir.delete(:none) || []
|
228
|
-
|
229
|
-
modules_without_vcs_cachedir.each {|mod| queue << Array(mod) }
|
230
|
-
modules_by_cachedir.values.each {|mods| queue << mods }
|
231
|
-
end
|
232
|
-
end
|
233
|
-
end
|
234
|
-
public :modules_queue
|
235
|
-
|
236
|
-
def visitor_thread(visitor, mods_queue)
|
237
|
-
Thread.new do
|
238
|
-
begin
|
239
|
-
while mods = mods_queue.pop(true) do
|
240
|
-
mods.each {|mod| mod.accept(visitor) }
|
241
|
-
end
|
242
|
-
rescue ThreadError => e
|
243
|
-
logger.debug _("Module thread %{id} exiting: %{message}") % {message: e.message, id: Thread.current.object_id}
|
244
|
-
Thread.exit
|
245
|
-
rescue => e
|
246
|
-
Thread.main.raise(e)
|
247
|
-
end
|
248
|
-
end
|
249
|
-
end
|
226
|
+
private
|
250
227
|
|
251
228
|
def puppetfile_contents
|
252
229
|
File.read(@puppetfile_path)
|
@@ -287,7 +264,13 @@ class Puppetfile
|
|
287
264
|
end
|
288
265
|
|
289
266
|
def mod(name, args = nil)
|
290
|
-
|
267
|
+
if args.is_a?(Hash)
|
268
|
+
opts = args
|
269
|
+
else
|
270
|
+
opts = { version: args }
|
271
|
+
end
|
272
|
+
|
273
|
+
@librarian.add_module(name, opts)
|
291
274
|
end
|
292
275
|
|
293
276
|
def forge(location)
|