require'digest/sha2'require'open3'require'find'moduleRBSmoduleCollectionmoduleSourcesclassGitMETADATA_FILENAME='.rbs_meta.yaml'classCommandError<StandardError;endattr_reader:name,:remote,:repo_dirdefinitialize(name:,revision:,remote:,repo_dir:)@name=name@remote=remote@repo_dir=repo_dir||'gems'setup!(revision: revision)enddefhas?(config_entry)gem_name=config_entry['name']gem_repo_dir.join(gem_name).directory?enddefversions(config_entry)gem_name=config_entry['name']gem_repo_dir.join(gem_name).glob('*/').map{|path|path.basename.to_s}enddefinstall(dest:,config_entry:,stdout:)gem_name=config_entry['name']version=config_entry['version']orraisegem_dir=dest.join(gem_name,version)ifgem_dir.directory?if(prev=YAML.load_file(gem_dir.join(METADATA_FILENAME)))==config_entrystdout.puts"Using #{format_config_entry(config_entry)}"else# @type var prev: RBS::Collection::Config::gem_entrystdout.puts"Updating to #{format_config_entry(config_entry)} from #{format_config_entry(prev)}"FileUtils.remove_entry_secure(gem_dir.to_s)_install(dest: dest,config_entry: config_entry)endelsestdout.puts"Installing #{format_config_entry(config_entry)}"_install(dest: dest,config_entry: config_entry)endenddefmanifest_of(config_entry)gem_name=config_entry['name']version=config_entry['version']orraisegem_dir=gem_repo_dir.join(gem_name,version)manifest_path=gem_dir.join('manifest.yaml')YAML.safe_load(manifest_path.read)ifmanifest_path.exist?endprivatedef_install(dest:,config_entry:)gem_name=config_entry['name']version=config_entry['version']orraisedest=dest.join(gem_name,version)dest.mkpathsrc=gem_repo_dir.join(gem_name,version)cp_r(src,dest)dest.join(METADATA_FILENAME).write(YAML.dump(config_entry))endprivatedefcp_r(src,dest)Find.find(src)do|file_src|file_src=Pathname(file_src)# Skip file if it starts with _, such as _test/Find.pruneiffile_src.basename.to_s.start_with?('_')file_src_relative=file_src.relative_path_from(src)file_dest=dest.join(file_src_relative)file_dest.dirname.mkpathFileUtils.copy_entry(file_src,file_dest,false,true)unlessfile_src.directory?endenddefto_lockfile{'type'=>'git','name'=>name,'revision'=>resolved_revision,'remote'=>remote,'repo_dir'=>repo_dir,}endprivatedefformat_config_entry(config_entry)name=config_entry['name']v=config_entry['version']rev=resolved_revision[0..10]desc="#{name}@#{rev}""#{name}:#{v} (#{desc})"endprivatedefsetup!(revision:)git_dir.mkpathifgit_dir.join('.git').directory?ifneed_to_fetch?(revision)git'fetch','origin'endelsebegin# git v2.27.0 or greatergit'clone','--filter=blob:none',remote,git_dir.to_s,chdir: nilrescueCommandErrorgit'clone',remote,git_dir.to_s,chdir: nilendendbegingit'checkout',"origin/#{revision}"# for branch name as `revision`rescueCommandErrorgit'checkout',revisionendendprivatedefneed_to_fetch?(revision)returntrueunlessrevision.match?(/\A[a-f0-9]{40}\z/)begingit('cat-file','-e',revision)falserescueCommandErrortrueendendprivatedefgit_dir@git_dir||=(base=Pathname(ENV['XDG_CACHE_HOME']||File.expand_path("~/.cache"))cache_key=remote.start_with?('.')?"#{remote}\0#{Dir.pwd}":remotedir=base.join('rbs',Digest::SHA256.hexdigest(cache_key))dir.mkpathdir)endprivatedefgem_repo_dirgit_dir.join@repo_direndprivatedefresolved_revision@resolved_revision||=resolve_revisionendprivatedefresolve_revisiongit('rev-parse','HEAD').chompendprivatedefgit(*cmd,**opt)sh!'git',*cmd,**optendprivatedefsh!(*cmd,**opt)RBS.logger.debug"$ #{cmd.join(' ')}"opt={chdir: git_dir}.merge(opt).compact(__skip__=Open3.capture3(*cmd,**opt)).thendo|out,err,status|raiseCommandError,"Unexpected status #{status.exitstatus}\n\n#{err}"unlessstatus.success?outendendendendendend