bolt 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bolt might be problematic. Click here for more details.

Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/lib/bolt/cli.rb +43 -43
  3. data/lib/bolt/config.rb +25 -5
  4. data/lib/bolt/node.rb +3 -1
  5. data/lib/bolt/node/ssh.rb +15 -2
  6. data/lib/bolt/node/winrm.rb +20 -9
  7. data/lib/bolt/version.rb +1 -1
  8. data/modules/boltlib/lib/puppet/functions/run_plan.rb +1 -1
  9. data/modules/boltlib/lib/puppet/functions/run_task.rb +29 -32
  10. data/vendored/puppet/lib/puppet.rb +2 -5
  11. data/vendored/puppet/lib/puppet/application.rb +18 -1
  12. data/vendored/puppet/lib/puppet/application/agent.rb +8 -1
  13. data/vendored/puppet/lib/puppet/application/config.rb +1 -0
  14. data/vendored/puppet/lib/puppet/application/device.rb +1 -2
  15. data/vendored/puppet/lib/puppet/application/filebucket.rb +10 -2
  16. data/vendored/puppet/lib/puppet/application/help.rb +1 -0
  17. data/vendored/puppet/lib/puppet/application_support.rb +6 -1
  18. data/vendored/puppet/lib/puppet/configurer.rb +8 -3
  19. data/vendored/puppet/lib/puppet/defaults.rb +29 -9
  20. data/vendored/puppet/lib/puppet/environments.rb +2 -0
  21. data/vendored/puppet/lib/puppet/face/config.rb +14 -1
  22. data/vendored/puppet/lib/puppet/face/module/list.rb +1 -1
  23. data/vendored/puppet/lib/puppet/face/module/search.rb +4 -1
  24. data/vendored/puppet/lib/puppet/forge.rb +6 -0
  25. data/vendored/puppet/lib/puppet/functions/convert_to.rb +32 -0
  26. data/vendored/puppet/lib/puppet/gettext/config.rb +135 -37
  27. data/vendored/puppet/lib/puppet/gettext/module_translations.rb +42 -0
  28. data/vendored/puppet/lib/puppet/indirector/catalog/compiler.rb +2 -0
  29. data/vendored/puppet/lib/puppet/module.rb +10 -18
  30. data/vendored/puppet/lib/puppet/network/http/factory.rb +9 -0
  31. data/vendored/puppet/lib/puppet/node/environment.rb +14 -0
  32. data/vendored/puppet/lib/puppet/parser/functions/sprintf.rb +17 -3
  33. data/vendored/puppet/lib/puppet/parser/scope.rb +11 -0
  34. data/vendored/puppet/lib/puppet/pops.rb +0 -1
  35. data/vendored/puppet/lib/puppet/pops/evaluator/epp_evaluator.rb +13 -0
  36. data/vendored/puppet/lib/puppet/pops/loader/loader_paths.rb +39 -5
  37. data/vendored/puppet/lib/puppet/pops/loader/module_loaders.rb +64 -24
  38. data/vendored/puppet/lib/puppet/pops/loader/static_loader.rb +1 -1
  39. data/vendored/puppet/lib/puppet/pops/loader/task_instantiator.rb +21 -70
  40. data/vendored/puppet/lib/puppet/pops/lookup/hiera_config.rb +2 -2
  41. data/vendored/puppet/lib/puppet/pops/parser/parser_support.rb +1 -1
  42. data/vendored/puppet/lib/puppet/pops/pcore.rb +43 -1
  43. data/vendored/puppet/lib/puppet/pops/types/type_factory.rb +4 -0
  44. data/vendored/puppet/lib/puppet/pops/types/types.rb +25 -5
  45. data/vendored/puppet/lib/puppet/provider/selmodule/semodule.rb +5 -3
  46. data/vendored/puppet/lib/puppet/provider/service/smf.rb +2 -0
  47. data/vendored/puppet/lib/puppet/settings/environment_conf.rb +14 -2
  48. data/vendored/puppet/lib/puppet/ssl/certificate_authority.rb +1 -1
  49. data/vendored/puppet/lib/puppet/ssl/certificate_signer.rb +6 -0
  50. data/vendored/puppet/lib/puppet/ssl/host.rb +1 -1
  51. data/vendored/puppet/lib/puppet/type/file/checksum.rb +1 -1
  52. data/vendored/puppet/lib/puppet/type/file/checksum_value.rb +4 -3
  53. data/vendored/puppet/lib/puppet/type/k5login.rb +101 -0
  54. data/vendored/puppet/lib/puppet/type/tidy.rb +4 -2
  55. data/vendored/puppet/lib/puppet/util/checksums.rb +82 -1
  56. data/vendored/puppet/lib/puppet/util/command_line.rb +5 -0
  57. data/vendored/puppet/lib/puppet/vendor/semantic_puppet/lib/semantic_puppet.rb +5 -1
  58. data/vendored/puppet/lib/puppet_pal.rb +272 -11
  59. data/vendored/require_vendored.rb +0 -6
  60. metadata +8 -8
  61. data/vendored/puppet/lib/puppet/bindings.rb +0 -147
  62. data/vendored/puppet/lib/puppet/pops/types/task.rb +0 -116
