Class: Chef::Provider::Package::Rubygems::AlternateGemEnvironment

Inherits:
GemEnvironment
  • Object
show all
Includes:
Mixin::ShellOut
Defined in:
lib/chef/provider/package/rubygems.rb

Constant Summary collapse

JRUBY_PLATFORM =
/(:?universal|x86_64|x86)\-java\-[0-9\.]+/

Constants inherited from GemEnvironment

GemEnvironment::DEFAULT_UNINSTALLER_OPTS

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from GemEnvironment

#candidate_version_from_file, #dependency_installer, #find_newest_remote_version, #install, #installed_versions, #spec_from_file, #uninstall, #uninstaller, #with_correct_verbosity, #with_gem_sources

Constructor Details

#initialize(gem_binary_location) ⇒ AlternateGemEnvironment

Returns a new instance of AlternateGemEnvironment.



313
314
315
# File 'lib/chef/provider/package/rubygems.rb', line 313

def initialize(gem_binary_location)
  @gem_binary_location = gem_binary_location
end

Instance Attribute Details

#gem_binary_locationObject (readonly)

Returns the value of attribute gem_binary_location.



311
312
313
# File 'lib/chef/provider/package/rubygems.rb', line 311

def gem_binary_location
  @gem_binary_location
end

Class Method Details

.gempath_cacheObject



301
302
303
# File 'lib/chef/provider/package/rubygems.rb', line 301

def self.gempath_cache
  @gempath_cache ||= {}
end

.platform_cacheObject



305
306
307
# File 'lib/chef/provider/package/rubygems.rb', line 305

def self.platform_cache
  @platform_cache ||= {}
end

Instance Method Details

#candidate_version_from_remote(gem_dependency, *sources) ⇒ Object



389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
# File 'lib/chef/provider/package/rubygems.rb', line 389

def candidate_version_from_remote(gem_dependency, *sources)
  source_args = sources.compact.map { |s| "--source=#{s}" }.join(" ")
  cmd = "#{@gem_binary_location} list #{gem_dependency.name} --remote --all #{source_args}"
  result = shell_out!(cmd)

  target_platforms = nil

  versions = []
  result.stdout.each_line do |line|
    next unless line.start_with?("#{gem_dependency.name} (")

    version_string = line[/\((.*)\)/, 1]
    next unless version_string

    version_string.split(/,\s*/).each do |v|
      # `gem list --remote --all` emits entries like "1.6.0 x86_64-linux".
      # Accept platform-specific tokens only when the platform is compatible
      # with the target gem environment; pure-Ruby tokens have no suffix and
      # are always accepted.
      version_token, *platform_tokens = v.strip.split(/\s+/)

      if platform_tokens.any?
        target_platforms ||= gem_platforms
        # Each comma-separated entry from `gem list --remote --all` can list
        # multiple platforms for one version: "1.5.9 ruby x86_64-linux aarch64-linux ...".
        # Accept if any listed platform is "ruby" (pure-Ruby) or matches the target env.
        compatible = platform_tokens.any? do |pt|
          pt == "ruby" || target_platforms.any? do |p|
            Gem::Platform.new(p) === Gem::Platform.new(pt)
          rescue ArgumentError
            false
          end
        end
        next unless compatible
      end

      version = Gem::Version.new(version_token)
      versions << version if gem_dependency.requirement.satisfied_by?(version)
    rescue ArgumentError
      # Skip tokens with invalid version strings.
    end
  end

  versions.max
rescue Mixlib::ShellOut::ShellCommandFailed
  with_gem_sources(*sources) do
    with_gem_platforms(*gem_platforms) do
      find_newest_remote_version(gem_dependency, *sources)
    end
  end
end

#gem_pathsObject



321
322
323
324
325
326
327
328
329
330
331
# File 'lib/chef/provider/package/rubygems.rb', line 321

def gem_paths
  if self.class.gempath_cache.key?(@gem_binary_location)
    self.class.gempath_cache[@gem_binary_location]
  else
    # shellout! is a fork/exec which won't work on windows
    shell_style_paths = shell_out!("#{@gem_binary_location} env gempath").stdout
    # on windows, the path separator is (usually? always?) semicolon
    paths = shell_style_paths.split(::File::PATH_SEPARATOR).map(&:strip)
    self.class.gempath_cache[@gem_binary_location] = paths
  end
end

#gem_platformsObject

Attempt to detect the correct platform settings for the target gem environment.

In practice, this only makes a difference if different versions are available depending on platform, and only if the target gem environment has a radically different platform (i.e., jruby), so we just try to detect jruby and fall back to the current platforms (Gem.platforms) if we don't detect it.

Returns

[String|Gem::Platform] returns an array of Gem::Platform-compatible objects, i.e., Strings that are valid for Gem::Platform or actual Gem::Platform objects.



367
368
369
370
371
372
373
374
375
376
377
378
# File 'lib/chef/provider/package/rubygems.rb', line 367

def gem_platforms
  if self.class.platform_cache.key?(@gem_binary_location)
    self.class.platform_cache[@gem_binary_location]
  else
    gem_environment = shell_out!("#{@gem_binary_location} env").stdout
    self.class.platform_cache[@gem_binary_location] = if jruby = gem_environment[JRUBY_PLATFORM]
                                                        ["ruby", Gem::Platform.new(jruby)]
                                                      else
                                                        Gem.platforms
                                                      end
  end
end

#gem_source_indexObject



333
334
335
# File 'lib/chef/provider/package/rubygems.rb', line 333

def gem_source_index
  @source_index ||= Gem::SourceIndex.from_gems_in(*gem_paths.map { |p| p + "/specifications" })
end

#gem_specificationObject



337
338
339
340
341
342
343
344
# File 'lib/chef/provider/package/rubygems.rb', line 337

def gem_specification
  # Only once, dirs calls a reset
  unless @specification
    Gem::Specification.dirs = gem_paths
    @specification = Gem::Specification
  end
  @specification
end

#gem_specification_recordObject



346
347
348
349
350
351
# File 'lib/chef/provider/package/rubygems.rb', line 346

def gem_specification_record
  unless @specification_record
    @specification_record = Gem::SpecificationRecord.new(gem_specification.dirs)
  end
  @specification_record
end

#rubygems_versionObject



317
318
319
# File 'lib/chef/provider/package/rubygems.rb', line 317

def rubygems_version
  @rubygems_version ||= shell_out!("#{@gem_binary_location} --version").stdout.chomp
end

#with_gem_platforms(*alt_gem_platforms) ⇒ Object



380
381
382
383
384
385
386
387
# File 'lib/chef/provider/package/rubygems.rb', line 380

def with_gem_platforms(*alt_gem_platforms)
  alt_gem_platforms.flatten!
  original_gem_platforms = Gem.platforms
  Gem.platforms = alt_gem_platforms
  yield
ensure
  Gem.platforms = original_gem_platforms
end