# frozen_string_literal: truerequire_relative"../vendored_fileutils"moduleBundlerclassSourceclassGit<Pathautoload:GitProxy,File.expand_path("git/git_proxy",__dir__)attr_reader:uri,:ref,:branch,:options,:glob,:submodulesdefinitialize(options)@options=options@glob=options["glob"]||DEFAULT_GLOB@allow_cached=false@allow_remote=false# Stringify options that could be set as symbols%w[ref branch tag revision].each{|k|options[k]=options[k].to_sifoptions[k]}@uri=options["uri"]||""@safe_uri=URICredentialsFilter.credential_filtered_uri(@uri)@branch=options["branch"]@ref=options["ref"]||options["branch"]||options["tag"]||"master"@submodules=options["submodules"]@name=options["name"]@version=options["version"].to_s.strip.gsub("-",".pre.")@copied=false@local=falseenddefself.from_lock(options)new(options.merge("uri"=>options.delete("remote")))enddefto_lockout=String.new("GIT\n")out<<" remote: #{@uri}\n"out<<" revision: #{revision}\n"%w[ref branch tag submodules].eachdo|opt|out<<" #{opt}: #{options[opt]}\n"ifoptions[opt]endout<<" glob: #{@glob}\n"unless@glob==DEFAULT_GLOBout<<" specs:\n"enddefhash[self.class,uri,ref,branch,name,version,glob,submodules].hashenddefeql?(other)other.is_a?(Git)&&uri==other.uri&&ref==other.ref&&branch==other.branch&&name==other.name&&version==other.version&&glob==other.glob&&submodules==other.submodulesendalias_method:==,:eql?defto_sat=iflocal?pathelsifuser_ref=options["ref"]ifref=~/\A[a-z0-9]{4,}\z/ishortref_for_display(user_ref)elseuser_refendelserefendrev=begin"@#{shortref_for_display(revision)}"rescueGitErrornilend"#{@safe_uri} (at #{at}#{rev})"enddefnameFile.basename(@uri,".git")end# This is the path which is going to contain a specific# checkout of the git repository. When using local git# repos, this is set to the local repo.definstall_path@install_path||=begingit_scope="#{base_name}-#{shortref_for_path(revision)}"path=Bundler.install_path.join(git_scope)if!path.exist?&&Bundler.requires_sudo?Bundler.user_bundle_path.join(Bundler.ruby_scope).join(git_scope)elsepathendendendalias_method:path,:install_pathdefextension_dir_name"#{base_name}-#{shortref_for_path(revision)}"enddefunlock!git_proxy.revision=niloptions["revision"]=nil@unlocked=trueenddeflocal_override!(path)returnfalseiflocal?original_path=pathpath=Pathname.new(path)path=path.expand_path(Bundler.root)unlesspath.relative?unlessoptions["branch"]||Bundler.settings[:disable_local_branch_check]raiseGitError,"Cannot use local override for #{name} at #{path} because "\":branch is not specified in Gemfile. Specify a branch or run "\"`bundle config unset local.#{override_for(original_path)}` to remove the local override"endunlesspath.exist?raiseGitError,"Cannot use local override for #{name} because #{path} "\"does not exist. Run `bundle config unset local.#{override_for(original_path)}` to remove the local override"endset_local!(path)# Create a new git proxy without the cached revision# so the Gemfile.lock always picks up the new revision.@git_proxy=GitProxy.new(path,uri,ref)ifgit_proxy.branch!=options["branch"]&&!Bundler.settings[:disable_local_branch_check]raiseGitError,"Local override for #{name} at #{path} is using branch "\"#{git_proxy.branch} but Gemfile specifies #{options["branch"]}"endchanged=cached_revision&&cached_revision!=git_proxy.revisionifchanged&&!@unlocked&&!git_proxy.contains?(cached_revision)raiseGitError,"The Gemfile lock is pointing to revision #{shortref_for_display(cached_revision)} "\"but the current branch in your local override for #{name} does not contain such commit. "\"Please make sure your branch is up to date."endchangedenddefspecs(*)set_local!(app_cache_path)ifhas_app_cache?&&!local?ifrequires_checkout?&&!@copiedfetchgit_proxy.copy_to(install_path,submodules)serialize_gemspecs_in(install_path)@copied=trueendlocal_specsenddefinstall(spec,options={})force=options[:force]print_using_message"Using #{version_message(spec)} from #{self}"if(requires_checkout?&&!@copied)||forceBundler.ui.debug" * Checking out revision: #{ref}"git_proxy.copy_to(install_path,submodules)serialize_gemspecs_in(install_path)@copied=trueendgenerate_bin_options={:disable_extensions=>!Bundler.rubygems.spec_missing_extensions?(spec),:build_args=>options[:build_args]}generate_bin(spec,generate_bin_options)requires_checkout??spec.post_install_message:nilenddefcache(spec,custom_path=nil)app_cache_path=app_cache_path(custom_path)returnunlessBundler.feature_flag.cache_all?returnifpath==app_cache_pathcached!FileUtils.rm_rf(app_cache_path)git_proxy.checkoutifrequires_checkout?git_proxy.copy_to(app_cache_path,@submodules)serialize_gemspecs_in(app_cache_path)enddefload_spec_filessuperrescuePathError=>eBundler.ui.traceeraiseGitError,"#{self} is not yet checked out. Run `bundle install` first."end# This is the path which is going to contain a cache# of the git repository. When using the same git repository# across different projects, this cache will be shared.# When using local git repos, this is set to the local repo.defcache_path@cache_path||=beginifBundler.requires_sudo?||Bundler.feature_flag.global_gem_cache?Bundler.user_cacheelseBundler.bundle_path.join("cache","bundler")end.join("git",git_scope)endenddefapp_cache_dirname"#{base_name}-#{shortref_for_path(cached_revision||revision)}"enddefrevisiongit_proxy.revisionenddefallow_git_ops?@allow_remote||@allow_cachedendprivatedefserialize_gemspecs_in(destination)destination=destination.expand_path(Bundler.root)ifdestination.relative?Dir["#{destination}/#{@glob}"].eachdo|spec_path|# Evaluate gemspecs and cache the result. Gemspecs# in git might require git or other dependencies.# The gemspecs we cache should already be evaluated.spec=Bundler.load_gemspec(spec_path)nextunlessspecBundler.rubygems.set_installed_by_version(spec)Bundler.rubygems.validate(spec)File.open(spec_path,"wb"){|file|file.write(spec.to_ruby)}endenddefset_local!(path)@local=true@local_specs=@git_proxy=nil@cache_path=@install_path=pathenddefhas_app_cache?cached_revision&&superenddeflocal?@localenddefrequires_checkout?allow_git_ops?&&!local?&&!cached_revision_checked_out?enddefcached_revision_checked_out?cached_revision&&cached_revision==revision&&install_path.exist?enddefbase_nameFile.basename(uri.sub(%r{^(\w+://)?([^/:]+:)?(//\w*/)?(\w*/)*},""),".git")enddefshortref_for_display(ref)ref[0..6]enddefshortref_for_path(ref)ref[0..11]enddefuri_hashifuri=~%r{^\w+://(\w+@)?}# Downcase the domain component of the URI# and strip off a trailing slash, if one is presentinput=Bundler::URI.parse(uri).normalize.to_s.sub(%r{/$},"")else# If there is no URI scheme, assume it is an ssh/git URIinput=uriendSharedHelpers.digest(:SHA1).hexdigest(input)enddefcached_revisionoptions["revision"]enddefcached?cache_path.exist?enddefgit_proxy@git_proxy||=GitProxy.new(cache_path,uri,ref,cached_revision,self)enddeffetchgit_proxy.checkoutrescueGitError=>eraiseunlessBundler.feature_flag.allow_offline_install?Bundler.ui.warn"Using cached git data because of network errors:\n#{e}"end# no-op, since we validate when re-serializing the gemspecdefvalidate_spec(_spec);enddefload_gemspec(file)stub=Gem::StubSpecification.gemspec_stub(file,install_path.parent,install_path.parent)stub.full_gem_path=Pathname.new(file).dirname.expand_path(root).to_s.tap{|x|x.untaintifRUBY_VERSION<"2.7"}StubSpecification.from_stub(stub)enddefgit_scope"#{base_name}-#{uri_hash}"enddefextension_cache_slug(_)extension_dir_nameenddefoverride_for(path)Bundler.settings.local_overrides.key(path)endendendend