Module: OS::Mac::CLT Private

Extended by:
Utils::Output::Mixin
Defined in:
os/mac/xcode.rb

Overview

This module is part of a private API. This module may only be used in the Homebrew/brew repository. Third parties should avoid using this module if possible, as it may be removed or changed without warning.

Helper module for querying macOS Command Line Tools information.

Constant Summary collapse

EXECUTABLE_PKG_ID =

This constant is part of a private API. This constant may only be used in the Homebrew/brew repository. Third parties should avoid using this constant if possible, as it may be removed or changed without warning.

"com.apple.pkg.CLTools_Executables"
PKG_PATH =

This constant is part of a private API. This constant may only be used in the Homebrew/brew repository. Third parties should avoid using this constant if possible, as it may be removed or changed without warning.

"/Library/Developer/CommandLineTools"

Class Method Summary collapse

Methods included from Utils::Output::Mixin

issue_reporting_message, odebug, odeprecated, odie, odisabled, ofail, oh1, oh1_title, ohai, ohai_title, onoe, opoo, opoo_once, opoo_outside_github_actions, opoo_without_github_actions_annotation, pretty_cannot_install, pretty_deprecated, pretty_disabled, pretty_duration, pretty_install_status, pretty_installed, pretty_uninstalled, pretty_unmarked, pretty_upgradable, pretty_warning

Class Method Details

.below_minimum_version? ⇒ Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:

  • (Boolean)


341
342
343
344
345
# File 'os/mac/xcode.rb', line 341

def self.below_minimum_version?
  return false if version.null?

  version < minimum_version
end

.detect_clang_version ⇒ String?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



357
358
359
360
# File 'os/mac/xcode.rb', line 357

def self.detect_clang_version
  version_output = Utils.popen_read("#{PKG_PATH}/usr/bin/clang", "--version")
  version_output[/clang-(\d+(?:\.\d+)+)/, 1]
end

.detect_version ⇒ String?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



378
379
380
381
382
# File 'os/mac/xcode.rb', line 378

def self.detect_version
  return unless installed?

  MacOS.pkgutil_info(EXECUTABLE_PKG_ID)[/version: (.+)$/, 1]
end

.installation_instructions ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'os/mac/xcode.rb', line 246

def self.installation_instructions
  if OS::Mac.version.prerelease?
    <<~EOS
      Install the Command Line Tools for Xcode #{minimum_version.split(".").first} from:
        #{Formatter.url(MacOS::Xcode::APPLE_DEVELOPER_DOWNLOAD_URL)}
    EOS
  else
    <<~EOS
      Install the Command Line Tools:
        xcode-select --install
    EOS
  end
end

.installation_then_reinstall_instructions ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



289
290
291
292
293
294
# File 'os/mac/xcode.rb', line 289

def self.installation_then_reinstall_instructions
  <<~EOS
    #{installation_instructions}
    #{reinstall_instructions}
  EOS
end

.installed? ⇒ Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns true even if outdated tools are installed.

Returns:

  • (Boolean)


226
227
228
# File 'os/mac/xcode.rb', line 226

def self.installed?
  File.exist?("#{PKG_PATH}/usr/bin/clang")
end

.latest_clang_version ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



311
312
313
314
315
316
317
318
319
320
321
# File 'os/mac/xcode.rb', line 311

def self.latest_clang_version
  case MacOS.version
  when "27" then "2100.3.34.2"
  when "26" then ::Hardware::CPU.physical_cpu_arm64? ? "2100.3.34.2" : "2100.1.1.101"
  when "15" then "1700.6.4.2"
  when "14" then "1600.0.26.6"
  when "13" then "1500.1.0.2.5"
  when "12" then "1400.0.29.202"
  else           "1300.0.29.30"
  end
end

.latest_version ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Bump these when the new version is distributed through Software Update and our CI systems have been updated.

CLT releases can differ from Xcode, so override mismatches and share Xcode's latest version otherwise.

Returns:



302
303
304
305
306
307
308
# File 'os/mac/xcode.rb', line 302

def self.latest_version
  case MacOS.version
  when "13" then "15.1"
  when "11" then "13.2"
  else           MacOS::Xcode.latest_version
  end
end

.minimum_version ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

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.

Returns:



327
328
329
330
331
332
333
334
335
336
337
338
# File 'os/mac/xcode.rb', line 327

def self.minimum_version
  macos = MacOS.version
  case macos
  when "15" then "16.0.0"
  when "14" then "15.0.0"
  when "13" then "14.0.0"
  when "12" then "13.0.0"
  when "11" then "12.5.0"
  else
    "#{macos}.0.0"
  end
end

.outdated? ⇒ Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:

  • (Boolean)


348
349
350
351
352
353
354
# File 'os/mac/xcode.rb', line 348

def self.outdated?
  clang_version = detect_clang_version
  return false unless clang_version
  return false if !version.null? && version.major_minor_patch > latest_version

  ::Version.new(clang_version) < latest_clang_version
end

.reinstall_instructions(reason: "resolve your issues") ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

  • reason (String) (defaults to: "resolve your issues")

Returns:



261
262
263
264
265
266
267
268
269
270
271
# File 'os/mac/xcode.rb', line 261

def self.reinstall_instructions(reason: "resolve your issues")
  <<~EOS
    If that doesn't #{reason}, run:
      sudo rm -rf /Library/Developer/CommandLineTools
      sudo xcode-select --install

    Alternatively, manually download them from:
      #{Formatter.url(MacOS::Xcode::APPLE_DEVELOPER_DOWNLOAD_URL)}.
    You should download the Command Line Tools for Xcode #{latest_version}.
  EOS
end

.sdk(version = nil) ⇒ SDK?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



236
237
238
# File 'os/mac/xcode.rb', line 236

def self.sdk(version = nil)
  sdk_locator.sdk_if_applicable(version)
end

.sdk_locator ⇒ CLTSDKLocator

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



231
232
233
# File 'os/mac/xcode.rb', line 231

def self.sdk_locator
  @sdk_locator ||= T.let(CLTSDKLocator.new, T.nilable(OS::Mac::CLTSDKLocator))
end

.sdk_path(version = nil) ⇒ ::Pathname?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



241
242
243
# File 'os/mac/xcode.rb', line 241

def self.sdk_path(version = nil)
  sdk(version)&.path
end

.update_instructions ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'os/mac/xcode.rb', line 274

def self.update_instructions
  software_update_location = if MacOS.version >= "13"
    "System Settings"
  else
    "System Preferences"
  end

  <<~EOS
    Update them from Software Update in #{software_update_location}.

    #{reinstall_instructions(reason: "show you any updates")}
  EOS
end

.version ⇒ ::Version

This method is part of an internal API. This method may only be used internally in repositories owned by Homebrew, except in casks or formulae. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Version string (a pretty long one) of the CLT package. Note that the different ways of installing the CLTs lead to different version numbers. Installations without a package receipt have an unknown version (Version::NULL).

Returns:



369
370
371
372
373
374
375
# File 'os/mac/xcode.rb', line 369

def self.version
  if @version ||= T.let(detect_version, T.nilable(String))
    ::Version.new @version
  else
    ::Version::NULL
  end
end