rubygems-precompiled 0.0.1 → 1.0.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: 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