Merge pull request #201 from gregory-nisbet/feature-env-shells
--env: support more shells, allow explicit shell selection
This commit is contained in:
commit
dfcbefff73
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
require "extend/ENV"
|
require "extend/ENV"
|
||||||
require "build_environment"
|
require "build_environment"
|
||||||
|
require "utils/shell"
|
||||||
|
|
||||||
module Homebrew
|
module Homebrew
|
||||||
def __env
|
def __env
|
||||||
@ -11,12 +12,24 @@ module Homebrew
|
|||||||
ENV.setup_build_environment
|
ENV.setup_build_environment
|
||||||
ENV.universal_binary if ARGV.build_universal?
|
ENV.universal_binary if ARGV.build_universal?
|
||||||
|
|
||||||
if $stdout.tty?
|
shell_value = ARGV.value("shell")
|
||||||
|
|
||||||
|
if ARGV.include?("--plain")
|
||||||
|
shell = nil
|
||||||
|
elsif shell_value.nil?
|
||||||
|
# legacy behavior
|
||||||
|
shell = :bash unless $stdout.tty?
|
||||||
|
elsif shell_value == "auto"
|
||||||
|
shell = Utils::Shell.parent_shell || Utils::Shell.preferred_shell
|
||||||
|
elsif shell_value
|
||||||
|
shell = Utils::Shell.path_to_shell(shell_value)
|
||||||
|
end
|
||||||
|
|
||||||
|
env_keys = build_env_keys(ENV)
|
||||||
|
if shell.nil?
|
||||||
dump_build_env ENV
|
dump_build_env ENV
|
||||||
else
|
else
|
||||||
build_env_keys(ENV).each do |key|
|
env_keys.each { |key| puts Utils::Shell.export_value(shell, key, ENV[key]) }
|
||||||
puts "export #{key}=\"#{ENV[key]}\""
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
10
Library/Homebrew/compat/utils.rb
Normal file
10
Library/Homebrew/compat/utils.rb
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# return the shell profile file based on users' preference shell
|
||||||
|
def shell_profile
|
||||||
|
opoo "shell_profile has been deprecated in favor of Utils::Shell.profile"
|
||||||
|
case ENV["SHELL"]
|
||||||
|
when %r{/(ba)?sh} then "~/.bash_profile"
|
||||||
|
when %r{/zsh} then "~/.zshrc"
|
||||||
|
when %r{/ksh} then "~/.kshrc"
|
||||||
|
else "~/.bash_profile"
|
||||||
|
end
|
||||||
|
end
|
@ -3,6 +3,7 @@ require "language/python"
|
|||||||
require "formula"
|
require "formula"
|
||||||
require "version"
|
require "version"
|
||||||
require "development_tools"
|
require "development_tools"
|
||||||
|
require "utils/shell"
|
||||||
|
|
||||||
module Homebrew
|
module Homebrew
|
||||||
module Diagnostic
|
module Diagnostic
|
||||||
@ -476,7 +477,7 @@ module Homebrew
|
|||||||
|
|
||||||
Consider setting your PATH so that #{HOMEBREW_PREFIX}/bin
|
Consider setting your PATH so that #{HOMEBREW_PREFIX}/bin
|
||||||
occurs before /usr/bin. Here is a one-liner:
|
occurs before /usr/bin. Here is a one-liner:
|
||||||
echo 'export PATH="#{HOMEBREW_PREFIX}/bin:$PATH"' >> #{shell_profile}
|
#{Utils::Shell.prepend_path_in_shell_profile("#{HOMEBREW_PREFIX}/bin")}
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -496,7 +497,7 @@ module Homebrew
|
|||||||
<<-EOS.undent
|
<<-EOS.undent
|
||||||
Homebrew's bin was not found in your PATH.
|
Homebrew's bin was not found in your PATH.
|
||||||
Consider setting the PATH for example like so
|
Consider setting the PATH for example like so
|
||||||
echo 'export PATH="#{HOMEBREW_PREFIX}/bin:$PATH"' >> #{shell_profile}
|
#{Utils::Shell.prepend_path_in_shell_profile("#{HOMEBREW_PREFIX}/bin")}
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -511,7 +512,7 @@ module Homebrew
|
|||||||
Homebrew's sbin was not found in your PATH but you have installed
|
Homebrew's sbin was not found in your PATH but you have installed
|
||||||
formulae that put executables in #{HOMEBREW_PREFIX}/sbin.
|
formulae that put executables in #{HOMEBREW_PREFIX}/sbin.
|
||||||
Consider setting the PATH for example like so
|
Consider setting the PATH for example like so
|
||||||
echo 'export PATH="#{HOMEBREW_PREFIX}/sbin:$PATH"' >> #{shell_profile}
|
#{Utils::Shell.prepend_path_in_shell_profile("#{HOMEBREW_PREFIX}/sbin")}
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -202,7 +202,7 @@ module Homebrew
|
|||||||
SSL_CERT_DIR support was removed from Apple's curl.
|
SSL_CERT_DIR support was removed from Apple's curl.
|
||||||
If fetching formulae fails you should:
|
If fetching formulae fails you should:
|
||||||
unset SSL_CERT_DIR
|
unset SSL_CERT_DIR
|
||||||
and remove it from #{shell_profile} if present.
|
and remove it from #{Utils::Shell.shell_profile} if present.
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
require "utils/shell"
|
||||||
|
|
||||||
module FormulaCellarChecks
|
module FormulaCellarChecks
|
||||||
def check_PATH(bin)
|
def check_PATH(bin)
|
||||||
# warn the user if stuff was installed outside of their PATH
|
# warn the user if stuff was installed outside of their PATH
|
||||||
@ -12,7 +14,7 @@ module FormulaCellarChecks
|
|||||||
|
|
||||||
<<-EOS.undent
|
<<-EOS.undent
|
||||||
#{prefix_bin} is not in your PATH
|
#{prefix_bin} is not in your PATH
|
||||||
You can amend this by altering your #{shell_profile} file
|
You can amend this by altering your #{Utils::Shell.shell_profile} file
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -227,6 +227,26 @@ class IntegrationCommandTests < Homebrew::TestCase
|
|||||||
cmd("--env"))
|
cmd("--env"))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_env_bash
|
||||||
|
assert_match %r{export CMAKE_PREFIX_PATH="#{Regexp.quote(HOMEBREW_PREFIX.to_s)}"},
|
||||||
|
cmd("--env", "--shell=bash")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_env_fish
|
||||||
|
assert_match %r{set [-]gx CMAKE_PREFIX_PATH "#{Regexp.quote(HOMEBREW_PREFIX.to_s)}"},
|
||||||
|
cmd("--env", "--shell=fish")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_env_csh
|
||||||
|
assert_match %r{setenv CMAKE_PREFIX_PATH #{Regexp.quote(HOMEBREW_PREFIX.to_s)};},
|
||||||
|
cmd("--env", "--shell=tcsh")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_env_plain
|
||||||
|
assert_match %r{CMAKE_PREFIX_PATH: #{Regexp.quote(HOMEBREW_PREFIX)}},
|
||||||
|
cmd("--env", "--plain")
|
||||||
|
end
|
||||||
|
|
||||||
def test_prefix_formula
|
def test_prefix_formula
|
||||||
assert_match "#{HOMEBREW_CELLAR}/testball",
|
assert_match "#{HOMEBREW_CELLAR}/testball",
|
||||||
cmd("--prefix", testball)
|
cmd("--prefix", testball)
|
||||||
|
59
Library/Homebrew/test/test_shell.rb
Normal file
59
Library/Homebrew/test/test_shell.rb
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
require "testing_env"
|
||||||
|
require "utils/shell"
|
||||||
|
|
||||||
|
class ShellSmokeTest < Homebrew::TestCase
|
||||||
|
def test_path_to_shell()
|
||||||
|
# raw command name
|
||||||
|
assert_equal :bash, Utils::Shell.path_to_shell("bash")
|
||||||
|
# full path
|
||||||
|
assert_equal :bash, Utils::Shell.path_to_shell("/bin/bash")
|
||||||
|
# versions
|
||||||
|
assert_equal :zsh, Utils::Shell.path_to_shell("zsh-5.2")
|
||||||
|
# strip newline too
|
||||||
|
assert_equal :zsh, Utils::Shell.path_to_shell("zsh-5.2\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_path_to_shell_failure()
|
||||||
|
assert_equal nil, Utils::Shell.path_to_shell("")
|
||||||
|
assert_equal nil, Utils::Shell.path_to_shell("@@@@@@")
|
||||||
|
assert_equal nil, Utils::Shell.path_to_shell("invalid_shell-4.2")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_sh_quote()
|
||||||
|
assert_equal "''", Utils::Shell.sh_quote("")
|
||||||
|
assert_equal "\\\\", Utils::Shell.sh_quote("\\")
|
||||||
|
assert_equal "'\n'", Utils::Shell.sh_quote("\n")
|
||||||
|
assert_equal "\\$", Utils::Shell.sh_quote("$")
|
||||||
|
assert_equal "word", Utils::Shell.sh_quote("word")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_csh_quote()
|
||||||
|
assert_equal "''", Utils::Shell.csh_quote("")
|
||||||
|
assert_equal "\\\\", Utils::Shell.csh_quote("\\")
|
||||||
|
# note this test is different than for sh
|
||||||
|
assert_equal "'\\\n'", Utils::Shell.csh_quote("\n")
|
||||||
|
assert_equal "\\$", Utils::Shell.csh_quote("$")
|
||||||
|
assert_equal "word", Utils::Shell.csh_quote("word")
|
||||||
|
end
|
||||||
|
|
||||||
|
def prepend_path_shell(shell, path, fragment)
|
||||||
|
original_shell = ENV["SHELL"]
|
||||||
|
ENV["SHELL"] = shell
|
||||||
|
|
||||||
|
prepend_message = Utils::Shell.prepend_path_in_shell_profile(path)
|
||||||
|
assert(
|
||||||
|
prepend_message.start_with?(fragment),
|
||||||
|
"#{shell}: expected #{prepend_message} to match #{fragment}"
|
||||||
|
)
|
||||||
|
|
||||||
|
ENV["SHELL"] = original_shell
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_prepend_path_in_shell_profile()
|
||||||
|
prepend_path_shell "/bin/tcsh", "/path", "echo 'setenv PATH /path"
|
||||||
|
|
||||||
|
prepend_path_shell "/bin/bash", "/path", "echo 'export PATH=\"/path"
|
||||||
|
|
||||||
|
prepend_path_shell "/usr/local/bin/fish", "/path", "echo 'set -g fish_user_paths \"/path\" $fish_user_paths' >>"
|
||||||
|
end
|
||||||
|
end
|
@ -1,6 +1,7 @@
|
|||||||
require "testing_env"
|
require "testing_env"
|
||||||
require "utils"
|
require "utils"
|
||||||
require "tempfile"
|
require "tempfile"
|
||||||
|
require "utils/shell"
|
||||||
|
|
||||||
class TtyTests < Homebrew::TestCase
|
class TtyTests < Homebrew::TestCase
|
||||||
def test_strip_ansi
|
def test_strip_ansi
|
||||||
@ -157,15 +158,15 @@ class UtilTests < Homebrew::TestCase
|
|||||||
|
|
||||||
def test_shell_profile
|
def test_shell_profile
|
||||||
ENV["SHELL"] = "/bin/sh"
|
ENV["SHELL"] = "/bin/sh"
|
||||||
assert_equal "~/.bash_profile", shell_profile
|
assert_equal "~/.bash_profile", Utils::Shell.shell_profile
|
||||||
ENV["SHELL"] = "/bin/bash"
|
ENV["SHELL"] = "/bin/bash"
|
||||||
assert_equal "~/.bash_profile", shell_profile
|
assert_equal "~/.bash_profile", Utils::Shell.shell_profile
|
||||||
ENV["SHELL"] = "/bin/another_shell"
|
ENV["SHELL"] = "/bin/another_shell"
|
||||||
assert_equal "~/.bash_profile", shell_profile
|
assert_equal "~/.bash_profile", Utils::Shell.shell_profile
|
||||||
ENV["SHELL"] = "/bin/zsh"
|
ENV["SHELL"] = "/bin/zsh"
|
||||||
assert_equal "~/.zshrc", shell_profile
|
assert_equal "~/.zshrc", Utils::Shell.shell_profile
|
||||||
ENV["SHELL"] = "/bin/ksh"
|
ENV["SHELL"] = "/bin/ksh"
|
||||||
assert_equal "~/.kshrc", shell_profile
|
assert_equal "~/.kshrc", Utils::Shell.shell_profile
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_popen_read
|
def test_popen_read
|
||||||
|
@ -526,16 +526,6 @@ def paths
|
|||||||
end.uniq.compact
|
end.uniq.compact
|
||||||
end
|
end
|
||||||
|
|
||||||
# return the shell profile file based on users' preference shell
|
|
||||||
def shell_profile
|
|
||||||
case ENV["SHELL"]
|
|
||||||
when %r{/(ba)?sh} then "~/.bash_profile"
|
|
||||||
when %r{/zsh} then "~/.zshrc"
|
|
||||||
when %r{/ksh} then "~/.kshrc"
|
|
||||||
else "~/.bash_profile"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def disk_usage_readable(size_in_bytes)
|
def disk_usage_readable(size_in_bytes)
|
||||||
if size_in_bytes >= 1_073_741_824
|
if size_in_bytes >= 1_073_741_824
|
||||||
size = size_in_bytes.to_f / 1_073_741_824
|
size = size_in_bytes.to_f / 1_073_741_824
|
||||||
|
87
Library/Homebrew/utils/shell.rb
Normal file
87
Library/Homebrew/utils/shell.rb
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
module Utils
|
||||||
|
SHELL_PROFILE_MAP = {
|
||||||
|
:bash => "~/.bash_profile",
|
||||||
|
:csh => "~/.cshrc",
|
||||||
|
:fish => "~/.config/fish/config.fish",
|
||||||
|
:ksh => "~/.kshrc",
|
||||||
|
:sh => "~/.bash_profile",
|
||||||
|
:tcsh => "~/.tcshrc",
|
||||||
|
:zsh => "~/.zshrc",
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
module Shell
|
||||||
|
UNSAFE_SHELL_CHAR = /([^A-Za-z0-9_\-.,:\/@\n])/
|
||||||
|
|
||||||
|
# take a path and heuristically convert it
|
||||||
|
# to a shell name, return nil if there's no match
|
||||||
|
def self.path_to_shell(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 sh tcsh zsh].include?(shell_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.preferred_shell
|
||||||
|
path_to_shell(ENV.fetch("SHELL", ""))
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.parent_shell
|
||||||
|
path_to_shell(`ps -p #{Process.ppid} -o ucomm=`.strip)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.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")
|
||||||
|
# newlines have to be specially quoted in csh
|
||||||
|
str.gsub!(/\n/, "'\\\n'")
|
||||||
|
str
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.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")
|
||||||
|
str.gsub!(/\n/, "'\n'")
|
||||||
|
str
|
||||||
|
end
|
||||||
|
|
||||||
|
# quote values. quoting keys is overkill
|
||||||
|
def self.export_value(shell, key, value)
|
||||||
|
case shell
|
||||||
|
when :bash, :ksh, :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 :csh, :tcsh
|
||||||
|
"setenv #{key} #{csh_quote(value)};"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# return the shell profile file based on users' preferred shell
|
||||||
|
def self.shell_profile
|
||||||
|
SHELL_PROFILE_MAP.fetch(preferred_shell, "~/.bash_profile")
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.prepend_path_in_shell_profile(path)
|
||||||
|
case preferred_shell
|
||||||
|
when :bash, :ksh, :sh, :zsh, nil
|
||||||
|
"echo 'export PATH=\"#{sh_quote(path)}:$PATH\"' >> #{shell_profile}"
|
||||||
|
when :csh, :tcsh
|
||||||
|
"echo 'setenv PATH #{csh_quote(path)}:$PATH' >> #{shell_profile}"
|
||||||
|
when :fish
|
||||||
|
"echo 'set -g fish_user_paths \"#{sh_quote(path)}\" $fish_user_paths' >> #{shell_profile}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
x
Reference in New Issue
Block a user