lib/autoproj/package_managers/bundler_manager.rb in autoproj-2.0.0.rc15 vs lib/autoproj/package_managers/bundler_manager.rb in autoproj-2.0.0.rc16

- old
+ new

@@ -29,30 +29,29 @@ def initialize_environment env = ws.env config = ws.config - 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 + env.set 'GEM_PATH', config.bundler_gem_home root_dir = File.join(ws.prefix_dir, 'gems') gemfile_path = File.join(root_dir, 'Gemfile') if File.file?(gemfile_path) env.set('BUNDLE_GEMFILE', gemfile_path) end if !config.private_bundler? || !config.private_autoproj? || !config.private_gems? env.set('GEM_PATH', *Gem.default_path) end + Autobuild.programs['bundler'] = File.join(ws.dot_autoproj_dir, 'bin', 'bundler') + 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 @@ -62,10 +61,15 @@ !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 + # 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) end ws.config.each_reused_autoproj_installation do |p| @@ -158,10 +162,67 @@ end end end end + # 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 |h, k| + h[k] = Hash.new do |a, b| + a[b] = Array.new + end + end + end + path.each do |gemfile| + bundler_def = Bundler::Dsl.evaluate(gemfile, nil, []) + gems_remotes |= bundler_def.send(:sources).rubygems_remotes.to_set + bundler_def.dependencies.each do |d| + d.groups.each do |group_name| + if !d.platforms.empty? + d.platforms.each do |platform_name| + dependencies[group_name][platform_name][d.name] = d + end + else + dependencies[group_name][''][d.name] = d + end + end + end + 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}'" + end + 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? + contents << " platform :#{platform_name} do" + platform_indent = " " + end + deps.each do |d| + if d.source + options = d.source.options.map { |k, v| "#{k}: \"#{v}\"" } + end + contents << [" #{platform_indent}gem \"#{d.name}\", \"#{d.requirement}\"", *options].join(", ") + end + if !platform_name.empty? + contents << " end" + end + end + contents << "end" + end + contents.join("\n") + 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_lock_path = "#{gemfile_path}.lock" backups = Hash[ @@ -186,35 +247,36 @@ end # In addition, look into overrides.d Dir.glob(File.join(ws.overrides_dir, "*.gemfile")) do |gemfile_path| gemfiles << gemfile_path end + gemfiles << File.join(ws.dot_autoproj_dir, 'autoproj', 'Gemfile') - # Generate the gemfile and remove the lockfile - gemfile_lines = gems.map do |name| - name, version = parse_package_entry(name) - "gem \"#{name}\", \"#{version || ">= 0"}\"" + # Save the osdeps entries in a temporary gemfile and finally + # merge the whole lot of it + gemfile_contents = Tempfile.open 'autoproj-gemfile' do |io| + osdeps_gemfile_lines = gems.sort.map do |name| + name, version = parse_package_entry(name) + 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 - gemfiles.each do |gemfile| - gemfile_lines.concat(File.readlines(gemfile).map(&:chomp)) - end - gemfile_lines = gemfile_lines.sort.uniq - gemfile_contents = [ - "eval_gemfile \"#{File.join(ws.dot_autoproj_dir, 'autoproj', 'Gemfile')}\"", - *gemfile_lines - ].join("\n") FileUtils.mkdir_p root_dir if updated = (!File.exist?(gemfile_path) || File.read(gemfile_path) != gemfile_contents) File.open(gemfile_path, 'w') do |io| io.puts gemfile_contents end end options = Array.new if ws.config.private_gems? - options << "--path" << ws.config.gems_gem_home + options << "--path" << ws.config.gems_bundler_path end 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, @@ -231,11 +293,11 @@ 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') + FileUtils.rm_f File.join(binstubs_path, 'bundler') if binstubs_path backup_clean(backups) end def discover_rubylib require 'bundler' @@ -244,10 +306,11 @@ Hash['RUBYLIB' => nil], 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? } end end end @@ -258,14 +321,15 @@ 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', + Hash['BUNDLE_GEMFILE' => gemfile, 'RUBYLIB' => nil], + Autobuild.tool('bundler'), 'exec', 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? } end end end end