bundler-source-pathext 0.2.1 → 0.3.0

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
  SHA256:
3
- metadata.gz: cdeaf53514088b07fa6fa9f2855330f37bb35f267b22b91204e82825c1935244
4
- data.tar.gz: 2bf8c27185fcfae260b11a35e0d19db9145e710a29354ac37e1860e47efcde17
3
+ metadata.gz: c60ff2869c3dd24a8af2baf53c12732d91ab94f7e0da7118ee89d69564c2fd60
4
+ data.tar.gz: dbb33d23f6d3958b156c6d3549f5faaecabd2955ed2a056258af62b48577c500
5
5
  SHA512:
6
- metadata.gz: 03d30d6b285753b0c0a094f2c452ba5df46e5ccbb304236c16a8ed8c772a6befea680f43d652627d6b4ea41e580bc4e694fe1a10e9bb1573f6535ac5606e0163
7
- data.tar.gz: 38defcddfe6be5be21844a8bad420279bc761c85622e10c77e2b95686dfc38be910162b36ab0fabe607a79ae95342d8212256d6ad4894504779818ffa0fd24dc
6
+ metadata.gz: a39f6d46858cd5a27108e937cb30a57238d3d73170a4151ec0511b9c5e2a63146921d65a1f4d27abb9d24cf65608456a97cfca8958f1f4cc558301747431d707
7
+ data.tar.gz: '0883191629d3506483e81fbeb2ed687ba666a79eb5c5034e16d5d0c1deea2bd14a49d013938359584304a498a4fdb4fb4c98bf07fd24660d74f57144ca02ef00'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bundler-source-pathext (0.2.0)
4
+ bundler-source-pathext (0.3.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -14,7 +14,7 @@ source './folder', type: 'pathext' do
14
14
  end
15
15
  ```
16
16
 
17
- Different from Rubygems, this plugin will prefer `rake compile` when an extension has a Rakefile, only falling back to the [Gem::Ext::Builder](https://github.com/ruby/rubygems/blob/master/lib/rubygems/ext/builder.rb) (or [other builders](https://github.com/ruby/rubygems/blob/master/lib/rubygems/ext/builder.rb#L173)) if needed. This is aimed at making debugging easier.
17
+ Different from Rubygems, this plugin uses a modified version of [Gem::Ext::Builder](https://github.com/ruby/rubygems/blob/master/lib/rubygems/ext/builder.rb) for Ruby extensions with an "extconf" folder, that does not create an additional copy of the created binaries in the extension install folder. This is done to avoid caching issues where the version in the extension install folder gets stale.
18
18
 
19
19
  ## LICENSE
20
20
 
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "bundler-source-pathext"
3
- spec.version = "0.2.1"
3
+ spec.version = "0.3.0"
4
4
  spec.authors = ["pganalyze Team"]
5
5
  spec.email = ["team@pganalyze.com"]
6
6
 
data/plugins.rb CHANGED
@@ -1,4 +1,7 @@
1
1
  class BundlerSourcePathext < Bundler::Plugin::API
2
+ HAS_TARGET_RBCONFIG = Gem.rubygems_version >= Gem::Version.new("3.6")
3
+ HAS_NJOBS = Gem.rubygems_version >= Gem::Version.new("4.0.2")
4
+
2
5
  class PathExtSource < Bundler::Source
3
6
  def install(spec, opts)
4
7
  print_using_message "Using #{spec.name} #{spec.version} from #{self}"
@@ -87,39 +90,41 @@ class BundlerSourcePathext < Bundler::Plugin::API
87
90
 
88
91
  dest_path = spec.extension_dir
89
92
  start = Time.now
90
- load_dir = File.dirname(spec.loaded_from)
91
93
 
92
- success = true
93
94
  spec.extensions.each do |extension|
94
- if extension[/extconf/] && File.exist?(File.join(load_dir, 'Rakefile'))
95
- rake_args = ['compile']
96
- builder.class.run(rake + rake_args, [], 'rake compile (via ' + self.class.to_s + ')', load_dir) do |status, results|
97
- unless status.success?
98
- success = false
99
- puts results
100
- end
101
- end
102
- else
103
- builder.build_extension extension, dest_path
104
- end
95
+ builder_for_ext = if extension[/extconf/]
96
+ ExtConfAlwaysCopyBuilder
97
+ else
98
+ builder.builder_for(extension)
99
+ end
100
+
101
+ # This throws a Gem::Ext::BuildError if building the extension fails
102
+ build_extension spec, builder, builder_for_ext, extension, dest_path
105
103
  end
106
- puts format(' Finished after %0.2f seconds', Time.now - start)
107
- FileUtils.touch(spec.gem_build_complete_path) if success
104
+ puts format(' Finished %s after %0.2f seconds', spec.name, Time.now - start)
105
+ FileUtils.touch(spec.gem_build_complete_path)
108
106
  end
109
107
 
110
- def rake
111
- rake = ENV["rake"]
108
+ def build_extension(spec, builder, builder_for_ext, extension, dest_path) # :nodoc:
109
+ results = []
112
110
 
113
- if rake
114
- rake = Shellwords.split(rake)
115
- else
116
- begin
117
- rake = Gem::Ext::Builder.ruby << "-rrubygems" << Gem.bin_path("rake", "rake")
118
- rescue Gem::Exception
119
- rake = [Gem.default_exec_format % "rake"]
120
- end
111
+ extension_dir =
112
+ File.expand_path File.join(spec.full_gem_path, File.dirname(extension))
113
+ lib_dir = File.join spec.full_gem_path, spec.raw_require_paths.first
114
+
115
+ begin
116
+ FileUtils.mkdir_p dest_path
117
+
118
+ results = builder_for_ext.build(extension, dest_path,
119
+ results, @build_args, lib_dir, extension_dir)
120
+
121
+ builder.verbose { results.join("\n") }
122
+
123
+ builder.write_gem_make_out results.join "\n"
124
+ rescue StandardError => e
125
+ results << e.message
126
+ builder.build_error(results.join("\n"), $@)
121
127
  end
122
- rake
123
128
  end
124
129
 
125
130
  def generate_bin(spec, options = {})
@@ -161,4 +166,101 @@ class BundlerSourcePathext < Bundler::Plugin::API
161
166
  end
162
167
 
163
168
  source 'pathext', PathExtSource
169
+
170
+ # Modified version of Gem::Ext::ExtConfBuilder that always copies the built binary
171
+ # to the destination path. This is necessary because when using local gems we cannot
172
+ # rely on versions being bumped when the gem changes.
173
+ require 'rubygems/ext'
174
+ class ExtConfAlwaysCopyBuilder < Gem::Ext::Builder
175
+ def self.build(extension, dest_path, results, args = [], lib_dir = nil, extension_dir = Dir.pwd,
176
+ target_rbconfig = nil, n_jobs: nil)
177
+ require "fileutils"
178
+ require "tempfile"
179
+
180
+ target_rbconfig ||= Gem.target_rbconfig if HAS_TARGET_RBCONFIG
181
+
182
+ tmp_dest = Dir.mktmpdir(".gem.", extension_dir)
183
+
184
+ # Some versions of `mktmpdir` return absolute paths, which will break make
185
+ # if the paths contain spaces.
186
+ #
187
+ # As such, we convert to a relative path.
188
+ tmp_dest_relative = get_relative_path(tmp_dest.clone, extension_dir)
189
+
190
+ destdir = ENV["DESTDIR"]
191
+
192
+ begin
193
+ cmd = ruby << File.basename(extension)
194
+ cmd << "--target-rbconfig=#{target_rbconfig.path}" if HAS_TARGET_RBCONFIG && target_rbconfig.path
195
+ cmd.push(*args)
196
+
197
+ run(cmd, results, 'ExtConfAlwaysCopy', extension_dir) do |s, r|
198
+ mkmf_log = File.join(extension_dir, "mkmf.log")
199
+ if File.exist? mkmf_log
200
+ unless s.success?
201
+ r << "To see why this extension failed to compile, please check" \
202
+ " the mkmf.log which can be found here:\n"
203
+ r << " " + File.join(dest_path, "mkmf.log") + "\n"
204
+ end
205
+ FileUtils.mv mkmf_log, dest_path
206
+ end
207
+ end
208
+
209
+ ENV["DESTDIR"] = nil
210
+
211
+ if HAS_TARGET_RBCONFIG && HAS_NJOBS
212
+ make dest_path, results, extension_dir, tmp_dest_relative, target_rbconfig: target_rbconfig, n_jobs: n_jobs
213
+ elsif HAS_TARGET_RBCONFIG
214
+ make dest_path, results, extension_dir, tmp_dest_relative, target_rbconfig: target_rbconfig
215
+ else
216
+ make dest_path, results, extension_dir, tmp_dest_relative
217
+ end
218
+
219
+ full_tmp_dest = File.join(extension_dir, tmp_dest_relative)
220
+
221
+ is_cross_compiling = HAS_TARGET_RBCONFIG && target_rbconfig["platform"] != RbConfig::CONFIG["platform"]
222
+ # Do not copy extension libraries by default when cross-compiling
223
+ # not to conflict with the one already built for the host platform.
224
+ if Gem.install_extension_in_lib && lib_dir && !is_cross_compiling
225
+ FileUtils.mkdir_p lib_dir
226
+ entries = Dir.entries(full_tmp_dest) - %w[. ..]
227
+ entries = entries.map {|entry| File.join full_tmp_dest, entry }
228
+ FileUtils.cp_r entries, lib_dir, remove_destination: true
229
+ end
230
+
231
+ # MODIFIED
232
+ # We skip installing into the destination directory, because we can rely on the copy in lib/ instead
233
+ # This also causes caching issues with stale files
234
+ #FileUtils::Entry_.new(full_tmp_dest).traverse do |ent|
235
+ # destent = ent.class.new(dest_path, ent.rel)
236
+ # destent.exist? || FileUtils.mv(ent.path, destent.path)
237
+ #end
238
+
239
+ if HAS_TARGET_RBCONFIG
240
+ make dest_path, results, extension_dir, tmp_dest_relative, ["clean"], target_rbconfig: target_rbconfig
241
+ else
242
+ make dest_path, results, extension_dir, tmp_dest_relative, ["clean"]
243
+ end
244
+ ensure
245
+ ENV["DESTDIR"] = destdir
246
+ end
247
+
248
+ results
249
+ rescue => error
250
+ if defined?(Gem::Ext::Builder::NoMakefileError) && error.is_a?(Gem::Ext::Builder::NoMakefileError)
251
+ results << error.message
252
+ results << "Skipping make for #{extension} as no Makefile was found."
253
+ # We are good, do not re-raise the error.
254
+ else
255
+ raise
256
+ end
257
+ ensure
258
+ FileUtils.rm_rf tmp_dest if tmp_dest
259
+ end
260
+
261
+ def self.get_relative_path(path, base)
262
+ path[0..base.length - 1] = "." if path.start_with?(base)
263
+ path
264
+ end
265
+ end
164
266
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bundler-source-pathext
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - pganalyze Team