Skip to content

Commit 277674e

Browse files
authored
Merge pull request #1222 from ruby/gemfile-require
Skip loading `require: false` gems in collection
2 parents 95ee114 + ea62411 commit 277674e

File tree

10 files changed

+210
-110
lines changed

10 files changed

+210
-110
lines changed

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,4 @@ DEPENDENCIES
115115
test-unit
116116

117117
BUNDLED WITH
118-
2.3.14
118+
2.4.6

lib/rbs/cli.rb

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,15 +1060,12 @@ def run_collection(args, options)
10601060
case args[0]
10611061
when 'install'
10621062
unless params[:frozen]
1063-
gemfile_lock_path = Bundler.default_lockfile
1064-
Collection::Config.generate_lockfile(config_path: config_path, gemfile_lock_path: gemfile_lock_path)
1063+
Collection::Config.generate_lockfile(config_path: config_path, definition: Bundler.definition)
10651064
end
10661065
Collection::Installer.new(lockfile_path: lock_path, stdout: stdout).install_from_lockfile
10671066
when 'update'
1068-
gemfile_lock_path = Bundler.default_lockfile
1069-
10701067
# TODO: Be aware of argv to update only specified gem
1071-
Collection::Config.generate_lockfile(config_path: config_path, gemfile_lock_path: gemfile_lock_path, with_lockfile: false)
1068+
Collection::Config.generate_lockfile(config_path: config_path, definition: Bundler.definition, with_lockfile: false)
10721069
Collection::Installer.new(lockfile_path: lock_path, stdout: stdout).install_from_lockfile
10731070
when 'init'
10741071
if config_path.exist?

lib/rbs/collection/config.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ def self.find_config_path
3131

3232
# Generate a rbs lockfile from Gemfile.lock to `config_path`.
3333
# If `with_lockfile` is true, it respects existing rbs lockfile.
34-
def self.generate_lockfile(config_path:, gemfile_lock_path:, with_lockfile: true)
34+
def self.generate_lockfile(config_path:, definition:, with_lockfile: true)
3535
config = from_path(config_path)
36-
lockfile = LockfileGenerator.generate(config: config, gemfile_lock_path: gemfile_lock_path, with_lockfile: with_lockfile)
36+
lockfile = LockfileGenerator.generate(config: config, definition: definition, with_lockfile: with_lockfile)
3737

3838
[config, lockfile]
3939
end

lib/rbs/collection/config/lockfile_generator.rb

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ def message
2020
end
2121
end
2222

23-
attr_reader :config, :lockfile, :gemfile_lock, :existing_lockfile
23+
attr_reader :config, :lockfile, :definition, :existing_lockfile, :gem_hash
2424

25-
def self.generate(config:, gemfile_lock_path:, with_lockfile: true)
26-
generator = new(config: config, gemfile_lock_path: gemfile_lock_path, with_lockfile: with_lockfile)
25+
def self.generate(config:, definition:, with_lockfile: true)
26+
generator = new(config: config, definition: definition, with_lockfile: with_lockfile)
2727
generator.generate
2828
generator.lockfile
2929
end
3030

31-
def initialize(config:, gemfile_lock_path:, with_lockfile:)
31+
def initialize(config:, definition:, with_lockfile:)
3232
@config = config
3333

3434
lockfile_path = Config.to_lockfile_path(config.config_path)
@@ -37,7 +37,7 @@ def initialize(config:, gemfile_lock_path:, with_lockfile:)
3737
@lockfile = Lockfile.new(
3838
lockfile_path: lockfile_path,
3939
path: config.repo_path_data,
40-
gemfile_lock_path: gemfile_lock_path.relative_path_from(lockfile_dir)
40+
gemfile_lock_path: definition.lockfile.relative_path_from(lockfile_dir)
4141
)
4242
config.sources.each do |source|
4343
case source
@@ -48,10 +48,13 @@ def initialize(config:, gemfile_lock_path:, with_lockfile:)
4848

4949
if with_lockfile && lockfile_path.file?
5050
@existing_lockfile = Lockfile.from_lockfile(lockfile_path: lockfile_path, data: YAML.load_file(lockfile_path.to_s))
51-
validate_gemfile_lock_path!(lock: @existing_lockfile, gemfile_lock_path: gemfile_lock_path)
51+
validate_gemfile_lock_path!(lock: @existing_lockfile, gemfile_lock_path: definition.lockfile)
5252
end
5353

