lib/autoproj/package_managers/bundler_manager.rb in autoproj-2.10.2 vs lib/autoproj/package_managers/bundler_manager.rb in autoproj-2.11.0
- old
+ new
@@ -45,67 +45,151 @@
env.add_path 'PATH', File.join(ws.dot_autoproj_dir, 'bin')
env.set 'GEM_HOME', config.gems_gem_home
env.clear 'GEM_PATH'
gemfile_path = File.join(ws.prefix_dir, 'gems', 'Gemfile')
- if File.file?(gemfile_path)
- env.set('BUNDLE_GEMFILE', gemfile_path)
- end
+ 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')
+ Autobuild.programs['bundler'] = File.join(ws.dot_autoproj_dir,
+ 'bin', 'bundle')
+ 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 =
(env['RUBYLIB'] || "").split(File::PATH_SEPARATOR).find_all do |p|
!p.start_with?(Bundler.rubygems.gem_dir) &&
- !Bundler.rubygems.gem_path.any? { |gem_p| p.start_with?(p) }
+ Bundler.rubygems.gem_path
+ .none? { |gem_p| p.start_with?(gem_p) }
end
# And discover the system's rubylib
- if system_rubylib = discover_rubylib
+ if (system_rubylib = discover_rubylib)
# Do not explicitely add the system rubylib to the
# environment, the interpreter will do it for us.
#
# This allows to use a binstub generated for one of ruby
# interpreter version on our workspace
env.system_env['RUBYLIB'] = []
- env.original_env['RUBYLIB'] = (original_rubylib - system_rubylib).join(File::PATH_SEPARATOR)
+ env.original_env['RUBYLIB'] = (original_rubylib - system_rubylib)
+ .join(File::PATH_SEPARATOR)
end
ws.config.each_reused_autoproj_installation do |p|
reused_w = ws.new(p)
env.add_path 'PATH', File.join(reused_w.prefix_dir, 'gems', 'bin')
end
prefix_gems = File.join(ws.prefix_dir, "gems")
FileUtils.mkdir_p prefix_gems
gemfile = File.join(prefix_gems, 'Gemfile')
- if !File.exist?(gemfile)
+ unless File.exist?(gemfile)
Ops.atomic_write(gemfile) do |io|
- io.puts "eval_gemfile \"#{File.join(ws.dot_autoproj_dir, 'Gemfile')}\""
+ dot_autoproj_gemfile = File.join(ws.dot_autoproj_dir, 'Gemfile')
+ io.puts "eval_gemfile \"#{dot_autoproj_gemfile}\""
end
end
- if bundle_rubylib = discover_bundle_rubylib(silent_errors: true)
+ if (bundle_rubylib = discover_bundle_rubylib(silent_errors: true))
update_env_rubylib(bundle_rubylib, system_rubylib)
end
end
+ # Enumerate the per-gem build configurations
+ def self.per_gem_build_config(ws)
+ ws.config.get('bundler.build', {})
+ end
+
+ # Add new build configuration arguments for a given gem
+ #
+ # This is meant to be used from the Autoproj configuration files,
+ # e.g. overrides.rb or package configuration
+ def self.add_build_configuration_for(gem_name, build_config, ws: Autoproj.workspace)
+ c = ws.config.get('bundler.build', {})
+ c[gem_name] = [c[gem_name], build_config].compact.join(" ")
+ ws.config.set('bundler.build', c)
+ end
+
+ # Set the build configuration for the given gem
+ #
+ # This is meant to be used from the Autoproj configuration files,
+ # e.g. overrides.rb or package configuration
+ def self.configure_build_for(gem_name, build_config, ws: Autoproj.workspace)
+ c = ws.config.get('bundler.build', {})
+ c[gem_name] = build_config
+ ws.config.set('bundler.build', c)
+ end
+
+ # Removes build configuration flags for the given gem
+ #
+ # This is meant to be used from the Autoproj configuration files,
+ # e.g. overrides.rb or package configuration
+ def self.remove_build_configuration_for(gem_name, ws: Autoproj.workspace)
+ c = ws.config.get('bundler.build', {})
+ c.delete(gem_name)
+ ws.config.set('bundler.build', c)
+ end
+
# @api private
#
+ # Apply configured per-gem build configuration options
+ #
+ # @param [Workspace] ws the workspace whose bundler configuration
+ # should be updated
+ # @return [void]
+ def self.apply_build_config(ws)
+ root_dir = File.join(ws.prefix_dir, 'gems')
+ current_config_path = File.join(root_dir, ".bundle", "config")
+ current_config =
+ if File.file?(current_config_path)
+ File.readlines(current_config_path)
+ else
+ []
+ end
+
+ build_config = {}
+ per_gem_build_config(ws).each do |name, conf|
+ build_config[name.upcase] = conf
+ end
+
+ new_config = current_config.map do |line|
+ next(line) unless (m = line.match(/BUNDLE_BUILD__(.*): "(.*)"$/))
+ next unless (desired_config = build_config.delete(m[1]))
+
+ if m[2] != desired_config
+ "BUNDLE_BUILD__#{m[1]}: \"#{desired_config}\""
+ else
+ line
+ end
+ end.compact
+
+ build_config.each do |name, config|
+ new_config << "BUNDLE_BUILD__#{name}: \"#{config}\""
+ end
+
+ if new_config != current_config
+ FileUtils.mkdir_p File.dirname(current_config_path)
+ File.open(current_config_path, 'w') do |io|
+ io.write new_config.join
+ end
+ end
+ end
+
+ # @api private
+ #
# Update RUBYLIB to add the gems that are part of the bundler
# install
#
# @param [Array<String>] bundle_rubylib the rubylib entries reported
# by bundler
# @param [Array<String>] system_rubylib the rubylib entries that are
# set by the underlying ruby interpreter itself
def update_env_rubylib(bundle_rubylib, system_rubylib = discover_rubylib)
- current = (ws.env.resolved_env['RUBYLIB'] || '').split(File::PATH_SEPARATOR) + system_rubylib
+ current = (ws.env.resolved_env['RUBYLIB'] || '')
+ .split(File::PATH_SEPARATOR) + system_rubylib
(bundle_rubylib - current).each do |p|
ws.env.add_path('RUBYLIB', p)
end
end
@@ -126,106 +210,106 @@
[entry]
end
end
class NotCleanState < RuntimeError; end
-
+
# @api private
#
# Create backup files matching a certain file mapping
#
# @param [Hash<String,String>] mapping a mapping from the original
# file to the file into which it should be backed up. The source
# file might not exist.
def backup_files(mapping)
mapping.each do |file, backup_file|
- if File.file?(file)
- FileUtils.cp file, backup_file
- end
+ FileUtils.cp file, backup_file if File.file?(file)
end
end
# @api private
#
# Restore backups saved by {#backup_file}
#
# @param (see #backup_file)
def backup_restore(mapping)
mapping.each do |file, backup_file|
- if File.file?(backup_file)
- FileUtils.cp backup_file, file
- end
+ FileUtils.cp backup_file, file if File.file?(backup_file)
end
end
# @api private
#
# Remove backups created by {#backup_files}
#
# @param (see #backup_file)
def backup_clean(mapping)
- mapping.each do |file, backup_file|
- if File.file?(backup_file)
- FileUtils.rm backup_file
- end
+ 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)
- if update && File.file?("#{gemfile}.lock")
- FileUtils.rm "#{gemfile}.lock"
- 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)
+ FileUtils.rm "#{gemfile}.lock" if update && File.file?("#{gemfile}.lock")
options << '--path' << gem_path
options << "--shebang" << Gem.ruby
- if binstubs
- options << "--binstubs" << binstubs
- end
+ options << "--binstubs" << binstubs if binstubs
+ apply_build_config(ws)
+
connections = Set.new
- run_bundler(ws, 'install', *options, gem_home: gem_home, gemfile: gemfile) do |line|
+ run_bundler(ws, 'install', *options,
+ gem_home: gem_home, gemfile: gemfile) do |line|
case line
when /Installing (.*)/
Autobuild.message " bundler: installing #{$1}"
when /Fetching.*from (.*)/
host = $1.gsub(/\.+$/, '')
- if !connections.include?(host)
+ unless connections.include?(host)
Autobuild.message " bundler: connected to #{host}"
connections << host
end
end
end
end
def self.bundle_gem_path(ws, gem_name, gem_home: nil, gemfile: nil)
path = String.new
- PackageManagers::BundlerManager.run_bundler(ws, 'show', gem_name, gem_home: gem_home, gemfile: gemfile) do |line|
- path << line
- end
+ PackageManagers::BundlerManager.run_bundler(
+ ws, 'show', gem_name,
+ 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)
+ bundle = Autobuild.programs['bundle'] || default_bundler(ws)
+
Bundler.with_clean_env do
target_env = Hash[
'GEM_HOME' => gem_home,
'GEM_PATH' => nil,
'BUNDLE_GEMFILE' => gemfile,
'RUBYOPT' => nil,
'RUBYLIB' => rubylib_for_bundler
]
- ws.run 'autoproj', 'osdeps',
- Autobuild.tool('bundle'), *commandline,
- working_directory: File.dirname(gemfile), env: target_env do |line|
- yield(line) if block_given?
- end
+ ws.run('autoproj', 'osdeps',
+ bundle, *commandline,
+ working_directory: File.dirname(gemfile),
+ env: target_env) { |line| yield(line) if block_given? }
end
end
- # Parse the contents of a gemfile into a set of
+ # Parse the contents of a gemfile into a set of
def merge_gemfiles(*path, unlock: [])
gems_remotes = Set.new
dependencies = Hash.new do |h, k|
h[k] = Hash.new do |i, j|
i[j] = Hash.new do |a, b|
@@ -235,13 +319,15 @@
end
path.each do |gemfile|
bundler_def =
begin Bundler::Dsl.evaluate(gemfile, nil, [])
rescue Exception => e
- cleaned_message = e.message.
- gsub(/There was an error parsing([^:]+)/, "Error in gem definitions").
- gsub(/# from.*/, '')
+ cleaned_message = e
+ .message
+ .gsub(/There was an error parsing([^:]+)/,
+ "Error in gem definitions")
+ .gsub(/# from.*/, '')
raise ConfigError, cleaned_message
end
gems_remotes |= bundler_def.send(:sources).rubygems_remotes.to_set
bundler_def.dependencies.each do |d|
d.groups.each do |group_name|
@@ -257,51 +343,51 @@
end
contents = []
gems_remotes.each do |g|
g = g.to_s
- if g.end_with?('/')
- g = g[0..-2]
- end
- contents << "source '#{g.to_s}'"
+ g = g[0..-2] if g.end_with?('/')
+ contents << "source '#{g}'"
end
- valid_keys = %w{group groups git path glob name branch ref tag require submodules platform platforms type source install_if}
+ valid_keys = %w[group groups git path glob name branch ref tag
+ require submodules platform platforms type
+ source install_if]
dependencies.each do |group_name, by_platform|
contents << "group :#{group_name} do"
by_platform.each do |platform_name, deps|
deps = deps.values.sort_by(&:name)
- if !platform_name.empty?
+ unless platform_name.empty?
contents << " platform :#{platform_name} do"
platform_indent = " "
end
deps.each do |d|
if d.source
options = d.source.options.dup
options.delete_if { |k, _| !valid_keys.include?(k) }
options = options.map { |k, v| "#{k}: \"#{v}\"" }
end
- contents << [" #{platform_indent}gem \"#{d.name}\", \"#{d.requirement}\"", *options].join(", ")
+ contents << [" #{platform_indent}gem \"#{d.name}\",
+ \"#{d.requirement}\"", *options].join(', ')
end
- if !platform_name.empty?
- contents << " end"
- end
+ contents << ' end' unless platform_name.empty?
end
- contents << "end"
+ contents << 'end'
end
contents.join("\n")
end
def workspace_configuration_gemfiles
gemfiles = []
ws.manifest.each_package_set do |source|
- if source.local_dir && File.file?(pkg_set_gemfile = File.join(source.local_dir, 'Gemfile'))
+ pkg_set_gemfile = File.join(source.local_dir, 'Gemfile')
+ if source.local_dir && File.file?(pkg_set_gemfile)
gemfiles << pkg_set_gemfile
end
end
# In addition, look into overrides.d
- Dir.glob(File.join(ws.overrides_dir, "*.gemfile")) do |overrides_gemfile_path|
- gemfiles << overrides_gemfile_path
+ Dir.glob(File.join(ws.overrides_dir, "*.gemfile")) do |overrides_gemfile|
+ gemfiles << overrides_gemfile
end
gemfiles
end
def install(gems, filter_uptodate_packages: false, install_only: false)
@@ -314,13 +400,14 @@
]
# Back up the existing gemfile, we'll restore it if something is
# wrong to avoid leaving bundler in an inconsistent state
backup_files(backups)
- if !File.file?("#{gemfile_path}.orig")
+ unless File.file?("#{gemfile_path}.orig")
Ops.atomic_write("#{gemfile_path}.orig") do |io|
- io.puts "eval_gemfile \"#{File.join(ws.dot_autoproj_dir, 'Gemfile')}\""
+ dot_autoproj_gemfile = File.join(ws.dot_autoproj_dir, 'Gemfile')
+ io.puts "eval_gemfile \"#{dot_autoproj_gemfile}\""
end
end
gemfiles = workspace_configuration_gemfiles
gemfiles << File.join(ws.dot_autoproj_dir, 'Gemfile')
@@ -328,48 +415,51 @@
# Save the osdeps entries in a temporary gemfile and finally
# merge the whole lot of it
gemfile_contents = Tempfile.open 'autoproj-gemfile' do |io|
gems.sort.each do |name|
name, version = parse_package_entry(name)
- io.puts "gem \"#{name}\", \"#{version || ">= 0"}\""
+ io.puts "gem \"#{name}\", \"#{version || '>= 0'}\""
end
io.flush
gemfiles.unshift io.path
# The autoproj gemfile needs to be last, we really don't
# want to mess it up
merge_gemfiles(*gemfiles)
end
FileUtils.mkdir_p root_dir
- if updated = (!File.exist?(gemfile_path) || File.read(gemfile_path) != gemfile_contents)
+ updated = (!File.exist?(gemfile_path) ||
+ File.read(gemfile_path) != gemfile_contents)
+ if updated
Ops.atomic_write(gemfile_path) do |io|
io.puts "ruby \"#{RUBY_VERSION}\" if respond_to?(:ruby)"
io.puts gemfile_contents
end
end
options = Array.new
binstubs_path = File.join(root_dir, 'bin')
if updated || !install_only || !File.file?("#{gemfile_path}.lock")
- self.class.run_bundler_install ws, gemfile_path, *options,
- binstubs: binstubs_path
+ self.class.run_bundler_install(ws, gemfile_path, *options,
+ binstubs: binstubs_path)
end
- if bundle_rubylib = discover_bundle_rubylib
+ if (bundle_rubylib = discover_bundle_rubylib)
update_env_rubylib(bundle_rubylib)
else
- raise NotCleanState, "bundler executed successfully, but the result was not in a clean state"
+ raise NotCleanState, "bundler executed successfully, "\
+ "but the result was not in a clean state"
end
-
rescue Exception
- Autoproj.warn "saved the new Gemfile in #{gemfile_path}.FAILED and restored the last Gemfile version"
+ Autoproj.warn "saved the new Gemfile in #{gemfile_path}.FAILED "\
+ "and restored the last Gemfile version"
FileUtils.cp gemfile_path, "#{gemfile_path}.FAILED"
backup_restore(backups)
raise
ensure
if binstubs_path
- FileUtils.rm_f File.join(binstubs_path, 'bundle')
+ FileUtils.rm_f File.join(binstubs_path, 'bundle')
FileUtils.rm_f File.join(binstubs_path, 'bundler')
end
backup_clean(backups)
end
@@ -381,11 +471,11 @@
Autobuild.tool('ruby'), '-e', 'puts $LOAD_PATH',
out: io,
err: '/dev/null')
if result
io.rewind
- io.readlines.map { |l| l.chomp }.find_all { |l| !l.empty? }
+ io.readlines.map(&:chomp).find_all { |l| !l.empty? }
end
end
end
def self.rubylib_for_bundler
@@ -395,27 +485,25 @@
def discover_bundle_rubylib(silent_errors: false)
require 'bundler'
gemfile = File.join(ws.prefix_dir, 'gems', 'Gemfile')
silent_redirect = Hash.new
- if silent_errors
- silent_redirect[:err] = :close
- end
+ silent_redirect[:err] = :close if silent_errors
env = ws.env.resolved_env
Tempfile.open 'autoproj-rubylib' do |io|
result = Bundler.clean_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',
+ Autobuild.tool('ruby'), '-rbundler/setup',
+ '-e', 'puts $LOAD_PATH',
out: io, **silent_redirect)
-
+
if result
io.rewind
- io.readlines.map { |l| l.chomp }.find_all { |l| !l.empty? }
+ io.readlines.map(&:chomp).find_all { |l| !l.empty? }
end
end
end
end
end
end
-