autoproj 2.11.0 → 2.12.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -13,8 +13,13 @@ require 'autoproj/ops/install'
13
13
  ENV.delete('BUNDLE_GEMFILE')
14
14
  ENV.delete('RUBYLIB')
15
15
  ops = Autoproj::Ops::Install.new(Dir.pwd)
16
+
17
+ existing_config = File.join(Dir.pwd, '.autoproj', 'config.yml')
18
+ if File.file?(existing_config)
19
+ puts "Found existing configuration, using it as seed"
20
+ puts "use --no-seed-config to avoid this behavior"
21
+ ops.add_seed_config(existing_config)
22
+ end
16
23
  ops.parse_options(ARGV)
17
24
  ops.stage1
18
- if !ops.skip_stage2?
19
- ops.call_stage2
20
- end
25
+ ops.call_stage2 unless ops.skip_stage2?
@@ -44,6 +44,7 @@
44
44
  require 'autoproj/source_package_query'
45
45
  require 'autoproj/os_package_query'
46
46
 
47
+ require 'autoproj/ops/phase_reporting'
47
48
  require 'autoproj/ops/install'
48
49
  require 'autoproj/ops/tools'
49
50
  require 'autoproj/ops/loader'
@@ -149,11 +149,13 @@ def ignore(*paths)
149
149
 
150
150
  # Adds a new setup block to an existing package
151
151
  def setup_package(package_name, workspace: Autoproj.workspace, &block)
152
- raise ConfigError.new, "you must give a block to #setup_package" unless block
152
+ unless block
153
+ raise Autoproj::ConfigError.new, 'you must give a block to #setup_package'
154
+ end
153
155
 
154
156
  package_definition = workspace.manifest.find_package_definition(package_name)
155
157
  if !package_definition
156
- raise ConfigError.new, "#{package_name} is not a known package"
158
+ raise Autoproj::ConfigError.new, "#{package_name} is not a known package"
157
159
  elsif package_definition.autobuild.kind_of?(Autobuild::DummyPackage)
158
160
  # Nothing to do!
159
161
  else
@@ -56,4 +56,22 @@ def self.post_import(*packages, &block)
56
56
  end
57
57
  end
58
58
  end
59
+
60
+ # Shim for a smooth upgrade path to bundler 2.1+
61
+ def self.bundler_unbundled_system(*args, **options)
62
+ if Bundler.respond_to?(:unbundled_system)
63
+ Bundler.unbundled_system(*args, **options)
64
+ else
65
+ Bundler.clean_system(*args, **options)
66
+ end
67
+ end
68
+
69
+ # Shim for a smooth upgrade path to bundler 2.1+
70
+ def self.bundler_with_unbundled_env(&block)
71
+ if Bundler.respond_to?(:with_unbundled_env)
72
+ Bundler.with_unbundled_env(&block)
73
+ else
74
+ Bundler.with_clean_env(&block)
75
+ end
76
+ end
59
77
  end
@@ -10,21 +10,50 @@ def validate_options(argv, options = Hash.new)
10
10
  if argv.empty?
11
11
  default_cache_dirs = Autobuild::Importer.default_cache_dirs
12
12
  if !default_cache_dirs || default_cache_dirs.empty?
13
- raise CLIInvalidArguments, "no cache directory defined with e.g. the AUTOBUILD_CACHE_DIR environment variable, expected one cache directory as argument"
13
+ raise CLIInvalidArguments,
14
+ "no cache directory defined with e.g. the "\
15
+ "AUTOBUILD_CACHE_DIR environment variable, "\
16
+ "expected one cache directory as argument"
14
17
  end
15
- Autoproj.warn "using cache directory #{default_cache_dirs.first} from the autoproj configuration"
18
+ Autoproj.warn "using cache directory #{default_cache_dirs.first} "\
19
+ "from the autoproj configuration"
16
20
  argv << default_cache_dirs.first
17
21
  end
18
22
 
19
- return File.expand_path(argv.first, ws.root_dir), *argv[1..-1], options
23
+ if (compile = options[:gems_compile])
24
+ options[:gems_compile] = compile.map do |name|
25
+ name, *artifacts = name.split('+')
26
+ [name, artifacts: artifacts]
27
+ end
28
+ end
29
+
30
+ [File.expand_path(argv.first, ws.root_dir), *argv[1..-1], options]
20
31
  end
