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
@@ -0,0 +1,42 @@
1
+ require 'puppet/gettext/config'
2
+
3
+ module Puppet::ModuleTranslations
4
+
5
+ # @api private
6
+ # Loads translation files for each of the specified modules,
7
+ # if present. Requires the modules to have `forge_name` specified.
8
+ # @param [[Module]] modules a list of modules for which to
9
+ # load translations
10
+ def self.load_from_modulepath(modules)
11
+ modules.each do |mod|
12
+ next unless mod.forge_name && mod.has_translations?(Puppet::GettextConfig.current_locale)
13
+
14
+ module_name = mod.forge_name.gsub('/', '-')
15
+ if Puppet::GettextConfig.load_translations(module_name, mod.locale_directory, :po)
16
+ Puppet.debug "Loaded translations for #{module_name}."
17
+ elsif Puppet::GettextConfig.gettext_loaded?
18
+ Puppet.debug "Could not find translation files for #{module_name} at #{mod.locale_directory}. Skipping translation initialization."
19
+ else
20
+ Puppet.warn_once("gettext_unavailable", "gettext_unavailable", "No gettext library found, skipping translation initialization.")
21
+ end
22
+ end
23
+ end
24
+
25
+ # @api private
26
+ # Loads translation files that have been pluginsync'd for modules
27
+ # from the $vardir.
28
+ # @param [String] vardir the path to Puppet's vardir
29
+ def self.load_from_vardir(vardir)
30
+ locale = Puppet::GettextConfig.current_locale
31
+ Dir.glob("#{vardir}/locales/#{locale}/*.po") do |f|
32
+ module_name = File.basename(f, ".po")
33
+ if Puppet::GettextConfig.load_translations(module_name, File.join(vardir, "locales"), :po)
34
+ Puppet.debug "Loaded translations for #{module_name}."
35
+ elsif Puppet::GettextConfig.gettext_loaded?
36
+ Puppet.debug "Could not load translations for #{module_name}."
37
+ else
38
+ Puppet.warn_once("gettext_unavailable", "gettext_unavailable", "No gettext library found, skipping translation initialization.")
39
+ end
40
+ end
41
+ end
42
+ end
@@ -49,6 +49,8 @@ class Puppet::Resource::Catalog::Compiler < Puppet::Indirector::Code
49
49
  node = node_from_request(facts, request)
50
50
  node.trusted_data = Puppet.lookup(:trusted_information) { Puppet::Context::TrustedInformation.local(node) }.to_h
51
51
 
52
+ node.environment.use_text_domain if node.environment
53
+
52
54
  if catalog = compile(node, request.options)
53
55
  return catalog
54
56
  else
@@ -97,9 +97,6 @@ class Puppet::Module
97
97
  load_metadata
98
98
 
99
99
  @absolute_path_to_manifests = Puppet::FileSystem::PathPattern.absolute(manifests)
100
-
101
- # i18n initialization for modules
102
- initialize_i18n unless Puppet[:disable_i18n]
103
100
  end
104
101
 
105
102
  # @deprecated The puppetversion module metadata field is no longer used.
@@ -308,6 +305,16 @@ class Puppet::Module
308
305
  subpath("locales")
309
306
  end
310
307
 
308
+ # Returns true if the module has translation files for the
309
+ # given locale.
310
+ # @param [String] locale the two-letter language code to check
311
+ # for translations
312
+ # @return true if the module has a directory for the locale, false
313
+ # false otherwise
314
+ def has_translations?(locale)
315
+ return Puppet::FileSystem.exist?(File.join(locale_directory, locale))
316
+ end
317
+
311
318
  def has_external_facts?
312
319
  File.directory?(plugin_fact_directory)
313
320
  end
@@ -428,21 +435,6 @@ class Puppet::Module
428
435
  @strict_semver
429
436
  end
430
437
 
431
- def initialize_i18n
432
- # this name takes the form "namespace-module", and should match the name of
433
- # the PO file containing the translations.
434
- module_name = @forge_name ? @forge_name.gsub("/", "-") : name
435
- return if Puppet::GettextConfig.translations_loaded?(module_name)
436
-
437
- if Puppet::GettextConfig.load_translations(module_name, locale_directory, :po)
438
- Puppet.debug "i18n initialized for #{module_name}"
439
- elsif Puppet::GettextConfig.gettext_loaded?
440
- Puppet.debug "Could not find translation files for #{module_name} at #{locale_directory}. Skipping i18n initialization."
441
- else
442
- Puppet.debug "No gettext library found, skipping i18n initialization."
443
- end
444
- end
445
-
446
438
  private
