Skip to content

Commit 7d9a6e0

Browse files
committed
Use IO.popen to start a process
RuboCop rightfully complains about using open() to spawn a process. This uses the way simpler IO.popen() method.
1 parent fc39fe4 commit 7d9a6e0

File tree

3 files changed

+21
-32
lines changed

3 files changed

+21
-32
lines changed

lib/puppet/util/execution.rb

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -57,31 +57,19 @@ def initialize(value, exitstatus)
5757
# @see Kernel#open for `mode` values
5858
# @api public
5959
def self.execpipe(command, failonfail = true)
60-
# Paste together an array with spaces. We used to paste directly
61-
# together, no spaces, which made for odd invocations; the user had to
62-
# include whitespace between arguments.
63-
#
64-
# Having two spaces is really not a big drama, since this passes to the
65-
# shell anyhow, while no spaces makes for a small developer cost every
66-
# time this is invoked. --daniel 2012-02-13
67-
command_str = command.respond_to?(:join) ? command.join(' ') : command
68-
6960
if respond_to? :debug
70-
debug "Executing '#{command_str}'"
61+
debug "Executing #{command.inspect}"
7162
else
72-
Puppet.debug { "Executing '#{command_str}'" }
63+
Puppet.debug { "Executing #{command.inspect}" }
7364
end
7465

75-
# force the run of the command with
76-
# the user/system locale to "C" (via environment variables LANG and LC_*)
77-
# it enables to have non localized output for some commands and therefore
78-
# a predictable output
79-
english_env = ENV.to_hash.merge({ 'LANG' => 'C', 'LC_ALL' => 'C' })
80-
output = Puppet::Util.withenv(english_env) do
81-
# We are intentionally using 'pipe' with open to launch a process
82-
open("| #{command_str} 2>&1") do |pipe| # rubocop:disable Security/Open
66+
begin
67+
output = IO.popen({ 'LANG' => 'C', 'LC_ALL' => 'C' }, command, err: :out) do |pipe|
8368
yield pipe
8469
end
70+
rescue Errno::ENOENT => e
71+
output = e.message
72+
raise Puppet::ExecutionFailure, output if failonfail
8573
end
8674

8775
if failonfail && exitstatus != 0

spec/unit/provider/package/pacman_spec.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -403,21 +403,21 @@
403403
let(:groups) { [['foo package1'], ['foo package2'], ['bar package3'], ['bar package4'], ['baz package5']] }
404404

405405
it 'should raise an error on non-zero pacman exit without a filter' do
406-
expect(executor).to receive(:open).with('| /usr/bin/pacman --sync -gg 2>&1').and_return('error!')
406+
expect(IO).to receive(:popen).with({ 'LANG' => 'C', 'LC_ALL' => 'C' }, ['/usr/bin/pacman', '--sync', '-gg'], err: :out).and_return('error!')
407407
expect(Puppet::Util::Execution).to receive(:exitstatus).and_return(1)
408408
expect { described_class.get_installed_groups(installed_packages) }.to raise_error(Puppet::ExecutionFailure, 'error!')
409409
end
410410

411411
it 'should return empty groups on non-zero pacman exit with a filter' do
412-
expect(executor).to receive(:open).with('| /usr/bin/pacman --sync -gg git 2>&1').and_return('')
412+
expect(IO).to receive(:popen).with({ 'LANG' => 'C', 'LC_ALL' => 'C' }, ['/usr/bin/pacman', '--sync', '-gg', 'git'], err: :out).and_return('')
413413
expect(Puppet::Util::Execution).to receive(:exitstatus).and_return(1)
414414
expect(described_class.get_installed_groups(installed_packages, 'git')).to eq({})
415415
end
416416

417417
it 'should return empty groups on empty pacman output' do
418418
pipe = double()
419419
expect(pipe).to receive(:each_line)
420-
expect(executor).to receive(:open).with('| /usr/bin/pacman --sync -gg 2>&1').and_yield(pipe).and_return('')
420+
expect(IO).to receive(:popen).with({ 'LANG' => 'C', 'LC_ALL' => 'C' }, ['/usr/bin/pacman', '--sync', '-gg'], err: :out).and_yield(pipe).and_return('')
421421
expect(Puppet::Util::Execution).to receive(:exitstatus).and_return(0)
422422
expect(described_class.get_installed_groups(installed_packages)).to eq({})
423423
end
@@ -427,7 +427,7 @@
427427
pipe_expectation = receive(:each_line)
428428
groups.each { |group| pipe_expectation = pipe_expectation.and_yield(*group) }
429429
expect(pipe).to pipe_expectation
430-
expect(executor).to receive(:open).with('| /usr/bin/pacman --sync -gg 2>&1').and_yield(pipe).and_return('')
430+
expect(IO).to receive(:popen).with({ 'LANG' => 'C', 'LC_ALL' => 'C' }, ['/usr/bin/pacman', '--sync', '-gg'], err: :out).and_yield(pipe).and_return('')
431431
expect(Puppet::Util::Execution).to receive(:exitstatus).and_return(0)
432432
expect(described_class.get_installed_groups(installed_packages)).to eq({'foo' => 'package1 1.0, package2 2.0'})
433433
end

