diff --git a/Library/Homebrew/dev-cmd/bottle.rb b/Library/Homebrew/dev-cmd/bottle.rb index e382e3586f..46144f0f3b 100644 --- a/Library/Homebrew/dev-cmd/bottle.rb +++ b/Library/Homebrew/dev-cmd/bottle.rb @@ -9,6 +9,7 @@ require "formula_versions" require "cli/parser" require "utils/inreplace" require "erb" +require "utils/ast" BOTTLE_ERB = <<-EOS bottle do @@ -510,13 +511,12 @@ module Homebrew output = bottle_output bottle end puts output - string = s.sub!(/ bottle do.+?end\n/m, output) - odie "Bottle block update failed!" unless string + Utils::AST.replace_bottle_stanza!(s.inreplace_string, output) else odie "--keep-old was passed but there was no existing bottle block!" if args.keep_old? puts output update_or_add = "add" - Utils::Bottles.add_bottle_stanza!(s.inreplace_string, output) + Utils::AST.add_bottle_stanza!(s.inreplace_string, output) end end diff --git a/Library/Homebrew/dev-cmd/bump-revision.rb b/Library/Homebrew/dev-cmd/bump-revision.rb index fac6c1461b..d2e28f2a25 100644 --- a/Library/Homebrew/dev-cmd/bump-revision.rb +++ b/Library/Homebrew/dev-cmd/bump-revision.rb @@ -52,9 +52,9 @@ module Homebrew Utils::Inreplace.inreplace(formula.path) do |s| s = s.inreplace_string if current_revision.zero? - Utils::AST.add_formula_stanza!(s, name: :revision, text: text) + Utils::AST.add_formula_stanza!(s, :revision, text) else - Utils::AST.replace_formula_stanza!(s, name: :revision, replacement: text) + Utils::AST.replace_formula_stanza!(s, :revision, text) end end end diff --git a/Library/Homebrew/test/utils/ast_spec.rb b/Library/Homebrew/test/utils/ast_spec.rb index cdf05a7032..a9f0ceb774 100644 --- a/Library/Homebrew/test/utils/ast_spec.rb +++ b/Library/Homebrew/test/utils/ast_spec.rb @@ -20,7 +20,7 @@ describe Utils::AST do describe ".replace_formula_stanza!" do it "replaces the specified stanza in a formula" do contents = initial_formula.dup - described_class.replace_formula_stanza! contents, name: :license, replacement: "license :public_domain" + described_class.replace_formula_stanza!(contents, :license, "license :public_domain") expect(contents).to eq <<~RUBY class Foo < Formula url "https://brew.sh/foo-1.0.tar.gz" @@ -33,7 +33,7 @@ describe Utils::AST do describe ".add_formula_stanza!" do it "adds the specified stanza to a formula" do contents = initial_formula.dup - described_class.add_formula_stanza! contents, name: :revision, text: "revision 1" + described_class.add_formula_stanza!(contents, :revision, "revision 1") expect(contents).to eq <<~RUBY class Foo < Formula url "https://brew.sh/foo-1.0.tar.gz" @@ -47,4 +47,260 @@ describe Utils::AST do RUBY end end + + describe ".add_bottle_stanza!" do + let(:bottle_output) do + <<~RUBY.chomp.indent(2) + bottle do + sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra + end + RUBY + end + + context "when `license` is a string" do + let(:formula_contents) do + <<~RUBY.chomp + class Foo < Formula + url "https://brew.sh/foo-1.0.tar.gz" + license "MIT" + end + RUBY + end + + let(:new_contents) do + <<~RUBY.chomp + class Foo < Formula + url "https://brew.sh/foo-1.0.tar.gz" + license "MIT" + + bottle do + sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra + end + end + RUBY + end + + it "adds `bottle` after `license`" do + described_class.add_bottle_stanza!(formula_contents, bottle_output) + expect(formula_contents).to eq(new_contents) + end + end + + context "when `license` is a symbol" do + let(:formula_contents) do + <<~RUBY.chomp + class Foo < Formula + url "https://brew.sh/foo-1.0.tar.gz" + license :cannot_represent + end + RUBY + end + + let(:new_contents) do + <<~RUBY.chomp + class Foo < Formula + url "https://brew.sh/foo-1.0.tar.gz" + license :cannot_represent + + bottle do + sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra + end + end + RUBY + end + + it "adds `bottle` after `license`" do + described_class.add_bottle_stanza!(formula_contents, bottle_output) + expect(formula_contents).to eq(new_contents) + end + end + + context "when `license` is multiline" do + let(:formula_contents) do + <<~RUBY.chomp + class Foo < Formula + url "https://brew.sh/foo-1.0.tar.gz" + license all_of: [ + :public_domain, + "MIT", + "GPL-3.0-or-later" => { with: "Autoconf-exception-3.0" }, + ] + end + RUBY + end + + let(:new_contents) do + <<~RUBY.chomp + class Foo < Formula + url "https://brew.sh/foo-1.0.tar.gz" + license all_of: [ + :public_domain, + "MIT", + "GPL-3.0-or-later" => { with: "Autoconf-exception-3.0" }, + ] + + bottle do + sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra + end + end + RUBY + end + + it "adds `bottle` after `license`" do + described_class.add_bottle_stanza!(formula_contents, bottle_output) + expect(formula_contents).to eq(new_contents) + end + end + + context "when `head` is a string" do + let(:formula_contents) do + <<~RUBY.chomp + class Foo < Formula + url "https://brew.sh/foo-1.0.tar.gz" + head "https://brew.sh/foo.git" + end + RUBY + end + + let(:new_contents) do + <<~RUBY.chomp + class Foo < Formula + url "https://brew.sh/foo-1.0.tar.gz" + head "https://brew.sh/foo.git" + + bottle do + sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra + end + end + RUBY + end + + it "adds `bottle` after `head`" do + described_class.add_bottle_stanza!(formula_contents, bottle_output) + expect(formula_contents).to eq(new_contents) + end + end + + context "when `head` is a block" do + let(:formula_contents) do + <<~RUBY.chomp + class Foo < Formula + url "https://brew.sh/foo-1.0.tar.gz" + + head do + url "https://brew.sh/foo.git" + end + end + RUBY + end + + let(:new_contents) do + <<~RUBY.chomp + class Foo < Formula + url "https://brew.sh/foo-1.0.tar.gz" + + bottle do + sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra + end + + head do + url "https://brew.sh/foo.git" + end + end + RUBY + end + + it "adds `bottle` before `head`" do + described_class.add_bottle_stanza!(formula_contents, bottle_output) + expect(formula_contents).to eq(new_contents) + end + end + + context "when there is a comment on the same line" do + let(:formula_contents) do + <<~RUBY.chomp + class Foo < Formula + url "https://brew.sh/foo-1.0.tar.gz" # comment + end + RUBY + end + + let(:new_contents) do + <<~RUBY.chomp + class Foo < Formula + url "https://brew.sh/foo-1.0.tar.gz" # comment + + bottle do + sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra + end + end + RUBY + end + + it "adds `bottle` after the comment" do + described_class.add_bottle_stanza!(formula_contents, bottle_output) + expect(formula_contents).to eq(new_contents) + end + end + + context "when the next line is a comment" do + let(:formula_contents) do + <<~RUBY.chomp + class Foo < Formula + url "https://brew.sh/foo-1.0.tar.gz" + # comment + end + RUBY + end + + let(:new_contents) do + <<~RUBY.chomp + class Foo < Formula + url "https://brew.sh/foo-1.0.tar.gz" + # comment + + bottle do + sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra + end + end + RUBY + end + + it "adds `bottle` after the comment" do + described_class.add_bottle_stanza!(formula_contents, bottle_output) + expect(formula_contents).to eq(new_contents) + end + end + + context "when the next line is blank and the one after it is a comment" do + let(:formula_contents) do + <<~RUBY.chomp + class Foo < Formula + url "https://brew.sh/foo-1.0.tar.gz" + + # comment + end + RUBY + end + + let(:new_contents) do + <<~RUBY.chomp + class Foo < Formula + url "https://brew.sh/foo-1.0.tar.gz" + + bottle do + sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra + end + + # comment + end + RUBY + end + + it "adds `bottle` before the comment" do + described_class.add_bottle_stanza!(formula_contents, bottle_output) + expect(formula_contents).to eq(new_contents) + end + end + end end diff --git a/Library/Homebrew/test/utils/bottles/bottles_spec.rb b/Library/Homebrew/test/utils/bottles/bottles_spec.rb index 601b1b4125..c7a0cf9af3 100644 --- a/Library/Homebrew/test/utils/bottles/bottles_spec.rb +++ b/Library/Homebrew/test/utils/bottles/bottles_spec.rb @@ -14,260 +14,4 @@ describe Utils::Bottles do end end end - - describe "#add_bottle_stanza!" do - let(:bottle_output) do - <<~RUBY.chomp.indent(2) - bottle do - sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra - end - RUBY - end - - context "when `license` is a string" do - let(:formula_contents) do - <<~RUBY.chomp - class Foo < Formula - url "https://brew.sh/foo-1.0.tar.gz" - license "MIT" - end - RUBY - end - - let(:new_contents) do - <<~RUBY.chomp - class Foo < Formula - url "https://brew.sh/foo-1.0.tar.gz" - license "MIT" - - bottle do - sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra - end - end - RUBY - end - - it "adds `bottle` after `license`" do - described_class.add_bottle_stanza! formula_contents, bottle_output - expect(formula_contents).to eq(new_contents) - end - end - - context "when `license` is a symbol" do - let(:formula_contents) do - <<~RUBY.chomp - class Foo < Formula - url "https://brew.sh/foo-1.0.tar.gz" - license :cannot_represent - end - RUBY - end - - let(:new_contents) do - <<~RUBY.chomp - class Foo < Formula - url "https://brew.sh/foo-1.0.tar.gz" - license :cannot_represent - - bottle do - sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra - end - end - RUBY - end - - it "adds `bottle` after `license`" do - described_class.add_bottle_stanza! formula_contents, bottle_output - expect(formula_contents).to eq(new_contents) - end - end - - context "when `license` is multiline" do - let(:formula_contents) do - <<~RUBY.chomp - class Foo < Formula - url "https://brew.sh/foo-1.0.tar.gz" - license all_of: [ - :public_domain, - "MIT", - "GPL-3.0-or-later" => { with: "Autoconf-exception-3.0" }, - ] - end - RUBY - end - - let(:new_contents) do - <<~RUBY.chomp - class Foo < Formula - url "https://brew.sh/foo-1.0.tar.gz" - license all_of: [ - :public_domain, - "MIT", - "GPL-3.0-or-later" => { with: "Autoconf-exception-3.0" }, - ] - - bottle do - sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra - end - end - RUBY - end - - it "adds `bottle` after `license`" do - described_class.add_bottle_stanza! formula_contents, bottle_output - expect(formula_contents).to eq(new_contents) - end - end - - context "when `head` is a string" do - let(:formula_contents) do - <<~RUBY.chomp - class Foo < Formula - url "https://brew.sh/foo-1.0.tar.gz" - head "https://brew.sh/foo.git" - end - RUBY - end - - let(:new_contents) do - <<~RUBY.chomp - class Foo < Formula - url "https://brew.sh/foo-1.0.tar.gz" - head "https://brew.sh/foo.git" - - bottle do - sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra - end - end - RUBY - end - - it "adds `bottle` after `head`" do - described_class.add_bottle_stanza! formula_contents, bottle_output - expect(formula_contents).to eq(new_contents) - end - end - - context "when `head` is a block" do - let(:formula_contents) do - <<~RUBY.chomp - class Foo < Formula - url "https://brew.sh/foo-1.0.tar.gz" - - head do - url "https://brew.sh/foo.git" - end - end - RUBY - end - - let(:new_contents) do - <<~RUBY.chomp - class Foo < Formula - url "https://brew.sh/foo-1.0.tar.gz" - - bottle do - sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra - end - - head do - url "https://brew.sh/foo.git" - end - end - RUBY - end - - it "adds `bottle` before `head`" do - described_class.add_bottle_stanza! formula_contents, bottle_output - expect(formula_contents).to eq(new_contents) - end - end - - context "when there is a comment on the same line" do - let(:formula_contents) do - <<~RUBY.chomp - class Foo < Formula - url "https://brew.sh/foo-1.0.tar.gz" # comment - end - RUBY - end - - let(:new_contents) do - <<~RUBY.chomp - class Foo < Formula - url "https://brew.sh/foo-1.0.tar.gz" # comment - - bottle do - sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra - end - end - RUBY - end - - it "adds `bottle` after the comment" do - described_class.add_bottle_stanza! formula_contents, bottle_output - expect(formula_contents).to eq(new_contents) - end - end - - context "when the next line is a comment" do - let(:formula_contents) do - <<~RUBY.chomp - class Foo < Formula - url "https://brew.sh/foo-1.0.tar.gz" - # comment - end - RUBY - end - - let(:new_contents) do - <<~RUBY.chomp - class Foo < Formula - url "https://brew.sh/foo-1.0.tar.gz" - # comment - - bottle do - sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra - end - end - RUBY - end - - it "adds `bottle` after the comment" do - described_class.add_bottle_stanza! formula_contents, bottle_output - expect(formula_contents).to eq(new_contents) - end - end - - context "when the next line is blank and the one after it is a comment" do - let(:formula_contents) do - <<~RUBY.chomp - class Foo < Formula - url "https://brew.sh/foo-1.0.tar.gz" - - # comment - end - RUBY - end - - let(:new_contents) do - <<~RUBY.chomp - class Foo < Formula - url "https://brew.sh/foo-1.0.tar.gz" - - bottle do - sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra - end - - # comment - end - RUBY - end - - it "adds `bottle` before the comment" do - described_class.add_bottle_stanza! formula_contents, bottle_output - expect(formula_contents).to eq(new_contents) - end - end - end end diff --git a/Library/Homebrew/utils/ast.rb b/Library/Homebrew/utils/ast.rb index fcc718c7ec..8cac1b66b9 100644 --- a/Library/Homebrew/utils/ast.rb +++ b/Library/Homebrew/utils/ast.rb @@ -9,18 +9,26 @@ module Utils class << self extend T::Sig - def replace_formula_stanza!(formula_contents, name:, replacement:, type: nil) + def replace_bottle_stanza!(formula_contents, bottle_output) + replace_formula_stanza!(formula_contents, :bottle, bottle_output.strip, type: :block_call) + end + + def add_bottle_stanza!(formula_contents, bottle_output) + add_formula_stanza!(formula_contents, :bottle, "\n#{bottle_output.chomp}", type: :block_call) + end + + def replace_formula_stanza!(formula_contents, name, replacement, type: nil) processed_source, body_node = process_formula(formula_contents) children = body_node.begin_type? ? body_node.children.compact : [body_node] stanza_node = children.find { |child| call_node_match?(child, name: name, type: type) } raise "Could not find #{name} stanza!" if stanza_node.nil? tree_rewriter = Parser::Source::TreeRewriter.new(processed_source.buffer) - tree_rewriter.replace(stanza_node.source_range, replacement.strip) + tree_rewriter.replace(stanza_node.source_range, replacement) formula_contents.replace(tree_rewriter.process) end - def add_formula_stanza!(formula_contents, name:, text:, type: nil) + def add_formula_stanza!(formula_contents, name, text, type: nil) processed_source, body_node = process_formula(formula_contents) preceding_component = if body_node.begin_type? diff --git a/Library/Homebrew/utils/bottles.rb b/Library/Homebrew/utils/bottles.rb index a825f46fd8..99c727cbd1 100644 --- a/Library/Homebrew/utils/bottles.rb +++ b/Library/Homebrew/utils/bottles.rb @@ -2,7 +2,6 @@ # frozen_string_literal: true require "tab" -require "utils/ast" module Utils # Helper functions for bottles. @@ -75,13 +74,6 @@ module Utils contents end - - def add_bottle_stanza!(formula_contents, bottle_output) - Utils::AST.add_formula_stanza!(formula_contents, - name: :bottle, - type: :block_call, - text: "\n#{bottle_output.chomp}") - end end # Helper functions for bottles hosted on Bintray.