lib/rbs/collection/config/lockfile_generator.rb in rbs-2.8.4 vs lib/rbs/collection/config/lockfile_generator.rb in rbs-3.0.0.dev.1

- old
+ new

@@ -18,97 +18,138 @@ Actual Gemfile.lock: #{@actual} MESSAGE end end - attr_reader :config, :lock, :gemfile_lock, :lock_path + attr_reader :config, :lockfile, :gemfile_lock, :existing_lockfile - def self.generate(config_path:, gemfile_lock_path:, with_lockfile: true) - new(config_path: config_path, gemfile_lock_path: gemfile_lock_path, with_lockfile: with_lockfile).generate + def self.generate(config:, gemfile_lock_path:, with_lockfile: true) + generator = new(config: config, gemfile_lock_path: gemfile_lock_path, with_lockfile: with_lockfile) + generator.generate + generator.lockfile end - def initialize(config_path:, gemfile_lock_path:, with_lockfile:) - @config = Config.from_path config_path - @lock_path = Config.to_lockfile_path(config_path) - @lock = Config.from_path(lock_path) if lock_path.exist? && with_lockfile - @gemfile_lock = Bundler::LockfileParser.new(gemfile_lock_path.read) - @gem_queue = [] + def initialize(config:, gemfile_lock_path:, with_lockfile:) + @config = config - validate_gemfile_lock_path!(lock: lock, gemfile_lock_path: gemfile_lock_path) + lockfile_path = Config.to_lockfile_path(config.config_path) + lockfile_dir = lockfile_path.parent - config.gemfile_lock_path = gemfile_lock_path + @lockfile = Lockfile.new( + lockfile_path: lockfile_path, + path: config.repo_path_data, + gemfile_lock_path: gemfile_lock_path.relative_path_from(lockfile_dir) + ) + config.sources.each do |source| + case source + when Sources::Git + lockfile.sources[source.name] = source + end + end + + 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) + end + + @gemfile_lock = Bundler::LockfileParser.new(gemfile_lock_path.read) end def generate + ignored_gems = config.gems.select {|gem| gem["ignore"] }.map {|gem| gem["name"] }.to_set + config.gems.each do |gem| - @gem_queue.push({ name: gem['name'], version: gem['version'] }) + if Sources::Stdlib.instance.has?(gem["name"], nil) || gem.dig("source", "type") == "stdlib" + unless ignored_gems.include?(gem["name"]) + assign_stdlib(name: gem["name"], from_gem: nil) + end + else + assign_gem(name: gem["name"], version: gem["version"], ignored_gems: ignored_gems, src_data: gem["source"]) + end end gemfile_lock_gems do |spec| - @gem_queue.push({ name: spec.name, version: spec.version }) + assign_gem(name: spec.name, version: spec.version, ignored_gems: ignored_gems, src_data: nil) end - while gem = @gem_queue.shift - assign_gem(**gem) - end - remove_ignored_gems! - - config.dump_to(lock_path) - config + lockfile.lockfile_path.write(YAML.dump(lockfile.to_lockfile)) end private def validate_gemfile_lock_path!(lock:, gemfile_lock_path:) return unless lock - return unless lock.gemfile_lock_path - return if lock.gemfile_lock_path == gemfile_lock_path - - raise GemfileLockMismatchError.new(expected: lock.gemfile_lock_path, actual: gemfile_lock_path) + return unless lock.gemfile_lock_fullpath + unless lock.gemfile_lock_fullpath == gemfile_lock_path + raise GemfileLockMismatchError.new(expected: lock.gemfile_lock_fullpath, actual: gemfile_lock_path) + end end - private def assign_gem(name:, version:) - # @type var locked: gem_entry? - locked = lock&.gem(name) - specified = config.gem(name) + private def assign_gem(name:, version:, ignored_gems:, src_data:) + return if ignored_gems.include?(name) + return if lockfile.gems.key?(name) - return if specified&.dig('ignore') - return if specified&.dig('source') # skip if the source is already filled + # @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 = find_source(name: name) + source = + if src_data + Sources.from_config_entry(src_data) + else + find_source(name: name) + end return unless source installed_version = version - best_version = find_best_version(version: installed_version, versions: source.versions({ 'name' => name })) + best_version = find_best_version(version: installed_version, versions: source.versions(name)) locked = { - 'name' => name, - 'version' => best_version.to_s, - 'source' => source.to_lockfile, + name: name, + version: best_version.to_s, + source: source, } end locked or raise - upsert_gem specified, locked - source = Sources.from_config_entry(locked['source'] || raise) - source.dependencies_of(locked)&.each do |dep| - @gem_queue.push({ name: dep['name'], version: nil} ) + lockfile.gems[name] = locked + source = locked[:source] + + source.dependencies_of(locked[:name], locked[:version])&.each do |dep| + assign_stdlib(name: dep["name"], from_gem: name) end end - private def upsert_gem(old, new) - if old - old.merge! new - else - config.add_gem new + private def assign_stdlib(name:, from_gem:) + return if lockfile.gems.key?(name) + + if name == 'rubygems' + if from_gem + RBS.logger.warn "`rubygems` has been moved to core library, so it is always loaded. Remove explicit loading `rubygems` from `#{from_gem}`" + else + RBS.logger.warn '`rubygems` has been moved to core library, so it is always loaded. Remove explicit loading `rubygems`' + end + + return end - end - private def remove_ignored_gems! - config.gems.reject! { |gem| gem['ignore'] } + 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 private def gemfile_lock_gems(&block) gemfile_lock.specs.each do |spec| yield spec @@ -116,10 +157,10 @@ end private def find_source(name:) sources = config.sources - sources.find { |c| c.has?({ 'name' => name, 'revision' => nil } ) } + sources.find { |c| c.has?(name, nil) } end private def find_best_version(version:, versions:) candidates = versions.map { |v| Gem::Version.create(v) or raise } return candidates.max || raise unless version