From 20f00a6427df74e181b149a6e93434e1d52db137 Mon Sep 17 00:00:00 2001 From: apainintheneck Date: Sun, 15 Oct 2023 15:14:48 -0700 Subject: [PATCH 1/3] dev-cmd/unbottled: add --lost option This option tries to find bottles where the bottle was removed from the formula in the past week and not added back in. It checks the output of `git log` to see if there are any bottles that fit this criteria. --- Library/Homebrew/dev-cmd/unbottled.rb | 64 ++++++++++++++++++++++++++- completions/bash/brew | 1 + completions/fish/brew.fish | 1 + completions/zsh/_brew | 5 ++- docs/Manpage.md | 2 + manpages/brew.1 | 4 ++ 6 files changed, 74 insertions(+), 3 deletions(-) diff --git a/Library/Homebrew/dev-cmd/unbottled.rb b/Library/Homebrew/dev-cmd/unbottled.rb index 0d3e6201f94a5..b4dc78796d827 100644 --- a/Library/Homebrew/dev-cmd/unbottled.rb +++ b/Library/Homebrew/dev-cmd/unbottled.rb @@ -21,11 +21,13 @@ def unbottled_args description: "Skip getting analytics data and sort by number of dependents instead." switch "--total", description: "Print the number of unbottled and total formulae." + switch "--lost", + description: "Print the `homebrew/core` commits where bottles were lost in the last week." switch "--eval-all", description: "Evaluate all available formulae and casks, whether installed or not, to check them. " \ "Implied if `HOMEBREW_EVAL_ALL` is set." - conflicts "--dependents", "--total" + conflicts "--dependents", "--total", "--lost" named_args :formula end @@ -43,6 +45,17 @@ def unbottled Utils::Bottles.tag end + if args.lost? + if args.named.present? + raise UsageError, "`brew unbottled --lost` cannot be used with formula arguments!" + elsif !CoreTap.instance.installed? + raise UsageError, "`brew unbottled --lost` requires `homebrew/core` to be tapped locally!" + else + output_lost_bottles + return + end + end + os = @bottle_tag.system arch = if Hardware::CPU::INTEL_ARCHS.include?(@bottle_tag.arch) :intel @@ -243,4 +256,53 @@ def output_unbottled(formulae, deps_hash, noun, hash, any_named_args) puts "No unbottled dependencies found!" end + + def output_lost_bottles + # $ git log --patch -G\^\ \+sha256.\*\ sonoma: --since=@\{\'1\ week\ ago\'\} + git_log = %w[git log --patch] + git_log << "-G^ +sha256.* #{@bottle_tag}:" + git_log << "--since=@{'1 week ago'}" + + bottle_tag_sha_regex = /^[+-] +sha256.* #{@bottle_tag}: / + + processed_formulae = Set.new + commit = T.let(nil, T.nilable(String)) + formula = T.let(nil, T.nilable(String)) + lost_bottles = 0 + + CoreTap.instance.path.cd do + Utils.safe_popen_read(*git_log) do |io| + io.each_line do |line| + case line + when /^commit [0-9a-f]{40}$/ + # Example match: `commit 7289b409b96a752540befef1a56b8a818baf1db7` + if commit && lost_bottles.positive? && processed_formulae.exclude?(formula) + puts "#{commit}: bottle lost for #{formula}" + end + processed_formulae << formula + commit = line.split.last + lost_bottles = 0 + when %r{^diff --git a/Formula/} + # Example match: `diff --git a/Formula/a/aws-cdk.rb b/Formula/a/aws-cdk.rb` + formula = line.split("/").last.chomp(".rb\n") + when bottle_tag_sha_regex + # Example match: `- sha256 cellar: :any_skip_relocation, sonoma: "f0a4..."` + next if processed_formulae.include?(formula) + + case line.chr + when "+" then lost_bottles -= 1 + when "-" then lost_bottles += 1 + end + when /^[+] +sha256.* all: / + # Example match: `+ sha256 cellar: :any_skip_relocation, all: "9e35..."` + lost_bottles -= 1 + end + end + end + end + + return if !commit || !lost_bottles.positive? || processed_formulae.include?(formula) + + puts "#{commit}: bottle lost for #{formula}" + end end diff --git a/completions/bash/brew b/completions/bash/brew index bddbb67163eb7..5bd972d729782 100644 --- a/completions/bash/brew +++ b/completions/bash/brew @@ -2258,6 +2258,7 @@ _brew_unbottled() { --dependents --eval-all --help + --lost --quiet --tag --total diff --git a/completions/fish/brew.fish b/completions/fish/brew.fish index 67a255d7d0448..c7bb873e439c1 100644 --- a/completions/fish/brew.fish +++ b/completions/fish/brew.fish @@ -1500,6 +1500,7 @@ __fish_brew_complete_arg 'unbottled' -l debug -d 'Display any debugging informat __fish_brew_complete_arg 'unbottled' -l dependents -d 'Skip getting analytics data and sort by number of dependents instead' __fish_brew_complete_arg 'unbottled' -l eval-all -d 'Evaluate all available formulae and casks, whether installed or not, to check them. Implied if `HOMEBREW_EVAL_ALL` is set' __fish_brew_complete_arg 'unbottled' -l help -d 'Show this message' +__fish_brew_complete_arg 'unbottled' -l lost -d 'Print the `homebrew/core` commits where bottles were lost in the last week' __fish_brew_complete_arg 'unbottled' -l quiet -d 'Make some output more quiet' __fish_brew_complete_arg 'unbottled' -l tag -d 'Use the specified bottle tag (e.g. `big_sur`) instead of the current OS' __fish_brew_complete_arg 'unbottled' -l total -d 'Print the number of unbottled and total formulae' diff --git a/completions/zsh/_brew b/completions/zsh/_brew index b6aee53e4bd5e..d853a5fffa9b6 100644 --- a/completions/zsh/_brew +++ b/completions/zsh/_brew @@ -1846,12 +1846,13 @@ _brew_typecheck() { _brew_unbottled() { _arguments \ '--debug[Display any debugging information]' \ - '(--total)--dependents[Skip getting analytics data and sort by number of dependents instead]' \ + '(--total --lost)--dependents[Skip getting analytics data and sort by number of dependents instead]' \ '--eval-all[Evaluate all available formulae and casks, whether installed or not, to check them. Implied if `HOMEBREW_EVAL_ALL` is set]' \ '--help[Show this message]' \ + '(--dependents --total)--lost[Print the `homebrew/core` commits where bottles were lost in the last week]' \ '--quiet[Make some output more quiet]' \ '--tag[Use the specified bottle tag (e.g. `big_sur`) instead of the current OS]' \ - '(--dependents)--total[Print the number of unbottled and total formulae]' \ + '(--dependents --lost)--total[Print the number of unbottled and total formulae]' \ '--verbose[Make some output more verbose]' \ - formula \ '*::formula:__brew_formulae' diff --git a/docs/Manpage.md b/docs/Manpage.md index 3d9e4779651dd..b43aeff9db903 100644 --- a/docs/Manpage.md +++ b/docs/Manpage.md @@ -1626,6 +1626,8 @@ Show the unbottled dependents of formulae. Skip getting analytics data and sort by number of dependents instead. * `--total`: Print the number of unbottled and total formulae. +* `--lost`: + Print the `homebrew/core` commits where bottles were lost in the last week. * `--eval-all`: Evaluate all available formulae and casks, whether installed or not, to check them. Implied if `HOMEBREW_EVAL_ALL` is set. diff --git a/manpages/brew.1 b/manpages/brew.1 index 1c433fc6a754a..5286d72d9464c 100644 --- a/manpages/brew.1 +++ b/manpages/brew.1 @@ -2339,6 +2339,10 @@ Skip getting analytics data and sort by number of dependents instead\. Print the number of unbottled and total formulae\. . .TP +\fB\-\-lost\fR +Print the \fBhomebrew/core\fR commits where bottles were lost in the last week\. +. +.TP \fB\-\-eval\-all\fR Evaluate all available formulae and casks, whether installed or not, to check them\. Implied if \fBHOMEBREW_EVAL_ALL\fR is set\. . From 83598bb950bdb55b23232f7fe6767852aa856a23 Mon Sep 17 00:00:00 2001 From: apainintheneck Date: Mon, 16 Oct 2023 20:51:38 -0700 Subject: [PATCH 2/3] cmd/unbottled: Address review feedback for --lost - Add heading message to indicate bottle tag used - Use --no-ext-diff with git to avoid potential problems - Resolve formula renames to avoid false positives - Increase parsing stringency --- Library/Homebrew/dev-cmd/unbottled.rb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Library/Homebrew/dev-cmd/unbottled.rb b/Library/Homebrew/dev-cmd/unbottled.rb index b4dc78796d827..3675a1b7b74bc 100644 --- a/Library/Homebrew/dev-cmd/unbottled.rb +++ b/Library/Homebrew/dev-cmd/unbottled.rb @@ -258,8 +258,10 @@ def output_unbottled(formulae, deps_hash, noun, hash, any_named_args) end def output_lost_bottles - # $ git log --patch -G\^\ \+sha256.\*\ sonoma: --since=@\{\'1\ week\ ago\'\} - git_log = %w[git log --patch] + ohai ":#{@bottle_tag} lost bottles" + + # $ git log --patch -G'^ +sha256.* sonoma:' --since=@{'1 week ago'} + git_log = %w[git log --patch --no-ext-diff] git_log << "-G^ +sha256.* #{@bottle_tag}:" git_log << "--since=@{'1 week ago'}" @@ -276,15 +278,17 @@ def output_lost_bottles case line when /^commit [0-9a-f]{40}$/ # Example match: `commit 7289b409b96a752540befef1a56b8a818baf1db7` - if commit && lost_bottles.positive? && processed_formulae.exclude?(formula) + if commit && formula && lost_bottles.positive? && processed_formulae.exclude?(formula) puts "#{commit}: bottle lost for #{formula}" end processed_formulae << formula commit = line.split.last - lost_bottles = 0 + formula = nil when %r{^diff --git a/Formula/} # Example match: `diff --git a/Formula/a/aws-cdk.rb b/Formula/a/aws-cdk.rb` formula = line.split("/").last.chomp(".rb\n") + formula = CoreTap.instance.formula_renames.fetch(formula, formula) + lost_bottles = 0 when bottle_tag_sha_regex # Example match: `- sha256 cellar: :any_skip_relocation, sonoma: "f0a4..."` next if processed_formulae.include?(formula) @@ -301,7 +305,7 @@ def output_lost_bottles end end - return if !commit || !lost_bottles.positive? || processed_formulae.include?(formula) + return if !commit || !formula || !lost_bottles.positive? || processed_formulae.include?(formula) puts "#{commit}: bottle lost for #{formula}" end From e48c155f42adeb98b2c6d793e3b2e125d7c2effe Mon Sep 17 00:00:00 2001 From: apainintheneck Date: Tue, 17 Oct 2023 22:41:50 -0700 Subject: [PATCH 3/3] dev-cmd/unbottled: share common parts of bottle tag regex This makes it easier to see that the two regexes are related and could make it easier to change them in the future if need be. --- Library/Homebrew/dev-cmd/unbottled.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Library/Homebrew/dev-cmd/unbottled.rb b/Library/Homebrew/dev-cmd/unbottled.rb index 3675a1b7b74bc..7c0d480c2a70e 100644 --- a/Library/Homebrew/dev-cmd/unbottled.rb +++ b/Library/Homebrew/dev-cmd/unbottled.rb @@ -260,12 +260,14 @@ def output_unbottled(formulae, deps_hash, noun, hash, any_named_args) def output_lost_bottles ohai ":#{@bottle_tag} lost bottles" - # $ git log --patch -G'^ +sha256.* sonoma:' --since=@{'1 week ago'} + bottle_tag_regex_fragment = " +sha256.* #{@bottle_tag}: " + + # $ git log --patch --no-ext-diff -G'^ +sha256.* sonoma:' --since=@{'1 week ago'} git_log = %w[git log --patch --no-ext-diff] - git_log << "-G^ +sha256.* #{@bottle_tag}:" + git_log << "-G^#{bottle_tag_regex_fragment}" git_log << "--since=@{'1 week ago'}" - bottle_tag_sha_regex = /^[+-] +sha256.* #{@bottle_tag}: / + bottle_tag_sha_regex = /^[+-]#{bottle_tag_regex_fragment}/ processed_formulae = Set.new commit = T.let(nil, T.nilable(String))