Rename Hbc::SystemCommand to SystemCommand.

This commit is contained in:
Markus Reiter 2018-07-19 23:56:51 +02:00
parent c5f92bfb8b
commit 28384ba518
35 changed files with 321 additions and 320 deletions

View File

@ -18,7 +18,7 @@ require "hbc/installer"
require "hbc/macos"
require "hbc/pkg"
require "hbc/staged"
require "hbc/system_command"
require "system_command"
require "hbc/topological_hash"
require "hbc/utils"
require "hbc/verify"

View File

@ -1,4 +1,4 @@
require "hbc/system_command"
require "system_command"
module Hbc
class DSL

View File

@ -1,194 +0,0 @@
require "open3"
require "vendor/plist/plist"
require "shellwords"
require "extend/io"
require "extend/hash_validator"
using HashValidator
module Hbc
class SystemCommand
extend Predicable
def self.run(executable, **options)
new(executable, **options).run!
end
def self.run!(command, **options)
run(command, **options, must_succeed: true)
end
def run!
@merged_output = []
@processed_output = { stdout: "", stderr: "" }
odebug command.shelljoin
each_output_line do |type, line|
case type
when :stdout
puts line.chomp if print_stdout?
processed_output[:stdout] << line
@merged_output << [:stdout, line]
when :stderr
$stderr.puts Formatter.error(line.chomp) if print_stderr?
processed_output[:stderr] << line
@merged_output << [:stderr, line]
end
end
assert_success if must_succeed?
result
end
def initialize(executable, args: [], sudo: false, input: [], print_stdout: false, print_stderr: true, must_succeed: false, env: {}, **options)
@executable = executable
@args = args
@sudo = sudo
@input = [*input]
@print_stdout = print_stdout
@print_stderr = print_stderr
@must_succeed = must_succeed
options.assert_valid_keys!(:chdir)
@options = options
@env = env
@env.keys.grep_v(/^[\w&&\D]\w*$/) do |name|
raise ArgumentError, "Invalid variable name: '#{name}'"
end
end
def command
[*sudo_prefix, *env_args, executable.to_s, *expanded_args]
end
private
attr_reader :executable, :args, :input, :options, :processed_output, :processed_status, :env
attr_predicate :sudo?, :print_stdout?, :print_stderr?, :must_succeed?
def env_args
return [] if env.empty?
variables = env.map do |name, value|
sanitized_name = Shellwords.escape(name)
sanitized_value = Shellwords.escape(value)
"#{sanitized_name}=#{sanitized_value}"
end
["env", *variables]
end
def sudo_prefix
return [] unless sudo?
askpass_flags = ENV.key?("SUDO_ASKPASS") ? ["-A"] : []
["/usr/bin/sudo", *askpass_flags, "-E", "--"]
end
def assert_success
return if processed_status&.success?
raise ErrorDuringExecution.new(command,
status: processed_status,
output: @merged_output)
end
def expanded_args
@expanded_args ||= args.map do |arg|
if arg.respond_to?(:to_path)
File.absolute_path(arg)
elsif arg.is_a?(Integer) || arg.is_a?(Float)
arg.to_s
else
arg.to_str
end
end
end
def each_output_line(&b)
executable, *args = command
raw_stdin, raw_stdout, raw_stderr, raw_wait_thr =
Open3.popen3([executable, executable], *args, **options)
write_input_to(raw_stdin)
raw_stdin.close_write
each_line_from [raw_stdout, raw_stderr], &b
@processed_status = raw_wait_thr.value
end
def write_input_to(raw_stdin)
input.each(&raw_stdin.method(:write))
end
def each_line_from(sources)
loop do
readable_sources, = IO.select(sources)
readable_sources = readable_sources.reject(&:eof?)
break if readable_sources.empty?
readable_sources.each do |source|
begin
line = source.readline_nonblock || ""
type = (source == sources[0]) ? :stdout : :stderr
yield(type, line)
rescue IO::WaitReadable, EOFError
next
end
end
end
sources.each(&:close_read)
end
def result
Result.new(command,
processed_output[:stdout],
processed_output[:stderr],
processed_status.exitstatus)
end
class Result
attr_accessor :command, :stdout, :stderr, :exit_status
def initialize(command, stdout, stderr, exit_status)
@command = command
@stdout = stdout
@stderr = stderr
@exit_status = exit_status
end
def success?
@exit_status.zero?
end
def plist
@plist ||= begin
output = stdout
if /\A(?<garbage>.*?)<\?\s*xml/m =~ output
output = output.sub(/\A#{Regexp.escape(garbage)}/m, "")
warn_plist_garbage(garbage)
end
if %r{<\s*/\s*plist\s*>(?<garbage>.*?)\Z}m =~ output
output = output.sub(/#{Regexp.escape(garbage)}\Z/, "")
warn_plist_garbage(garbage)
end
Plist.parse_xml(output)
end
end
def warn_plist_garbage(garbage)
return unless ARGV.verbose?
return unless garbage =~ /\S/
opoo "Received non-XML output from #{Formatter.identifier(command.first)}:"
$stderr.puts garbage.strip
end
private :warn_plist_garbage
end
end
end

View File

@ -7,7 +7,7 @@ module Hbc
attr_reader :cask, :downloaded_path
def initialize(cask, downloaded_path, command = Hbc::SystemCommand)
def initialize(cask, downloaded_path, command = SystemCommand)
@command = command
@cask = cask
@downloaded_path = downloaded_path

View File

@ -76,6 +76,13 @@ module Readall
# Retrieve messages about syntax errors/warnings printed to `$stderr`, but
# discard a `Syntax OK` printed to `$stdout` (in absence of syntax errors).
messages = Utils.popen_read("#{RUBY_PATH} -c -w #{rb} 2>&1 >/dev/null")
# Ignore unnecessary warning about named capture conflicts.
# See https://bugs.ruby-lang.org/issues/12359.
messages = messages.lines
.reject { |line| line.include?("named capture conflicts a local variable") }
.join
$stderr.print messages
# Only syntax errors result in a non-zero status code. To detect syntax

View File

@ -0,0 +1,192 @@
require "open3"
require "vendor/plist/plist"
require "shellwords"
require "extend/io"
require "extend/hash_validator"
using HashValidator
class SystemCommand
extend Predicable
def self.run(executable, **options)
new(executable, **options).run!
end
def self.run!(command, **options)
run(command, **options, must_succeed: true)
end
def run!
@merged_output = []
@processed_output = { stdout: "", stderr: "" }
odebug command.shelljoin
each_output_line do |type, line|
case type
when :stdout
puts line.chomp if print_stdout?
processed_output[:stdout] << line
@merged_output << [:stdout, line]
when :stderr
$stderr.puts Formatter.error(line.chomp) if print_stderr?
processed_output[:stderr] << line
@merged_output << [:stderr, line]
end
end
assert_success if must_succeed?
result
end
def initialize(executable, args: [], sudo: false, input: [], print_stdout: false, print_stderr: true, must_succeed: false, env: {}, **options)
@executable = executable
@args = args
@sudo = sudo
@input = [*input]
@print_stdout = print_stdout
@print_stderr = print_stderr
@must_succeed = must_succeed
options.assert_valid_keys!(:chdir)
@options = options
@env = env
@env.keys.grep_v(/^[\w&&\D]\w*$/) do |name|
raise ArgumentError, "Invalid variable name: '#{name}'"
end
end
def command
[*sudo_prefix, *env_args, executable.to_s, *expanded_args]
end
private
attr_reader :executable, :args, :input, :options, :processed_output, :processed_status, :env
attr_predicate :sudo?, :print_stdout?, :print_stderr?, :must_succeed?
def env_args
return [] if env.empty?
variables = env.map do |name, value|
sanitized_name = Shellwords.escape(name)
sanitized_value = Shellwords.escape(value)
"#{sanitized_name}=#{sanitized_value}"
end
["env", *variables]
end
def sudo_prefix
return [] unless sudo?
askpass_flags = ENV.key?("SUDO_ASKPASS") ? ["-A"] : []
["/usr/bin/sudo", *askpass_flags, "-E", "--"]
end
def assert_success
return if processed_status&.success?
raise ErrorDuringExecution.new(command,
status: processed_status,
output: @merged_output)
end
def expanded_args
@expanded_args ||= args.map do |arg|
if arg.respond_to?(:to_path)
File.absolute_path(arg)
elsif arg.is_a?(Integer) || arg.is_a?(Float)
arg.to_s
else
arg.to_str
end
end
end
def each_output_line(&b)
executable, *args = command
raw_stdin, raw_stdout, raw_stderr, raw_wait_thr =
Open3.popen3([executable, executable], *args, **options)
write_input_to(raw_stdin)
raw_stdin.close_write
each_line_from [raw_stdout, raw_stderr], &b
@processed_status = raw_wait_thr.value
end
def write_input_to(raw_stdin)
input.each(&raw_stdin.method(:write))
end
def each_line_from(sources)
loop do
readable_sources, = IO.select(sources)
readable_sources = readable_sources.reject(&:eof?)
break if readable_sources.empty?
readable_sources.each do |source|
begin
line = source.readline_nonblock || ""
type = (source == sources[0]) ? :stdout : :stderr
yield(type, line)
rescue IO::WaitReadable, EOFError
next
end
end
end
sources.each(&:close_read)
end
def result
Result.new(command,
processed_output[:stdout],
processed_output[:stderr],
processed_status.exitstatus)
end
class Result
attr_accessor :command, :stdout, :stderr, :exit_status
def initialize(command, stdout, stderr, exit_status)
@command = command
@stdout = stdout
@stderr = stderr
@exit_status = exit_status
end
def success?
@exit_status.zero?
end
def plist
@plist ||= begin
output = stdout
if /\A(?<garbage>.*?)<\?\s*xml/m =~ output
output = output.sub(/\A#{Regexp.escape(garbage)}/m, "")
warn_plist_garbage(garbage)
end
if %r{<\s*/\s*plist\s*>(?<garbage>.*?)\Z}m =~ output
output = output.sub(/#{Regexp.escape(garbage)}\Z/, "")
warn_plist_garbage(garbage)
end
Plist.parse_xml(output)
end
end
def warn_plist_garbage(garbage)
return unless ARGV.verbose?
return unless garbage =~ /\S/
opoo "Received non-XML output from #{Formatter.identifier(command.first)}:"
$stderr.puts garbage.strip
end
private :warn_plist_garbage
end
end

View File

@ -2,7 +2,7 @@
# that class is abstracted from installer.rb.
describe "Accessibility Access", :cask do
let(:cask) { Hbc::CaskLoader.load(cask_path("with-accessibility-access")) }
let(:fake_system_command) { class_double(Hbc::SystemCommand) }
let(:fake_system_command) { class_double(SystemCommand) }
let(:installer) { Hbc::Installer.new(cask, command: fake_system_command) }
before do

View File

@ -5,7 +5,7 @@ describe Hbc::Artifact::App, :cask do
let(:install_phase) {
lambda do
cask.artifacts.select { |a| a.is_a?(described_class) }.each do |artifact|
artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false)
artifact.install_phase(command: NeverSudoSystemCommand, force: false)
end
end
}

View File

@ -1,6 +1,6 @@
describe Hbc::Artifact::App, :cask do
let(:cask) { Hbc::CaskLoader.load(cask_path("local-caffeine")) }
let(:command) { Hbc::SystemCommand }
let(:command) { SystemCommand }
let(:force) { false }
let(:app) { cask.artifacts.find { |a| a.is_a?(described_class) } }

View File

@ -24,7 +24,7 @@ describe Hbc::Artifact::Binary, :cask do
it "links the binary to the proper directory" do
artifacts.each do |artifact|
artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false)
artifact.install_phase(command: NeverSudoSystemCommand, force: false)
end
expect(expected_path).to be_a_symlink
@ -45,7 +45,7 @@ describe Hbc::Artifact::Binary, :cask do
.with("+x", cask.staged_path.join("naked_non_executable")).and_call_original
artifacts.each do |artifact|
artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false)
artifact.install_phase(command: NeverSudoSystemCommand, force: false)
end
expect(expected_path).to be_a_symlink
@ -58,7 +58,7 @@ describe Hbc::Artifact::Binary, :cask do
expect {
artifacts.each do |artifact|
artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false)
artifact.install_phase(command: NeverSudoSystemCommand, force: false)
end
}.to raise_error(Hbc::CaskError)
@ -69,7 +69,7 @@ describe Hbc::Artifact::Binary, :cask do
expected_path.make_symlink("/tmp")
artifacts.each do |artifact|
artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false)
artifact.install_phase(command: NeverSudoSystemCommand, force: false)
end
expect(File.readlink(expected_path)).not_to eq("/tmp")
@ -79,7 +79,7 @@ describe Hbc::Artifact::Binary, :cask do
FileUtils.rmdir Hbc::Config.global.binarydir
artifacts.each do |artifact|
artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false)
artifact.install_phase(command: NeverSudoSystemCommand, force: false)
end
expect(expected_path.exist?).to be true
@ -94,10 +94,10 @@ describe Hbc::Artifact::Binary, :cask do
it "links the binary to the proper directory" do
cask.artifacts.select { |a| a.is_a?(Hbc::Artifact::App) }.each do |artifact|
artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false)
artifact.install_phase(command: NeverSudoSystemCommand, force: false)
end
artifacts.each do |artifact|
artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false)
artifact.install_phase(command: NeverSudoSystemCommand, force: false)
end
expect(expected_path).to be_a_symlink

