From 7df90eb7e1d3c1d32b99daf9206d57591d2a5a93 Mon Sep 17 00:00:00 2001 From: Harry Marr Date: Mon, 2 May 2022 19:53:44 -0400 Subject: [PATCH] Support git partial clones with sparse checkouts --- Library/Homebrew/cask/url.rb | 10 +++++++-- Library/Homebrew/download_strategy.rb | 30 +++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/Library/Homebrew/cask/url.rb b/Library/Homebrew/cask/url.rb index 6221f0414e..f692b0f0e5 100644 --- a/Library/Homebrew/cask/url.rb +++ b/Library/Homebrew/cask/url.rb @@ -15,7 +15,7 @@ class URL < Delegator :verified, :using, :tag, :branch, :revisions, :revision, :trust_cert, :cookies, :referer, :header, :user_agent, - :data + :data, :only_paths extend Forwardable def_delegators :uri, :path, :scheme, :to_s @@ -36,6 +36,7 @@ class URL < Delegator header: T.nilable(String), user_agent: T.nilable(T.any(Symbol, String)), data: T.nilable(T::Hash[String, String]), + only_paths: T.nilable(T::Array[String]), ).void } def initialize( @@ -51,7 +52,8 @@ class URL < Delegator referer: nil, header: nil, user_agent: nil, - data: nil + data: nil, + only_paths: nil ) @uri = URI(uri) @@ -69,6 +71,7 @@ class URL < Delegator specs[:header] = @header = header specs[:user_agent] = @user_agent = user_agent || :default specs[:data] = @data = data + specs[:only_paths] = @only_paths = only_paths @specs = specs.compact end @@ -156,6 +159,7 @@ class URL < Delegator header: T.nilable(String), user_agent: T.nilable(T.any(Symbol, String)), data: T.nilable(T::Hash[String, String]), + only_paths: T.nilable(T::Array[String]), caller_location: Thread::Backtrace::Location, dsl: T.nilable(Cask::DSL), block: T.nilable(T.proc.params(arg0: T.all(String, BlockDSL::PageWithURL)).returns(T.untyped)), @@ -175,6 +179,7 @@ class URL < Delegator header: nil, user_agent: nil, data: nil, + only_paths: nil, caller_location: T.must(caller_locations).fetch(0), dsl: nil, &block @@ -202,6 +207,7 @@ class URL < Delegator header: header, user_agent: user_agent, data: data, + only_paths: only_paths, ) end ) diff --git a/Library/Homebrew/download_strategy.rb b/Library/Homebrew/download_strategy.rb index c53e62d99b..d3aead0c4c 100644 --- a/Library/Homebrew/download_strategy.rb +++ b/Library/Homebrew/download_strategy.rb @@ -814,6 +814,7 @@ class GitDownloadStrategy < VCSDownloadStrategy super @ref_type ||= :branch @ref ||= "master" + @only_paths = meta[:only_paths] end # @see AbstractDownloadStrategy#source_modified_time @@ -880,6 +881,14 @@ class GitDownloadStrategy < VCSDownloadStrategy (cached_location/".gitmodules").exist? end + def partial_clone_sparse_checkout? + return false if @only_paths.nil? + + # There is some support for partial clones prior to 2.20, but we avoid using it + # due to performance issues + Version.create(Utils::Git.version) >= Version.create("2.20.0") + end + sig { returns(T::Array[String]) } def clone_args args = %w[clone] @@ -889,6 +898,8 @@ class GitDownloadStrategy < VCSDownloadStrategy args << "--branch" << @ref end + args << "--no-checkout" << "--filter=blob:none" if partial_clone_sparse_checkout? + args << "-c" << "advice.detachedHead=false" # silences detached head warning args << @url << cached_location end @@ -922,6 +933,13 @@ class GitDownloadStrategy < VCSDownloadStrategy command! "git", args: ["config", "advice.detachedHead", "false"], chdir: cached_location + + if partial_clone_sparse_checkout? + command! "git", + args: ["config", "origin.partialclonefilter", "blob:none"], + chdir: cached_location + configure_sparse_checkout + end end sig { params(timeout: T.nilable(Time)).void } @@ -950,6 +968,9 @@ class GitDownloadStrategy < VCSDownloadStrategy args: ["config", "homebrew.cacheversion", cache_version], chdir: cached_location, timeout: timeout&.remaining + + configure_sparse_checkout if partial_clone_sparse_checkout? + checkout(timeout: timeout) update_submodules(timeout: timeout) if submodules? end @@ -1020,6 +1041,15 @@ class GitDownloadStrategy < VCSDownloadStrategy dot_git.atomic_write("gitdir: #{relative_git_dir}\n") end end + + def configure_sparse_checkout + command! "git", + args: ["config", "core.sparseCheckout", "true"], + chdir: cached_location + + sparse_checkout_paths = @only_paths.join("\n") + "\n" + (git_dir/"info"/"sparse-checkout").atomic_write(sparse_checkout_paths) + end end # Strategy for downloading a Git repository from GitHub.