rubygems-precompiled 0.0.1 → 1.0.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: 437a696f3109133c285f30281afb05a3a774ab5c
4
- data.tar.gz: 1068539b91ba04f83dbd865c24aacbb048a0af00
3
+ metadata.gz: a0e5cac9e19549ede238139f4fda54ccc3fd8d1c
4
+ data.tar.gz: 0fc7264556763bd4bc0499324356b26e116abb24
5
5
  SHA512:
6
- metadata.gz: 72e124fac7166f9528fd155452d89d8aa263db8dd8a859113af2e4c874124b0758afd1ec15a1be0f06c2c675481f5e23d0baf478e5b4960863f7c5807aa70537
7
- data.tar.gz: 40ff597a7dbd0190c05aac335ad6cda38c6bf2b01a69d44568a69a1737a70913e88fbeb2123584a92a6e6ed338be3a6fc2188c7c233c7fb1fcbdd505a5357157
6
+ metadata.gz: a38e2d35832ad3bcbf2a8a09985aa2f26b137b4ec7e83c902c8c2cbe1740623455e317b9ed43a5a21e83f5587b5710c0683ffa6d69b902fc065f6983cf35de7b
7
+ data.tar.gz: a67172765f91f0cc7f2a93603e62e1130cb36b2847254e8a33b95bdd64e2680b6f9b090d6b3b1c6fe0ef30365ea27b4a06ed2cb304bd0b8d7d22cf5ff8c06609
data/.gitignore CHANGED
@@ -1,4 +1,3 @@
1
- *.gem
2
1
  *.rbc
3
2
  .bundle
4
3
  .config
@@ -0,0 +1 @@
1
+ 2.1.8
data/README.md CHANGED
@@ -38,5 +38,16 @@ Install a gem using the cache:
38
38
 
39
39
  gem install foobar -v '0.1.0'
40
40
 
41
+ ### Running the tests
41
42
 
43
+ There are a couple of simple cucumber specs that exercise the plugin via the current version of rubygems. You can run them via:
44
+
45
+ bundle
46
+ bundle exec cucumber
47
+
48
+ When doing this, ensure you don't have either the simple_gem or compiled_gem installed locally, as this will inevitably confuse poor rubygems.
49
+
50
+ #### Fixture gems
51
+ The sources to build the gems used in the test are included in the gem-sources.tar.gz file in the fixtures directory. If you need to change these you will have to extract
52
+ the file modify the sources and re-create the .tar.gz archive, as well as putting the new gems in place in the fixtures directory.
42
53
 
@@ -23,6 +23,7 @@ Feature: Installing using a compiled-cache
23
23
 
24
24
  Then I should see "Hello, world!"
25
25
 
26
+ # this works in reality but the test is dodgy on ruby 2. Needs investment in time to fix
26
27
  Scenario: Installing a compiled gem with a cache hit
27
28
  Given I use the gem configuration option
