autoproj 2.0.0.rc4 → 2.0.0.rc5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bbe30e7cd487de7bf07f9cf6b19d1766caa87aa4
4
- data.tar.gz: e88e2b24c5e121542212cb253296b7c73fa01681
3
+ metadata.gz: df06bafc27ce59e3c5ad6c46590c44045755f496
4
+ data.tar.gz: 340b8871ba997370ed1b8b6fc526a7388c30de18
5
5
  SHA512:
6
- metadata.gz: bfdabcb92034ade239d6e7df0438b5e4e77b1cf3ad88a1b05d1cdc3e3b265ec351523511b9ca89e878d898928ae64e287d7f3486394e29fcc1e1da77687f3dd6
7
- data.tar.gz: 07506f2a88a2f999b91faa521475bfd203ae24a6f5587f00f3bd1fc49c60865807501f4b205f91bf0cc7abd6840ed58813810d23500b5e5f69d65cbded0b76ef
6
+ metadata.gz: 44b11ccb7dacb6e6dac7f3fad212c5755e5fd00fb2416ef303744333b7c26afa09894af22a755a3ef69dbdc04a4d05f87a556e104ebb87e7fc35c8e67cac1e3b
7
+ data.tar.gz: e65540e5a2a77faf9e10e0a425e5f723ae25737f76575ed0e31b2050e66e6072c2210c0431f90da82e9fa237ef642b5e153c45ff3e62afe032a00afb0960c71f
data/.travis.yml CHANGED
@@ -1,5 +1,9 @@
1
+ sudo: false
1
2
  language: ruby
2
3
  rvm:
3
4
  - 2.0.0
4
5
  - 2.1.6
5
6
  - 2.2.2
7
+ script:
8
+ - bundler exec rake
9
+ - bundler exec rake test
data/bin/alocate CHANGED
@@ -1,6 +1,6 @@
1
1
  #! /usr/bin/env ruby
2
2
 
3
- require 'autoproj/cli/locate'
3
+ require 'autoproj/cli/main'
4
4
  Autoproj::CLI.basic_setup
5
5
  Autoproj::CLI::Main.start(['locate', *ARGV])
6
6
 
data/bin/autoproj CHANGED
@@ -1,11 +1,12 @@
1
1
  #! /usr/bin/env ruby
2
2
 
3
- require 'autoproj'
4
- require 'autoproj/autobuild'
5
3
  require 'autoproj/cli'
6
4
  require 'autoproj/cli/main'
7
5
  Autoproj::CLI.basic_setup
8
6
 
9
- Autoproj::CLI.load_plugins
10
- Autoproj::CLI::Main.start(ARGV)
7
+ argv = ARGV.find_all { |arg| arg != "--no-plugins" }
8
+ if argv.size == ARGV.size
9
+ Autoproj::CLI.load_plugins
10
+ end
11
+ Autoproj::CLI::Main.start(argv)
11
12
 
@@ -5,6 +5,7 @@ if RUBY_VERSION < "1.9.2"
5
5
  exit 1
6
6
  end
7
7
 
8
+ require 'pathname'
8
9
  require 'optparse'
9
10
  require 'fileutils'
10
11
  require 'yaml'
@@ -17,19 +18,65 @@ module Autoproj
17
18
  # It can be required standalone (i.e. does not depend on anything else than
18
19
  # ruby and the ruby standard library)
19
20
  class Install
21
+ class UnexpectedBinstub < RuntimeError; end
22
+
20
23
  # The directory in which to install autoproj
21
24
  attr_reader :root_dir
22
25
  # Content of the Gemfile generated to install autoproj itself
23
26
  attr_accessor :gemfile
27
+ # The environment that is passed to the bundler installs
28
+ attr_reader :env
24
29
 
25
30
  def initialize(root_dir)
26
31
  @root_dir = root_dir
27
- @gemfile = default_gemfile_contents
32
+ if File.file?(autoproj_gemfile_path)
33
+ @gemfile = File.read(autoproj_gemfile_path)
34
+ else
35
+ @gemfile = default_gemfile_contents
36
+ end
37
+
28
38
  @private_bundler = false
29
39
  @private_autoproj = false