21
32
 
22
- def run(cache_dir, *package_names, all: true, keep_going: false, checkout_only: false)
33
+ def run(cache_dir, *package_names,
34
+ keep_going: false,
35
+ packages: true, all: true, checkout_only: false,
36
+ gems: false, gems_compile: [], gems_compile_force: false)
23
37
  initialize_and_load
24
38
  finalize_setup
25
39
 
26
- cache_op = Autoproj::Ops::Cache.new(cache_dir, ws.manifest)
27
- cache_op.create_or_update(*package_names, all: all, keep_going: keep_going, checkout_only: checkout_only)
40
+ cache_op = Autoproj::Ops::Cache.new(cache_dir, ws)
41
+ if packages
42
+ cache_op.create_or_update(
43
+ *package_names,
44
+ all: all, keep_going: keep_going,
45
+ checkout_only: checkout_only
46
+ )
47
+ end
48
+
49
+ if gems
50
+ Autoproj.message "caching gems in #{cache_op.gems_cache_dir}"
51
+ cache_op.create_or_update_gems(
52
+ keep_going: keep_going,
53
+ compile: gems_compile,
54
+ compile_force: gems_compile_force
55
+ )
56
+ end
28
57
  end
29
58
  end
30
59
  end
@@ -300,13 +300,34 @@ def build(*packages)
300
300
  end
301
301
  end
302
302
 
303
- desc 'cache CACHE_DIR', 'create or update a cache directory that can be given to AUTOBUILD_CACHE_DIR'
304
- option :keep_going, aliases: :k,
305
- desc: 'do not stop on errors'
306
- option :checkout_only, aliases: :c, type: :boolean, default: false,
307
- desc: "only checkout packages, do not update already-cached ones"
308
- option :all, type: :boolean, default: true,
309
- desc: "cache all defined packages (the default) or only the selected ones"
303
+ desc 'cache CACHE_DIR', 'create or update a cache directory that '\
304
+ 'can be given to AUTOBUILD_CACHE_DIR'
305
+ option :keep_going,
306
+ aliases: :k,
307
+ desc: 'do not stop on errors'
308
+ option :checkout_only,
309
+ aliases: :c, type: :boolean, default: false,
310
+ desc: 'only checkout packages, do not update already-cached ones'
311
+ option :all,
312
+ type: :boolean, default: true,
313
+ desc: 'cache all defined packages (the default), '\
314
+ ' or only the selected ones'
315
+ option :packages,
316
+ type: :boolean, default: true,
317
+ desc: 'update the package cache'
318
+ option :gems,
319
+ type: :boolean, default: false,
320
+ desc: 'update the gems cache'
321
+ option :gems_compile_force,
322
+ type: :boolean, default: false,
323
+ desc: 'with --gems-compile, recompile existing gems as well'
324
+ option :gems_compile,
325
+ type: :array,
326
+ desc: 'pre-compile the following gems. This requires gem-compiler '\
327
+ 'to be available in the workspace. Use GEM_NAME+ARTIFACT'\
328
+ '[+ARTIFACT] to add files or directories to the precompiled '\
329
+ 'gems beyond what gem-compiler auto-adds (which is mostly '\
330
+ 'dynamic libraries)'
310
331
  def cache(*args)
311
332
  run_autoproj_cli(:cache, :Cache, Hash[], *args)
312
333
  end
