From 1e57445eca12e45896010aead6226f0f4c1df473 Mon Sep 17 00:00:00 2001 From: Shaun Jackman Date: Mon, 25 Sep 2017 11:10:36 -0700 Subject: [PATCH 1/6] receipt_path: Ensure the bottle contains INSTALL_RECEIPT.json --- Library/Homebrew/utils/bottles.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Library/Homebrew/utils/bottles.rb b/Library/Homebrew/utils/bottles.rb index 927963bc1e..73353496a8 100644 --- a/Library/Homebrew/utils/bottles.rb +++ b/Library/Homebrew/utils/bottles.rb @@ -29,9 +29,11 @@ module Utils end def receipt_path(bottle_file) - Utils.popen_read("tar", "-tzf", bottle_file).lines.map(&:chomp).find do |line| + path = Utils.popen_read("tar", "-tzf", bottle_file).lines.map(&:chomp).find do |line| line =~ %r{.+/.+/INSTALL_RECEIPT.json} end + raise "This bottle does not contain the file INSTALL_RECEIPT.json: #{bottle_file}" unless path + path end def resolve_formula_names(bottle_file) From 3ebf282269b62722ceff61df0335b5ee305e9f3c Mon Sep 17 00:00:00 2001 From: Shaun Jackman Date: Mon, 25 Sep 2017 11:37:07 -0700 Subject: [PATCH 2/6] pour_bottle?: Fix when formula.bottle is nil formula.bottle is nil when bottle.compatible_cellar? is false. Use formula.bottle_specification.compatible_cellar? rather than formula.bottle.compatible_cellar?. --- Library/Homebrew/formula_installer.rb | 7 +++---- Library/Homebrew/test/bottle_hooks_spec.rb | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index b4f9db8458..4966151a36 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -84,8 +84,7 @@ class FormulaInstaller return false if @pour_failed - bottle = formula.bottle - return false if !bottle && !formula.local_bottle_path + return false if !formula.bottled? && !formula.local_bottle_path return true if force_bottle? return false if build_from_source? || build_bottle? || interactive? return false if ARGV.cc @@ -101,11 +100,11 @@ class FormulaInstaller return false end - unless bottle.compatible_cellar? + unless formula.bottled? if install_bottle_options[:warn] opoo <<-EOS.undent Building #{formula.full_name} from source: - The bottle needs a #{bottle.cellar} Cellar (yours is #{HOMEBREW_CELLAR}). + The bottle needs a #{formula.bottle_specification.cellar} Cellar (yours is #{HOMEBREW_CELLAR}). EOS end return false diff --git a/Library/Homebrew/test/bottle_hooks_spec.rb b/Library/Homebrew/test/bottle_hooks_spec.rb index e70b558a18..eb66173805 100644 --- a/Library/Homebrew/test/bottle_hooks_spec.rb +++ b/Library/Homebrew/test/bottle_hooks_spec.rb @@ -8,7 +8,7 @@ describe Homebrew::Hooks::Bottles do let(:formula) do double( - bottle: nil, + bottled?: false, local_bottle_path: nil, bottle_disabled?: false, some_random_method: true, From 9642ec769e6b187c375964e4206e5ac4014d37fa Mon Sep 17 00:00:00 2001 From: Shaun Jackman Date: Mon, 25 Sep 2017 11:28:45 -0700 Subject: [PATCH 3/6] testball_bottle-0.1: Add the formula to the bottle Update the SHA-256. --- Library/Homebrew/test/formulary_spec.rb | 2 +- ...testball_bottle-0.1.yosemite.bottle.tar.gz | Bin 1379 -> 1731 bytes .../test/support/fixtures/testball_bottle.rb | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Library/Homebrew/test/formulary_spec.rb b/Library/Homebrew/test/formulary_spec.rb index 234ebc93c3..3180ad9a7b 100644 --- a/Library/Homebrew/test/formulary_spec.rb +++ b/Library/Homebrew/test/formulary_spec.rb @@ -14,7 +14,7 @@ describe Formulary do bottle do cellar :any_skip_relocation root_url "file://#{bottle_dir}" - sha256 "9abc8ce779067e26556002c4ca6b9427b9874d25f0cafa7028e05b5c5c410cb4" => :#{Utils::Bottles.tag} + sha256 "d48bbbe583dcfbfa608579724fc6f0328b3cd316935c6ea22f134610aaf2952f" => :#{Utils::Bottles.tag} end def install diff --git a/Library/Homebrew/test/support/fixtures/bottles/testball_bottle-0.1.yosemite.bottle.tar.gz b/Library/Homebrew/test/support/fixtures/bottles/testball_bottle-0.1.yosemite.bottle.tar.gz index d88838a94d8f0c62ab5e2a0b776aacf795f34604..62ea6c264b94f8b22389d7ff0bdaf5914698136a 100644 GIT binary patch literal 1731 zcmV;!20Zy6iwFQRO37IO1MQsMZ`)K9z@4>YRX4Uu^Z@~4cU~Wc6cRg$lePlUmS(h~ zU8^?JI<{fi&Q0Uiu`Pde?Z(8UY7$j7J|rag6Oee}5g{H1;{}iqf5Ie~)Q2JMVGO85QLm05vWr_Hp^;3 z%w&Rk9U`X1Y$}z>q|zxOh}n#o;fS;s!ED8MJ;i}g+&M*?uPA0CIoYr+n>vbTId%J^ zOEjr*S`o?z9>q$tjO{Y0|E2j3hL#5^vrZ&aBNJT%D+Dz)h{D?Fsd+e>mlIk!nr*4cOiNKbr{)M!F z&;Ko9r~IFpn3!yak4NS|C9VJdXF&q;FA6OGc>mvfPM!!J_f*9#cT%lvk!B?wc_L`^ z{6A}1MRkeF8vM)~@@300ijVDMSMPt(^Pd2Ma6gbT@cfr5Q^TRlwbdi^54u; z59dQ_oPYSKmonA&zigJ}AKnA;`M)Ln^4A}KAA-6K$^j@xpxlCu8&Jof^g@y4$-%es z@8qW@Y81N~+hlsT0=+_hrm#h)YopEl9*q2QfxJf-y$$iL`sL#s_W`SqZRiBFbJsU? zG}m)C;A^LBoCbX|KO@(niPvCV!N>{y~pM5xZFp43@?KteW z!NzMnnD0#FD~vG~lxjRsW;IQA6Ji2F)73gU?J;Yc&h(P&(Mn>ds)Qg2f*=TjAjrNj z$F1C5{{8;)y{^?u?JF01xSQi0D`P$F%eQ0S{dOSsGwkYEZCk$Ge&d$^Cu|&9i-Xq6 za1Xb39^N?~tT7`q55Ll&TD{KRZXezW_pM$(7i^tfxjVgluRGXz;pXxSOufBljez#o zY~S(^-4}kmJ;MI4L(Z{(?3}0@Xz*@(=c5iNtbK&Q`yG^aD8YLpf*=TjAP9mW2!bF_ z91p7OcO(dcAP9mW2!bF8g6tJ+F7eATj{D+xIRBZozlC-J+DF?su8V|Iw~w`ja{)%8 zHk%VL8MWEGfQuZPo81-6AF!kSY|g+EYlF?7z~=i=o6U<3*B8Ws>CdY*Z8op_aA1;6 z%9dTvS7lWCz>KJmwZ!`4a=JM?NC;(C|VhWlp+&4Gc)MSYEiuaO0w-( zv!+s^(5{qaw!+c(XjPt?3%X;O99Yp!jx7rDVCSL^e{J7$Tb7U(({TNd-n?~JJFoxQ z{QZY;{ZB5PlQ<%_VsX+_zW%52_g}WJkAGYr?E4R4zU${dn~^qu|0R{qWYW0)s}*R5 z;<}^|<$5ScHF=Gkww#J@D4m29X^H5j?&*r5U!kYi4V1i2_${M@j}!I*2I!fDiU}o5 zdij(rpB^2{%knD;x@aqAQD#DM!al74qW$5w72*U;D{j!&PfXo-1>6$iQlpdz!b|8T zNSYdz>4IXAq80RmM4+DV9fR;C-Jt!+legscT8dFN@Tzj_6lm zkS9F#3cuNoTUJt1mM{ZD?DHqnBZIIV$!Lp<;m0UstxUCfh<#qSgFb2&!+3od9-ZNK z^}K;;!w9-(o1MQsKZ`)KDz)#kURbAOC(FX*Gd8Ut1;!EtbeW4i*w4#@& zD_X}kEZaFvJRCdnr5BBfNzo*#YFs2F_!E$L;SnJo2IB>g5P!lXnAC?M?O_rU4~*|P zUXotY4lT_z?fXfm=h!~q#r}?+IQqT@)DH~Zwl%{I0-I*YAs`4sE~jwNi#bJT@0)O< zq^L?(Q3OTd1X0O~3gMK)aAqf=ALt&qvTE73rB^%7JLq_P9?kwKA=nXrAuV=&4Y2qN z!lT7slw}rwHJ8Qs_kz9RZ&*%O*T5siUzB7?6qTGRLj2XNEMfe6L8tgvtX0>uOI@)6 z*F#Y{KL2GQt7Mz;S5>iEnl4yQF*Mipco${4agnY#MlP#Hu zB)Qg-G5x@^oN@;p_dv(40bLr#x~d*{1W=lp+63-7|-d8 z8Cl zDp^vt<_Dpn8J1JBoU&G-c8z**ioCWQI;Lj3?)zb_F;}bVW(6kcB{pepDesldxL*Mw zt>(F9N3T*CS1TG_qh=V;=6vd`Sf1+;&|*1+6@>(_bIpRkwJ`8|7LXp(vHpkUiFBz1 zX#e`3?e$-c`X5zRa)c9mQJnOQ*Z*|7#AVkl8S7Lty^z}4<6Z8k{x|nO>VKuIA`66* zy158Df$`rJf7>$H)3IwcppRDnsmd@-6eNj*!;-3E{bw)OFaC4$^TmTT9L$07mz0Ok ze^nAx7XKWJKh}R9KChjQ9`}asR|cqAak*{<9eFC)>;9jfJG+>lnb8&sZxp7Bi|NZg zd@p_s;C@i|yZ_HZLPH5XH-gK)q%cdUaFm2r_vk73| z1T$ConjTc(z{JGV{A}UOLgAcNTqwLby)-eAnXwE{_trC0Zj~AyUCppXpV_hU)1CqP l0=@RonqQ+PDD Utils::Bottles.tag + sha256 "d48bbbe583dcfbfa608579724fc6f0328b3cd316935c6ea22f134610aaf2952f" => Utils::Bottles.tag end cxxstdlib_check :skip end From 3ed832d4f0465aa9d938d3f4867ad12aaf394710 Mon Sep 17 00:00:00 2001 From: Shaun Jackman Date: Tue, 19 Sep 2017 12:22:32 -0700 Subject: [PATCH 4/6] BottleLoader: Use the formula stored in the bottle --- Library/Homebrew/exceptions.rb | 10 +++++----- Library/Homebrew/formulary.rb | 10 +++------- Library/Homebrew/test/exceptions_spec.rb | 6 +++--- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/Library/Homebrew/exceptions.rb b/Library/Homebrew/exceptions.rb index 5418f93310..22a7fe0232 100644 --- a/Library/Homebrew/exceptions.rb +++ b/Library/Homebrew/exceptions.rb @@ -555,12 +555,12 @@ end # raised when a single patch file is not found and apply hasn't been specified class MissingApplyError < RuntimeError; end -class BottleVersionMismatchError < RuntimeError - def initialize(bottle_file, bottle_version, formula, formula_version) +class BottleFormulaUnavailableError < RuntimeError + def initialize(bottle_path, formula_path) super <<-EOS.undent - Bottle version mismatch - Bottle: #{bottle_file} (#{bottle_version}) - Formula: #{formula.full_name} (#{formula_version}) + This bottle does not contain the formula file: + #{bottle_path} + #{formula_path} EOS end end diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb index dd67b4f243..c8ab8a9228 100644 --- a/Library/Homebrew/formulary.rb +++ b/Library/Homebrew/formulary.rb @@ -122,14 +122,10 @@ module Formulary super name, Formulary.path(full_name) end - def get_formula(spec, alias_path: nil) - formula = super + def get_formula(spec, **) + contents = Utils::Bottles.formula_contents @bottle_filename, name: name + formula = Formulary.from_contents name, @bottle_filename, contents, spec formula.local_bottle_path = @bottle_filename - formula_version = formula.pkg_version - bottle_version = Utils::Bottles.resolve_version(@bottle_filename) - unless formula_version == bottle_version - raise BottleVersionMismatchError.new(@bottle_filename, bottle_version, formula, formula_version) - end formula end end diff --git a/Library/Homebrew/test/exceptions_spec.rb b/Library/Homebrew/test/exceptions_spec.rb index 33547ea32e..0a8313355f 100644 --- a/Library/Homebrew/test/exceptions_spec.rb +++ b/Library/Homebrew/test/exceptions_spec.rb @@ -181,8 +181,8 @@ describe DuplicateResourceError do its(:to_s) { is_expected.to eq("Resource is defined more than once") } end -describe BottleVersionMismatchError do - subject { described_class.new("/foo.bottle.tar.gz", "1.0", formula, "1.1") } +describe BottleFormulaUnavailableError do + subject { described_class.new("/foo.bottle.tar.gz", "foo/1.0/.brew/foo.rb") } let(:formula) { double(Formula, full_name: "foo") } - its(:to_s) { is_expected.to match(/Bottle version mismatch/) } + its(:to_s) { is_expected.to match(/This bottle does not contain the formula file/) } end From 2e77de3b58043cb8acc1e28070ae7e24fbf596fb Mon Sep 17 00:00:00 2001 From: Shaun Jackman Date: Mon, 25 Sep 2017 22:46:51 -0700 Subject: [PATCH 5/6] Fix installing a local bottle from source Factor Utils::Bottles.formula_contents out of BottleLoader. --- Library/Homebrew/formula_installer.rb | 7 ++++++- Library/Homebrew/utils/bottles.rb | 9 +++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index 4966151a36..ea4415796b 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -308,7 +308,12 @@ class FormulaInstaller clean # Store the formula used to build the keg in the keg. - s = formula.path.read.gsub(/ bottle do.+?end\n\n?/m, "") + formula_contents = if formula.local_bottle_path + Utils::Bottles.formula_contents formula.local_bottle_path, name: formula.name + else + formula.path.read + end + s = formula_contents.gsub(/ bottle do.+?end\n\n?/m, "") brew_prefix = formula.prefix/".brew" brew_prefix.mkdir Pathname(brew_prefix/"#{formula.name}.rb").atomic_write(s) diff --git a/Library/Homebrew/utils/bottles.rb b/Library/Homebrew/utils/bottles.rb index 73353496a8..66b5fb640d 100644 --- a/Library/Homebrew/utils/bottles.rb +++ b/Library/Homebrew/utils/bottles.rb @@ -54,6 +54,15 @@ module Utils def resolve_version(bottle_file) PkgVersion.parse receipt_path(bottle_file).split("/")[1] end + + def formula_contents(bottle_file, + name: resolve_formula_names(bottle_file)[0]) + bottle_version = resolve_version bottle_file + formula_path = "#{name}/#{bottle_version}/.brew/#{name}.rb" + contents = Utils.popen_read "tar", "-xOzf", bottle_file, formula_path + raise BottleFormulaUnavailableError.new(bottle_file, formula_path) unless $CHILD_STATUS.success? + contents + end end class Bintray From c19cc70ac8b87bfe93d2b94e5693584139238e23 Mon Sep 17 00:00:00 2001 From: Shaun Jackman Date: Thu, 28 Sep 2017 11:36:56 -0700 Subject: [PATCH 6/6] FormulaInstaller: Warn when tap version is newer Warn if a more recent version of this formula is available in the tap. --- Library/Homebrew/formula_installer.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index ea4415796b..845152e24d 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -235,6 +235,15 @@ class FormulaInstaller raise CannotInstallFormulaError, message end + # Warn if a more recent version of this formula is available in the tap. + begin + if formula.pkg_version < (v = Formulary.factory(formula.full_name).pkg_version) + opoo "#{formula.full_name} #{v} is available and more recent than version #{formula.pkg_version}." + end + rescue FormulaUnavailableError + nil + end + check_conflicts if !pour_bottle? && !formula.bottle_unneeded? && !DevelopmentTools.installed?