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
|
end
|
||||||
with_choices_file do |choices_path|
|
with_choices_file do |choices_path|
|
||||||
args << "-applyChoiceChangesXML" << choices_path if 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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ module Hbc
|
|||||||
result
|
result
|
||||||
end
|
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
|
@executable = executable
|
||||||
@args = args
|
@args = args
|
||||||
@sudo = sudo
|
@sudo = sudo
|
||||||
@ -47,7 +47,11 @@ module Hbc
|
|||||||
@must_succeed = must_succeed
|
@must_succeed = must_succeed
|
||||||
options.extend(HashValidator).assert_valid_keys(:chdir)
|
options.extend(HashValidator).assert_valid_keys(:chdir)
|
||||||
@options = options
|
@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
|
end
|
||||||
|
|
||||||
def command
|
def command
|
||||||
@ -56,14 +60,22 @@ module Hbc
|
|||||||
|
|
||||||
private
|
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?
|
attr_predicate :sudo?, :print_stdout?, :print_stderr?, :must_succeed?
|
||||||
|
|
||||||
def sudo_prefix
|
def sudo_prefix
|
||||||
return [] unless sudo?
|
return [] unless sudo?
|
||||||
askpass_flags = ENV.key?("SUDO_ASKPASS") ? ["-A"] : []
|
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
|
end
|
||||||
|
|
||||||
def assert_success
|
def assert_success
|
||||||
@ -85,7 +97,7 @@ module Hbc
|
|||||||
executable, *args = expanded_command
|
executable, *args = expanded_command
|
||||||
|
|
||||||
raw_stdin, raw_stdout, raw_stderr, raw_wait_thr =
|
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)
|
write_input_to(raw_stdin)
|
||||||
raw_stdin.close_write
|
raw_stdin.close_write
|
||||||
|
@ -15,6 +15,11 @@ describe Hbc::Artifact::Pkg, :cask do
|
|||||||
args: ["-pkg", cask.staged_path.join("MyFancyPkg", "Fancy.pkg"), "-target", "/"],
|
args: ["-pkg", cask.staged_path.join("MyFancyPkg", "Fancy.pkg"), "-target", "/"],
|
||||||
sudo: true,
|
sudo: true,
|
||||||
print_stdout: true,
|
print_stdout: true,
|
||||||
|
env: {
|
||||||
|
"LOGNAME" => ENV["USER"],
|
||||||
|
"USER" => ENV["USER"],
|
||||||
|
"USERNAME" => ENV["USER"],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
pkg.install_phase(command: fake_system_command)
|
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")],
|
args: ["-pkg", cask.staged_path.join("MyFancyPkg", "Fancy.pkg"), "-target", "/", "-applyChoiceChangesXML", cask.staged_path.join("/tmp/choices.xml")],
|
||||||
sudo: true,
|
sudo: true,
|
||||||
print_stdout: true,
|
print_stdout: true,
|
||||||
|
env: {
|
||||||
|
"LOGNAME" => ENV["USER"],
|
||||||
|
"USER" => ENV["USER"],
|
||||||
|
"USERNAME" => ENV["USER"],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
pkg.install_phase(command: fake_system_command)
|
pkg.install_phase(command: fake_system_command)
|
||||||
|
@ -1,4 +1,59 @@
|
|||||||
describe Hbc::SystemCommand, :cask do
|
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 "when the exit code is 0" do
|
||||||
describe "its result" do
|
describe "its result" do
|
||||||
subject { described_class.run("/usr/bin/true") }
|
subject { described_class.run("/usr/bin/true") }
|
||||||
@ -134,4 +189,11 @@ describe Hbc::SystemCommand, :cask do
|
|||||||
}.to be_a_success
|
}.to be_a_success
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
def sudo(*args)
|
def sudo(*args)
|
||||||
%w[/usr/bin/sudo -E --] + args.flatten
|
["/usr/bin/sudo", "-E", "PATH=#{ENV["PATH"]}", "--"] + args.flatten
|
||||||
end
|
end
|
||||||
|
|
||||||
module Hbc
|
module Hbc
|
||||||
|
@ -80,7 +80,7 @@ shared_examples Hbc::Staged do
|
|||||||
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
||||||
|
|
||||||
Hbc::FakeSystemCommand.expects_command(
|
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)
|
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)
|
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
||||||
|
|
||||||
Hbc::FakeSystemCommand.expects_command(
|
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])
|
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)
|
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
||||||
|
|
||||||
Hbc::FakeSystemCommand.expects_command(
|
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")
|
staged.set_ownership(fake_pathname.to_s, user: "other_user", group: "other_group")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user