View File

@ -4,7 +4,7 @@ describe Hbc::Artifact::Artifact, :cask do
let(:install_phase) {
lambda do
cask.artifacts.select { |a| a.is_a?(described_class) }.each do |artifact|
artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false)
artifact.install_phase(command: NeverSudoSystemCommand, force: false)
end
end
}

View File

@ -2,7 +2,7 @@ describe Hbc::Artifact::Installer, :cask do
let(:staged_path) { mktmpdir }
let(:cask) { instance_double("Cask", staged_path: staged_path, config: nil) }
subject(:installer) { described_class.new(cask, **args) }
let(:command) { Hbc::SystemCommand }
let(:command) { SystemCommand }
let(:args) { {} }

View File

@ -6,7 +6,7 @@ describe Hbc::Artifact::NestedContainer, :cask do
end
cask.artifacts.select { |a| a.is_a?(described_class) }.each do |artifact|
artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false)
artifact.install_phase(command: NeverSudoSystemCommand, force: false)
end
expect(cask.staged_path.join("MyNestedApp.app")).to be_a_directory

View File

@ -1,6 +1,6 @@
describe Hbc::Artifact::Pkg, :cask do
let(:cask) { Hbc::CaskLoader.load(cask_path("with-installable")) }
let(:fake_system_command) { class_double(Hbc::SystemCommand) }
let(:fake_system_command) { class_double(SystemCommand) }
before do
InstallHelper.install_without_artifacts(cask)

