r10k 3.12.0 → 3.14.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/docker.yml +1 -1
  3. data/.github/workflows/rspec_tests.yml +5 -5
  4. data/.github/workflows/stale.yml +2 -0
  5. data/.gitignore +1 -0
  6. data/.travis.yml +1 -1
  7. data/CHANGELOG.mkd +33 -0
  8. data/doc/dynamic-environments/configuration.mkd +59 -10
  9. data/doc/git/providers.mkd +22 -0
  10. data/doc/puppetfile.mkd +13 -0
  11. data/docker/Makefile +1 -1
  12. data/docker/r10k/Dockerfile +1 -1
  13. data/docker/r10k/release.Dockerfile +1 -1
  14. data/lib/r10k/action/base.rb +1 -1
  15. data/lib/r10k/action/deploy/deploy_helpers.rb +4 -0
  16. data/lib/r10k/action/deploy/display.rb +1 -1
  17. data/lib/r10k/action/deploy/environment.rb +5 -7
  18. data/lib/r10k/action/deploy/module.rb +3 -4
  19. data/lib/r10k/action/runner.rb +6 -0
  20. data/lib/r10k/action/visitor.rb +3 -0
  21. data/lib/r10k/environment/bare.rb +4 -7
  22. data/lib/r10k/environment/name.rb +14 -9
  23. data/lib/r10k/environment/plain.rb +16 -0
  24. data/lib/r10k/environment/tarball.rb +78 -0
  25. data/lib/r10k/environment/with_modules.rb +1 -1
  26. data/lib/r10k/environment.rb +2 -0
  27. data/lib/r10k/errors.rb +5 -0
  28. data/lib/r10k/forge/module_release.rb +2 -1
  29. data/lib/r10k/git/cache.rb +4 -13
  30. data/lib/r10k/git/rugged/bare_repository.rb +1 -1
  31. data/lib/r10k/git/rugged/base_repository.rb +12 -1
  32. data/lib/r10k/git/rugged/cache.rb +8 -0
  33. data/lib/r10k/git/rugged/credentials.rb +1 -1
  34. data/lib/r10k/git/rugged/working_repository.rb +1 -1
  35. data/lib/r10k/git/stateful_repository.rb +2 -0
  36. data/lib/r10k/initializers.rb +20 -0
  37. data/lib/r10k/logging.rb +78 -1
  38. data/lib/r10k/module/base.rb +6 -2
  39. data/lib/r10k/module/forge.rb +10 -10
  40. data/lib/r10k/module/git.rb +1 -3
  41. data/lib/r10k/module/local.rb +6 -2
  42. data/lib/r10k/module/tarball.rb +101 -0
  43. data/lib/r10k/module.rb +1 -0
  44. data/lib/r10k/module_loader/puppetfile/dsl.rb +1 -1
  45. data/lib/r10k/module_loader/puppetfile.rb +17 -2
  46. data/lib/r10k/settings.rb +35 -0
  47. data/lib/r10k/source/git.rb +18 -18
  48. data/lib/r10k/source/yaml.rb +1 -1
  49. data/lib/r10k/tarball.rb +183 -0
  50. data/lib/r10k/util/cacheable.rb +31 -0
  51. data/lib/r10k/util/downloader.rb +134 -0
  52. data/lib/r10k/util/purgeable.rb +6 -2
  53. data/lib/r10k/util/setopts.rb +2 -0
  54. data/lib/r10k/util/subprocess.rb +1 -0
  55. data/lib/r10k/version.rb +1 -1
  56. data/locales/r10k.pot +85 -57
  57. data/r10k.gemspec +2 -2
  58. data/r10k.yaml.example +28 -0
  59. data/spec/fixtures/tarball/tarball.tar.gz +0 -0
  60. data/spec/fixtures/unit/action/r10k_logging.yaml +12 -0
  61. data/spec/fixtures/unit/puppetfile/various-modules/Puppetfile +1 -0
  62. data/spec/fixtures/unit/puppetfile/various-modules/Puppetfile.new +1 -0
  63. data/spec/fixtures/unit/util/purgeable/managed_one/managed_subdir_1/managed_symlink_file +1 -0
  64. data/spec/fixtures/unit/util/purgeable/managed_one/managed_subdir_1/{managed_subdir_2 → subdir_allowlisted_2}/ignored_1 +0 -0
  65. data/spec/fixtures/unit/util/purgeable/managed_one/managed_subdir_1/unmanaged_symlink_dir +1 -0
  66. data/spec/fixtures/unit/util/purgeable/managed_one/managed_symlink_dir +1 -0
  67. data/spec/fixtures/unit/util/purgeable/managed_one/unmanaged_symlink_file +1 -0
  68. data/spec/integration/git/rugged/cache_spec.rb +33 -0
  69. data/spec/integration/util/purageable_spec.rb +41 -0
  70. data/spec/shared-contexts/tarball.rb +32 -0
  71. data/spec/spec_helper.rb +1 -0
  72. data/spec/unit/action/deploy/module_spec.rb +2 -2
  73. data/spec/unit/action/puppetfile/install_spec.rb +2 -2
  74. data/spec/unit/action/runner_spec.rb +52 -1
  75. data/spec/unit/environment/bare_spec.rb +13 -0
  76. data/spec/unit/environment/name_spec.rb +18 -0
  77. data/spec/unit/environment/plain_spec.rb +8 -0
  78. data/spec/unit/environment/tarball_spec.rb +45 -0
  79. data/spec/unit/environment/with_modules_spec.rb +1 -1
  80. data/spec/unit/git/cache_spec.rb +2 -15
  81. data/spec/unit/git/rugged/cache_spec.rb +19 -0
  82. data/spec/unit/module/forge_spec.rb +9 -7
  83. data/spec/unit/module/tarball_spec.rb +70 -0
  84. data/spec/unit/module_loader/puppetfile_spec.rb +21 -3
  85. data/spec/unit/module_spec.rb +14 -7
  86. data/spec/unit/tarball_spec.rb +57 -0
  87. data/spec/unit/util/cacheable_spec.rb +23 -0
  88. data/spec/unit/util/downloader_spec.rb +98 -0
  89. data/spec/unit/util/purgeable_spec.rb +22 -11
  90. metadata +39 -17
