Refactor artifacts.

This commit is contained in:
Markus Reiter 2017-03-10 09:33:48 +01:00
parent b38c52f930
commit 621b67e531
7 changed files with 80 additions and 104 deletions

View File

@ -32,10 +32,7 @@ module Hbc
def self.read_script_arguments(arguments, stanza, default_arguments = {}, override_arguments = {}, key = nil) def self.read_script_arguments(arguments, stanza, default_arguments = {}, override_arguments = {}, key = nil)
# TODO: when stanza names are harmonized with class names, # TODO: when stanza names are harmonized with class names,
# stanza may not be needed as an explicit argument # stanza may not be needed as an explicit argument
description = stanza.to_s description = key ? "#{stanza} #{key.inspect}" : stanza.to_s
if key
description.concat(" #{key.inspect}")
end
# backward-compatible string value # backward-compatible string value
arguments = { executable: arguments } if arguments.is_a?(String) arguments = { executable: arguments } if arguments.is_a?(String)

View File

@ -7,8 +7,8 @@ module Hbc
super if CLI.binaries? super if CLI.binaries?
end end
def link(artifact_spec) def link
super(artifact_spec) super
FileUtils.chmod "+x", source FileUtils.chmod "+x", source
end end
end end

View File

@ -8,61 +8,38 @@ module Hbc
end end
def install_phase def install_phase
each_artifact do |artifact| each_artifact(&method(:move))
load_specification(artifact)
next unless preflight_checks
delete if Utils.path_occupied?(target) && force
move
end
end end
def uninstall_phase def uninstall_phase
each_artifact do |artifact| each_artifact(&method(:delete))
load_specification(artifact)
next unless File.exist?(target)
delete
end
end end
private private
def each_artifact
# the sort is for predictability between Ruby versions
@cask.artifacts[self.class.artifact_dsl_key].sort.each do |artifact|
yield artifact
end
end
def move def move
ohai "Moving #{self.class.artifact_english_name} '#{source.basename}' to '#{target}'" if Utils.path_occupied?(target)
message = "It seems there is already #{self.class.artifact_english_article} #{self.class.artifact_english_name} at '#{target}'"
raise CaskError, "#{message}." unless force
opoo "#{message}; overwriting."
delete
end
unless source.exist?
raise CaskError, "It seems the #{self.class.artifact_english_name} source '#{source}' is not there."
end
ohai "Moving #{self.class.artifact_english_name} '#{source.basename}' to '#{target}'."
target.dirname.mkpath target.dirname.mkpath
FileUtils.move(source, target) FileUtils.move(source, target)
add_altname_metadata target, source.basename.to_s add_altname_metadata target, source.basename.to_s
end end
def preflight_checks
if Utils.path_occupied?(target)
raise CaskError, warning_target_exists << "." unless force
opoo(warning_target_exists { |s| s << "overwriting." })
end
unless source.exist?
message = "It seems the #{self.class.artifact_english_name} source is not there: '#{source}'"
raise CaskError, message
end
true
end
def warning_target_exists
message_parts = [
"It seems there is already #{self.class.artifact_english_article} #{self.class.artifact_english_name} at '#{target}'",
]
yield(message_parts) if block_given?
message_parts.join("; ")
end
def delete def delete
ohai "Removing #{self.class.artifact_english_name}: '#{target}'" ohai "Removing #{self.class.artifact_english_name} '#{target}'."
raise CaskError, "Cannot remove undeletable #{self.class.artifact_english_name}" if MacOS.undeletable?(target) return unless Utils.path_occupied?(target)
raise CaskError, "Cannot remove undeletable #{self.class.artifact_english_name}." if MacOS.undeletable?(target)
if force if force
Utils.gain_permissions_remove(target, command: @command) Utils.gain_permissions_remove(target, command: @command)

View File

@ -42,6 +42,14 @@ module Hbc
print_stderr: false) print_stderr: false)
end end
def each_artifact
# the sort is for predictability between Ruby versions
@cask.artifacts[self.class.artifact_dsl_key].sort.each do |artifact|
load_specification(artifact)
yield
end
end
def load_specification(artifact_spec) def load_specification(artifact_spec)
source_string, target_hash = artifact_spec source_string, target_hash = artifact_spec
raise CaskInvalidError if source_string.nil? raise CaskInvalidError if source_string.nil?

View File

