require'uri'require'rubygems/user_interaction'require'rubygems/spec_fetcher'moduleBundlerclassSourceclassRubygems<SourceAPI_REQUEST_LIMIT=100# threshold for switching back to the modern index instead of fetching every specattr_reader:remotes,:cachesattr_accessor:dependency_namesdefinitialize(options={})@options=options@remotes=[]@fetchers={}@dependency_names=[]@allow_remote=false@allow_cached=false@caches=[Bundler.app_cache,*Bundler.rubygems.gem_cache]Array(options["remotes"]||[]).reverse_each{|r|add_remote(r)}enddefremote!@allow_remote=trueenddefcached!@allow_cached=trueenddefhash@remotes.hashenddefeql?(o)o.is_a?(Rubygems)&&remotes==o.remotesendalias==eql?defcan_lock?(spec)spec.source.is_a?(Rubygems)enddefoptions{"remotes"=>@remotes.map{|r|r.to_s}}enddefself.from_lock(options)new(options)enddefto_lockout="GEM\n"out<<remotes.map{|remote|" remote: #{suppress_configured_credentialsremote}\n"}.joinout<<" specs:\n"enddefto_sremote_names=self.remotes.map{|r|r.to_s}.join(', ')"rubygems repository #{remote_names}"endalias_method:name,:to_sdefspecs@specs||=fetch_specsenddefinstall(spec)return["Using #{version_message(spec)}",nil]ifinstalled_specs[spec].any?# Download the gem to get the spec, because some specs that are returned# by rubygems.org are broken and wrong.ifspec.source_uri# Check for this spec from other sourcesuris=[spec.source_uri]uris+=source_uris_for_spec(spec)uris.compact!uris.uniq!Installer.ambiguous_gems<<[spec.name,*uris]ifuris.length>1s=Bundler.rubygems.spec_from_gem(fetch_gem(spec),Bundler.settings["trust-policy"])spec.__swap__(s)endpath=cached_gem(spec)ifBundler.requires_sudo?install_path=Bundler.tmp(spec.full_name)bin_path=install_path.join("bin")elseinstall_path=Bundler.rubygems.gem_dirbin_path=Bundler.system_bindirendinstalled_spec=nilBundler.rubygems.preserve_pathsdoinstalled_spec=Bundler::GemInstaller.new(path,:install_dir=>install_path.to_s,:bin_dir=>bin_path.to_s,:ignore_dependencies=>true,:wrappers=>true,:env_shebang=>true).installend# SUDO HAXifBundler.requires_sudo?Bundler.rubygems.repository_subdirectories.eachdo|name|src=File.join(install_path,name,"*")dst=File.join(Bundler.rubygems.gem_dir,name)ifname=="extensions"&&Dir.glob(src).any?src=File.join(src,"*/*")ext_src=Dir.glob(src).firstext_src.gsub!(src[0..-6],'')dst=File.dirname(File.join(dst,ext_src))endBundler.mkdir_pdstBundler.sudo"cp -R #{src}#{dst}"ifDir[src].any?endspec.executables.eachdo|exe|Bundler.mkdir_pBundler.system_bindirBundler.sudo"cp -R #{install_path}/bin/#{exe}#{Bundler.system_bindir}/"endendspec.loaded_from="#{Bundler.rubygems.gem_dir}/specifications/#{spec.full_name}.gemspec"installed_spec.loaded_from=spec.loaded_from["Installing #{version_message(spec)}",spec.post_install_message]ensureifinstall_path&&Bundler.requires_sudo?FileUtils.remove_entry_secure(install_path)endenddefcache(spec,custom_path=nil)ifbuiltin_gem?(spec)cached_path=cached_built_in_gem(spec)elsecached_path=cached_gem(spec)endraiseGemNotFound,"Missing gem file '#{spec.full_name}.gem'."unlesscached_pathreturnifFile.dirname(cached_path)==Bundler.app_cache.to_sBundler.ui.info" * #{File.basename(cached_path)}"FileUtils.cp(cached_path,Bundler.app_cache(custom_path))enddefcached_built_in_gem(spec)cached_path=cached_path(spec)ifcached_path.nil?remote_spec=remote_specs.search(spec).firstcached_path=fetch_gem(remote_spec)endcached_pathenddefadd_remote(source)uri=normalize_uri(source)@remotes.unshift(uri)unless@remotes.include?(uri)endprotecteddefsource_uris_for_spec(spec)specs.search_all(spec.name).map{|s|s.source_uri}endprivatedefcached_gem(spec)cached_gem=cached_path(spec)unlesscached_gemraiseBundler::GemNotFound,"Could not find #{spec.file_name} for installation"endcached_gemenddefcached_path(spec)possibilities=@caches.map{|p|"#{p}/#{spec.file_name}"}possibilities.find{|p|File.exist?(p)}enddefnormalize_uri(uri)uri=uri.to_suri="#{uri}/"unlessuri=~%r'/$'uri=URI(uri)raiseArgumentError,"The source must be an absolute URI"unlessuri.absolute?urienddefsuppress_configured_credentials(remote)remote_nouser=remote.tap{|uri|uri.user=uri.password=nil}.to_sifremote.userinfo&&remote.userinfo==Bundler.settings[remote_nouser]remote_nouserelseremoteendenddeffetch_specs# remote_specs usually generates a way larger Index than the other# sources, and large_idx.use small_idx is way faster than# small_idx.use large_idx.if@allow_remoteidx=remote_specs.dupelseidx=Index.newendidx.use(cached_specs,:override_dupes)if@allow_cached||@allow_remoteidx.use(installed_specs,:override_dupes)idxenddefinstalled_specs@installed_specs||=beginidx=Index.newhave_bundler=falseBundler.rubygems.all_specs.reverse.eachdo|spec|nextifspec.name=='bundler'&&spec.version.to_s!=VERSIONhave_bundler=trueifspec.name=='bundler'spec.source=selfidx<<specend# Always have bundler locallyunlesshave_bundler# We're running bundler directly from the source# so, let's create a fake gemspec for it (it's a path)# gemspecbundler=Gem::Specification.newdo|s|s.name='bundler's.version=VERSIONs.platform=Gem::Platform::RUBYs.source=selfs.authors=["bundler team"]s.loaded_from=File.expand_path("..",__FILE__)endidx<<bundlerendidxendenddefcached_specs@cached_specs||=beginidx=installed_specs.duppath=Bundler.app_cacheDir["#{path}/*.gem"].eachdo|gemfile|nextifgemfile=~/^bundler\-[\d\.]+?\.gem/s||=Bundler.rubygems.spec_from_gem(gemfile)s.source=selfidx<<sendendidxenddefremote_specs@remote_specs||=beginold=Bundler.rubygems.sourcesidx=Index.newfetchers=remotes.map{|uri|Bundler::Fetcher.new(uri)}api_fetchers=fetchers.select{|f|f.use_api}index_fetchers=fetchers-api_fetchers# gather lists from non-api sitesindex_fetchers.eachdo|f|Bundler.ui.info"Fetching source index from #{f.uri}"idx.usef.specs(nil,self)endreturnidxifapi_fetchers.empty?# because ensuring we have all the gems we need involves downloading# the gemspecs of those gems, if the non-api sites contain more than# about 100 gems, we just treat all sites as non-api for speed.allow_api=idx.size<API_REQUEST_LIMIT&&dependency_names.size<API_REQUEST_LIMITifallow_apiapi_fetchers.eachdo|f|Bundler.ui.info"Fetching gem metadata from #{f.uri}",Bundler.ui.debug?idx.usef.specs(dependency_names,self)Bundler.ui.info""if!Bundler.ui.debug?# new line now that the dots are overendifapi_fetchers.all?{|f|f.use_api}# it's possible that gems from one source depend on gems from some# other source, so now we download gemspecs and iterate over those# dependencies, looking for gems we don't have info on yet.unmet=idx.unmet_dependency_names# if there are any cross-site gems we missed, get them nowapi_fetchers.eachdo|f|Bundler.ui.info"Fetching additional metadata from #{f.uri}",Bundler.ui.debug?idx.usef.specs(unmet,self)Bundler.ui.info""if!Bundler.ui.debug?# new line now that the dots are overendifunmet.any?elseallow_api=falseendendif!allow_apiapi_fetchers.eachdo|f|Bundler.ui.info"Fetching source index from #{f.uri}"idx.usef.specs(nil,self)endendreturnidxensureBundler.rubygems.sources=oldendenddeffetch_gem(spec)returnfalseunlessspec.source_uriFetcher.download_gem_from_uri(spec,spec.source_uri)enddefbuiltin_gem?(spec)# Ruby 2.1, where all included gems have this summaryreturntrueifspec.summary=~/is bundled with Ruby/# Ruby 2.0, where gemspecs are stored in specifications/default/spec.loaded_from&&spec.loaded_from.include?("specifications/default/")endendendend