30
40
  @private_gems = false
41
+ @local = false
42
+ @env = self.class.clean_env
43
+ end
44
+
45
+ def self.clean_env
46
+ env = Hash.new
47
+ env['RUBYLIB'] = []
48
+ env['GEM_PATH'] = []
49
+ %w{PATH GEM_HOME}.each do |name|
50
+ env[name] = sanitize_env(ENV[name] || "")
51
+ end
52
+ env['BUNDLE_GEMFILE'] = nil
53
+ env
54
+ end
55
+
56
+ def env_for_child
57
+ env.inject(Hash.new) do |h, (k, v)|
58
+ h[k] = (v.join(File::PATH_SEPARATOR) if v && !v.empty?)
59
+ h
60
+ end
61
+ end
62
+
63
+ def self.sanitize_env(value)
64
+ value.split(File::PATH_SEPARATOR).
65
+ find_all { |p| !in_workspace?(p) }
66
+ end
67
+
68
+ def self.in_workspace?(base_dir)
69
+ path = Pathname.new(base_dir)
70
+ while !path.root?
71
+ if (path + ".autoproj").exist? || (path + "autoproj").exist?
72
+ return true
73
+ end
74
+ path = path.parent
75
+ end
76
+ return false
31
77
  end
32
78
 
79
+
33
80
  def dot_autoproj; File.join(root_dir, '.autoproj') end
34
81
  def bin_dir; File.join(dot_autoproj, 'bin') end
35
82
  def bundler_install_dir; File.join(dot_autoproj, 'bundler') end
@@ -38,13 +85,24 @@ module Autoproj
38
85
  def autoproj_gemfile_path; File.join(autoproj_install_dir, 'Gemfile') end
39
86
  def autoproj_config_path; File.join(dot_autoproj, 'config.yml') end
40
87
 
88
+ # Whether we can access the network while installing
89
+ def local?; !!@local end
90
+ # (see #local?)
91
+ def local=(flag); @local = flag end
92
+
41
93
  # Whether bundler should be installed locally in {#dot_autoproj}
42
94
  def private_bundler?; @private_bundler end
95
+ # (see #private_bundler?)
96
+ def private_bundler=(flag); @private_bundler = flag end
43
97
  # Whether autoproj should be installed locally in {#dot_autoproj}
44
98
  def private_autoproj?; @private_autoproj end
99
+ # (see #private_autoproj?)
100
+ def private_autoproj=(flag); @private_autoproj = flag end
45
101
  # Whether bundler should be installed locally in the workspace
46
102
  # prefix directory
47
103
  def private_gems?; @private_gems end
104
+ # (see #private_gems?)
105
+ def private_gems=(flag); @private_gems = flag end
48
106
 
49
107
  def guess_gem_program
50
108
  ruby_bin = RbConfig::CONFIG['RUBY_INSTALL_NAME']
@@ -68,14 +126,18 @@ module Autoproj
68
126
  # @param [String] autoproj_version a constraint on the autoproj version
69
127
  # that should be used
70
128
  # @return [String]
71
- def default_gemfile_contents(autoproj_version = ">= 0")
129
+ def default_gemfile_contents(autoproj_version = ">= 2.0.0.a")
72
130
  ["source \"https://rubygems.org\"",
73
- "gem \"autoproj\", \"#{autoproj_version}\""].join("\n")
131
+ "gem \"autoproj\", \"#{autoproj_version}\"",
132
+ "gem \"utilrb\", \">= 3.0.0.a\""].join("\n")
74
133
  end
75
134
 
76
135
  # Parse the provided command line options and returns the non-options
77
136
  def parse_options(args = ARGV)
78
137
  options = OptionParser.new do |opt|
138
+ opt.on '--local', 'do not access the network (may fail)' do
139
+ @local = true
140
+ end
79
141
  opt.on '--private-bundler', 'install bundler locally in the workspace' do
80
142
  @private_bundler = true
81
143
  end
@@ -104,28 +166,37 @@ module Autoproj
104
166
  gem_program = guess_gem_program
105
167
  puts "Detected 'gem' to be #{gem_program}"
106
168
 
