lib/autoproj/package_managers/bundler_manager.rb in autoproj-2.0.0.rc9 vs lib/autoproj/package_managers/bundler_manager.rb in autoproj-2.0.0.rc10

- old
+ new

@@ -27,69 +27,59 @@ # Filters all paths that come from other autoproj installations out # of GEM_PATH def initialize_environment env = ws.env - env.inherit 'GEM_PATH' - env.init_from_env 'GEM_PATH' - env.system_env['GEM_PATH'] = Gem.default_path + config = ws.config - if (env.original_env['GEM_HOME'] || '').empty? - env.unset('GEM_HOME') + env.add_path 'PATH', File.join(Gem.user_dir, 'bin') + env.add_path 'PATH', File.join(ws.prefix_dir, 'gems', 'bin') + env.add_path 'PATH', File.join(config.bundler_gem_home, 'bin') + env.add_path 'PATH', File.join(ws.dot_autoproj_dir, 'autoproj', 'bin') + env.set 'GEM_HOME', config.gems_gem_home + + if !config.private_bundler? || !config.private_autoproj? || !config.private_gems? + env.set('GEM_PATH', *Gem.default_path) end + if config.private_bundler? + Autobuild.programs['bundler'] = File.join(config.bundler_gem_home, 'bin', 'bundler') + env.add_path 'GEM_PATH', config.bundler_gem_home + else + Autobuild.programs['bundler'] = env.find_in_path('bundler') + end 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) } end + # And discover the system's rubylib if system_rubylib = discover_rubylib env.system_env['RUBYLIB'] = [] 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) reused_c = reused_w.load_config - if reused_c.private_gems? - env.add_path 'GEM_PATH', File.join(reused_w.prefix_dir, 'gems') - end env.add_path 'PATH', File.join(reused_w.prefix_dir, 'gems', 'bin') end - gem_home = File.join(ws.prefix_dir, "gems") - if ws.config.private_gems? - env.set 'GEM_HOME', gem_home - env.add_path 'GEM_PATH', gem_home - end - - FileUtils.mkdir_p gem_home - gemfile = File.join(gem_home, 'Gemfile') + prefix_gems = File.join(ws.prefix_dir, "gems") + FileUtils.mkdir_p prefix_gems + gemfile = File.join(prefix_gems, 'Gemfile') if !File.exists?(gemfile) File.open(gemfile, 'w') do |io| io.puts "eval_gemfile \"#{File.join(ws.dot_autoproj_dir, 'autoproj', 'Gemfile')}\"" end end - env.set 'BUNDLE_GEMFILE', File.join(gem_home, 'Gemfile') - env.add_path 'PATH', Gem.bindir - env.add_path 'PATH', File.join(gem_home, 'bin') - - dot_autoproj = ws.dot_autoproj_dir - if ws.config.private_bundler? - env.add_path 'PATH', File.join(dot_autoproj, 'bundler', 'bin') - env.add_path 'GEM_PATH', File.join(dot_autoproj, 'bundler') - end - env.add_path 'PATH', File.join(dot_autoproj, 'autoproj', 'bin') - if ws.config.private_autoproj? - env.add_path 'GEM_PATH', File.join(dot_autoproj, 'autoproj') - end - Autobuild.programs['bundler'] = 'bundler' - - if bundle_rubylib = discover_bundle_rubylib + if bundle_rubylib = discover_bundle_rubylib(silent_errors: true) update_env_rubylib(bundle_rubylib, system_rubylib) end end def update_env_rubylib(bundle_rubylib, system_rubylib = discover_rubylib) @@ -131,10 +121,41 @@ FileUtils.rm backup_file end end end + def self.run_bundler_install(ws, gemfile, *options, update: true, binstubs: nil) + if update && File.file?("#{gemfile}.lock") + FileUtils.rm "#{gemfile}.lock" + end + + options << "--shebang" << Gem.ruby + if binstubs + options << "--binstubs" << binstubs + end + + Bundler.with_clean_env do + connections = Set.new + ws.run 'autoproj', 'osdeps', + Autobuild.tool('bundler'), 'install', + *options, + working_directory: File.dirname(gemfile), env: Hash['BUNDLE_GEMFILE' => nil, 'RUBYOPT' => nil] do |line| + + case line + when /Installing (.*)/ + Autobuild.message " bundler: installing #{$1}" + when /Fetching.*from (.*)/ + host = $1.gsub(/\.+$/, '') + if !connections.include?(host) + Autobuild.message " bundler: connected to #{host}" + connections << host + end + end + end + end + end + def install(gems) root_dir = File.join(ws.prefix_dir, 'gems') gemfile_path = File.join(root_dir, 'Gemfile') gemfile_lock_path = "#{gemfile_path}.lock" backups = Hash[ @@ -149,52 +170,53 @@ File.open("#{gemfile_path}.orig", 'w') do |io| io.puts "eval_gemfile \"#{File.join(ws.dot_autoproj_dir, 'autoproj', 'Gemfile')}\"" end end + gemfiles = [] + ws.manifest.each_package_set do |source| + if source.local_dir && File.file?(pkg_set_gemfile = File.join(source.local_dir, 'Gemfile')) + gemfiles << pkg_set_gemfile + end + end + # In addition, look into overrides.d + Dir.glob(File.join(ws.config_dir, "*.gemfile")) do |gemfile_path| + gemfiles << gemfile_path + end + # Generate the gemfile and remove the lockfile gems = gems.sort.map do |name| name, version = parse_package_entry(name) "gem \"#{name}\", \"#{version || ">= 0"}\"" end.join("\n") FileUtils.mkdir_p root_dir File.open(gemfile_path, 'w') do |io| io.puts "eval_gemfile \"#{File.join(ws.dot_autoproj_dir, 'autoproj', 'Gemfile')}\"" + gemfiles.each do |gemfile| + io.puts File.read(gemfile) + end io.puts gems end - FileUtils.rm File.join(root_dir, 'Gemfile.lock') - binstubs_path = File.join(root_dir, 'bin') - Bundler.with_clean_env do - connections = Set.new - Autobuild::Subprocess.run 'autoproj', 'osdeps', - Autobuild.tool('bundler'), 'install', - "--gemfile=#{gemfile_path}", *options, - "--binstubs", binstubs_path, - "--shebang", Gem.ruby, - env: Hash['BUNDLE_GEMFILE' => gemfile_path] do |line| - - case line - when /Installing (.*)/ - Autobuild.message " bundler: installing #{$1}" - when /Fetching.*from (.*)/ - host = $1.gsub(/\.+$/, '') - if !connections.include?(host) - Autobuild.message " bundler: connected to #{host}" - connections << host - end - end - end + options = Array.new + if ws.config.private_gems? + options << "--path" << ws.config.gems_gem_home end + binstubs_path = File.join(root_dir, 'bin') + self.class.run_bundler_install ws, gemfile_path, *options, + binstubs: binstubs_path + if bundle_rubylib = discover_bundle_rubylib update_env_rubylib(bundle_rubylib) else - raise NotCleanState, "bundler executed successfully, but the result is not in a clean state" + raise NotCleanState, "bundler executed successfully, but the result was not in a clean state" end rescue Exception => e + 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 FileUtils.rm_f File.join(binstubs_path, 'bundler') backup_clean(backups) @@ -212,18 +234,22 @@ io.readlines.map { |l| l.chomp }.find_all { |l| !l.empty? } end end end - def discover_bundle_rubylib + 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] = '/dev/null' + end Tempfile.open 'autoproj-rubylib' do |io| result = Bundler.clean_system( Hash['BUNDLE_GEMFILE' => gemfile], Autobuild.tool('bundler'), 'exec', 'ruby', '-e', 'puts $LOAD_PATH', - out: io, - err: '/dev/null') + out: io, **silent_redirect) + if result io.readlines.map { |l| l.chomp }.find_all { |l| !l.empty? } end end end