@@ -10,7 +10,7 @@ def initialize(ws = Workspace.default,
10
10
  end
11
11
 
12
12
  def package_metadata(package)
13
- u = package.autobuild.test_utility
13
+ u = package.test_utility
14
14
  super.merge(
15
15
  'coverage_available' => !!u.coverage_available?,
16
16
  'coverage_enabled' => !!u.coverage_enabled?,
@@ -89,24 +89,37 @@ def run(user_selection, options = {})
89
89
  raise CLIInvalidArguments, "autoproj: the provided package "\
90
90
  "is not selected for build"
91
91
  end
92
+ return if package_names.empty?
92
93
 
93
94
  packages = package_names.map do |pkg_name|
94
95
  ws.manifest.find_package_definition(pkg_name)
95
96
  end
96
97
 
98
+ apply_to_packages(packages, parallel: options[:parallel])
99
+ end
100
+
101
+ def apply_to_packages(packages, parallel: ws.config.parallel_build_level)
102
+ if @report_path
103
+ reporting = Ops::PhaseReporting.new(
104
+ @utility_name, @report_path,
105
+ method(:package_metadata)
106
+ )
107
+ end
108
+
109
+ reporting&.initialize_incremental_report
97
110
  Autobuild.apply(
98
- package_names,
99
- "autoproj-#{utility_name}",
100
- [utility_name],
101
- parallel: options[:parallel]
102
- )
111
+ packages.map(&:name), "autoproj-#{@utility_name}",
112
+ [@utility_name], parallel: parallel
113
+ ) do |pkg, phase|
114
+ reporting&.report_incremental(pkg) if phase == utility_name
115
+ end
103
116
 
104
117
  ensure
105
- create_report(packages) if packages && @report_path
118
+ reporting&.create_report(packages.map(&:autobuild))
106
119
  end
107
120
 
108
- def package_metadata(package)
109
- u = package.autobuild.utility(@utility_name)
121
+ def package_metadata(autobuild_package)
122
+ u = autobuild_package.utility(@utility_name)
110
123
  {
111
124
  'source_dir' => u.source_dir,
112
125
  'target_dir' => u.target_dir,
@@ -117,23 +130,6 @@ def package_metadata(package)
117
130
  'installed' => !!u.installed?,
118
131
  }
119
132
  end
120
-
121
- def create_report(packages)
122
- info = packages.each_with_object({}) do |p, map|
123
- map[p.name] = package_metadata(p)
124
- end
125
-
126
- FileUtils.mkdir_p File.dirname(@report_path)
127
- File.open(@report_path, 'w') do |io|
128
- dump = JSON.dump(
129
- "#{@utility_name}_report" => {
130
- 'timestamp' => Time.now,
131
- 'packages' => info
132
- }
133
- )
134
- io.write dump
135
- end
136
- end
137
133
  end
138
134
  end
139
135
  end
@@ -196,7 +196,9 @@ def configure(option_name)
196
196
  Autoproj.info " using: #{value} (noninteractive mode)"
197
197
  end
198
198
  @modified = true
199
- if !is_default
199
+ if is_default
200
+ value = opt.validate(value)
201
+ else
200
202
  config[option_name] = [value, true]
201
203
  displayed_options[option_name] = value
202
204
  end
@@ -353,6 +355,10 @@ def shell_helpers=(flag)
353
355
  set 'shell_helpers', flag, true
354
356
  end
355
357
 
358
+ def bundler_version
359
+ get 'bundler_version', nil
360
+ end
361
+
356
362
  def apply_autobuild_configuration
357
363
  if has_value_for?('autobuild')
358
364
  params = get('autobuild')
@@ -369,6 +375,11 @@ def importer_cache_dir
369
375
  get('importer_cache_dir', nil)
370
376
  end
371
377
 
378
+ # Set import and gem cache directory
379
+ def importer_cache_dir=(path)
380
+ set('importer_cache_dir', path, true)
381
+ end
382
+
372
383
  # Sets the directory in which packages will be installed
373
384
  def prefix_dir=(path)
374
385
  set('prefix', path, true)
@@ -1,7 +1,8 @@
1
1
  module Autoproj
2
2
  # Manifest of installed packages imported from another autoproj installation
3
3
  class InstallationManifest
4
- Package = Struct.new :name, :type, :vcs, :srcdir, :prefix, :builddir, :logdir, :dependencies
4
+ Package = Struct.new :name, :type, :vcs, :srcdir, :importdir,
5
+ :prefix, :builddir, :logdir, :dependencies
5
6
  PackageSet = Struct.new :name, :vcs, :raw_local_dir, :user_local_dir
6
7
 
7
8
  attr_reader :path
@@ -28,11 +29,11 @@ def add_package_set(pkg_set)
28
29
  def each_package_set(&block)
29
30
  package_sets.each_value(&block)
30
31
  end
31
-
32
+
32
33
  def each_package(&block)
33
34
  packages.each_value(&block)
34
35
  end
35
-
36
+
36
37
  def load
37
38
  @packages = Hash.new
38
39
  raw = YAML.load(File.open(path))
@@ -51,8 +52,8 @@ def load
51
52
  package_sets[pkg_set.name] = pkg_set
52
53
  else
53
54
  pkg = Package.new(
54
- entry['name'], entry['type'], entry['vcs'], entry['srcdir'], entry['prefix'],
55
- entry['builddir'], entry['logdir'], entry['dependencies'])
55
+ entry['name'], entry['type'], entry['vcs'], entry['srcdir'], entry['importdir'],
56
+ entry['prefix'], entry['builddir'], entry['logdir'], entry['dependencies'])
56
57
  packages[pkg.name] = pkg