447
439
 
448
440
  def wanted_manifests_from(pattern)
@@ -38,6 +38,15 @@ class Puppet::Network::HTTP::Factory
38
38
  http.read_timeout = Puppet[:http_read_timeout]
39
39
  http.open_timeout = Puppet[:http_connect_timeout]
40
40
 
41
+ if Puppet[:sourceaddress]
42
+ if http.respond_to?(:local_host)
43
+ Puppet.debug("Using source IP #{Puppet[:sourceaddress]}")
44
+ http.local_host = Puppet[:sourceaddress]
45
+ else
46
+ raise ArgumentError, "Setting 'sourceaddress' is unsupported by this version of Net::HTTP."
47
+ end
48
+ end
49
+
41
50
  if Puppet[:http_debug]
42
51
  http.set_debug_output($stderr)
43
52
  end
@@ -433,6 +433,20 @@ class Puppet::Node::Environment
433
433
  deps
434
434
  end
435
435
 
436
+ # Loads module translations for the current environment once for
437
+ # the lifetime of the environment.
438
+ def use_text_domain
439
+ return if Puppet[:disable_i18n]
440
+
441
+ if @text_domain.nil?
442
+ @text_domain = @name
443
+ Puppet::GettextConfig.reset_text_domain(@text_domain)
444
+ Puppet::ModuleTranslations.load_from_modulepath(modules)
445
+ else
446
+ Puppet::GettextConfig.use_text_domain(@text_domain)
447
+ end
448
+ end
449
+
436
450
  # Checks if a reparse is required (cache of files is stale).
437
451
  #
438
452
  def check_for_reparse
@@ -29,8 +29,22 @@ Puppet::Parser::Functions::newfunction(
29
29
  :arity => -2,
30
30
  :doc => "Perform printf-style formatting of text.
31
31
 
32
- The first parameter is format string describing how the rest of the parameters should be formatted. See the documentation for the `Kernel::sprintf` function in Ruby for all the details."
32
+ The first parameter is format string describing how the rest of the parameters should be formatted.
33
+ See the documentation for the `Kernel::sprintf` function in Ruby for all the details."
33
34
  ) do |args|
34
- fmt = args.shift
35
- return sprintf(fmt, *args)
35
+ fmt = args[0]
36
+ args = args[1..-1]
37
+ begin
38
+ return sprintf(fmt, *args)
39
+ rescue KeyError => e
40
+ if args.size == 1 && args[0].is_a?(Hash)
41
+ # map the single hash argument such that all top level string keys are symbols
42
+ # as that allows named arguments to be used in the format string.
43
+ #
44
+ result = {}
45
+ args[0].each_pair { |k,v| result[k.is_a?(String) ? k.to_sym : k] = v }
46
+ return sprintf(fmt, result)
47
+ end
48
+ raise e
49
+ end
36
50
  end
@@ -611,6 +611,7 @@ class Puppet::Parser::Scope
611
611
  begin
612
612
  qs = qualified_scope(class_name)
613
613
  unless qs.nil?
614
+ return qs.get_local_variable(leaf_name) if qs.has_local_variable?(leaf_name)
614
615
  iscope = qs.inherited_scope
615
616
  return lookup_qualified_variable("#{iscope.source.name}::#{leaf_name}", options) unless iscope.nil?
616
617
  end
@@ -623,6 +624,16 @@ class Puppet::Parser::Scope
623
624
  return handle_not_found('', fqn, options)
624
625
  end
625
626
 
627
+ # @api private
628
+ def has_local_variable?(name)
629
+ @ephemeral.last.include?(name)
630
+ end
631
+
632
+ # @api private
633
+ def get_local_variable(name)
634
+ @ephemeral.last[name]
635
+ end
636
+
626
637
  def handle_not_found(class_name, variable_name, position, reason = nil)
627
638
  unless Puppet[:strict_variables]
628
639
  # Do not issue warning if strict variables are on, as an error will be raised by variable_not_found