@@ -3,6 +3,7 @@ require 'r10k/git'
3
3
  require 'r10k/settings'
4
4
  require 'r10k/instance_cache'
5
5
  require 'forwardable'
6
+ require 'r10k/util/cacheable'
6
7
 
7
8
  # Cache Git repository mirrors for object database reuse.
8
9
  #
@@ -15,18 +16,9 @@ require 'forwardable'
15
16
  class R10K::Git::Cache
16
17
 
17
18
  include R10K::Settings::Mixin
19
+ include R10K::Util::Cacheable
18
20
 
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
21
+ def_setting_attr :cache_root, R10K::Util::Cacheable.default_cachedir('git')
30
22
 
31
23
  @instance_cache = R10K::InstanceCache.new(self)
32
24
 
@@ -109,8 +101,7 @@ class R10K::Git::Cache
109
101
 
110
102
  alias cached? exist?
111
103
 
112
- # Reformat the remote name into something that can be used as a directory
113
104
  def sanitized_dirname
114
- @sanitized_dirname ||= @remote.gsub(/(\w+:\/\/)(.*)(@)/, '\1').gsub(/[^@\w\.-]/, '-')
105
+ @sanitized_dirname ||= super(@remote)
115
106
  end
116
107
  end
@@ -64,7 +64,7 @@ class R10K::Git::Rugged::BareRepository < R10K::Git::Rugged::BaseRepository
64
64
  results = nil
65
65
 
66
66
  R10K::Git.with_proxy(proxy) do
67
- results = with_repo { |repo| repo.fetch(remote_name, refspecs, options) }
67
+ results = with_repo { |repo| repo.fetch(remote_name, refspecs, **options) }
68
68
  end
69
69
 
70
70
  report_transfer(results, remote_name)
@@ -20,7 +20,8 @@ class R10K::Git::Rugged::BaseRepository
20
20
  else
21
21
  object.oid
22
22
  end
23
- rescue ::Rugged::ReferenceError
23
+ rescue ::Rugged::ReferenceError, ::Rugged::OdbError => e
24
+ logger.debug2(_("Unable to resolve %{pattern}: %{e} ") % {pattern: pattern, e: e })
24
25
  nil
25
26
  end
26
27
 
