Class: RBS::Collection::Config::LockfileGenerator
- Inherits:
-
Object
- Object
- RBS::Collection::Config::LockfileGenerator
- Defined in:
- lib/rbs/collection/config/lockfile_generator.rb,
sig/collection/config/lockfile_generator.rbs
Defined Under Namespace
Classes: GemfileLockMismatchError
Constant Summary collapse
- ALUMNI_STDLIBS =
Name of stdlibs that was rbs-bundled stdlib but is now a gem.
{ "mutex_m" => ">= 0.3.0", "abbrev" => nil, "base64" => nil, "benchmark" => nil, "bigdecimal" => nil, "csv" => nil, "kconv" => nil, "logger" => nil, "minitest" => nil, "net-smtp" => nil, "nkf" => nil, "observer" => nil, "cgi" => nil, "pstore" => nil, }
- NONGEM_STDLIBS =
Set[ "cgi-escape", "coverage", "monitor", "objspace", "pathname", "pty", "ripper", "socket", ]
Instance Attribute Summary collapse
-
#config ⇒ Config
readonly
Returns the value of attribute config.
-
#definition ⇒ Bundler::Definition
readonly
Returns the value of attribute definition.
-
#existing_lockfile ⇒ Lockfile?
readonly
Returns the value of attribute existing_lockfile.
-
#gem_entries ⇒ Hash[String, gem_entry?]
readonly
A hash table to look up a gem entry in collection config from the name of the gem.
-
#gem_hash ⇒ Hash[String, Bundler::LazySpecification]
readonly
A hash table to look up a spec from name of the gem.
-
#lockfile ⇒ Lockfile
readonly
Returns the value of attribute lockfile.
Class Method Summary collapse
Instance Method Summary collapse
-
#assign_gem(name:, version:, skip: false) ⇒ void
Inserts a entry to lockfile of a gem and its dependencies, if not included in
ignored_gems:. -
#assign_stdlib(name:, from_gem: nil) ⇒ void
Assign a gem from stdlib to lockfile.
- #find_best_version(version:, versions:) ⇒ Gem::Version
-
#find_source(name:) ⇒ Sources::t?
Find a source of a gem from ones registered in
config.sources. - #generate ⇒ void
-
#initialize(config:, definition:, with_lockfile:) ⇒ LockfileGenerator
constructor
A new instance of LockfileGenerator.
-
#validate_gemfile_lock_path!(lock:, gemfile_lock_path:) ⇒ void
Ensure if current
gemfile_lock_pathis the same with the path saved inlock.
Constructor Details
#initialize(config:, definition:, with_lockfile:) ⇒ LockfileGenerator
Returns a new instance of LockfileGenerator.
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/rbs/collection/config/lockfile_generator.rb', line 59 def initialize(config:, definition:, with_lockfile:) @config = config @gem_entries = config.gems.each.with_object({}) do |entry, hash| #$ Hash[String, gem_entry?] name = entry["name"] hash[name] = entry end lockfile_path = Config.to_lockfile_path(config.config_path) lockfile_dir = lockfile_path.parent @lockfile = Lockfile.new( lockfile_path: lockfile_path, path: config.repo_path_data, gemfile_lock_path: definition.lockfile.relative_path_from(lockfile_dir) ) 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: definition.lockfile) end @definition = definition @gem_hash = definition.locked_gems.specs.each.with_object({}) do |spec, hash| #$ Hash[String, Bundler::LazySpecification] hash[spec.name] = spec end end |
Instance Attribute Details
#config ⇒ Config (readonly)
Returns the value of attribute config.
51 52 53 |
# File 'lib/rbs/collection/config/lockfile_generator.rb', line 51 def config @config end |
#definition ⇒ Bundler::Definition (readonly)
Returns the value of attribute definition.
51 52 53 |
# File 'lib/rbs/collection/config/lockfile_generator.rb', line 51 def definition @definition end |
#existing_lockfile ⇒ Lockfile? (readonly)
Returns the value of attribute existing_lockfile.
51 52 53 |
# File 'lib/rbs/collection/config/lockfile_generator.rb', line 51 def existing_lockfile @existing_lockfile end |
#gem_entries ⇒ Hash[String, gem_entry?] (readonly)
A hash table to look up a gem entry in collection config from the name of the gem
32 33 34 |
# File 'sig/collection/config/lockfile_generator.rbs', line 32 def gem_entries @gem_entries end |
#gem_hash ⇒ Hash[String, Bundler::LazySpecification] (readonly)
A hash table to look up a spec from name of the gem
29 30 31 |
# File 'sig/collection/config/lockfile_generator.rbs', line 29 def gem_hash @gem_hash end |
#lockfile ⇒ Lockfile (readonly)
Returns the value of attribute lockfile.
51 52 53 |
# File 'lib/rbs/collection/config/lockfile_generator.rb', line 51 def lockfile @lockfile end |
Class Method Details
.generate(config:, definition:, with_lockfile: true) ⇒ Lockfile
53 54 55 56 57 |
# File 'lib/rbs/collection/config/lockfile_generator.rb', line 53 def self.generate(config:, definition:, with_lockfile: true) generator = new(config: config, definition: definition, with_lockfile: with_lockfile) generator.generate generator.lockfile end |
Instance Method Details
#assign_gem(name:, version:, skip: false) ⇒ void
This method returns an undefined value.
Inserts a entry to lockfile of a gem and its dependencies, if not included in ignored_gems:
- If
skip:is true, it skips adding the gem, but adds it's dependencies.
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'sig/collection/config/lockfile_generator.rbs', line 50 private def assign_gem(name:, version:, skip: false) entry = gem_entries[name] src_data = entry&.fetch("source", nil) ignored = entry&.fetch("ignore", false) return if ignored return if lockfile.gems.key?(name) unless skip # @type var locked: Lockfile::library? if existing_lockfile locked = existing_lockfile.gems[name] end # If rbs_collection.lock.yaml contain the gem, use it. # Else find the gem from gem_collection. unless locked source = if src_data Sources.from_config_entry(src_data, base_directory: config.config_path.dirname) else find_source(name: name) end if source.is_a?(Sources::Stdlib) assign_stdlib(name: name) return end if source installed_version = version best_version = find_best_version(version: installed_version, versions: source.versions(name)) locked = { name: name, version: best_version.to_s, source: source, } end end if locked lockfile.gems[name] = locked begin locked[:source].dependencies_of(locked[:name], locked[:version])&.each do |dep| assign_stdlib(name: dep["name"], from_gem: name) end rescue RBS.logger.warn "Cannot find `#{locked[:name]}-#{locked[:version]}` gem. Using incorrect Bundler context? (#{definition.lockfile})" end end end if spec = gem_hash.fetch(name, nil) spec.dependencies.each do |dep| if dep_spec = gem_hash[dep.name] assign_gem(name: dep.name, version: dep_spec.version) end end else unless NONGEM_STDLIBS.include?(name) RBS.logger.warn "Cannot find `#{name}` gem. Using incorrect Bundler context? (#{definition.lockfile})" end end end |
#assign_stdlib(name:, from_gem: nil) ⇒ void
This method returns an undefined value.
Assign a gem from stdlib to lockfile
from_gem is a String when the stdlib is assigned through the dependencies: in manifest.yaml of a gem.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'sig/collection/config/lockfile_generator.rbs', line 56 private def assign_stdlib(name:, from_gem: nil) return if lockfile.gems.key?(name) case name when 'bigdecimal-math', 'kconv' # These gems are never released as a gem. # Therefore, `assign_gem` should not be called. RBS.logger.info { from = from_gem || "rbs_collection.yaml" "`#{name}` is included in the RBS dependencies of `#{from}`, but the type definition as a stdlib in rbs-gem is deprecated. Delete `#{name}` from the RBS dependencies of `#{from}`." } source = find_source(name: name) if source&.is_a?(Sources::Stdlib) lockfile.gems[name] = { name: name, version: "0", source: source } end return when 'set' # set is migrated to core from stdlib. RBS.logger.info { from = from_gem || "rbs_collection.yaml" "`#{name}` is a part of the Ruby core library. The dependency to the library can be safely deleted from #{from}." } return when *ALUMNI_STDLIBS.keys version = ALUMNI_STDLIBS.fetch(name) if from_gem # From `dependencies:` of a `manifest.yaml` of a gem source = find_source(name: name) or raise if source.is_a?(Sources::Stdlib) && version RBS.logger.warn { "`#{name}` is included in the RBS dependencies of `#{from_gem}`, but the type definition as a stdlib in rbs-gem is deprecated. Add `#{name}` (#{version}) to the dependency of your Ruby program to use the gem-bundled type definition." } else RBS.logger.info { "`#{name}` is included in the RBS dependencies of `#{from_gem}`, but the type definition as a stdlib in rbs-gem is deprecated. Delete `#{name}` from the RBS dependencies of `#{from_gem}`." } assign_gem(name: name, version: nil) return end else # From `gems:` of a `rbs_collection.yaml` RBS.logger.warn { if version "`#{name}` as a stdlib in rbs-gem is deprecated. Add `#{name}` (#{version}) to the dependency of your Ruby program to use the gem-bundled type definition." else "`#{name}` as a stdlib in rbs-gem is deprecated. Delete `#{name}` from the RBS dependencies in your rbs_collection.yaml." end } end end source = Sources::Stdlib.instance lockfile.gems[name] = { name: name, version: "0", source: source } unless source.has?(name, nil) raise "Cannot find `#{name}` from standard libraries" end if deps = source.dependencies_of(name, "0") deps.each do |dep| assign_stdlib(name: dep["name"], from_gem: name) end end end |
#find_best_version(version:, versions:) ⇒ Gem::Version
259 260 261 262 263 264 265 |
# File 'lib/rbs/collection/config/lockfile_generator.rb', line 259 private def find_best_version(version:, versions:) candidates = versions.map { |v| Gem::Version.create(v) or raise } return candidates.max || raise unless version v = Gem::Version.create(version) or raise Repository.find_best_version(v, candidates) end |
#find_source(name:) ⇒ Sources::t?
Find a source of a gem from ones registered in config.sources
Returns nil if no source contains the definition of the gem.
62 63 64 65 66 |
# File 'sig/collection/config/lockfile_generator.rbs', line 62 private def find_source(name:) sources = config.sources sources.find { |c| c.has?(name, nil) } end |
#generate ⇒ void
This method returns an undefined value.
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/rbs/collection/config/lockfile_generator.rb', line 87 def generate config.gems.each do |gem| case when gem.dig("source", "type") == "stdlib" unless gem.fetch("ignore", false) assign_stdlib(name: gem["name"]) end else assign_gem(name: gem["name"], version: gem["version"]) end end definition.dependencies.each do |dep| if dep.autorequire && dep.autorequire.empty? next end if spec = gem_hash[dep.name] assign_gem(name: dep.name, version: spec.version, skip: dep.source.is_a?(Bundler::Source::Gemspec)) end end lockfile.lockfile_path.write(YAML.dump(lockfile.to_lockfile)) end |
#validate_gemfile_lock_path!(lock:, gemfile_lock_path:) ⇒ void
This method returns an undefined value.
Ensure if current gemfile_lock_path is the same with the path saved in lock
44 45 46 47 48 49 50 |
# File 'sig/collection/config/lockfile_generator.rbs', line 44 private def validate_gemfile_lock_path!(lock:, gemfile_lock_path:) return unless lock return unless lock.gemfile_lock_fullpath unless File.realpath(lock.gemfile_lock_fullpath) == File.realpath(gemfile_lock_path) raise GemfileLockMismatchError.new(expected: lock.gemfile_lock_fullpath, actual: gemfile_lock_path) end end |