54-
@gemfile_lock = Bundler::LockfileParser.new(gemfile_lock_path.read)
54+
@definition = definition
55+
@gem_hash = definition.locked_gems.specs.each.with_object({}) do |spec, hash| #$ Hash[String, Bundler::LazySpecification]
56+
hash[spec.name] = spec
57+
end
5558
end
5659

5760
def generate
@@ -67,8 +70,13 @@ def generate
6770
end
6871
end
6972

70-
gemfile_lock_gems do |spec|
71-
assign_gem(name: spec.name, version: spec.version, ignored_gems: ignored_gems, src_data: nil)
73+
definition.dependencies.each do |dep|
74+
if dep.autorequire && dep.autorequire.empty?
75+
next
76+
end
77+
78+
spec = gem_hash[dep.name] or raise "Cannot find `#{dep.name}` in bundler context"
79+
assign_gem(name: dep.name, version: spec.version, ignored_gems: ignored_gems, src_data: nil)
7280
end
7381

7482
lockfile.lockfile_path.write(YAML.dump(lockfile.to_lockfile))
@@ -82,7 +90,7 @@ def generate
8290
end
8391
end
8492

85-
private def assign_gem(name:, version:, ignored_gems:, src_data:)
93+
private def assign_gem(name:, version:, src_data:, ignored_gems:)
8694
return if ignored_gems.include?(name)
8795
return if lockfile.gems.key?(name)
8896

@@ -99,9 +107,8 @@ def generate
99107
if src_data
100108
Sources.from_config_entry(src_data)
101109
else
102-
find_source(name: name)
110+
find_source(name: name) or return
103111
end
104-
return unless source
105112

106113
installed_version = version
107114
best_version = find_best_version(version: installed_version, versions: source.versions(name))
@@ -116,11 +123,15 @@ def generate
116123
locked or raise
117124

118125
lockfile.gems[name] = locked
119-
source = locked[:source]
120126

121-
source.dependencies_of(locked[:name], locked[:version])&.each do |dep|
127+
locked[:source].dependencies_of(locked[:name], locked[:version])&.each do |dep|
122128
assign_stdlib(name: dep["name"], from_gem: name)
123129
end
130+
131+
gem_hash[name].dependencies.each do |dep|
132+
spec = gem_hash[dep.name]
133+
assign_gem(name: dep.name, version: spec.version, src_data: nil, ignored_gems: ignored_gems)
134+
end
124135
end
125136

126137
private def assign_stdlib(name:, from_gem:)
@@ -150,12 +161,6 @@ def generate
150161
end
151162
end
152163

153-
private def gemfile_lock_gems(&block)
154-
gemfile_lock.specs.each do |spec|
155-
yield spec
156-
end
157-
end
158-
159164
private def find_source(name:)
160165
sources = config.sources
161166

sig/collection/config.rbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ module RBS
2323

2424
def self.find_config_path: () -> Pathname?
2525

26-
def self.generate_lockfile: (config_path: Pathname, gemfile_lock_path: Pathname, ?with_lockfile: boolish) -> [Config, Lockfile]
26+
def self.generate_lockfile: (config_path: Pathname, definition: Bundler::Definition, ?with_lockfile: boolish) -> [Config, Lockfile]
2727

2828
def self.from_path: (Pathname path) -> Config
2929

sig/collection/config/lockfile_generator.rbs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,18 @@ module RBS
1313
end
1414

1515
attr_reader config: Config
16-
attr_reader gemfile_lock: Bundler::LockfileParser
1716

1817
attr_reader lockfile: Lockfile
1918
attr_reader existing_lockfile: Lockfile?
2019

21-
type gem_queue_entry = { name: String, version: String? }
20+
attr_reader definition: Bundler::Definition
2221

23-
@gem_queue: Array[gem_queue_entry]
22+
# A hash table to look up a spec from name of the gem
23+
attr_reader gem_hash: Hash[String, Bundler::LazySpecification]
2424