spec/unit/util/execution_spec.rb

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -909,43 +909,44 @@ def expect_cwd_to_be(cwd)
909909

910910
describe "#execpipe" do
911911
it "should execute a string as a string" do
912-
expect(Puppet::Util::Execution).to receive(:open).with('| echo hello 2>&1').and_return('hello')
912+
expect(IO).to receive(:popen).with({ 'LANG' => 'C', 'LC_ALL' => 'C' }, 'echo hello', err: :out).and_return('hello')
913913
expect(Puppet::Util::Execution).to receive(:exitstatus).and_return(0)
914914
expect(Puppet::Util::Execution.execpipe('echo hello')).to eq('hello')
915915
end
916916

917917
it "should print meaningful debug message for string argument" do
918918
Puppet[:log_level] = 'debug'
919-
expect(Puppet).to receive(:send_log).with(:debug, "Executing 'echo hello'")
920-
expect(Puppet::Util::Execution).to receive(:open).with('| echo hello 2>&1').and_return('hello')
919+
expect(Puppet).to receive(:send_log).with(:debug, 'Executing "echo hello"')
920+
expect(IO).to receive(:popen).with({ 'LANG' => 'C', 'LC_ALL' => 'C' }, 'echo hello', err: :out).and_return('hello')
921921
expect(Puppet::Util::Execution).to receive(:exitstatus).and_return(0)
922922
Puppet::Util::Execution.execpipe('echo hello')
923923
end
924924

925925
it "should print meaningful debug message for array argument" do
926926
Puppet[:log_level] = 'debug'
927-
expect(Puppet).to receive(:send_log).with(:debug, "Executing 'echo hello'")
928-
expect(Puppet::Util::Execution).to receive(:open).with('| echo hello 2>&1').and_return('hello')
927+
expect(Puppet).to receive(:send_log).with(:debug, 'Executing ["echo", "hello"]')
928+
expect(IO).to receive(:popen).with({ 'LANG' => 'C', 'LC_ALL' => 'C' }, ['echo', 'hello'], err: :out).and_return('hello')
929929
expect(Puppet::Util::Execution).to receive(:exitstatus).and_return(0)
930930
Puppet::Util::Execution.execpipe(['echo','hello'])
931931
end
932932

933-
it "should execute an array by pasting together with spaces" do
934-
expect(Puppet::Util::Execution).to receive(:open).with('| echo hello 2>&1').and_return('hello')
933+
it "should execute an array" do
934+
expect(IO).to receive(:popen).with({ 'LANG' => 'C', 'LC_ALL' => 'C' }, ['echo', 'hello'], err: :out).and_return('hello')
935935
expect(Puppet::Util::Execution).to receive(:exitstatus).and_return(0)
936936
expect(Puppet::Util::Execution.execpipe(['echo', 'hello'])).to eq('hello')
937937
end
938938

939939
it "should fail if asked to fail, and the child does" do
940-
allow(Puppet::Util::Execution).to receive(:open).with('| echo hello 2>&1').and_return('error message')
940+
expect(IO).to receive(:popen).with({ 'LANG' => 'C', 'LC_ALL' => 'C' }, ['echo', 'hello'], err: :out).and_return('error message')
941941
expect(Puppet::Util::Execution).to receive(:exitstatus).and_return(1)
942942
expect {
943943
Puppet::Util::Execution.execpipe('echo hello')
944944
}.to raise_error Puppet::ExecutionFailure, /error message/
945945
end
946946

947947
it "should not fail if asked not to fail, and the child does" do
948-
allow(Puppet::Util::Execution).to receive(:open).and_return('error message')
948+
expect(IO).to receive(:popen).with({ 'LANG' => 'C', 'LC_ALL' => 'C' }, 'echo hello', err: :out).and_return('error message')
949+
expect(Puppet::Util::Execution).not_to receive(:exitstatus)
949950
expect(Puppet::Util::Execution.execpipe('echo hello', false)).to eq('error message')
950951
end
951952
end

0 commit comments

Comments
 (0)