169
+ local = ['--local'] if local?
170
+
107
171
  result = system(
108
- Hash['GEM_PATH' => nil,
109
- 'GEM_HOME' => bundler_install_dir],
172
+ env_for_child.merge('GEM_PATH' => nil, 'GEM_HOME' => bundler_install_dir),
110
173
  gem_program, 'install', '--no-document', '--no-user-install', '--no-format-executable',
174
+ *local,
111
175
  "--bindir=#{File.join(bundler_install_dir, 'bin')}", 'bundler')
112
176
 
113
177
  if !result
114
178
  STDERR.puts "FATAL: failed to install bundler in #{dot_autoproj}"
115
179
  exit 1
116
180
  end
181
+ env['GEM_PATH'] << bundler_install_dir
182
+ env['PATH'] << File.join(bundler_install_dir, 'bin')
117
183
  File.join(bin_dir, 'bundler')
118
184
  end
119
185
 
120
186
  def save_env_sh
121
187
  env = Autobuild::Environment.new
122
- path = []
123
- if private_bundler?
124
- env.push_path 'PATH', File.join(bundler_install_dir, 'bin')
125
- env.push_path 'GEM_PATH', bundler_install_dir
188
+ env.prepare
189
+
190
+ %w{GEM_HOME GEM_PATH}.each do |name|
191
+ value = self.env[name]
192
+ if value.empty?
193
+ env.unset name
194
+ else
195
+ env.set name, *value
196
+ end
126
197
  end
127
198
  env.push_path 'PATH', File.join(autoproj_install_dir, 'bin')
128
- env.inherit 'PATH'
199
+
129
200
  if private_autoproj?
130
201
  env.push_path 'GEM_PATH', autoproj_install_dir
131
202
  end
@@ -149,7 +220,9 @@ export AUTOPROJ_CURRENT_ROOT=#{root_dir}
149
220
  io.write gemfile
150
221
  end
151
222
  end