@@ -38,6 +38,7 @@ class Puppet::Application::Agent < Puppet::Application
38
38
  :digest => 'SHA256',
39
39
  :graph => true,
40
40
  :fingerprint => false,
41
+ :sourceaddress => nil,
41
42
  }.each do |opt,val|
42
43
  options[opt] = val
43
44
  end
@@ -59,6 +60,8 @@ class Puppet::Application::Agent < Puppet::Application
59
60
  option("--fingerprint")
60
61
  option("--digest DIGEST")
61
62
 
63
+ option("--sourceaddress IP_ADDRESS")
64
+
62
65
  option("--detailed-exitcodes") do |arg|
63
66
  options[:detailed_exitcodes] = true
64
67
  end
@@ -99,7 +102,7 @@ USAGE
99
102
  puppet agent [--certname <NAME>] [-D|--daemonize|--no-daemonize]
100
103
  [-d|--debug] [--detailed-exitcodes] [--digest <DIGEST>] [--disable [MESSAGE]] [--enable]
101
104
  [--fingerprint] [-h|--help] [-l|--logdest syslog|eventlog|<ABS FILEPATH>|console]
102
- [--masterport <PORT>] [--noop] [-o|--onetime] [-t|--test]
105
+ [--masterport <PORT>] [--noop] [-o|--onetime] [--sourceaddress <IP_ADDRESS>] [-t|--test]
103
106
  [-v|--verbose] [-V|--version] [-w|--waitforcert <SECONDS>]
104
107
 
105
108
 
@@ -273,6 +276,10 @@ generated by running puppet agent with '--genconfig'.
273
276
  (This is a Puppet setting, and can go in puppet.conf. Note the special 'no-'
274
277
  prefix for boolean settings on the command line.)
275
278
 
279
+ * --sourceaddress:
280
+ Set the source IP address for transactions. This defaults to automatically selected.
281
+ (This is a Puppet setting, and can go in puppet.conf.)
282
+
276
283
  * --test:
277
284
  Enable the most common options used for testing. These are 'onetime',
278
285
  'verbose', 'no-daemonize', 'no-usecacheonfailure', 'detailed-exitcodes',
@@ -1,4 +1,5 @@
1
1
  require 'puppet/application/face_base'
2
2
 
3
3
  class Puppet::Application::Config < Puppet::Application::FaceBase
4
+ environment_mode :not_required
4
5
  end
@@ -155,8 +155,7 @@ you can specify '--server <servername>' as an argument.
155
155
  device run against only that device/certificate.
156
156
 
157
157
  * --user:
158
- The user to run as. '--user=root' is required, even when run as root,
159
- for runs that create device certificates or keys.
158
+ The user to run as.
160
159
 
161
160
  * --verbose:
162
161
  Turn on verbose reporting.
@@ -249,10 +249,18 @@ Copyright (c) 2011 Puppet Inc., LLC Licensed under the Apache 2.0 License
249
249
  require 'puppet/file_bucket/dipper'
250
250
  begin
251
251
  if options[:local] or options[:bucket]
252
- path = options[:bucket] || Puppet[:bucketdir]
252
+ path = options[:bucket] || Puppet[:clientbucketdir]
253
253
  @client = Puppet::FileBucket::Dipper.new(:Path => path)
