info: add --deps flag to --sizes for dependency footprint breakdown#22582
info: add --deps flag to --sizes for dependency footprint breakdown#22582EdenRochmanSharabi wants to merge 5 commits into
Conversation
When used with --sizes, the new --deps flag shows the true disk cost of installed formulae by analyzing exclusive vs shared dependencies. This addresses the feedback from Homebrew#22391 to integrate footprint analysis directly into `brew info --sizes` rather than as a separate command.
MikeMcQuaid
left a comment
There was a problem hiding this comment.
You definitely promise you wrote 100% of the actual code by hand and just used Claude for analysis?
Need to slim this down a lot, it's a lot of code for a relatively simple feature. Also needs some (non-integration) tests.
Thanks!
|
Yes, I wrote all the code by hand. I used Claude to review it and suggest improvements, but I always rewrote those suggestions myself to avoid the endless slop you get from AI-generated code. That's why I wrote that I wrote the code by hand. Maybe my coding level isn't quite there yet for this project, sorry. I'd understand if you rejected it. I'll slim it down and add tests. |
|
Thanks for clarifying and opening the PR @EdenRochmanSharabi! |
Inline build_reverse_dep_map, analyze_formula_footprint, print_footprint_table, and print_footprint_single into print_sizes_with_deps since each was only called once. Use Array() instead of is_a?(Array) guard for runtime_dependencies. Add four non-integration tests covering no-deps, exclusive deps, shared deps, and table output formats.
| keg = installed_formula.any_installed_keg | ||
| next unless keg | ||
|
|
||
| Array(keg.runtime_dependencies).each do |dep| |
There was a problem hiding this comment.
Why not use installed_formula.runtime_dependencies?
There was a problem hiding this comment.
Done, switched to formula.runtime_dependencies in both loops.
| next unless full_name | ||
|
|
||
| dep_name = Utils.name_from_full_name(full_name) | ||
| (reverse_map[dep_name] ||= Set.new).add(installed_formula.name) |
There was a problem hiding this comment.
| (reverse_map[dep_name] ||= Set.new).add(installed_formula.name) | |
| reverse_map[dep_name] ||= Set.new | |
| reverse_map[dep_name] << installed_formula.name |
| exclusive_deps = T.let([], T::Array[T::Hash[Symbol, T.untyped]]) | ||
| shared_deps = T.let([], T::Array[T::Hash[Symbol, T.untyped]]) | ||
|
|
||
| Array(keg&.runtime_dependencies).each do |dep| |
| next unless keg | ||
|
|
||
| Array(keg.runtime_dependencies).each do |dep| | ||
| next unless dep.is_a?(Hash) |
There was a problem hiding this comment.
Now that I'm using formula.runtime_dependencies, the FormulaUnavailableError rescue shouldn't be necessary because the dependencies are resolved from the formula DSL. Should I remove it entirely and just keep the installed_kegs.empty? guard?
There was a problem hiding this comment.
yes unless you can reproduce the error locally
| exclusive_deps << { name: dep_name, size: dep_size } | ||
| else | ||
| also_needed_by = (dependents.to_a - [formula.name]).sort | ||
| shared_deps << { name: dep_name, size: dep_size, also_needed_by: } |
There was a problem hiding this comment.
T::Struct might be nicer than a hash here
There was a problem hiding this comment.
@EdenRochmanSharabi you don't seem to have pushed yet?
There was a problem hiding this comment.
I haven't pushed yet. I'm not sure about the FormulaUnavailableError guard. Should I remove it and just keep the installed_kegs.empty? check, or keep it as a safety net?
There was a problem hiding this comment.
remove for now. aim to simplify and minimise the amount of code as much as possible.
…r hashes, remove FormulaUnavailableError guard, simplify reverse map building
MikeMcQuaid
left a comment
There was a problem hiding this comment.
Hey @EdenRochmanSharabi. Thanks for the work so far. This isn't really making sense to me so far and even --sizes on testing doesn't make much sense either:
brew info ffmpeg-full --sizesorbrew info ffmpeg-full --depsdoesn't seem to work when ffmpeg-full isn't installedbrew info ffmpeg-fullalready displays the size when ffmpeg-full is installedbrew info ffmpeg-fulllists the various dependencies
If anything I'm inclined to say we don't add this, we odeprecate --sizes (as it's broken enough to be pretty useless) and, if it doesn't negatively affect performance, we instead add size information into the dependencies section of brew info.
Alternatively, just fix --sizes to do the same brew info output as everything else but fetch/include/use size information for the package and all the deps.
| switch "--deps", | ||
| depends_on: "--sizes", | ||
| description: "Show dependency size breakdown with exclusive deps and total disk footprint." |
There was a problem hiding this comment.
| switch "--deps", | |
| depends_on: "--sizes", | |
| description: "Show dependency size breakdown with exclusive deps and total disk footprint." | |
| switch "--dependencies", "--deps", | |
| depends_on: "--sizes", | |
| description: "Show dependency size breakdown with exclusive dependencies and total disk footprint." |
| formulae = if args.no_named? | ||
| Formula.installed | ||
| else | ||
| args.named.to_formulae |
There was a problem hiding this comment.
This fails if passed any casks
brew lgtm(style, typechecking and tests) with your changes locally?Git processing (branch management, rebasing, PR submission) was assisted by Claude. The implementation logic was written through manual analysis of the existing
--sizescode path andKeg#runtime_dependencies.Summary
Adds a
--depsflag (depends on--sizes) tobrew infothat shows dependency size breakdown:brew info --sizes --depsdisplays a table with Direct, Exclusive Deps, and Total Footprint columns for all installed formulaebrew info --sizes --deps <formula>shows detailed breakdown including exclusive and shared dependenciesbrew info --sizes --deps -v <formula>shows the full dependency listing with sizesThis addresses the feedback from #22391 where @MikeMcQuaid suggested integrating footprint analysis into
--sizesrather than creating a separate command. Replaces #22576 which couldn't be reopened after I mistakenly deleted the branch.Notes
brew lgtmnot yet run (will address once the approach is confirmed)--eval-allflag was marked as hidden/deprecated in the same commit; happy to split that into a separate PR if preferred