diff options
| author | Ben Muschol | 2017-09-27 16:36:10 -0400 | 
|---|---|---|
| committer | GitHub | 2017-09-27 16:36:10 -0400 | 
| commit | 2d6bd0400785b5fb061f793f70736f12e6ec8231 (patch) | |
| tree | fd0abc8937fc85fb49714ad9dc4a3735fa58242f /Library/Homebrew/cask | |
| parent | fe5c885da0b8b69a5de74647e4181b137acb835f (diff) | |
| parent | cb139ca381cb7f00a4dfdc21482515f103aed417 (diff) | |
| download | brew-2d6bd0400785b5fb061f793f70736f12e6ec8231.tar.bz2 | |
Merge branch 'master' into check-for-master-no-refactor
Diffstat (limited to 'Library/Homebrew/cask')
42 files changed, 614 insertions, 573 deletions
diff --git a/Library/Homebrew/cask/lib/hbc/artifact.rb b/Library/Homebrew/cask/lib/hbc/artifact.rb index 074d15017..cb15ec051 100644 --- a/Library/Homebrew/cask/lib/hbc/artifact.rb +++ b/Library/Homebrew/cask/lib/hbc/artifact.rb @@ -33,7 +33,7 @@ module Hbc      # We want to extract nested containers before we      # handle any other artifacts.      # -    TYPES = [ +    CLASSES = [        PreflightBlock,        Uninstall,        NestedContainer, @@ -60,12 +60,9 @@ module Hbc        Zap,      ].freeze -    def self.for_cask(cask, options = {}) +    def self.for_cask(cask)        odebug "Determining which artifacts are present in Cask #{cask}" - -      TYPES -        .select { |klass| klass.me?(cask) } -        .map { |klass| klass.new(cask, options) } +      CLASSES.flat_map { |klass| klass.for_cask(cask) }      end    end  end diff --git a/Library/Homebrew/cask/lib/hbc/artifact/base.rb b/Library/Homebrew/cask/lib/hbc/artifact/abstract_artifact.rb index ae15552a4..1b18cc6e7 100644 --- a/Library/Homebrew/cask/lib/hbc/artifact/base.rb +++ b/Library/Homebrew/cask/lib/hbc/artifact/abstract_artifact.rb @@ -1,34 +1,28 @@  module Hbc    module Artifact -    class Base +    class AbstractArtifact        extend Predicable -      def self.artifact_name -        @artifact_name ||= name.sub(/^.*:/, "").gsub(/(.)([A-Z])/, '\1_\2').downcase +      def self.english_name +        @english_name ||= name.sub(/^.*:/, "").gsub(/(.)([A-Z])/, '\1 \2')        end -      def self.artifact_english_name -        @artifact_english_name ||= name.sub(/^.*:/, "").gsub(/(.)([A-Z])/, '\1 \2') +      def self.english_article +        @english_article ||= (english_name =~ /^[aeiou]/i) ? "an" : "a"        end -      def self.artifact_english_article -        @artifact_english_article ||= (artifact_english_name =~ /^[aeiou]/i) ? "an" : "a" +      def self.dsl_key +        @dsl_key ||= name.sub(/^.*:/, "").gsub(/(.)([A-Z])/, '\1_\2').downcase.to_sym        end -      def self.artifact_dsl_key -        @artifact_dsl_key ||= artifact_name.to_sym +      def self.dirmethod +        @dirmethod ||= "#{dsl_key}dir".to_sym        end -      def self.artifact_dirmethod -        @artifact_dirmethod ||= "#{artifact_name}dir".to_sym +      def self.for_cask(cask) +        cask.artifacts[dsl_key].to_a        end -      def self.me?(cask) -        cask.artifacts[artifact_dsl_key].any? -      end - -      attr_reader :force -        # TODO: this sort of logic would make more sense in dsl.rb, or a        #       constructor called from dsl.rb, so long as that isn't slow.        def self.read_script_arguments(arguments, stanza, default_arguments = {}, override_arguments = {}, key = nil) @@ -63,17 +57,14 @@ module Hbc          [executable, arguments]        end -      def summary -        {} -      end +      attr_reader :cask -      attr_predicate :force?, :verbose? - -      def initialize(cask, command: SystemCommand, force: false, verbose: false) +      def initialize(cask)          @cask = cask -        @command = command -        @force = force -        @verbose = verbose +      end + +      def to_s +        "#{summarize} (#{self.class.english_name})"        end      end    end diff --git a/Library/Homebrew/cask/lib/hbc/artifact/abstract_flight_block.rb b/Library/Homebrew/cask/lib/hbc/artifact/abstract_flight_block.rb index be3050acb..4e8edbc11 100644 --- a/Library/Homebrew/cask/lib/hbc/artifact/abstract_flight_block.rb +++ b/Library/Homebrew/cask/lib/hbc/artifact/abstract_flight_block.rb @@ -1,39 +1,51 @@ -require "hbc/artifact/base" +require "hbc/artifact/abstract_artifact"  module Hbc    module Artifact -    class AbstractFlightBlock < Base -      def self.artifact_dsl_key +    class AbstractFlightBlock < AbstractArtifact +      def self.dsl_key          super.to_s.sub(/_block$/, "").to_sym        end -      def self.uninstall_artifact_dsl_key -        artifact_dsl_key.to_s.prepend("uninstall_").to_sym +      def self.uninstall_dsl_key +        dsl_key.to_s.prepend("uninstall_").to_sym        end -      def self.class_for_dsl_key(dsl_key) -        Object.const_get("Hbc::DSL::#{dsl_key.to_s.split("_").collect(&:capitalize).join}") +      def self.for_cask(cask) +        [dsl_key, uninstall_dsl_key].flat_map do |key| +          [*cask.artifacts[key]].map { |block| new(cask, key => block) } +        end        end -      def self.me?(cask) -        cask.artifacts[artifact_dsl_key].any? || -          cask.artifacts[uninstall_artifact_dsl_key].any? +      attr_reader :directives + +      def initialize(cask, **directives) +        super(cask) +        @directives = directives        end -      def install_phase -        abstract_phase(self.class.artifact_dsl_key) +      def install_phase(**) +        abstract_phase(self.class.dsl_key)        end -      def uninstall_phase -        abstract_phase(self.class.uninstall_artifact_dsl_key) +      def uninstall_phase(**) +        abstract_phase(self.class.uninstall_dsl_key)        end        private +      def class_for_dsl_key(dsl_key) +        namespace = self.class.name.to_s.sub(/::.*::.*$/, "") +        self.class.const_get("#{namespace}::DSL::#{dsl_key.to_s.split("_").collect(&:capitalize).join}") +      end +        def abstract_phase(dsl_key) -        @cask.artifacts[dsl_key].each do |block| -          self.class.class_for_dsl_key(dsl_key).new(@cask).instance_eval(&block) -        end +        return if (block = directives[dsl_key]).nil? +        class_for_dsl_key(dsl_key).new(cask).instance_eval(&block) +      end + +      def summarize +        directives.keys.map(&:to_s).join(", ")        end      end    end diff --git a/Library/Homebrew/cask/lib/hbc/artifact/uninstall_base.rb b/Library/Homebrew/cask/lib/hbc/artifact/abstract_uninstall.rb index d92644150..badd549ce 100644 --- a/Library/Homebrew/cask/lib/hbc/artifact/uninstall_base.rb +++ b/Library/Homebrew/cask/lib/hbc/artifact/abstract_uninstall.rb @@ -1,11 +1,11 @@  require "pathname"  require "timeout" -require "hbc/artifact/base" +require "hbc/artifact/abstract_artifact"  module Hbc    module Artifact -    class UninstallBase < Base +    class AbstractUninstall < AbstractArtifact        ORDERED_DIRECTIVES = [          :early_script,          :launchctl, @@ -20,26 +20,42 @@ module Hbc          :rmdir,        ].freeze -      def dispatch_uninstall_directives -        directives_set = @cask.artifacts[stanza] +      def self.from_args(cask, **directives) +        new(cask, directives) +      end + +      attr_reader :directives + +      def initialize(cask, directives) +        super(cask) +        directives[:signal] = [*directives[:signal]].flatten.each_slice(2).to_a +        @directives = directives +      end + +      def to_h +        directives.to_h +      end + +      def summarize +        to_h.map { |key, val| [*val].map { |v| "#{key.inspect} => #{v.inspect}" }.join(", ") }.join(", ") +      end + +      private + +      def dispatch_uninstall_directives(**options)          ohai "Running #{stanza} process for #{@cask}; your password may be necessary" -        directives_set.each do |directives| -          warn_for_unknown_directives(directives) -        end +        warn_for_unknown_directives(directives)          ORDERED_DIRECTIVES.each do |directive_sym| -          directives_set.select { |h| h.key?(directive_sym) }.each do |directives| -            args = directives[directive_sym] -            send("uninstall_#{directive_sym}", *(args.is_a?(Hash) ? [args] : args)) -          end +          next unless directives.key?(directive_sym) +          args = directives[directive_sym] +          send("uninstall_#{directive_sym}", *(args.is_a?(Hash) ? [args] : args), **options)          end        end -      private -        def stanza -        self.class.artifact_dsl_key +        self.class.dsl_key        end        def warn_for_unknown_directives(directives) @@ -51,18 +67,18 @@ module Hbc        # Preserve prior functionality of script which runs first. Should rarely be needed.        # :early_script should not delete files, better defer that to :script.        # If Cask writers never need :early_script it may be removed in the future. -      def uninstall_early_script(directives) -        uninstall_script(directives, directive_name: :early_script) +      def uninstall_early_script(directives, **options) +        uninstall_script(directives, directive_name: :early_script, **options)        end        # :launchctl must come before :quit/:signal for cases where app would instantly re-launch -      def uninstall_launchctl(*services) +      def uninstall_launchctl(*services, command: nil, **_)          services.each do |service|            ohai "Removing launchctl service #{service}"            [false, true].each do |with_sudo| -            plist_status = @command.run("/bin/launchctl", args: ["list", service], sudo: with_sudo, print_stderr: false).stdout +            plist_status = command.run("/bin/launchctl", args: ["list", service], sudo: with_sudo, print_stderr: false).stdout              if plist_status =~ /^\{/ -              @command.run!("/bin/launchctl", args: ["remove", service], sudo: with_sudo) +              command.run!("/bin/launchctl", args: ["remove", service], sudo: with_sudo)                sleep 1              end              paths = ["/Library/LaunchAgents/#{service}.plist", @@ -70,38 +86,38 @@ module Hbc              paths.each { |elt| elt.prepend(ENV["HOME"]) } unless with_sudo              paths = paths.map { |elt| Pathname(elt) }.select(&:exist?)              paths.each do |path| -              @command.run!("/bin/rm", args: ["-f", "--", path], sudo: with_sudo) +              command.run!("/bin/rm", args: ["-f", "--", path], sudo: with_sudo)              end              # undocumented and untested: pass a path to uninstall :launchctl              next unless Pathname(service).exist? -            @command.run!("/bin/launchctl", args: ["unload", "-w", "--", service], sudo: with_sudo) -            @command.run!("/bin/rm",        args: ["-f", "--", service], sudo: with_sudo) +            command.run!("/bin/launchctl", args: ["unload", "-w", "--", service], sudo: with_sudo) +            command.run!("/bin/rm",        args: ["-f", "--", service], sudo: with_sudo)              sleep 1            end          end        end -      def running_processes(bundle_id) -        @command.run!("/bin/launchctl", args: ["list"]).stdout.lines -                .map { |line| line.chomp.split("\t") } -                .map { |pid, state, id| [pid.to_i, state.to_i, id] } -                .select do |fields| -                  next if fields[0].zero? -                  fields[2] =~ /^#{Regexp.escape(bundle_id)}($|\.\d+)/ -                end +      def running_processes(bundle_id, command: nil) +        command.run!("/bin/launchctl", args: ["list"]).stdout.lines +               .map { |line| line.chomp.split("\t") } +               .map { |pid, state, id| [pid.to_i, state.to_i, id] } +               .select do |fields| +                 next if fields[0].zero? +                 fields[2] =~ /^#{Regexp.escape(bundle_id)}($|\.\d+)/ +               end        end        # :quit/:signal must come before :kext so the kext will not be in use by a running process -      def uninstall_quit(*bundle_ids) +      def uninstall_quit(*bundle_ids, command: nil, **_)          bundle_ids.each do |bundle_id|            ohai "Quitting application ID #{bundle_id}" -          next if running_processes(bundle_id).empty? -          @command.run!("/usr/bin/osascript", args: ["-e", %Q(tell application id "#{bundle_id}" to quit)], sudo: true) +          next if running_processes(bundle_id, command: command).empty? +          command.run!("/usr/bin/osascript", args: ["-e", %Q(tell application id "#{bundle_id}" to quit)], sudo: true)            begin              Timeout.timeout(3) do                Kernel.loop do -                break if running_processes(bundle_id).empty? +                break if running_processes(bundle_id, command: command).empty?                end              end            rescue Timeout::Error @@ -111,15 +127,15 @@ module Hbc        end        # :signal should come after :quit so it can be used as a backup when :quit fails -      def uninstall_signal(*signals) -        signals.flatten.each_slice(2) do |pair| +      def uninstall_signal(*signals, command: nil, **_) +        signals.each do |pair|            unless pair.size == 2 -            raise CaskInvalidError.new(@cask, "Each #{stanza} :signal must consist of 2 elements.") +            raise CaskInvalidError.new(cask, "Each #{stanza} :signal must consist of 2 elements.")            end            signal, bundle_id = pair            ohai "Signalling '#{signal}' to application ID '#{bundle_id}'" -          pids = running_processes(bundle_id).map(&:first) +          pids = running_processes(bundle_id, command: command).map(&:first)            next unless pids.any?            # Note that unlike :quit, signals are sent from the current user (not            # upgraded to the superuser). This is a todo item for the future, but @@ -133,10 +149,10 @@ module Hbc          end        end -      def uninstall_login_item(*login_items) +      def uninstall_login_item(*login_items, command: nil, **_)          login_items.each do |name|            ohai "Removing login item #{name}" -          @command.run!("/usr/bin/osascript", +          command.run!("/usr/bin/osascript",                          args: ["-e", %Q(tell application "System Events" to delete every login item whose name is "#{name}")],                          sudo: false)            sleep 1 @@ -144,23 +160,24 @@ module Hbc        end        # :kext should be unloaded before attempting to delete the relevant file -      def uninstall_kext(*kexts) +      def uninstall_kext(*kexts, command: nil, **_)          kexts.each do |kext|            ohai "Unloading kernel extension #{kext}" -          is_loaded = @command.run!("/usr/sbin/kextstat", args: ["-l", "-b", kext], sudo: true).stdout +          is_loaded = command.run!("/usr/sbin/kextstat", args: ["-l", "-b", kext], sudo: true).stdout            if is_loaded.length > 1 -            @command.run!("/sbin/kextunload", args: ["-b", kext], sudo: true) +            command.run!("/sbin/kextunload", args: ["-b", kext], sudo: true)              sleep 1            end -          @command.run!("/usr/sbin/kextfind", args: ["-b", kext], sudo: true).stdout.chomp.lines.each do |kext_path| +          command.run!("/usr/sbin/kextfind", args: ["-b", kext], sudo: true).stdout.chomp.lines.each do |kext_path|              ohai "Removing kernel extension #{kext_path}" -            @command.run!("/bin/rm", args: ["-rf", kext_path], sudo: true) +            command.run!("/bin/rm", args: ["-rf", kext_path], sudo: true)            end          end        end        # :script must come before :pkgutil, :delete, or :trash so that the script file is not already deleted -      def uninstall_script(directives, directive_name: :script) +      def uninstall_script(directives, directive_name: :script, force: false, command: nil, **_) +        # TODO: Create a common `Script` class to run this and Artifact::Installer.          executable, script_arguments = self.class.read_script_arguments(directives,                                                                          "uninstall",                                                                          { must_succeed: true, sudo: false }, @@ -168,25 +185,25 @@ module Hbc                                                                          directive_name)          ohai "Running uninstall script #{executable}" -        raise CaskInvalidError.new(@cask, "#{stanza} :#{directive_name} without :executable.") if executable.nil? -        executable_path = @cask.staged_path.join(executable) +        raise CaskInvalidError.new(cask, "#{stanza} :#{directive_name} without :executable.") if executable.nil? +        executable_path = cask.staged_path.join(executable)          unless executable_path.exist?            message = "uninstall script #{executable} does not exist" -          raise CaskError, "#{message}." unless force? +          raise CaskError, "#{message}." unless force            opoo "#{message}, skipping."            return          end -        @command.run("/bin/chmod", args: ["--", "+x", executable_path]) -        @command.run(executable_path, script_arguments) +        command.run("/bin/chmod", args: ["--", "+x", executable_path]) +        command.run(executable_path, script_arguments)          sleep 1        end -      def uninstall_pkgutil(*pkgs) +      def uninstall_pkgutil(*pkgs, command: nil, **_)          ohai "Uninstalling packages:"          pkgs.each do |regex| -          Hbc::Pkg.all_matching(regex, @command).each do |pkg| +          Hbc::Pkg.all_matching(regex, command).each do |pkg|              puts pkg.package_id              pkg.uninstall            end @@ -215,28 +232,28 @@ module Hbc          end        end -      def uninstall_delete(*paths) +      def uninstall_delete(*paths, command: nil, **_)          return if paths.empty?          ohai "Removing files:"          each_resolved_path(:delete, paths) do |path, resolved_paths|            puts path -          @command.run!("/usr/bin/xargs", args: ["-0", "--", "/bin/rm", "-r", "-f", "--"], input: resolved_paths.join("\0"), sudo: true) +          command.run!("/usr/bin/xargs", args: ["-0", "--", "/bin/rm", "-r", "-f", "--"], input: resolved_paths.join("\0"), sudo: true)          end        end -      def uninstall_trash(*paths) +      def uninstall_trash(*paths, **options)          return if paths.empty?          resolved_paths = each_resolved_path(:trash, paths).to_a          ohai "Trashing files:"          puts resolved_paths.map(&:first) -        trash_paths(*resolved_paths.flat_map(&:last)) +        trash_paths(*resolved_paths.flat_map(&:last), **options)        end -      def trash_paths(*paths) -        @command.run!("/usr/bin/osascript", args: ["-e", <<-'EOS'.undent, *paths]) +      def trash_paths(*paths, command: nil, **_) +        command.run!("/usr/bin/osascript", args: ["-e", <<-'EOS'.undent, *paths])            on run argv              repeat with i from 1 to (count argv)                set item i of argv to (item i of argv as POSIX file) @@ -260,7 +277,7 @@ module Hbc          EOS        end -      def uninstall_rmdir(*directories) +      def uninstall_rmdir(*directories, command: nil, **_)          return if directories.empty?          ohai "Removing directories if empty:" @@ -268,10 +285,10 @@ module Hbc            puts path            resolved_paths.select(&:directory?).each do |resolved_path|              if (ds_store = resolved_path.join(".DS_Store")).exist? -              @command.run!("/bin/rm", args: ["-f", "--", ds_store], sudo: true, print_stderr: false) +              command.run!("/bin/rm", args: ["-f", "--", ds_store], sudo: true, print_stderr: false)              end -            @command.run("/bin/rmdir", args: ["--", resolved_path], sudo: true, print_stderr: false) +            command.run("/bin/rmdir", args: ["--", resolved_path], sudo: true, print_stderr: false)            end          end        end diff --git a/Library/Homebrew/cask/lib/hbc/artifact/artifact.rb b/Library/Homebrew/cask/lib/hbc/artifact/artifact.rb index b42db877d..0f37afade 100644 --- a/Library/Homebrew/cask/lib/hbc/artifact/artifact.rb +++ b/Library/Homebrew/cask/lib/hbc/artifact/artifact.rb @@ -5,21 +5,32 @@ require "hbc/utils/hash_validator"  module Hbc    module Artifact      class Artifact < Moved -      def self.artifact_english_name +      def self.english_name          "Generic Artifact"        end -      def self.artifact_dirmethod -        :appdir -      end +      def self.from_args(cask, *args) +        source_string, target_hash = args + +        if source_string.nil? +          raise CaskInvalidError.new(cask.token, "no source given for #{english_name}") +        end + +        unless target_hash.is_a?(Hash) +          raise CaskInvalidError.new(cask.token, "target required for #{english_name} '#{source_string}'") +        end -      def load_specification(artifact_spec) -        source_string, target_hash = artifact_spec -        raise CaskInvalidError.new(@cask.token, "no source given for artifact") if source_string.nil? -        @source = @cask.staged_path.join(source_string) -        raise CaskInvalidError.new(@cask.token, "target required for generic artifact #{source_string}") unless target_hash.is_a?(Hash)          target_hash.extend(HashValidator).assert_valid_keys(:target) -        @target = Pathname.new(target_hash[:target]) + +        new(cask, source_string, **target_hash) +      end + +      def self.resolve_target(target) +        Pathname(target) +      end + +      def initialize(cask, source, target: nil) +        super(cask, source, target: target)        end      end    end diff --git a/Library/Homebrew/cask/lib/hbc/artifact/binary.rb b/Library/Homebrew/cask/lib/hbc/artifact/binary.rb index 7178c2af6..68f4b074d 100644 --- a/Library/Homebrew/cask/lib/hbc/artifact/binary.rb +++ b/Library/Homebrew/cask/lib/hbc/artifact/binary.rb @@ -3,13 +3,13 @@ require "hbc/artifact/symlinked"  module Hbc    module Artifact      class Binary < Symlinked -      def link -        super +      def link(command: nil, **options) +        super(command: command, **options)          return if source.executable?          if source.writable?            FileUtils.chmod "+x", source          else -          @command.run!("/bin/chmod", args: ["+x", source], sudo: true) +          command.run!("/bin/chmod", args: ["+x", source], sudo: true)          end        end      end diff --git a/Library/Homebrew/cask/lib/hbc/artifact/installer.rb b/Library/Homebrew/cask/lib/hbc/artifact/installer.rb index be857696e..588bcabd5 100644 --- a/Library/Homebrew/cask/lib/hbc/artifact/installer.rb +++ b/Library/Homebrew/cask/lib/hbc/artifact/installer.rb @@ -1,29 +1,82 @@ -require "hbc/artifact/base" +require "hbc/artifact/abstract_artifact"  module Hbc    module Artifact -    class Installer < Base -      def install_phase -        @cask.artifacts[self.class.artifact_dsl_key].each do |artifact| -          if artifact.manual -            puts <<-EOS.undent -              To complete the installation of Cask #{@cask}, you must also -              run the installer at - -                '#{@cask.staged_path.join(artifact.manual)}' - -            EOS -          else -            executable, script_arguments = self.class.read_script_arguments(artifact.script, -                                                                            self.class.artifact_dsl_key.to_s, -                                                                            { must_succeed: true, sudo: false }, -                                                                            print_stdout: true) -            ohai "Running #{self.class.artifact_dsl_key} script #{executable}" -            raise CaskInvalidError.new(@cask, "#{self.class.artifact_dsl_key} missing executable") if executable.nil? -            executable_path = @cask.staged_path.join(executable) -            @command.run("/bin/chmod", args: ["--", "+x", executable_path]) if File.exist?(executable_path) -            @command.run(executable_path, script_arguments) +    class Installer < AbstractArtifact +      VALID_KEYS = Set.new [ +        :manual, +        :script, +      ] + +      module ManualInstaller +        def install_phase(**) +          puts <<-EOS.undent +            To complete the installation of Cask #{cask}, you must also +            run the installer at + +              '#{path}' +          EOS +        end +      end + +      module ScriptInstaller +        def install_phase(command: nil, **_) +          ohai "Running #{self.class.dsl_key} script '#{path.relative_path_from(cask.staged_path)}'" +          FileUtils.chmod "+x", path unless path.executable? +          command.run(path, **args) +        end +      end + +      def self.from_args(cask, **args) +        raise CaskInvalidError.new(cask, "'installer' stanza requires an argument.") if args.empty? + +        if args.key?(:script) && !args[:script].respond_to?(:key?) +          if args.key?(:executable) +            raise CaskInvalidError.new(cask, "'installer' stanza gave arguments for both :script and :executable.")            end + +          args[:executable] = args[:script] +          args.delete(:script) +          args = { script: args } +        end + +        unless args.keys.count == 1 +          raise CaskInvalidError.new(cask, "invalid 'installer' stanza: Only one of #{VALID_KEYS.inspect} is permitted.") +        end + +        args.extend(HashValidator).assert_valid_keys(*VALID_KEYS) +        new(cask, **args) +      end + +      attr_reader :path, :args + +      def initialize(cask, **args) +        super(cask) + +        if args.key?(:manual) +          @path = cask.staged_path.join(args[:manual]) +          @args = [] +          extend(ManualInstaller) +          return +        end + +        path, @args = self.class.read_script_arguments( +          args[:script], self.class.dsl_key.to_s, { must_succeed: true, sudo: false }, print_stdout: true +        ) +        raise CaskInvalidError.new(cask, "#{self.class.dsl_key} missing executable") if path.nil? + +        path = Pathname(path) +        @path = path.absolute? ? path : cask.staged_path.join(path) +        extend(ScriptInstaller) +      end + +      def summarize +        path.relative_path_from(cask.staged_path).to_s +      end + +      def to_h +        { path: path.relative_path_from(cask.staged_path).to_s }.tap do |h| +          h[:args] = args unless is_a?(ManualInstaller)          end        end      end diff --git a/Library/Homebrew/cask/lib/hbc/artifact/moved.rb b/Library/Homebrew/cask/lib/hbc/artifact/moved.rb index 3fe969c0c..ba1c8e907 100644 --- a/Library/Homebrew/cask/lib/hbc/artifact/moved.rb +++ b/Library/Homebrew/cask/lib/hbc/artifact/moved.rb @@ -4,63 +4,61 @@ module Hbc    module Artifact      class Moved < Relocated        def self.english_description -        "#{artifact_english_name}s" +        "#{english_name}s"        end -      def install_phase -        each_artifact(&method(:move)) +      def install_phase(**options) +        move(**options)        end -      def uninstall_phase -        each_artifact(&method(:delete)) +      def uninstall_phase(**options) +        delete(**options) +      end + +      def summarize_installed +        if target.exist? +          "#{printable_target} (#{target.abv})" +        else +          Formatter.error(printable_target, label: "Missing #{self.class.english_name}") +        end        end        private -      def move +      def move(force: false, command: nil, **options)          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? +          message = "It seems there is already #{self.class.english_article} #{self.class.english_name} at '#{target}'" +          raise CaskError, "#{message}." unless force            opoo "#{message}; overwriting." -          delete +          delete(force: force, command: command, **options)          end          unless source.exist? -          raise CaskError, "It seems the #{self.class.artifact_english_name} source '#{source}' is not there." +          raise CaskError, "It seems the #{self.class.english_name} source '#{source}' is not there."          end -        ohai "Moving #{self.class.artifact_english_name} '#{source.basename}' to '#{target}'." +        ohai "Moving #{self.class.english_name} '#{source.basename}' to '#{target}'."          target.dirname.mkpath          if target.parent.writable?            FileUtils.move(source, target)          else -          SystemCommand.run("/bin/mv", args: [source, target], sudo: true) +          command.run("/bin/mv", args: [source, target], sudo: true)          end -        add_altname_metadata target, source.basename.to_s +        add_altname_metadata(target, source.basename, command: command)        end -      def delete -        ohai "Removing #{self.class.artifact_english_name} '#{target}'." -        raise CaskError, "Cannot remove undeletable #{self.class.artifact_english_name}." if MacOS.undeletable?(target) +      def delete(force: false, command: nil, **_) +        ohai "Removing #{self.class.english_name} '#{target}'." +        raise CaskError, "Cannot remove undeletable #{self.class.english_name}." if MacOS.undeletable?(target)          return unless Utils.path_occupied?(target)          if target.parent.writable? && !force            target.rmtree          else -          Utils.gain_permissions_remove(target, command: @command) -        end -      end - -      def summarize_artifact(artifact_spec) -        load_specification artifact_spec - -        if target.exist? -          "#{printable_target} (#{target.abv})" -        else -          Formatter.error(printable_target, label: "Missing #{self.class.artifact_english_name}") +          Utils.gain_permissions_remove(target, command: command)          end        end      end diff --git a/Library/Homebrew/cask/lib/hbc/artifact/nested_container.rb b/Library/Homebrew/cask/lib/hbc/artifact/nested_container.rb index 84253ea30..81adf9029 100644 --- a/Library/Homebrew/cask/lib/hbc/artifact/nested_container.rb +++ b/Library/Homebrew/cask/lib/hbc/artifact/nested_container.rb @@ -1,23 +1,31 @@ -require "hbc/artifact/base" +require "hbc/artifact/abstract_artifact"  module Hbc    module Artifact -    class NestedContainer < Base -      def install_phase -        @cask.artifacts[:nested_container].each { |container| extract(container) } +    class NestedContainer < AbstractArtifact +      attr_reader :path + +      def initialize(cask, path) +        super(cask) +        @path = cask.staged_path.join(path) +      end + +      def install_phase(**options) +        extract(**options)        end -      def extract(container_relative_path) -        source = @cask.staged_path.join(container_relative_path) -        container = Container.for_path(source, @command) +      private + +      def extract(command: nil, verbose: nil, **_) +        container = Container.for_path(path, command)          unless container            raise CaskError, "Aw dang, could not identify nested container at '#{source}'"          end -        ohai "Extracting nested container #{source.basename}" -        container.new(@cask, source, @command, verbose: verbose?).extract -        FileUtils.remove_entry_secure(source) +        ohai "Extracting nested container #{path.relative_path_from(cask.staged_path)}" +        container.new(cask, path, command, verbose: verbose).extract +        FileUtils.remove_entry_secure(path)        end      end    end diff --git a/Library/Homebrew/cask/lib/hbc/artifact/pkg.rb b/Library/Homebrew/cask/lib/hbc/artifact/pkg.rb index be0a6be71..0967fd99d 100644 --- a/Library/Homebrew/cask/lib/hbc/artifact/pkg.rb +++ b/Library/Homebrew/cask/lib/hbc/artifact/pkg.rb @@ -1,4 +1,4 @@ -require "hbc/artifact/base" +require "hbc/artifact/abstract_artifact"  require "hbc/utils/hash_validator" @@ -6,62 +6,57 @@ require "vendor/plist/plist"  module Hbc    module Artifact -    class Pkg < Base +    class Pkg < AbstractArtifact        attr_reader :pkg_relative_path -      def self.artifact_dsl_key -        :pkg +      def self.from_args(cask, path, **options) +        options.extend(HashValidator).assert_valid_keys(:allow_untrusted, :choices) +        new(cask, path, **options)        end -      def load_pkg_description(pkg_description) -        @pkg_relative_path = pkg_description.shift -        @pkg_install_opts = pkg_description.shift -        begin -          if @pkg_install_opts.respond_to?(:keys) -            @pkg_install_opts.extend(HashValidator).assert_valid_keys(:allow_untrusted, :choices) -          elsif @pkg_install_opts -            raise -          end -          raise if pkg_description.nil? -        rescue StandardError -          raise CaskInvalidError.new(@cask, "Bad pkg stanza") -        end +      attr_reader :path, :options + +      def initialize(cask, path, **options) +        super(cask) +        @path = cask.staged_path.join(path) +        @options = options        end -      def pkg_install_opts(opt) -        @pkg_install_opts[opt] if @pkg_install_opts.respond_to?(:keys) +      def summarize +        path.relative_path_from(cask.staged_path).to_s        end -      def install_phase -        @cask.artifacts[:pkg].each { |pkg_description| run_installer(pkg_description) } +      def install_phase(**options) +        run_installer(**options)        end -      def run_installer(pkg_description) -        load_pkg_description pkg_description -        ohai "Running installer for #{@cask}; your password may be necessary." +      private + +      def run_installer(command: nil, verbose: false, **options) +        ohai "Running installer for #{cask}; your password may be necessary."          ohai "Package installers may write to any location; options such as --appdir are ignored." -        source = @cask.staged_path.join(pkg_relative_path) -        unless source.exist? -          raise CaskError, "pkg source file not found: '#{source}'" +        unless path.exist? +          raise CaskError, "pkg source file not found: '#{path.relative_path_from(cask.staged_path)}'"          end          args = [ -          "-pkg",    source, +          "-pkg",    path,            "-target", "/"          ] -        args << "-verboseR" if verbose? -        args << "-allowUntrusted" if pkg_install_opts :allow_untrusted +        args << "-verboseR" if verbose +        args << "-allowUntrusted" if options.fetch(:allow_untrusted, false)          with_choices_file do |choices_path|            args << "-applyChoiceChangesXML" << choices_path if choices_path -          @command.run!("/usr/sbin/installer", sudo: true, args: args, print_stdout: true) +          command.run!("/usr/sbin/installer", sudo: true, args: args, print_stdout: true)          end        end        def with_choices_file -        return yield nil unless pkg_install_opts(:choices) +        choices = options.fetch(:choices, {}) +        return yield nil if choices.empty?          Tempfile.open(["choices", ".xml"]) do |file|            begin -            file.write Plist::Emit.dump(pkg_install_opts(:choices)) +            file.write Plist::Emit.dump(choices)              file.close              yield file.path            ensure diff --git a/Library/Homebrew/cask/lib/hbc/artifact/prefpane.rb b/Library/Homebrew/cask/lib/hbc/artifact/prefpane.rb index a44f8ae3a..87f120934 100644 --- a/Library/Homebrew/cask/lib/hbc/artifact/prefpane.rb +++ b/Library/Homebrew/cask/lib/hbc/artifact/prefpane.rb @@ -3,7 +3,7 @@ require "hbc/artifact/moved"  module Hbc    module Artifact      class Prefpane < Moved -      def self.artifact_english_name +      def self.english_name          "Preference Pane"        end      end diff --git a/Library/Homebrew/cask/lib/hbc/artifact/qlplugin.rb b/Library/Homebrew/cask/lib/hbc/artifact/qlplugin.rb index ee41de2fe..298714d89 100644 --- a/Library/Homebrew/cask/lib/hbc/artifact/qlplugin.rb +++ b/Library/Homebrew/cask/lib/hbc/artifact/qlplugin.rb @@ -3,22 +3,24 @@ require "hbc/artifact/moved"  module Hbc    module Artifact      class Qlplugin < Moved -      def self.artifact_english_name +      def self.english_name          "QuickLook Plugin"        end -      def install_phase -        super -        reload_quicklook +      def install_phase(**options) +        super(**options) +        reload_quicklook(**options)        end -      def uninstall_phase -        super -        reload_quicklook +      def uninstall_phase(**options) +        super(**options) +        reload_quicklook(**options)        end -      def reload_quicklook -        @command.run!("/usr/bin/qlmanage", args: ["-r"]) +      private + +      def reload_quicklook(command: nil, **_) +        command.run!("/usr/bin/qlmanage", args: ["-r"])        end      end    end diff --git a/Library/Homebrew/cask/lib/hbc/artifact/relocated.rb b/Library/Homebrew/cask/lib/hbc/artifact/relocated.rb index 4dba46c9d..540699630 100644 --- a/Library/Homebrew/cask/lib/hbc/artifact/relocated.rb +++ b/Library/Homebrew/cask/lib/hbc/artifact/relocated.rb @@ -1,65 +1,79 @@ -require "hbc/artifact/base" +require "hbc/artifact/abstract_artifact"  require "hbc/utils/hash_validator"  module Hbc    module Artifact -    class Relocated < Base -      def summary -        { -          english_description: self.class.english_description, -          contents:            @cask.artifacts[self.class.artifact_dsl_key].map(&method(:summarize_artifact)).compact, -        } +    class Relocated < AbstractArtifact +      def self.from_args(cask, *args) +        source_string, target_hash = args + +        if target_hash +          raise CaskInvalidError unless target_hash.respond_to?(:keys) +          target_hash.extend(HashValidator).assert_valid_keys(:target) +        end + +        target_hash ||= {} + +        new(cask, source_string, **target_hash) +      end + +      def self.resolve_target(target) +        Hbc.public_send(dirmethod).join(target)        end        attr_reader :source, :target -      def printable_target -        target.to_s.sub(/^#{ENV['HOME']}(#{File::SEPARATOR}|$)/, "~/") +      def initialize(cask, source, target: nil) +        super(cask) + +        @source_string = source.to_s +        @target_string = target.to_s +        source = cask.staged_path.join(source) +        @source = source +        target ||= source.basename +        @target = self.class.resolve_target(target)        end +      def to_a +        [@source_string].tap do |ary| +          ary << { target: @target_string } unless @target_string.empty? +        end +      end + +      def summarize +        target_string = @target_string.empty? ? "" : " -> #{@target_string}" +        "#{@source_string}#{target_string}" +      end + +      private +        ALT_NAME_ATTRIBUTE = "com.apple.metadata:kMDItemAlternateNames".freeze        # Try to make the asset searchable under the target name.  Spotlight        # respects this attribute for many filetypes, but ignores it for App        # bundles. Alfred 2.2 respects it even for App bundles. -      def add_altname_metadata(file, altname) -        return if altname.casecmp(file.basename).zero? +      def add_altname_metadata(file, altname, command: nil) +        return if altname.to_s.casecmp(file.basename.to_s).zero?          odebug "Adding #{ALT_NAME_ATTRIBUTE} metadata" -        altnames = @command.run("/usr/bin/xattr", -                                args:         ["-p", ALT_NAME_ATTRIBUTE, file.to_s], +        altnames = command.run("/usr/bin/xattr", +                                args:         ["-p", ALT_NAME_ATTRIBUTE, file],                                  print_stderr: false).stdout.sub(/\A\((.*)\)\Z/, '\1')          odebug "Existing metadata is: '#{altnames}'"          altnames.concat(", ") unless altnames.empty?          altnames.concat(%Q("#{altname}"))          altnames = "(#{altnames})" -        # Some packges are shipped as u=rx (e.g. Bitcoin Core) -        @command.run!("/bin/chmod", args: ["--", "u+rw", file, file.realpath]) +        # Some packages are shipped as u=rx (e.g. Bitcoin Core) +        command.run!("/bin/chmod", args: ["--", "u+rw", file, file.realpath]) -        @command.run!("/usr/bin/xattr", +        command.run!("/usr/bin/xattr",                        args:         ["-w", ALT_NAME_ATTRIBUTE, altnames, file],                        print_stderr: false)        end -      def each_artifact -        @cask.artifacts[self.class.artifact_dsl_key].each do |artifact| -          load_specification(artifact) -          yield -        end -      end - -      def load_specification(artifact_spec) -        source_string, target_hash = artifact_spec -        raise CaskInvalidError if source_string.nil? -        @source = @cask.staged_path.join(source_string) -        if target_hash -          raise CaskInvalidError unless target_hash.respond_to?(:keys) -          target_hash.extend(HashValidator).assert_valid_keys(:target) -          @target = Hbc.send(self.class.artifact_dirmethod).join(target_hash[:target]) -        else -          @target = Hbc.send(self.class.artifact_dirmethod).join(source.basename) -        end +      def printable_target +        target.to_s.sub(/^#{ENV['HOME']}(#{File::SEPARATOR}|$)/, "~/")        end      end    end diff --git a/Library/Homebrew/cask/lib/hbc/artifact/stage_only.rb b/Library/Homebrew/cask/lib/hbc/artifact/stage_only.rb index 1122c1d02..8c32a52d0 100644 --- a/Library/Homebrew/cask/lib/hbc/artifact/stage_only.rb +++ b/Library/Homebrew/cask/lib/hbc/artifact/stage_only.rb @@ -1,10 +1,22 @@ -require "hbc/artifact/base" +require "hbc/artifact/abstract_artifact"  module Hbc    module Artifact -    class StageOnly < Base -      def self.artifact_dsl_key -        :stage_only +    class StageOnly < AbstractArtifact +      def self.from_args(cask, *args) +        if args != [true] +          raise CaskInvalidError.new(cask.token, "'stage_only' takes only a single argument: true") +        end + +        new(cask) +      end + +      def initialize(cask) +        super(cask) +      end + +      def to_a +        [true]        end      end    end diff --git a/Library/Homebrew/cask/lib/hbc/artifact/suite.rb b/Library/Homebrew/cask/lib/hbc/artifact/suite.rb index 35251f70c..59ae58cf1 100644 --- a/Library/Homebrew/cask/lib/hbc/artifact/suite.rb +++ b/Library/Homebrew/cask/lib/hbc/artifact/suite.rb @@ -3,11 +3,11 @@ require "hbc/artifact/moved"  module Hbc    module Artifact      class Suite < Moved -      def self.artifact_english_name +      def self.english_name          "App Suite"        end -      def self.artifact_dirmethod +      def self.dirmethod          :appdir        end      end diff --git a/Library/Homebrew/cask/lib/hbc/artifact/symlinked.rb b/Library/Homebrew/cask/lib/hbc/artifact/symlinked.rb index 16715fe81..3726ebb5c 100644 --- a/Library/Homebrew/cask/lib/hbc/artifact/symlinked.rb +++ b/Library/Homebrew/cask/lib/hbc/artifact/symlinked.rb @@ -8,58 +8,56 @@ module Hbc        end        def self.english_description -        "#{artifact_english_name} #{link_type_english_name}s" +        "#{english_name} #{link_type_english_name}s"        end -      def install_phase -        each_artifact(&method(:link)) +      def install_phase(**options) +        link(**options)        end -      def uninstall_phase -        each_artifact(&method(:unlink)) +      def uninstall_phase(**options) +        unlink(**options) +      end + +      def summarize_installed +        if target.symlink? && target.exist? && target.readlink.exist? +          "#{printable_target} -> #{target.readlink} (#{target.readlink.abv})" +        else +          string = if target.symlink? +            "#{printable_target} -> #{target.readlink}" +          else +            printable_target +          end + +          Formatter.error(string, label: "Broken Link") +        end        end        private -      def link +      def link(**options)          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.english_article} #{self.class.english_name} at '#{target}'; not linking."          end -        ohai "Linking #{self.class.artifact_english_name} '#{source.basename}' to '#{target}'." -        create_filesystem_link(source, target) +        ohai "Linking #{self.class.english_name} '#{source.basename}' to '#{target}'." +        create_filesystem_link(**options)        end -      def unlink +      def unlink(**)          return unless target.symlink? -        ohai "Unlinking #{self.class.artifact_english_name} '#{target}'." +        ohai "Unlinking #{self.class.english_name} '#{target}'."          target.delete        end -      def create_filesystem_link(source, target) +      def create_filesystem_link(command: nil, **_)          target.dirname.mkpath -        @command.run!("/bin/ln", args: ["-h", "-f", "-s", "--", source, target]) -        add_altname_metadata source, target.basename.to_s -      end - -      def summarize_artifact(artifact_spec) -        load_specification artifact_spec - -        if target.symlink? && target.exist? && target.readlink.exist? -          "#{printable_target} -> #{target.readlink} (#{target.readlink.abv})" -        else -          string = if target.symlink? -            "#{printable_target} -> #{target.readlink}" -          else -            printable_target -          end - -          Formatter.error(string, label: "Broken Link") -        end +        command.run!("/bin/ln", args: ["-h", "-f", "-s", "--", source, target]) +        add_altname_metadata(source, target.basename, command: command)        end      end    end diff --git a/Library/Homebrew/cask/lib/hbc/artifact/uninstall.rb b/Library/Homebrew/cask/lib/hbc/artifact/uninstall.rb index 5a3dc098d..2bbf82862 100644 --- a/Library/Homebrew/cask/lib/hbc/artifact/uninstall.rb +++ b/Library/Homebrew/cask/lib/hbc/artifact/uninstall.rb @@ -1,10 +1,10 @@ -require "hbc/artifact/uninstall_base" +require "hbc/artifact/abstract_uninstall"  module Hbc    module Artifact -    class Uninstall < UninstallBase -      def uninstall_phase -        dispatch_uninstall_directives +    class Uninstall < AbstractUninstall +      def uninstall_phase(**options) +        dispatch_uninstall_directives(**options)        end      end    end diff --git a/Library/Homebrew/cask/lib/hbc/artifact/zap.rb b/Library/Homebrew/cask/lib/hbc/artifact/zap.rb index cdfe2531d..31ff54d20 100644 --- a/Library/Homebrew/cask/lib/hbc/artifact/zap.rb +++ b/Library/Homebrew/cask/lib/hbc/artifact/zap.rb @@ -1,10 +1,10 @@ -require "hbc/artifact/uninstall_base" +require "hbc/artifact/abstract_uninstall"  module Hbc    module Artifact -    class Zap < UninstallBase -      def zap_phase -        dispatch_uninstall_directives +    class Zap < AbstractUninstall +      def zap_phase(**options) +        dispatch_uninstall_directives(**options)        end      end    end diff --git a/Library/Homebrew/cask/lib/hbc/audit.rb b/Library/Homebrew/cask/lib/hbc/audit.rb index b8bb6ab81..03d8cce82 100644 --- a/Library/Homebrew/cask/lib/hbc/audit.rb +++ b/Library/Homebrew/cask/lib/hbc/audit.rb @@ -214,12 +214,10 @@ module Hbc      end      def check_generic_artifacts -      cask.artifacts[:artifact].each do |source, target_hash| -        unless target_hash.is_a?(Hash) && target_hash[:target] -          add_error "target required for generic artifact #{source}" -          next +      cask.artifacts[:artifact].each do |artifact| +        unless artifact.target.absolute? +          add_error "target must be absolute path for #{artifact.class.english_name} #{artifact.source}"          end -        add_error "target must be absolute path for generic artifact #{source}" unless Pathname.new(target_hash[:target]).absolute?        end      end diff --git a/Library/Homebrew/cask/lib/hbc/cask.rb b/Library/Homebrew/cask/lib/hbc/cask.rb index 6d89a997c..72a23066f 100644 --- a/Library/Homebrew/cask/lib/hbc/cask.rb +++ b/Library/Homebrew/cask/lib/hbc/cask.rb @@ -17,7 +17,7 @@ module Hbc        @token = token        @sourcefile_path = sourcefile_path        @tap = tap -      @dsl = DSL.new(@token) +      @dsl = DSL.new(self)        return unless block_given?        @dsl.instance_eval(&block)        @dsl.language_eval @@ -41,6 +41,14 @@ module Hbc                            .reverse      end +    def full_name +      if @tap.nil? || @tap == Hbc.default_tap +        token +      else +        "#{@tap}/#{token}" +      end +    end +      def installed?        !versions.empty?      end diff --git a/Library/Homebrew/cask/lib/hbc/cask_loader.rb b/Library/Homebrew/cask/lib/hbc/cask_loader.rb index dd9c61089..8fce9636a 100644 --- a/Library/Homebrew/cask/lib/hbc/cask_loader.rb +++ b/Library/Homebrew/cask/lib/hbc/cask_loader.rb @@ -56,7 +56,7 @@ module Hbc      class FromURILoader < FromPathLoader        def self.can_load?(ref) -        ref.to_s.match?(::URI.regexp) +        ref.to_s.match?(::URI::DEFAULT_PARSER.make_regexp)        end        attr_reader :url @@ -116,6 +116,22 @@ module Hbc        end      end +    class FromInstanceLoader +      attr_reader :cask + +      def self.can_load?(ref) +        ref.is_a?(Cask) +      end + +      def initialize(cask) +        @cask = cask +      end + +      def load +        cask +      end +    end +      class NullLoader < FromPathLoader        def self.can_load?(*)          true @@ -149,6 +165,7 @@ module Hbc      def self.for(ref)        [ +        FromInstanceLoader,          FromURILoader,          FromTapLoader,          FromTapPathLoader, diff --git a/Library/Homebrew/cask/lib/hbc/cli/abstract_command.rb b/Library/Homebrew/cask/lib/hbc/cli/abstract_command.rb index 77f85301e..001a9623b 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/abstract_command.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/abstract_command.rb @@ -42,41 +42,32 @@ module Hbc          @args = process_arguments(*args)        end -      def self.warn_unavailable_with_suggestion(cask_token, e) -        exact_match, partial_matches = Search.search(cask_token) -        error_message = e.message -        if exact_match -          error_message.concat(" Did you mean:\n#{exact_match}") -        elsif !partial_matches.empty? -          error_message.concat(" Did you mean one of:\n") -                       .concat(Formatter.columns(partial_matches.take(20))) -        end -        onoe error_message -      end -        private        def casks(alternative: -> { [] }) -        return to_enum(:casks, alternative: alternative) unless block_given? - -        count = 0 - +        return @casks if defined?(@casks)          casks = args.empty? ? alternative.call : args +        @casks = casks.map { |cask| CaskLoader.load(cask) } +      rescue CaskUnavailableError => e +        reason = [e.reason, suggestion_message(e.token)].join(" ") +        raise e.class.new(e.token, reason) +      end + +      def suggestion_message(cask_token) +        exact_match, partial_matches = Search.search(cask_token) -        casks.each do |cask_or_token| -          begin -            yield cask_or_token.respond_to?(:token) ? cask_or_token : CaskLoader.load(cask_or_token) -            count += 1 -          rescue CaskUnavailableError => e -            cask_token = cask_or_token -            self.class.warn_unavailable_with_suggestion cask_token, e -          rescue CaskError => e -            onoe e.message -          end +        if exact_match.nil? && partial_matches.count == 1 +          exact_match = partial_matches.first          end -        return :empty if casks.length.zero? -        (count == casks.length) ? :complete : :incomplete +        if exact_match +          "Did you mean “#{exact_match}”?" +        elsif !partial_matches.empty? +          "Did you mean one of these?\n" +            .concat(Formatter.columns(partial_matches.take(20))) +        else +          "" +        end        end      end    end diff --git a/Library/Homebrew/cask/lib/hbc/cli/cat.rb b/Library/Homebrew/cask/lib/hbc/cli/cat.rb index d08c87bea..043080556 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/cat.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/cat.rb @@ -7,10 +7,6 @@ module Hbc        end        def run -        raise CaskError, "Cat incomplete." if cat_casks == :incomplete -      end - -      def cat_casks          casks.each do |cask|            puts File.open(cask.sourcefile_path, &:read)          end diff --git a/Library/Homebrew/cask/lib/hbc/cli/edit.rb b/Library/Homebrew/cask/lib/hbc/cli/edit.rb index b9485886c..8bce81c52 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/edit.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/edit.rb @@ -4,21 +4,18 @@ module Hbc        def initialize(*)          super          raise CaskUnspecifiedError if args.empty? -        raise ArgumentError, "Only one Cask can be created at a time." if args.count > 1 +        raise ArgumentError, "Only one Cask can be edited at a time." if args.count > 1        end        def run -        cask_token = args.first -        cask_path = begin -          CaskLoader.load(cask_token).sourcefile_path -        rescue CaskUnavailableError => e -          reason = e.reason.empty? ? "" : "#{e.reason} " -          reason.concat("Run #{Formatter.identifier("brew cask create #{e.token}")} to create a new Cask.") -          raise e.class.new(e.token, reason) -        end - -        odebug "Opening editor for Cask #{cask_token}" +        cask = casks.first +        cask_path = cask.sourcefile_path +        odebug "Opening editor for Cask #{cask.token}"          exec_editor cask_path +      rescue CaskUnavailableError => e +        reason = e.reason.empty? ? "" : "#{e.reason} " +        reason.concat("Run #{Formatter.identifier("brew cask create #{e.token}")} to create a new Cask.") +        raise e.class.new(e.token, reason)        end        def self.help diff --git a/Library/Homebrew/cask/lib/hbc/cli/fetch.rb b/Library/Homebrew/cask/lib/hbc/cli/fetch.rb index e31b1a17c..12c794f5f 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/fetch.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/fetch.rb @@ -9,10 +9,6 @@ module Hbc        end        def run -        raise CaskError, "Fetch incomplete." if fetch_casks == :incomplete -      end - -      def fetch_casks          casks.each do |cask|            ohai "Downloading external files for Cask #{cask}"            downloaded_path = Download.new(cask, force: force?).perform diff --git a/Library/Homebrew/cask/lib/hbc/cli/info.rb b/Library/Homebrew/cask/lib/hbc/cli/info.rb index d26747e17..9cdada62e 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/info.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/info.rb @@ -69,13 +69,11 @@ module Hbc        def self.artifact_info(cask)          ohai "Artifacts" -        DSL::ORDINARY_ARTIFACT_TYPES.each do |type| -          next if cask.artifacts[type].empty? -          cask.artifacts[type].each do |artifact| -            activatable_item = (type == :stage_only) ? "<none>" : artifact.first -            puts "#{activatable_item} (#{type})" -          end -        end +        DSL::ORDINARY_ARTIFACT_CLASSES.flat_map { |klass| klass.for_cask(cask) } +                                      .select { |artifact| artifact.respond_to?(:install_phase) } +                                      .each do |artifact| +                                        puts artifact.to_s +                                      end        end      end    end diff --git a/Library/Homebrew/cask/lib/hbc/cli/install.rb b/Library/Homebrew/cask/lib/hbc/cli/install.rb index 0f1a5dd34..9a2116e6a 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/install.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/install.rb @@ -10,10 +10,6 @@ module Hbc        end        def run -        raise CaskError, "Install incomplete." if install_casks == :incomplete -      end - -      def install_casks          casks.each do |cask|            begin              Installer.new(cask, binaries:       binaries?, diff --git a/Library/Homebrew/cask/lib/hbc/cli/internal_appcast_checkpoint.rb b/Library/Homebrew/cask/lib/hbc/cli/internal_appcast_checkpoint.rb index cd2679782..a538ffd8c 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/internal_appcast_checkpoint.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/internal_appcast_checkpoint.rb @@ -12,7 +12,7 @@ module Hbc          if args.all? { |t| t =~ %r{^https?://} && t !~ /\.rb$/ }            self.class.appcask_checkpoint_for_url(args)          else -          self.class.appcask_checkpoint(args, calculate?) +          self.class.appcask_checkpoint(casks, calculate?)          end        end @@ -23,33 +23,27 @@ module Hbc          end        end -      def self.appcask_checkpoint(cask_tokens, calculate) -        count = 0 - -        cask_tokens.each do |cask_token| -          cask = CaskLoader.load(cask_token) - +      def self.appcask_checkpoint(casks, calculate) +        casks.each do |cask|            if cask.appcast.nil?              opoo "Cask '#{cask}' is missing an `appcast` stanza."            else -            if calculate +            checkpoint = if calculate                result = cask.appcast.calculate_checkpoint - -              checkpoint = result[:checkpoint] +              result[:checkpoint]              else -              checkpoint = cask.appcast.checkpoint +              cask.appcast.checkpoint              end -            if checkpoint.nil? +            if calculate && checkpoint.nil?                onoe "Could not retrieve `appcast` checkpoint for cask '#{cask}': #{result[:command_result].stderr}" +            elsif casks.count > 1 +              puts "#{checkpoint}  #{cask}"              else -              puts((cask_tokens.count > 1) ? "#{checkpoint}  #{cask}" : checkpoint) -              count += 1 +              puts checkpoint              end            end          end - -        count == cask_tokens.count        end        def self.help diff --git a/Library/Homebrew/cask/lib/hbc/cli/internal_dump.rb b/Library/Homebrew/cask/lib/hbc/cli/internal_dump.rb index e21ce86b6..8a38ce1be 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/internal_dump.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/internal_dump.rb @@ -7,10 +7,6 @@ module Hbc        end        def run -        raise CaskError, "Dump incomplete." if dump_casks == :incomplet -      end - -      def dump_casks          casks.each(&:dumpcask)        end diff --git a/Library/Homebrew/cask/lib/hbc/cli/internal_stanza.rb b/Library/Homebrew/cask/lib/hbc/cli/internal_stanza.rb index 4515fe931..c04619798 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/internal_stanza.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/internal_stanza.rb @@ -3,7 +3,7 @@ module Hbc      class InternalStanza < AbstractInternalCommand        # Syntax        # -      #     brew cask _stanza <stanza_name> [ --table | --yaml | --inspect | --quiet ] [ <cask_token> ... ] +      #     brew cask _stanza <stanza_name> [ --quiet ] [ --table | --yaml ] [ <cask_token> ... ]        #        # If no tokens are given, then data for all Casks is returned.        # @@ -14,41 +14,16 @@ module Hbc        # Examples        #        #     brew cask _stanza appcast   --table -      #     brew cask _stanza app       --table alfred google-chrome adium voicemac logisim vagrant -      #     brew cask _stanza url       --table alfred google-chrome adium voicemac logisim vagrant -      #     brew cask _stanza version   --table alfred google-chrome adium voicemac logisim vagrant -      #     brew cask _stanza artifacts --table --inspect alfred google-chrome adium voicemac logisim vagrant -      #     brew cask _stanza artifacts --table --yaml    alfred google-chrome adium voicemac logisim vagrant +      #     brew cask _stanza app       --table           alfred google-chrome adium vagrant +      #     brew cask _stanza url       --table           alfred google-chrome adium vagrant +      #     brew cask _stanza version   --table           alfred google-chrome adium vagrant +      #     brew cask _stanza artifacts --table           alfred google-chrome adium vagrant +      #     brew cask _stanza artifacts --table --yaml    alfred google-chrome adium vagrant        # -      # TODO: this should be retrievable from Hbc::DSL -      ARTIFACTS = Set.new [ -        :app, -        :suite, -        :artifact, -        :prefpane, -        :qlplugin, -        :dictionary, -        :font, -        :service, -        :colorpicker, -        :binary, -        :input_method, -        :internet_plugin, -        :audio_unit_plugin, -        :vst_plugin, -        :vst3_plugin, -        :screen_saver, -        :pkg, -        :installer, -        :stage_only, -        :nested_container, -        :uninstall, -        :preflight, -        :postflight, -        :uninstall_preflight, -        :uninstall_postflight, -      ] +      ARTIFACTS = +        DSL::ORDINARY_ARTIFACT_CLASSES.map(&:dsl_key) + +        DSL::ARTIFACT_BLOCK_CLASSES.map(&:dsl_key)        option "--table",   :table,   false        option "--quiet",   :quiet,   false @@ -68,16 +43,9 @@ module Hbc          @stanza = args.shift.to_sym          @format = :to_yaml if yaml? -        @format = :inspect if inspect?        end        def run -        return unless print_stanzas == :incomplete -        exit 1 if quiet? -        raise CaskError, "Print incomplete." -      end - -      def print_stanzas          if ARTIFACTS.include?(stanza)            artifact_name = stanza            @stanza = :artifacts @@ -93,7 +61,7 @@ module Hbc            end            begin -            value = cask.send(@stanza) +            value = cask.send(stanza)            rescue StandardError              opoo "failure calling '#{stanza}' on Cask '#{cask}'" unless quiet?              puts "" @@ -106,11 +74,25 @@ module Hbc              next            end -          value = value.fetch(artifact_name).to_a.flatten if artifact_name +          if stanza == :artifacts +            value = Hash[ +              value.map do |k, v| +                v = v.map do |a| +                  next a.to_a if a.respond_to?(:to_a) +                  next a.to_h if a.respond_to?(:to_h) +                  a +                end + +                [k, v] +              end +            ] + +            value = value.fetch(artifact_name) if artifact_name +          end -          if @format -            puts value.send(@format) -          elsif artifact_name || value.is_a?(Symbol) +          if format +            puts value.send(format) +          elsif value.is_a?(Symbol)              puts value.inspect            else              puts value.to_s diff --git a/Library/Homebrew/cask/lib/hbc/cli/list.rb b/Library/Homebrew/cask/lib/hbc/cli/list.rb index 9d978360e..32415af8a 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/list.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/list.rb @@ -3,6 +3,7 @@ module Hbc      class List < AbstractCommand        option "-1", :one, false        option "--versions", :versions, false +      option "--full-name", :full_name, false        option "-l", (lambda do |*|          one = true # rubocop:disable Lint/UselessAssignment @@ -10,8 +11,7 @@ module Hbc        end)        def run -        retval = args.any? ? list : list_installed -        raise CaskError, "Listing incomplete." if retval == :incomplete +        args.any? ? list : list_installed        end        def list @@ -30,9 +30,9 @@ module Hbc        end        def self.list_artifacts(cask) -        Artifact.for_cask(cask).each do |artifact| -          summary = artifact.summary -          ohai summary[:english_description], summary[:contents] unless summary.empty? +        Artifact.for_cask(cask).group_by(&:class).each do |klass, artifacts| +          next unless klass.respond_to?(:english_description) +          ohai klass.english_description, artifacts.map(&:summarize_installed)          end        end @@ -43,11 +43,11 @@ module Hbc            puts installed_casks.map(&:to_s)          elsif versions?            puts installed_casks.map(&self.class.method(:format_versioned)) +        elsif full_name? +          puts installed_casks.map(&:full_name).sort &tap_and_name_comparison          elsif !installed_casks.empty?            puts Formatter.columns(installed_casks.map(&:to_s))          end - -        installed_casks.empty? ? :empty : :complete        end        def self.format_versioned(cask) diff --git a/Library/Homebrew/cask/lib/hbc/cli/reinstall.rb b/Library/Homebrew/cask/lib/hbc/cli/reinstall.rb index 337a2eb9d..408be134d 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/reinstall.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/reinstall.rb @@ -1,7 +1,7 @@  module Hbc    class CLI      class Reinstall < Install -      def install_casks +      def run          casks.each do |cask|            Installer.new(cask, binaries:       binaries?,                                verbose:        verbose?, diff --git a/Library/Homebrew/cask/lib/hbc/cli/search.rb b/Library/Homebrew/cask/lib/hbc/cli/search.rb index e89dced92..d56d0c81f 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/search.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/search.rb @@ -2,8 +2,12 @@ module Hbc    class CLI      class Search < AbstractCommand        def run -        results = self.class.search(*args) -        self.class.render_results(*results) +        if args.empty? +          puts Formatter.columns(CLI.nice_listing(Hbc.all_tokens)) +        else +          results = self.class.search(*args) +          self.class.render_results(*results) +        end        end        def self.extract_regexp(string) @@ -15,8 +19,17 @@ module Hbc        end        def self.search_remote(query) -        matches = GitHub.search_code(user: "caskroom", path: "Casks", -                                     filename: query, extension: "rb") +        matches = begin +          GitHub.search_code( +            user: "caskroom", +            path: "Casks", +            filename: query, +            extension: "rb", +          ) +        rescue GitHub::Error => error +          opoo "Error searching on GitHub: #{error}\n" +          [] +        end          matches.map do |match|            tap = Tap.fetch(match["repository"]["full_name"])            next if tap.installed? diff --git a/Library/Homebrew/cask/lib/hbc/cli/uninstall.rb b/Library/Homebrew/cask/lib/hbc/cli/uninstall.rb index c0697c808..7e55db5f1 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/uninstall.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/uninstall.rb @@ -9,10 +9,6 @@ module Hbc        end        def run -        raise CaskError, "Uninstall incomplete." if uninstall_casks == :incomplete -      end - -      def uninstall_casks          casks.each do |cask|            odebug "Uninstalling Cask #{cask}" diff --git a/Library/Homebrew/cask/lib/hbc/cli/zap.rb b/Library/Homebrew/cask/lib/hbc/cli/zap.rb index e709f4191..7f5e6785d 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/zap.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/zap.rb @@ -9,10 +9,6 @@ module Hbc        end        def run -        raise CaskError, "Zap incomplete." if zap_casks == :incomplete -      end - -      def zap_casks          casks.each do |cask|            odebug "Zapping Cask #{cask}"            Installer.new(cask, verbose: verbose?, force: force?).zap diff --git a/Library/Homebrew/cask/lib/hbc/container/naked.rb b/Library/Homebrew/cask/lib/hbc/container/naked.rb index 375d62f7a..dc265c402 100644 --- a/Library/Homebrew/cask/lib/hbc/container/naked.rb +++ b/Library/Homebrew/cask/lib/hbc/container/naked.rb @@ -16,7 +16,7 @@ module Hbc        def target_file          return @path.basename if @nested -        URI.decode(File.basename(@cask.url.path)) +        CGI.unescape(File.basename(@cask.url.path))        end      end    end diff --git a/Library/Homebrew/cask/lib/hbc/dsl.rb b/Library/Homebrew/cask/lib/hbc/dsl.rb index 8ad206c2f..3824b9761 100644 --- a/Library/Homebrew/cask/lib/hbc/dsl.rb +++ b/Library/Homebrew/cask/lib/hbc/dsl.rb @@ -1,6 +1,8 @@  require "set"  require "locale" +require "hbc/artifact" +  require "hbc/dsl/appcast"  require "hbc/dsl/base"  require "hbc/dsl/caveats" @@ -8,7 +10,6 @@ require "hbc/dsl/conflicts_with"  require "hbc/dsl/container"  require "hbc/dsl/depends_on"  require "hbc/dsl/gpg" -require "hbc/dsl/installer"  require "hbc/dsl/postflight"  require "hbc/dsl/preflight"  require "hbc/dsl/stanza_proxy" @@ -18,39 +19,35 @@ require "hbc/dsl/version"  module Hbc    class DSL -    ORDINARY_ARTIFACT_TYPES = [ -      :app, -      :artifact, -      :audio_unit_plugin, -      :binary, -      :colorpicker, -      :dictionary, -      :font, -      :input_method, -      :internet_plugin, -      :pkg, -      :prefpane, -      :qlplugin, -      :screen_saver, -      :service, -      :stage_only, -      :suite, -      :vst_plugin, -      :vst3_plugin, +    ORDINARY_ARTIFACT_CLASSES = [ +      Artifact::Installer, +      Artifact::App, +      Artifact::Artifact, +      Artifact::AudioUnitPlugin, +      Artifact::Binary, +      Artifact::Colorpicker, +      Artifact::Dictionary, +      Artifact::Font, +      Artifact::InputMethod, +      Artifact::InternetPlugin, +      Artifact::Pkg, +      Artifact::Prefpane, +      Artifact::Qlplugin, +      Artifact::ScreenSaver, +      Artifact::Service, +      Artifact::StageOnly, +      Artifact::Suite, +      Artifact::VstPlugin, +      Artifact::Vst3Plugin, +      Artifact::Uninstall, +      Artifact::Zap,      ].freeze -    ACTIVATABLE_ARTIFACT_TYPES = ([:installer, *ORDINARY_ARTIFACT_TYPES] - [:stage_only]).freeze - -    SPECIAL_ARTIFACT_TYPES = [ -      :uninstall, -      :zap, -    ].freeze +    ACTIVATABLE_ARTIFACT_TYPES = (ORDINARY_ARTIFACT_CLASSES.map(&:dsl_key) - [:stage_only]).freeze -    ARTIFACT_BLOCK_TYPES = [ -      :preflight, -      :postflight, -      :uninstall_preflight, -      :uninstall_postflight, +    ARTIFACT_BLOCK_CLASSES = [ +      Artifact::PreflightBlock, +      Artifact::PostflightBlock,      ].freeze      DSL_METHODS = Set.new [ @@ -72,15 +69,15 @@ module Hbc        :url,        :version,        :appdir, -      *ORDINARY_ARTIFACT_TYPES, +      *ORDINARY_ARTIFACT_CLASSES.map(&:dsl_key),        *ACTIVATABLE_ARTIFACT_TYPES, -      *SPECIAL_ARTIFACT_TYPES, -      *ARTIFACT_BLOCK_TYPES, +      *ARTIFACT_BLOCK_CLASSES.flat_map { |klass| [klass.dsl_key, klass.uninstall_dsl_key] },      ].freeze -    attr_reader :token -    def initialize(token) -      @token = token +    attr_reader :token, :cask +    def initialize(cask) +      @cask = cask +      @token = cask.token      end      def name(*args) @@ -93,12 +90,14 @@ module Hbc        return instance_variable_get("@#{stanza}") if should_return        if instance_variable_defined?("@#{stanza}") -        raise CaskInvalidError.new(token, "'#{stanza}' stanza may only appear once") +        raise CaskInvalidError.new(cask, "'#{stanza}' stanza may only appear once.")        end        instance_variable_set("@#{stanza}", yield) +    rescue CaskInvalidError +      raise      rescue StandardError => e -      raise CaskInvalidError.new(token, "'#{stanza}' stanza failed with: #{e}") +      raise CaskInvalidError.new(cask, "'#{stanza}' stanza failed with: #{e}")      end      def homepage(homepage = nil) @@ -113,7 +112,7 @@ module Hbc          return unless default          unless @language_blocks.default.nil? -          raise CaskInvalidError.new(token, "Only one default language may be defined") +          raise CaskInvalidError.new(cask, "Only one default language may be defined.")          end          @language_blocks.default = block @@ -162,8 +161,8 @@ module Hbc          begin            DSL::Container.new(*args).tap do |container|              # TODO: remove this backward-compatibility section after removing nested_container -            if container && container.nested -              artifacts[:nested_container] << container.nested +            if container&.nested +              artifacts[:nested_container] << Artifact::NestedContainer.new(cask, container.nested)              end            end          end @@ -173,7 +172,7 @@ module Hbc      def version(arg = nil)        set_unique_stanza(:version, arg.nil?) do          if !arg.is_a?(String) && arg != :latest -          raise CaskInvalidError.new(token, "invalid 'version' value: '#{arg.inspect}'") +          raise CaskInvalidError.new(cask, "invalid 'version' value: '#{arg.inspect}'")          end          DSL::Version.new(arg)        end @@ -182,7 +181,7 @@ module Hbc      def sha256(arg = nil)        set_unique_stanza(:sha256, arg.nil?) do          if !arg.is_a?(String) && arg != :no_check -          raise CaskInvalidError.new(token, "invalid 'sha256' value: '#{arg.inspect}'") +          raise CaskInvalidError.new(cask, "invalid 'sha256' value: '#{arg.inspect}'")          end          arg        end @@ -195,7 +194,7 @@ module Hbc        begin          @depends_on.load(*args)        rescue RuntimeError => e -        raise CaskInvalidError.new(token, e) +        raise CaskInvalidError.new(cask, e)        end        @depends_on      end @@ -237,39 +236,29 @@ module Hbc        set_unique_stanza(:auto_updates, auto_updates.nil?) { auto_updates }      end -    ORDINARY_ARTIFACT_TYPES.each do |type| +    ORDINARY_ARTIFACT_CLASSES.each do |klass| +      type = klass.dsl_key +        define_method(type) do |*args| -        if type == :stage_only -          if args != [true] -            raise CaskInvalidError.new(token, "'stage_only' takes a single argument: true") +        begin +          if [*artifacts.keys, type].include?(:stage_only) && (artifacts.keys & ACTIVATABLE_ARTIFACT_TYPES).any? +            raise CaskInvalidError.new(cask, "'stage_only' must be the only activatable artifact.")            end -          unless (artifacts.keys & ACTIVATABLE_ARTIFACT_TYPES).empty? -            raise CaskInvalidError.new(token, "'stage_only' must be the only activatable artifact") -          end +          artifacts[type].add(klass.from_args(cask, *args)) +        rescue CaskInvalidError +          raise +        rescue StandardError => e +          raise CaskInvalidError.new(cask, "invalid '#{klass.dsl_key}' stanza: #{e}")          end - -        artifacts[type].add(args)        end      end -    def installer(*args) -      return artifacts[:installer] if args.empty? -      artifacts[:installer] << DSL::Installer.new(*args) -      raise "'stage_only' must be the only activatable artifact" if artifacts.key?(:stage_only) -    rescue StandardError => e -      raise CaskInvalidError.new(token, e) -    end - -    SPECIAL_ARTIFACT_TYPES.each do |type| -      define_method(type) do |*args| -        artifacts[type].merge(args) -      end -    end - -    ARTIFACT_BLOCK_TYPES.each do |type| -      define_method(type) do |&block| -        artifacts[type] << block +    ARTIFACT_BLOCK_CLASSES.each do |klass| +      [klass.dsl_key, klass.uninstall_dsl_key].each do |dsl_key| +        define_method(dsl_key) do |&block| +          artifacts[dsl_key] << block +        end        end      end diff --git a/Library/Homebrew/cask/lib/hbc/dsl/installer.rb b/Library/Homebrew/cask/lib/hbc/dsl/installer.rb deleted file mode 100644 index b01b28d76..000000000 --- a/Library/Homebrew/cask/lib/hbc/dsl/installer.rb +++ /dev/null @@ -1,32 +0,0 @@ -module Hbc -  class DSL -    class Installer -      VALID_KEYS = Set.new [ -        :manual, -        :script, -      ] - -      attr_accessor(*VALID_KEYS) - -      def initialize(*parameters) -        raise CaskInvalidError.new(token, "'installer' stanza requires an argument") if parameters.empty? -        parameters = {}.merge(*parameters) -        if parameters.key?(:script) && !parameters[:script].respond_to?(:key?) -          if parameters.key?(:executable) -            raise CaskInvalidError.new(token, "'installer' stanza gave arguments for both :script and :executable") -          end -          parameters[:executable] = parameters[:script] -          parameters.delete(:script) -          parameters = { script: parameters } -        end -        unless parameters.keys.length == 1 -          raise "invalid 'installer' stanza: only one of #{VALID_KEYS.inspect} is permitted" -        end -        key = parameters.keys.first -        raise "invalid 'installer' stanza key: '#{key.inspect}'" unless VALID_KEYS.include?(key) -        writer_method = "#{key}=".to_sym -        send(writer_method, parameters[key]) -      end -    end -  end -end diff --git a/Library/Homebrew/cask/lib/hbc/dsl/version.rb b/Library/Homebrew/cask/lib/hbc/dsl/version.rb index d73205f52..9605feb57 100644 --- a/Library/Homebrew/cask/lib/hbc/dsl/version.rb +++ b/Library/Homebrew/cask/lib/hbc/dsl/version.rb @@ -49,7 +49,7 @@ module Hbc          end        end -      DIVIDERS.keys.each do |divider| +      DIVIDERS.each_key do |divider|          define_divider_methods(divider)        end diff --git a/Library/Homebrew/cask/lib/hbc/installer.rb b/Library/Homebrew/cask/lib/hbc/installer.rb index 37cc4e561..01aae935d 100644 --- a/Library/Homebrew/cask/lib/hbc/installer.rb +++ b/Library/Homebrew/cask/lib/hbc/installer.rb @@ -159,7 +159,7 @@ module Hbc        odebug "Extracting primary container"        FileUtils.mkdir_p @cask.staged_path -      container = if @cask.container && @cask.container.type +      container = if @cask.container&.type          Container.from_type(@cask.container.type)        else          Container.for_path(@downloaded_path, @command) @@ -177,7 +177,7 @@ module Hbc        already_installed_artifacts = []        odebug "Installing artifacts" -      artifacts = Artifact.for_cask(@cask, command: @command, verbose: verbose?, force: force?) +      artifacts = Artifact.for_cask(@cask)        odebug "#{artifacts.length} artifact/s defined", artifacts        artifacts.each do |artifact| @@ -188,7 +188,7 @@ module Hbc            next unless binaries?          end -        artifact.install_phase +        artifact.install_phase(command: @command, verbose: verbose?, force: force?)          already_installed_artifacts.unshift(artifact)        end      rescue StandardError => e @@ -196,7 +196,7 @@ module Hbc          already_installed_artifacts.each do |artifact|            next unless artifact.respond_to?(:uninstall_phase)            odebug "Reverting installation of artifact of class #{artifact.class}" -          artifact.uninstall_phase +          artifact.uninstall_phase(command: @command, verbose: verbose?, force: force?)          end        ensure          purge_versioned_files @@ -361,7 +361,7 @@ module Hbc        savedir = @cask.metadata_subdir("Casks", timestamp: :now, create: true)        FileUtils.copy @cask.sourcefile_path, savedir -      old_savedir.rmtree unless old_savedir.nil? +      old_savedir&.rmtree      end      def uninstall @@ -374,25 +374,27 @@ module Hbc      def uninstall_artifacts        odebug "Un-installing artifacts" -      artifacts = Artifact.for_cask(@cask, command: @command, verbose: verbose?, force: force?) +      artifacts = Artifact.for_cask(@cask)        odebug "#{artifacts.length} artifact/s defined", artifacts        artifacts.each do |artifact|          next unless artifact.respond_to?(:uninstall_phase)          odebug "Un-installing artifact of class #{artifact.class}" -        artifact.uninstall_phase +        artifact.uninstall_phase(command: @command, verbose: verbose?, force: force?)        end      end      def zap        ohai %Q(Implied "brew cask uninstall #{@cask}")        uninstall_artifacts -      if Artifact::Zap.me?(@cask) -        ohai "Dispatching zap stanza" -        Artifact::Zap.new(@cask, command: @command).zap_phase -      else +      if (zap_stanzas = Artifact::Zap.for_cask(@cask)).empty?          opoo "No zap stanza present for Cask '#{@cask}'" +      else +        ohai "Dispatching zap stanza" +        zap_stanzas.each do |stanza| +          stanza.zap_phase(command: @command, verbose: verbose?, force: force?) +        end        end        ohai "Removing all staged versions of Cask '#{@cask}'"        purge_caskroom_path diff --git a/Library/Homebrew/cask/lib/hbc/staged.rb b/Library/Homebrew/cask/lib/hbc/staged.rb index c1aa01b29..dc21279de 100644 --- a/Library/Homebrew/cask/lib/hbc/staged.rb +++ b/Library/Homebrew/cask/lib/hbc/staged.rb @@ -4,7 +4,7 @@ module Hbc        index =  0 if index == :first        index =  1 if index == :second        index = -1 if index == :last -      Hbc.appdir.join(@cask.artifacts[:app].to_a.at(index).first, "Contents", "Info.plist") +      @cask.artifacts[:app].to_a.at(index).target.join("Contents", "Info.plist")      end      def plist_exec(cmd) diff --git a/Library/Homebrew/cask/lib/hbc/system_command.rb b/Library/Homebrew/cask/lib/hbc/system_command.rb index b735ae4f9..be083c29e 100644 --- a/Library/Homebrew/cask/lib/hbc/system_command.rb +++ b/Library/Homebrew/cask/lib/hbc/system_command.rb @@ -61,7 +61,7 @@ module Hbc      end      def assert_success -      return if processed_status && processed_status.success? +      return if processed_status&.success?        raise CaskCommandFailedError.new(command, processed_output[:stdout], processed_output[:stderr], processed_status)      end  | 
