prebundler 0.0.4 → 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: 14809b2ea93fc2442016314d9f173db3be3e383f
4
- data.tar.gz: 4d6c78d6743dc6584adc689ee4f4b3b222084578
3
+ metadata.gz: a8f3573257ed6d3ae187bd8cc9b3e37ce6787373
4
+ data.tar.gz: 7780812efb908e7e533e1e7a3299b529f281bda5
5
5
  SHA512:
6
- metadata.gz: 957cbcdff72652ecdc09a8e29ec6725a5dfe05efef3ee538f21c266dc6a65bd42a2a602079abeeaa6340f0910923c724d43e538ef46ca8f3efc6538be18cda07
7
- data.tar.gz: 288c16b848d8909554198f7bee6fff33f67776303fc7d4890650d9e83326cc5da084342e53434473b702de9094b4a459f6678990486b615a1156d76f81d3bf4f
6
+ metadata.gz: 51e0f4e6e61305cd9535de52ca2bd3366694f63b99a0ea43d20ac084571815be95683a035698983ea0aa7eaeb4f14bf903f97aecb7b32988df1d4d296ba0834d
7
+ data.tar.gz: b1890c8532ddce82b3da898d5aae18d1c5da929b328fd460df090949310d5c70ec2d3cd3f7c98bdb1b2315fd44875e60b4594e2f91de7a87c115bb94683edbab
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ 0.5.0
2
+ ===
3
+ - Works for a repository with a significant number of dependencies (~ 400).
4
+ - Testing on staging server indicates bundle is installed correctly.
5
+
1
6
  0.0.4
2
7
  ===
3
8
  - Pass bundle path to `gem install`.
@@ -1,7 +1,8 @@
1
1
  require 'securerandom'
2
2
  require 'tmpdir'
3
3
  require 'parallel'
4
- require 'bundler'
4
+ require 'fileutils'
5
+ require 'yaml'
5
6
 
6
7
  module Prebundler
7
8
  module Cli
@@ -9,15 +10,34 @@ module Prebundler
9
10
  def run
10
11
  prepare
11
12
  install
13
+ update_bundle_config
14
+ generate_binstubs
12
15
  check
13
16
  end
14
17
 
15
18
  private
16
19
 
17
20
  def prepare
18
- gem_list.each do |_, gem_ref|
21
+ FileUtils.mkdir_p(bundle_path)
22
+
23
+ gem_list.each do |name, gem_ref|
19
24
  next if backend_file_list.include?(gem_ref.tar_file)
20
25
  next unless member_of_installable_group?(gem_ref)
26
+
27
+ # Edge case: installation could fail if dependencies of this
28
+ # gem ref haven't been installed yet. They should have been
29
+ # prepared by this point because of the tsort logic in the
30
+ # gemfile class, but we need to actually install them in
31
+ # order to install this current gem. A good example is nokogiri,
32
+ # which can't build its native extension without mini-portile2.
33
+ gem_ref.dependencies.each do |dep|
34
+ if gem_list.gems[dep]
35
+ install_gem_ref(gem_list.gems[dep])
36
+ else
37
+ out.puts "Oops, couldn't find dependency #{dep}"
38
+ end
39
+ end
40
+
21
41
  install_gem(gem_ref) if gem_ref.installable?
22
42
  end
23
43
  end
@@ -79,17 +99,51 @@ module Prebundler
79
99
  config.storage_backend.store_file(dest_file, gem_ref.tar_file)
80
100
  end
81
101
 
102
+ def update_bundle_config
103
+ file = Bundler.app_config_path.join('config').to_s
104
+ config = File.exist?(file) ? YAML.load_file(file) : {}
105
+ config['BUNDLE_WITH'] = with_groups.join(':') unless with_groups.empty?
106
+ config['BUNDLE_WITHOUT'] = without_groups.join(':') unless without_groups.empty?
107
+ File.write(file, YAML.dump(config))
108
+ end
109
+
110
+ def generate_binstubs
111
+ out.puts 'Generating binstubs...'
112
+
113
+ gems_with_executables = gem_list.gems.values.select do |gem_ref|
114
+ next false unless member_of_installable_group?(gem_ref)
115
+ !gem_ref.executables.empty?
116
+ end
117
+
118
+ return if gems_with_executables.empty?
119
+
120
+ system "bundle binstubs #{gems_with_executables.map(&:name).join(' ')}"
121
+ system "bundle binstubs --force bundler"
122
+ out.puts 'Done generating binstubs'
123
+ end
124
+
82
125
  def check