@@ -60,6 +61,16 @@ class R10K::Git::Rugged::BaseRepository
60
61
  remotes_hash
61
62
  end
62
63
 
64
+ # Update a remote URL
65
+ # @param [String] The remote URL of the git repository
66
+ # @param [String] An optional remote name for the git repository
67
+ def update_remote(remote, remote_name='origin')
68
+ if @_rugged_repo
69
+ logger.debug2(_("Remote URL is different from cache, updating %{orig} to %{update}") % {orig: remotes[remote_name], update: remote})
70
+ @_rugged_repo.remotes.set_url(remote_name, remote)
71
+ end
72
+ end
73
+
63
74
  private
64
75
 
65
76
  def with_repo(opts={})
@@ -8,4 +8,12 @@ class R10K::Git::Rugged::Cache < R10K::Git::Cache
8
8
  def self.bare_repository
9
9
  R10K::Git::Rugged::BareRepository
10
10
  end
11
+
12
+ # Update the remote URL if the cache differs from the current configuration
13
+ def sync!
14
+ if cached? && @repo.remotes['origin'] != @remote
15
+ @repo.update_remote(@remote)
16
+ end
17
+ super
18
+ end
11
19
  end
@@ -130,7 +130,7 @@ class R10K::Git::Rugged::Credentials
130
130
 
131
131
  user = nil
132
132
 
133
- if !username_from_url.nil?
133
+ if !username_from_url.nil? && !username_from_url.empty?
134
134
  user = username_from_url
135
135
  logger.debug2 _("URL %{url} includes the username %{username}, using that user for authentication.") % {url: url.inspect, username: username_from_url}
136
136
  elsif git_user
@@ -93,7 +93,7 @@ class R10K::Git::Rugged::WorkingRepository < R10K::Git::Rugged::BaseRepository
93
93
  results = nil
94
94
 
95
95
  R10K::Git.with_proxy(proxy) do
96
- results = with_repo { |repo| repo.fetch(remote_name, refspecs, options) }
96
+ results = with_repo { |repo| repo.fetch(remote_name, refspecs, **options) }
97
97
  end
98
98
 
99
99
  report_transfer(results, remote)
@@ -86,6 +86,8 @@ class R10K::Git::StatefulRepository
86
86
  :mismatched
87
87
  elsif !(@repo.origin == @remote)
88
88
  :mismatched
89
+ elsif @repo.head.nil?
90
+ :mismatched
89
91
  elsif @repo.dirty?
90
92
  :dirty
91
93
  elsif !(@repo.head == @cache.resolve(ref))
@@ -4,6 +4,7 @@ require 'r10k/git'
4
4
  require 'r10k/git/cache'
5
5
 
6
6
  require 'r10k/forge/module_release'
7
+ require 'r10k/tarball'
7
8
 
8
9
  module R10K
9
10
  module Initializers
@@ -30,14 +31,27 @@ module R10K
30
31
  logger.warn(_("the purgedirs key in r10k.yaml is deprecated. it is currently ignored."))
31
32
  end
32
33
 
34
+ with_setting(:logging) { |value| LoggingInitializer.new(value).call }
35
+
33
36
  with_setting(:deploy) { |value| DeployInitializer.new(value).call }
34
37
 
35
38
  with_setting(:cachedir) { |value| R10K::Git::Cache.settings[:cache_root] = value }
36
39
  with_setting(:cachedir) { |value| R10K::Forge::ModuleRelease.settings[:cache_root] = value }
40
+ with_setting(:cachedir) { |value| R10K::Tarball.settings[:cache_root] = value }
37
41
  with_setting(:pool_size) { |value| R10K::Puppetfile.settings[:pool_size] = value }
42
+ with_setting(:proxy) { |value| R10K::Tarball.settings[:proxy] = value }
38
43
 
39
44
  with_setting(:git) { |value| GitInitializer.new(value).call }
40
45
  with_setting(:forge) { |value| ForgeInitializer.new(value).call }
46
+ with_setting(:tarball) { |value| TarballInitializer.new(value).call }
47
+ end
48
+ end
49
+
50
+ class LoggingInitializer < BaseInitializer
51
+ def call
52
+ with_setting(:level) { |value| R10K::Logging.level = value }
53
+ with_setting(:disable_default_stderr) { |value| R10K::Logging.disable_default_stderr = value }
54
+ with_setting(:outputs) { |value| R10K::Logging.add_outputters(value) }
41
55
  end
