Class: TargetBundle

Inherits:
Object
  • Object
show all
Defined in:
lib/bundler/patch/target_bundle.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dir: Dir.pwd, gemfile: TargetBundle.default_gemfile) ⇒ TargetBundle

Returns a new instance of TargetBundle.



17
18
19
20
# File 'lib/bundler/patch/target_bundle.rb', line 17

def initialize(dir: Dir.pwd, gemfile: TargetBundle.default_gemfile)
  @dir = dir
  @gemfile = gemfile
end

Instance Attribute Details

#dirObject (readonly)

Returns the value of attribute dir.



2
3
4
# File 'lib/bundler/patch/target_bundle.rb', line 2

def dir
  @dir
end

#gemfileObject (readonly)

Returns the value of attribute gemfile.



2
3
4
# File 'lib/bundler/patch/target_bundle.rb', line 2

def gemfile
  @gemfile
end

Class Method Details

.bundler_version_or_higher(version) ⇒ Object



4
5
6
# File 'lib/bundler/patch/target_bundle.rb', line 4

def self.bundler_version_or_higher(version)
  version_greater_than_or_equal_to_other(Bundler::VERSION, version)
end

.default_gemfileObject



12
13
14
15
# File 'lib/bundler/patch/target_bundle.rb', line 12

def self.default_gemfile
  # TODO: Make gems.rb default in Bundler 2.0.
  'Gemfile'
end

.version_greater_than_or_equal_to_other(a, b) ⇒ Object



8
9
10
# File 'lib/bundler/patch/target_bundle.rb', line 8

def self.version_greater_than_or_equal_to_other(a, b)
  Gem::Version.new(a) >= Gem::Version.new(b)
end

Instance Method Details

#build_ruby_bin(current_ruby_bin, target_ruby_version) ⇒ Object



62
63
64
65
66
67
68
69
70
# File 'lib/bundler/patch/target_bundle.rb', line 62

def build_ruby_bin(current_ruby_bin, target_ruby_version)
  current_ruby_bin.split(File::SEPARATOR).reverse.map do |segment|
    if segment =~ /\d+\.\d+\.\d+/
      segment.gsub(/(\d+\.\d+\.\d+)-*(p\d+)*/, target_ruby_version)
    else
      segment
    end
  end.reverse.join(File::SEPARATOR)
end

#gem_homeObject

Have to run a separate process in the other Ruby, because Gem.default_dir depends on RbConfig::CONFIG which is all special data derived from the active runtime. It could perhaps be redone here, but I’d rather not copy that code in here at the moment.

At one point during development, this would execute Bundler::Settings#path, which in most cases would just fall through to Gem.default_dir … but would give preference to GEM_HOME env variable, which could be in a different Ruby, and that won’t work.



89
90
91
92
93
94
95
# File 'lib/bundler/patch/target_bundle.rb', line 89

def gem_home
  result = shell_command "#{ruby_bin_exe} -C#{@dir} -e 'puts Gem.default_dir'"
  path = result[:stdout].chomp
  expanded_path = Pathname.new(path).expand_path(@dir).to_s
  puts expanded_path if ENV['BP_DEBUG']
  expanded_path
end

#install_bundler_patch_in_targetObject

To properly update another bundle, bundler-patch does need to live in the same Ruby version because of its dependencies (it’s not a self-contained gem), and it can’t both act on another bundle location AND find its own dependencies in a separate bundle location.

One known issue: older RubyGems in older Rubies don’t install bundler-patch bin in the right directory. Upgrading RubyGems fixes this.



103
104
105
106
107
108
# File 'lib/bundler/patch/target_bundle.rb', line 103

def install_bundler_patch_in_target
  # TODO: reconsider --conservative flag. Had problems with it in place on Travis, but I think I want it.
  # cmd = "#{ruby_bin}#{File::SEPARATOR}gem install -V --install-dir #{gem_home} --conservative --no-document --prerelease bundler-patch"
  cmd = "#{ruby_bin}#{File::SEPARATOR}gem install -V --install-dir #{gem_home} --no-document --prerelease bundler-patch"
  shell_command cmd
end

#ruby_bin(current_ruby_bin = RbConfig::CONFIG['bindir'], target_ruby_version = self.ruby_version) ⇒ Object

This is hairy here. All the possible variants will make this mucky, but … can prolly get close enough in many circumstances.



48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/bundler/patch/target_bundle.rb', line 48

def ruby_bin(current_ruby_bin=RbConfig::CONFIG['bindir'], target_ruby_version=self.ruby_version)
  [
    target_ruby_version,
    target_ruby_version.gsub(/-p\d+/, ''),
    "ruby-#{target_ruby_version}",
    "ruby-#{target_ruby_version.gsub(/-p\d+/, '')}"
  ].map do |ruby_ver|
    build_ruby_bin(current_ruby_bin, ruby_ver)
  end.detect do |ruby_ver|
    print "Looking for #{ruby_ver}... " if ENV['BP_DEBUG']
    File.exist?(ruby_ver).tap { |exist| puts(exist ? 'found' : 'not found') if ENV['BP_DEBUG'] }
  end
end

#ruby_bin_exeObject



72
73
74
75
76
# File 'lib/bundler/patch/target_bundle.rb', line 72

def ruby_bin_exe
  ruby_install_name = RbConfig::CONFIG['ruby_install_name']
  exe_ext = RbConfig::CONFIG['EXEEXT']
  File.join(ruby_bin, "#{ruby_install_name}#{exe_ext}")
end

#ruby_versionObject

First, the version of Ruby itself:

  1. Look in the Gemfile/lockfile for ruby version

  2. Look for a .ruby-version file

  3. (An additional flag so user can specify?)

Second, look bin path presuming version is in current path.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/bundler/patch/target_bundle.rb', line 28

def ruby_version
  result = if TargetBundle.bundler_version_or_higher('1.12.0') && File.exist?(lockfile_name)
             lockfile_parser = Bundler::LockfileParser.new(Bundler.read_file(lockfile_name))
             lockfile_parser.ruby_version
           end

  result ||= if File.exist?(ruby_version_filename)
               File.read(File.join(@dir, '.ruby-version')).chomp
             elsif File.exist?(gemfile_name)
               Bundler::Definition.build(gemfile_name, lockfile_name, nil).ruby_version
             end

  result ||= RbConfig::CONFIG['RUBY_PROGRAM_VERSION']

  version, patch_level = result.to_s.scan(/(\d+\.\d+\.\d+)(p\d+)*/).first
  patch_level ? "#{version}-#{patch_level}" : version
end

#target_ruby_is_different?Boolean

Returns:

  • (Boolean)


78
79
80
# File 'lib/bundler/patch/target_bundle.rb', line 78

def target_ruby_is_different?
  !(ruby_bin == RbConfig::CONFIG['bindir'])
end