254
254
  else
255
- @client = Puppet::FileBucket::Dipper.new(:Server => Puppet[:server])
255
+ if Puppet[:server_list] && !Puppet[:server_list].empty?
256
+ server = Puppet[:server_list].first
257
+ @client = Puppet::FileBucket::Dipper.new(
258
+ :Server => server[0],
259
+ :Port => server[1]
260
+ )
261
+ else
262
+ @client = Puppet::FileBucket::Dipper.new(:Server => Puppet[:server])
263
+ end
256
264
  end
257
265
  rescue => detail
258
266
  Puppet.log_exception(detail)
@@ -1,4 +1,5 @@
1
1
  require 'puppet/application/face_base'
2
2
 
3
3
  class Puppet::Application::Help < Puppet::Application::FaceBase
4
+ environment_mode :not_required
4
5
  end
@@ -14,9 +14,11 @@ module Puppet
14
14
  # before being set in a pushed Puppet Context.
15
15
  #
16
16
  # @param run_mode [Puppet::Util::RunMode] Puppet's current Run Mode.
17
+ # @param environment_mode [Symbol] optional, Puppet's
18
+ # current Environment Mode. Defaults to :local
17
19
  # @return [void]
18
20
  # @api private
19
- def self.push_application_context(run_mode)
21
+ def self.push_application_context(run_mode, environment_mode = :local)
20
22
  Puppet.push_context(Puppet.base_context(Puppet.settings), "Update for application settings (#{run_mode})")
21
23
  # This use of configured environment is correct, this is used to establish
22
24
  # the defaults for an application that does not override, or where an override
@@ -25,6 +27,9 @@ module Puppet
25
27
  configured_environment_name = Puppet[:environment]
26
28
  if run_mode.name == :agent
27
29
  configured_environment = Puppet::Node::Environment.remote(configured_environment_name)
30
+ elsif environment_mode == :not_required
31
+ configured_environment =
32
+ Puppet.lookup(:environments).get(configured_environment_name) || Puppet::Node::Environment.remote(configured_environment_name)
28
33
  else
29
34
  configured_environment = Puppet.lookup(:environments).get!(configured_environment_name)
30
35
  end
@@ -115,6 +115,9 @@ class Puppet::Configurer
115
115
  if options[:pluginsync]
116
116
  remote_environment_for_plugins = Puppet::Node::Environment.remote(@environment)
117
117
  download_plugins(remote_environment_for_plugins)
118
+
119
+ Puppet::GettextConfig.reset_text_domain('agent')
120
+ Puppet::ModuleTranslations.load_from_vardir(Puppet[:vardir])
118
121
  end
119
122
 
120
123
  facts_hash = {}
@@ -232,6 +235,9 @@ class Puppet::Configurer
232
235
  # If a cached catalog is explicitly requested, attempt to retrieve it. Skip the node request,
233
236
  # don't pluginsync and switch to the catalog's environment if we successfully retrieve it.
234
237
  if Puppet[:use_cached_catalog]
238
+ Puppet::GettextConfig.reset_text_domain('agent')
239
+ Puppet::ModuleTranslations.load_from_vardir(Puppet[:vardir])
240
+
235
241
  if catalog = prepare_and_retrieve_catalog_from_cache
236
242
  options[:catalog] = catalog
237
243
  @cached_catalog_status = 'explicitly_requested'
@@ -292,11 +298,10 @@ class Puppet::Configurer
292
298
  end
293
299
 
294
300
  current_environment = Puppet.lookup(:current_environment)
295
- local_node_environment =
296
301
  if current_environment.name == @environment.intern
297
- current_environment
302
+ local_node_environment = current_environment
298
303
  else
299
- Puppet::Node::Environment.create(@environment,
304
+ local_node_environment = Puppet::Node::Environment.create(@environment,
300
305
  current_environment.modulepath,
301
306
  current_environment.manifest,
302
307
  current_environment.config_version)
@@ -298,10 +298,25 @@ module Puppet
298
298
  },