25-
def self.generate: (config: Config, gemfile_lock_path: Pathname, ?with_lockfile: boolish) -> Lockfile
25+
def self.generate: (config: Config, definition: Bundler::Definition, ?with_lockfile: boolish) -> Lockfile
2626

27-
def initialize: (config: Config, gemfile_lock_path: Pathname, with_lockfile: boolish) -> void
27+
def initialize: (config: Config, definition: Bundler::Definition, with_lockfile: boolish) -> void
2828

2929
def generate: () -> void
3030

@@ -34,14 +34,12 @@ module RBS
3434
#
3535
def validate_gemfile_lock_path!: (lock: Lockfile?, gemfile_lock_path: Pathname) -> void
3636

37-
def assign_gem: (name: String, version: String?, ignored_gems: Set[String], src_data: Sources::source_entry?) -> void
37+
# Inserts a entry to lockfile of a gem and its dependencies, if not included in `ignored_gems:`
38+
#
39+
def assign_gem: (name: String, version: String?, src_data: Sources::source_entry?, ignored_gems: Set[String]) -> void
3840

3941
def assign_stdlib: (name: String, from_gem: String?) -> void
4042

41-
def gemfile_lock_gems: () { (untyped) -> void } -> void
42-
43-
def remove_ignored_gems!: () -> void
44-
4543
# Find a source of a gem from ones registered in `config.sources`
4644
#
4745
# Returns `nil` if no source contains the definition of the gem.

sig/collection/sources.rbs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,28 +78,34 @@ module RBS
7878

7979
def cp_r: (Pathname, Pathname) -> void
8080

81-
# Ensure the git repository status is expected one
81+
# Ensure the git repository exists, and
8282
#
83-
# * It exists, and
84-
# * The `HEAD` is the `revision`
83+
# * When `revision` is a commit hash, the commit exists in the local repository, or
84+
# * When `revision` is a branch name, the latest version is fetched from `origin`
85+
#
86+
# It may require a network connection to fetch or clone the repository from remote.
87+
#
88+
# * If `revision` is a commit hash and the commit doesn't exists in the local repository, it runs `git fetch`
89+
# * If `revision` is a branch name, it runs `git fetch` once per instance
8590
#
8691
def setup!: [T] () { () -> T } -> T
8792
| () -> void
8893

8994
def need_to_fetch?: (String revision) -> bool
9095

96+
# The full path of local git repository
9197
def git_dir: () -> Pathname
9298

99+
# The full path of `repo_dir` in the local git repository
93100
def gem_repo_dir: () -> Pathname
94101

95-
def with_revision: [T] () { () -> T } -> T
96-
97102
# Returns `true` if `revision` looks like a commit hash
98-
#
99103
def commit_hash?: () -> bool
100104

105+
# Executes a git command, raises an error if failed
101106
def git: (*String cmd, **untyped opt) -> String
102107

108+
# Executes a git command, returns `nil` if failed
103109
def git?: (*String cmd, **untyped opt) -> String?
104110

105111
def sh!: (*String cmd, **untyped opt) -> String

sig/shims/bundler.rbs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,31 @@
11
module Bundler
22
class LockfileParser
33
def initialize: (String) -> void
4+
45
def specs: () -> Array[LazySpecification]
56
end
67

78
class LazySpecification
89
def name: () -> String
10+
911
def version: () -> String
12+
13+
def dependencies: () -> Array[Gem::Dependency]
14+
end
15+
16+
class Dependency < Gem::Dependency
17+
attr_reader autorequire: Array[String]?
18+
end
19+
20+
class Definition
21+
def lockfile: () -> Pathname
22+
23+
def locked_gems: () -> LockfileParser
24+
25+
def dependencies: () -> Array[Dependency]
1026
end
1127

1228
def self.default_lockfile: () -> Pathname
29+
30+
def self.definition: () -> Definition
1331
end

sig/shims/rubygems.rbs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,11 @@ module Gem
55
attr_reader gem_dir (): String
66

77
def self.find_by_name: (String name, *String requirements) -> instance
8+
9+
def dependencies: () -> Array[Dependency]
10+
end
11+
12+
class Dependency
13+
def name: () -> String
814
end
915
end

0 commit comments

Comments
 (0)