# frozen_string_literal: truerequire_relative"../worker"require_relative"gem_installer"moduleBundlerclassParallelInstallerclassSpecInstallationattr_accessor:spec,:name,:full_name,:post_install_message,:state,:errordefinitialize(spec)@spec=spec@name=spec.name@full_name=spec.full_name@state=:none@post_install_message=""@error=nilenddefinstalled?state==:installedenddefenqueued?state==:enqueuedenddeffailed?state==:failedenddefready_to_enqueue?state==:noneenddefhas_post_install_message?!post_install_message.empty?enddefignorable_dependency?(dep)dep.type==:development||dep.name==@nameend# Checks installed dependencies against spec's dependencies to make# sure needed dependencies have been installed.defdependencies_installed?(all_specs)installed_specs=all_specs.select(&:installed?).map(&:name)dependencies.all?{|d|installed_specs.include?d.name}end# Represents only the non-development dependencies, the ones that are# itself and are in the total list.defdependencies@dependencies||=all_dependencies.reject{|dep|ignorable_dependency?dep}enddefmissing_lockfile_dependencies(all_spec_names)dependencies.reject{|dep|all_spec_names.include?dep.name}end# Represents all dependenciesdefall_dependencies@spec.dependenciesenddefto_s"#<#{self.class}#{full_name} (#{state})>"endenddefself.call(*args)new(*args).callendattr_reader:sizedefinitialize(installer,all_specs,size,standalone,force)@installer=installer@size=size@standalone=standalone@force=force@specs=all_specs.map{|s|SpecInstallation.new(s)}@spec_set=all_specs@rake=@specs.find{|s|s.name=="rake"}enddefcallcheck_for_corrupt_lockfileif@rakedo_install(@rake,0)Gem::Specification.resetendif@size>1install_with_workerelseinstall_seriallyendcheck_for_unmet_dependencieshandle_erroriffailed_specs.any?@specsensureworker_pool&&worker_pool.stopenddefcheck_for_unmet_dependenciesunmet_dependencies=@specs.mapdo|s|[s,s.dependencies.reject{|dep|@specs.any?{|spec|dep.matches_spec?(spec.spec)}},]end.reject{|a|a.last.empty?}returnifunmet_dependencies.empty?warning=[]warning<<"Your lockfile doesn't include a valid resolution."warning<<"You can fix this by regenerating your lockfile or trying to manually editing the bad locked gems to a version that satisfies all dependencies."warning<<"The unmet dependencies are:"unmet_dependencies.eachdo|spec,unmet_spec_dependencies|unmet_spec_dependencies.eachdo|unmet_spec_dependency|warning<<"* #{unmet_spec_dependency}, depended upon #{spec.full_name}, unsatisfied by #{@specs.find{|s|s.name==unmet_spec_dependency.name&&!unmet_spec_dependency.matches_spec?(s.spec)}.full_name}"endendBundler.ui.warn(warning.join("\n"))enddefcheck_for_corrupt_lockfilemissing_dependencies=@specs.mapdo|s|[s,s.missing_lockfile_dependencies(@specs.map(&:name)),]end.reject{|a|a.last.empty?}returnifmissing_dependencies.empty?warning=[]warning<<"Your lockfile was created by an old Bundler that left some things out."if@size!=1warning<<"Because of the missing DEPENDENCIES, we can only install gems one at a time, instead of installing #{@size} at a time."@size=1endwarning<<"You can fix this by adding the missing gems to your Gemfile, running bundle install, and then removing the gems from your Gemfile."warning<<"The missing gems are:"missing_dependencies.eachdo|spec,missing|warning<<"* #{missing.map(&:name).join(", ")} depended upon by #{spec.name}"endBundler.ui.warn(warning.join("\n"))endprivatedeffailed_specs@specs.select(&:failed?)enddefinstall_with_workerenqueue_specsprocess_specsuntilfinished_installing?enddefinstall_seriallyuntilfinished_installing?raise"failed to find a spec to enqueue while installing serially"unlessspec_install=@specs.find(&:ready_to_enqueue?)spec_install.state=:enqueueddo_install(spec_install,0)endenddefworker_pool@worker_pool||=Bundler::Worker.new@size,"Parallel Installer",lambda{|spec_install,worker_num|do_install(spec_install,worker_num)}enddefdo_install(spec_install,worker_num)Plugin.hook(Plugin::Events::GEM_BEFORE_INSTALL,spec_install)gem_installer=Bundler::GemInstaller.new(spec_install.spec,@installer,@standalone,worker_num,@force)success,message=gem_installer.install_from_specifsuccessspec_install.state=:installedspec_install.post_install_message=messageunlessmessage.nil?elsespec_install.error="#{message}\n\n#{require_tree_for_spec(spec_install.spec)}"spec_install.state=:failedendPlugin.hook(Plugin::Events::GEM_AFTER_INSTALL,spec_install)spec_installend# Dequeue a spec and save its post-install message and then enqueue the# remaining specs.# Some specs might've had to wait til this spec was installed to be# processed so the call to `enqueue_specs` is important after every# dequeue.defprocess_specsworker_pool.deqenqueue_specsenddeffinished_installing?@specs.all?do|spec|returntrueifspec.failed?spec.installed?endenddefhandle_errorerrors=failed_specs.map(&:error)ifexception=errors.find{|e|e.is_a?(Bundler::BundlerError)}raiseexceptionendraiseBundler::InstallError,errors.join("\n\n")enddefrequire_tree_for_spec(spec)tree=@spec_set.what_required(spec)t=String.new("In #{File.basename(SharedHelpers.default_gemfile)}:\n")tree.each_with_indexdo|s,depth|t<<" "*depth.succ<<s.nameunlesstree.last==st<<%( was resolved to #{s.version}, which depends on)endt<<%(\n)endtend# Keys in the remains hash represent uninstalled gems specs.# We enqueue all gem specs that do not have any dependencies.# Later we call this lambda again to install specs that depended on# previously installed specifications. We continue until all specs# are installed.defenqueue_specs@specs.select(&:ready_to_enqueue?).eachdo|spec|ifspec.dependencies_installed?@specsspec.state=:enqueuedworker_pool.enqspecendendendendend