bin/autoproj_install in autoproj-2.11.0 vs bin/autoproj_install in autoproj-2.12.0
- old
+ new
@@ -6,14 +6,17 @@
elsif ENV['AUTOPROJ_CURRENT_ROOT'] && (ENV['AUTOPROJ_CURRENT_ROOT'] != Dir.pwd)
STDERR.puts "it seems that you've already loaded an env.sh script in this console, open a new console and try again"
exit 1
end
+# frozen_string_literal: true
+
require 'pathname'
require 'optparse'
require 'fileutils'
require 'yaml'
+require 'English'
module Autoproj
module Ops
# This class contains the functionality necessary to install autoproj in a
# clean root
@@ -21,10 +24,40 @@
# It can be required standalone (i.e. does not depend on anything else than
# ruby and the ruby standard library)
class Install
class UnexpectedBinstub < RuntimeError; end
+ RUBYLIB_REINIT = <<~RUBY
+ if defined?(Bundler)
+ if Bundler.respond_to?(:with_unbundled_env)
+ Bundler.with_unbundled_env do
+ exec(Hash['RUBYLIB' => nil], $0, *ARGV)
+ end
+ else
+ Bundler.with_clean_env do
+ exec(Hash['RUBYLIB' => nil], $0, *ARGV)
+ end
+ end
+ elsif ENV['RUBYLIB']
+ exec(Hash['RUBYLIB' => nil], $0, *ARGV)
+ end
+ RUBY
+
+ WITHOUT_BUNDLER = <<~RUBY
+ if defined?(Bundler)
+ if Bundler.respond_to?(:with_unbundled_env)
+ Bundler.with_unbundled_env do
+ exec($0, *ARGV)
+ end
+ else
+ Bundler.with_clean_env do
+ exec($0, *ARGV)
+ end
+ end
+ end
+ RUBY
+
# The created workspace's root directory
attr_reader :root_dir
# Content of the Gemfile generated to install autoproj itself
attr_accessor :gemfile
# The environment that is passed to the bundler installs
@@ -228,10 +261,14 @@
"ruby \"#{RUBY_VERSION}\" if respond_to?(:ruby)",
"gem \"autoproj\", \"#{autoproj_version}\"",
"gem \"utilrb\", \">= 3.0.1\""].join("\n")
end
+ def add_seed_config(path)
+ @config.merge!(YAML.safe_load(File.read(path)))
+ end
+
# Parse the provided command line options and returns the non-options
def parse_options(args = ARGV)
options = OptionParser.new do |opt|
opt.on '--local', 'do not access the network (may fail)' do
@local = true
@@ -251,10 +288,14 @@
self.gems_install_path = path
end
opt.on '--public-gems', "install gems in the default gem location" do
self.install_gems_in_gem_user_dir
end
+ opt.on '--bundler-version=VERSION_CONSTRAINT', String, 'use the provided '\
+ 'string as a version constraint for bundler' do |version|
+ @config['bundler_version'] = version
+ end
opt.on '--version=VERSION_CONSTRAINT', String, 'use the provided '\
'string as a version constraint for autoproj' do |version|
if @gemfile
raise "cannot give both --version and --gemfile"
end
@@ -265,13 +306,18 @@
if @gemfile
raise "cannot give both --version and --gemfile"
end
@gemfile = File.read(path)
end
+ opt.on '--no-seed-config',
+ 'when reinstalling an existing autoproj workspace, do not '\
+ 'use the config in .autoproj/ as seed' do
+ @config.clear
+ end
opt.on '--seed-config=PATH', String, 'path to a seed file that '\
'should be used to initialize the configuration' do |path|
- @config.merge!(YAML.load(File.read(path)))
+ add_seed_config(path)
end
opt.on '--prefer-os-independent-packages', 'prefer OS-independent '\
'packages (such as a RubyGem) over their OS-packaged equivalent '\
'(e.g. the thor gem vs. the ruby-thor debian package)' do
@prefer_indep_over_os_packages = true
@@ -297,60 +343,91 @@
end
args = options.parse(ARGV)
@autoproj_options + args
end
- def find_bundler(gem_program)
+ def bundler_version
+ @config['bundler_version']
+ end
+
+ def find_bundler(gem_program, version: nil)
+ bundler_path = File.join(gems_gem_home, 'bin', 'bundle')
+ return unless File.exist?(bundler_path)
+
setup_paths =
- IO.popen([env_for_child, Gem.ruby, gem_program, 'which','-a', 'bundler/setup']) do |io|
- io.read
+ if version
+ find_versioned_bundler_setup(gem_program, version)
+ else
+ find_unversioned_bundler_setup(gem_program)
end
- return unless $?.success?
- bundler_path = File.join(gems_gem_home, 'bin', 'bundle')
- setup_paths.each_line do |setup_path|
- if File.exist?(bundler_path) && setup_path.start_with?(gems_gem_home)
- return bundler_path
- end
+
+ setup_paths.each do |setup_path|
+ return bundler_path if setup_path.start_with?(gems_gem_home)
end
- return
+ nil
end
- def install_bundler(gem_program, silent: false)
+ def find_versioned_bundler_setup(gem_program, version)
+ contents = IO.popen(
+ [env_for_child, Gem.ruby, gem_program,
+ 'contents', '-v', version, 'bundler'],
+ &:readlines
+ )
+ return [] unless $CHILD_STATUS.success?
+
+ contents.grep(%r{bundler/setup.rb$})
+ end
+
+ def find_unversioned_bundler_setup(gem_program)
+ setup_paths = IO.popen(
+ [env_for_child, Gem.ruby, gem_program,
+ 'which', '-a', 'bundler/setup'],
+ &:readlines
+ )
+ return [] unless $CHILD_STATUS.success?
+
+ setup_paths
+ end
+
+ def install_bundler(gem_program, version: nil, silent: false)
local = ['--local'] if local?
redirection = Hash.new
if silent
redirection = Hash[out: :close]
end
+ version_args = []
+ version_args << '-v' << version if version
+
# Shut up the bundler warning about 'bin' not being in PATH
env = self.env
env['PATH'] += [File.join(gems_gem_home, 'bin')]
result = system(
env_for_child(env),
Gem.ruby, gem_program, 'install',
'--env-shebang', '--no-document', '--no-format-executable',
'--clear-sources', '--source', gem_source,
'--no-user-install', '--install-dir', gems_gem_home,
*local, "--bindir=#{File.join(gems_gem_home, 'bin')}",
- 'bundler', **redirection)
+ 'bundler', *version_args, **redirection)
if !result
STDERR.puts "FATAL: failed to install bundler in #{gems_gem_home}"
nil
end
- if (bundler_path = find_bundler(gem_program))
+ if (bundler_path = find_bundler(gem_program, version: version))
bundler_path
else
STDERR.puts "gem install bundler returned successfully, but still "\
"cannot find bundler in #{gems_gem_home}"
nil
end
end
- def install_autoproj(bundler)
+ def install_autoproj(bundler, bundler_version: self.bundler_version)
# Force bundler to update. If the user does not want this, let
# him specify a Gemfile with tighter version constraints
lockfile = File.join(dot_autoproj, 'Gemfile.lock')
if File.exist?(lockfile)
FileUtils.rm lockfile
@@ -361,27 +438,32 @@
opts = Array.new
opts << '--local' if local?
opts << "--path=#{gems_install_path}"
shims_path = File.join(dot_autoproj, 'bin')
- result = system(clean_env,
- Gem.ruby, bundler, 'install',
- "--gemfile=#{autoproj_gemfile_path}",
- "--shebang=#{Gem.ruby}",
- "--binstubs=#{shims_path}",
- *opts, chdir: dot_autoproj)
+ version_arg = []
+ version_arg << "_#{bundler_version}_" if bundler_version
- if !result
+ result = system(
+ clean_env,
+ Gem.ruby, bundler, *version_arg, 'install',
+ "--gemfile=#{autoproj_gemfile_path}",
+ "--shebang=#{Gem.ruby}",
+ "--binstubs=#{shims_path}",
+ *opts, chdir: dot_autoproj
+ )
+
+ unless result
STDERR.puts "FATAL: failed to install autoproj in #{dot_autoproj}"
exit 1
end
ensure
self.class.rewrite_shims(shims_path, ruby_executable,
root_dir, autoproj_gemfile_path, gems_gem_home)
end
- EXCLUDED_FROM_SHIMS = %w{rake thor}
+ EXCLUDED_FROM_SHIMS = %w[rake thor].freeze
def self.rewrite_shims(shim_path, ruby_executable,
root_dir, autoproj_gemfile_path, gems_gem_home)
FileUtils.mkdir_p shim_path
File.open(File.join(shim_path, 'ruby'), 'w') do |io|
@@ -433,15 +515,11 @@
#
# This file was generated by Bundler.
#
# Autoproj generated preamble
-if defined?(Bundler)
- Bundler.with_clean_env do
- exec($0, *ARGV)
- end
-end
+#{WITHOUT_BUNDLER}
ENV['BUNDLE_GEMFILE'] ||= '#{autoproj_gemfile_path}'
ENV['GEM_HOME'] = '#{gems_gem_home}'
ENV.delete('GEM_PATH')
Gem.paths = Hash['GEM_HOME' => '#{gems_gem_home}', 'GEM_PATH' => '']
RESTART_BUNDLER
@@ -449,16 +527,11 @@
end
def self.shim_bundler_old(ruby_executable, autoproj_gemfile_path, gems_gem_home)
"#! #{ruby_executable}
-if defined?(Bundler)
- Bundler.with_clean_env do
- exec($0, *ARGV)
- end
-end
-
+#{WITHOUT_BUNDLER}
ENV['BUNDLE_GEMFILE'] ||= '#{autoproj_gemfile_path}'
ENV['GEM_HOME'] = '#{gems_gem_home}'
ENV.delete('GEM_PATH')
Gem.paths = Hash['GEM_HOME' => '#{gems_gem_home}', 'GEM_PATH' => '']
@@ -479,18 +552,11 @@
#
# This file was generated by Bundler.
#
# Autoproj generated preamble, v1
-if defined?(Bundler)
- Bundler.with_clean_env do
- exec(Hash['RUBYLIB' => nil], $0, *ARGV)
- end
-elsif ENV['RUBYLIB']
- exec(Hash['RUBYLIB' => nil], $0, *ARGV)
-end
-
+#{RUBYLIB_REINIT}
ENV['BUNDLE_GEMFILE'] = '#{autoproj_gemfile_path}'
ENV['AUTOPROJ_CURRENT_ROOT'] = '#{root_dir}'
Gem.paths = Hash['GEM_HOME' => '#{gems_gem_home}', 'GEM_PATH' => '']
AUTOPROJ_PREAMBLE
return script_lines.join
@@ -498,18 +564,11 @@
def self.shim_script_old(ruby_executable, root_dir, autoproj_gemfile_path,
gems_gem_home, load_line)
"#! #{ruby_executable}
-if defined?(Bundler)
- Bundler.with_clean_env do
- exec(Hash['RUBYLIB' => nil], $0, *ARGV)
- end
-elsif ENV['RUBYLIB']
- exec(Hash['RUBYLIB' => nil], $0, *ARGV)
-end
-
+#{RUBYLIB_REINIT}
ENV['BUNDLE_GEMFILE'] = '#{autoproj_gemfile_path}'
ENV['AUTOPROJ_CURRENT_ROOT'] = '#{root_dir}'
require 'rubygems'
Gem.paths = Hash['GEM_HOME' => '#{gems_gem_home}', 'GEM_PATH' => '']
require 'bundler/setup'
@@ -599,38 +658,40 @@
# because of limitations of autoproj 1.x. This leads to
# Gem.bindir being *not* valid for subprocesses
#
# So, we're calling 'gem' as a subcommand to discovery the
# actual bindir
- bindir = IO.popen(env_for_child,
- [Gem.ruby, '-e', 'puts "#{Gem.user_dir}/bin"']).read
+ bindir = IO.popen(
+ env_for_child,
+ [Gem.ruby, '-e', 'puts "#{Gem.user_dir}/bin"'], # rubocop:disable Lint/InterpolationCheck
+ &:read
+ )
if bindir
@gem_bindir = bindir.chomp
else
raise "FATAL: cannot run #{Gem.ruby} -e 'puts Gem.bindir'"
end
end
- def install
+ def install(bundler_version: self.bundler_version)
if ENV['BUNDLER_GEMFILE']
raise "cannot run autoproj_install or autoproj_bootstrap while "\
- "under a 'bundler exec' subcommand or having loaded an env.sh. "\
- "Open a new console and try again"
+ "under a 'bundler exec' subcommand or having loaded an "\
+ "env.sh. Open a new console and try again"
end
gem_program = self.class.guess_gem_program
puts "Detected 'gem' to be #{gem_program}"
env['GEM_HOME'] = [gems_gem_home]
env['GEM_PATH'] = [gems_gem_home]
- if bundler = find_bundler(gem_program)
+ if (bundler = find_bundler(gem_program, version: bundler_version))
puts "Detected bundler at #{bundler}"
else
puts "Installing bundler in #{gems_gem_home}"
- if !(bundler = install_bundler(gem_program))
- exit 1
- end
+ bundler = install_bundler(gem_program, version: bundler_version)
+ exit(1) unless bundler
end
self.class.rewrite_shims(
File.join(dot_autoproj, 'bin'),
ruby_executable,
root_dir,
@@ -638,11 +699,11 @@
gems_gem_home)
env['PATH'].unshift File.join(dot_autoproj, 'bin')
save_gemfile
puts "Installing autoproj in #{gems_gem_home}"
- install_autoproj(bundler)
+ install_autoproj(bundler, bundler_version: bundler_version)
end
def load_config
v1_config_path = File.join(root_dir, 'autoproj', 'config.yml')
@@ -740,10 +801,15 @@
ENV.delete('BUNDLE_GEMFILE')
ENV.delete('RUBYLIB')
ops = Autoproj::Ops::Install.new(Dir.pwd)
+
+existing_config = File.join(Dir.pwd, '.autoproj', 'config.yml')
+if File.file?(existing_config)
+ puts "Found existing configuration, using it as seed"
+ puts "use --no-seed-config to avoid this behavior"
+ ops.add_seed_config(existing_config)
+end
ops.parse_options(ARGV)
ops.stage1
-if !ops.skip_stage2?
- ops.call_stage2
-end
+ops.call_stage2 unless ops.skip_stage2?