42
56
  end
43
57
 
@@ -69,5 +83,11 @@ module R10K
69
83
  with_setting(:authorization_token) { |value| PuppetForge::Connection.authorization = value }
70
84
  end
71
85
  end
86
+
87
+ class TarballInitializer < BaseInitializer
88
+ def call
89
+ with_setting(:proxy) { |value| R10K::Tarball.settings[:proxy] = value }
90
+ end
91
+ end
72
92
  end
73
93
  end
data/lib/r10k/logging.rb CHANGED
@@ -8,6 +8,16 @@ require 'r10k/logging/terminaloutputter'
8
8
  module R10K::Logging
9
9
 
10
10
  LOG_LEVELS = %w{DEBUG2 DEBUG1 DEBUG INFO NOTICE WARN ERROR FATAL}
11
+ SYSLOG_LEVELS_MAP = {
12
+ 'DEBUG2' => 'DEBUG',
13
+ 'DEBUG1' => 'DEBUG',
14
+ 'DEBUG' => 'DEBUG',
15
+ 'INFO' => 'INFO',
16
+ 'NOTICE' => 'INFO',
17
+ 'WARN' => 'WARN',
18
+ 'ERROR' => 'ERROR',
19
+ 'FATAL' => 'FATAL',
20
+ }.freeze
11
21
 
12
22
  def logger_name
13
23
  self.class.to_s
@@ -21,6 +31,9 @@ module R10K::Logging
21
31
  else
22
32
  @logger = Log4r::Logger.new(name)
23
33
  @logger.add(R10K::Logging.outputter)
34
+ R10K::Logging.outputters.each do |output|
35
+ @logger.add(output)
36
+ end
24
37
  end
25
38
  end
26
39
  @logger
@@ -59,7 +72,7 @@ module R10K::Logging
59
72
  if level.nil?
60
73
  raise ArgumentError, _("Invalid log level '%{val}'. Valid levels are %{log_levels}") % {val: val, log_levels: LOG_LEVELS.map(&:downcase).inspect}
61
74
  end
62
- outputter.level = level
75
+ outputter.level = level unless @disable_default_stderr
63
76
  @level = level
64
77
 
65
78
  if level < Log4r::INFO
@@ -69,6 +82,58 @@ module R10K::Logging
69
82
  end
70
83
  end
71
84
 
85
+ def disable_default_stderr=(val)
86
+ @disable_default_stderr = val
87
+ outputter.level = val ? Log4r::OFF : @level
88
+ end
89
+
90
+ def add_outputters(outputs)
91
+ outputs.each do |output|
92
+ type = output.fetch(:type)
93
+ # Support specifying both short as well as full names
94
+ type = type.to_s[0..-10] if type.to_s.downcase.end_with? 'outputter'
95
+
96
+ name = output.fetch(:name, 'r10k')
97
+ if output[:level]
98
+ level = parse_level(output[:level])
99
+ if level.nil?
100
+ raise ArgumentError, _("Invalid log level '%{val}'. Valid levels are %{log_levels}") % { val: output[:level], log_levels: LOG_LEVELS.map(&:downcase).inspect }
101
+ end
102
+ else
103
+ level = self.level
104
+ end
105
+ only_at = output[:only_at]
106
+ only_at&.map! do |val|
107
+ lv = parse_level(val)
108
+ if lv.nil?
109
+ raise ArgumentError, _("Invalid log level '%{val}'. Valid levels are %{log_levels}") % { val: val, log_levels: LOG_LEVELS.map(&:downcase).inspect }
110
+ end
111
+
112
+ lv
113
+ end
114
+ parameters = output.fetch(:parameters, {}).merge({ level: level })
115
+
116
+ begin
117
+ # Try to load the outputter file if possible
118
+ require "log4r/outputter/#{type.to_s.downcase}outputter"
119
+ rescue LoadError
120
+ false
121
+ end
122
+ outputtertype = Log4r.constants
123
+ .select { |klass| klass.to_s.end_with? 'Outputter' }
124
+ .find { |klass| klass.to_s.downcase == "#{type.to_s.downcase}outputter" }
125
+ raise ArgumentError, "Unable to find a #{output[:type]} outputter." unless outputtertype
126
+
127
+ outputter = Log4r.const_get(outputtertype).new(name, parameters)
128
+ outputter.only_at(*only_at) if only_at
129
+ # Handle log4r's syslog mapping correctly
130
+ outputter.map_levels_by_name_to_syslog(SYSLOG_LEVELS_MAP) if outputter.respond_to? :map_levels_by_name_to_syslog
131
+
132
+ @outputters << outputter
133
+ Log4r::Logger.global.add outputter
134
+ end
135
+ end
136
+
72
137
  extend Forwardable
