Add types for SystemCommand
.
This commit is contained in:
parent
d96b85e512
commit
d5b184d17a
@ -34,15 +34,15 @@ module Context
|
|||||||
end
|
end
|
||||||
|
|
||||||
def debug?
|
def debug?
|
||||||
@debug
|
@debug == true
|
||||||
end
|
end
|
||||||
|
|
||||||
def quiet?
|
def quiet?
|
||||||
@quiet
|
@quiet == true
|
||||||
end
|
end
|
||||||
|
|
||||||
def verbose?
|
def verbose?
|
||||||
@verbose
|
@verbose == true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
|
|
||||||
source = ARGV[5]
|
source = ARGV[5]
|
||||||
|
|
||||||
/\busing +Magic\b/.match(source) do |_|
|
case source[/\Ausing\s+(.*)\Z/, 1]
|
||||||
|
when "Magic"
|
||||||
puts <<-RUBY
|
puts <<-RUBY
|
||||||
# typed: strict
|
# typed: strict
|
||||||
|
|
||||||
@ -18,4 +19,13 @@ source = ARGV[5]
|
|||||||
def zipinfo; end
|
def zipinfo; end
|
||||||
end
|
end
|
||||||
RUBY
|
RUBY
|
||||||
|
when "HashValidator"
|
||||||
|
puts <<-RUBY
|
||||||
|
# typed: strict
|
||||||
|
|
||||||
|
class ::Hash
|
||||||
|
sig { params(valid_keys: T.untyped).void }
|
||||||
|
def assert_valid_keys!(*valid_keys); end
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
end
|
end
|
@ -28559,6 +28559,7 @@ class Socket
|
|||||||
IPV6_PATHMTU = ::T.let(nil, ::T.untyped)
|
IPV6_PATHMTU = ::T.let(nil, ::T.untyped)
|
||||||
IPV6_RECVPATHMTU = ::T.let(nil, ::T.untyped)
|
IPV6_RECVPATHMTU = ::T.let(nil, ::T.untyped)
|
||||||
IPV6_USE_MIN_MTU = ::T.let(nil, ::T.untyped)
|
IPV6_USE_MIN_MTU = ::T.let(nil, ::T.untyped)
|
||||||
|
IP_DONTFRAG = ::T.let(nil, ::T.untyped)
|
||||||
IP_PORTRANGE = ::T.let(nil, ::T.untyped)
|
IP_PORTRANGE = ::T.let(nil, ::T.untyped)
|
||||||
IP_RECVDSTADDR = ::T.let(nil, ::T.untyped)
|
IP_RECVDSTADDR = ::T.let(nil, ::T.untyped)
|
||||||
IP_RECVIF = ::T.let(nil, ::T.untyped)
|
IP_RECVIF = ::T.let(nil, ::T.untyped)
|
||||||
@ -28650,6 +28651,7 @@ module Socket::Constants
|
|||||||
IPV6_PATHMTU = ::T.let(nil, ::T.untyped)
|
IPV6_PATHMTU = ::T.let(nil, ::T.untyped)
|
||||||
IPV6_RECVPATHMTU = ::T.let(nil, ::T.untyped)
|
IPV6_RECVPATHMTU = ::T.let(nil, ::T.untyped)
|
||||||
IPV6_USE_MIN_MTU = ::T.let(nil, ::T.untyped)
|
IPV6_USE_MIN_MTU = ::T.let(nil, ::T.untyped)
|
||||||
|
IP_DONTFRAG = ::T.let(nil, ::T.untyped)
|
||||||
IP_PORTRANGE = ::T.let(nil, ::T.untyped)
|
IP_PORTRANGE = ::T.let(nil, ::T.untyped)
|
||||||
IP_RECVDSTADDR = ::T.let(nil, ::T.untyped)
|
IP_RECVDSTADDR = ::T.let(nil, ::T.untyped)
|
||||||
IP_RECVIF = ::T.let(nil, ::T.untyped)
|
IP_RECVIF = ::T.let(nil, ::T.untyped)
|
||||||
@ -29210,6 +29212,11 @@ end
|
|||||||
class SynchronizedDelegator
|
class SynchronizedDelegator
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class SystemCommand::Result
|
||||||
|
extend ::T::Private::Methods::MethodHooks
|
||||||
|
extend ::T::Private::Methods::SingletonMethodHooks
|
||||||
|
end
|
||||||
|
|
||||||
class SystemCommand
|
class SystemCommand
|
||||||
extend ::T::Private::Methods::MethodHooks
|
extend ::T::Private::Methods::MethodHooks
|
||||||
extend ::T::Private::Methods::SingletonMethodHooks
|
extend ::T::Private::Methods::SingletonMethodHooks
|
||||||
|
@ -2,6 +2,6 @@ ruby_extra_args:
|
|||||||
- --disable-gems
|
- --disable-gems
|
||||||
|
|
||||||
triggers:
|
triggers:
|
||||||
using: sorbet/plugins/unpack_strategy_magic.rb
|
using: sorbet/plugins/using.rb
|
||||||
attr_predicate: sorbet/plugins/attr_predicate.rb
|
attr_predicate: sorbet/plugins/attr_predicate.rb
|
||||||
delegate: sorbet/plugins/delegate.rb
|
delegate: sorbet/plugins/delegate.rb
|
||||||
|
@ -9,7 +9,6 @@ require "shellwords"
|
|||||||
require "extend/io"
|
require "extend/io"
|
||||||
require "extend/predicable"
|
require "extend/predicable"
|
||||||
require "extend/hash_validator"
|
require "extend/hash_validator"
|
||||||
using HashValidator
|
|
||||||
|
|
||||||
# Class for running sub-processes and capturing their output and exit status.
|
# Class for running sub-processes and capturing their output and exit status.
|
||||||
#
|
#
|
||||||
@ -17,14 +16,16 @@ using HashValidator
|
|||||||
class SystemCommand
|
class SystemCommand
|
||||||
extend T::Sig
|
extend T::Sig
|
||||||
|
|
||||||
|
using HashValidator
|
||||||
|
|
||||||
# Helper functions for calling {SystemCommand.run}.
|
# Helper functions for calling {SystemCommand.run}.
|
||||||
module Mixin
|
module Mixin
|
||||||
def system_command(*args)
|
def system_command(*args)
|
||||||
SystemCommand.run(*args)
|
T.unsafe(SystemCommand).run(*args)
|
||||||
end
|
end
|
||||||
|
|
||||||
def system_command!(*args)
|
def system_command!(*args)
|
||||||
SystemCommand.run!(*args)
|
T.unsafe(SystemCommand).run!(*args)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -34,11 +35,11 @@ class SystemCommand
|
|||||||
attr_reader :pid
|
attr_reader :pid
|
||||||
|
|
||||||
def self.run(executable, **options)
|
def self.run(executable, **options)
|
||||||
new(executable, **options).run!
|
T.unsafe(self).new(executable, **options).run!
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.run!(command, **options)
|
def self.run!(command, **options)
|
||||||
run(command, **options, must_succeed: true)
|
T.unsafe(self).run(command, **options, must_succeed: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
sig { returns(SystemCommand::Result) }
|
sig { returns(SystemCommand::Result) }
|
||||||
@ -63,45 +64,61 @@ class SystemCommand
|
|||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig do
|
||||||
|
params(
|
||||||
|
executable: T.any(String, Pathname),
|
||||||
|
args: T::Array[T.any(String, Integer, Float, URI::Generic)],
|
||||||
|
sudo: T::Boolean,
|
||||||
|
env: T::Hash[String, String],
|
||||||
|
input: T.any(String, T::Array[String]),
|
||||||
|
must_succeed: T::Boolean,
|
||||||
|
print_stdout: T::Boolean,
|
||||||
|
print_stderr: T::Boolean,
|
||||||
|
verbose: T::Boolean,
|
||||||
|
secrets: T::Array[String],
|
||||||
|
chdir: T.any(String, Pathname),
|
||||||
|
).void
|
||||||
|
end
|
||||||
def initialize(executable, args: [], sudo: false, env: {}, input: [], must_succeed: false,
|
def initialize(executable, args: [], sudo: false, env: {}, input: [], must_succeed: false,
|
||||||
print_stdout: false, print_stderr: true, verbose: false, secrets: [], **options)
|
print_stdout: false, print_stderr: true, verbose: false, secrets: [], chdir: T.unsafe(nil))
|
||||||
require "extend/ENV"
|
require "extend/ENV"
|
||||||
@executable = executable
|
@executable = executable
|
||||||
@args = args
|
@args = args
|
||||||
@sudo = sudo
|
@sudo = sudo
|
||||||
@input = Array(input)
|
env.each_key do |name|
|
||||||
@print_stdout = print_stdout
|
|
||||||
@print_stderr = print_stderr
|
|
||||||
@verbose = verbose
|
|
||||||
@secrets = (Array(secrets) + ENV.sensitive_environment.values).uniq
|
|
||||||
@must_succeed = must_succeed
|
|
||||||
options.assert_valid_keys!(:chdir)
|
|
||||||
@options = options
|
|
||||||
@env = env
|
|
||||||
|
|
||||||
@env.each_key do |name|
|
|
||||||
next if /^[\w&&\D]\w*$/.match?(name)
|
next if /^[\w&&\D]\w*$/.match?(name)
|
||||||
|
|
||||||
raise ArgumentError, "Invalid variable name: '#{name}'"
|
raise ArgumentError, "Invalid variable name: '#{name}'"
|
||||||
end
|
end
|
||||||
|
@env = env
|
||||||
|
@input = Array(input)
|
||||||
|
@must_succeed = must_succeed
|
||||||
|
@print_stdout = print_stdout
|
||||||
|
@print_stderr = print_stderr
|
||||||
|
@verbose = verbose
|
||||||
|
@secrets = (Array(secrets) + ENV.sensitive_environment.values).uniq
|
||||||
|
@chdir = chdir
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { returns(T::Array[String]) }
|
||||||
def command
|
def command
|
||||||
[*sudo_prefix, *env_args, executable.to_s, *expanded_args]
|
[*sudo_prefix, *env_args, executable.to_s, *expanded_args]
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
attr_reader :executable, :args, :input, :options, :env
|
attr_reader :executable, :args, :input, :chdir, :env
|
||||||
|
|
||||||
attr_predicate :sudo?, :print_stdout?, :print_stderr?, :must_succeed?
|
attr_predicate :sudo?, :print_stdout?, :print_stderr?, :must_succeed?
|
||||||
|
|
||||||
|
sig { returns(T::Boolean) }
|
||||||
def verbose?
|
def verbose?
|
||||||
return super if @verbose.nil?
|
return super if @verbose.nil?
|
||||||
|
|
||||||
@verbose
|
@verbose
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { returns(T::Array[String]) }
|
||||||
def env_args
|
def env_args
|
||||||
set_variables = env.compact.map do |name, value|
|
set_variables = env.compact.map do |name, value|
|
||||||
sanitized_name = Shellwords.escape(name)
|
sanitized_name = Shellwords.escape(name)
|
||||||
@ -114,6 +131,7 @@ class SystemCommand
|
|||||||
["/usr/bin/env", *set_variables]
|
["/usr/bin/env", *set_variables]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { returns(T::Array[String]) }
|
||||||
def sudo_prefix
|
def sudo_prefix
|
||||||
return [] unless sudo?
|
return [] unless sudo?
|
||||||
|
|
||||||
@ -121,11 +139,12 @@ class SystemCommand
|
|||||||
["/usr/bin/sudo", *askpass_flags, "-E", "--"]
|
["/usr/bin/sudo", *askpass_flags, "-E", "--"]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { returns(T::Array[String]) }
|
||||||
def expanded_args
|
def expanded_args
|
||||||
@expanded_args ||= args.map do |arg|
|
@expanded_args ||= args.map do |arg|
|
||||||
if arg.respond_to?(:to_path)
|
if arg.respond_to?(:to_path)
|
||||||
File.absolute_path(arg)
|
File.absolute_path(arg)
|
||||||
elsif arg.is_a?(Integer) || arg.is_a?(Float) || arg.is_a?(URI)
|
elsif arg.is_a?(Integer) || arg.is_a?(Float) || arg.is_a?(URI::Generic)
|
||||||
arg.to_s
|
arg.to_s
|
||||||
else
|
else
|
||||||
arg.to_str
|
arg.to_str
|
||||||
@ -137,7 +156,7 @@ class SystemCommand
|
|||||||
executable, *args = command
|
executable, *args = command
|
||||||
|
|
||||||
raw_stdin, raw_stdout, raw_stderr, raw_wait_thr =
|
raw_stdin, raw_stdout, raw_stderr, raw_wait_thr =
|
||||||
Open3.popen3(env, [executable, executable], *args, **options)
|
T.unsafe(Open3).popen3(env, [executable, executable], *args, **{ chdir: chdir }.compact)
|
||||||
@pid = raw_wait_thr.pid
|
@pid = raw_wait_thr.pid
|
||||||
|
|
||||||
write_input_to(raw_stdin)
|
write_input_to(raw_stdin)
|
||||||
@ -158,7 +177,7 @@ class SystemCommand
|
|||||||
loop do
|
loop do
|
||||||
readable_sources, = IO.select(sources)
|
readable_sources, = IO.select(sources)
|
||||||
|
|
||||||
readable_sources = readable_sources.reject(&:eof?)
|
readable_sources = T.must(readable_sources).reject(&:eof?)
|
||||||
|
|
||||||
break if readable_sources.empty?
|
break if readable_sources.empty?
|
||||||
|
|
||||||
@ -176,10 +195,20 @@ class SystemCommand
|
|||||||
|
|
||||||
# Result containing the output and exit status of a finished sub-process.
|
# Result containing the output and exit status of a finished sub-process.
|
||||||
class Result
|
class Result
|
||||||
|
extend T::Sig
|
||||||
|
|
||||||
include Context
|
include Context
|
||||||
|
|
||||||
attr_accessor :command, :status, :exit_status
|
attr_accessor :command, :status, :exit_status
|
||||||
|
|
||||||
|
sig do
|
||||||
|
params(
|
||||||
|
command: T::Array[String],
|
||||||
|
output: T::Array[[Symbol, String]],
|
||||||
|
status: Process::Status,
|
||||||
|
secrets: T::Array[String],
|
||||||
|
).void
|
||||||
|
end
|
||||||
def initialize(command, output, status, secrets:)
|
def initialize(command, output, status, secrets:)
|
||||||
@command = command
|
@command = command
|
||||||
@output = output
|
@output = output
|
||||||
@ -188,57 +217,65 @@ class SystemCommand
|
|||||||
@secrets = secrets
|
@secrets = secrets
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { void }
|
||||||
def assert_success!
|
def assert_success!
|
||||||
return if @status.success?
|
return if @status.success?
|
||||||
|
|
||||||
raise ErrorDuringExecution.new(command, status: @status, output: @output, secrets: @secrets)
|
raise ErrorDuringExecution.new(command, status: @status, output: @output, secrets: @secrets)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { returns(String) }
|
||||||
def stdout
|
def stdout
|
||||||
@stdout ||= @output.select { |type,| type == :stdout }
|
@stdout ||= @output.select { |type,| type == :stdout }
|
||||||
.map { |_, line| line }
|
.map { |_, line| line }
|
||||||
.join
|
.join
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { returns(String) }
|
||||||
def stderr
|
def stderr
|
||||||
@stderr ||= @output.select { |type,| type == :stderr }
|
@stderr ||= @output.select { |type,| type == :stderr }
|
||||||
.map { |_, line| line }
|
.map { |_, line| line }
|
||||||
.join
|
.join
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { returns(String) }
|
||||||
def merged_output
|
def merged_output
|
||||||
@merged_output ||= @output.map { |_, line| line }
|
@merged_output ||= @output.map { |_, line| line }
|
||||||
.join
|
.join
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { returns(T::Boolean) }
|
||||||
def success?
|
def success?
|
||||||
return false if @exit_status.nil?
|
return false if @exit_status.nil?
|
||||||
|
|
||||||
@exit_status.zero?
|
@exit_status.zero?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { returns([String, String, Process::Status]) }
|
||||||
def to_ary
|
def to_ary
|
||||||
[stdout, stderr, status]
|
[stdout, stderr, status]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { returns(T.nilable(T.any(Array, Hash))) }
|
||||||
def plist
|
def plist
|
||||||
@plist ||= begin
|
@plist ||= begin
|
||||||
output = stdout
|
output = stdout
|
||||||
|
|
||||||
if /\A(?<garbage>.*?)<\?\s*xml/m =~ output
|
output = output.sub(/\A(.*?)(\s*<\?\s*xml)/m) do
|
||||||
output = output.sub(/\A#{Regexp.escape(garbage)}/m, "")
|
warn_plist_garbage(T.must(Regexp.last_match(1)))
|
||||||
warn_plist_garbage(garbage)
|
Regexp.last_match(2)
|
||||||
end
|
end
|
||||||
|
|
||||||
if %r{<\s*/\s*plist\s*>(?<garbage>.*?)\Z}m =~ output
|
output = output.sub(%r{(<\s*/\s*plist\s*>\s*)(.*?)\Z}m) do
|
||||||
output = output.sub(/#{Regexp.escape(garbage)}\Z/, "")
|
warn_plist_garbage(T.must(Regexp.last_match(2)))
|
||||||
warn_plist_garbage(garbage)
|
Regexp.last_match(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
Plist.parse_xml(output)
|
Plist.parse_xml(output)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { params(garbage: String).void }
|
||||||
def warn_plist_garbage(garbage)
|
def warn_plist_garbage(garbage)
|
||||||
return unless verbose?
|
return unless verbose?
|
||||||
return unless garbage.match?(/\S/)
|
return unless garbage.match?(/\S/)
|
||||||
|
@ -8,7 +8,7 @@ shared_examples "#uninstall_phase or #zap_phase" do
|
|||||||
|
|
||||||
let(:artifact_dsl_key) { described_class.dsl_key }
|
let(:artifact_dsl_key) { described_class.dsl_key }
|
||||||
let(:artifact) { cask.artifacts.find { |a| a.is_a?(described_class) } }
|
let(:artifact) { cask.artifacts.find { |a| a.is_a?(described_class) } }
|
||||||
let(:fake_system_command) { FakeSystemCommand }
|
let(:fake_system_command) { class_double(SystemCommand) }
|
||||||
|
|
||||||
context "using :launchctl" do
|
context "using :launchctl" do
|
||||||
let(:cask) { Cask::CaskLoader.load(cask_path("with-#{artifact_dsl_key}-launchctl")) }
|
let(:cask) { Cask::CaskLoader.load(cask_path("with-#{artifact_dsl_key}-launchctl")) }
|
||||||
@ -31,41 +31,37 @@ shared_examples "#uninstall_phase or #zap_phase" do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "works when job is owned by user" do
|
it "works when job is owned by user" do
|
||||||
FakeSystemCommand.stubs_command(
|
allow(fake_system_command).to receive(:run)
|
||||||
launchctl_list_cmd,
|
.with("/bin/launchctl", args: ["list", "my.fancy.package.service"], print_stderr: false, sudo: false)
|
||||||
service_info,
|
.and_return(instance_double(SystemCommand::Result, stdout: service_info))
|
||||||
)
|
allow(fake_system_command).to receive(:run)
|
||||||
|
.with("/bin/launchctl", args: ["list", "my.fancy.package.service"], print_stderr: false, sudo: true)
|
||||||
|
.and_return(instance_double(SystemCommand::Result, stdout: unknown_response))
|
||||||
|
|
||||||
FakeSystemCommand.stubs_command(
|
expect(fake_system_command).to receive(:run!)
|
||||||
sudo(launchctl_list_cmd),
|
.with("/bin/launchctl", args: ["remove", "my.fancy.package.service"], sudo: false)
|
||||||
unknown_response,
|
.and_return(instance_double(SystemCommand::Result))
|
||||||
)
|
|
||||||
|
|
||||||
FakeSystemCommand.expects_command(launchctl_remove_cmd)
|
|
||||||
|
|
||||||
subject.public_send(:"#{artifact_dsl_key}_phase", command: fake_system_command)
|
subject.public_send(:"#{artifact_dsl_key}_phase", command: fake_system_command)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "works when job is owned by system" do
|
it "works when job is owned by system" do
|
||||||
FakeSystemCommand.stubs_command(
|
allow(fake_system_command).to receive(:run)
|
||||||
launchctl_list_cmd,
|
.with("/bin/launchctl", args: ["list", "my.fancy.package.service"], print_stderr: false, sudo: false)
|
||||||
unknown_response,
|
.and_return(instance_double(SystemCommand::Result, stdout: unknown_response))
|
||||||
)
|
allow(fake_system_command).to receive(:run)
|
||||||
|
.with("/bin/launchctl", args: ["list", "my.fancy.package.service"], print_stderr: false, sudo: true)
|
||||||
|
.and_return(instance_double(SystemCommand::Result, stdout: service_info))
|
||||||
|
|
||||||
FakeSystemCommand.stubs_command(
|
expect(fake_system_command).to receive(:run!)
|
||||||
sudo(launchctl_list_cmd),
|
.with("/bin/launchctl", args: ["remove", "my.fancy.package.service"], sudo: true)
|
||||||
service_info,
|
.and_return(instance_double(SystemCommand::Result))
|
||||||
)
|
|
||||||
|
|
||||||
FakeSystemCommand.expects_command(sudo(launchctl_remove_cmd))
|
|
||||||
|
|
||||||
subject.public_send(:"#{artifact_dsl_key}_phase", command: fake_system_command)
|
subject.public_send(:"#{artifact_dsl_key}_phase", command: fake_system_command)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "using :pkgutil" do
|
context "using :pkgutil" do
|
||||||
let(:fake_system_command) { class_double(SystemCommand) }
|
|
||||||
|
|
||||||
let(:cask) { Cask::CaskLoader.load(cask_path("with-#{artifact_dsl_key}-pkgutil")) }
|
let(:cask) { Cask::CaskLoader.load(cask_path("with-#{artifact_dsl_key}-pkgutil")) }
|
||||||
|
|
||||||
let(:main_pkg_id) { "my.fancy.package.main" }
|
let(:main_pkg_id) { "my.fancy.package.main" }
|
||||||
|
@ -6,7 +6,8 @@ require "test/cask/dsl/shared_examples/staged"
|
|||||||
|
|
||||||
describe Cask::DSL::Postflight, :cask do
|
describe Cask::DSL::Postflight, :cask do
|
||||||
let(:cask) { Cask::CaskLoader.load(cask_path("basic-cask")) }
|
let(:cask) { Cask::CaskLoader.load(cask_path("basic-cask")) }
|
||||||
let(:dsl) { described_class.new(cask, FakeSystemCommand) }
|
let(:fake_system_command) { class_double(SystemCommand) }
|
||||||
|
let(:dsl) { described_class.new(cask, fake_system_command) }
|
||||||
|
|
||||||
it_behaves_like Cask::DSL::Base
|
it_behaves_like Cask::DSL::Base
|
||||||
|
|
||||||
|
@ -6,7 +6,8 @@ require "test/cask/dsl/shared_examples/staged"
|
|||||||
|
|
||||||
describe Cask::DSL::Preflight, :cask do
|
describe Cask::DSL::Preflight, :cask do
|
||||||
let(:cask) { Cask::CaskLoader.load(cask_path("basic-cask")) }
|
let(:cask) { Cask::CaskLoader.load(cask_path("basic-cask")) }
|
||||||
let(:dsl) { described_class.new(cask, FakeSystemCommand) }
|
let(:fake_system_command) { class_double(SystemCommand) }
|
||||||
|
let(:dsl) { described_class.new(cask, fake_system_command) }
|
||||||
|
|
||||||
it_behaves_like Cask::DSL::Base
|
it_behaves_like Cask::DSL::Base
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
require "cask/staged"
|
require "cask/staged"
|
||||||
|
|
||||||
shared_examples Cask::Staged do
|
shared_examples Cask::Staged do
|
||||||
let(:existing_path) { Pathname.new("/path/to/file/that/exists") }
|
let(:existing_path) { Pathname("/path/to/file/that/exists") }
|
||||||
let(:non_existent_path) { Pathname.new("/path/to/file/that/does/not/exist") }
|
let(:non_existent_path) { Pathname("/path/to/file/that/does/not/exist") }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow(existing_path).to receive(:exist?).and_return(true)
|
allow(existing_path).to receive(:exist?).and_return(true)
|
||||||
@ -17,9 +17,8 @@ shared_examples Cask::Staged do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "can run system commands with list-form arguments" do
|
it "can run system commands with list-form arguments" do
|
||||||
FakeSystemCommand.expects_command(
|
expect(fake_system_command).to receive(:run!)
|
||||||
["echo", "homebrew-cask", "rocks!"],
|
.with("echo", args: ["homebrew-cask", "rocks!"])
|
||||||
)
|
|
||||||
|
|
||||||
staged.system_command("echo", args: ["homebrew-cask", "rocks!"])
|
staged.system_command("echo", args: ["homebrew-cask", "rocks!"])
|
||||||
end
|
end
|
||||||
@ -28,9 +27,8 @@ shared_examples Cask::Staged do
|
|||||||
fake_pathname = existing_path
|
fake_pathname = existing_path
|
||||||
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
||||||
|
|
||||||
FakeSystemCommand.expects_command(
|
expect(fake_system_command).to receive(:run!)
|
||||||
["/bin/chmod", "-R", "--", "777", fake_pathname],
|
.with("/bin/chmod", args: ["-R", "--", "777", fake_pathname], sudo: false)
|
||||||
)
|
|
||||||
|
|
||||||
staged.set_permissions(fake_pathname.to_s, "777")
|
staged.set_permissions(fake_pathname.to_s, "777")
|
||||||
end
|
end
|
||||||
@ -39,9 +37,8 @@ shared_examples Cask::Staged do
|
|||||||
fake_pathname = existing_path
|
fake_pathname = existing_path
|
||||||
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
||||||
|
|
||||||
FakeSystemCommand.expects_command(
|
expect(fake_system_command).to receive(:run!)
|
||||||
["/bin/chmod", "-R", "--", "777", fake_pathname, fake_pathname],
|
.with("/bin/chmod", args: ["-R", "--", "777", fake_pathname, fake_pathname], sudo: false)
|
||||||
)
|
|
||||||
|
|
||||||
staged.set_permissions([fake_pathname.to_s, fake_pathname.to_s], "777")
|
staged.set_permissions([fake_pathname.to_s, fake_pathname.to_s], "777")
|
||||||
end
|
end
|
||||||
@ -58,9 +55,8 @@ shared_examples Cask::Staged do
|
|||||||
allow(User).to receive(:current).and_return(User.new("fake_user"))
|
allow(User).to receive(:current).and_return(User.new("fake_user"))
|
||||||
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
||||||
|
|
||||||
FakeSystemCommand.expects_command(
|
expect(fake_system_command).to receive(:run!)
|
||||||
sudo("/usr/sbin/chown", "-R", "--", "fake_user:staff", fake_pathname),
|
.with("/usr/sbin/chown", args: ["-R", "--", "fake_user:staff", fake_pathname], sudo: true)
|
||||||
)
|
|
||||||
|
|
||||||
staged.set_ownership(fake_pathname.to_s)
|
staged.set_ownership(fake_pathname.to_s)
|
||||||
end
|
end
|
||||||
@ -71,9 +67,8 @@ shared_examples Cask::Staged do
|
|||||||
allow(User).to receive(:current).and_return(User.new("fake_user"))
|
allow(User).to receive(:current).and_return(User.new("fake_user"))
|
||||||
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
||||||
|
|
||||||
FakeSystemCommand.expects_command(
|
expect(fake_system_command).to receive(:run!)
|
||||||
sudo("/usr/sbin/chown", "-R", "--", "fake_user:staff", fake_pathname, fake_pathname),
|
.with("/usr/sbin/chown", args: ["-R", "--", "fake_user:staff", fake_pathname, fake_pathname], sudo: true)
|
||||||
)
|
|
||||||
|
|
||||||
staged.set_ownership([fake_pathname.to_s, fake_pathname.to_s])
|
staged.set_ownership([fake_pathname.to_s, fake_pathname.to_s])
|
||||||
end
|
end
|
||||||
@ -83,9 +78,8 @@ shared_examples Cask::Staged do
|
|||||||
|
|
||||||
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
allow(staged).to receive(:Pathname).and_return(fake_pathname)
|
||||||
|
|
||||||
FakeSystemCommand.expects_command(
|
expect(fake_system_command).to receive(:run!)
|
||||||
sudo("/usr/sbin/chown", "-R", "--", "other_user:other_group", fake_pathname),
|
.with("/usr/sbin/chown", args: ["-R", "--", "other_user:other_group", fake_pathname], sudo: true)
|
||||||
)
|
|
||||||
|
|
||||||
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")
|
||||||
end
|
end
|
||||||
|
@ -5,7 +5,7 @@ require "test/cask/dsl/shared_examples/base"
|
|||||||
|
|
||||||
describe Cask::DSL::UninstallPostflight, :cask do
|
describe Cask::DSL::UninstallPostflight, :cask do
|
||||||
let(:cask) { Cask::CaskLoader.load(cask_path("basic-cask")) }
|
let(:cask) { Cask::CaskLoader.load(cask_path("basic-cask")) }
|
||||||
let(:dsl) { described_class.new(cask, FakeSystemCommand) }
|
let(:dsl) { described_class.new(cask, class_double(SystemCommand)) }
|
||||||
|
|
||||||
it_behaves_like Cask::DSL::Base
|
it_behaves_like Cask::DSL::Base
|
||||||
end
|
end
|
||||||
|
@ -6,7 +6,8 @@ require "test/cask/dsl/shared_examples/staged"
|
|||||||
|
|
||||||
describe Cask::DSL::UninstallPreflight, :cask do
|
describe Cask::DSL::UninstallPreflight, :cask do
|
||||||
let(:cask) { Cask::CaskLoader.load(cask_path("basic-cask")) }
|
let(:cask) { Cask::CaskLoader.load(cask_path("basic-cask")) }
|
||||||
let(:dsl) { described_class.new(cask, FakeSystemCommand) }
|
let(:fake_system_command) { class_double(SystemCommand) }
|
||||||
|
let(:dsl) { described_class.new(cask, fake_system_command) }
|
||||||
|
|
||||||
it_behaves_like Cask::DSL::Base
|
it_behaves_like Cask::DSL::Base
|
||||||
|
|
||||||
|
@ -153,8 +153,12 @@ describe Cask::Pkg, :cask do
|
|||||||
"/usr/sbin/pkgutil",
|
"/usr/sbin/pkgutil",
|
||||||
args: ["--pkg-info-plist", pkg_id],
|
args: ["--pkg-info-plist", pkg_id],
|
||||||
).and_return(
|
).and_return(
|
||||||
SystemCommand::Result.new(nil, [[:stdout, pkg_info_plist]], instance_double(Process::Status, exitstatus: 0),
|
SystemCommand::Result.new(
|
||||||
secrets: []),
|
["/usr/sbin/pkgutil", "--pkg-info-plist", pkg_id],
|
||||||
|
[[:stdout, pkg_info_plist]],
|
||||||
|
instance_double(Process::Status, exitstatus: 0),
|
||||||
|
secrets: [],
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
info = pkg.info
|
info = pkg.info
|
||||||
|
@ -1,74 +0,0 @@
|
|||||||
# typed: true
|
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
def sudo(*args)
|
|
||||||
["/usr/bin/sudo", "-E", "--"] + args.flatten
|
|
||||||
end
|
|
||||||
|
|
||||||
class FakeSystemCommand
|
|
||||||
def self.responses
|
|
||||||
@responses ||= {}
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.expectations
|
|
||||||
@expectations ||= {}
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.system_calls
|
|
||||||
@system_calls ||= Hash.new(0)
|
|
||||||
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.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
|
|
||||||
end
|
|
||||||
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
|
|
||||||
|
|
||||||
response = responses[command]
|
|
||||||
if response.respond_to?(:call)
|
|
||||||
response.call(command_string, options)
|
|
||||||
else
|
|
||||||
SystemCommand::Result.new(command, [[:stdout, response]], OpenStruct.new(exitstatus: 0), secrets: [])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.run!(command, options = {})
|
|
||||||
run(command, options.merge(must_succeed: true))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
RSpec.configure do |config|
|
|
||||||
config.after do
|
|
||||||
FakeSystemCommand.verify_expectations!
|
|
||||||
ensure
|
|
||||||
FakeSystemCommand.clear
|
|
||||||
end
|
|
||||||
end
|
|
@ -4,7 +4,6 @@
|
|||||||
require "cask/config"
|
require "cask/config"
|
||||||
require "cask/cache"
|
require "cask/cache"
|
||||||
|
|
||||||
require "test/support/helper/cask/fake_system_command"
|
|
||||||
require "test/support/helper/cask/install_helper"
|
require "test/support/helper/cask/install_helper"
|
||||||
require "test/support/helper/cask/never_sudo_system_command"
|
require "test/support/helper/cask/never_sudo_system_command"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user