@@ -113,7 +113,6 @@ module Puppet
113
113
  end
114
114
 
115
115
  require 'puppet/parser/ast/pops_bridge'
116
- require 'puppet/bindings'
117
116
  require 'puppet/functions'
118
117
 
119
118
  Puppet::Pops::Model.register_pcore_types
@@ -71,6 +71,19 @@ class Puppet::Pops::Evaluator::EppEvaluator
71
71
  enforce_parameters = true
72
72
  end
73
73
 
74
+ # filter out all qualified names and set them in qualified_variables
75
+ # only pass unqualified (filtered) variable names to the the template
76
+ filtered_args = {}
77
+ template_args.each_pair do |k, v|
78
+ if k =~ /::/
79
+ k = k[2..-1] if k.start_with?('::')
80
+ scope[k] = v
81
+ else
82
+ filtered_args[k] = v
83
+ end
84
+ end
85
+ template_args = filtered_args
86
+
74
87
  # inline_epp() logic sees all local variables, epp() all global
75
88
  if use_global_scope_only
76
89
  scope.with_global_scope do |global_scope|
@@ -28,9 +28,10 @@ module LoaderPaths
28
28
  # When wanted also add FunctionPath3x to load 3x functions
29
29
  when :plan
30
30
  result << PlanPathPP.new(loader)
31
+ when :task
32
+ result << TaskPath.new(loader) if Puppet[:tasks] && loader.loadables.include?(:task)
31
33
  when :type
32
34
  result << TypePathPP.new(loader) if loader.loadables.include?(:type_pp)
33
- result << TaskPath.new(loader) if Puppet[:tasks] && loader.loadables.include?(:task)
34
35
  when :resource_type_pp
35
36
  result << ResourceTypeImplPP.new(loader) if loader.loadables.include?(:resource_type_pp)
36
37
  else
@@ -73,6 +74,10 @@ module LoaderPaths
73
74
  @loader.path
74
75
  end
75
76
 
77
+ def lib_root?
78
+ @loader.lib_root?
79
+ end
80
+
76
81
  # Effective path is the generic path + the name part(s) + extension.
77
82
  #
78
83
  def effective_path(typed_name, start_index_in_name)
@@ -93,6 +98,10 @@ module LoaderPaths
93
98
  TypedName.new(type, n, name_authority)
94
99
  end
95
100
 
101
+ def valid_path?(path)
102
+ path.end_with?(extension) && path.start_with?(generic_path)
103
+ end
104
+
96
105
  def valid_name?(typed_name)
97
106
  true
98
107
  end
@@ -157,10 +166,11 @@ module LoaderPaths
157
166
  end
158
167
 
159
168
  class FunctionPath4x < RubySmartPath
160
- FUNCTION_PATH_4X = File.join('lib', 'puppet', 'functions').freeze
169
+ SYSTEM_FUNCTION_PATH_4X = File.join('puppet', 'functions').freeze
170
+ FUNCTION_PATH_4X = File.join('lib', SYSTEM_FUNCTION_PATH_4X).freeze
161
171
 
162
172
  def relative_path
163
- FUNCTION_PATH_4X
173
+ lib_root? ? SYSTEM_FUNCTION_PATH_4X : FUNCTION_PATH_4X
164
174
  end
165
175
 
166
176
  def instantiator
@@ -169,10 +179,11 @@ module LoaderPaths
169
179
  end
170
180
 
171
181
  class FunctionPath3x < RubySmartPath
172
- FUNCTION_PATH_3X = File.join('lib', 'puppet', 'parser', 'functions').freeze
182
+ SYSTEM_FUNCTION_PATH_3X = File.join('puppet', 'parser', 'functions').freeze
183
+ FUNCTION_PATH_3X = File.join('lib', SYSTEM_FUNCTION_PATH_3X).freeze
173
184
 
174
185
  def relative_path
175
- FUNCTION_PATH_3X
186
+ lib_root? ? SYSTEM_FUNCTION_PATH_3X : FUNCTION_PATH_3X
176
187
  end
177
188
 
178
189
  def instantiator
@@ -208,6 +219,7 @@ module LoaderPaths
208
219
  # match more than one path with one name
209
220
  class TaskPath < PuppetSmartPath
210
221
  TASKS_PATH = 'tasks'.freeze
