From 91e598cf3f88591f2146218eaa2ecc2a3a261e31 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Mon, 29 Jun 2015 14:09:57 -0400 Subject: [PATCH] Install: add BuildToolsError and BuildFlagsError Add these new errors, and guards in formula installation and cmd/{,un,re}install to match, move can_build? to the MacOS module, flatten conditions, remove redundant can_build? check reinstate removed (doctor) check --- Library/Homebrew/cmd/install.rb | 18 +++-- Library/Homebrew/cmd/reinstall.rb | 8 +++ Library/Homebrew/cmd/upgrade.rb | 8 +++ Library/Homebrew/exceptions.rb | 94 +++++++++++++++++++++++++++ Library/Homebrew/extend/ARGV.rb | 13 ++++ Library/Homebrew/formula_installer.rb | 4 ++ Library/Homebrew/os/mac.rb | 4 ++ 7 files changed, 143 insertions(+), 6 deletions(-) diff --git a/Library/Homebrew/cmd/install.rb b/Library/Homebrew/cmd/install.rb index 1ef1ca61a5..ce9bf5291d 100644 --- a/Library/Homebrew/cmd/install.rb +++ b/Library/Homebrew/cmd/install.rb @@ -38,6 +38,14 @@ module Homebrew end end + # if the user's flags will prevent bottle only-installations when no + # developer tools are available, we need to stop them early on + if !MacOS.can_build? + bf = ARGV.collect_build_flags + + raise BuildFlagsError.new(bf) if !bf.empty? + end + ARGV.formulae.each do |f| # head-only without --HEAD is an error if !ARGV.build_head? && f.stable.nil? && f.devel.nil? @@ -129,6 +137,9 @@ module Homebrew # when one is no longer required checks = Checks.new %w[ + check_for_unsupported_osx + check_for_bad_install_name_tool + check_for_installed_developer_tools check_xcode_license_approved check_for_osx_gcc_installer ].each do |check| @@ -157,12 +168,7 @@ module Homebrew def perform_preinstall_checks check_ppc check_writable_install_location - if MacOS::Xcode.installed? - check_xcode - else - opoo "You have not installed Xcode." - puts "Bottles may install correctly, but builds will fail!" - end + check_xcode if MacOS::Xcode.installed? check_cellar end diff --git a/Library/Homebrew/cmd/reinstall.rb b/Library/Homebrew/cmd/reinstall.rb index bf49282ae9..98941698a3 100644 --- a/Library/Homebrew/cmd/reinstall.rb +++ b/Library/Homebrew/cmd/reinstall.rb @@ -2,6 +2,14 @@ require "formula_installer" module Homebrew def reinstall + if !MacOS.can_build? + bf = ARGV.collect_build_flags + + if !bf.empty? + raise BuildFlagsError.new(bf) + end + end + ARGV.resolved_formulae.each { |f| reinstall_formula(f) } end diff --git a/Library/Homebrew/cmd/upgrade.rb b/Library/Homebrew/cmd/upgrade.rb index 8ae231002d..e8fc9c0f86 100644 --- a/Library/Homebrew/cmd/upgrade.rb +++ b/Library/Homebrew/cmd/upgrade.rb @@ -3,6 +3,14 @@ require "cmd/outdated" module Homebrew def upgrade + if !MacOS.can_build? + bf = ARGV.collect_build_flags + + if !bf.empty? + raise BuildFlagsError.new(bf) + end + end + Homebrew.perform_preinstall_checks if ARGV.named.empty? diff --git a/Library/Homebrew/exceptions.rb b/Library/Homebrew/exceptions.rb index 841cc8b392..585ca7e60b 100644 --- a/Library/Homebrew/exceptions.rb +++ b/Library/Homebrew/exceptions.rb @@ -226,6 +226,100 @@ class BuildError < RuntimeError end end +# raised by FormulaInstaller.check_dependencies_bottled and +# FormulaInstaller.install if the formula or its dependencies are not bottled +# and are being installed on a system without necessary build tools +class BuildToolsError < RuntimeError + def initialize(formulae) + if formulae.length > 1 + formula_text = "formulae" + package_text = "binary packages" + else + formula_text = "formula" + package_text = "a binary package" + end + + if MacOS.version >= "10.10" + xcode_text = <<-EOS.undent + To continue, you must install Xcode from the App Store, + or the CLT by running: + xcode-select --install + EOS + elsif MacOS.version == "10.9" + xcode_text = <<-EOS.undent + To continue, you must install Xcode from: + https://developer.apple.com/downloads/ + or the CLT by running: + xcode-select --install + EOS + elsif MacOS.version >= "10.7" + xcode_text = <<-EOS.undent + To continue, you must install Xcode or the CLT from: + https://developer.apple.com/downloads/ + EOS + else + xcode_text = <<-EOS.undent + To continue, you must install Xcode from: + https://developer.apple.com/downloads/ + EOS + end + + super <<-EOS.undent + The following #{formula_text}: + #{formulae.join(', ')} + cannot be installed as a #{package_text} and must be built from source. + #{xcode_text} + EOS + end +end + +# raised by Homebrew.install, Homebrew.reinstall, and Homebrew.upgrade +# if the user passes any flags/environment that would case a bottle-only +# installation on a system without build tools to fail +class BuildFlagsError < RuntimeError + def initialize(flags) + if flags.length > 1 + flag_text = "flags" + require_text = "require" + else + flag_text = "flag" + require_text = "requires" + end + + if MacOS.version >= "10.10" + xcode_text = <<-EOS.undent + or install Xcode from the App Store, or the CLT by running: + xcode-select --install + EOS + elsif MacOS.version == "10.9" + xcode_text = <<-EOS.undent + or install Xcode from: + https://developer.apple.com/downloads/ + or the CLT by running: + xcode-select --install + EOS + elsif MacOS.version >= "10.7" + xcode_text = <<-EOS.undent + or install Xcode or the CLT from: + https://developer.apple.com/downloads/ + EOS + else + xcode_text = <<-EOS.undent + or install Xcode from: + https://developer.apple.com/downloads/ + EOS + end + + super <<-EOS.undent + The following #{flag_text}: + #{flags.join(', ')} + #{require_text} building tools, but none are installed. + Either remove the #{flag_text} to attempt bottle installation, + #{xcode_text} + EOS + end +end + # raised by CompilerSelector if the formula fails with all of # the compilers available on the user's system class CompilerSelectionError < RuntimeError diff --git a/Library/Homebrew/extend/ARGV.rb b/Library/Homebrew/extend/ARGV.rb index a8eb9a5d22..706b625684 100644 --- a/Library/Homebrew/extend/ARGV.rb +++ b/Library/Homebrew/extend/ARGV.rb @@ -200,6 +200,19 @@ module HomebrewArgvExtension value "env" end + # collect any supplied build flags into an array for reporting + def collect_build_flags + build_flags = [] + + build_flags << '--HEAD' if build_head? + build_flags << '--universal' if build_universal? + build_flags << '--32-bit' if build_32_bit? + build_flags << '--build-bottle' if build_bottle? + build_flags << '--build-from-source' if build_from_source? + + build_flags + end + private def spec(default = :stable) diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index bb1ed74f78..45bbd60d14 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -147,6 +147,10 @@ class FormulaInstaller check_conflicts + if !pour_bottle? && !MacOS.can_build? + raise BuildToolsError.new([formula]) + end + if !ignore_deps? deps = compute_dependencies check_dependencies_bottled(deps) if pour_bottle? diff --git a/Library/Homebrew/os/mac.rb b/Library/Homebrew/os/mac.rb index 1851265488..4e69a60356 100644 --- a/Library/Homebrew/os/mac.rb +++ b/Library/Homebrew/os/mac.rb @@ -52,6 +52,10 @@ module OS end end + def can_build? + Xcode.installed? || CLT.installed? + end + def active_developer_dir @active_developer_dir ||= Utils.popen_read("/usr/bin/xcode-select", "-print-path").strip end