299
299
  :environment => {
300
300
  :default => "production",
301
- :desc => "The environment Puppet is running in. For clients
302
- (e.g., `puppet agent`) this determines the environment itself, which
303
- is used to find modules and much more. For servers (i.e., `puppet master`)
304
- this provides the default environment for nodes we know nothing about.",
301
+ :desc => "The environment in which Puppet is running. For clients,
302
+ such as `puppet agent`, this determines the environment itself, which
303
+ Puppet uses to find modules and much more. For servers, such as `puppet master`,
304
+ this provides the default environment for nodes that Puppet knows nothing about.
305
+
306
+ When defining an environment in the `[agent]` section, this refers to the
307
+ environment that the agent requests from the master. The environment doesn't
308
+ have to exist on the local filesystem because the agent fetches it from the
309
+ master. This definition is used when running `puppet agent`.
310
+
311
+ When defined in the `[user]` section, the environment refers to the path that
312
+ Puppet uses to search for code and modules related to its execution. This
313
+ requires the environment to exist locally on the filesystem where puppet is
314
+ being executed. Puppet subcommands, including `puppet module` and
315
+ `puppet apply`, use this definition.
316
+
317
+ Given that the context and effects vary depending on the
318
+ [config section](https://puppet.com/docs/puppet/latest/config_file_main.html#config-sections)
319
+ in which the `environment` setting is defined, do not set it globally.",
305
320
  :short => "E"
306
321
  },
307
322
  :environmentpath => {
@@ -902,19 +917,20 @@ EOT
902
917
  :digest_algorithm => {
903
918
  :default => 'md5',
904
919
  :type => :enum,
905
- :values => ["md5", "sha256"],
920
+ :values => ["md5", "sha256", "sha384", "sha512", "sha224"],
906
921
  :desc => 'Which digest algorithm to use for file resources and the filebucket.
907
- Valid values are md5, sha256. Default is md5.',
922
+ Valid values are md5, sha256, sha384, sha512, sha224. Default is md5.',
908
923
  },
909
924
  :supported_checksum_types => {
910
- :default => ['md5', 'sha256'],
925
+ :default => ['md5', 'sha256', 'sha384', 'sha512', 'sha224'],
911
926
  :type => :array,
912
927
  :desc => 'Checksum types supported by this agent for use in file resources of a
913
928
  static catalog. Values must be comma-separated. Valid types are md5,
914
- md5lite, sha256, sha256lite, sha1, sha1lite, mtime, ctime.',
929
+ md5lite, sha256, sha256lite, sha384, sha512,
930
+ sha1, sha1lite, sha224, mtime, ctime.',
915
931
  :hook => proc do |value|
916
932
  values = munge(value)
917
- valid = ['md5', 'md5lite', 'sha256', 'sha256lite', 'sha1', 'sha1lite', 'mtime', 'ctime']
933
+ valid = ['md5', 'md5lite', 'sha256', 'sha256lite', 'sha384', 'sha512', 'sha224', 'sha1', 'sha1lite', 'mtime', 'ctime']
918
934
  invalid = values.reject {|alg| valid.include?(alg)}
919
935
  if not invalid.empty?
920
936
  raise ArgumentError, "Unrecognized checksum types #{invalid} are not supported. Valid values are #{valid}."
@@ -1085,6 +1101,10 @@ EOT
1085
1101
  and monitoring systems to determine if a puppet process is still in
1086
1102
  the process table.",
1087
1103
  },
1104
+ :sourceaddress => {
1105
+ :default => nil,
1106
+ :desc => "The address the agent should use to initiate requests.",
1107
+ },
1088
1108
  :bindaddress => {
1089
1109
  :default => "*",
1090
1110
  :desc => "The address a listening server should bind to.",
@@ -382,6 +382,7 @@ module Puppet::Environments
382
382
  # (The intention is that this could be used from a MANUAL cache eviction command (TBD)
383
383
  def clear(name)
384
384
  @cache.delete(name)
385
+ Puppet::GettextConfig.delete_text_domain(name)
385
386
  end
386
387
 
387
388
  # Clears all cached environments.
@@ -391,6 +392,7 @@ module Puppet::Environments
391
392
  @cache = {}
392
393
  @expirations.clear
393
394
  @next_expiration = END_OF_TIME
395
+ Puppet::GettextConfig.delete_environment_text_domains
394
396
  end
395
397
 
396
398
  # Clears all environments that have expired, either by exceeding their time to live, or
@@ -75,7 +75,7 @@ Puppet::Face.define(:config, '0.0.1') do
75
75
  if args.length == 1
76
76
  puts values.interpolate(args[0].to_sym)
77
77
  else
78
- args.each do |setting_name|
78
+ args.sort.each do |setting_name|
79
79
  puts "#{setting_name} = #{values.interpolate(setting_name.to_sym)}"
80
80
  end
81
81
  end
@@ -106,6 +106,19 @@ Puppet::Face.define(:config, '0.0.1') do
106
106
  EOT
107
107
 
108
108
  when_invoked do |name, value, options|
109
+ if name == 'environment' && options[:section] == 'main'
110
+ Puppet.warning _(<<-EOM).chomp
111
+ The environment should be set in either the `[user]`, `[agent]`, or `[master]`
112
+ section. Variables set in the `[agent]` section are used when running
113
+ `puppet agent`. Variables set in the `[user]` section are used when running
114
+ various other puppet subcommands, like `puppet apply` and `puppet module`; these
115
+ require the defined environment directory to exist locally. Set the config
116
+ section by using the `--section` flag. For example,
117
+ `puppet config --section user set environment foo`. For more information, see
118
+ https://puppet.com/docs/puppet/latest/configuration.html#environment
119
+ EOM
120
+ end
121
+
109
122
  path = Puppet::FileSystem.pathname(Puppet.settings.which_configuration_file)
110
123
  Puppet::FileSystem.touch(path)
111
124
  Puppet::FileSystem.open(path, nil, 'r+:UTF-8') do |file|
@@ -150,7 +150,7 @@ Puppet::Face.define(:module, '1.0.0') do
150
150
  error_display_order = [:non_semantic_version, :version_mismatch, :missing]
151
151
  error_display_order.each do |type|
152
152
  unless @unmet_deps[type].empty?
153
- @unmet_deps[type].keys.sort_by {|dep| dep }.each do |dep|
153
+ @unmet_deps[type].keys.sort.each do |dep|
154
154
  name = dep.gsub('/', '-')
155
155
  errors = @unmet_deps[type][dep][:errors]
156
156
  version = @unmet_deps[type][dep][:version]
@@ -49,8 +49,10 @@ Puppet::Face.define(:module, '1.0.0') do
49
49
  terminal_width = [Puppet::Util::Terminal.width, min_width].max
50
50
 
51
51
  columns = results[:answers].inject(min_widths) do |hash, result|
52
+ deprecated_buffer = result['deprecated_at'].nil? ? 0 : 11 # ' DEPRECATED'.length
53
+
52
54
  {
53
- 'full_name' => [ hash['full_name'], result['full_name'].length ].max,
55
+ 'full_name' => [ hash['full_name'], result['full_name'].length + deprecated_buffer ].max,
54
56
  'desc' => [ hash['desc'], result['desc'].length ].max,
55
57
  'author' => [ hash['author'], "@#{result['author']}".length ].max,
56
58
  'tag_list' => [ hash['tag_list'], result['tag_list'].join(' ').length ].max,
@@ -86,6 +88,7 @@ Puppet::Face.define(:module, '1.0.0') do
86
88
  format % [ headers['full_name'], headers['desc'], headers['author'], headers['tag_list'] ] +
87
89
  results[:answers].map do |match|
88
90
  name, desc, author, keywords = %w{full_name desc author tag_list}.map { |k| match[k] }
91
+ name += " #{colorize(:red, 'DEPRECATED')}" unless match['deprecated_at'].nil?
89
92
  desc = desc[0...(columns['desc'] - 3)] + '...' if desc.length > columns['desc']
90
93
  highlight[format % [ name.sub('/', '-'), desc, "@#{author}", [keywords].flatten.join(' ') ]]
91
94
  end.join
@@ -166,6 +166,8 @@ class Puppet::Forge < SemanticPuppet::Dependency::Source
166
166
  def prepare
167
167
  return @unpacked_into if @unpacked_into
168
168
 
169
+ Puppet.warning "#{@metadata['name']} has been deprecated by its author! View module on Puppet Forge for more info." if deprecated?
170
+
169
171
  download(@data['file_uri'], tmpfile)
170
172
  validate_checksum(tmpfile, @data['file_md5'])
171
173
  unpack(tmpfile, tmpdir)
@@ -209,6 +211,10 @@ class Puppet::Forge < SemanticPuppet::Dependency::Source
209
211
  raise RuntimeError, _("Could not extract contents of module archive: %{message}") % { message: e.message }
210
212
  end
211
213
  end
214
+
215
+ def deprecated?
216
+ @data['module'] && (@data['module']['deprecated_at'] != nil)
217
+ end
212
218
  end
213
219
 
214
220
  private
@@ -0,0 +1,32 @@
1
+ # The `convert_to(value, type)` is a convenience function does the same as `new(type, value)`.
2
+ # The difference in the argument ordering allows it to be used in chained style for
3
+ # improved readability "left to right".
4
+ #
5
+ # When the function is given a lambda, it is called with the converted value, and the function
6
+ # returns what the lambda returns, otherwise the converted value.
7
+ #
8
+ # @example 'convert_to' instead of 'new'
9
+ #
10
+ # ~~~ puppet
11
+ # # using new operator - that is "calling the type" with operator ()
12
+ # Hash(Array("abc").map |$i,$v| { [$i, $v] })
13
+ #
14
+ # # using 'convert_to'
15
+ # "abc".convert_to(Array).map |$i,$v| { [$i, $v] }.convert_to(Hash)
16
+ #
17
+ # ~~~
18
+ #
19
+ # @since 5.4.0
20
+ #
21
+ Puppet::Functions.create_function(:convert_to) do
22
+ dispatch :convert_to do
23
+ param 'Any', :value
24
+ param 'Type', :type
25
+ optional_block_param 'Callable[1,1]', :block
26
+ end
27
+
28
+ def convert_to(value, type, &block)
29
+ result = call_function('new', type, value)
30
+ block_given? ? yield(result) : result
31
+ end
32
+ end
@@ -6,9 +6,10 @@ module Puppet::GettextConfig
6
6
  POSIX_PATH = File.absolute_path('../../../../../share/locale', File.dirname(__FILE__))
7
7
  WINDOWS_PATH = File.absolute_path('../../../../../../../puppet/share/locale', File.dirname(__FILE__))
8
8
 
9
+ DEFAULT_TEXT_DOMAIN = 'default-text-domain'
10
+
9
11
  # Load gettext helpers and track whether they're available.
10
12
  # Used instead of features because we initialize gettext before features is available.
11
- # Stubbing gettext if unavailable is handled in puppet.rb.
12
13
  begin
13
14
  require 'fast_gettext'
14
15
  require 'locale'
@@ -34,33 +35,123 @@ module Puppet::GettextConfig
34
35
  end
35
36
 
36
37
  # @api private
37
- # Whether translations have been loaded for a given project
38
- # @param project_name [String] the project whose translations we are querying
39
- # @return [Boolean] true if translations have been loaded for the project
40
- def self.translations_loaded?(project_name)
41
- return false unless gettext_loaded?
42
- if @loaded_repositories[project_name]
43
- return true
38
+ # Returns the currently selected locale from FastGettext,
39
+ # or 'en' of gettext has not been loaded
40
+ # @return [String] the active locale
41
+ def self.current_locale
42
+ if gettext_loaded?
43
+ return FastGettext.default_locale
44
44
  else
45
- return false
45
+ return 'en'
46
46
  end
47
47
  end
48
48
 
49
49
  # @api private
50
- # Creates a new empty text domain with the given name, replacing
51
- # any existing domain with that name, then switches to using
52
- # that domain. Also clears the cache of loaded translations.
53
- # @param domain_name [String] the name of the domain to create
54
- def self.create_text_domain(domain_name)
55
- return unless gettext_loaded?
56
- # Clear the cache of loaded translation repositories
57
- @loaded_repositories = {}
58
- FastGettext.add_text_domain(domain_name, type: :chain, chain: [])
59
- #TODO remove this when we start managing domains per environment
60
- FastGettext.default_text_domain = domain_name
50
+ # Returns a list of the names of the loaded text domains
51
+ # @return [[String]] the names of the loaded text domains
52
+ def self.loaded_text_domains
53
+ return [] if @gettext_disabled || !gettext_loaded?
54
+
55
+ return FastGettext.translation_repositories.keys
56
+ end
57
+
58
+ # @api private
59
+ # Clears the translation repository for the given text domain,
60
+ # creating it if it doesn't exist, then adds default translations
61
+ # and switches to using this domain.
62
+ # @param [String] domain_name the name of the domain to create
63
+ def self.reset_text_domain(domain_name)
64
+ return if @gettext_disabled || !gettext_loaded?
65
+
66
+ FastGettext.add_text_domain(domain_name,
67
+ type: :chain,
68
+ chain: [],
69
+ report_warning: false)
70
+ copy_default_translations(domain_name)
61
71
  FastGettext.text_domain = domain_name
62
72
  end
63
73
 
74
+ # @api private
75
+ # Creates a default text domain containing the translations for
76
+ # Puppet as the start of chain. When semantic_puppet gets initialized,
77
+ # its translations are added to this chain. This is used as a cache
78
+ # so that all non-module translations only need to be loaded once as
79
+ # we create and reset environment-specific text domains.
80
+ #
81
+ # @return true if Puppet translations were successfully loaded, false
82
+ # otherwise
83
+ def self.create_default_text_domain
84
+ return if @gettext_disabled || !gettext_loaded?
85
+
86
+ FastGettext.add_text_domain(DEFAULT_TEXT_DOMAIN,
87
+ type: :chain,
88
+ chain: [],
89
+ report_warning: false)
90
+ FastGettext.default_text_domain = DEFAULT_TEXT_DOMAIN
91
+
92
+ load_translations('puppet', puppet_locale_path, translation_mode(puppet_locale_path))
93
+ end
94
+
95
+ # @api private
96
+ # Switches the active text domain, if the requested domain exists.
97
+ # @param [String] domain_name the name of the domain to switch to
98
+ def self.use_text_domain(domain_name)
99
+ return if @gettext_disabled || !gettext_loaded?
100
+
101
+ if FastGettext.translation_repositories.include?(domain_name)
102
+ FastGettext.text_domain = domain_name
103
+ end
104
+ end
105
+
106
+ # @api private
107
+ # Delete all text domains.
108
+ def self.delete_all_text_domains
109
+ FastGettext.translation_repositories.clear
110
+ FastGettext.default_text_domain = nil
111
+ end
112
+
113
+ # @api private
114
+ # Deletes the text domain with the given name
115
+ # @param [String] domain_name the name of the domain to delete
116
+ def self.delete_text_domain(domain_name)
117
+ return if @gettext_disabled || !gettext_loaded?
118
+
119
+ FastGettext.translation_repositories.delete(domain_name)
120
+ end
121
+
122
+ # @api private
123
+ # Deletes all text domains except the default one
124
+ def self.delete_environment_text_domains
125
+ return if @gettext_disabled || !gettext_loaded?
126
+
127
+ FastGettext.translation_repositories.keys.each do |key|
128
+ # do not clear default translations
129
+ next if key == DEFAULT_TEXT_DOMAIN
130
+
131
+ FastGettext.translation_repositories.delete(key)
132
+ end
133
+ end
134
+
135
+ # @api private
136
+ # Adds translations from the default text domain to the specified
137
+ # text domain. Creates the default text domain if one does not exist
138
+ # (this will load Puppet's translations).
139
+ #
140
+ # Since we are currently (Nov 2017) vendoring semantic_puppet, in normal
141
+ # flows these translations will be copied along with Puppet's.
142
+ #
143
+ # @param [String] domain_name the name of the domain to add translations to
144
+ def self.copy_default_translations(domain_name)
145
+ return if @gettext_disabled || !gettext_loaded?
146
+
147
+ if FastGettext.default_text_domain.nil?
148
+ create_default_text_domain
149
+ end
150
+
151
+ puppet_translations = FastGettext.translation_repositories[FastGettext.default_text_domain].chain
152
+ FastGettext.translation_repositories[domain_name].chain.push(*puppet_translations)
153
+ end
154
+
64
155
  # @api private
65
156
  # Search for puppet gettext config files
66
157
  # @return [String] path to the config, or nil if not found
@@ -78,7 +169,7 @@ module Puppet::GettextConfig
78
169
 
79
170
  # @api private
80
171
  # Determine which translation file format to use
81
- # @param conf_path [String] the path to the gettext config file
172
+ # @param [String] conf_path the path to the gettext config file
82
173
  # @return [Symbol] :mo if in a package structure, :po otherwise
83
174
  def self.translation_mode(conf_path)
84
175
  if WINDOWS_PATH == conf_path || POSIX_PATH == conf_path
@@ -96,11 +187,15 @@ module Puppet::GettextConfig
96
187
 
97
188
  # @api private
98
189
  # Attempt to load tranlstions for the given project.
99
- # @param project_name [String] the project whose translations we want to load
100
- # @param locale_dir [String] the path to the directory containing translations
101
- # @param file_format [Symbol] translation file format to use, either :po or :mo
190
+ # @param [String] project_name the project whose translations we want to load
191
+ # @param [String] locale_dir the path to the directory containing translations
192
+ # @param [Symbol] file_format translation file format to use, either :po or :mo
102
193
  # @return true if initialization succeeded, false otherwise
103
194
  def self.load_translations(project_name, locale_dir, file_format)
195
+ if project_name.nil? || project_name.empty?
196
+ raise Puppet::Error, "A project name must be specified in order to initialize translations."
197
+ end
198
+
104
199
  return false if @gettext_disabled || !@gettext_loaded
105
200
 
106
201
  return false unless locale_dir && Puppet::FileSystem.exist?(locale_dir)
@@ -109,10 +204,6 @@ module Puppet::GettextConfig
109
204
  raise Puppet::Error, "Unsupported translation file format #{file_format}; please use :po or :mo"
110
205
  end
111
206
 
112
- if project_name.nil? || project_name.empty?
113
- raise Puppet::Error, "A project name must be specified in order to initialize translations."
114
- end
115
-
116
207
  add_repository_to_domain(project_name, locale_dir, file_format)
117
208
  return true
118
209
  end
@@ -120,27 +211,34 @@ module Puppet::GettextConfig
120
211
  # @api private
121
212
  # Add the translations for this project to the domain's repository chain
122
213
  # chain for the currently selected text domain, if needed.
123
- # @param project_name [String] the name of the project for which to load translations
124
- # @param locale_dir [String] the path to the directory containing translations
125
- # @param file_format [Symbol] the fomat of the translations files, :po or :mo
214
+ # @param [String] project_name the name of the project for which to load translations
215
+ # @param [String] locale_dir the path to the directory containing translations
216
+ # @param [Symbol] file_format the fomat of the translations files, :po or :mo
126
217
  def self.add_repository_to_domain(project_name, locale_dir, file_format)
127
- # check if we've already loaded these transltaions
218
+ return if @gettext_disabled || !gettext_loaded?
219
+
128
220
  current_chain = FastGettext.translation_repositories[FastGettext.text_domain].chain
129
- return current_chain if @loaded_repositories[project_name]
130
221
 
131
222
  repository = FastGettext::TranslationRepository.build(project_name,
132
223
  path: locale_dir,
133
224
  type: file_format,
134
- ignore_fuzzy: false)
135
- @loaded_repositories[project_name] = true
225
+ report_warning: false)
136
226
  current_chain << repository
137
227
  end
138
228
 
229
+ # @api private
230
+ # Sets FastGettext's locale to the current system locale
231
+ def self.setup_locale
232
+ return if @gettext_disabled || !gettext_loaded?
233
+
234
+ set_locale(Locale.current.language)
235
+ end
236
+
139
237
  # @api private
140
238
  # Sets the language in which to display strings.
141
- # @param locale [String] the language portion of a locale string (e.g. "ja")
239
+ # @param [String] locale the language portion of a locale string (e.g. "ja")
142
240
  def self.set_locale(locale)
143
- return if !gettext_loaded?
241
+ return if @gettext_disabled || !gettext_loaded?
144
242
  # make sure we're not using the `available_locales` machinery
145
243
  FastGettext.default_available_locales = nil
146
244