require"fileutils"require"uri"require"digest/sha1"moduleBundlerclassSourceclassGit<Pathautoload:GitProxy,"bundler/source/git/git_proxy"attr_reader:uri,:ref,:branch,:options,: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"]||""@branch=options["branch"]@ref=options["ref"]||options["branch"]||options["tag"]||"master"@submodules=options["submodules"]@name=options["name"]@version=options["version"]@copied=false@local=falseenddefself.from_lock(options)new(options.merge("uri"=>options.delete("remote")))enddefto_lockout="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,submodules].hashenddefeql?(other)other.is_a?(Git)&&uri==other.uri&&ref==other.ref&&branch==other.branch&&name==other.name&&version==other.version&&submodules==other.submodulesendalias_method:==,:eql?defto_sat=iflocal?pathelsifoptions["ref"]shortref_for_display(options["ref"])elserefendrev=begin"@#{shortref_for_display(revision)}"rescueGitErrornilend"#{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=nil@unlocked=trueenddeflocal_override!(path)returnfalseiflocal?path=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 use "\"`bundle config --delete` to remove the local override"endunlesspath.exist?raiseGitError,"Cannot use local override for #{name} because #{path} "\"does not exist. Check `bundle config --delete` 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."endchangedend# TODO: actually cache git specsdefspecs(*)set_local!(app_cache_path)ifhas_app_cache?&&!local?ifrequires_checkout?&&!@copiedgit_proxy.checkoutgit_proxy.copy_to(install_path,submodules)serialize_gemspecs_in(install_path)@copied=trueendlocal_specsenddefinstall(spec,force=false)Bundler.ui.info"Using #{version_message(spec)} from #{self}"ifrequires_checkout?&&!@copied&&!forceBundler.ui.debug" * Checking out revision: #{ref}"git_proxy.copy_to(install_path,submodules)serialize_gemspecs_in(install_path)@copied=trueendgenerate_bin(spec)requires_checkout??spec.post_install_message:nilenddefcache(spec,custom_path=nil)app_cache_path=app_cache_path(custom_path)returnunlessBundler.settings[: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||=begingit_scope="#{base_name}-#{uri_hash}"ifBundler.requires_sudo?Bundler.user_bundle_path.join("cache/git",git_scope)elseBundler.cache.join("git",git_scope)endendenddefapp_cache_dirname"#{base_name}-#{shortref_for_path(cached_revision||revision)}"enddefrevisiongit_proxy.revisionenddefallow_git_ops?@allow_remote||@allow_cachedendprivatedefserialize_gemspecs_in(destination)expanded_path=destination.expand_path(Bundler.root)Dir["#{expanded_path}/#{@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)nextunlessspecFile.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?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=URI.parse(uri).normalize.to_s.sub(%r{/$},"")else# If there is no URI scheme, assume it is an ssh/git URIinput=uriendDigest::SHA1.hexdigest(input)enddefcached_revisionoptions["revision"]enddefcached?cache_path.exist?enddefgit_proxy@git_proxy||=GitProxy.new(cache_path,uri,ref,cached_revision,self)endendendend