gem-compiler 0.4.0 → 0.5.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
  SHA1:
3
- metadata.gz: 59169d53e08c6315d2d6dd219c2ca65998cbaf36
4
- data.tar.gz: 409e30463beab8bc6704d453cb19b47071c71e5c
3
+ metadata.gz: 76146eae5124b2c492cddca593c27b5af3595b2b
4
+ data.tar.gz: c39f906cd91e03f5ffb85019b2a581ed19508c9b
5
5
  SHA512:
6
- metadata.gz: c9bcc65c52d554ccf58466a524744ef68b0034ceda7dc48c344ad1979ab10c46e644347fcfdeaac4b50d082fbac5d009d71f513e6cd8386c576a2248b7ed646c
7
- data.tar.gz: 6bc96ffa4aa473e9a5382af54ba1105da3b4f6c043285fc621c38a1f37e7e0ef859286df01d597d5f087b842b57985a3ad7c04e71e2f2b4eb05841c6a2a50ce9
6
+ metadata.gz: 75ba4bcbe505d08fc603da2836b6120e46e66bb06c34892356f87777c5eb6d63dbd797d5d92acd2d7c3e10a39c1f6a54eba04d453a4c39cbbf455c7ee0762efa
7
+ data.tar.gz: 5b697f3f4a943c76ee58b620ffa7d3babb94e4b6af64f8d05cc25c1fde8b479fd495c103114d8ff436481e79651f4928130f9e7604185a8d246e870caf63b302
data/History.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # gem-compiler
2
2
 
