Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,4 @@ DEPENDENCIES
test-unit

BUNDLED WITH
2.3.14
2.4.6
7 changes: 2 additions & 5 deletions lib/rbs/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1060,15 +1060,12 @@ def run_collection(args, options)
case args[0]
when 'install'
unless params[:frozen]
gemfile_lock_path = Bundler.default_lockfile
Collection::Config.generate_lockfile(config_path: config_path, gemfile_lock_path: gemfile_lock_path)
Collection::Config.generate_lockfile(config_path: config_path, definition: Bundler.definition)
end
Collection::Installer.new(lockfile_path: lock_path, stdout: stdout).install_from_lockfile
when 'update'
gemfile_lock_path = Bundler.default_lockfile

# TODO: Be aware of argv to update only specified gem
Collection::Config.generate_lockfile(config_path: config_path, gemfile_lock_path: gemfile_lock_path, with_lockfile: false)
Collection::Config.generate_lockfile(config_path: config_path, definition: Bundler.definition, with_lockfile: false)
Collection::Installer.new(lockfile_path: lock_path, stdout: stdout).install_from_lockfile
when 'init'
if config_path.exist?
Expand Down
4 changes: 2 additions & 2 deletions lib/rbs/collection/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ def self.find_config_path

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

[config, lockfile]
end
Expand Down
45 changes: 25 additions & 20 deletions lib/rbs/collection/config/lockfile_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ def message
end
end

attr_reader :config, :lockfile, :gemfile_lock, :existing_lockfile
attr_reader :config, :lockfile, :definition, :existing_lockfile, :gem_hash

def self.generate(config:, gemfile_lock_path:, with_lockfile: true)
generator = new(config: config, gemfile_lock_path: gemfile_lock_path, with_lockfile: with_lockfile)
def self.generate(config:, definition:, with_lockfile: true)
generator = new(config: config, definition: definition, with_lockfile: with_lockfile)
generator.generate
generator.lockfile
end

def initialize(config:, gemfile_lock_path:, with_lockfile:)
def initialize(config:, definition:, with_lockfile:)
@config = config

lockfile_path = Config.to_lockfile_path(config.config_path)
Expand All @@ -37,7 +37,7 @@ def initialize(config:, gemfile_lock_path:, with_lockfile:)
@lockfile = Lockfile.new(
lockfile_path: lockfile_path,
path: config.repo_path_data,
gemfile_lock_path: gemfile_lock_path.relative_path_from(lockfile_dir)
gemfile_lock_path: definition.lockfile.relative_path_from(lockfile_dir)
)
config.sources.each do |source|
case source
Expand All @@ -48,10 +48,13 @@ def initialize(config:, gemfile_lock_path:, with_lockfile:)

if with_lockfile && lockfile_path.file?
@existing_lockfile = Lockfile.from_lockfile(lockfile_path: lockfile_path, data: YAML.load_file(lockfile_path.to_s))
validate_gemfile_lock_path!(lock: @existing_lockfile, gemfile_lock_path: gemfile_lock_path)
validate_gemfile_lock_path!(lock: @existing_lockfile, gemfile_lock_path: definition.lockfile)
end

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

def generate
Expand All @@ -67,8 +70,13 @@ def generate
end
end

gemfile_lock_gems do |spec|
assign_gem(name: spec.name, version: spec.version, ignored_gems: ignored_gems, src_data: nil)
definition.dependencies.each do |dep|
if dep.autorequire && dep.autorequire.empty?
next
end

spec = gem_hash[dep.name] or raise "Cannot find `#{dep.name}` in bundler context"
assign_gem(name: dep.name, version: spec.version, ignored_gems: ignored_gems, src_data: nil)
end

lockfile.lockfile_path.write(YAML.dump(lockfile.to_lockfile))
Expand All @@ -82,7 +90,7 @@ def generate
end
end

private def assign_gem(name:, version:, ignored_gems:, src_data:)
private def assign_gem(name:, version:, src_data:, ignored_gems:)
return if ignored_gems.include?(name)
return if lockfile.gems.key?(name)

Expand All @@ -99,9 +107,8 @@ def generate
if src_data
Sources.from_config_entry(src_data)
else
find_source(name: name)
find_source(name: name) or return
end
return unless source

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

lockfile.gems[name] = locked
source = locked[:source]

source.dependencies_of(locked[:name], locked[:version])&.each do |dep|
locked[:source].dependencies_of(locked[:name], locked[:version])&.each do |dep|
assign_stdlib(name: dep["name"], from_gem: name)
end

gem_hash[name].dependencies.each do |dep|
spec = gem_hash[dep.name]
assign_gem(name: dep.name, version: spec.version, src_data: nil, ignored_gems: ignored_gems)
end
end

private def assign_stdlib(name:, from_gem:)
Expand Down Expand Up @@ -150,12 +161,6 @@ def generate
end
end

private def gemfile_lock_gems(&block)
gemfile_lock.specs.each do |spec|
yield spec
end
end

private def find_source(name:)
sources = config.sources

Expand Down
2 changes: 1 addition & 1 deletion sig/collection/config.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ module RBS

def self.find_config_path: () -> Pathname?

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

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

Expand Down
18 changes: 8 additions & 10 deletions sig/collection/config/lockfile_generator.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@ module RBS
end

attr_reader config: Config
attr_reader gemfile_lock: Bundler::LockfileParser

attr_reader lockfile: Lockfile
attr_reader existing_lockfile: Lockfile?

type gem_queue_entry = { name: String, version: String? }
attr_reader definition: Bundler::Definition

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

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

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

def generate: () -> void

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

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

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

def gemfile_lock_gems: () { (untyped) -> void } -> void

def remove_ignored_gems!: () -> void

# Find a source of a gem from ones registered in `config.sources`
#
# Returns `nil` if no source contains the definition of the gem.
Expand Down
18 changes: 12 additions & 6 deletions sig/collection/sources.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -78,28 +78,34 @@ module RBS

def cp_r: (Pathname, Pathname) -> void

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

def need_to_fetch?: (String revision) -> bool

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

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

def with_revision: [T] () { () -> T } -> T

# Returns `true` if `revision` looks like a commit hash
#
def commit_hash?: () -> bool

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

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

def sh!: (*String cmd, **untyped opt) -> String
Expand Down
18 changes: 18 additions & 0 deletions sig/shims/bundler.rbs
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
module Bundler
class LockfileParser
def initialize: (String) -> void

def specs: () -> Array[LazySpecification]
end

class LazySpecification
def name: () -> String

def version: () -> String

def dependencies: () -> Array[Gem::Dependency]
end

class Dependency < Gem::Dependency
attr_reader autorequire: Array[String]?
end

class Definition
def lockfile: () -> Pathname

def locked_gems: () -> LockfileParser

def dependencies: () -> Array[Dependency]
end

def self.default_lockfile: () -> Pathname

def self.definition: () -> Definition
end
6 changes: 6 additions & 0 deletions sig/shims/rubygems.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,11 @@ module Gem
attr_reader gem_dir (): String

def self.find_by_name: (String name, *String requirements) -> instance

def dependencies: () -> Array[Dependency]
end

class Dependency
def name: () -> String
end
end
Loading