Skip to content
Snippets Groups Projects
env_config.rb 17.1 KiB
Newer Older
# frozen_string_literal: true

module Homebrew
Markus Reiter's avatar
Markus Reiter committed
  # Helper module for querying Homebrew-specific environment variables.
  #
  # @api private
  module EnvConfig
    module_function

    ENVS = {
      HOMEBREW_ARCH:                         {
        description: "Linux only: Pass the set value to a type name representing the compiler's `-march` option.",
        default:     "native",
      },
      HOMEBREW_ARTIFACT_DOMAIN:              {
        description: "Prefix all download URLs, including those for bottles, with this " \
                     "variable. For example, `HOMEBREW_ARTIFACT_DOMAIN=http://localhost:8080` will cause a " \
                     "formula with the URL `https://example.com/foo.tar.gz` to instead download from " \
                     "`http://localhost:8080/example.com/foo.tar.gz`.",
      },
      HOMEBREW_AUTO_UPDATE_SECS:             {
        description: "Automatically check for updates once per this seconds interval.",
        default:     300,
      },
      HOMEBREW_BAT:                          {
        description: "If set, use `bat` for the `brew cat` command.",
        boolean:     true,
      },
      HOMEBREW_BAT_CONFIG_PATH:              {
        description:  "Use the `bat` configuration file. For example, `HOMEBREW_BAT=$HOME/.bat/config`.",
        default_text: "$HOME/.bat/config",
      },
      HOMEBREW_BINTRAY_KEY:                  {
        description: "Use this API key when accessing the Bintray API (where bottles are stored).",
      HOMEBREW_BINTRAY_USER:                 {
        description: "Use this username when accessing the Bintray API (where bottles are stored).",
      HOMEBREW_BOTTLE_DOMAIN:                {
        description:  "Use the specified URL as the download mirror for bottles. " \
        "For example, `HOMEBREW_BOTTLE_DOMAIN=http://localhost:8080` will cause all bottles to " \
        "download from the prefix `http://localhost:8080/`.",
        default_text: "macOS: `https://homebrew.bintray.com/`, Linux: `https://linuxbrew.bintray.com/`.",
        default:      HOMEBREW_BOTTLE_DEFAULT_DOMAIN,
      },
      HOMEBREW_BREW_GIT_REMOTE:              {
        description: "Use the specified URL as the Homebrew/brew `git`(1) remote.",
        default:     HOMEBREW_BREW_DEFAULT_GIT_REMOTE,
      },
      HOMEBREW_BROWSER:                      {
        description:  "Use this as the browser when opening project homepages.",
        default_text: "`$BROWSER` or the OS's default browser.",
      },
      HOMEBREW_CACHE:                        {
        description:  "Use the specified directory as the download cache.",
        default_text: "macOS: `$HOME/Library/Caches/Homebrew`, " \
                      "Linux: `$XDG_CACHE_HOME/Homebrew` or `$HOME/.cache/Homebrew`.",
        default:      HOMEBREW_DEFAULT_CACHE,
      },
      HOMEBREW_CASK_OPTS:                    {
        description: "Options which should be used for all `cask` commands. All `--*dir` options, " \
                     "`--language`, `--require-sha`, `--no-quarantine` and `--no-binaries` are supported." \
                     "\n" \
                     "For example, you might add something like the following to your " \
                     "~/.profile, ~/.bash_profile, or ~/.zshenv:\n\n" \
                     "`export HOMEBREW_CASK_OPTS='--appdir=~/Applications --fontdir=/Library/Fonts'`",
      HOMEBREW_CLEANUP_MAX_AGE_DAYS:         {
        description: "Cleanup all cached files older than this many days.",
        default:     120,
      },
      HOMEBREW_COLOR:                        {
        description: "If set, force colour output on non-TTY outputs.",
        boolean:     true,
      },
      HOMEBREW_CORE_GIT_REMOTE:              {
        description:  "Use the specified URL as the Homebrew/homebrew-core `git`(1) remote.",
        default_text: "macOS: `https://github.com/Homebrew/homebrew-core`, " \
                      "Linux: `https://github.com/Homebrew/linuxbrew-core`.",
        default:      HOMEBREW_CORE_DEFAULT_GIT_REMOTE,
      },
      HOMEBREW_CURLRC:                       {
        description: "If set, do not pass `--disable` when invoking `curl`(1), which disables the " \
                     "use of `curlrc`.",
        boolean:     true,
      },
      HOMEBREW_CURL_RETRIES:                 {
        description: "Pass the given retry count to `--retry` when invoking `curl`(1).",
      HOMEBREW_CURL_VERBOSE:                 {
        description: "If set, pass `--verbose` when invoking `curl`(1).",
        boolean:     true,
      },
      HOMEBREW_DEVELOPER:                    {
        description: "If set, tweak behaviour to be more relevant for Homebrew developers (active or " \
                     "budding) by e.g. turning warnings into errors.",
        boolean:     true,
      },
      HOMEBREW_DISABLE_LOAD_FORMULA:         {
        description: "If set, refuse to load formulae. This is useful when formulae are not trusted (such " \
                     "as in pull requests).",
        boolean:     true,
      },
      HOMEBREW_DISPLAY:                      {
        description:  "Use this X11 display when opening a page in a browser, for example with " \
                     "`brew home`. Primarily useful on Linux.",
        default_text: "`$DISPLAY`.",
      },
      HOMEBREW_DISPLAY_INSTALL_TIMES:        {
        description: "If set, print install times for each formula at the end of the run.",
      HOMEBREW_EDITOR:                       {
        description:  "Use this editor when editing a single formula, or several formulae in the " \
                     "same directory.\n\n    *Note:* `brew edit` will open all of Homebrew as discontinuous files " \
                     "and directories. Visual Studio Code can handle this correctly in project mode, but many " \
                     "editors will do strange things in this case.",
        default_text: "`$EDITOR` or `$VISUAL`.",
      },
      HOMEBREW_FAIL_LOG_LINES:               {
        description: "Output this many lines of output on formula `system` failures.",
      HOMEBREW_FORBIDDEN_LICENSES:           {
        description: "A space-separated list of licenses. Homebrew will refuse to install a " \
        "formula if that formula or any of its dependencies has a license on this list.",
      HOMEBREW_FORCE_BREWED_CURL:            {
        description: "If set, always use a Homebrew-installed `curl`(1) rather than the system version. " \
                     "Automatically set if the system version of `curl` is too old.",
      HOMEBREW_FORCE_BREWED_GIT:             {
        description: "If set, always use a Homebrew-installed `git`(1) rather than the system version. " \
                     "Automatically set if the system version of `git` is too old.",
      HOMEBREW_FORCE_HOMEBREW_ON_LINUX:      {
        description: "If set, running Homebrew on Linux will use URLs for macOS. This is useful when merging " \
                     "pull requests for macOS while on Linux.",
      HOMEBREW_FORCE_VENDOR_RUBY:            {
        description: "If set, always use Homebrew's vendored, relocatable Ruby version even if the system version " \
                     "of Ruby is new enough.",
        boolean:     true,
      },
      HOMEBREW_GITHUB_API_PASSWORD:          {
        description: "Use this password for authentication with the GitHub API, for features " \
                     "such as `brew search`. We strongly recommend using `HOMEBREW_GITHUB_API_TOKEN` instead.",
      },
      HOMEBREW_GITHUB_API_TOKEN:             {
        description: "Use this personal access token for the GitHub API, for features such as " \
                     "`brew search`. You can create one at <https://github.com/settings/tokens>. If set, " \
                     "GitHub will allow you a greater number of API requests. For more information, see: " \
                     "<https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting>.\n\n" \
                     "    *Note:* Homebrew doesn't require permissions for any of the scopes, but some developer " \
                     "commands may require additional permissions.",
      HOMEBREW_GITHUB_API_USERNAME:          {
        description: "Use this username for authentication with the GitHub API, for features " \
                     "such as `brew search`. We strongly recommend using `HOMEBREW_GITHUB_API_TOKEN` instead.",
      },
      HOMEBREW_GIT_EMAIL:                    {
        description: "Set the Git author and committer name to this value.",
      HOMEBREW_GIT_NAME:                     {
        description: "Set the Git author and committer email to this value.",
      HOMEBREW_INSTALL_BADGE:                {
        description:  "Print this text before the installation summary of each successful build.",
        default_text: 'The "Beer Mug" emoji.',
        default:      "🍺",
      },
      HOMEBREW_LIVECHECK_WATCHLIST:          {
        description: "Use this file to get the list of default Formulae to check when no Formula argument " \
                     "is passed to `brew livecheck`",
        default:     "$HOME/.brew_livecheck_watchlist",
      },
      HOMEBREW_LOGS:                         {
        description:  "Use the specified directory to store log files.",
        default_text: "macOS: `$HOME/Library/Logs/Homebrew`, "\
                      "Linux: `$XDG_CACHE_HOME/Homebrew/Logs` or `$HOME/.cache/Homebrew/Logs`.",
        default:      HOMEBREW_DEFAULT_LOGS,
      },
      HOMEBREW_MAKE_JOBS:                    {
        description:  "Use this value as the number of parallel jobs to run when building with `make`(1).",
        default_text: "The number of available CPU cores.",
        default:      lambda {
          require "os"
          require "hardware"
          Hardware::CPU.cores
        },
      },
      HOMEBREW_NO_ANALYTICS:                 {
        description: "If set, do not send analytics. See: <https://docs.brew.sh/Analytics>.",
      HOMEBREW_NO_AUTO_UPDATE:               {
        description: "If set, do not automatically update before running " \
                     "`brew install`, `brew upgrade` or `brew tap`.",
      HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK:    {
        description: "If set, fail on the failure of installation from a bottle rather than " \
                     "falling back to building from source.",
        boolean:     true,
      },
      HOMEBREW_NO_COLOR:                     {
        description:  "If set, do not print text with colour added.",
        default_text: "`$NO_COLOR`.",
        boolean:      true,
      },
      HOMEBREW_NO_COMPAT:                    {
        description: "If set, disable all use of legacy compatibility code.",
      HOMEBREW_NO_EMOJI:                     {
        description: "If set, do not print `HOMEBREW_INSTALL_BADGE` on a successful build." \
                     "\n\n    *Note:* Only tries to print emoji on OS X Lion or newer.",
      HOMEBREW_NO_GITHUB_API:                {
        description: "If set, do not use the GitHub API, e.g. for searches or fetching relevant issues " \
                     "on a failed install.",
        boolean:     true,
      },
      HOMEBREW_NO_INSECURE_REDIRECT:         {
        description: "If set, forbid redirects from secure HTTPS to insecure HTTP." \
                     "\n\n    *Note:* While ensuring your downloads are fully secure, this is likely to cause " \
                     "from-source SourceForge, some GNU & GNOME based formulae to fail to download.",
        boolean:     true,
      },
      HOMEBREW_NO_INSTALL_CLEANUP:           {
        description: "If set, `brew install`, `brew upgrade` and `brew reinstall` will never automatically " \
                     "cleanup installed/upgraded/reinstalled formulae or all formulae every 30 days.",
      HOMEBREW_PRY:                          {
        description: "If set, use Pry for the `brew irb` command.",
      HOMEBREW_SKIP_OR_LATER_BOTTLES:        {
        description: "If set with `HOMEBREW_DEVELOPER`, do not use bottles from older versions " \
                     "of macOS. This is useful in development on new macOS versions.",
      HOMEBREW_SVN:                          {
        description:  "Use this as the `svn`(1) binary.",
        default_text: "A Homebrew-built Subversion (if installed), or the system-provided binary.",
      HOMEBREW_TEMP:                         {
        description:  "Use this path as the temporary directory for building packages. Changing " \
                      "this may be needed if your system temporary directory and Homebrew prefix are on " \
                      "different volumes, as macOS has trouble moving symlinks across volumes when the target " \
                      "does not yet exist. This issue typically occurs when using FileVault or custom SSD " \
                      "configurations.",
        default_text: "macOS: `/private/tmp`, Linux: `/tmp`.",
        default:      HOMEBREW_DEFAULT_TEMP,
      },
      HOMEBREW_UPDATE_REPORT_ONLY_INSTALLED: {
        description: "If set, `brew update` only outputs updates to installed software.",
        boolean:     true,
      },
      HOMEBREW_UPDATE_TO_TAG:                {
        description: "If set, always use the latest stable tag (even if developer commands " \
                     "have been run).",
        boolean:     true,
      },
      HOMEBREW_VERBOSE:                      {
        description: "If set, always assume `--verbose` when running commands.",
      HOMEBREW_DEBUG:                        {
        description: "If set, always assume `--debug` when running commands.",
        boolean:     true,
      },
      HOMEBREW_VERBOSE_USING_DOTS:           {
        description: "If set, verbose output will print a `.` no more than once a minute. This can be " \
                     "useful to avoid long-running Homebrew commands being killed due to no output.",
        description: "Use this SOCKS5 proxy for `curl`(1), `git`(1) and `svn`(1) when downloading through Homebrew.",
        description: "Use this FTP proxy for `curl`(1), `git`(1) and `svn`(1) when downloading through Homebrew.",
        description: "Use this HTTP proxy for `curl`(1), `git`(1) and `svn`(1) when downloading through Homebrew.",
      https_proxy:                           {
        description: "Use this HTTPS proxy for `curl`(1), `git`(1) and `svn`(1) when downloading through Homebrew.",
        description: "A comma-separated list of hostnames and domain names excluded " \
                     "from proxying by `curl`(1), `git`(1) and `svn`(1) when downloading through Homebrew.",
      },
      SUDO_ASKPASS:                          {
        description: "When this variable is set, the `-A` option is passed when calling `sudo`(8)",
      },
    }.freeze

    def env_method_name(env, hash)
      method_name = env.to_s
                       .sub(/^HOMEBREW_/, "")
                       .downcase
      method_name = "#{method_name}?" if hash[:boolean]
      method_name
    end

Mike McQuaid's avatar
Mike McQuaid committed
    CUSTOM_IMPLEMENTATIONS = %w[
      HOMEBREW_MAKE_JOBS
      HOMEBREW_CASK_OPTS
    ].freeze

    ENVS.each do |env, hash|
      method_name = env_method_name(env, hash)
      env = env.to_s

      if hash[:boolean]
        define_method(method_name) do
          ENV[env].present?
        end
      elsif hash[:default].present?
        # Needs a custom implementation.
Mike McQuaid's avatar
Mike McQuaid committed
        next if CUSTOM_IMPLEMENTATIONS.include?(env)

        define_method(method_name) do
          ENV[env].presence || hash.fetch(:default).to_s
        end
      else
        define_method(method_name) do
          ENV[env].presence
        end
      end
    end

    # Needs a custom implementation.
    def make_jobs
      jobs = ENV["HOMEBREW_MAKE_JOBS"].to_i
      return jobs.to_s if jobs.positive?

      ENVS.fetch(:HOMEBREW_MAKE_JOBS)
          .fetch(:default)
          .call
          .to_s
    end

    def cask_opts
      Shellwords.shellsplit(ENV.fetch("HOMEBREW_CASK_OPTS", ""))
    end

    def cask_opts_binaries?
      cask_opts.reverse_each do |opt|
        return true if opt == "--binaries"
        return false if opt == "--no-binaries"
      end

      true
    end

    def cask_opts_quarantine?
      cask_opts.reverse_each do |opt|
        return true if opt == "--quarantine"
        return false if opt == "--no-quarantine"
      end

      true
    end

    def cask_opts_require_sha?
      cask_opts.include?("--require-sha")
    end