# typed: strict # frozen_string_literal: true require "abstract_command" require "fileutils" require "stringio" require "formula" require "cask/download" require "unpack_strategy" module Homebrew module DevCmd class Unpack < AbstractCommand include FileUtils cmd_args do description <<~EOS Unpack the source files for and binaries for into subdirectories of the current working directory. EOS flag "--destdir=", description: "Create subdirectories in the directory named by instead." switch "--patch", description: "Patches for will be applied to the unpacked source." switch "-g", "--git", description: "Initialise a Git repository in the unpacked source. This is useful for creating " \ "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, :cask], min: 1 end sig { override.void } def run formulae_and_casks = if args.cask? args.named.to_formulae_and_casks(only: :cask) elsif args.formula? 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 unpack_dir.mkpath else unpack_dir = Pathname.pwd end odie "Cannot write to #{unpack_dir}" unless unpack_dir.writable? formulae_and_casks.each do |formula_or_cask| case formula_or_cask when Formula unpack_formula(formula_or_cask, unpack_dir) when Cask::Cask unpack_cask(formula_or_cask, 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 the cask download = Cask::Download.new(cask, quarantine: false) downloaded_path = download.fetch(quiet: false) # Extract to destination stage_dir.mkpath UnpackStrategy.detect(downloaded_path).extract_nestedly(to: stage_dir, verbose: true) 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 end end end