| 
									
										
										
										
											2021-09-29 15:12:53 -07:00
										 |  |  | # typed: true | 
					
						
							| 
									
										
										
										
											2019-04-19 15:38:03 +09:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  | module OS | 
					
						
							|  |  |  |   module Mac | 
					
						
							| 
									
										
										
										
											2020-08-25 00:38:56 +02:00
										 |  |  |     # Helper module for querying Xcode information. | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # @api private | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |     module Xcode | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |       extend T::Sig | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 20:11:54 +02:00
										 |  |  |       module_function | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |       DEFAULT_BUNDLE_PATH = Pathname("/Applications/Xcode.app").freeze | 
					
						
							| 
									
										
										
										
											2019-04-19 15:38:03 +09:00
										 |  |  |       BUNDLE_ID = "com.apple.dt.Xcode" | 
					
						
							|  |  |  |       OLD_BUNDLE_ID = "com.apple.Xcode" | 
					
						
							| 
									
										
										
										
											2021-10-04 22:22:20 +08:00
										 |  |  |       APPLE_DEVELOPER_DOWNLOAD_URL = "https://developer.apple.com/download/all/" | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-09 14:27:37 +01:00
										 |  |  |       # Bump these when a new version is available from the App Store and our | 
					
						
							|  |  |  |       # CI systems have been updated. | 
					
						
							|  |  |  |       # This may be a beta version for a beta macOS. | 
					
						
							| 
									
										
										
										
											2021-02-23 04:41:29 +00:00
										 |  |  |       sig { params(macos: MacOS::Version).returns(String) } | 
					
						
							|  |  |  |       def latest_version(macos: MacOS.version) | 
					
						
							| 
									
										
										
										
											2022-05-26 18:11:29 +01:00
										 |  |  |         latest_stable = "13.4" | 
					
						
							| 
									
										
										
										
											2021-02-23 04:41:29 +00:00
										 |  |  |         case macos | 
					
						
							| 
									
										
										
										
											2022-06-06 19:13:42 +01:00
										 |  |  |         when "13" then "14.0" | 
					
						
							| 
									
										
										
										
											2022-03-24 15:09:30 +00:00
										 |  |  |         when "12" then latest_stable | 
					
						
							|  |  |  |         when "11" then "13.2.1" | 
					
						
							| 
									
										
										
										
											2021-01-29 17:08:29 +11:00
										 |  |  |         when "10.15" then "12.4" | 
					
						
							| 
									
										
										
										
											2020-04-09 14:27:37 +01:00
										 |  |  |         when "10.14" then "11.3.1" | 
					
						
							|  |  |  |         when "10.13" then "10.1" | 
					
						
							|  |  |  |         when "10.12" then "9.2" | 
					
						
							|  |  |  |         when "10.11" then "8.2.1" | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |         else | 
					
						
							| 
									
										
										
										
											2021-06-22 13:06:46 -04:00
										 |  |  |           raise "macOS '#{MacOS.version}' is invalid" unless OS::Mac.version.prerelease? | 
					
						
							| 
									
										
										
										
											2016-09-23 22:02:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 19:57:19 +01:00
										 |  |  |           # Default to newest known version of Xcode for unreleased macOS versions. | 
					
						
							| 
									
										
										
										
											2020-06-23 14:11:05 +01:00
										 |  |  |           latest_stable | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2013-06-04 13:58:08 +01:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2012-08-17 17:18:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-09 14:27:37 +01:00
										 |  |  |       # Bump these if things are badly broken (e.g. no SDK for this macOS) | 
					
						
							|  |  |  |       # without this. Generally this will be the first Xcode release on that | 
					
						
							|  |  |  |       # macOS version (which may initially be a beta if that version of macOS is | 
					
						
							|  |  |  |       # also in beta). | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |       sig { returns(String) } | 
					
						
							| 
									
										
										
										
											2016-11-05 10:35:39 -04:00
										 |  |  |       def minimum_version | 
					
						
							|  |  |  |         case MacOS.version | 
					
						
							| 
									
										
										
										
											2022-06-06 19:13:42 +01:00
										 |  |  |         when "13" then "14.0" | 
					
						
							| 
									
										
										
										
											2021-10-19 16:56:06 +01:00
										 |  |  |         when "12" then "13.1" | 
					
						
							| 
									
										
										
										
											2020-11-23 10:14:18 +01:00
										 |  |  |         when "11" then "12.2" | 
					
						
							| 
									
										
										
										
											2019-06-04 16:11:18 -07:00
										 |  |  |         when "10.15" then "11.0" | 
					
						
							| 
									
										
										
										
											2019-05-01 09:06:41 +01:00
										 |  |  |         when "10.14" then "10.2" | 
					
						
							| 
									
										
										
										
											2017-06-06 04:33:55 +01:00
										 |  |  |         when "10.13" then "9.0" | 
					
						
							| 
									
										
										
										
											2016-11-05 10:35:39 -04:00
										 |  |  |         when "10.12" then "8.0" | 
					
						
							|  |  |  |         else "2.0" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-23 10:14:18 +01:00
										 |  |  |       sig { returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2016-12-18 15:31:15 -08:00
										 |  |  |       def below_minimum_version? | 
					
						
							| 
									
										
										
										
											2017-11-05 12:09:04 +00:00
										 |  |  |         return false unless installed? | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-05 10:35:39 -04:00
										 |  |  |         version < minimum_version | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-23 10:14:18 +01:00
										 |  |  |       sig { returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2017-11-17 19:53:38 +00:00
										 |  |  |       def latest_sdk_version? | 
					
						
							| 
									
										
										
										
											2020-11-23 10:14:18 +01:00
										 |  |  |         OS::Mac.full_version >= OS::Mac.latest_sdk_version | 
					
						
							| 
									
										
										
										
											2017-11-17 19:53:38 +00:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-23 10:14:18 +01:00
										 |  |  |       sig { returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2017-11-17 19:53:38 +00:00
										 |  |  |       def needs_clt_installed? | 
					
						
							|  |  |  |         return false if latest_sdk_version? | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-31 16:32:23 +01:00
										 |  |  |         # With fake El Capitan for Portable Ruby, we want the full 10.11 SDK so that we can link | 
					
						
							|  |  |  |         # against the correct set of libraries in the SDK sysroot rather than the system's copies. | 
					
						
							|  |  |  |         # We therefore do not use the CLT under this setup, which installs to /usr/include. | 
					
						
							|  |  |  |         return false if ENV["HOMEBREW_FAKE_EL_CAPITAN"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-17 19:53:38 +00:00
										 |  |  |         without_clt? | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-23 10:14:18 +01:00
										 |  |  |       sig { returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       def outdated? | 
					
						
							| 
									
										
										
										
											2017-11-05 12:09:04 +00:00
										 |  |  |         return false unless installed? | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-05 12:09:04 +00:00
										 |  |  |         version < latest_version | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2013-05-22 22:26:09 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-23 10:14:18 +01:00
										 |  |  |       sig { returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       def without_clt? | 
					
						
							| 
									
										
										
										
											2019-01-26 17:13:14 +00:00
										 |  |  |         !MacOS::CLT.installed? | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2013-08-09 20:47:28 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-16 22:51:39 -07:00
										 |  |  |       # Returns a Pathname object corresponding to Xcode.app's Developer | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |       # directory or nil if Xcode.app is not installed. | 
					
						
							| 
									
										
										
										
											2021-09-29 17:43:47 -07:00
										 |  |  |       sig { returns(T.nilable(Pathname)) } | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       def prefix | 
					
						
							| 
									
										
										
										
											2021-09-29 18:16:34 -07:00
										 |  |  |         return @prefix if defined?(@prefix) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         @prefix = T.let(@prefix, T.nilable(Pathname)) | 
					
						
							| 
									
										
										
										
											2014-05-02 16:48:59 -05:00
										 |  |  |         @prefix ||= | 
					
						
							|  |  |  |           begin | 
					
						
							|  |  |  |             dir = MacOS.active_developer_dir | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-09 21:30:20 +00:00
										 |  |  |             if dir.empty? || dir == CLT::PKG_PATH || !File.directory?(dir) | 
					
						
							| 
									
										
										
										
											2014-05-02 16:48:59 -05:00
										 |  |  |               path = bundle_path | 
					
						
							| 
									
										
										
										
											2017-01-09 21:30:20 +00:00
										 |  |  |               path/"Contents/Developer" if path | 
					
						
							| 
									
										
										
										
											2014-05-02 16:48:59 -05:00
										 |  |  |             else | 
					
						
							| 
									
										
										
										
											2016-03-15 23:40:59 -07:00
										 |  |  |               # Use cleanpath to avoid pathological trailing slash | 
					
						
							|  |  |  |               Pathname.new(dir).cleanpath | 
					
						
							| 
									
										
										
										
											2014-05-02 16:48:59 -05:00
										 |  |  |             end | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |           end | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |       sig { returns(Pathname) } | 
					
						
							| 
									
										
										
										
											2014-05-01 18:36:46 -05:00
										 |  |  |       def toolchain_path | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |         Pathname("#{prefix}/Toolchains/XcodeDefault.xctoolchain") | 
					
						
							| 
									
										
										
										
											2014-05-01 18:36:46 -05:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 15:12:53 -07:00
										 |  |  |       sig { returns(T.nilable(Pathname)) } | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       def bundle_path | 
					
						
							| 
									
										
										
										
											2017-01-09 21:30:32 +00:00
										 |  |  |         # Use the default location if it exists. | 
					
						
							|  |  |  |         return DEFAULT_BUNDLE_PATH if DEFAULT_BUNDLE_PATH.exist? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Ask Spotlight where Xcode is. If the user didn't install the | 
					
						
							|  |  |  |         # helper tools and installed Xcode in a non-conventional place, this | 
					
						
							|  |  |  |         # is our only option. See: https://superuser.com/questions/390757 | 
					
						
							|  |  |  |         MacOS.app_with_bundle_id(BUNDLE_ID, OLD_BUNDLE_ID) | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2013-07-21 16:41:51 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |       sig { returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       def installed? | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |         !prefix.nil? | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 15:12:53 -07:00
										 |  |  |       sig { returns(XcodeSDKLocator) } | 
					
						
							| 
									
										
										
										
											2020-07-01 16:02:29 +01:00
										 |  |  |       def sdk_locator | 
					
						
							|  |  |  |         @sdk_locator ||= XcodeSDKLocator.new | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2018-07-26 17:57:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 15:12:53 -07:00
										 |  |  |       sig { params(v: T.nilable(MacOS::Version)).returns(T.nilable(SDK)) } | 
					
						
							| 
									
										
										
										
											2020-07-01 16:02:29 +01:00
										 |  |  |       def sdk(v = nil) | 
					
						
							|  |  |  |         sdk_locator.sdk_if_applicable(v) | 
					
						
							| 
									
										
										
										
											2018-07-26 17:57:11 -07:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 15:12:53 -07:00
										 |  |  |       sig { params(v: T.nilable(MacOS::Version)).returns(T.nilable(Pathname)) } | 
					
						
							| 
									
										
										
										
											2018-07-26 17:57:11 -07:00
										 |  |  |       def sdk_path(v = nil) | 
					
						
							|  |  |  |         sdk(v)&.path | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 15:12:53 -07:00
										 |  |  |       sig { returns(String) } | 
					
						
							| 
									
										
										
										
											2021-02-07 04:21:59 +00:00
										 |  |  |       def installation_instructions | 
					
						
							| 
									
										
										
										
											2021-06-22 13:06:46 -04:00
										 |  |  |         if OS::Mac.version.prerelease? | 
					
						
							| 
									
										
										
										
											2021-02-07 04:21:59 +00:00
										 |  |  |           <<~EOS | 
					
						
							|  |  |  |             Xcode can be installed from: | 
					
						
							| 
									
										
										
										
											2021-10-04 22:22:20 +08:00
										 |  |  |               #{Formatter.url(APPLE_DEVELOPER_DOWNLOAD_URL)} | 
					
						
							| 
									
										
										
										
											2021-02-07 04:21:59 +00:00
										 |  |  |           EOS | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           <<~EOS | 
					
						
							|  |  |  |             Xcode can be installed from the App Store. | 
					
						
							|  |  |  |           EOS | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |       sig { returns(String) } | 
					
						
							| 
									
										
										
										
											2016-07-16 21:01:34 +01:00
										 |  |  |       def update_instructions | 
					
						
							| 
									
										
										
										
											2021-06-22 13:06:46 -04:00
										 |  |  |         if OS::Mac.version.prerelease? | 
					
						
							| 
									
										
										
										
											2017-10-15 02:28:32 +02:00
										 |  |  |           <<~EOS | 
					
						
							| 
									
										
										
										
											2019-01-26 17:13:14 +00:00
										 |  |  |             Xcode can be updated from: | 
					
						
							| 
									
										
										
										
											2021-10-04 22:22:20 +08:00
										 |  |  |               #{Formatter.url(APPLE_DEVELOPER_DOWNLOAD_URL)} | 
					
						
							| 
									
										
										
										
											2016-07-16 21:01:34 +01:00
										 |  |  |           EOS | 
					
						
							|  |  |  |         else | 
					
						
							| 
									
										
										
										
											2017-10-15 02:28:32 +02:00
										 |  |  |           <<~EOS | 
					
						
							| 
									
										
										
										
											2019-01-26 17:13:14 +00:00
										 |  |  |             Xcode can be updated from the App Store. | 
					
						
							| 
									
										
										
										
											2016-07-16 21:01:34 +01:00
										 |  |  |           EOS | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 15:12:53 -07:00
										 |  |  |       sig { returns(::Version) } | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       def version | 
					
						
							|  |  |  |         # may return a version string | 
					
						
							|  |  |  |         # that is guessed based on the compiler, so do not | 
					
						
							|  |  |  |         # use it in order to check if Xcode is installed. | 
					
						
							| 
									
										
										
										
											2017-11-05 12:09:04 +00:00
										 |  |  |         if @version ||= detect_version | 
					
						
							|  |  |  |           ::Version.new @version | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           ::Version::NULL | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 15:12:53 -07:00
										 |  |  |       sig { returns(T.nilable(String)) } | 
					
						
							| 
									
										
										
										
											2017-11-05 12:09:04 +00:00
										 |  |  |       def detect_version | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |         # This is a separate function as you can't cache the value out of a block | 
					
						
							|  |  |  |         # if return is used in the middle, which we do many times in here. | 
					
						
							| 
									
										
										
										
											2017-11-05 12:09:04 +00:00
										 |  |  |         return if !MacOS::Xcode.installed? && !MacOS::CLT.installed? | 
					
						
							| 
									
										
										
										
											2015-07-26 16:49:16 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 20:44:19 +02:00
										 |  |  |         %W[
 | 
					
						
							|  |  |  |           #{prefix}/usr/bin/xcodebuild | 
					
						
							|  |  |  |           #{which("xcodebuild")} | 
					
						
							|  |  |  |         ].uniq.each do |xcodebuild_path| | 
					
						
							| 
									
										
										
										
											2016-09-11 17:49:27 +01:00
										 |  |  |           next unless File.executable? xcodebuild_path | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-11 17:49:27 +01:00
										 |  |  |           xcodebuild_output = Utils.popen_read(xcodebuild_path, "-version") | 
					
						
							| 
									
										
										
										
											2017-06-10 20:12:55 +03:00
										 |  |  |           next unless $CHILD_STATUS.success? | 
					
						
							| 
									
										
										
										
											2016-05-04 20:44:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-05 19:44:11 -06:00
										 |  |  |           xcode_version = xcodebuild_output[/Xcode (\d+(\.\d+)*)/, 1] | 
					
						
							| 
									
										
										
										
											2016-09-11 17:49:27 +01:00
										 |  |  |           return xcode_version if xcode_version | 
					
						
							| 
									
										
										
										
											2014-04-17 08:23:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-11 17:49:27 +01:00
										 |  |  |           # Xcode 2.x's xcodebuild has a different version string | 
					
						
							|  |  |  |           case xcodebuild_output[/DevToolsCore-(\d+\.\d)/, 1] | 
					
						
							|  |  |  |           when "798.0" then return "2.5" | 
					
						
							| 
									
										
										
										
											2020-04-09 14:27:37 +01:00
										 |  |  |           when "515.0" then return "2.0" | 
					
						
							| 
									
										
										
										
											2014-04-15 14:18:45 -05:00
										 |  |  |           end | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-08 14:59:15 +00:00
										 |  |  |         detect_version_from_clang_version | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |       sig { returns(String) } | 
					
						
							| 
									
										
										
										
											2017-12-08 14:59:15 +00:00
										 |  |  |       def detect_version_from_clang_version | 
					
						
							| 
									
										
										
										
											2021-05-09 17:07:00 +01:00
										 |  |  |         version = DevelopmentTools.clang_version | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return "dunno" if version.null? | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-08 14:59:15 +00:00
										 |  |  |         # This logic provides a fake Xcode version based on the | 
					
						
							| 
									
										
										
										
											2017-04-22 16:28:07 +01:00
										 |  |  |         # installed CLT version. This is useful as they are packaged | 
					
						
							|  |  |  |         # simultaneously so workarounds need to apply to both based on their | 
					
						
							|  |  |  |         # comparable version. | 
					
						
							| 
									
										
										
										
											2021-05-09 17:07:00 +01:00
										 |  |  |         case version | 
					
						
							|  |  |  |         when "6.0.0"  then "6.2" | 
					
						
							|  |  |  |         when "6.1.0"  then "6.4" | 
					
						
							|  |  |  |         when "7.0.0"  then "7.1" | 
					
						
							|  |  |  |         when "7.0.2"  then "7.2.1" | 
					
						
							|  |  |  |         when "7.3.0"  then "7.3.1" | 
					
						
							|  |  |  |         when "8.0.0"  then "8.2.1" | 
					
						
							|  |  |  |         when "8.1.0"  then "8.3.3" | 
					
						
							|  |  |  |         when "9.0.0"  then "9.2" | 
					
						
							|  |  |  |         when "9.1.0"  then "9.4.1" | 
					
						
							|  |  |  |         when "10.0.0" then "10.1" | 
					
						
							|  |  |  |         when "10.0.1" then "10.3" | 
					
						
							|  |  |  |         when "11.0.0" then "11.3.1" | 
					
						
							|  |  |  |         when "11.0.3" then "11.7" | 
					
						
							|  |  |  |         when "12.0.0" then "12.4" | 
					
						
							| 
									
										
										
										
											2021-09-26 16:57:43 +01:00
										 |  |  |         when "12.0.5" then "12.5.1" | 
					
						
							| 
									
										
										
										
											2022-03-23 23:35:06 +00:00
										 |  |  |         when "13.0.0" then "13.2.1" | 
					
						
							| 
									
										
										
										
											2022-06-06 19:13:42 +01:00
										 |  |  |         when "14.0.0" then "14.0" | 
					
						
							| 
									
										
										
										
											2022-05-26 18:11:29 +01:00
										 |  |  |         else               "13.4" | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2012-08-06 13:46:02 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 15:12:53 -07:00
										 |  |  |       sig { returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       def default_prefix? | 
					
						
							| 
									
										
										
										
											2019-01-26 17:13:14 +00:00
										 |  |  |         prefix.to_s == "/Applications/Xcode.app/Contents/Developer" | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-07-09 15:19:30 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-25 00:40:10 +02:00
										 |  |  |     # Helper module for querying macOS Command Line Tools information. | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # @api private | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |     module CLT | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |       extend T::Sig | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-07 00:31:28 +02:00
										 |  |  |       module_function | 
					
						
							| 
									
										
										
										
											2012-07-10 21:01:16 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-06 15:15:23 -07:00
										 |  |  |       # The original Mavericks CLT package ID | 
					
						
							| 
									
										
										
										
											2019-04-19 15:38:03 +09:00
										 |  |  |       EXECUTABLE_PKG_ID = "com.apple.pkg.CLTools_Executables" | 
					
						
							|  |  |  |       MAVERICKS_NEW_PKG_ID = "com.apple.pkg.CLTools_Base" # obsolete | 
					
						
							|  |  |  |       PKG_PATH = "/Library/Developer/CommandLineTools" | 
					
						
							| 
									
										
										
										
											2012-09-14 13:24:28 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |       # Returns true even if outdated tools are installed. | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |       sig { returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       def installed? | 
					
						
							| 
									
										
										
										
											2017-11-05 12:09:04 +00:00
										 |  |  |         !version.null? | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2013-07-21 16:41:50 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 15:12:53 -07:00
										 |  |  |       sig { returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2018-06-12 14:30:27 -07:00
										 |  |  |       def separate_header_package? | 
					
						
							| 
									
										
										
										
											2020-03-08 20:11:49 +00:00
										 |  |  |         version >= "10" && MacOS.version >= "10.14" | 
					
						
							| 
									
										
										
										
											2018-06-12 14:30:27 -07:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 15:12:53 -07:00
										 |  |  |       sig { returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2018-07-26 17:56:47 -07:00
										 |  |  |       def provides_sdk? | 
					
						
							|  |  |  |         version >= "8" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 15:12:53 -07:00
										 |  |  |       sig { returns(CLTSDKLocator) } | 
					
						
							| 
									
										
										
										
											2020-07-01 16:02:29 +01:00
										 |  |  |       def sdk_locator | 
					
						
							|  |  |  |         @sdk_locator ||= CLTSDKLocator.new | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2018-07-26 17:57:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 15:12:53 -07:00
										 |  |  |       sig { params(v: T.nilable(MacOS::Version)).returns(T.nilable(SDK)) } | 
					
						
							| 
									
										
										
										
											2020-07-01 16:02:29 +01:00
										 |  |  |       def sdk(v = nil) | 
					
						
							|  |  |  |         sdk_locator.sdk_if_applicable(v) | 
					
						
							| 
									
										
										
										
											2018-07-26 17:57:11 -07:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 15:12:53 -07:00
										 |  |  |       sig { params(v: T.nilable(MacOS::Version)).returns(T.nilable(Pathname)) } | 
					
						
							| 
									
										
										
										
											2018-07-26 17:57:11 -07:00
										 |  |  |       def sdk_path(v = nil) | 
					
						
							|  |  |  |         sdk(v)&.path | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 15:12:53 -07:00
										 |  |  |       sig { returns(String) } | 
					
						
							| 
									
										
										
										
											2021-02-07 04:21:59 +00:00
										 |  |  |       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: | 
					
						
							| 
									
										
										
										
											2021-10-04 22:22:20 +08:00
										 |  |  |               #{Formatter.url(MacOS::Xcode::APPLE_DEVELOPER_DOWNLOAD_URL)} | 
					
						
							| 
									
										
										
										
											2021-02-07 04:21:59 +00:00
										 |  |  |           EOS | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           <<~EOS | 
					
						
							|  |  |  |             Install the Command Line Tools: | 
					
						
							|  |  |  |               xcode-select --install | 
					
						
							|  |  |  |           EOS | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |       sig { returns(String) } | 
					
						
							| 
									
										
										
										
											2016-07-16 21:01:34 +01:00
										 |  |  |       def update_instructions | 
					
						
							| 
									
										
										
										
											2020-04-09 14:27:37 +01:00
										 |  |  |         software_update_location = if MacOS.version >= "10.14" | 
					
						
							|  |  |  |           "System Preferences" | 
					
						
							| 
									
										
										
										
											2019-01-26 17:13:14 +00:00
										 |  |  |         else | 
					
						
							| 
									
										
										
										
											2020-04-09 14:27:37 +01:00
										 |  |  |           "the App Store" | 
					
						
							| 
									
										
										
										
											2016-07-16 21:01:34 +01:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2020-04-09 14:27:37 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         <<~EOS | 
					
						
							|  |  |  |           Update them from Software Update in #{software_update_location} or run: | 
					
						
							|  |  |  |             softwareupdate --all --install --force | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 15:21:24 -05:00
										 |  |  |           If that doesn't show you any updates, run: | 
					
						
							| 
									
										
										
										
											2020-04-09 14:27:37 +01:00
										 |  |  |             sudo rm -rf /Library/Developer/CommandLineTools | 
					
						
							|  |  |  |             sudo xcode-select --install | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           Alternatively, manually download them from: | 
					
						
							| 
									
										
										
										
											2021-10-04 22:22:20 +08:00
										 |  |  |             #{Formatter.url(MacOS::Xcode::APPLE_DEVELOPER_DOWNLOAD_URL)}. | 
					
						
							| 
									
										
										
										
											2021-05-18 16:19:31 +02:00
										 |  |  |           You should download the Command Line Tools for Xcode #{MacOS::Xcode.latest_version}. | 
					
						
							| 
									
										
										
										
											2020-04-09 14:27:37 +01:00
										 |  |  |         EOS | 
					
						
							| 
									
										
										
										
											2016-07-16 21:01:34 +01:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-09 14:27:37 +01:00
										 |  |  |       # Bump these when the new version is distributed through Software Update | 
					
						
							|  |  |  |       # and our CI systems have been updated. | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |       sig { returns(String) } | 
					
						
							| 
									
										
										
										
											2019-12-11 13:50:21 +00:00
										 |  |  |       def latest_clang_version | 
					
						
							| 
									
										
										
										
											2014-09-18 10:09:14 -05:00
										 |  |  |         case MacOS.version | 
					
						
							| 
									
										
										
										
											2022-06-06 19:13:42 +01:00
										 |  |  |         when "13"    then "1400.0.17.3.1" | 
					
						
							| 
									
										
										
										
											2022-05-26 18:11:29 +01:00
										 |  |  |         when "12"    then "1316.0.21.2.5" | 
					
						
							| 
									
										
										
										
											2022-03-24 15:09:30 +00:00
										 |  |  |         when "11"    then "1300.0.29.30" | 
					
						
							|  |  |  |         when "10.15" then "1200.0.32.29" | 
					
						
							|  |  |  |         when "10.14" then "1100.0.33.17" | 
					
						
							|  |  |  |         when "10.13" then "1000.10.44.2" | 
					
						
							|  |  |  |         when "10.12" then "900.0.39.2" | 
					
						
							| 
									
										
										
										
											2022-05-30 14:59:14 +01:00
										 |  |  |         else              "800.0.42.1" | 
					
						
							| 
									
										
										
										
											2013-11-01 16:16:01 -05:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2012-08-17 17:18:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-09 14:27:37 +01:00
										 |  |  |       # Bump these if things are badly broken (e.g. no SDK for this macOS) | 
					
						
							|  |  |  |       # without this. Generally this will be the first stable CLT release on | 
					
						
							|  |  |  |       # that macOS version. | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |       sig { returns(String) } | 
					
						
							| 
									
										
										
										
											2016-11-05 10:35:39 -04:00
										 |  |  |       def minimum_version | 
					
						
							|  |  |  |         case MacOS.version | 
					
						
							| 
									
										
										
										
											2022-06-06 19:13:42 +01:00
										 |  |  |         when "13" then "14.0.0" | 
					
						
							| 
									
										
										
										
											2021-06-08 19:28:20 +02:00
										 |  |  |         when "12" then "13.0.0" | 
					
						
							| 
									
										
										
										
											2021-03-03 04:01:27 +00:00
										 |  |  |         when "11" then "12.5.0" | 
					
						
							| 
									
										
										
										
											2019-06-04 16:11:18 -07:00
										 |  |  |         when "10.15" then "11.0.0" | 
					
						
							| 
									
										
										
										
											2018-08-14 00:02:19 +01:00
										 |  |  |         when "10.14" then "10.0.0" | 
					
						
							| 
									
										
										
										
											2017-06-22 18:18:52 +01:00
										 |  |  |         when "10.13" then "9.0.0" | 
					
						
							| 
									
										
										
										
											2016-11-05 10:35:39 -04:00
										 |  |  |         when "10.12" then "8.0.0" | 
					
						
							| 
									
										
										
										
											2017-12-08 14:59:15 +00:00
										 |  |  |         else              "1.0.0" | 
					
						
							| 
									
										
										
										
											2016-11-05 10:35:39 -04:00
										 |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 15:12:53 -07:00
										 |  |  |       sig { returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2016-12-18 15:31:15 -08:00
										 |  |  |       def below_minimum_version? | 
					
						
							| 
									
										
										
										
											2017-11-05 12:09:04 +00:00
										 |  |  |         return false unless installed? | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-05 10:35:39 -04:00
										 |  |  |         version < minimum_version | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |       sig { returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       def outdated? | 
					
						
							| 
									
										
										
										
											2017-11-05 12:09:04 +00:00
										 |  |  |         clang_version = detect_clang_version | 
					
						
							|  |  |  |         return false unless clang_version | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-11 13:50:21 +00:00
										 |  |  |         ::Version.new(clang_version) < latest_clang_version | 
					
						
							| 
									
										
										
										
											2017-11-05 12:09:04 +00:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 15:12:53 -07:00
										 |  |  |       sig { returns(T.nilable(String)) } | 
					
						
							| 
									
										
										
										
											2017-11-05 12:09:04 +00:00
										 |  |  |       def detect_clang_version | 
					
						
							| 
									
										
										
										
											2021-03-17 15:34:20 +00:00
										 |  |  |         version_output = Utils.popen_read("#{PKG_PATH}/usr/bin/clang", "--version") | 
					
						
							| 
									
										
										
										
											2022-05-27 11:18:11 +02:00
										 |  |  |         version_output[/clang-(\d+(\.\d+)+)/, 1] | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2013-05-22 22:26:09 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 15:12:53 -07:00
										 |  |  |       sig { returns(T.nilable(String)) } | 
					
						
							| 
									
										
										
										
											2019-12-11 13:49:56 +00:00
										 |  |  |       def detect_version_from_clang_version | 
					
						
							| 
									
										
										
										
											2021-03-26 10:29:27 +00:00
										 |  |  |         detect_clang_version&.sub(/^(\d+)0(\d)\./, "\\1.\\2.") | 
					
						
							| 
									
										
										
										
											2019-12-11 13:49:56 +00:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-22 10:14:20 +00:00
										 |  |  |       # Version string (a pretty long one) of the CLT package. | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |       # Note that the different ways of installing the CLTs lead to different | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       # version numbers. | 
					
						
							| 
									
										
										
										
											2021-09-29 15:12:53 -07:00
										 |  |  |       sig { returns(::Version) } | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       def version | 
					
						
							| 
									
										
										
										
											2017-11-05 12:09:04 +00:00
										 |  |  |         if @version ||= detect_version | 
					
						
							|  |  |  |           ::Version.new @version | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           ::Version::NULL | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2013-07-21 20:09:55 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 15:12:53 -07:00
										 |  |  |       sig { returns(T.nilable(String)) } | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       def detect_version | 
					
						
							| 
									
										
										
										
											2021-09-29 15:12:53 -07:00
										 |  |  |         version = T.let(nil, T.nilable(String)) | 
					
						
							| 
									
										
										
										
											2019-01-26 17:13:14 +00:00
										 |  |  |         [EXECUTABLE_PKG_ID, MAVERICKS_NEW_PKG_ID].each do |id| | 
					
						
							|  |  |  |           next unless File.exist?("#{PKG_PATH}/usr/bin/clang") | 
					
						
							| 
									
										
										
										
											2019-02-19 13:12:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |           version = MacOS.pkgutil_info(id)[/version: (.+)$/, 1] | 
					
						
							| 
									
										
										
										
											2019-10-16 16:26:57 +01:00
										 |  |  |           return version if version | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2019-10-16 16:26:57 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-11 13:49:56 +00:00
										 |  |  |         detect_version_from_clang_version | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2013-07-21 20:09:55 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  |   end | 
					
						
							|  |  |  | end |