28
29
  """
@@ -4,7 +4,7 @@ Feature: Pre-compiling gems
4
4
  Given I have changed to a temporary directory containing "spec/fixtures/*.gem"
5
5
 
6
6
  Scenario: Input validation
7
- When I run the command "gem precompile"
7
+ When I run the command "gem precompile" ignoring the exit code
8
8
  Then I should see "Please specify a gem file on the command line, e.g. gem precompile foo-0.1.0.gem"
9
9
  And the command should not return a success status code
10
10
 
@@ -20,11 +20,25 @@ Feature: Pre-compiling gems
20
20
  Then I should see "Compiling 'compiled-gem'..."
21
21
  And the command should return a success status code
22
22
 
23
+ Scenario: Pre-compiling a single compiled gem with the --noclean options
24
+ When I run the command "gem precompile --noclean compiled-gem.gem"
25
+
26
+ Then I should see "Leaving"
27
+ And the command should leave behind temporary directories
28
+ And the command should return a success status code
29
+
30
+ Scenario: Pre-compiling a single compiled gem with --build-config
31
+ When I run the command "gem precompile --verbose --build-config='--foo --bar' compiled-gem.gem"
32
+
33
+ Then I should see "build-args --foo --bar"
34
+ And the command should return a success status code
35
+
23
36
  Scenario: Pre-compiling multiple gems
24
37
  When I run the command "gem precompile *.gem"
25
38
 
26
39
  Then I should see "The gem 'simple-gem' doesn't contain a compiled extension"
27
- And I should see "Compiling 'compiled-gem'... done."
40
+ And I should see "Compiling 'compiled-gem'..."
41
+ And I should see "done."
28
42
  And the command should return a success status code
29
43
 
30
44
  Scenario: Creating the flat output files
@@ -17,7 +17,8 @@ After do
17
17
  end
18
18
 
19
19
  def execute(command)
20
- @last_stderr, @last_stdout = "", ""
20
+ $stderr.puts "Executing '#{command}'"
21
+ @last_stderr, @last_stdout = "", ""
21
22
 
22
23
  stderr_r, stderr_w, stdout_r, stdout_w = [IO.pipe, IO.pipe].flatten
23
24
  @command_env ||= {}
@@ -30,13 +31,18 @@ def execute(command)
30
31
  @last_status = status.exitstatus
31
32
  @last_stderr += stderr_r.read until stderr_r.eof?
32
33
  @last_stdout += stdout_r.read until stdout_r.eof?
34
+
35
+ puts @last_stderr
33
36
  end
34
37
 
35
- When /^I (?:run the command|execute) "(.*?)"$/ do |command|
38
+ When /^I (?:run the command|execute) "(.*?)"( ignoring the exit code)?$/ do |command,ignore_exit_code|
36
39
  execute(command)
40
+ raise RuntimeError, "Command '#{command}' exited with non-zero exit status" unless ignore_exit_code or @last_status == 0
41
+
37
42
  end
38
43
  When /^I (?:run the command|execute)$/ do |command|
39
44
  execute(command)
45
+ raise RuntimeError, "Command '#{command}' exited with non-zero exit status" unless @last_status == 0
40
46
  end
41
47
 
42
48
  Then /^I should( not)? see "(.*?)"( on (stdout|stderr))?$/ do |invert, expect, any, channel|
@@ -55,6 +61,15 @@ Then /^I should( not)? see "(.*?)"( on (stdout|stderr))?$/ do |invert, expect, a
55
61
  end
56
62
  end
57
63
 
64
+ Then /^the command should leave behind temporary directories/ do
65
+ data = @last_stdout + @last_stderr
66
+ data.each_line do |l|
67
+ if m = l.match(/Leaving (.*) in place/)
68
+ expect(Dir.exists?(m[1])).to be_true
69
+ end
70
+ end
71
+ end
72
+
58
73
  Then /^the command should( not)? return a success status code$/ do |invert|
59
74
  if invert
60
75
  @last_status.should_not == 0
@@ -1,4 +1,5 @@
1
1
  require "rubygems/command"
2
+ require "shellwords"
2
3
 
3
4
  class Gem::Commands::PrecompileCommand < Gem::Command
4
5
  def initialize
@@ -11,6 +12,14 @@ class Gem::Commands::PrecompileCommand < Gem::Command
11
12
  add_option('-a','--arch-dirs','Adds the architecture sub-folders to the output directory before writing') do |arch, options|
12
13
  options[:arch] = true
13
14
  end
15
+
16
+ add_option('-n','--noclean','do not clean up tempdirs, leaves temp dirs in place etc for inspection and debugging') do |noclean, options|
17
+ options[:debug] = true
18
+ end
19
+
20
+ add_option('-b','--build-config=CONFIG','commands to pass to the build i.e the run of extconf.rb') do |config, options|
21
+ options[:build_config] = Shellwords.split(config)
22
+ end
14
23
  end
15
24
 
16
25
  def arguments
@@ -34,7 +43,7 @@ class Gem::Commands::PrecompileCommand < Gem::Command
34
43
  gemfiles.each do |gemfile|
35
44
  compiler = Gem::Precompiler.new(gemfile, options)
36
45
  if compiler.has_extension?
37
- $stderr.puts "Compiling '#{compiler.gem_name}'... "
46
+ $stderr.write "Compiling '#{compiler.gem_name}'... "
38
47
  compiler.compile
39
48
  $stderr.puts "done."
40
49
  else
@@ -42,4 +51,4 @@ class Gem::Commands::PrecompileCommand < Gem::Command
42
51
  end
43
52
  end
44
53
  end
45
- end
54
+ end
@@ -8,7 +8,12 @@ require 'net/http'
8
8
  require 'uri'
9
9
  require 'tempfile'
10
10
 
11
- class Gem::Installer
11
+ module Precompiled
12
+
13
+ def self.included(base)
14
+ base.send(:alias_method, :build_extensions_without_cache, :build_extensions)
15
+ base.send(:alias_method, :build_extensions, :build_extensions_with_cache)
16
+ end
12
17
 
13
18
  class BaseCache
14
19
  def initialize(root_uri)
@@ -69,7 +74,7 @@ class Gem::Installer
69
74
  'http' => HttpCache
70
75
  }.freeze
71
76
 
72
- # Private: A list of precompiled cache root URLs loaded from the rubyges configuration file
77
+ # Private: A list of precompiled cache root URLs loaded from the rubygems configuration file
73
78
  #
74
79
  # Returns Array of BaseCache subclasses
75
80
  def self.precompiled_caches
@@ -80,27 +85,28 @@ class Gem::Installer
80
85
  end
81
86
 
82
87
  def build_extensions_with_cache
83
- cache = Gem::Installer.precompiled_caches.find { |cache| cache.contains?(@spec) }
88
+ cache = Precompiled.precompiled_caches.find { |cache| cache.contains?(@spec) }
84
89
 
85
90
  if cache
86
- puts "Loading native extension from cache"
91
+ $stderr.puts "Loading native extension from cache"
87
92
  cache.retrieve(@spec) do |path|
88
- overlay_tarball(path)
93
+ if @spec.respond_to?(:extension_dir)
94
+ overlay_tarball(path, @spec.extension_dir)
95
+ else
96
+ overlay_tarball(path, @gem_dir)
97
+ end
89
98
  end
90
99
  else
91
100
  build_extensions_without_cache
92
101
  end
93
102
  end
94
103
 
95
- alias_method :build_extensions_without_cache, :build_extensions
96
- alias_method :build_extensions, :build_extensions_with_cache
97
-
98
104
  # Private: Extracts a .tar.gz file on-top of the gem's installation directory
99
- def overlay_tarball(tarball)
105
+ def overlay_tarball(tarball, target_root)
100
106
  Zlib::GzipReader.open(tarball) do |gzip_io|
101
107
  Gem::Package::TarReader.new(gzip_io) do |tar|
102
108
  tar.each do |entry|
103
- target_path = File.join(gem_dir, entry.full_name)
109
+ target_path = File.join(target_root, entry.full_name)
104
110
  if entry.directory?
105
111
  FileUtils.mkdir_p(target_path)
106
112
  elsif entry.file?
@@ -111,8 +117,10 @@ class Gem::Installer
111
117
  end
112
118
  entry.close
113
119
  end
114
- end
120
+ end
115
121
  end
116
122
  end
117
123
 
118
- end
124
+ end
125
+
126
+ Gem::Installer.send(:include, Precompiled)
@@ -1,5 +1,5 @@
1
1
  module Rubygems
2
2
  module Precompiled
3
- VERSION = "0.0.1"
3
+ VERSION = "1.0.0"
4
4
  end
5
5
  end
@@ -6,38 +6,80 @@ require 'rubygems/package/tar_writer'
6
6
  require 'zlib'
7
7
  require 'pathname'
8
8
 
9
+
9
10
  class Gem::Precompiler
10
11
  include FileUtils
11
12
 
12
13
  def initialize(gemfile, opts = {})
13
- @installer = Gem::Installer.new(gemfile, opts.dup.merge(:unpack => true))
14
+ @installer = Gem::Installer.new(gemfile, opts.dup.merge(:unpack => true, :build_args => opts.fetch(:build_config,[])))
15
+ @spec = @installer.spec
16
+
14
17
  @target_dir = opts.fetch(:output, Dir.pwd)
15
18
  @target_dir = File.join(@target_dir, arch_string) if opts.fetch(:arch, false)
19
+ @debug = opts.fetch(:debug, false)
16
20
  @options = opts
21
+
22
+ # This writes out a build_info file that the extension builder will process to set the
23
+ # build configuration. We use the write_build_info_file method which should work on ruby 2+
24
+ # on ruby < 1.9.3 we don't support setting of build options. 1.9.3 is EOL.
25
+ # However most simple gems that do not require build time config will still work.
26
+ return if opts.fetch(:build_config,[]).empty?
27
+
28
+ if Gem::Installer.method_defined?(:write_build_info_file)
29
+ @installer.write_build_info_file
30
+ else
31
+ puts("Older version of rubygems, rubygems-precompiled does not support build options on this rubygems release (pull req welcome)")
32
+ puts("Try again without build configuration")
33
+ exit(1)
34
+ end
35
+ end
36
+
37
+ # Private: Extracts the gem files into the specified path
38
+ #
39
+ def extract_files_into(dir)
40
+ @installer.unpack(dir)
17
41
  end
18
42
 
19
- # Public: Returns the name of hte gem
43
+ # Public: Returns the name of the gem
20
44
  #
21
45
  # Returns a string
22
46
  def gem_name
23
- @installer.spec.name
47
+ @spec.name
48
+ end
49
+
50
+ # Public: Returns the version string of the gem
51
+ #
52
+ # Returns a Gem::Version
53
+ def gem_version
54
+ @spec.version
55
+ end
56
+
57
+ # Public: Returns the relative require-paths specified by the gem
58
+ #
59
+ # Returns an array of strings
60
+ def gem_require_paths
61
+ @spec.require_paths
24
62
  end
25
63
 
26
64
  # Public: Does the gem actually have any compiled extensions?
27
65
  #
28
66
  # Returns boolean - true if the gem has a c-extension that needs building
29
67
  def has_extension?
30
- !@installer.spec.extensions.empty?
68
+ !@spec.extensions.empty?
31
69
  end
32
70
 
33
71
  # Private: Yield the path to a temporary directory that will get deleted when
34
- # the block returns
72
+ # the block returns, unless debug option was used on the cli
35
73
  #
36
74
  def tempdir
37
75
  temp_dir = Dir.mktmpdir
38
76
  yield temp_dir
39
77
  ensure
40
- rm_rf temp_dir
78
+ if @debug
79
+ puts("\nLeaving #{temp_dir} in place")
80
+ else
81
+ rm_rf temp_dir
82
+ end
41
83
  end
42
84
 
43
85
  # Private: Return a string that uniquely keys this machines ruby version and architecture
@@ -51,31 +93,61 @@ class Gem::Precompiler
51
93
  #
52
94
  # Returns a string
53
95
  def output_path
54
- File.join(*[@target_dir, "#{@installer.spec.name}-#{@installer.spec.version}.tar.gz"].compact)
96
+ File.join(*[@target_dir, "#{gem_name}-#{gem_version.to_s}.tar.gz"].compact)
55
97
  end
56
98
 
57
- # Private: Return a list fo build-products in a given directory
99
+ # Private: Calls the code necessary to build all the extensions
100
+ # into a specified install root
58
101
  #
59
- # Returns an array of paths
60
- def build_products(installer, path)
61
- dlext = RbConfig::CONFIG["DLEXT"]
62
- lib_dirs = installer.spec.require_paths.join(',')
63
- Dir.glob("#{path}/{#{lib_dirs}}/**/*.#{dlext}")
102
+ # Returns a list of files beneath that root making up the build
103
+ # products of the extensions
104
+ #
105
+ def build_extensions(install_root)
106
+ if @spec.respond_to?(:extension_dir=)
107
+ tempdir do |workroot|
108
+ extract_files_into(workroot)
109
+
110
+ # override the full_gem_path function so we can return
111
+ # the directory we want. Otherwise by default the build process will
112
+ # look for the gem installed in the usual place won't find it and will then
113
+ # bail
114
+ class <<@spec
115
+ attr_accessor :workroot
116
+ def full_gem_path
117
+ return workroot
118
+ end
119
+ end
120
+ @spec.workroot = workroot
121
+
122
+ @spec.extension_dir = install_root
123
+ @spec.installed_by_version = Gem::VERSION
124
+ @spec.build_extensions
125
+ Dir.glob(File.join(install_root, "**", "*"))
126
+ end
127
+ else
128
+ extract_files_into(install_root)
129
+ @installer.build_extensions
130
+
131
+ dlext = RbConfig::CONFIG["DLEXT"]
132
+ lib_dirs = gem_require_paths.join(',')
133
+ Dir.glob("#{install_root}/{#{lib_dirs}}/**/*.#{dlext}")
134
+ end
64
135
  end
65
136
 
137
+
66
138
  # Public: Compile
67
139
  #
140
+ # This compiles into a temporary file, then moves into place. Otherwise we potentially confuse
141
+ # the gem installer with partial files!
68
142
  #
69
143
  def compile
70
- FileUtils.mkdir_p(@target_dir)
71
-
144
+ temp_output = Tempfile.new('partial-output')
72
145
  tempdir do |path|
73
- @installer.unpack(path)
74
- @installer.build_extensions
75
146
 
76
- targz_file(output_path) do |tar_writer|
147
+ targz_file(temp_output) do |tar_writer|
77
148
 
78
- build_products(@installer, path).each do |product_path|
149
+ build_extensions(path).each do |product_path|
150
+ next if File.directory?(product_path)
79
151
  product_path = Pathname.new(product_path)
80
152
  relative_path = product_path.relative_path_from(Pathname.new(path))
81
153
 
@@ -94,6 +166,9 @@ class Gem::Precompiler
94
166
 
95
167
  end
96
168
  end
169
+
170
+ FileUtils.mkdir_p(@target_dir)
171
+ FileUtils.mv(temp_output.path, output_path)
97
172
  end
98
173
 
99
174
  # Private: Yield a reference to a TarWriter that writes to
@@ -2,3 +2,4 @@ require 'rubygems/precompiled'
2
2
  require 'rubygems/command_manager'
3
3
 
4
4
  Gem::CommandManager.instance.register_command :precompile
5
+
metadata CHANGED
@@ -1,69 +1,69 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubygems-precompiled
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Haggett
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-21 00:00:00.000000000 Z
11
+ date: 2016-04-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.3'
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: '1.3'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
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
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: cucumber
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  description: RubyGems plugin to allow a gem's compiled extension to be pre-built and
@@ -74,7 +74,8 @@ executables: []
74
74
  extensions: []
75
75
  extra_rdoc_files: []
76
76
  files:
77
- - .gitignore
77
+ - ".gitignore"
78
+ - ".ruby-version"
78
79
  - Gemfile
79
80
  - LICENSE.txt
80
81
  - README.md
@@ -90,7 +91,9 @@ files:
90
91
  - lib/rubygems/precompiler.rb
91
92
  - lib/rubygems_plugin.rb
92
93
  - rubygems-precompiled.gemspec
94
+ - spec/fixtures/compiled-gem.gem
93
95
  - spec/fixtures/gem-sources.tar.gz
96
+ - spec/fixtures/simple-gem.gem
94
97
  homepage: https://github.com/joshado/rubygems-precompiled
95
98
  licenses:
96
99
  - MIT
@@ -101,17 +104,17 @@ require_paths:
101
104
  - lib
102
105
  required_ruby_version: !ruby/object:Gem::Requirement
103
106
  requirements:
104
- - - '>='
107
+ - - ">="
105
108
  - !ruby/object:Gem::Version
106
109
  version: '0'
107
110
  required_rubygems_version: !ruby/object:Gem::Requirement
108
111
  requirements:
109
- - - '>='
112
+ - - ">="
110
113
  - !ruby/object:Gem::Version
111
114
  version: '0'
112
115
  requirements: []
113
116
  rubyforge_project:
114
- rubygems_version: 2.0.3
117
+ rubygems_version: 2.2.5
115
118
  signing_key:
116
119
  specification_version: 4
117
120
  summary: RubyGems plugin to allow a gem's compiled extension to be pre-built and cached
@@ -121,4 +124,6 @@ test_files:
121
124
  - features/steps/command_steps.rb
122
125
  - features/steps/file_steps.rb
123
126
  - features/steps/rubygem_steps.rb
127
+ - spec/fixtures/compiled-gem.gem
124
128
  - spec/fixtures/gem-sources.tar.gz
129
+ - spec/fixtures/simple-gem.gem