73
138
  def_delegators :@outputter, :use_color, :use_color=
74
139
 
@@ -87,6 +152,16 @@ module R10K::Logging
87
152
  # @return [Log4r::Outputter]
88
153
  attr_reader :outputter
89
154
 
155
+ # @!attribute [r] outputters
156
+ # @api private
157
+ # @return [Array[Log4r::Outputter]]
158
+ attr_reader :outputters
159
+
160
+ # @!attribute [r] disable_default_stderr
161
+ # @api private
162
+ # @return [Boolean]
163
+ attr_reader :disable_default_stderr
164
+
90
165
  def default_formatter
91
166
  Log4r::PatternFormatter.new(:pattern => '%l\t -> %m')
92
167
  end
@@ -106,4 +181,6 @@ module R10K::Logging
106
181
  @level = Log4r::WARN
107
182
  @formatter = default_formatter
108
183
  @outputter = default_outputter
184
+ @outputters = []
185
+ @disable_default_stderr = false
109
186
  end
@@ -60,8 +60,12 @@ class R10K::Module::Base
60
60
  @environment = environment
61
61
  @overrides = args.delete(:overrides) || {}
62
62
  @spec_deletable = true
63
- @exclude_spec = args.delete(:exclude_spec)
64
- @exclude_spec = @overrides[:modules].delete(:exclude_spec) if @overrides.dig(:modules, :exclude_spec)
63
+ @exclude_spec = false
64
+ @exclude_spec = @overrides.dig(:modules, :exclude_spec) if @overrides.dig(:modules, :exclude_spec)
65
+ if args.has_key?(:exclude_spec)
66
+ logger.debug2 _("Overriding :exclude_spec setting with per module setting for #{@title}")
67
+ @exclude_spec = args.delete(:exclude_spec)
68
+ end
65
69
  @origin = 'external' # Expect Puppetfile or R10k::Environment to set this to a specific value
66
70
 
67
71
  @requested_modules = @overrides.dig(:modules, :requested_modules) || []
@@ -13,16 +13,7 @@ class R10K::Module::Forge < R10K::Module::Base
13
13
  R10K::Module.register(self)
14
14
 
15
15
  def self.implement?(name, args)
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])))
22
- end
23
-
24
- def self.valid_version?(expected_version)
25
- expected_version == :latest || expected_version.nil? || PuppetForge::Util.version_valid?(expected_version)
16
+ args[:type].to_s == 'forge'
26
17
  end
27
18
 
28
19
  def self.statically_defined_version(name, args)
@@ -54,11 +45,20 @@ class R10K::Module::Forge < R10K::Module::Base
54
45
  :type => ::R10K::Util::Setopts::Ignore,
55
46
  }, :raise_on_unhandled => false)
56
47
 
48
+ # Validate version and raise on issue. Title is validated by base class.
49
+ unless valid_version?(@expected_version)
50
+ raise ArgumentError, _("Module version %{ver} is not a valid Forge module version") % {ver: @expected_version}
51
+ end
52
+
57
53
  @expected_version ||= current_version || :latest
58
54
 
59
55
  @v3_module = PuppetForge::V3::Module.new(:slug => @title)
60
56
  end
61
57
 
58
+ def valid_version?(version)
59
+ version == :latest || version.nil? || PuppetForge::Util.version_valid?(version)
60
+ end
61
+
62
62
  # @param [Hash] opts Deprecated
63
63
  # @return [Boolean] true if the module was updated, false otherwise
64
64
  def sync(opts={})
@@ -9,8 +9,6 @@ class R10K::Module::Git < R10K::Module::Base
9
9
 
