lib/autoproj/package_managers/bundler_manager.rb in autoproj-2.11.0 vs lib/autoproj/package_managers/bundler_manager.rb in autoproj-2.12.0
- old
+ new
@@ -22,10 +22,18 @@
@with_prerelease = saved_flag
end
end
end
+ # Directory with cached .gem packages
+ #
+ # The directory must exist, but may be empty.
+ # It is initialized with {BundlerManager.cache_dir}
+ #
+ # @return [String]
+ attr_accessor :cache_dir
+
# (see Manager#call_while_empty?)
def call_while_empty?
!workspace_configuration_gemfiles.empty?
end
@@ -43,19 +51,36 @@
env.add_path 'PATH', File.join(ws.prefix_dir, 'gems', 'bin')
env.add_path 'PATH', File.join(ws.dot_autoproj_dir, 'bin')
env.set 'GEM_HOME', config.gems_gem_home
env.clear 'GEM_PATH'
+ if (bundler_version = config.bundler_version)
+ env.set 'BUNDLER_VERSION', bundler_version
+ else
+ env.clear 'BUNDLER_VERSION'
+ end
gemfile_path = File.join(ws.prefix_dir, 'gems', 'Gemfile')
env.set('BUNDLE_GEMFILE', gemfile_path) if File.file?(gemfile_path)
- Autobuild.programs['bundler'] = File.join(ws.dot_autoproj_dir,
- 'bin', 'bundle')
- Autobuild.programs['bundle'] = File.join(ws.dot_autoproj_dir,
- 'bin', 'bundle')
+ if cache_dir && File.exist?(cache_dir)
+ vendor_dir = File.join(File.dirname(gemfile_path), 'vendor')
+ FileUtils.mkdir_p vendor_dir
+ bundler_cache_dir = File.join(vendor_dir, 'cache')
+ if File.writable?(cache_dir)
+ create_cache_symlink(cache_dir, bundler_cache_dir)
+ else
+ Autoproj.warn "BundlerManager: #{cache_dir} is read-only "\
+ "copying the cache instead of symlinking it"
+ create_cache_copy(cache_dir, bundler_cache_dir)
+ end
+ end
+ Autobuild.programs['bundler'] =
+ Autobuild.programs['bundle'] =
+ File.join(ws.dot_autoproj_dir, 'bin', 'bundle')
+
env.init_from_env 'RUBYLIB'
env.inherit 'RUBYLIB'
# Sanitize the rubylib we get from the environment by removing
# anything that comes from Gem or Bundler
original_rubylib =
@@ -94,10 +119,47 @@
if (bundle_rubylib = discover_bundle_rubylib(silent_errors: true))
update_env_rubylib(bundle_rubylib, system_rubylib)
end
end
+ def create_cache_symlink(cache_dir, bundler_cache_dir)
+ valid = !File.exist?(bundler_cache_dir) ||
+ File.symlink?(bundler_cache_dir)
+
+ unless valid
+ Autoproj.warn "cannot use #{cache_dir} as gem cache as "\
+ "#{bundler_cache_dir} already exists"
+ return
+ end
+
+ FileUtils.rm_f bundler_cache_dir
+ FileUtils.ln_s cache_dir, bundler_cache_dir
+ end
+
+ def create_cache_copy(cache_dir, bundler_cache_dir)
+ valid = !File.exist?(bundler_cache_dir) ||
+ File.directory?(bundler_cache_dir) ||
+ File.symlink?(bundler_cache_dir)
+
+ unless valid
+ Autoproj.warn "cannot use #{cache_dir} as gem cache as "\
+ "#{bundler_cache_dir} already exists"
+ return
+ end
+
+ # Gracefully upgrade from the symlinks
+ FileUtils.rm_f bundler_cache_dir if File.symlink?(bundler_cache_dir)
+ FileUtils.mkdir_p bundler_cache_dir
+
+ Dir.glob(File.join(cache_dir, '*.gem')) do |path_src|
+ path_dest = File.join(bundler_cache_dir, File.basename(path_src))
+ next if File.exist?(path_dest)
+
+ FileUtils.cp path_src, path_dest
+ end
+ end
+
# Enumerate the per-gem build configurations
def self.per_gem_build_config(ws)
ws.config.get('bundler.build', {})
end
@@ -246,24 +308,28 @@
mapping.each do |_file, backup_file|
FileUtils.rm backup_file if File.file?(backup_file)
end
end
- def self.run_bundler_install(ws, gemfile, *options,
- update: true, binstubs: nil,
- gem_home: ws.config.gems_gem_home,
- gem_path: ws.config.gems_install_path)
+ def self.run_bundler_install(
+ ws, gemfile, *options,
+ update: true, binstubs: nil,
+ bundler_version: ws.config.bundler_version,
+ gem_home: ws.config.gems_gem_home,
+ gem_path: ws.config.gems_install_path
+ )
FileUtils.rm "#{gemfile}.lock" if update && File.file?("#{gemfile}.lock")
options << '--path' << gem_path
options << "--shebang" << Gem.ruby
options << "--binstubs" << binstubs if binstubs
apply_build_config(ws)
connections = Set.new
run_bundler(ws, 'install', *options,
+ bundler_version: bundler_version,
gem_home: gem_home, gemfile: gemfile) do |line|
case line
when /Installing (.*)/
Autobuild.message " bundler: installing #{$1}"
when /Fetching.*from (.*)/
@@ -274,34 +340,45 @@
end
end
end
end
- def self.bundle_gem_path(ws, gem_name, gem_home: nil, gemfile: nil)
+ def self.bundle_gem_path(ws, gem_name,
+ bundler_version: ws.config.bundler_version,
+ gem_home: nil, gemfile: nil)
path = String.new
- PackageManagers::BundlerManager.run_bundler(
+ run_bundler(
ws, 'show', gem_name,
- gem_home: gem_home,
+ bundler_version: bundler_version, gem_home: gem_home,
gemfile: gemfile) { |line| path << line }
path.chomp
end
def self.default_bundler(ws)
File.join(ws.dot_autoproj_dir, 'bin', 'bundle')
end
- def self.run_bundler(ws, *commandline, gem_home: nil, gemfile: nil)
+ def self.run_bundler(ws, *commandline,
+ bundler_version: ws.config.bundler_version,
+ gem_home: ws.config.gems_gem_home,
+ gemfile: default_gemfile_path(ws))
bundle = Autobuild.programs['bundle'] || default_bundler(ws)
- Bundler.with_clean_env do
+ Autoproj.bundler_with_unbundled_env do
+ bundler_version_env =
+ if bundler_version
+ { 'BUNDLER_VERSION' => bundler_version }
+ else
+ {}
+ end
target_env = Hash[
'GEM_HOME' => gem_home,
'GEM_PATH' => nil,
'BUNDLE_GEMFILE' => gemfile,
'RUBYOPT' => nil,
- 'RUBYLIB' => rubylib_for_bundler
- ]
+ 'RUBYLIB' => rubylib_for_bundler,
+ ].merge(bundler_version_env)
ws.run('autoproj', 'osdeps',
bundle, *commandline,
working_directory: File.dirname(gemfile),
env: target_env) { |line| yield(line) if block_given? }
end
@@ -388,13 +465,17 @@
gemfiles << overrides_gemfile
end
gemfiles
end
+ def self.default_gemfile_path(ws)
+ File.join(ws.prefix_dir, 'gems', 'Gemfile')
+ end
+
def install(gems, filter_uptodate_packages: false, install_only: false)
- root_dir = File.join(ws.prefix_dir, 'gems')
- gemfile_path = File.join(root_dir, 'Gemfile')
+ gemfile_path = self.class.default_gemfile_path(ws)
+ root_dir = File.dirname(gemfile_path)
gemfile_lock_path = "#{gemfile_path}.lock"
backups = Hash[
gemfile_path => "#{gemfile_path}.orig",
gemfile_lock_path => "#{gemfile_lock_path}.orig"
]
@@ -464,11 +545,11 @@
end
def discover_rubylib
require 'bundler'
Tempfile.open 'autoproj-rubylib' do |io|
- result = Bundler.clean_system(
+ result = Autoproj.bundler_unbundled_system(
Hash['RUBYLIB' => nil],
Autobuild.tool('ruby'), '-e', 'puts $LOAD_PATH',
out: io,
err: '/dev/null')
if result
@@ -488,10 +569,10 @@
gemfile = File.join(ws.prefix_dir, 'gems', 'Gemfile')
silent_redirect = Hash.new
silent_redirect[:err] = :close if silent_errors
env = ws.env.resolved_env
Tempfile.open 'autoproj-rubylib' do |io|
- result = Bundler.clean_system(
+ result = Autoproj.bundler_unbundled_system(
Hash['GEM_HOME' => env['GEM_HOME'], 'GEM_PATH' => env['GEM_PATH'],
'BUNDLE_GEMFILE' => gemfile, 'RUBYOPT' => nil,
'RUBYLIB' => self.class.rubylib_for_bundler],
Autobuild.tool('ruby'), '-rbundler/setup',
'-e', 'puts $LOAD_PATH',