diff --git a/Library/Homebrew/cmd/info.rb b/Library/Homebrew/cmd/info.rb index 9da3a45d7d..fb61f2c546 100644 --- a/Library/Homebrew/cmd/info.rb +++ b/Library/Homebrew/cmd/info.rb @@ -50,6 +50,9 @@ module Homebrew description: "Print a JSON representation. Currently the default value for is `v1` for "\ ". For and use `v2`. See the docs for examples of using the "\ "JSON output: " + switch "--bottle", + depends_on: "--json", + description: "Output information about the bottles for and its dependencies." switch "--installed", depends_on: "--json", description: "Print JSON of formulae that are currently installed." @@ -66,6 +69,10 @@ module Homebrew conflicts "--installed", "--all" conflicts "--formula", "--cask" + %w[--cask --analytics --github].each do |conflict| + conflicts "--bottle", conflict + end + named_args [:formula, :cask] end end @@ -184,7 +191,11 @@ module Homebrew args.named.to_formulae end - formulae.map(&:to_hash) + if args.bottle? + formulae.map(&:to_recursive_bottle_hash) + else + formulae.map(&:to_hash) + end when :v2 formulae, casks = if args.all? [Formula.sort, Cask::Cask.to_a.sort_by(&:full_name)] @@ -194,10 +205,14 @@ module Homebrew args.named.to_formulae_to_casks end - { - "formulae" => formulae.map(&:to_hash), - "casks" => casks.map(&:to_h), - } + if args.bottle? + { "formulae" => formulae.map(&:to_recursive_bottle_hash) } + else + { + "formulae" => formulae.map(&:to_hash), + "casks" => casks.map(&:to_h), + } + end else raise end diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index 35b5d565ff..b22336f8ac 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -1908,6 +1908,30 @@ class Formula hsh end + # @api private + # Generate a hash to be used to install a formula from a JSON file + def to_recursive_bottle_hash(top_level: true) + bottle = bottle_hash + + bottles = bottle["files"].map do |tag, file| + info = { "url" => file["url"] } + info["sha256"] = file["sha256"] if tap.name != "homebrew/core" + [tag.to_s, info] + end.to_h + + return bottles unless top_level + + dependencies = declared_runtime_dependencies.map do |dep| + dep.to_formula.to_recursive_bottle_hash(top_level: false) + end + + { + "name" => name, + "bottles" => bottles, + "dependencies" => dependencies, + } + end + # Returns the bottle information for a formula def bottle_hash bottle_spec = stable.bottle_specification diff --git a/Library/Homebrew/test/formula_spec.rb b/Library/Homebrew/test/formula_spec.rb index 2f13cd771e..63140706bd 100644 --- a/Library/Homebrew/test/formula_spec.rb +++ b/Library/Homebrew/test/formula_spec.rb @@ -871,6 +871,25 @@ describe Formula do expect(h["versions"]["bottle"]).to be_truthy end + specify "#to_recursive_bottle_hash" do + f1 = formula "foo" do + url "foo-1.0" + + bottle do + sha256 cellar: :any, Utils::Bottles.tag.to_sym => TEST_SHA256 + sha256 cellar: :any, foo: TEST_SHA256 + end + end + + h = f1.to_recursive_bottle_hash + + expect(h).to be_a(Hash) + expect(h["name"]).to eq "foo" + expect(h["bottles"].keys).to eq [Utils::Bottles.tag.to_s, "x86_64_foo"] + expect(h["bottles"][Utils::Bottles.tag.to_s].keys).to eq ["url"] + expect(h["dependencies"]).to eq [] + end + describe "#eligible_kegs_for_cleanup" do it "returns Kegs eligible for cleanup" do f1 = Class.new(Testball) do