10
10
  def self.implement?(name, args)
11
11
  args.has_key?(:git) || args[:type].to_s == 'git'
12
- rescue
13
- false
14
12
  end
15
13
 
16
14
  # Will be called if self.implement? above returns true. Will return
@@ -69,7 +67,7 @@ class R10K::Module::Git < R10K::Module::Base
69
67
  :default_branch_override => :default_override_ref,
70
68
  }, :raise_on_unhandled => false)
71
69
 
72
- force = @overrides.dig(:modules, :force)
70
+ force = @overrides[:force]
73
71
  @force = force == false ? false : true
74
72
 
75
73
  @desired_ref ||= 'master'
@@ -8,13 +8,17 @@ class R10K::Module::Local < R10K::Module::Base
8
8
  R10K::Module.register(self)
9
9
 
10
10
  def self.implement?(name, args)
11
- args.is_a?(Hash) && (args[:local] || args[:type].to_s == 'local')
11
+ args[:local] || args[:type].to_s == 'local'
12
12
  end
13
13
 
14
- def version
14
+ def self.statically_defined_version(*)
15
15
  "0.0.0"
16
16
  end
17
17
 
18
+ def version
19
+ self.class.statically_defined_version
20
+ end
21
+
18
22
  def properties
19
23
  {
20
24
  :expected => "0.0.0 (local)",
@@ -0,0 +1,101 @@
1
+ require 'r10k/module'
2
+ require 'r10k/util/setopts'
3
+ require 'r10k/tarball'
4
+
5
+ # This class defines a tarball source module implementation
6
+ class R10K::Module::Tarball < R10K::Module::Base
7
+
8
+ R10K::Module.register(self)
9
+
10
+ def self.implement?(name, args)
11
+ args.is_a?(Hash) && args[:type].to_s == 'tarball'
12
+ rescue
13
+ false
14
+ end
15
+
16
+ def self.statically_defined_version(name, args)
17
+ args[:version] || args[:checksum]
18
+ end
19
+
20
+ # @!attribute [r] tarball
21
+ # @api private
22
+ # @return [R10K::Tarball]
23
+ attr_reader :tarball
24
+
25
+ include R10K::Util::Setopts
26
+
27
+ def initialize(name, dirname, opts, environment=nil)
28
+ super
29
+ setopts(opts, {
30
+ # Standard option interface
31
+ :source => :self,
32
+ :version => :checksum,
33
+ :type => ::R10K::Util::Setopts::Ignore,
34
+ :overrides => :self,
35
+
36
+ # Type-specific options
37
+ :checksum => :self,
38
+ })
39
+
40
+ @tarball = R10K::Tarball.new(name, @source, checksum: @checksum)
41
+ end
42
+
43
+ # Return the status of the currently installed module.
44
+ #
45
+ # @return [Symbol]
46
+ def status
47
+ if not path.exist?
48
+ :absent
49
+ elsif not (tarball.cache_valid? && tarball.insync?(path.to_s))
50
+ :mismatched
51
+ else
52
+ :insync
53
+ end
54
+ end
55
+
56
+ # Synchronize this module with the indicated state.
57
+ # @param [Hash] opts Deprecated
58
+ # @return [Boolean] true if the module was updated, false otherwise
59
+ def sync(opts={})
60
+ tarball.get unless tarball.cache_valid?
61
+ if should_sync?
62
+ case status
63
+ when :absent
64
+ tarball.unpack(path.to_s)
65
+ when :mismatched
66
+ path.rmtree
67
+ tarball.unpack(path.to_s)
68
+ end
69
+ maybe_delete_spec_dir
70
+ true
71
+ else
72
+ false
73
+ end
74
+ end
75
+
76
+ # Return the desired version of this module
77
+ def version
78
+ @checksum || '(present)'
79
+ end
80
+
81
+ # Return the properties of the module
82
+ #
83
+ # @return [Hash]
84
+ # @abstract
85
+ def properties
86
+ {
87
+ :expected => version,
88
+ :actual => ((state = status) == :insync) ? version : state,
89
+ :type => :tarball,
90
+ }
91
+ end
92
+
93
+ # Tarball caches are files, not directories. An important purpose of this
94
+ # method is to indicate where the cache "path" is, for locking/parallelism,
95
+ # so for the Tarball module type, the relevant path location is returned.
96
+ #
97
+ # @return [String] The path this module will cache its tarball source to
98
+ def cachedir
99
+ tarball.cache_path
100
+ end
101
+ end
data/lib/r10k/module.rb CHANGED
@@ -53,4 +53,5 @@ module R10K::Module
53
53
  require 'r10k/module/local'
54
54
  require 'r10k/module/forge'
55
55
  require 'r10k/module/definition'
56
+ require 'r10k/module/tarball'
56
57
  end
@@ -15,7 +15,7 @@ module R10K
15
15
  if args.is_a?(Hash)
16
16
  opts = args
17
17
  else
18
- opts = { version: args }
18
+ opts = { type: 'forge', version: args }
19
19
  end
20
20
 
21
21
  if @metadata_only
@@ -1,5 +1,9 @@
1
+ require 'r10k/errors'
1
2
  require 'r10k/logging'
2
3
  require 'r10k/module'
4
+ require 'r10k/module_loader/puppetfile/dsl'
5
+
6
+ require 'pathname'
3
7
 
4
8
  module R10K
5
9
  module ModuleLoader
@@ -12,7 +16,8 @@ module R10K
12
16
 
13
17
  attr_accessor :default_branch_override, :environment
14
18
  attr_reader :modules, :moduledir, :puppetfile_path,
15
- :managed_directories, :desired_contents, :purge_exclusions
19
+ :managed_directories, :desired_contents, :purge_exclusions,
20
+ :environment_name
16
21
 
17
22
  # @param basedir [String] The path that contains the moduledir &
18
23
  # Puppetfile by default. May be an environment, project, or
@@ -36,6 +41,7 @@ module R10K
36
41
  @puppetfile_path = resolve_path(@basedir, puppetfile)
37
42
  @overrides = overrides
38
43
  @environment = environment
44
+ @environment_name = @environment&.name
39
45
  @default_branch_override = @overrides.dig(:environments, :default_branch_override)
40
46
  @allow_puppetfile_forge = @overrides.dig(:forge, :allow_puppetfile_override)
41
47
 
@@ -161,6 +167,13 @@ module R10K
161
167
  @modules << mod
162
168
  end
163
169
 
170
+ # @deprecated
171
+ # @return [String] The base directory that contains the Puppetfile
172
+ def basedir
173
+ logger.warn _('"basedir" is deprecated. Please use "environment_name" instead. "basedir" will be removed in a future version.')
174
+ @basedir
175
+ end
176
+
164
177
  private
165
178
 
166
179
  def empty_load_output
@@ -183,8 +196,10 @@ module R10K
183
196
  end
184
197
 
185
198
  def parse_module_definition(name, info)
199
+ # The only valid (deprecated) way a module can be defined with a
200
+ # non-hash info is if it is a Forge module.
186
201
  if !info.is_a?(Hash)
187
- info = { version: info }
202
+ info = { type: 'forge', version: info }
188
203
  end
189
204
 
190
205
  info[:overrides] = @overrides
data/lib/r10k/settings.rb CHANGED
@@ -217,6 +217,39 @@ module R10K
217
217
  })])
