diff --git a/Library/Homebrew/dev-cmd/unpack.rb b/Library/Homebrew/dev-cmd/unpack.rb index 8ecc1c1f2e..5daa726cac 100644 --- a/Library/Homebrew/dev-cmd/unpack.rb +++ b/Library/Homebrew/dev-cmd/unpack.rb @@ -5,6 +5,8 @@ require "abstract_command" require "fileutils" require "stringio" require "formula" +require "cask/download" +require "unpack_strategy" module Homebrew module DevCmd @@ -13,7 +15,7 @@ module Homebrew cmd_args do description <<~EOS - Unpack the source files for into subdirectories of the current + Unpack the files for the or into subdirectories of the current working directory. EOS flag "--destdir=", @@ -25,15 +27,28 @@ module Homebrew "patches for the software." switch "-f", "--force", description: "Overwrite the destination directory if it already exists." + switch "--formula", "--formulae", + description: "Treat all named arguments as formulae." + switch "--cask", "--casks", + description: "Treat all named arguments as casks." conflicts "--git", "--patch" + conflicts "--formula", "--cask" + conflicts "--cask", "--patch" + conflicts "--cask", "--git" - named_args :formula, min: 1 + named_args [:formula, :cask], min: 1 end sig { override.void } def run - formulae = args.named.to_formulae + formulae_and_casks = if args.casks? + args.named.to_formulae_and_casks(only: :cask) + elsif args.formulae? + args.named.to_formulae_and_casks(only: :formula) + else + args.named.to_formulae_and_casks + end if (dir = args.destdir) unpack_dir = Pathname.new(dir).expand_path @@ -44,35 +59,70 @@ module Homebrew odie "Cannot write to #{unpack_dir}" unless unpack_dir.writable? - formulae.each do |f| - stage_dir = unpack_dir/"#{f.name}-#{f.version}" - - if stage_dir.exist? - odie "Destination #{stage_dir} already exists!" unless args.force? - - rm_rf stage_dir - end - - oh1 "Unpacking #{Formatter.identifier(f.full_name)} to: #{stage_dir}" - - # show messages about tar - with_env VERBOSE: "1" do - f.brew do - f.patch if args.patch? - cp_r getwd, stage_dir, preserve: true - end - end - - next unless args.git? - - ohai "Setting up Git repository" - cd(stage_dir) do - system "git", "init", "-q" - system "git", "add", "-A" - system "git", "commit", "-q", "-m", "brew-unpack" + formulae_and_casks.each do |formula_or_cask| + if formula_or_cask.is_a?(Cask::Cask) + unpack_cask(formula_or_cask, unpack_dir) + elsif (formula = T.cast(formula_or_cask, Formula)) + unpack_formula(formula, unpack_dir) end end end + + private + + sig { params(formula: Formula, unpack_dir: Pathname).void } + def unpack_formula(formula, unpack_dir) + stage_dir = unpack_dir/"#{formula.name}-#{formula.version}" + + if stage_dir.exist? + odie "Destination #{stage_dir} already exists!" unless args.force? + + rm_rf stage_dir + end + + oh1 "Unpacking #{Formatter.identifier(formula.full_name)} to: #{stage_dir}" + + # show messages about tar + with_env VERBOSE: "1" do + formula.brew do + formula.patch if args.patch? + cp_r getwd, stage_dir, preserve: true + end + end + + return unless args.git? + + ohai "Setting up Git repository" + cd(stage_dir) do + system "git", "init", "-q" + system "git", "add", "-A" + system "git", "commit", "-q", "-m", "brew-unpack" + end + end + + sig { params(cask: Cask::Cask, unpack_dir: Pathname).void } + def unpack_cask(cask, unpack_dir) + stage_dir = unpack_dir/"#{cask.token}-#{cask.version}" + + if stage_dir.exist? + odie "Destination #{stage_dir} already exists!" unless args.force? + + rm_rf stage_dir + end + + oh1 "Unpacking #{Formatter.identifier(cask.full_name)} to: #{stage_dir}" + + download = Cask::Download.new(cask, quarantine: true) + + downloaded_path = if download.downloaded? + download.cached_download + else + download.fetch(quiet: false) + end + + stage_dir.mkpath + UnpackStrategy.detect(downloaded_path).extract_nestedly(to: stage_dir, verbose: true) + end end end end diff --git a/Library/Homebrew/sorbet/rbi/dsl/homebrew/dev_cmd/unpack.rbi b/Library/Homebrew/sorbet/rbi/dsl/homebrew/dev_cmd/unpack.rbi index b1d7bbd6af..dcb3bacfc7 100644 --- a/Library/Homebrew/sorbet/rbi/dsl/homebrew/dev_cmd/unpack.rbi +++ b/Library/Homebrew/sorbet/rbi/dsl/homebrew/dev_cmd/unpack.rbi @@ -11,6 +11,12 @@ class Homebrew::DevCmd::Unpack end class Homebrew::DevCmd::Unpack::Args < Homebrew::CLI::Args + sig { returns(T::Boolean) } + def cask?; end + + sig { returns(T::Boolean) } + def casks?; end + sig { returns(T.nilable(String)) } def destdir; end @@ -20,6 +26,12 @@ class Homebrew::DevCmd::Unpack::Args < Homebrew::CLI::Args sig { returns(T::Boolean) } def force?; end + sig { returns(T::Boolean) } + def formula?; end + + sig { returns(T::Boolean) } + def formulae?; end + sig { returns(T::Boolean) } def g?; end diff --git a/Library/Homebrew/test/dev-cmd/unpack_spec.rb b/Library/Homebrew/test/dev-cmd/unpack_spec.rb index 10251c7dda..b31e220060 100644 --- a/Library/Homebrew/test/dev-cmd/unpack_spec.rb +++ b/Library/Homebrew/test/dev-cmd/unpack_spec.rb @@ -16,4 +16,15 @@ RSpec.describe Homebrew::DevCmd::Unpack do expect(path/"testball-0.1").to be_a_directory end end + + it "unpacks a given Cask's archive", :integration_test do + caffeine_cask = Cask::CaskLoader.load(cask_path("local-caffeine")) + + mktmpdir do |path| + expect { brew "unpack", cask_path("local-caffeine"), "--destdir=#{path}" } + .to be_a_success + + expect(path/"local-caffeine-#{caffeine_cask.version}").to be_a_directory + end + end end