gem-compiler 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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.