os/mac/diagnostic: check SDK version matches the path

This commit is contained in:
Bo Anderson 2021-02-07 04:21:59 +00:00
parent 8c81a2822c
commit fe52b3a402
4 changed files with 140 additions and 5 deletions

View File

@ -51,10 +51,7 @@ class DevelopmentTools
sig { returns(String) } sig { returns(String) }
def installation_instructions def installation_instructions
<<~EOS MacOS::CLT.installation_instructions
Install the Command Line Tools:
xcode-select --install
EOS
end end
sig { returns(String) } sig { returns(String) }

View File

@ -64,6 +64,7 @@ module Homebrew
check_clt_minimum_version check_clt_minimum_version
check_if_xcode_needs_clt_installed check_if_xcode_needs_clt_installed
check_if_supported_sdk_available check_if_supported_sdk_available
check_broken_sdks
].freeze ].freeze
end end
@ -425,7 +426,7 @@ module Homebrew
source = if locator.source == :clt source = if locator.source == :clt
update_instructions = MacOS::CLT.update_instructions update_instructions = MacOS::CLT.update_instructions
"CLT" "Command Line Tools (CLT)"
else else
update_instructions = MacOS::Xcode.update_instructions update_instructions = MacOS::Xcode.update_instructions
"Xcode" "Xcode"
@ -438,6 +439,40 @@ module Homebrew
#{update_instructions} #{update_instructions}
EOS EOS
end end
# The CLT 10.x -> 11.x upgrade process on 10.14 contained a bug which broke the SDKs.
# Notably, MacOSX10.14.sdk would indirectly symlink to MacOSX10.15.sdk.
# This diagnostic was introduced to check for this and recommend a full reinstall.
def check_broken_sdks
locator = MacOS.sdk_locator
return if locator.all_sdks.all? do |sdk|
path_version = sdk.path.basename.to_s[MacOS::SDK::VERSIONED_SDK_REGEX, 1]
next true if path_version.blank?
sdk.version == MacOS::Version.new(path_version).strip_patch
end
if locator.source == :clt
source = "Command Line Tools (CLT)"
path_to_remove = MacOS::CLT::PKG_PATH
installation_instructions = MacOS::CLT.installation_instructions
else
source = "Xcode"
path_to_remove = MacOS::Xcode.bundle_path
installation_instructions = MacOS::Xcode.installation_instructions
end
<<~EOS
The contents of the SDKs in your #{source} installation do not match the SDK folder names.
A clean reinstall of #{source} should fix this.
Remove the broken installation before reinstalling:
sudo rm -rf #{path_to_remove}
#{installation_instructions}
EOS
end
end end
end end
end end

View File

@ -134,6 +134,19 @@ module OS
sdk(v)&.path sdk(v)&.path
end end
def installation_instructions
if OS::Mac.prerelease?
<<~EOS
Xcode can be installed from:
#{Formatter.url("https://developer.apple.com/download/more/")}
EOS
else
<<~EOS
Xcode can be installed from the App Store.
EOS
end
end
sig { returns(String) } sig { returns(String) }
def update_instructions def update_instructions
if OS::Mac.prerelease? if OS::Mac.prerelease?
@ -254,6 +267,21 @@ module OS
sdk(v)&.path sdk(v)&.path
end end
def installation_instructions
if MacOS.version == "10.14"
# This is not available from `xcode-select`
<<~EOS
Install the Command Line Tools for Xcode 11.3.1 from:
#{Formatter.url("https://developer.apple.com/download/more/")}
EOS
else
<<~EOS
Install the Command Line Tools:
xcode-select --install
EOS
end
end
sig { returns(String) } sig { returns(String) }
def update_instructions def update_instructions
software_update_location = if MacOS.version >= "10.14" software_update_location = if MacOS.version >= "10.14"

View File

@ -39,4 +39,79 @@ describe Homebrew::Diagnostic::Checks do
expect(checks.check_ruby_version) expect(checks.check_ruby_version)
.to match "Ruby version 1.8.6 is unsupported on 10.12" .to match "Ruby version 1.8.6 is unsupported on 10.12"
end end
describe "#check_if_supported_sdk_available" do
let(:macos_version) { OS::Mac::Version.new("11") }
before do
allow(DevelopmentTools).to receive(:installed?).and_return(true)
allow(OS::Mac).to receive(:version).and_return(macos_version)
end
it "doesn't trigger when SDK root is not needed" do
allow(OS::Mac).to receive(:sdk_root_needed?).and_return(false)
allow(OS::Mac).to receive(:sdk).and_return(nil)
expect(checks.check_if_supported_sdk_available).to be_nil
end
it "doesn't trigger when a valid SDK is present" do
allow(OS::Mac).to receive(:sdk_root_needed?).and_return(true)
allow(OS::Mac).to receive(:sdk).and_return(OS::Mac::SDK.new(macos_version, "/some/path/MacOSX.sdk", :clt))
expect(checks.check_if_supported_sdk_available).to be_nil
end
it "triggers when a valid SDK is not present on CLT systems" do
allow(OS::Mac).to receive(:sdk_root_needed?).and_return(true)
allow(OS::Mac).to receive(:sdk).and_return(nil)
allow(OS::Mac).to receive(:sdk_locator).and_return(OS::Mac::CLT.sdk_locator)
expect(checks.check_if_supported_sdk_available)
.to include("Your Command Line Tools (CLT) does not support macOS #{macos_version}")
end
it "triggers when a valid SDK is not present on Xcode systems" do
allow(OS::Mac).to receive(:sdk_root_needed?).and_return(true)
allow(OS::Mac).to receive(:sdk).and_return(nil)
allow(OS::Mac).to receive(:sdk_locator).and_return(OS::Mac::Xcode.sdk_locator)
expect(checks.check_if_supported_sdk_available)
.to include("Your Xcode does not support macOS #{macos_version}")
end
end
describe "#check_broken_sdks" do
it "doesn't trigger when SDK versions are as expected" do
allow(OS::Mac).to receive(:sdk_locator).and_return(OS::Mac::CLT.sdk_locator)
allow_any_instance_of(OS::Mac::CLTSDKLocator).to receive(:all_sdks)
.and_return([
OS::Mac::SDK.new(OS::Mac::Version.new("11"), "/some/path/MacOSX.sdk", :clt),
OS::Mac::SDK.new(OS::Mac::Version.new("10.15"), "/some/path/MacOSX10.15.sdk", :clt),
])
expect(checks.check_broken_sdks).to be_nil
end
it "triggers when the CLT SDK version doesn't match the folder name" do
allow_any_instance_of(OS::Mac::CLTSDKLocator).to receive(:all_sdks)
.and_return([
OS::Mac::SDK.new(OS::Mac::Version.new("10.14"), "/some/path/MacOSX10.15.sdk", :clt),
])
expect(checks.check_broken_sdks)
.to include("SDKs in your Command Line Tools (CLT) installation do not match the SDK folder names")
end
it "triggers when the Xcode SDK version doesn't match the folder name" do
allow(OS::Mac).to receive(:sdk_locator).and_return(OS::Mac::Xcode.sdk_locator)
allow_any_instance_of(OS::Mac::XcodeSDKLocator).to receive(:all_sdks)
.and_return([
OS::Mac::SDK.new(OS::Mac::Version.new("10.14"), "/some/path/MacOSX10.15.sdk", :xcode),
])
expect(checks.check_broken_sdks)
.to include("The contents of the SDKs in your Xcode installation do not match the SDK folder names")
end
end
end end