3
+ ## 0.5.0 (2016-04-24)
4
+
5
+ - Drop support for any Ruby version prior to 2.0.0
6
+ - Workaround shortname directories on Windows. Thanks to @mbland (#17 & #19)
7
+ - Validate both Ruby and RubyGems versions defined in gemspec
8
+ - Ensure any RubyGems' `pre_install` hooks are run at extension compilation (#18)
9
+ - Lock compile gems to Ruby's ABI version which can be disabled using
10
+ `--no-abi-lock` option (#11)
11
+
3
12
  ## 0.4.0 (2015-07-18)
4
13
 
5
14
  - Introduce `--prune` option to cleanup gemspecs. Thanks to @androbtech [#13]
data/README.md CHANGED
@@ -2,10 +2,10 @@
2
2
 
3
3
  A RubyGems plugin that generates binary (pre-compiled) gems.
4
4
 
5
- [![Gem Version](https://badge.fury.io/rb/gem-compiler.svg)](http://badge.fury.io/rb/gem-compiler)
6
- [![Travis status](https://travis-ci.org/luislavena/gem-compiler.svg?branch=master)](https://travis-ci.org/luislavena/gem-compiler)
7
- [![AppVeyor status](https://ci.appveyor.com/api/projects/status/2mo41n9ltsoe3rn1/branch/master?svg=true)](https://ci.appveyor.com/project/luislavena/gem-compiler/branch/master)
8
- [![Code Climate](http://img.shields.io/codeclimate/github/luislavena/gem-compiler.svg)](https://codeclimate.com/github/luislavena/gem-compiler)
5
+ [![Gem Version](https://img.shields.io/gem/v/gem-compiler.svg)](https://rubygems.org/gems/gem-compiler)
6
+ [![Travis status](https://img.shields.io/travis/luislavena/gem-compiler/master.svg)](https://travis-ci.org/luislavena/gem-compiler)
7
+ [![AppVeyor status](https://img.shields.io/appveyor/ci/luislavena/gem-compiler/master.svg)](https://ci.appveyor.com/project/luislavena/gem-compiler)
8
+ [![Code Climate](https://img.shields.io/codeclimate/github/luislavena/gem-compiler.svg)](https://codeclimate.com/github/luislavena/gem-compiler)
9
9
 
10
10
  - [home](https://github.com/luislavena/gem-compiler)
11
11
  - [bugs](https://github.com/luislavena/gem-compiler/issues)
@@ -94,6 +94,23 @@ process:
94
94
  Successfully installed nokogiri-1.6.6.2-x86_64-darwin-12
95
95
  1 gem installed
96
96
 
97
+ #### Restrictions of binaries
98
+
99
+ Gems compiled with `gem-compiler` will be lock to the version of Ruby used
100
+ to compile them.
101
+
102
+ This means that a gem compiled under Ruby 2.2 could only be installed under
103
+ Ruby 2.2.
104
+
105
+ You can disable this by using `--no-abi-lock` option during compilation:
106
+
107
+ $ gem compile yajl-ruby-1.1.0.gem --no-abi-lock
108
+
109
+ **Warning**: this is not recommended since different versions of Ruby might
110
+ expose different options on the API. The binary might be expecting specific
111
+ features not present in the version of Ruby you're installing the binary gem
112
+ into.
113
+
97
114
  ### Compiling from Rake
98
115
 
99
116
  Most of the times, as gem developer, you would like to generate both kind of
@@ -160,20 +177,6 @@ While the ideal scenario is using a tool like rake-compiler that endorses
160
177
  *convention over configuration*, is not humanly possible change all the
161
178
  projects by snapping your fingers :wink:
162
179
 
163
- ## What is missing
164
-
165
- The following are the list of features I would like to implement at some
166
- point:
167
-
168
- - Cross compile gems to any platform that Ruby can run
169
- (e.g. from Linux/OSX to Windows, x86 to x64, x86 Linux to ARM Linux, etc)
170
-
171
- - Create multiple gems from the same build
172
- (e.g. target both x86-mswin32-60 and x86-mingw32)
173
-
174
- - Ability to build fat-binaries targeting both Ruby 1.8 and 1.9.x,
175
- placing automatic stubs to handle extension loading.
176
-
177
180
  ## License
178
181
 
179
182
  [The MIT License](LICENSE)
@@ -8,6 +8,10 @@ class Gem::Commands::CompileCommand < Gem::Command
8
8
  add_option "--prune", "Clean non-existing files during re-packaging" do |value, options|
9
9
  options[:prune] = true
10
10
  end
11
+
12
+ add_option "-N", "--no-abi-lock", "Do not lock compiled Gem to Ruby's ABI" do |value, options|
13
+ options[:no_abi_lock] = true
14
+ end
11
15
  end
12
16
 
13
17
  def arguments
@@ -26,18 +26,24 @@ class Gem::Compiler
26
26
  def compile
27
27
  unpack
28
28
 
29
- # build extensions
30
- installer.build_extensions
31
-
32
- # determine build artifacts from require_paths
33
- dlext = RbConfig::CONFIG["DLEXT"]
34
- lib_dirs = installer.spec.require_paths.join(",")
29
+ build_extensions
35
30
 
36
- artifacts = Dir.glob("#{target_dir}/{#{lib_dirs}}/**/*.#{dlext}")
31
+ artifacts = collect_artifacts
37
32
 
38
33
  # build a new gemspec from the original one
39
34
  gemspec = installer.spec.dup
40
35
 
36
+ adjust_gemspec_files gemspec, artifacts
37
+
38
+ # generate new gem and return new path to it
39
+ repackage gemspec
40
+ ensure
41
+ cleanup
42
+ end
43
+
44
+ private
45
+
46
+ def adjust_gemspec_files(gemspec, artifacts)
41
47
  # remove any non-existing files
42
48
  if @options[:prune]
43
49
  gemspec.files.reject! { |f| !File.exist?("#{target_dir}/#{f}") }
@@ -46,45 +52,35 @@ class Gem::Compiler
46
52
  # add discovered artifacts
47
53
  artifacts.each do |path|
48
54
  # path needs to be relative to target_dir
49
- file = path.gsub("#{target_dir}/", "")
55
+ file = path.sub("#{target_dir}/", "")
50
56
 
51
57
  debug "Adding '#{file}' to gemspec"
52
58
  gemspec.files.push file
53
59
  end
60
+ end
54
61
 
55
- # clear out extensions from gemspec
56
- gemspec.extensions.clear
57
-
58
- # adjust platform
59
- gemspec.platform = Gem::Platform::CURRENT
60
-
61
- # build new gem
62
- output_gem = nil
62
+ def build_extensions
63
+ # run pre_install hooks
63
64
 
64
- Dir.chdir target_dir do
65
- output_gem = if defined?(Gem::Builder)
66
- Gem::Builder.new(gemspec).build
67
- else
68
- Gem::Package.build(gemspec)
69
- end
65
+ if installer.respond_to?(:run_pre_install_hooks)
66
+ installer.run_pre_install_hooks
70
67
  end
71
68
 
72
- unless output_gem
73
- raise CompilerError,
74
- "There was a problem building the gem."
75
- end
69
+ installer.build_extensions
70
+ end
76
71
 
77
- # move the built gem to the original output directory
78
- FileUtils.mv File.join(target_dir, output_gem), @output_dir
72
+ def cleanup
73
+ FileUtils.rm_rf tmp_dir
74
+ end
79
75
 
80
- cleanup
76
+ def collect_artifacts
77
+ # determine build artifacts from require_paths
78
+ dlext = RbConfig::CONFIG["DLEXT"]
79
+ lib_dirs = installer.spec.require_paths.join(",")
81
80
 
82
- # return the path of the gem
83
- output_gem
81
+ Dir.glob("#{target_dir}/{#{lib_dirs}}/**/*.#{dlext}")
84
82
  end
85
83
 
86
- private
87
-
88
84
  def info(msg)
89
85
  say msg if Gem.configuration.verbose
90
86
  end
@@ -104,6 +100,16 @@ class Gem::Compiler
104
100
  installer.spec.extension_dir = File.join(@target_dir, "lib")
105
101
  end
106
102
 
103
+ # Ensure Ruby version is met
104
+ if installer.respond_to?(:ensure_required_ruby_version_met)
105
+ installer.ensure_required_ruby_version_met
106
+ end
107
+
108
+ # Check version of RubyGems (just in case)
109
+ if installer.respond_to?(:ensure_required_rubygems_version_met)
110
+ installer.ensure_required_rubygems_version_met
111
+ end
112
+
107
113
  # Hmm, gem already compiled?
108
114
  if installer.spec.platform != Gem::Platform::RUBY
109
115
  raise CompilerError,
@@ -119,8 +125,44 @@ class Gem::Compiler
119
125
  @installer = installer
120
126
  end
121
127
 
128
+ def repackage(gemspec)
129
+ # clear out extensions from gemspec
130
+ gemspec.extensions.clear
131
+
132
+ # adjust platform
133
+ gemspec.platform = Gem::Platform::CURRENT
134
+
135
+ # adjust version of Ruby
136
+ unless @options[:no_abi_lock]
137
+ ruby_abi = RbConfig::CONFIG["ruby_version"]
138
+ gemspec.required_ruby_version = "~> #{ruby_abi}"
139
+ end
140
+
141
+ # build new gem
142
+ output_gem = nil
143
+
144
+ Dir.chdir target_dir do
145
+ output_gem = if defined?(Gem::Builder)
146
+ Gem::Builder.new(gemspec).build
147
+ else
148
+ Gem::Package.build(gemspec)
149
+ end
150
+ end
151
+
152
+ unless output_gem
153
+ raise CompilerError,
154
+ "There was a problem building the gem."
155
+ end
156
+
157
+ # move the built gem to the original output directory
158
+ FileUtils.mv File.join(target_dir, output_gem), @output_dir
159
+
160
+ # return the path of the gem
161
+ output_gem
162
+ end
163
+
122
164
  def tmp_dir
123
- @tmp_dir ||= Dir.mktmpdir
165
+ @tmp_dir ||= Dir.glob(Dir.mktmpdir).first
124
166
  end
125
167
 
126
168
  def unpack
@@ -132,8 +174,4 @@ class Gem::Compiler
132
174
  info "Unpacking gem: '#{basename}' in temporary directory..."
133
175
  installer.unpack(@target_dir)
134
176
  end
135
-
136
- def cleanup
137
- FileUtils.rm_rf tmp_dir
138
- end
139
177
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Gem
4
4
  class Compiler
5
- VERSION = "0.4.0"
5
+ VERSION = "0.5.0"
6
6
  end
7
7
  end
@@ -38,6 +38,60 @@ class TestGemCompiler < Gem::TestCase
38
38
  assert_equal "The gem file seems to be compiled already.", e.message
39
39
  end
40
40
 
41
+ def test_compile_pre_install_hooks
42
+ util_reset_arch
43
+
44
+ artifact = "foo.#{RbConfig::CONFIG["DLEXT"]}"
45
+
46
+ gem_file = util_bake_gem("foo") { |s|
47
+ util_fake_extension s, "foo", util_custom_configure(artifact)
48
+ }
49
+
50
+ hook_run = false
51
+
52
+ Gem.pre_install do |installer|
53
+ hook_run = true
54
+ true
55
+ end
56
+
57
+ compiler = Gem::Compiler.new(gem_file, :output => @output_dir)
58
+
59
+ use_ui @ui do
60
+ compiler.compile
61
+ end
62
+
63
+ assert hook_run, "pre_install hook not run"
64
+ end
65
+
66
+ def test_compile_required_ruby
67
+ gem_file = util_bake_gem("old_required") { |s| s.required_ruby_version = "= 1.4.6" }
68
+
69
+ compiler = Gem::Compiler.new(gem_file, :output => @output_dir)
70
+
71
+ e = assert_raises Gem::InstallError do
72
+ use_ui @ui do
73
+ compiler.compile
74
+ end
75
+ end
76
+
77
+ assert_equal "old_required requires Ruby version = 1.4.6.", e.message
78
+ end
79
+
80
+ def test_compile_required_rubygems
81
+ gem_file = util_bake_gem("old_rubygems") { |s| s.required_rubygems_version = "< 0" }
82
+
83
+ compiler = Gem::Compiler.new(gem_file, :output => @output_dir)
84
+
85
+ e = assert_raises Gem::InstallError do
86
+ use_ui @ui do
87
+ compiler.compile
88
+ end
89
+ end
90
+
91
+ assert_equal "old_rubygems requires RubyGems version < 0. " +
92
+ "Try 'gem update --system' to update RubyGems itself.", e.message
93
+ end
94
+
41
95
  def test_compile_succeed
42
96
  util_set_arch "i386-mingw32"
43
97
 
@@ -109,6 +163,112 @@ class TestGemCompiler < Gem::TestCase
109
163
  assert_includes spec.files, "lib/#{artifact}"
110
164
  end
111
165
 
166
+ # We need to check that tempdir paths that contain spaces as are handled
167
+ # properly on Windows. In some cases, Dir.tmpdir may returned shortened
168
+ # versions of these components, e.g. "C:/Users/JOHNDO~1/AppData/Local/Temp"
169
+ # for "C:/Users/John Doe/AppData/Local/Temp".
170
+ def test_compile_bundle_artifacts_path_with_spaces
171
+ skip("only necessary to test on Windows") unless Gem.win_platform?
172
+ old_tempdir = @tempdir
173
+ old_output_dir = @output_dir
174
+
175
+ old_tmp = ENV["TMP"]
176
+ old_temp = ENV["TEMP"]
177
+ old_tmpdir = ENV["TMPDIR"]
178
+
179
+ # We want to make sure Dir.tmpdir returns the path containing "DIRWIT~1"
180
+ # so that we're testing whether the compiler expands the path properly. To
181
+ # do this, "dir with spaces" must not be the last path component.
182
+ #
183
+ # This is because Dir.tmpdir calls File.expand_path on ENV[TMPDIR] (or
184
+ # ENV[TEMP], etc.). When "DIRWIT~1" is the last component,
185
+ # File.expand_path will expand this to "dir with spaces". When it's not
186
+ # the last component, it will leave "DIRWIT~1" as-is.
187
+ @tempdir = File.join(@tempdir, "dir with spaces", "tmp")
188
+ FileUtils.mkdir_p(@tempdir)
189
+ @tempdir = File.join(old_tempdir, "DIRWIT~1", "tmp")
190
+
191
+ @output_dir = File.join(@tempdir, "output")
192
+ FileUtils.mkdir_p(@output_dir)
193
+
194
+ ["TMP", "TEMP", "TMPDIR"].each { |varname| ENV[varname] = @tempdir }
195
+
196
+ util_reset_arch
197
+
198
+ artifact = "foo.#{RbConfig::CONFIG["DLEXT"]}"
199
+
200
+ gem_file = util_bake_gem("foo") { |s|
201
+ util_fake_extension s, "foo", util_custom_configure(artifact)
202
+ }
203
+
204
+ compiler = Gem::Compiler.new(gem_file, :output => @output_dir)
205
+ output_gem = nil
206
+
207
+ use_ui @ui do
208
+ output_gem = compiler.compile
209
+ end
210
+
211
+ assert_path_exists File.join(@output_dir, output_gem)
212
+ spec = util_read_spec File.join(@output_dir, output_gem)
213
+
214
+ assert_includes spec.files, "lib/#{artifact}"
215
+ ensure
216
+ if Gem.win_platform?
217
+ FileUtils.rm_rf @tempdir
218
+
219
+ ENV["TMP"] = old_tmp
220
+ ENV["TEMP"] = old_temp
221
+ ENV["TMPDIR"] = old_tmpdir
222
+
223
+ @tempdir = old_tempdir
224
+ @output_dir = old_output_dir
225
+ end
226
+ end
227
+
228
+ def test_compile_lock_ruby_abi
229
+ util_reset_arch
230
+
231
+ ruby_abi = RbConfig::CONFIG["ruby_version"]
232
+ artifact = "foo.#{RbConfig::CONFIG["DLEXT"]}"
233
+
234
+ gem_file = util_bake_gem("foo") { |s|
235
+ util_fake_extension s, "foo", util_custom_configure(artifact)
236
+ }
237
+
238
+ compiler = Gem::Compiler.new(gem_file, :output => @output_dir)
239
+ output_gem = nil
240
+
241
+ use_ui @ui do
242
+ output_gem = compiler.compile
243
+ end
244
+
245
+ spec = util_read_spec File.join(@output_dir, output_gem)
246
+
247
+ assert_equal spec.required_ruby_version, Gem::Requirement.new("~> #{ruby_abi}")
248
+ end
249
+
250
+ def test_compile_no_lock_ruby_abi
251
+ util_reset_arch
252
+
253
+ ruby_abi = RbConfig::CONFIG["ruby_version"]
254
+ artifact = "foo.#{RbConfig::CONFIG["DLEXT"]}"
255
+
256
+ gem_file = util_bake_gem("foo") { |s|
257
+ util_fake_extension s, "foo", util_custom_configure(artifact)
258
+ }
259
+
260
+ compiler = Gem::Compiler.new(gem_file, :output => @output_dir, :no_abi_lock => true)
261
+ output_gem = nil
262
+
263
+ use_ui @ui do
264
+ output_gem = compiler.compile
265
+ end
266
+
267
+ spec = util_read_spec File.join(@output_dir, output_gem)
268
+
269
+ assert_equal spec.required_ruby_version, Gem::Requirement.new(">= 0")
270
+ end
271
+
112
272
  ##
113
273
  # Reset RubyGems platform to original one. Useful when testing platform
114
274
  # specific features (like compiled extensions)
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gem-compiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luis Lavena
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-19 00:00:00.000000000 Z
11
+ date: 2016-04-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 0.9.2.2
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.9.2.2
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: minitest
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '4.0'
33
+ version: '5.8'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '4.0'
40
+ version: '5.8'
41
41
  description: |
42
42
  A RubyGems plugin that helps generates binary gems from already existing
43
43
  ones without altering the original source code. It compiles Ruby C
@@ -47,12 +47,12 @@ executables: []
47
47
  extensions: []
48
48
  extra_rdoc_files: []
49
49
  files:
50
- - README.md
51
50
  - History.md
51
+ - README.md
52
52
  - Rakefile
53
53
  - lib/rubygems/commands/compile_command.rb
54
- - lib/rubygems/compiler/version.rb
55
54
  - lib/rubygems/compiler.rb
55
+ - lib/rubygems/compiler/version.rb
56
56
  - lib/rubygems_plugin.rb
57
57
  - test/rubygems/test_gem_commands_compile_command.rb
58
58
  - test/rubygems/test_gem_compiler.rb
@@ -66,17 +66,17 @@ require_paths:
66
66
  - lib
67
67
  required_ruby_version: !ruby/object:Gem::Requirement
68
68
  requirements:
69
- - - '>='
69
+ - - ">="
70
70
  - !ruby/object:Gem::Version
71
- version: 1.8.7
71
+ version: 2.0.0
72
72
  required_rubygems_version: !ruby/object:Gem::Requirement
73
73
  requirements:
74
- - - '>='
74
+ - - ">="
75
75
  - !ruby/object:Gem::Version
76
76
  version: 1.8.24
77
77
  requirements: []
78
78
  rubyforge_project:
79
- rubygems_version: 2.0.14
79
+ rubygems_version: 2.4.5.1
80
80
  signing_key:
81
81
  specification_version: 4
82
82
  summary: A RubyGems plugin that generates binary gems.