bundler-source-pathext 0.2.0 → 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: fe992635560597c121fa90491f6501471dedddf344d497cfa87f4c512e51deb8
4
- data.tar.gz: afd9e49a4916dbf8b9ec52505ef19fee11de8052716d94411a15e3961f93e628
3
+ metadata.gz: c60ff2869c3dd24a8af2baf53c12732d91ab94f7e0da7118ee89d69564c2fd60
4
+ data.tar.gz: dbb33d23f6d3958b156c6d3549f5faaecabd2955ed2a056258af62b48577c500
5
5
  SHA512:
6
- metadata.gz: eafc5e0d6fd8e7ff002ed82cc766332ec1b9e371fa596bc20f9877625a8feb5afc28160f5a698eedc85d8c9c6281e9c52e7fbb78cf18d0727c5791fc7788265d
7
- data.tar.gz: c89d33b02882c2bb025e16a097cf48940ed86c7f0ce653bf4422e3bdf08d49db6dea1e885dc7c2062d261b8fab8932c0c0972d7d239f1712d58254a969c8b3ed
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,8 +1,6 @@
1
- require_relative 'lib/bundler-source-pathext/version'
2
-
3
1
  Gem::Specification.new do |spec|
4
2
  spec.name = "bundler-source-pathext"
5
- spec.version = BundlerSourcePathext::VERSION
3
+ spec.version = "0.3.0"
6
4
  spec.authors = ["pganalyze Team"]
7
5
  spec.email = ["team@pganalyze.com"]
8
6
 
data/plugins.rb CHANGED
@@ -1,2 +1,266 @@
1
- require 'bundler-source-pathext'
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")
2
4
 
5
+ class PathExtSource < Bundler::Source
6
+ def install(spec, opts)
7
+ print_using_message "Using #{spec.name} #{spec.version} from #{self}"
8
+
9
+ using_message = "Using #{version_message(spec, options[:previous_spec])} from #{self}"
10
+ using_message += " and installing its executables" unless spec.executables.empty?
11
+ print_using_message using_message
12
+ generate_bin(spec, disable_extensions: true) # Turned off!
13
+
14
+ build_local_extensions(spec)
15
+
16
+ nil # no post-install message
17
+ end
18
+
19
+ # Bundler plugin api, we need to return a Bundler::Index
20
+ def specs
21
+ files = Dir.glob(File.join(File.expand_path(uri), '*.gemspec'))
22
+
23
+ Bundler::Index.build do |index|
24
+ files.each do |file|
25
+ next unless spec = Bundler.load_gemspec(file)
26
+ spec.installed_by_version = Gem::VERSION
27
+ spec.source = self
28
+ spec.extension_dir = File.join(File.dirname(file), 'tmp', RUBY_PLATFORM, spec.name, RUBY_VERSION)
29
+ Bundler.rubygems.validate(spec)
30
+
31
+ index << spec
32
+ end
33
+ end
34
+ end
35
+
36
+ # Set internal representation to fetch the gems/specs locally.
37
+ #
38
+ # When this is called, the source should try to fetch the specs and
39
+ # install from the local system.
40
+ def local!
41
+ # not applicable
42
+ end
43
+
44
+ # Set internal representation to fetch the gems/specs from remote.
45
+ #
46
+ # When this is called, the source should try to fetch the specs and
47
+ # install from remote path.
48
+ def remote!
49
+ # not applicable
50
+ end
51
+
52
+ # Set internal representation to fetch the gems/specs from app cache.
53
+ #
54
+ # When this is called, the source should try to fetch the specs and
55
+ # install from the path provided by `app_cache_path`.
56
+ def cached!
57
+ # not applicable
58
+ end
59
+
60
+ # This is called to update the spec and installation.
61
+ #
62
+ # If the source plugin is loaded from lockfile or otherwise, it shall
63
+ # refresh the cache/specs (e.g. git sources can make a fresh clone).
64
+ def unlock!
65
+ # not applicable
66
+ end
67
+
68
+ private
69
+
70
+ def build_local_extensions(spec)
71
+ build_args = options[:build_args] || Bundler.rubygems.build_args || begin
72
+ require_relative "command"
73
+ Gem::Command.build_args
74
+ end
75
+
76
+ builder = Gem::Ext::Builder.new spec, build_args
77
+
78
+ build_extensions(spec, build_args, builder)
79
+ end
80
+
81
+ def build_extensions(spec, build_args, builder)
82
+ return if spec.extensions.empty?
83
+
84
+ if build_args.empty?
85
+ puts "Building native extensions for #{spec.name}. This could take a while..."
86
+ else
87
+ puts "Building native extensions for #{spec.name} with: '#{@build_args.join " "}'"
88
+ puts "This could take a while..."
89
+ end
90
+
91
+ dest_path = spec.extension_dir
92
+ start = Time.now
93
+
94
+ spec.extensions.each do |extension|
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
103
+ end
104
+ puts format(' Finished %s after %0.2f seconds', spec.name, Time.now - start)
105
+ FileUtils.touch(spec.gem_build_complete_path)
106
+ end
107
+
108
+ def build_extension(spec, builder, builder_for_ext, extension, dest_path) # :nodoc:
109
+ results = []
110
+
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"), $@)
127
+ end
128
+ end
129
+
130
+ def generate_bin(spec, options = {})
131
+ gem_dir = Pathname.new(spec.full_gem_path)
132
+
133
+ # Some gem authors put absolute paths in their gemspec
134
+ # and we have to save them from themselves
135
+ spec.files = spec.files.filter_map do |path|
136
+ next path unless /\A#{Pathname::SEPARATOR_PAT}/o.match?(path)
137
+ next if File.directory?(path)
138
+ begin
139
+ Pathname.new(path).relative_path_from(gem_dir).to_s
140
+ rescue ArgumentError
141
+ path
142
+ end
143
+ end
144
+
145
+ installer = Path::Installer.new(
146
+ spec,
147
+ env_shebang: false,
148
+ disable_extensions: options[:disable_extensions],
149
+ build_args: options[:build_args],
150
+ bundler_extension_cache_path: extension_cache_path(spec)
151
+ )
152
+ installer.post_install
153
+ rescue Gem::InvalidSpecificationException => e
154
+ Bundler.ui.warn "\n#{spec.name} at #{spec.full_gem_path} did not have a valid gemspec.\n" \
155
+ "This prevents bundler from installing bins or native extensions, but " \
156
+ "that may not affect its functionality."
157
+
158
+ if !spec.extensions.empty? && !spec.email.empty?
159
+ Bundler.ui.warn "If you need to use this package without installing it from a gem " \
160
+ "repository, please contact #{spec.email} and ask them " \
161
+ "to modify their .gemspec so it can work with `gem build`."
162
+ end
163
+
164
+ Bundler.ui.warn "The validation message from RubyGems was:\n #{e.message}"
165
+ end
166
+ end
167
+
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
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.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - pganalyze Team
@@ -24,8 +24,6 @@ files:
24
24
  - README.md