View File

@ -12,7 +12,7 @@ describe Hbc::Artifact::PostflightBlock, :cask do
end
cask.artifacts.select { |a| a.is_a?(described_class) }.each do |artifact|
artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false)
artifact.install_phase(command: NeverSudoSystemCommand, force: false)
end
expect(called).to be true
@ -33,7 +33,7 @@ describe Hbc::Artifact::PostflightBlock, :cask do
end
cask.artifacts.select { |a| a.is_a?(described_class) }.each do |artifact|
artifact.uninstall_phase(command: Hbc::NeverSudoSystemCommand, force: false)
artifact.uninstall_phase(command: NeverSudoSystemCommand, force: false)
end
expect(called).to be true

View File

@ -12,7 +12,7 @@ describe Hbc::Artifact::PreflightBlock, :cask do
end
cask.artifacts.select { |a| a.is_a?(described_class) }.each do |artifact|
artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false)
artifact.install_phase(command: NeverSudoSystemCommand, force: false)
end
expect(called).to be true
@ -33,7 +33,7 @@ describe Hbc::Artifact::PreflightBlock, :cask do
end
cask.artifacts.select { |a| a.is_a?(described_class) }.each do |artifact|
artifact.uninstall_phase(command: Hbc::NeverSudoSystemCommand, force: false)
artifact.uninstall_phase(command: NeverSudoSystemCommand, force: false)
end
expect(called).to be true