218
218
  end
219
219
 
220
+ def self.logging_settings
221
+ R10K::Settings::Collection.new(:logging, [
222
+ Definition.new(:level, {
223
+ desc: 'What logging level should R10k run on if not specified at runtime.',
224
+ validate: lambda do |value|
225
+ if R10K::Logging.parse_level(value).nil?
226
+ raise ArgumentError, "`level` must be a valid log level.
227
+ Valid levels are #{R10K::Logging::LOG_LEVELS.map(&:downcase).inspect}"
228
+ end
229
+ end
230
+ }),
231
+
232
+ Definition.new(:outputs, {
233
+ desc: 'Additional log outputs to use.',
234
+ validate: lambda do |value|
235
+ unless value.is_a?(Array)
236
+ raise ArgumentError, "The `outputs` setting should be an array of outputs, not a #{value.class}"
237
+ end
238
+ end
239
+ }),
240
+
241
+ Definition.new(:disable_default_stderr, {
242
+ desc: 'Disable the default stderr logging output',
243
+ default: false,
244
+ validate: lambda do |value|
245
+ unless !!value == value
246
+ raise ArgumentError, "`disable_default_stderr` can only be a boolean value, not '#{value}'"
247
+ end
248
+ end
249
+ })
250
+ ])
251
+ end
252
+
220
253
  def self.global_settings