57
58
  end
58
59
  end
@@ -74,6 +75,7 @@ def save(path = self.path)
74
75
  'type' => v.class.name,
75
76
  'vcs' => package_def.vcs.to_hash,
76
77
  'srcdir' => v.srcdir,
78
+ 'importdir' => (v.importdir if v.respond_to?(:importdir)),
77
79
  'builddir' => (v.builddir if v.respond_to?(:builddir)),
78
80
  'logdir' => v.logdir,
79
81
  'prefix' => v.prefix,
@@ -87,34 +87,36 @@ def force_build_packages(selected_packages, all_enabled_packages)
87
87
  # names of the packages that should be rebuilt
88
88
  # @return [void]
89
89
  def build_packages(all_enabled_packages, options = Hash.new)
90
+ if @report_path
91
+ reporting = Ops::PhaseReporting.new(
92
+ 'build', @report_path, method(:package_metadata)
93
+ )
94
+ end
95
+
90
96
  Autobuild.do_rebuild = false
91
97
  Autobuild.do_forced_build = false
98
+ reporting&.initialize_incremental_report
92
99
  begin
93
- Autobuild.apply(all_enabled_packages, "autoproj-build", ['build'], options)
100
+ Autobuild.apply(
101
+ all_enabled_packages,
102
+ "autoproj-build", ['build'], options
103
+ ) do |pkg, phase|
104
+ reporting&.report_incremental(pkg) if phase == 'build'
105
+ end
106
+
94
107
  ensure
95
- create_report(all_enabled_packages) if @report_path
108
+ packages = all_enabled_packages.map do |name|
109
+ @manifest.find_autobuild_package(name)
110
+ end
111
+ reporting&.create_report(packages)
96
112
  end
97
113
  end
98
114
 
99
- def create_report(package_list)
100
- FileUtils.mkdir_p File.dirname(@report_path)
101
-
102
- packages = package_list.each_with_object({}) do |pkg_name, h|
103
- pkg = manifest.find_autobuild_package(pkg_name)
104
-
105
- h[pkg.name] = {
106
- invoked: !!pkg.install_invoked?,
107
- success: !!pkg.installed?
108
- }
109
- end
110
-
111
- report = JSON.pretty_generate({
112
- build_report: {
113
- timestamp: Time.now,
114
- packages: packages
115
- }
116
- })
117
- IO.write(@report_path, report)
115
+ def package_metadata(autobuild_package)
116
+ {
117
+ invoked: !!autobuild_package.install_invoked?,
118
+ success: !!autobuild_package.installed?
119
+ }
118
120
  end
119
121
  end
120
122
  end
@@ -4,9 +4,10 @@ class Cache
4
4
  attr_reader :cache_dir
5
5
  attr_reader :manifest
6
6
 
7
- def initialize(cache_dir, manifest)
7
+ def initialize(cache_dir, ws)
8
8
  @cache_dir = cache_dir
9
- @manifest = manifest
9
+ @ws = ws
10
+ @manifest = ws.manifest
10
11
  end
11
12
 
12
13
  def with_retry(count)
@@ -27,29 +28,39 @@ def git_cache_dir
27
28
  File.join(cache_dir, 'git')
28
29
  end
29
30
 
30
- def cache_git(pkg, options = Hash.new)
31
+ def cache_git(pkg, checkout_only: false)
31
32
  pkg.importdir = File.join(git_cache_dir, pkg.name)
32
- if options[:checkout_only] && File.directory?(pkg.importdir)
33
- return
34
- end
33
+ return if checkout_only && File.directory?(pkg.importdir)
35
34
 
36
35
  pkg.importer.local_branch = nil
37
36
  pkg.importer.remote_branch = nil
38
37
  pkg.importer.remote_name = 'autobuild'
39
38
 
40
- if !File.directory?(pkg.importdir)
39
+ unless File.directory?(pkg.importdir)
41
40
  FileUtils.mkdir_p File.dirname(pkg.importdir)