View File

@ -4,7 +4,7 @@ describe Hbc::Artifact::Suite, :cask do
let(:install_phase) {
lambda do
cask.artifacts.select { |a| a.is_a?(described_class) }.each do |artifact|
artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false)
artifact.install_phase(command: NeverSudoSystemCommand, force: false)
end
end
}

View File

@ -5,7 +5,7 @@ describe Hbc::Artifact::App, :cask do
let(:install_phase) {
lambda do
cask.artifacts.select { |a| a.is_a?(described_class) }.each do |artifact|
artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false)
artifact.install_phase(command: NeverSudoSystemCommand, force: false)
end
end
}

View File

@ -1,7 +1,7 @@
shared_examples "#uninstall_phase or #zap_phase" do
let(:artifact_dsl_key) { described_class.dsl_key }
let(:artifact) { cask.artifacts.find { |a| a.is_a?(described_class) } }
let(:fake_system_command) { Hbc::FakeSystemCommand }
let(:fake_system_command) { FakeSystemCommand }
subject { artifact.public_send(:"#{artifact_dsl_key}_phase", command: fake_system_command) }
@ -26,40 +26,40 @@ shared_examples "#uninstall_phase or #zap_phase" do
end
it "works when job is owned by user" do
Hbc::FakeSystemCommand.stubs_command(
FakeSystemCommand.stubs_command(
launchctl_list_cmd,
service_info,
)
Hbc::FakeSystemCommand.stubs_command(
FakeSystemCommand.stubs_command(
sudo(launchctl_list_cmd),
unknown_response,
)
Hbc::FakeSystemCommand.expects_command(launchctl_remove_cmd)
FakeSystemCommand.expects_command(launchctl_remove_cmd)
subject
end
it "works when job is owned by system" do
Hbc::FakeSystemCommand.stubs_command(
FakeSystemCommand.stubs_command(
launchctl_list_cmd,
unknown_response,
)
Hbc::FakeSystemCommand.stubs_command(
FakeSystemCommand.stubs_command(
sudo(launchctl_list_cmd),
service_info,
)
Hbc::FakeSystemCommand.expects_command(sudo(launchctl_remove_cmd))
FakeSystemCommand.expects_command(sudo(launchctl_remove_cmd))
subject
end
end
context "using :pkgutil" do
let(:fake_system_command) { class_double(Hbc::SystemCommand) }
let(:fake_system_command) { class_double(SystemCommand) }
let(:cask) { Hbc::CaskLoader.load(cask_path("with-#{artifact_dsl_key}-pkgutil")) }
@ -89,19 +89,19 @@ shared_examples "#uninstall_phase or #zap_phase" do
let(:kext_id) { "my.fancy.package.kernelextension" }
it "is supported" do
Hbc::FakeSystemCommand.stubs_command(
FakeSystemCommand.stubs_command(
sudo(%W[/usr/sbin/kextstat -l -b #{kext_id}]), "loaded"
)
Hbc::FakeSystemCommand.expects_command(
FakeSystemCommand.expects_command(
sudo(%W[/sbin/kextunload -b #{kext_id}]),
)
Hbc::FakeSystemCommand.expects_command(
FakeSystemCommand.expects_command(
sudo(%W[/usr/sbin/kextfind -b #{kext_id}]), "/Library/Extensions/FancyPackage.kext\n"
)
Hbc::FakeSystemCommand.expects_command(
FakeSystemCommand.expects_command(
sudo(["/bin/rm", "-rf", "/Library/Extensions/FancyPackage.kext"]),
)
@ -117,11 +117,11 @@ shared_examples "#uninstall_phase or #zap_phase" do
end
it "is supported" do
Hbc::FakeSystemCommand.stubs_command(
FakeSystemCommand.stubs_command(
%w[/bin/launchctl list], "999\t0\t#{bundle_id}\n"
)
Hbc::FakeSystemCommand.stubs_command(
FakeSystemCommand.stubs_command(
%w[/bin/launchctl list],
)
@ -136,7 +136,7 @@ shared_examples "#uninstall_phase or #zap_phase" do
let(:unix_pids) { [12_345, 67_890] }
it "is supported" do
Hbc::FakeSystemCommand.stubs_command(
FakeSystemCommand.stubs_command(
%w[/bin/launchctl list], unix_pids.map { |pid| [pid, 0, bundle_id].join("\t") }.join("\n")
)
@ -171,7 +171,7 @@ shared_examples "#uninstall_phase or #zap_phase" do
end
end
let(:fake_system_command) { Hbc::NeverSudoSystemCommand }
let(:fake_system_command) { NeverSudoSystemCommand }
let(:cask) { Hbc::CaskLoader.load(cask_path("with-#{artifact_dsl_key}-#{directive}")) }
before(:each) do
@ -197,7 +197,7 @@ shared_examples "#uninstall_phase or #zap_phase" do
end
context "using :rmdir" do
let(:fake_system_command) { Hbc::NeverSudoSystemCommand }
let(:fake_system_command) { NeverSudoSystemCommand }
let(:cask) { Hbc::CaskLoader.load(cask_path("with-#{artifact_dsl_key}-rmdir")) }
let(:empty_directory) { Pathname.new("#{TEST_TMPDIR}/empty_directory_path") }
let(:ds_store) { empty_directory.join(".DS_Store") }
@ -224,7 +224,7 @@ shared_examples "#uninstall_phase or #zap_phase" do
[:script, :early_script].each do |script_type|
context "using #{script_type.inspect}" do
let(:fake_system_command) { Hbc::NeverSudoSystemCommand }
let(:fake_system_command) { NeverSudoSystemCommand }
let(:token) { "with-#{artifact_dsl_key}-#{script_type}".tr("_", "-") }
let(:cask) { Hbc::CaskLoader.load(cask_path(token.to_s)) }
let(:script_pathname) { cask.staged_path.join("MyFancyPkg", "FancyUninstaller.tool") }
@ -255,7 +255,7 @@ shared_examples "#uninstall_phase or #zap_phase" do
let(:cask) { Hbc::CaskLoader.load(cask_path("with-#{artifact_dsl_key}-login-item")) }
it "is supported" do
Hbc::FakeSystemCommand.expects_command(
FakeSystemCommand.expects_command(
["/usr/bin/osascript", "-e", 'tell application "System Events" to delete every login ' \
'item whose name is "Fancy"'],
)

View File

@ -38,7 +38,7 @@ describe Hbc::Audit, :cask do
let(:cask) { instance_double(Hbc::Cask) }
let(:download) { false }
let(:check_token_conflicts) { false }
let(:fake_system_command) { class_double(Hbc::SystemCommand) }
let(:fake_system_command) { class_double(SystemCommand) }
let(:audit) {
Hbc::Audit.new(cask, download: download,
check_token_conflicts: check_token_conflicts,

View File

@ -73,7 +73,7 @@ describe Hbc::CLI::List, :cask do
casks.each(&InstallHelper.method(:install_without_artifacts_with_caskfile))
transmission.artifacts.select { |a| a.is_a?(Hbc::Artifact::App) }.each do |artifact|
artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false)
artifact.install_phase(command: NeverSudoSystemCommand, force: false)
end
expect {

View File

@ -38,13 +38,13 @@ describe Hbc::CLI::Zap, :cask do
#
# with_zap.must_be :installed?
#
# Hbc::FakeSystemCommand.stubs_command(['/usr/bin/sudo', '-E', '--', '/usr/bin/osascript', '-e', 'tell application "System Events" to count processes whose bundle identifier is "my.fancy.package.app"'], '1')
# Hbc::FakeSystemCommand.stubs_command(['/usr/bin/sudo', '-E', '--', '/usr/bin/osascript', '-e', 'tell application id "my.fancy.package.app" to quit'])
# Hbc::FakeSystemCommand.stubs_command(['/usr/bin/sudo', '-E', '--', '/usr/bin/osascript', '-e', 'tell application "System Events" to count processes whose bundle identifier is "my.fancy.package.app.from.uninstall"'], '1')
# Hbc::FakeSystemCommand.stubs_command(['/usr/bin/sudo', '-E', '--', '/usr/bin/osascript', '-e', 'tell application id "my.fancy.package.app.from.uninstall" to quit'])
# FakeSystemCommand.stubs_command(['/usr/bin/sudo', '-E', '--', '/usr/bin/osascript', '-e', 'tell application "System Events" to count processes whose bundle identifier is "my.fancy.package.app"'], '1')
# FakeSystemCommand.stubs_command(['/usr/bin/sudo', '-E', '--', '/usr/bin/osascript', '-e', 'tell application id "my.fancy.package.app" to quit'])
# FakeSystemCommand.stubs_command(['/usr/bin/sudo', '-E', '--', '/usr/bin/osascript', '-e', 'tell application "System Events" to count processes whose bundle identifier is "my.fancy.package.app.from.uninstall"'], '1')
# FakeSystemCommand.stubs_command(['/usr/bin/sudo', '-E', '--', '/usr/bin/osascript', '-e', 'tell application id "my.fancy.package.app.from.uninstall" to quit'])
#
# Hbc::FakeSystemCommand.expects_command(['/usr/bin/sudo', '-E', '--', with_zap.staged_path.join('MyFancyPkg','FancyUninstaller.tool'), '--please'])
# Hbc::FakeSystemCommand.expects_command(['/usr/bin/sudo', '-E', '--', '/bin/rm', '-rf', '--',
# FakeSystemCommand.expects_command(['/usr/bin/sudo', '-E', '--', with_zap.staged_path.join('MyFancyPkg','FancyUninstaller.tool'), '--please'])
# FakeSystemCommand.expects_command(['/usr/bin/sudo', '-E', '--', '/bin/rm', '-rf', '--',
# Pathname.new('~/Library/Preferences/my.fancy.app.plist').expand_path])
#
# Hbc::CLI::Zap.run('with-zap')

View File

@ -6,7 +6,7 @@ describe Hbc::Container::Dmg, :cask do
dmg = Hbc::Container::Dmg.new(
transmission,
Pathname(transmission.url.path),
Hbc::SystemCommand,
SystemCommand,
)
dmg.mount do |mounts|

View File

@ -8,9 +8,9 @@ describe Hbc::Container::Naked, :cask do
path = Pathname("/tmp/downloads/kevin-spacey.pkg")
expected_destination = cask.staged_path.join("kevin spacey.pkg")
container = Hbc::Container::Naked.new(cask, path, Hbc::FakeSystemCommand)
container = Hbc::Container::Naked.new(cask, path, FakeSystemCommand)
Hbc::FakeSystemCommand.expects_command(
FakeSystemCommand.expects_command(
["/usr/bin/ditto", "--", path, expected_destination],
)

View File

@ -205,7 +205,7 @@ describe "download strategies", :cask do
describe Hbc::SubversionDownloadStrategy do
let(:url_options) { { using: :svn } }
let(:fake_system_command) { class_double(Hbc::SystemCommand) }
let(:fake_system_command) { class_double(SystemCommand) }
let(:downloader) { Hbc::SubversionDownloadStrategy.new(cask, command: fake_system_command) }
before do

View File

@ -3,7 +3,7 @@ require "test/support/helper/spec/shared_examples/hbc_staged"
describe Hbc::DSL::Postflight, :cask do
let(:cask) { Hbc::CaskLoader.load(cask_path("basic-cask")) }
let(:dsl) { Hbc::DSL::Postflight.new(cask, Hbc::FakeSystemCommand) }
let(:dsl) { Hbc::DSL::Postflight.new(cask, FakeSystemCommand) }
it_behaves_like Hbc::DSL::Base

View File

@ -3,7 +3,7 @@ require "test/support/helper/spec/shared_examples/hbc_staged"
describe Hbc::DSL::Preflight, :cask do
let(:cask) { Hbc::CaskLoader.load(cask_path("basic-cask")) }
let(:dsl) { Hbc::DSL::Preflight.new(cask, Hbc::FakeSystemCommand) }
let(:dsl) { Hbc::DSL::Preflight.new(cask, FakeSystemCommand) }
it_behaves_like Hbc::DSL::Base

View File

@ -2,7 +2,7 @@ require "test/support/helper/spec/shared_examples/hbc_dsl_base"
describe Hbc::DSL::UninstallPostflight, :cask do
let(:cask) { Hbc::CaskLoader.load(cask_path("basic-cask")) }
let(:dsl) { Hbc::DSL::UninstallPostflight.new(cask, Hbc::FakeSystemCommand) }
let(:dsl) { Hbc::DSL::UninstallPostflight.new(cask, FakeSystemCommand) }
it_behaves_like Hbc::DSL::Base
end

View File

@ -3,7 +3,7 @@ require "test/support/helper/spec/shared_examples/hbc_staged"
describe Hbc::DSL::UninstallPreflight, :cask do
let(:cask) { Hbc::CaskLoader.load(cask_path("basic-cask")) }
let(:dsl) { Hbc::DSL::UninstallPreflight.new(cask, Hbc::FakeSystemCommand) }
let(:dsl) { Hbc::DSL::UninstallPreflight.new(cask, FakeSystemCommand) }
it_behaves_like Hbc::DSL::Base

View File

@ -1,6 +1,6 @@
describe Hbc::Pkg, :cask do
describe "#uninstall" do
let(:fake_system_command) { Hbc::NeverSudoSystemCommand }
let(:fake_system_command) { NeverSudoSystemCommand }
let(:empty_response) { double(stdout: "", plist: { "volume" => "/", "install-location" => "", "paths" => {} }) }
let(:pkg) { described_class.new("my.fake.pkg", fake_system_command) }
@ -101,7 +101,7 @@ describe Hbc::Pkg, :cask do
end
describe "#info" do
let(:fake_system_command) { class_double(Hbc::SystemCommand) }
let(:fake_system_command) { class_double(SystemCommand) }
let(:volume) { "/" }
let(:install_location) { "tmp" }
@ -148,7 +148,7 @@ describe Hbc::Pkg, :cask do
"/usr/sbin/pkgutil",
args: ["--pkg-info-plist", pkg_id],
).and_return(
Hbc::SystemCommand::Result.new(nil, pkg_info_plist, nil, 0),
SystemCommand::Result.new(nil, pkg_info_plist, nil, 0),
)
info = pkg.info

View File

@ -2,73 +2,71 @@ def sudo(*args)
["/usr/bin/sudo", "-E", "--"] + args.flatten
end
module Hbc
class FakeSystemCommand
def self.responses
@responses ||= {}
end
class FakeSystemCommand
def self.responses
@responses ||= {}
end
def self.expectations
@expectations ||= {}
end
def self.expectations
@expectations ||= {}
end
def self.system_calls
@system_calls ||= Hash.new(0)
end
def self.system_calls
@system_calls ||= Hash.new(0)
end
def self.clear
@responses = nil
@expectations = nil
@system_calls = nil
end
def self.clear
@responses = nil
@expectations = nil
@system_calls = nil
end
def self.stubs_command(command, response = "")
command = command.map(&:to_s)
responses[command] = response
end
def self.stubs_command(command, response = "")
command = command.map(&:to_s)
responses[command] = response
end
def self.expects_command(command, response = "", times = 1)
command = command.map(&:to_s)
stubs_command(command, response)
expectations[command] = times
end
def self.expects_command(command, response = "", times = 1)
command = command.map(&:to_s)
stubs_command(command, response)
expectations[command] = times
end
def self.verify_expectations!
expectations.each do |command, times|
unless system_calls[command] == times
raise("expected #{command.inspect} to be run #{times} times, but got #{system_calls[command]}")
end
def self.verify_expectations!
expectations.each do |command, times|
unless system_calls[command] == times
raise("expected #{command.inspect} to be run #{times} times, but got #{system_calls[command]}")
end
end
end
def self.run(command_string, options = {})
command = Hbc::SystemCommand.new(command_string, options).command
puts command
unless responses.key?(command)
raise("no response faked for #{command.inspect}, faked responses are: #{responses.inspect}")
end
system_calls[command] += 1
response = responses[command]
if response.respond_to?(:call)
response.call(command_string, options)
else
Hbc::SystemCommand::Result.new(command, response, "", 0)
end
def self.run(command_string, options = {})
command = SystemCommand.new(command_string, options).command
puts command
unless responses.key?(command)
raise("no response faked for #{command.inspect}, faked responses are: #{responses.inspect}")
end
system_calls[command] += 1
def self.run!(command, options = {})
run(command, options.merge(must_succeed: true))
response = responses[command]
if response.respond_to?(:call)
response.call(command_string, options)
else
SystemCommand::Result.new(command, response, "", 0)
end
end
def self.run!(command, options = {})
run(command, options.merge(must_succeed: true))
end
end
RSpec.configure do |config|
config.after(:each) do
begin
Hbc::FakeSystemCommand.verify_expectations!
FakeSystemCommand.verify_expectations!
ensure
Hbc::FakeSystemCommand.clear
FakeSystemCommand.clear
end
end
end

View File

@ -1,9 +1,7 @@
require "hbc/system_command"
require "system_command"
module Hbc
class NeverSudoSystemCommand < SystemCommand
def self.run(command, options = {})
super(command, options.merge(sudo: false))
end
class NeverSudoSystemCommand < SystemCommand
def self.run(command, options = {})
super(command, options.merge(sudo: false))
end
end

View File

@ -14,7 +14,7 @@ shared_examples Hbc::Staged do
end
it "can run system commands with list-form arguments" do
Hbc::FakeSystemCommand.expects_command(
FakeSystemCommand.expects_command(
["echo", "homebrew-cask", "rocks!"],
)
@ -28,7 +28,7 @@ shared_examples Hbc::Staged do
it "can execute commands on the Info.plist file" do
allow(staged).to receive(:bundle_identifier).and_return("com.example.BasicCask")
Hbc::FakeSystemCommand.expects_command(
FakeSystemCommand.expects_command(
["/usr/libexec/PlistBuddy", "-c", "Print CFBundleIdentifier", staged.info_plist_file],
)
@ -38,7 +38,7 @@ shared_examples Hbc::Staged do
it "can set a key in the Info.plist file" do
allow(staged).to receive(:bundle_identifier).and_return("com.example.BasicCask")
Hbc::FakeSystemCommand.expects_command(
FakeSystemCommand.expects_command(
["/usr/libexec/PlistBuddy", "-c", "Set :JVMOptions:JVMVersion 1.6+", staged.info_plist_file],
)
@ -49,7 +49,7 @@ shared_examples Hbc::Staged do
fake_pathname = existing_path
allow(staged).to receive(:Pathname).and_return(fake_pathname)
Hbc::FakeSystemCommand.expects_command(
FakeSystemCommand.expects_command(
["/bin/chmod", "-R", "--", "777", fake_pathname],
)
@ -60,7 +60,7 @@ shared_examples Hbc::Staged do
fake_pathname = existing_path
allow(staged).to receive(:Pathname).and_return(fake_pathname)
Hbc::FakeSystemCommand.expects_command(
FakeSystemCommand.expects_command(
["/bin/chmod", "-R", "--", "777", fake_pathname, fake_pathname],
)
@ -79,7 +79,7 @@ shared_examples Hbc::Staged do
allow(staged).to receive(:current_user).and_return("fake_user")
allow(staged).to receive(:Pathname).and_return(fake_pathname)
Hbc::FakeSystemCommand.expects_command(
FakeSystemCommand.expects_command(
sudo("/usr/sbin/chown", "-R", "--", "fake_user:staff", fake_pathname),
)
@ -92,7 +92,7 @@ shared_examples Hbc::Staged do
allow(staged).to receive(:current_user).and_return("fake_user")
allow(staged).to receive(:Pathname).and_return(fake_pathname)
Hbc::FakeSystemCommand.expects_command(
FakeSystemCommand.expects_command(
sudo("/usr/sbin/chown", "-R", "--", "fake_user:staff", fake_pathname, fake_pathname),
)
@ -104,7 +104,7 @@ shared_examples Hbc::Staged do
allow(staged).to receive(:Pathname).and_return(fake_pathname)
Hbc::FakeSystemCommand.expects_command(
FakeSystemCommand.expects_command(
sudo("/usr/sbin/chown", "-R", "--", "other_user:other_group", fake_pathname),
)

View File

@ -1,6 +1,6 @@
require "hbc/system_command"
require "system_command"
describe Hbc::SystemCommand::Result, :cask do
describe SystemCommand::Result, :cask do
describe "#plist" do
subject { described_class.new(command, stdout, "", 0).plist }

View File

@ -1,4 +1,4 @@
describe Hbc::SystemCommand, :cask do
describe SystemCommand, :cask do
describe "#initialize" do
let(:env_args) { ["bash", "-c", 'printf "%s" "${A?}" "${B?}" "${C?}"'] }