221
254
  R10K::Settings::Collection.new(:global, [
222
255
  Definition.new(:sources, {
@@ -271,6 +304,8 @@ module R10K
271
304
  R10K::Settings.git_settings,
272
305
 
273
306
  R10K::Settings.deploy_settings,
307
+
308
+ R10K::Settings.logging_settings
274
309
  ])
275
310
  end
276
311
  end
@@ -100,26 +100,26 @@ class R10K::Source::Git < R10K::Source::Base
100
100
 
101
101
  def generate_environments
102
102
  envs = []
103
- branch_names.each do |bn|
104
- if bn.valid?
105
- envs << R10K::Environment::Git.new(bn.name,
103
+ environment_names.each do |en|
104
+ if en.valid?
105
+ envs << R10K::Environment::Git.new(en.name,
106
106
  @basedir,
107
- bn.dirname,
107
+ en.dirname,
108
108
  {remote: remote,
109
- ref: bn.name,
109
+ ref: en.original_name,
110
110
  puppetfile_name: puppetfile_name,
111
111
  overrides: @options[:overrides]})
112
- elsif bn.correct?
113
- logger.warn _("Environment %{env_name} contained non-word characters, correcting name to %{corrected_env_name}") % {env_name: bn.name.inspect, corrected_env_name: bn.dirname}
114
- envs << R10K::Environment::Git.new(bn.name,
112
+ elsif en.correct?
113
+ logger.warn _("Environment %{env_name} contained non-word characters, correcting name to %{corrected_env_name}") % {env_name: en.name.inspect, corrected_env_name: en.dirname}
114
+ envs << R10K::Environment::Git.new(en.name,
115
115
  @basedir,
116
- bn.dirname,
116
+ en.dirname,
117
117
  {remote: remote,
118
- ref: bn.name,
118
+ ref: en.original_name,
119
119
  puppetfile_name: puppetfile_name,
120
120
  overrides: @options[:overrides]})
121
- elsif bn.validate?
122
- logger.error _("Environment %{env_name} contained non-word characters, ignoring it.") % {env_name: bn.name.inspect}
121
+ elsif en.validate?
122
+ logger.error _("Environment %{env_name} contained non-word characters, ignoring it.") % {env_name: en.name.inspect}
123
123
  end
124
124
  end
125
125
 
@@ -157,22 +157,22 @@ class R10K::Source::Git < R10K::Source::Base
157
157
 
158
158
  private
159
159
 
160
- def branch_names
160
+ def environment_names
161
161
  opts = {prefix: @prefix,
162
162
  invalid: @invalid_branches,
163
163
  source: @name,
164
164
  strip_component: @strip_component}
165
- branches = @cache.branches
165
+ branch_names = @cache.branches
166
166
  if @ignore_branch_prefixes && !@ignore_branch_prefixes.empty?
167
- branches = filter_branches_by_regexp(branches, @ignore_branch_prefixes)
167
+ branch_names = filter_branches_by_regexp(branch_names, @ignore_branch_prefixes)
168
168
  end
169
169
 
170
170
  if @filter_command && !@filter_command.empty?
171
- branches = filter_branches_by_command(branches, @filter_command)
171
+ branch_names = filter_branches_by_command(branch_names, @filter_command)
172
172
  end
173
173
 
174
- branches.map do |branch|
175
- R10K::Environment::Name.new(branch, opts)
174
+ branch_names.map do |branch_name|
175
+ R10K::Environment::Name.new(branch_name, opts)
176
176
  end
177
177
  end
178
178
  end
@@ -7,7 +7,7 @@ class R10K::Source::Yaml < R10K::Source::Hash
7
7
  begin
8
8
  contents = ::YAML.load_file(config)
9
9
  rescue => e
10
- raise ConfigError, _("Couldn't open environments file %{file}: %{err}") % {file: config, err: e.message}
10
+ raise R10K::ConfigError, _("Couldn't open environments file %{file}: %{err}") % {file: config, err: e.message}
11
11
  end
12
12
 
13
13
  # Set the environments key for the parent class to consume