Module: Utils::Shell Private

Extended by:
T::Helpers
Included in:
Formula
Defined in:
utils/shell.rb

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.

Constant Summary collapse

SHELL_PROFILE_MAP =

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.

T.let(
  {
    bash: "~/.profile",
    csh:  "~/.cshrc",
    fish: "~/.config/fish/config.fish",
    ksh:  "~/.kshrc",
    mksh: "~/.kshrc",
    pwsh: "~/.config/powershell/Microsoft.PowerShell_profile.ps1",
    rc:   "~/.rcrc",
    sh:   "~/.profile",
    tcsh: "~/.tcshrc",
    zsh:  "~/.zshrc",
  }.freeze,
  T::Hash[Symbol, String],
)
UNSAFE_SHELL_CHAR =

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.

%r{([^A-Za-z0-9_\-.,:/@~+\n])}

Class Method Summary collapse

Class Method Details

.csh_quote(str) ⇒ 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:

Returns:



130
131
132
133
134
135
136
137
138
139
140
141
# File 'utils/shell.rb', line 130

def csh_quote(str)
  # Ruby's implementation of `shell_escape`.
  str = str.to_s
  return "''" if str.empty?

  str = str.dup
  # Anything that isn't a known safe character is padded.
  str.gsub!(UNSAFE_SHELL_CHAR, "\\\\" + "\\1") # rubocop:disable Style/StringConcatenation
  # Newlines have to be specially quoted in `csh`.
  str.gsub!("\n", "'\\\n'")
  str
end

.export_value(key, value, shell = preferred) ⇒ 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.

Quote values. Quoting keys is overkill.

Parameters:

Returns:



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'utils/shell.rb', line 40

def export_value(key, value, shell = preferred)
  case shell
  when :bash, :ksh, :mksh, :sh, :zsh
    "export #{key}=\"#{sh_quote(value)}\""
  when :fish
    # fish quoting is mostly Bourne compatible except that
    # a single quote can be included in a single-quoted string via \'
    # and a literal \ can be included via \\
    "set -gx #{key} \"#{sh_quote(value)}\""
  when :rc
    "#{key}=(#{sh_quote(value)})"
  when :csh, :tcsh
    "setenv #{key} #{csh_quote(value)};"
  end
end

.from_path(path) ⇒ Symbol?

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.

Take a path and heuristically convert it to a shell name, return nil if there's no match.

Parameters:

Returns:



15
16
17
18
19
20
21
# File 'utils/shell.rb', line 15

def from_path(path)
  # we only care about the basename
  shell_name = File.basename(path)
  # handle possible version suffix like `zsh-5.2`
  shell_name.sub!(/-.*\z/m, "")
  shell_name.to_sym if %w[bash csh fish ksh mksh pwsh rc sh tcsh zsh].include?(shell_name)
end

.parentSymbol?

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:



34
35
36
# File 'utils/shell.rb', line 34

def parent
  from_path(`ps -p #{Process.ppid} -o ucomm=`.strip)
end

.preferredSymbol?

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:



29
30
31
# File 'utils/shell.rb', line 29

def preferred
  from_path(preferred_path)
end

.preferred_path(default: "") ⇒ 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:

  • default (String) (defaults to: "")

Returns:



24
25
26
# File 'utils/shell.rb', line 24

def preferred_path(default: "")
  ENV.fetch("SHELL", default)
end

.prepend_path_in_profile(path) ⇒ 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:

Returns:



96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'utils/shell.rb', line 96

def prepend_path_in_profile(path)
  case preferred
  when :bash, :ksh, :mksh, :sh, :zsh, nil
    "echo 'export PATH=\"#{sh_quote(path)}:$PATH\"' >> #{profile}"
  when :pwsh
    "$env:PATH = '#{path}' + \":${env:PATH}\" >> #{profile}"
  when :rc
    "echo 'path=(#{sh_quote(path)} $path)' >> #{profile}"
  when :csh, :tcsh
    "echo 'setenv PATH #{csh_quote(path)}:$PATH' >> #{profile}"
  when :fish
    "fish_add_path #{sh_quote(path)}"
  end
end

.profileString

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.

Return the shell profile file based on user's preferred shell.

Returns:



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'utils/shell.rb', line 58

def profile
  case preferred
  when :bash
    bash_profile = "#{Dir.home}/.bash_profile"
    return bash_profile if File.exist? bash_profile
  when :pwsh
    pwsh_profile = "#{Dir.home}/.config/powershell/Microsoft.PowerShell_profile.ps1"
    return pwsh_profile if File.exist? pwsh_profile
  when :rc
    rc_profile = "#{Dir.home}/.rcrc"
    return rc_profile if File.exist? rc_profile
  when :zsh
    return "#{ENV["HOMEBREW_ZDOTDIR"]}/.zshrc" if ENV["HOMEBREW_ZDOTDIR"].present?
  end

  shell = preferred
  return "~/.profile" if shell.nil?

  SHELL_PROFILE_MAP.fetch(shell, "~/.profile")
end

.set_variable_in_profile(variable, value) ⇒ 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:

Returns:



80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'utils/shell.rb', line 80

def set_variable_in_profile(variable, value)
  case preferred
  when :bash, :ksh, :sh, :zsh, nil
    "echo 'export #{variable}=#{sh_quote(value)}' >> #{profile}"
  when :pwsh
    "$env:#{variable}='#{value}' >> #{profile}"
  when :rc
    "echo '#{variable}=(#{sh_quote(value)})' >> #{profile}"
  when :csh, :tcsh
    "echo 'setenv #{variable} #{csh_quote(value)}' >> #{profile}"
  when :fish
    "echo 'set -gx #{variable} #{sh_quote(value)}' >> #{profile}"
  end
end

.sh_quote(str) ⇒ 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:

Returns:



144
145
146
147
148
149
150
151
152
153
154
# File 'utils/shell.rb', line 144

def sh_quote(str)
  # Ruby's implementation of `shell_escape`.
  str = str.to_s
  return "''" if str.empty?

  str = str.dup
  # Anything that isn't a known safe character is padded.
  str.gsub!(UNSAFE_SHELL_CHAR, "\\\\" + "\\1") # rubocop:disable Style/StringConcatenation
  str.gsub!("\n", "'\n'")
  str
end

.shell_with_prompt(type, preferred_path:, notice:) ⇒ 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:

Returns:



157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'utils/shell.rb', line 157

def shell_with_prompt(type, preferred_path:, notice:)
  preferred = from_path(preferred_path)
  subshell = case preferred
  when :zsh
    "PROMPT='%B%F{green}#{type}%f %F{blue}$%f%b ' RPROMPT='[%B%F{red}%~%f%b]' #{preferred_path} -f"
  else
    "PS1=\"\\[\\033[1;32m\\]brew \\[\\033[1;31m\\]\\w \\[\\033[1;34m\\]$\\[\\033[0m\\] \" #{preferred_path}"
  end

  puts notice if notice.present?
  $stdout.flush

  subshell
end