152
-
223
+
224
+ ENV_BUNDLE_GEMFILE_RX = /^(\s*ENV\[['"]BUNDLE_GEMFILE['"]\]\s*)(?:\|\|)?=/
225
+
153
226
  def install_autoproj(bundler)
154
227
  # Force bundler to update. If the user does not want this, let him specify a
155
228
  # Gemfile with tighter version constraints
@@ -158,24 +231,57 @@ export AUTOPROJ_CURRENT_ROOT=#{root_dir}
158
231
  FileUtils.rm lockfile
159
232
  end
160
233
 
161
- env = Hash['BUNDLE_GEMFILE' => nil, 'RUBYLIB' => nil]
162
234
  opts = Array.new
235
+ opts << '--local' if local?
163
236
 
237
+ env = env_for_child
164
238
  if private_autoproj?
165
- env = Hash['GEM_PATH' => bundler_install_dir,
166
- 'GEM_HOME' => nil]
239
+ env = env.merge(
240
+ 'GEM_PATH' => bundler_install_dir,
241
+ 'GEM_HOME' => nil)
167
242
  opts << "--clean" << "--path=#{autoproj_install_dir}"
168
243
  end
169
244
 
245
+ binstubs_path = File.join(autoproj_install_dir, 'bin')
246
+
170
247
  result = system(env,
171
- bundler, 'install',
248
+ Gem.ruby, bundler, 'install',
172
249
  "--gemfile=#{autoproj_gemfile_path}",
173
- "--binstubs=#{File.join(autoproj_install_dir, 'bin')}",
250
+ "--binstubs=#{binstubs_path}",
174
251
  *opts)
175
252
  if !result
176
253
  STDERR.puts "FATAL: failed to install autoproj in #{dot_autoproj}"
177
254
  exit 1
178
255
  end
256
+
257
+ # Now tune the binstubs to force the usage of the autoproj
258
+ # gemfile. Otherwise, they get BUNDLE_GEMFILE from the
259
+ # environment by default
260
+ Dir.glob(File.join(binstubs_path, '*')) do |path|
261
+ next if !File.file?(path)
262
+ # Do NOT do that for bundler, otherwise it will fail with an
263
+ # "already loaded gemfile" message once we e.g. try to do
264
+ # 'bundler install --gemfile=NEW_GEMFILE'
265
+ next if File.basename(path) == 'bundler'
266
+
267
+ lines = File.readlines(path)
268
+ matched = false
269
+ filtered = lines.map do |l|
270
+ matched ||= (ENV_BUNDLE_GEMFILE_RX === l)
271
+ l.gsub(ENV_BUNDLE_GEMFILE_RX, '\\1=')
272
+ end
273
+ if !matched
274
+ raise UnexpectedBinstub, "expected #{path} to contain a line looking like ENV['BUNDLE_GEMFILE'] ||= but could not find one"
275
+ end
276
+ File.open(path, 'w') do |io|
277
+ io.write filtered.join("")
278
+ end
279
+ end
280
+
281
+ env['PATH'] << File.join(autoproj_install_dir, 'bin')
282
+ if private_autoproj?
283
+ env['GEM_PATH'] << autoproj_install_dir
284
+ end
179
285
  end
180
286
 
181
287
  def update_configuration
@@ -192,25 +298,92 @@ export AUTOPROJ_CURRENT_ROOT=#{root_dir}
192
298
  end
193
299
  end
194
300
 
301
+ def find_in_clean_path(command)
302
+ clean_path = env_for_child['PATH'].split(File::PATH_SEPARATOR)
303
+ clean_path.each do |p|
304
+ full_path = File.join(p, command)
305
+ if File.file?(full_path)
306
+ return full_path
307
+ end
308
+ end
309
+ nil
310
+ end
311
+
312
+ def find_bundler
313
+ clean_env = env_for_child
314
+ Gem.paths = Hash[
315
+ 'GEM_HOME' => clean_env['GEM_HOME'] || Gem.default_dir,
316
+ 'GEM_PATH' => clean_env['GEM_PATH'] || nil
317
+ ]
318
+ # Here, we're getting into the esotheric
319
+ #
320
+ # The problem is that e.g. Ubuntu and Debian install an
321
+ # operating_system.rb file that sets proper OS defaults. Some
322
+ # autoproj installs have it in their RUBYLIB but should not
323
+ # because of limitations of autoproj 1.x. This leads to
324
+ # Gem.bindir being *not* valid for subprocesses
325
+ #
326
+ # So, we're calling 'gem' as a subcommand to discovery the
327
+ # actual bindir
328
+ bindir = IO.popen(clean_env, [Gem.ruby, '-e', 'puts Gem.bindir']).read
329
+ if bindir
330
+ env['PATH'].unshift bindir.chomp
331
+ else
332
+ STDERR.puts "FATAL: cannot run #{Gem.ruby} -e 'puts Gem.bindir'"
333
+ exit 1
334
+ end
335
+
336
+ bundler = find_in_clean_path('bundler')
337
+ if !bundler
338
+ clean_path = env_for_child['PATH']
339
+ STDERR.puts "FATAL: cannot find 'bundler' in PATH=#{clean_path}"
340
+ if ENV['PATH'] != clean_path
341
+ STDERR.puts " it appears that you already have some autoproj-generated env.sh loaded"
342
+ STDERR.puts " - if you are running 'autoproj upgrade', please contact the autoproj author at https://github.com/rock-core/autoproj/issues/new"
343
+ STDERR.puts " - if you are running an install, try again in a console where the env.sh is not loaded"
344
+ exit 1
345
+ else
346
+ STDERR.puts " the recommended action is to install it manually first by running 'gem install bundler'"
347
+ STDERR.puts " or call this command again with --private-bundler to have it installed in the workspace"
348
+ exit 1
349
+ end
350
+ end
351
+ bundler
352
+ end
353
+
195
354
  def install
196
355
  if private_bundler?
197
356
  puts "Installing bundler in #{bundler_install_dir}"
198
357
  bundler = install_bundler
358
+ else
359
+ bundler = find_bundler
360
+ puts "Detected bundler at #{bundler}"
199
361
  end
200
362
  save_gemfile
201
363
  puts "Installing autoproj in #{dot_autoproj}"
202
- install_autoproj(bundler || 'bundler')
364
+ install_autoproj(bundler)
203
365
  end
204
366
 
205
367
  # Actually perform the install
206
- def run
207
- install
208
- ENV['BUNDLE_GEMFILE'] = autoproj_gemfile_path
209
- require 'bundler'
210
- Bundler.setup
211
- require 'autobuild'
212
- save_env_sh
213
- update_configuration
368
+ def run(stage2: false)
369
+ if stage2
370
+ require 'autobuild'
371
+ save_env_sh
372
+ else
373
+ install
374
+
375
+ env_for_child.each do |k, v|
376
+ if v
377
+ ENV[k] = v
378
+ else
379
+ ENV.delete(k)
380
+ end
381
+ end
382
+ ENV['BUNDLE_GEMFILE'] = autoproj_gemfile_path
383
+ update_configuration
384
+ exec Gem.ruby, File.join(autoproj_install_dir, 'bin', 'autoproj'),
385
+ 'install-stage2', root_dir
386
+ end
214
387
  end
215
388
  end
216
389
  end
@@ -219,5 +392,11 @@ end
219
392
 
220
393
 
221
394
  ops = Autoproj::Ops::Install.new(Dir.pwd)
222
- ops.parse_options(ARGV)
395
+ bootstrap_options = ops.parse_options(ARGV)
223
396
  ops.run
397
+
398
+ # we assume that Install#run loads bundler and autobuild. Load autoproj and run
399
+ # bootstrap
400
+ require 'autoproj/cli/main'
401
+ Autoproj::CLI::Main.start(['bootstrap', *bootstrap_options])
402
+
@@ -8,5 +8,11 @@ end
8
8
  AUTOPROJ_OPS_INSTALL
9
9
 
10
10
  ops = Autoproj::Ops::Install.new(Dir.pwd)
11
- ops.parse_options(ARGV)
11
+ bootstrap_options = ops.parse_options(ARGV)
12
12
  ops.run
13
+
14
+ # we assume that Install#run loads bundler and autobuild. Load autoproj and run
15
+ # bootstrap
16
+ require 'autoproj/cli/main'
17
+ Autoproj::CLI::Main.start(['bootstrap', *bootstrap_options])
18
+
data/bin/autoproj_install CHANGED
@@ -5,6 +5,7 @@ if RUBY_VERSION < "1.9.2"
5
5
  exit 1
6
6
  end
7
7
 
8
+ require 'pathname'
8
9
  require 'optparse'
9
10
  require 'fileutils'
10
11
  require 'yaml'
@@ -17,19 +18,65 @@ module Autoproj
17
18
  # It can be required standalone (i.e. does not depend on anything else than
18
19
  # ruby and the ruby standard library)
19
20
  class Install
21
+ class UnexpectedBinstub < RuntimeError; end
22
+
20
23
  # The directory in which to install autoproj
21
24
  attr_reader :root_dir
22
25
  # Content of the Gemfile generated to install autoproj itself
23
26
  attr_accessor :gemfile
27
+ # The environment that is passed to the bundler installs
28
+ attr_reader :env
24
29
 
25
30
  def initialize(root_dir)
26
31
  @root_dir = root_dir
27
- @gemfile = default_gemfile_contents
32
+ if File.file?(autoproj_gemfile_path)
33
+ @gemfile = File.read(autoproj_gemfile_path)
34
+ else
35
+ @gemfile = default_gemfile_contents
36
+ end
37
+
28
38
  @private_bundler = false
29
39
  @private_autoproj = false
30
40
  @private_gems = false
41
+ @local = false
42
+ @env = self.class.clean_env
43
+ end
44
+
45
+ def self.clean_env
46
+ env = Hash.new
47
+ env['RUBYLIB'] = []
48
+ env['GEM_PATH'] = []
49
+ %w{PATH GEM_HOME}.each do |name|
50
+ env[name] = sanitize_env(ENV[name] || "")
51
+ end
52
+ env['BUNDLE_GEMFILE'] = nil
53
+ env
31
54
  end
32
55
 
56
+ def env_for_child
57
+ env.inject(Hash.new) do |h, (k, v)|
58
+ h[k] = (v.join(File::PATH_SEPARATOR) if v && !v.empty?)
59
+ h
60
+ end
61
+ end
62
+
63
+ def self.sanitize_env(value)
64
+ value.split(File::PATH_SEPARATOR).
65
+ find_all { |p| !in_workspace?(p) }
66
+ end
67
+
68
+ def self.in_workspace?(base_dir)
69
+ path = Pathname.new(base_dir)
70
+ while !path.root?
71
+ if (path + ".autoproj").exist? || (path + "autoproj").exist?
72
+ return true
73
+ end
74
+ path = path.parent
75
+ end
76
+ return false
77
+ end
78
+
79
+
33
80
  def dot_autoproj; File.join(root_dir, '.autoproj') end
34
81
  def bin_dir; File.join(dot_autoproj, 'bin') end
35
82
  def bundler_install_dir; File.join(dot_autoproj, 'bundler') end
@@ -38,13 +85,24 @@ module Autoproj
38
85
  def autoproj_gemfile_path; File.join(autoproj_install_dir, 'Gemfile') end
39
86
  def autoproj_config_path; File.join(dot_autoproj, 'config.yml') end
40
87
 
88
+ # Whether we can access the network while installing
89
+ def local?; !!@local end
90
+ # (see #local?)
91
+ def local=(flag); @local = flag end
92
+
41
93
  # Whether bundler should be installed locally in {#dot_autoproj}
42
94
  def private_bundler?; @private_bundler end
95
+ # (see #private_bundler?)
96
+ def private_bundler=(flag); @private_bundler = flag end
43
97
  # Whether autoproj should be installed locally in {#dot_autoproj}
44
98
  def private_autoproj?; @private_autoproj end
99
+ # (see #private_autoproj?)
100
+ def private_autoproj=(flag); @private_autoproj = flag end
45
101
  # Whether bundler should be installed locally in the workspace
46
102
  # prefix directory
47
103
  def private_gems?; @private_gems end
104
+ # (see #private_gems?)
105
+ def private_gems=(flag); @private_gems = flag end
48
106
 
49
107
  def guess_gem_program
50
108
  ruby_bin = RbConfig::CONFIG['RUBY_INSTALL_NAME']
@@ -68,14 +126,18 @@ module Autoproj
68
126
  # @param [String] autoproj_version a constraint on the autoproj version
69
127
  # that should be used
70
128
  # @return [String]
71
- def default_gemfile_contents(autoproj_version = ">= 0")
129
+ def default_gemfile_contents(autoproj_version = ">= 2.0.0.a")
72
130
  ["source \"https://rubygems.org\"",
73
- "gem \"autoproj\", \"#{autoproj_version}\""].join("\n")
131
+ "gem \"autoproj\", \"#{autoproj_version}\"",
132
+ "gem \"utilrb\", \">= 3.0.0.a\""].join("\n")
74
133
  end
75
134
 
76
135
  # Parse the provided command line options and returns the non-options
77
136
  def parse_options(args = ARGV)
78
137
  options = OptionParser.new do |opt|
138
+ opt.on '--local', 'do not access the network (may fail)' do
139
+ @local = true
140
+ end
79
141
  opt.on '--private-bundler', 'install bundler locally in the workspace' do
80
142
  @private_bundler = true
81
143
  end
@@ -104,28 +166,37 @@ module Autoproj
104
166
  gem_program = guess_gem_program
105
167
  puts "Detected 'gem' to be #{gem_program}"
106
168
 
169
+ local = ['--local'] if local?
170
+
107
171
  result = system(
108
- Hash['GEM_PATH' => nil,
109
- 'GEM_HOME' => bundler_install_dir],
172
+ env_for_child.merge('GEM_PATH' => nil, 'GEM_HOME' => bundler_install_dir),
110
173
  gem_program, 'install', '--no-document', '--no-user-install', '--no-format-executable',
174
+ *local,
111
175
  "--bindir=#{File.join(bundler_install_dir, 'bin')}", 'bundler')
112
176
 
113
177
  if !result
114
178
  STDERR.puts "FATAL: failed to install bundler in #{dot_autoproj}"
115
179
  exit 1
116
180
  end
181
+ env['GEM_PATH'] << bundler_install_dir
182
+ env['PATH'] << File.join(bundler_install_dir, 'bin')
117
183
  File.join(bin_dir, 'bundler')
118
184
  end
119
185
 
120
186
  def save_env_sh
121
187
  env = Autobuild::Environment.new
122
- path = []
123
- if private_bundler?
124
- env.push_path 'PATH', File.join(bundler_install_dir, 'bin')
125
- env.push_path 'GEM_PATH', bundler_install_dir
188
+ env.prepare
189
+
190
+ %w{GEM_HOME GEM_PATH}.each do |name|
191
+ value = self.env[name]
192
+ if value.empty?
193
+ env.unset name
194
+ else
195
+ env.set name, *value
196
+ end
126
197
  end
127
198
  env.push_path 'PATH', File.join(autoproj_install_dir, 'bin')
128
- env.inherit 'PATH'
199
+
129
200
  if private_autoproj?
130
201
  env.push_path 'GEM_PATH', autoproj_install_dir
131
202
  end
@@ -149,7 +220,9 @@ export AUTOPROJ_CURRENT_ROOT=#{root_dir}
149
220
  io.write gemfile
150
221
  end
151
222
  end
152
-
223
+
224
+ ENV_BUNDLE_GEMFILE_RX = /^(\s*ENV\[['"]BUNDLE_GEMFILE['"]\]\s*)(?:\|\|)?=/
225
+
153
226
  def install_autoproj(bundler)
154
227
  # Force bundler to update. If the user does not want this, let him specify a
155
228
  # Gemfile with tighter version constraints
@@ -158,24 +231,57 @@ export AUTOPROJ_CURRENT_ROOT=#{root_dir}
158
231
  FileUtils.rm lockfile
159
232
  end
160
233
 
161
- env = Hash['BUNDLE_GEMFILE' => nil, 'RUBYLIB' => nil]
162
234
  opts = Array.new
235
+ opts << '--local' if local?
163
236
 
237
+ env = env_for_child
164
238
  if private_autoproj?
165
- env = Hash['GEM_PATH' => bundler_install_dir,
166
- 'GEM_HOME' => nil]
239
+ env = env.merge(
240
+ 'GEM_PATH' => bundler_install_dir,
241
+ 'GEM_HOME' => nil)
167
242
  opts << "--clean" << "--path=#{autoproj_install_dir}"
168
243
  end
169
244
 
245
+ binstubs_path = File.join(autoproj_install_dir, 'bin')
246
+
170
247
  result = system(env,
171
- bundler, 'install',
248
+ Gem.ruby, bundler, 'install',
172
249
  "--gemfile=#{autoproj_gemfile_path}",
173
- "--binstubs=#{File.join(autoproj_install_dir, 'bin')}",
250
+ "--binstubs=#{binstubs_path}",
174
251
  *opts)
175
252
  if !result
176
253
  STDERR.puts "FATAL: failed to install autoproj in #{dot_autoproj}"
177
254
  exit 1
178
255
  end
256
+
257
+ # Now tune the binstubs to force the usage of the autoproj
258
+ # gemfile. Otherwise, they get BUNDLE_GEMFILE from the
259
+ # environment by default
260
+ Dir.glob(File.join(binstubs_path, '*')) do |path|
261
+ next if !File.file?(path)
262
+ # Do NOT do that for bundler, otherwise it will fail with an
263
+ # "already loaded gemfile" message once we e.g. try to do
264
+ # 'bundler install --gemfile=NEW_GEMFILE'
265
+ next if File.basename(path) == 'bundler'
266
+
267
+ lines = File.readlines(path)
268
+ matched = false
269
+ filtered = lines.map do |l|
270
+ matched ||= (ENV_BUNDLE_GEMFILE_RX === l)
271
+ l.gsub(ENV_BUNDLE_GEMFILE_RX, '\\1=')
272
+ end
273
+ if !matched
274
+ raise UnexpectedBinstub, "expected #{path} to contain a line looking like ENV['BUNDLE_GEMFILE'] ||= but could not find one"
275
+ end
276
+ File.open(path, 'w') do |io|
277
+ io.write filtered.join("")
278
+ end
279
+ end
280
+
281
+ env['PATH'] << File.join(autoproj_install_dir, 'bin')
282
+ if private_autoproj?
283
+ env['GEM_PATH'] << autoproj_install_dir
284
+ end
179
285
  end
180
286
 
181
287
  def update_configuration
@@ -192,25 +298,92 @@ export AUTOPROJ_CURRENT_ROOT=#{root_dir}
192
298
  end
193
299
  end
194
300
 
301
+ def find_in_clean_path(command)
302
+ clean_path = env_for_child['PATH'].split(File::PATH_SEPARATOR)
303
+ clean_path.each do |p|
304
+ full_path = File.join(p, command)
305
+ if File.file?(full_path)
306
+ return full_path
307
+ end
308
+ end
309
+ nil
310
+ end
311
+
312
+ def find_bundler
313
+ clean_env = env_for_child
314
+ Gem.paths = Hash[
315
+ 'GEM_HOME' => clean_env['GEM_HOME'] || Gem.default_dir,
316
+ 'GEM_PATH' => clean_env['GEM_PATH'] || nil
317
+ ]
318
+ # Here, we're getting into the esotheric
319
+ #
320
+ # The problem is that e.g. Ubuntu and Debian install an
321
+ # operating_system.rb file that sets proper OS defaults. Some
322
+ # autoproj installs have it in their RUBYLIB but should not
323
+ # because of limitations of autoproj 1.x. This leads to
324
+ # Gem.bindir being *not* valid for subprocesses
325
+ #
326
+ # So, we're calling 'gem' as a subcommand to discovery the
327
+ # actual bindir
328
+ bindir = IO.popen(clean_env, [Gem.ruby, '-e', 'puts Gem.bindir']).read
329
+ if bindir
330
+ env['PATH'].unshift bindir.chomp
331
+ else
332
+ STDERR.puts "FATAL: cannot run #{Gem.ruby} -e 'puts Gem.bindir'"
333
+ exit 1
334
+ end
335
+
336
+ bundler = find_in_clean_path('bundler')
337
+ if !bundler
338
+ clean_path = env_for_child['PATH']
339
+ STDERR.puts "FATAL: cannot find 'bundler' in PATH=#{clean_path}"
340
+ if ENV['PATH'] != clean_path
341
+ STDERR.puts " it appears that you already have some autoproj-generated env.sh loaded"
342
+ STDERR.puts " - if you are running 'autoproj upgrade', please contact the autoproj author at https://github.com/rock-core/autoproj/issues/new"
343
+ STDERR.puts " - if you are running an install, try again in a console where the env.sh is not loaded"
344
+ exit 1
345
+ else
346
+ STDERR.puts " the recommended action is to install it manually first by running 'gem install bundler'"
347
+ STDERR.puts " or call this command again with --private-bundler to have it installed in the workspace"
348
+ exit 1
349
+ end
350
+ end
351
+ bundler
352
+ end
353
+
195
354
  def install
196
355
  if private_bundler?
197
356
  puts "Installing bundler in #{bundler_install_dir}"
198
357
  bundler = install_bundler
358
+ else
359
+ bundler = find_bundler
360
+ puts "Detected bundler at #{bundler}"
199
361
  end
200
362
  save_gemfile
201
363
  puts "Installing autoproj in #{dot_autoproj}"
202
- install_autoproj(bundler || 'bundler')
364
+ install_autoproj(bundler)
203
365
  end
204
366
 
205
367
  # Actually perform the install
206
- def run
207
- install
208
- ENV['BUNDLE_GEMFILE'] = autoproj_gemfile_path
209
- require 'bundler'
210
- Bundler.setup
211
- require 'autobuild'
212
- save_env_sh
213
- update_configuration
368
+ def run(stage2: false)
369
+ if stage2
370
+ require 'autobuild'
371
+ save_env_sh
372
+ else
373
+ install
374
+
375
+ env_for_child.each do |k, v|
376
+ if v
377
+ ENV[k] = v
378
+ else
379
+ ENV.delete(k)
380
+ end
381
+ end
382
+ ENV['BUNDLE_GEMFILE'] = autoproj_gemfile_path
383
+ update_configuration
384
+ exec Gem.ruby, File.join(autoproj_install_dir, 'bin', 'autoproj'),
385
+ 'install-stage2', root_dir
386
+ end
214
387
  end
215
388
  end
216
389
  end