@ -11,55 +11,48 @@ module Hbc
"#{artifact_english_name} #{link_type_english_name}s" "#{artifact_english_name} #{link_type_english_name}s"
end end
def self.islink?(path)
path.symlink?
end
def link(artifact_spec)
load_specification artifact_spec
return unless preflight_checks(source, target)
ohai "#{self.class.link_type_english_name}ing #{self.class.artifact_english_name} '#{source.basename}' to '#{target}'"
create_filesystem_link(source, target)
end
def unlink(artifact_spec)
load_specification artifact_spec
return unless self.class.islink?(target)
ohai "Removing #{self.class.artifact_english_name} #{self.class.link_type_english_name.downcase}: '#{target}'"
target.delete
end
def install_phase def install_phase
@cask.artifacts[self.class.artifact_dsl_key].each(&method(:link)) each_artifact(&method(:link))
end end
def uninstall_phase def uninstall_phase
@cask.artifacts[self.class.artifact_dsl_key].each(&method(:unlink)) each_artifact(&method(:unlink))
end end
def preflight_checks(source, target) private
if target.exist? && !self.class.islink?(target)
def link
unless source.exist?
raise CaskError, "It seems the #{self.class.link_type_english_name.downcase} source '#{source}' is not there."
end
if target.exist? && !target.symlink?
raise CaskError, "It seems there is already #{self.class.artifact_english_article} #{self.class.artifact_english_name} at '#{target}'; not linking." raise CaskError, "It seems there is already #{self.class.artifact_english_article} #{self.class.artifact_english_name} at '#{target}'; not linking."
end end
unless source.exist?
raise CaskError, "It seems the #{self.class.link_type_english_name.downcase} source is not there: '#{source}'" ohai "Linking #{self.class.artifact_english_name} '#{source.basename}' to '#{target}'."
end create_filesystem_link(source, target)
true end
def unlink
return unless target.symlink?
ohai "Unlinking #{self.class.artifact_english_name} '#{target}'."
target.delete
end end
def create_filesystem_link(source, target) def create_filesystem_link(source, target)
Pathname.new(target).dirname.mkpath target.dirname.mkpath
@command.run!("/bin/ln", args: ["-hfs", "--", source, target]) @command.run!("/bin/ln", args: ["-h", "-f", "-s", "--", source, target])
add_altname_metadata source, target.basename.to_s add_altname_metadata source, target.basename.to_s
end end
def summarize_artifact(artifact_spec) def summarize_artifact(artifact_spec)
load_specification artifact_spec load_specification artifact_spec
if self.class.islink?(target) && target.exist? && target.readlink.exist? if target.symlink? && target.exist? && target.readlink.exist?
"#{printable_target} -> #{target.readlink} (#{target.readlink.abv})" "#{printable_target} -> #{target.readlink} (#{target.readlink.abv})"
else else
string = if self.class.islink?(target) string = if target.symlink?
"#{printable_target} -> #{target.readlink}" "#{printable_target} -> #{target.readlink}"
else else
printable_target printable_target

View File