83
- system 'bundle check'
126
+ system "bundle check --gemfile #{gemfile_path}"
84
127
 
85
128
  if $?.exitstatus != 0
86
129
  out.puts 'Bundle not satisfied, falling back to `bundle install`'
87
- system 'bundle install'
130
+ system "bundle install #{bundle_install_args}"
88
131
  end
89
132
  end
90
133
 
134
+ def bundle_install_args
135
+ [].tap do |args|
136
+ args << "--gemfile #{gemfile_path}"
137
+ args << "--with #{with_groups}" unless with_groups.empty?
138
+ args << "--without #{without_groups}" unless without_groups.empty?
139
+ args << "--jobs #{options[:jobs]}"
140
+ end.join(' ')
141
+ end
142
+
91
143
  def gem_list
92
- @gem_list ||= Prebundler::GemfileInterpreter.interpret(gemfile_path, bundle_path)
144
+ @gem_list ||= Prebundler::GemfileInterpreter.interpret(
145
+ gemfile_path, bundle_path
146
+ )
93
147
  end
94
148
 
95
149
  def backend_file_list
@@ -115,14 +169,18 @@ module Prebundler
115
169
 
116
170
  def groups
117
171
  @groups ||= begin
118
- all_groups = gem_list.flat_map { |_, gem_ref| gem_ref.groups }.uniq
119
- with_groups = (options[:with] || '').split(',').map { |g| g.strip.to_sym }
120
- without_groups = (options[:without] || '').split(',').map { |g| g.strip.to_sym }
121
-
122
- groups = with_groups.empty? ? all_groups : with_groups
123
- groups - without_groups
172
+ all_groups = gem_list.flat_map { |_, gem_ref| gem_ref.groups.to_a }.uniq
173
+ (all_groups + with_groups).uniq - without_groups
124
174
  end
125
175
  end
176
+
177
+ def with_groups
178
+ @with_groups ||= (options[:with] || '').split(/[:, ]/).map { |g| g.strip.to_sym }
179
+ end
180
+
181
+ def without_groups
182
+ @without_groups ||= (options[:without] || '').split(/[:, ]/).map { |g| g.strip.to_sym }
183
+ end
126
184
  end
127
185
  end
128
186
  end
@@ -1,4 +1,5 @@
1
1
  require 'fileutils'
2
+ require 'set'
2
3
 
3
4
  module Prebundler
4
5
  class GemRef
@@ -12,13 +13,13 @@ module Prebundler
12
13
  end
13
14
  end
14
15
 
15
- attr_reader :name, :bundle_path
16
+ attr_reader :name, :bundle_path, :groups
16
17
  attr_accessor :spec, :dependencies
17
18
 
18
19
  def initialize(name, bundle_path, options = {})
19
20
  @name = name
20
21
  @bundle_path = bundle_path
21
- @groups = options[:groups]
22
+ @groups = Set.new(options[:groups])
22
23
  @source = options[:source]
23
24
  @dependencies = options[:dependencies]
24
25
  end
@@ -27,10 +28,6 @@ module Prebundler
27
28
  @dependencies ||= []
28
29
  end
29
30
 
30
- def groups
31
- @groups ||= []
32
- end
33
-
34
31
  def source
35
32
  @source ||= DEFAULT_SOURCE
36
33
  end
@@ -44,8 +41,8 @@ module Prebundler
44
41
  end
45
42
 
46
43
  def install
47
- system "gem install -N -i #{bundle_path} --ignore-dependencies --source #{source} #{name} -v #{version}"
48
- $?.exitstatus == 0
44
+ system({ "GEM_HOME" => bundle_path }, "gem install -N --ignore-dependencies --source #{source} #{name} -v #{version}")
45
+ $?.exitstatus
49
46
  end
50
47
 
51
48
  def install_from_tar(tar_file)
@@ -57,11 +54,28 @@ module Prebundler
57
54
  tar_flags = File.exist?(tar_file) ? '-rf' : '-cf'
58
55
 
59
56
  system "tar -C #{bundle_path} #{tar_flags} #{tar_file} #{relative_gem_dir}"
60
- system "tar -C #{bundle_path} -rf #{tar_file} #{relative_gemspec_dir}"
57
+
58
+ relative_gemspec_files.each do |relative_gemspec_file|
59
+ system "tar -C #{bundle_path} -rf #{tar_file} #{relative_gemspec_file}"
60
+ end
61
61
 