42
- Autobuild::Subprocess.run("autoproj-cache", "import", Autobuild.tool(:git), "--git-dir", pkg.importdir, 'init', "--bare")
41
+ Autobuild::Subprocess.run(
42
+ "autoproj-cache", "import", Autobuild.tool(:git),
43
+ "--git-dir", pkg.importdir, 'init', "--bare"
44
+ )
43
45
  end
44
46
  pkg.importer.update_remotes_configuration(pkg)
45
47
 
46
48
  with_retry(10) do
47
- Autobuild::Subprocess.run('autoproj-cache', :import, Autobuild.tool('git'), '--git-dir', pkg.importdir, 'remote', 'update', 'autobuild')
49
+ Autobuild::Subprocess.run(
50
+ 'autoproj-cache', :import, Autobuild.tool('git'),
51
+ '--git-dir', pkg.importdir, 'remote', 'update', 'autobuild'
52
+ )
48
53
  end
49
54
  with_retry(10) do
50
- Autobuild::Subprocess.run('autoproj-cache', :import, Autobuild.tool('git'), '--git-dir', pkg.importdir, 'fetch', 'autobuild', '--tags')
55
+ Autobuild::Subprocess.run(
56
+ 'autoproj-cache', :import, Autobuild.tool('git'),
57
+ '--git-dir', pkg.importdir, 'fetch', 'autobuild', '--tags'
58
+ )
51
59
  end
52
- Autobuild::Subprocess.run('autoproj-cache', :import, Autobuild.tool('git'), '--git-dir', pkg.importdir, 'gc', '--prune=all')
60
+ Autobuild::Subprocess.run(
61
+ 'autoproj-cache', :import, Autobuild.tool('git'),
62
+ '--git-dir', pkg.importdir, 'gc', '--prune=all'
63
+ )
53
64
  end
54
65
 
55
66
  def archive_cache_dir
@@ -63,7 +74,8 @@ def cache_archive(pkg)
63
74
  end
64
75
  end
65
76
 
66
- def create_or_update(*package_names, all: true, keep_going: false, checkout_only: false)
77
+ def create_or_update(*package_names, all: true, keep_going: false,
78
+ checkout_only: false)
67
79
  FileUtils.mkdir_p cache_dir
68
80
 
69
81
  if package_names.empty?