222
+ FORBIDDEN_EXTENSIONS = %w{.conf .md}.freeze
211
223
 
212
224
  def extension
213
225
  EMPTY_STRING
@@ -221,6 +233,20 @@ module LoaderPaths
221
233
  TASKS_PATH
222
234
  end
223
235
 
236
+ def typed_name(type, name_authority, relative_path, module_name)
237
+ n = ''
238
+ n << module_name unless module_name.nil?
239
+
240
+ # Remove extension regardless of what it is. A task name cannot contain dots
241
+ relative_path = relative_path.sub(/\.[^\/]*\z/, '')
242
+
243
+ relative_path.split('/').each do |segment|
244
+ n << '::' if n.size > 0
245
+ n << segment
246
+ end
247
+ TypedName.new(type, n, name_authority)
248
+ end
249
+
224
250
  def instantiator
225
251
  require_relative 'task_instantiator'
226
252
  TaskInstantiator
@@ -230,6 +256,14 @@ module LoaderPaths
230
256
  # TODO: Remove when PE has proper namespace handling
231
257
  typed_name.name_parts.size <= 2
232
258
  end
259
+
260
+ def valid_path?(path)
261
+ path.start_with?(generic_path) && is_task_name?(File.basename(path, '.*')) && !FORBIDDEN_EXTENSIONS.any? { |ext| path.end_with?(ext) }
262
+ end
263
+
264
+ def is_task_name?(name)
265
+ !!(name =~ /^[a-z][a-z0-9_]*$/)
266
+ end
233
267
  end
234
268
 
235
269
  class ResourceTypeImplPP < PuppetSmartPath
@@ -27,8 +27,8 @@ module ModuleLoaders
27
27
  # to search up the path from this source file's __FILE__ location until it finds the base of
28
28
  # puppet.
29
29
  #