62
62
  if File.directory?(extension_dir)
63
63
  system "tar -C #{bundle_path} -rf #{tar_file} #{relative_extension_dir}"
64
64
  end
65
+
66
+ executables.each do |executable|
67
+ system "tar -C #{bundle_path} -rf #{tar_file} #{File.join('bin', executable)}"
68
+ end
69
+ end
70
+
71
+ def executables
72
+ gemspecs.flat_map(&:executables)
73
+ end
74
+
75
+ def gemspecs
76
+ @gemspecs ||= relative_gemspec_files.map do |relative_gemspec_file|
77
+ Bundler.load_gemspec(File.join(bundle_path, relative_gemspec_file))
78
+ end
65
79
  end
66
80
 
67
81
  def installable?
@@ -96,8 +110,8 @@ module Prebundler
96
110
  File.join('gems', id)
97
111
  end
98
112
 
99
- def relative_gemspec_dir
100
- File.join('specifications', gemspec_file)
113
+ def relative_gemspec_files
114
+ [File.join('specifications', gemspec_file)]
101
115
  end
102
116
 
103
117
  def tar_file
@@ -9,6 +9,10 @@ module Prebundler
9
9
 
10
10
  def initialize(gems)
11
11
  @gems = gems
12
+
13
+ gems.each do |_, gem_ref|
14
+ assign_groups(gem_ref, [])
15
+ end
12
16
  end
13
17
 
14
18
  def each
@@ -23,6 +27,16 @@ module Prebundler
23
27
 
24
28
  private
25
29
 
30
+ # propagate groups to dependencies
31
+ def assign_groups(gem_ref, seen)
32
+ gem_ref.dependencies.each do |dep|
33
+ next if seen.include?(dep)
34
+ next unless gems[dep]
35
+ gem_ref.groups.each { |group| gems[dep].groups << group }
36
+ assign_groups(gems[dep], seen + [dep])
37
+ end
38
+ end
39
+
26
40
  def tsort_each_node(&block)
27
41
  gems.keys.each(&block)
28
42
  end
@@ -1,18 +1,21 @@
1
+ require 'set'
2
+
1
3
  module Prebundler
2
4
  class GemfileInterpreter
3
- def self.interpret(path, bundle_path)
4
- Gemfile.new(new(path, bundle_path).gems)
5
+ def self.interpret(gemfile_path, bundle_path)
6
+ Gemfile.new(new(gemfile_path, bundle_path).gems)
5
7
  end
6
8
 
7
- attr_reader :gems, :bundle_path
9
+ attr_reader :gems, :gemfile_path, :bundle_path
8
10
 
9
- def initialize(path, bundle_path)
11
+ def initialize(gemfile_path, bundle_path)
10
12
  @gems = {}
11
- @current_groups = []
13
+ @current_groups = [:global]
14
+ @gemfile_path = gemfile_path
12
15
  @bundle_path = bundle_path
13
- instance_eval(File.read(path))
16
+ instance_eval(File.read(gemfile_path))
14
17
 
15
- lockfile = Bundler::LockfileParser.new(File.read("#{path}.lock"))
18
+ lockfile = Bundler::LockfileParser.new(File.read("#{gemfile_path}.lock"))
16
19
 
17
20
  lockfile.specs.each do |spec|
18
21
  gems[spec.name] ||= GemRef.create(spec.name, bundle_path)
@@ -35,7 +38,7 @@ module Prebundler
35
38
  end
36
39
 
37
40
  def path(dir)
38
- @current_path = dir
41
+ @current_path = File.join(File.dirname(gemfile_path), dir)
39
42
  yield if block_given?
40
43
  @current_path = nil
41
44
  end
@@ -49,7 +52,7 @@ module Prebundler
49
52
  def group(*groups)
50
53
  @current_groups = groups
51
54
  yield if block_given?
52
- @current_groups = []
55
+ @current_groups = [:global]
53
56
  end
54
57
 
55
58
  def gemspec
@@ -15,10 +15,13 @@ module Prebundler
15
15
  def initialize(name, bundle_path, options = {})
16
16
  super
17
17
  @strategy = options.include?(:git) ? :git : :github
18
- @uri = options[@strategy]
19
18
  end
20
19
 
21
20
  def install
21
+ FileUtils.mkdir_p(spec_path)
22
+ FileUtils.mkdir_p(install_path)
23
+ FileUtils.mkdir_p(cache_path)
24
+
22
25
  return if File.exist?(cache_dir) || File.exist?(install_dir)
