mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00
Fix PKG installer environment
This commit solves an issue where the environment handed to `/usr/sbin/installer` is not the same as the environment used by the graphical PKG installer. This is evident in some post-install scripts, e. g. the `component-10.pkg/Scripts/postinstall` script in the `dymo-label` cask. The code says: ``` USER_ID=`id -u ${USER}` launchctl bootstrap gui/$USER_ID /Library/LaunchAgents/com.dymo.dls.webservice.plist ``` The graphical installer will export e. g. `USER=alice`, and everything works as intended. However, `brew cask install` does not override `sudo`’s default, which is `USER=ROOT`. This violates the assumptions in the script. This commit fixes the issue by configuring `sudo` to override the following environment variables with the proper user name: - `LOGNAME` - `USER` - `USERNAME`
This commit is contained in:
parent
9fff177844
commit
3dbb735f3c
@ -50,7 +50,13 @@ module Hbc
|
||||
end
|
||||
with_choices_file do |choices_path|
|
||||
args << "-applyChoiceChangesXML" << choices_path if choices_path
|
||||
command.run!("/usr/sbin/installer", sudo: true, args: args, print_stdout: true)
|
||||
logged_in_user = Utils.current_user
|
||||
env = {
|
||||
"LOGNAME" => logged_in_user,
|
||||
"USER" => logged_in_user,
|
||||
"USERNAME" => logged_in_user,
|
||||
}
|
||||
command.run!("/usr/sbin/installer", sudo: true, args: args, print_stdout: true, env: env)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -37,7 +37,7 @@ module Hbc
|
||||
result
|
||||
end
|
||||
|
||||
def initialize(executable, args: [], sudo: false, input: [], print_stdout: false, print_stderr: true, must_succeed: false, path: ENV["PATH"], **options)
|
||||
def initialize(executable, args: [], sudo: false, input: [], print_stdout: false, print_stderr: true, must_succeed: false, env: {}, **options)
|
||||
@executable = executable
|
||||
@args = args
|
||||
@sudo = sudo
|
||||
@ -47,7 +47,11 @@ module Hbc
|
||||
@must_succeed = must_succeed
|
||||
options.extend(HashValidator).assert_valid_keys(:chdir)
|
||||
@options = options
|
||||
@path = path
|
||||
@env = { "PATH" => ENV["PATH"] }.merge(env)
|
||||
|
||||
@env.keys.grep_v(/^[\w&&\D]\w*$/) do |name|
|
||||
raise ArgumentError, "Invalid variable name: '#{name}'"
|
||||
end
|
||||
end
|
||||
|
||||
def command
|
||||
@ -56,14 +60,22 @@ module Hbc
|
||||
|
||||
private
|
||||
|
||||
attr_reader :executable, :args, :input, :options, :processed_output, :processed_status, :path
|
||||
attr_reader :executable, :args, :input, :options, :processed_output, :processed_status, :env
|
||||
|
||||
attr_predicate :sudo?, :print_stdout?, :print_stderr?, :must_succeed?
|
||||
|
||||
def sudo_prefix
|
||||
return [] unless sudo?
|
||||
askpass_flags = ENV.key?("SUDO_ASKPASS") ? ["-A"] : []
|
||||
["/usr/bin/sudo", *askpass_flags, "-E", "--"]
|
||||
prefix = ["/usr/bin/sudo", *askpass_flags, "-E"]
|
||||
|
||||
env.each do |name, value|
|
||||
sanitized_name = Shellwords.escape(name)
|
||||
sanitized_value = Shellwords.escape(value)
|
||||
prefix << "#{sanitized_name}=#{sanitized_value}"
|
||||
end
|
||||
|
||||
prefix << "--"
|
||||
end
|
||||
|
||||
def assert_success
|
||||
@ -85,7 +97,7 @@ module Hbc
|
||||
executable, *args = expanded_command
|
||||
|
||||
raw_stdin, raw_stdout, raw_stderr, raw_wait_thr =
|
||||
Open3.popen3({ "PATH" => path }, [executable, executable], *args, **options)
|
||||
Open3.popen3(env, [executable, executable], *args, **options)
|
||||
|
||||
write_input_to(raw_stdin)
|
||||
raw_stdin.close_write
|
||||
|
@ -15,6 +15,11 @@ describe Hbc::Artifact::Pkg, :cask do
|
||||
args: ["-pkg", cask.staged_path.join("MyFancyPkg", "Fancy.pkg"), "-target", "/"],
|
||||
sudo: true,
|
||||
print_stdout: true,
|
||||
env: {
|
||||
"LOGNAME" => ENV["USER"],
|
||||
"USER" => ENV["USER"],
|
||||
"USERNAME" => ENV["USER"],
|
||||
},
|
||||
)
|
||||
|
||||
pkg.install_phase(command: fake_system_command)
|
||||
@ -55,6 +60,11 @@ describe Hbc::Artifact::Pkg, :cask do
|
||||
args: ["-pkg", cask.staged_path.join("MyFancyPkg", "Fancy.pkg"), "-target", "/", "-applyChoiceChangesXML", cask.staged_path.join("/tmp/choices.xml")],
|
||||
sudo: true,
|
||||
print_stdout: true,
|
||||
env: {
|
||||
"LOGNAME" => ENV["USER"],
|
||||
"USER" => ENV["USER"],
|
||||
"USERNAME" => ENV["USER"],
|
||||
},
|
||||
)
|
||||
|
||||
pkg.install_phase(command: fake_system_command)
|
||||
|
@ -1,4 +1,59 @@
|
||||
describe Hbc::SystemCommand, :cask do
|
||||
describe "#initialize" do
|
||||
let(:env_args) { ["bash", "-c", 'printf "%s" "${A?}" "${B?}" "${C?}"'] }
|
||||
|
||||
describe "given some environment variables" do
|
||||
subject {
|
||||
described_class.new(
|
||||
"env",
|
||||
args: env_args,
|
||||
env: { "A" => "1", "B" => "2", "C" => "3" },
|
||||
must_succeed: true,
|
||||
)
|
||||
}
|
||||
|
||||
its("run!.stdout") { is_expected.to eq("123") }
|
||||
|
||||
describe "the resulting command line" do
|
||||
it "does not include the given variables" do
|
||||
expect(Open3)
|
||||
.to receive(:popen3)
|
||||
.with(a_hash_including("PATH"), ["env"] * 2, *env_args, {})
|
||||
.and_call_original
|
||||
|
||||
subject.run!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "given some environment variables and sudo: true" do
|
||||
subject {
|
||||
described_class.new(
|
||||
"env",
|
||||
args: env_args,
|
||||
env: { "A" => "1", "B" => "2", "C" => "3" },
|
||||
must_succeed: true,
|
||||
sudo: true,
|
||||
)
|
||||
}
|
||||
|
||||
describe "the resulting command line" do
|
||||
it "includes the given variables explicitly" do
|
||||
expect(Open3)
|
||||
.to receive(:popen3)
|
||||
.with(an_instance_of(Hash), ["/usr/bin/sudo"] * 2,
|
||||
"-E", a_string_starting_with("PATH="),
|
||||
"A=1", "B=2", "C=3", "--", "env", *env_args, {})
|
||||
.and_wrap_original do |original_popen3, *_, &block|
|
||||
original_popen3.call("/usr/bin/true", &block)
|
||||
end
|
||||
|
||||
subject.run!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "when the exit code is 0" do
|
||||
describe "its result" do
|
||||
subject { described_class.run("/usr/bin/true") }
|
||||
@ -134,4 +189,11 @@ describe Hbc::SystemCommand, :cask do
|
||||
}.to be_a_success
|
||||
end
|
||||
end
|
||||
|
||||
describe "given an invalid variable name" do
|
||||
it "raises an ArgumentError" do
|
||||
expect { described_class.run("true", env: { "1ABC" => true }) }
|
||||
.to raise_error(ArgumentError, /variable name/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,5 +1,5 @@
|
||||
def sudo(*args)
|
||||
%w[/usr/bin/sudo -E --] + args.flatten
|
||||
["/usr/bin/sudo", "-E", "PATH=#{ENV["PATH"]}", "--"] + args.flatten
|
||||
end
|
||||
|
||||
module Hbc
|
||||
|
@ -80,7 +80,7 @@ shared_examples Hbc::Staged do
|
||||
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
||||
|
||||
Hbc::FakeSystemCommand.expects_command(
|
||||
["/usr/bin/sudo", "-E", "--", "/usr/sbin/chown", "-R", "--", "fake_user:staff", fake_pathname],
|
||||
["/usr/bin/sudo", "-E", "PATH=#{ENV["PATH"]}", "--", "/usr/sbin/chown", "-R", "--", "fake_user:staff", fake_pathname],
|
||||
)
|
||||
|
||||
staged.set_ownership(fake_pathname.to_s)
|
||||
@ -93,7 +93,7 @@ shared_examples Hbc::Staged do
|
||||
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
||||
|
||||
Hbc::FakeSystemCommand.expects_command(
|
||||
["/usr/bin/sudo", "-E", "--", "/usr/sbin/chown", "-R", "--", "fake_user:staff", fake_pathname, fake_pathname],
|
||||
["/usr/bin/sudo", "-E", "PATH=#{ENV["PATH"]}", "--", "/usr/sbin/chown", "-R", "--", "fake_user:staff", fake_pathname, fake_pathname],
|
||||
)
|
||||
|
||||
staged.set_ownership([fake_pathname.to_s, fake_pathname.to_s])
|
||||
@ -105,7 +105,7 @@ shared_examples Hbc::Staged do
|
||||
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
||||
|
||||
Hbc::FakeSystemCommand.expects_command(
|
||||
["/usr/bin/sudo", "-E", "--", "/usr/sbin/chown", "-R", "--", "other_user:other_group", fake_pathname],
|
||||
["/usr/bin/sudo", "-E", "PATH=#{ENV["PATH"]}", "--", "/usr/sbin/chown", "-R", "--", "other_user:other_group", fake_pathname],
|
||||
)
|
||||
|
||||
staged.set_ownership(fake_pathname.to_s, user: "other_user", group: "other_group")
|
||||
|
Loading…
x
Reference in New Issue
Block a user