25
25
  - Rakefile
26
26
  - bundler-source-pathext.gemspec
27
- - lib/bundler-source-pathext.rb
28
- - lib/bundler-source-pathext/version.rb
29
27
  - plugins.rb
30
28
  homepage:
31
29
  licenses: []
@@ -1,3 +0,0 @@
1
- class BundlerSourcePathext < Bundler::Plugin::API
2
- VERSION = "0.2.0"
3
- end
@@ -1,166 +0,0 @@
1
- require "bundler-source-pathext/version"
2
-
3
- class BundlerSourcePathext < Bundler::Plugin::API
4
- class PathExtSource < Bundler::Source#Bundler::Source::Path
5
- def install(spec, opts)
6
- print_using_message "Using #{spec.name} #{spec.version} from #{self}"
7
-
8
- using_message = "Using #{version_message(spec, options[:previous_spec])} from #{self}"
9
- using_message += " and installing its executables" unless spec.executables.empty?
10
- print_using_message using_message
11
- generate_bin(spec, disable_extensions: true) # Turned off!
12
-
13
- build_local_extensions(spec)
14
-
15
- nil # no post-install message
16
- end
17
-
18
- # Bundler plugin api, we need to return a Bundler::Index
19
- def specs
20
- files = Dir.glob(File.join(File.expand_path(uri), '*.gemspec'))
21
-
22
- Bundler::Index.build do |index|
23
- files.each do |file|
24
- next unless spec = Bundler.load_gemspec(file)
25
- spec.installed_by_version = Gem::VERSION
26
- spec.source = self
27
- spec.extension_dir = File.join(File.dirname(file), 'tmp', RUBY_PLATFORM, spec.name, RUBY_VERSION)
28
- Bundler.rubygems.validate(spec)
29
-
30
- index << spec
31
- end
32
- end
33
- end
34
-
35
- # Set internal representation to fetch the gems/specs locally.
36
- #
37
- # When this is called, the source should try to fetch the specs and
38
- # install from the local system.
39
- def local!
40
- # not applicable
41
- end
42
-
43
- # Set internal representation to fetch the gems/specs from remote.
44
- #
45
- # When this is called, the source should try to fetch the specs and
46
- # install from remote path.
47
- def remote!
48
- # not applicable
49
- end
50
-
51
- # Set internal representation to fetch the gems/specs from app cache.
52
- #
53
- # When this is called, the source should try to fetch the specs and
54
- # install from the path provided by `app_cache_path`.
55
- def cached!
56
- # not applicable
57
- end
58
-
59
- # This is called to update the spec and installation.
60
- #
61
- # If the source plugin is loaded from lockfile or otherwise, it shall
62
- # refresh the cache/specs (e.g. git sources can make a fresh clone).
63
- def unlock!
64
- # not applicable
65
- end
66
-
67
- private
68
-
69
- def build_local_extensions(spec)
70
- build_args = options[:build_args] || Bundler.rubygems.build_args || begin
71
- require_relative "command"
72
- Gem::Command.build_args
73
- end
74
-
75
- builder = Gem::Ext::Builder.new spec, build_args
76
-
77
- build_extensions(spec, build_args, builder)
78
- end
79
-
80
- def build_extensions(spec, build_args, builder)
81
- return if spec.extensions.empty?
82
-
83
- if build_args.empty?
84
- puts "Building native extensions for #{spec.name}. This could take a while..."
85
- else
86
- puts "Building native extensions for #{spec.name} with: '#{@build_args.join " "}'"
87
- puts "This could take a while..."
88
- end
89
-
90
- dest_path = spec.extension_dir
91
- start = Time.now
92
- load_dir = File.dirname(spec.loaded_from)
93
-
94
- success = true
95
- spec.extensions.each do |extension|
96
- if extension[/extconf/] && File.exist?(File.join(load_dir, 'Rakefile'))
97
- rake_args = ['compile']
98
- builder.class.run(rake + rake_args, [], 'rake compile (via ' + self.class.to_s + ')', load_dir) do |status, results|
99
- unless status.success?
100
- success = false
101
- puts results
102
- end
103
- end
104
- else
105
- builder.build_extension extension, dest_path
106
- end
107
- end
108
- puts format(' Finished after %0.2f seconds', Time.now - start)
109
- FileUtils.touch(spec.gem_build_complete_path) if success
110
- end
111
-
112
- def rake
113
- rake = ENV["rake"]
114
-
115
- if rake
116
- rake = Shellwords.split(rake)
117
- else
118
- begin
119
- rake = Gem::Ext::Builder.ruby << "-rrubygems" << Gem.bin_path("rake", "rake")
120
- rescue Gem::Exception
121
- rake = [Gem.default_exec_format % "rake"]
122
- end
123
- end
124
- rake
125
- end
126
-
127
- def generate_bin(spec, options = {})
128
- gem_dir = Pathname.new(spec.full_gem_path)
129
-
130
- # Some gem authors put absolute paths in their gemspec
131
- # and we have to save them from themselves
132
- spec.files = spec.files.filter_map do |path|
133
- next path unless /\A#{Pathname::SEPARATOR_PAT}/o.match?(path)
134
- next if File.directory?(path)
135
- begin
136
- Pathname.new(path).relative_path_from(gem_dir).to_s
137
- rescue ArgumentError
138
- path
139
- end
140
- end
141
-
142
- installer = Path::Installer.new(
143
- spec,
144
- env_shebang: false,
145
- disable_extensions: options[:disable_extensions],
146
- build_args: options[:build_args],
147
- bundler_extension_cache_path: extension_cache_path(spec)
148
- )
149
- installer.post_install
150
- rescue Gem::InvalidSpecificationException => e
151
- Bundler.ui.warn "\n#{spec.name} at #{spec.full_gem_path} did not have a valid gemspec.\n" \
152
- "This prevents bundler from installing bins or native extensions, but " \
153
- "that may not affect its functionality."
154
-
155
- if !spec.extensions.empty? && !spec.email.empty?
156
- Bundler.ui.warn "If you need to use this package without installing it from a gem " \
157
- "repository, please contact #{spec.email} and ask them " \
158
- "to modify their .gemspec so it can work with `gem build`."
159
- end
160
-
161
- Bundler.ui.warn "The validation message from RubyGems was:\n #{e.message}"
162
- end
163
- end
164
-
165
- source 'pathext', PathExtSource
166
- end