23
26
  system "git clone #{uri} \"#{cache_dir}\" --bare --no-hardlinks --quiet"
24
27
  return $? if $?.exitstatus != 0
@@ -55,11 +58,7 @@ module Prebundler
55
58
  end
56
59
 
57
60
  def uri
58
- if strategy == :github
59
- "git://github.com/#{@uri}.git"
60
- else
61
- @uri
62
- end
61
+ spec.source.uri
63
62
  end
64
63
 
65
64
  alias_method :source, :uri
@@ -68,16 +67,26 @@ module Prebundler
68
67
  spec.source.revision
69
68
  end
70
69
 
70
+ def gemspecs
71
+ @gemspecs ||= gemspec_files.map do |gemspec_file|
72
+ Bundler.load_gemspec(gemspec_file)
73
+ end
74
+ end
75
+
71
76
  private
72
77
 
78
+ def gemspec_files
79
+ @gemspec_files ||= Dir[File.join(install_dir, '*.gemspec')]
80
+ end
81
+
73
82
  def copy_gemspecs
74
- FileUtils.cp(Dir[File.join(install_dir, '*.gemspec')], spec_path)
83
+ FileUtils.cp(gemspec_files, spec_path)
75
84
  end
76
85
 
77
86
  # adapted from
78
87
  # https://github.com/bundler/bundler/blob/fea23637886c1b1bde471c98344b8844f82e60ce/lib/bundler/source/git.rb#L237
79
88
  def serialize_gemspecs
80
- Dir[File.join(install_dir, '*.gemspec')].each do |path|
89
+ gemspec_files.each do |path|
81
90
  # Evaluate gemspecs and cache the result. Gemspecs
82
91
  # in git might require git or other dependencies.
83
92
  # The gemspecs we cache should already be evaluated.
@@ -100,7 +109,7 @@ module Prebundler
100
109
  # If there is no URI scheme, assume it is an ssh/git URI
101
110
  input = uri
102
111
  end
103
- Digest::SHA1.hexdigest(input)
112
+ Bundler::SharedHelpers.digest(:SHA1).hexdigest(input)
104
113
  end
105
114
  end
106
115
  end
@@ -10,7 +10,11 @@ module Prebundler
10
10
 
11
11
  def initialize(name, bundle_path, options = {})
12
12
  super
13
- @path = options[:path]
13
+
14
+ # @TODO: Individual gem calls can also specify a path, which
15
+ # we don't currently handle. For now just use the gem's name
16
+ # to complete the path.
17
+ @path = File.join(options[:path], name)
14
18
  end
15
19
 
16
20
  def installable?
@@ -21,6 +25,20 @@ module Prebundler
21
25
  false
22
26
  end
23
27
 
28
+ def gemspecs
29
+ @gemspecs ||= gemspec_files.map do |gemspec_file|
30
+ Dir.chdir(File.dirname(gemspec_file)) do
31
+ Bundler.load_gemspec(File.basename(gemspec_file))
32
+ end
33
+ end
34
+ end
35
+
24
36
  alias_method :source, :path
37
+
38
+ private
39
+
40
+ def gemspec_files
41
+ @gemspec_files ||= Dir[File.join(path, '*.gemspec')]
42
+ end
25
43
  end
26
44
  end
@@ -1,3 +1,3 @@
1
1
  module Prebundler
2
- VERSION = '0.0.4'
2
+ VERSION = '0.5.0'
3
3
  end
data/prebundler.gemspec CHANGED
@@ -17,9 +17,8 @@ Gem::Specification.new do |s|
17
17
  s.add_dependency 'parallel', '~> 1.0'
18
18
  s.add_dependency 'gli', '~> 2.0'
19
19
 
20
- # @TODO: remove these, maybe move s3 support into separate gem?
20
+ # @TODO: move s3 support into separate gem
21
21
  s.add_dependency 'aws-sdk', '~> 2.0'
22
- s.add_dependency 'pry-byebug'
23
22
 
24
23
  s.executables << 'prebundle'
25
24
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prebundler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cameron Dutro
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-29 00:00:00.000000000 Z
11
+ date: 2017-12-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,20 +66,6 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '2.0'
69
- - !ruby/object:Gem::Dependency
70
- name: pry-byebug
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
69
  description: Gem dependency prebuilder
84
70
  email:
85
71
  - camertron@gmail.com