@ -7,8 +7,8 @@ describe Hbc::Artifact::App, :cask do
let(:source_path) { cask.staged_path.join("Caffeine.app") } let(:source_path) { cask.staged_path.join("Caffeine.app") }
let(:target_path) { Hbc.appdir.join("Caffeine.app") } let(:target_path) { Hbc.appdir.join("Caffeine.app") }
let(:install_phase) { -> { app.install_phase } } let(:install_phase) { app.install_phase }
let(:uninstall_phase) { -> { app.uninstall_phase } } let(:uninstall_phase) { app.uninstall_phase }
before(:each) do before(:each) do
InstallHelper.install_without_artifacts(cask) InstallHelper.install_without_artifacts(cask)
@ -17,7 +17,7 @@ describe Hbc::Artifact::App, :cask do
describe "install_phase" do describe "install_phase" do
it "installs the given app using the proper target directory" do it "installs the given app using the proper target directory" do
shutup do shutup do
install_phase.call install_phase
end end
expect(target_path).to be_a_directory expect(target_path).to be_a_directory
@ -40,7 +40,7 @@ describe Hbc::Artifact::App, :cask do
FileUtils.mv(source_path, appsubdir) FileUtils.mv(source_path, appsubdir)
shutup do shutup do
install_phase.call install_phase
end end
expect(target_path).to be_a_directory expect(target_path).to be_a_directory
@ -53,7 +53,7 @@ describe Hbc::Artifact::App, :cask do
FileUtils.cp_r source_path, staged_app_copy FileUtils.cp_r source_path, staged_app_copy
shutup do shutup do
install_phase.call install_phase
end end
expect(target_path).to be_a_directory expect(target_path).to be_a_directory
@ -69,7 +69,7 @@ describe Hbc::Artifact::App, :cask do
end end
it "avoids clobbering an existing app" do it "avoids clobbering an existing app" do
expect(install_phase).to raise_error(Hbc::CaskError, "It seems there is already an App at '#{target_path}'.") expect { install_phase }.to raise_error(Hbc::CaskError, "It seems there is already an App at '#{target_path}'.")
expect(source_path).to be_a_directory expect(source_path).to be_a_directory
expect(target_path).to be_a_directory expect(target_path).to be_a_directory
@ -89,17 +89,17 @@ describe Hbc::Artifact::App, :cask do
describe "target is both writable and user-owned" do describe "target is both writable and user-owned" do
it "overwrites the existing app" do it "overwrites the existing app" do
stdout = <<-EOS.undent stdout = <<-EOS.undent
==> Removing App: '#{target_path}' ==> Removing App '#{target_path}'.
==> Moving App 'Caffeine.app' to '#{target_path}' ==> Moving App 'Caffeine.app' to '#{target_path}'.
EOS EOS
stderr = <<-EOS.undent stderr = <<-EOS.undent
Warning: It seems there is already an App at '#{target_path}'; overwriting. Warning: It seems there is already an App at '#{target_path}'; overwriting.
EOS EOS
expect { expect { install_phase }
expect(install_phase).to output(stdout).to_stdout .to output(stdout).to_stdout
}.to output(stderr).to_stderr .and output(stderr).to_stderr
expect(source_path).not_to exist expect(source_path).not_to exist
expect(target_path).to be_a_directory expect(target_path).to be_a_directory
@ -124,17 +124,17 @@ describe Hbc::Artifact::App, :cask do
.and_call_original .and_call_original
stdout = <<-EOS.undent stdout = <<-EOS.undent
==> Removing App: '#{target_path}' ==> Removing App '#{target_path}'.
==> Moving App 'Caffeine.app' to '#{target_path}' ==> Moving App 'Caffeine.app' to '#{target_path}'.
EOS EOS
stderr = <<-EOS.undent stderr = <<-EOS.undent
Warning: It seems there is already an App at '#{target_path}'; overwriting. Warning: It seems there is already an App at '#{target_path}'; overwriting.
EOS EOS
expect { expect { install_phase }
expect(install_phase).to output(stdout).to_stdout .to output(stdout).to_stdout
}.to output(stderr).to_stderr .and output(stderr).to_stderr
expect(source_path).not_to exist expect(source_path).not_to exist
expect(target_path).to be_a_directory expect(target_path).to be_a_directory
@ -160,7 +160,7 @@ describe Hbc::Artifact::App, :cask do
end end
it "leaves the target alone" do it "leaves the target alone" do
expect(install_phase).to raise_error(Hbc::CaskError, "It seems there is already an App at '#{target_path}'.") expect { install_phase }.to raise_error(Hbc::CaskError, "It seems there is already an App at '#{target_path}'.")
expect(target_path).to be_a_symlink expect(target_path).to be_a_symlink
end end
@ -169,17 +169,17 @@ describe Hbc::Artifact::App, :cask do
it "overwrites the existing app" do it "overwrites the existing app" do
stdout = <<-EOS.undent stdout = <<-EOS.undent
==> Removing App: '#{target_path}' ==> Removing App '#{target_path}'.
==> Moving App 'Caffeine.app' to '#{target_path}' ==> Moving App 'Caffeine.app' to '#{target_path}'.
EOS EOS
stderr = <<-EOS.undent stderr = <<-EOS.undent
Warning: It seems there is already an App at '#{target_path}'; overwriting. Warning: It seems there is already an App at '#{target_path}'; overwriting.
EOS EOS
expect { expect { install_phase }
expect(install_phase).to output(stdout).to_stdout .to output(stdout).to_stdout
}.to output(stderr).to_stderr .and output(stderr).to_stderr
expect(source_path).not_to exist expect(source_path).not_to exist
expect(target_path).to be_a_directory expect(target_path).to be_a_directory
@ -193,22 +193,22 @@ describe Hbc::Artifact::App, :cask do
it "gives a warning if the source doesn't exist" do it "gives a warning if the source doesn't exist" do
source_path.rmtree source_path.rmtree
message = "It seems the App source is not there: '#{source_path}'" message = "It seems the App source '#{source_path}' is not there."
expect(install_phase).to raise_error(Hbc::CaskError, message) expect { install_phase }.to raise_error(Hbc::CaskError, message)
end end
end end
describe "uninstall_phase" do describe "uninstall_phase" do
it "deletes managed apps" do it "deletes managed apps" do
shutup do shutup do
install_phase.call install_phase
end end
expect(target_path).to exist expect(target_path).to exist
shutup do shutup do
uninstall_phase.call uninstall_phase
end end
expect(target_path).not_to exist expect(target_path).not_to exist
@ -226,7 +226,7 @@ describe Hbc::Artifact::App, :cask do
describe "app is correctly installed" do describe "app is correctly installed" do
it "returns the path to the app" do it "returns the path to the app" do
shutup do shutup do
install_phase.call install_phase
end end
expect(contents).to eq(["#{target_path} (#{target_path.abv})"]) expect(contents).to eq(["#{target_path} (#{target_path.abv})"])

View File

@ -47,6 +47,7 @@ describe Hbc::CLI::Uninstall, :cask do
end end
expect(cask).to be_installed expect(cask).to be_installed
expect(Hbc.appdir.join("MyFancyApp.app")).to exist
expect { expect {
shutup do shutup do