@@ -75,7 +87,7 @@ def create_or_update(*package_names, all: true, keep_going: false, checkout_only
75
87
  end
76
88
  else
77
89
  packages = package_names.map do |name|
78
- if pkg = manifest.find_autobuild_package(name)
90
+ if (pkg = manifest.find_autobuild_package(name))
79
91
  pkg
80
92
  else
81
93
  raise PackageNotFound, "no package named #{name}"
@@ -88,7 +100,10 @@ def create_or_update(*package_names, all: true, keep_going: false, checkout_only
88
100
  total = packages.size
89
101
  Autoproj.message "Handling #{total} packages"
90
102
  packages.each_with_index do |pkg, i|
91
- next if pkg.srcdir != pkg.importdir # No need to process this one, it is uses another package's import
103
+ # No need to process this one, it is uses another package's
104
+ # import
105
+ next if pkg.srcdir != pkg.importdir
106
+
92
107
  begin
93
108
  case pkg.importer
94
109
  when Autobuild::Git
@@ -103,27 +118,117 @@ def create_or_update(*package_names, all: true, keep_going: false, checkout_only
103
118
  rescue Interrupt
104
119
  raise
105
120
  rescue ::Exception => e
106
- if keep_going
107
- pkg.error " failed to cache #{pkg.name}, but going on as requested"
108
- lines = e.to_s.split("\n")
109
- if lines.empty?
110
- lines = e.message.split("\n")
111
- end
112
- if lines.empty?
113
- lines = ["unknown error"]
114
- end
115
- pkg.message(lines.shift, :red, :bold)
116
- lines.each do |line|
117
- pkg.message(line)
121
+ raise unless keep_going
122
+
123
+ pkg.error " failed to cache #{pkg.name}, "\
124
+ 'but going on as requested'
125
+ lines = e.to_s.split('\n')
126
+ lines = e.message.split('\n') if lines.empty?
127
+ lines = ['unknown error'] if lines.empty?
128
+ pkg.message(lines.shift, :red, :bold)
129
+ lines.each do |line|
130
+ pkg.message(line)
131
+ end
132
+ nil
133
+ end
134
+ end
135
+ end
136
+
137
+ def gems_cache_dir
138
+ File.join(cache_dir, 'package_managers', 'gem')
139
+ end
140
+
141
+ def create_or_update_gems(keep_going: true, compile_force: false, compile: [])
142
+ # Note: this might directly copy into the cache directoy, and
143
+ # we support it later
144
+ cache_dir = File.join(@ws.prefix_dir, 'gems', 'vendor', 'cache')
145
+ PackageManagers::BundlerManager.run_bundler(
146
+ @ws, 'cache'
147
+ )
148
+
149
+ FileUtils.mkdir_p(gems_cache_dir) unless File.exist?(gems_cache_dir)
150
+
151
+ needs_copy =
152
+ if File.exist?(cache_dir)
153
+ real_cache_dir = File.realpath(cache_dir)
154
+ real_target_dir = File.realpath(gems_cache_dir)
155
+ (real_cache_dir != real_target_dir)
156
+ end
157
+
158
+ synchronize_gems_cache_dirs(real_cache_dir, real_target_dir) if needs_copy
159
+
160
+ platform_suffix = "-#{Gem::Platform.local}.gem"
161
+ failed = []
162
+ compile.each do |gem_name, artifacts: []|
163
+ Dir.glob(File.join(cache_dir, "#{gem_name}*.gem")) do |gem|
164
+ next if gem.end_with?(platform_suffix)
165
+
166
+ gem_basename = File.basename(gem, ".gem")
167
+ expected_platform_gem = File.join(
168
+ real_target_dir, "#{gem_basename}#{platform_suffix}"
169
+ )
170
+ next if !compile_force && File.file?(expected_platform_gem)
171
+
172
+ begin
173
+ compile_gem(gem, artifacts: artifacts, output: real_target_dir)
174
+ rescue CompilationFailed
175
+ unless keep_going
176
+ raise CompilationFailed, "#{gem} failed to compile"
118
177
  end
119
- nil
120
- else
121
- raise
178
+
179
+ failed << gem
122
180
  end
123
181
  end
124
182
  end
183
+
184
+ unless failed.empty?
185
+ raise CompilationFailed, "#{failed.sort.join(', ')} failed to compile"
186
+ end
187
+ end
188
+
189
+ class CompilationFailed < RuntimeError; end
190
+
191
+ def synchronize_gems_cache_dirs(source, target)
192
+ Dir.glob(File.join(source, "*.gem")) do |source_file|
193
+ basename = File.basename(source_file)
194
+ target_file = File.join(target, basename)
195
+ next if File.file?(target_file)
196
+
197
+ Autoproj.message "gems: caching #{basename}"
198
+ FileUtils.cp source_file, target_file
199
+ end
200
+ end
201
+
202
+ def guess_gem_program
203
+ if Autobuild.programs['gem']
204
+ return Autobuild.programs['gem']
205
+ end
206
+
207
+ ruby_bin = RbConfig::CONFIG['RUBY_INSTALL_NAME']
208
+ ruby_bindir = RbConfig::CONFIG['bindir']
209
+
210
+ candidates = ['gem']
211
+ if ruby_bin =~ /^ruby(.+)$/
212
+ candidates << "gem#{$1}"
213
+ end
214
+
215
+ candidates.each do |gem_name|
216
+ if File.file?(gem_full_path = File.join(ruby_bindir, gem_name))
217
+ Autobuild.programs['gem'] = gem_full_path
218
+ return Autobuild.programs['gem']
219
+ end
220
+ end
221
+
222
+ raise ArgumentError, "cannot find a gem program (tried #{candidates.sort.join(", ")} in #{ruby_bindir})"
223
+ end
224
+
225
+ private def compile_gem(gem_path, output:, artifacts: [])
226
+ artifacts = artifacts.flat_map { |n| ["--artifact", n] }
227
+ unless system(Autobuild.tool('ruby'), '-S', guess_gem_program,
228
+ 'compile', '--output', output, *artifacts, gem_path)
229
+ raise CompilationFailed, "#{gem_path} failed to compile"
230
+ end
125
231
  end
126
232
  end
127
233
  end
128
234
  end
129
-