30
- puppet_lib = File.join(File.dirname(__FILE__), '../../../..')
31
- ModuleLoaders::FileBased.new(parent_loader,
30
+ puppet_lib = File.realpath(File.join(File.dirname(__FILE__), '../../..'))
31
+ LibRootedFileBased.new(parent_loader,
32
32
  loaders,
33
33
  nil,
34
34
  puppet_lib, # may or may not have a 'lib' above 'puppet'
@@ -38,12 +38,16 @@ module ModuleLoaders
38
38
  end
39
39
 
40
40
  def self.environment_loader_from(parent_loader, loaders, env_path)
41
- ModuleLoaders::FileBased.new(parent_loader,
42
- loaders,
43
- ENVIRONMENT,
44
- env_path,
45
- ENVIRONMENT
46
- )
41
+ if env_path.nil? || env_path.empty?
42
+ EmptyLoader.new(parent_loader, ENVIRONMENT)
43
+ else
44
+ FileBased.new(parent_loader,
45
+ loaders,
46
+ ENVIRONMENT,
47
+ env_path,
48
+ ENVIRONMENT
49
+ )
50
+ end
47
51
  end
48
52
 
49
53
  def self.module_loader_from(parent_loader, loaders, module_name, module_path)
@@ -64,6 +68,20 @@ module ModuleLoaders
64
68
  )
65
69
  end
66
70
 
71
+ class EmptyLoader < BaseLoader
72
+ def find(typed_name)
73
+ return nil
74
+ end
75
+
76
+ def private_loader
77
+ @private_loader ||= self
78
+ end
79
+
80
+ def private_loader=(loader)
81
+ @private_loader = loader
82
+ end
83
+ end
84
+
67
85
  class AbstractPathBasedModuleLoader < BaseLoader
68
86
 
69
87
  # The name of the module, or nil, if this is a global "component"
@@ -92,6 +110,8 @@ module ModuleLoaders
92
110
  def initialize(parent_loader, loaders, module_name, path, loader_name, loadables)
93
111
  super parent_loader, loader_name
94
112
 
113
+ raise ArgumentError, 'path based loader cannot be instantiated without a path' if path.nil? || path.empty?
114
+
95
115
  @module_name = module_name
96
116
  @path = path
97
117
  @smart_paths = LoaderPaths::SmartPaths.new(self)
@@ -158,6 +178,16 @@ module ModuleLoaders
158
178
  return smart_path.nil? ? nil : instantiate(smart_path, typed_name, origin)
159
179
  end
160
180
 
181
+ when :task
182
+ if !global?
183
+ # Global name must be the name of the module
184
+ return nil unless name_parts[0] == module_name
185
+
186
+ # Look for the special 'init' Task
187
+ origin, smart_path = find_existing_path(init_task_name)
188
+ return smart_path.nil? ? nil : instantiate(smart_path, typed_name, origin)
189
+ end
190
+
161
191
  when :type
162
192
  if !global?
163
193
  # Global name must be the name of the module
@@ -165,16 +195,7 @@ module ModuleLoaders
165
195
 
166
196
  # Look for the special 'init_typeset' TypeSet
167
197
  origin, smart_path = find_existing_path(init_typeset_name)
168
-
169
- # The init_typeset has no special meaning unless found under the 'types' folder
170
- unless smart_path.is_a?(LoaderPaths::TypePathPP)
171
-
172
- # Look for the special 'init' Task
173
- origin, smart_path = find_existing_path(init_type_name)
174
-
175
- # The init has no special meaning unless found under the 'tasks' folder
176
- return smart_path.is_a?(LoaderPaths::TaskPath) ? instantiate(smart_path, typed_name, origin) : nil
177
- end
198
+ return nil if smart_path.nil?
178
199
 
179
200
  value = smart_path.instantiator.create(self, typed_name, origin, get_contents(origin))
180
201
  if value.is_a?(Types::PTypeSetType)
@@ -290,6 +311,16 @@ module ModuleLoaders
290
311
  module_name.nil? || module_name == ENVIRONMENT
291
312
  end
292
313
 
314
+ # Answers `true` if the loader used by this instance is rooted beneath 'lib'. This is
315
+ # typically true for the the system_loader. It will have a path relative to the parent
316
+ # of 'puppet' instead of the parent of 'lib/puppet' since the 'lib' directory of puppet
317
+ # is renamed during install. This is significant for loaders that load ruby code.
318
+ #
319
+ # @return [Boolean] a boolean answering if the loader is rooted beneath 'lib'.
320
+ def lib_root?
321
+ false
322
+ end
323
+
293
324
  # Produces the private loader for the module. If this module is not already resolved, this will trigger resolution
294
325
  #
295
326
  def private_loader
@@ -316,8 +347,8 @@ module ModuleLoaders
316
347
 
317
348
  # @return [TypedName] the fake typed name that maps to the path of an init[arbitrary extension]
318
349
  # file that represents a task named after the module
319
- def init_type_name
320
- @init_type_name ||= TypedName.new(:type, "#{module_name}::init")
350
+ def init_task_name
351
+ @init_task_name ||= TypedName.new(:task, "#{module_name}::init")
321
352
  end
322
353
 
323
354
  # @return [TypedName] the fake typed name that maps to the path of an init.pp file that represents
@@ -413,17 +444,26 @@ module ModuleLoaders
413
444
  # @return [Array<String>] found paths
414
445
  def relative_paths(smart_path)
415
446
  root = smart_path.generic_path
416
- ext = smart_path.extension
417
- ext = nil if ext.empty?
418
447
  found = []
419
448
  @path_index.each do |path|
420
- next unless (ext.nil? || path.end_with?(ext)) && path.start_with?(root)
421
- found << Pathname(path).relative_path_from(Pathname(root)).to_s
449
+ found << Pathname(path).relative_path_from(Pathname(root)).to_s if smart_path.valid_path?(path)
422
450
  end
423
451
  found
424
452
  end
425
453
  end
426
454
 
455
+ # Specialization used by the system_loader which is limited to see what's beneath 'lib' and hence
456
+ # cannot be rooted in its parent. The 'lib' directory is renamed during install so any attempt
457
+ # to traverse into it from above would fail.
458
+ #
459
+ # @api private
460
+ #
461
+ class LibRootedFileBased < FileBased
462
+ def lib_root?
463
+ true
464
+ end
465
+ end
466
+
427
467
  # Loads from a gem specified as a URI, gem://gemname/optional/path/in/gem, or just a String gemname.
428
468
  # The source reference (shown in errors etc.) is the expanded path of the gem as this is believed to be more
429
469
  # helpful - given the location it should be quite obvious which gem it is, without the location, the user would