Class: Cask::Artifact::AbstractUninstall Private
- Inherits:
-
AbstractArtifact
- Object
- AbstractArtifact
- Cask::Artifact::AbstractUninstall
- Defined in:
- cask/artifact/abstract_uninstall.rb
Overview
This class is part of a private API. This class may only be used in the Homebrew/brew repository. Third parties should avoid using this class if possible, as it may be removed or changed without warning.
Abstract superclass for uninstall artifacts.
Constant Summary collapse
- ORDERED_DIRECTIVES =
This constant is part of a private API. This constant may only be used in the Homebrew/brew repository. Third parties should avoid using this constant if possible, as it may be removed or changed without warning.
[ :early_script, :launchctl, :quit, :signal, :login_item, :kext, :script, :pkgutil, :delete, :trash, :rmdir, ].freeze
- METADATA_KEYS =
This constant is part of a private API. This constant may only be used in the Homebrew/brew repository. Third parties should avoid using this constant if possible, as it may be removed or changed without warning.
[ :on_upgrade, ].freeze
- UPGRADE_REINSTALL_SKIP_DIRECTIVES =
This constant is part of a private API. This constant may only be used in the Homebrew/brew repository. Third parties should avoid using this constant if possible, as it may be removed or changed without warning.
[:signal].freeze
Constants inherited from AbstractArtifact
Cask::Artifact::AbstractArtifact::DirectivesType
Class Attribute Summary collapse
-
.ancestor_bundle_ids ⇒ Array<String>
private
Bundle IDs of the applications this
brewprocess is running inside.
Instance Attribute Summary collapse
- #directives ⇒ Hash{Symbol => DirectivesType} readonly private
Attributes inherited from AbstractArtifact
Class Method Summary collapse
- .bundle_identifier_for_pid(_pid) ⇒ String? private
-
.dispatch_directives(artifacts, command:, deferred: false, force: false, successor: nil, upgrade: false, reinstall: false, quit: true) ⇒ void
private
Dispatches the directives of one or more
uninstall/zapstanzas in a singleORDERED_DIRECTIVESpass, the earlier stanza's first at each step, so that zapping runszapdirectives alongside theuninstallstanza's. - .from_args(cask, **directives) ⇒ AbstractUninstall private
- .owner_uid(_pid) ⇒ Integer? private
- .parent_pid(_pid) ⇒ Integer? private
Instance Method Summary collapse
- #bundle_ids_to_reopen ⇒ Array<String> private
-
#deferred_directives ⇒ Array<Symbol>
private
Directives that wait until the cask's artifacts have been removed and its
uninstall_postflightsteps have run, so that directories which held only those artifacts are seen as empty. -
#dispatch_uninstall_directive(directive_sym, command:, force: false, successor: nil, upgrade: false) ⇒ void
private
Runs this stanza's
directive_symdirective, if it has one. -
#each_resolved_path(action, paths, &_block) ⇒ T.untyped
private
This returns T::Enumerable[[Pathname, T::Array[Pathname]]] when called without a block, but sorbet doesn't support overloads.
- #find_launchctl_with_wildcard(search) ⇒ Array<String> private
- #initialize(cask, **directives) ⇒ void constructor private
- #summarize ⇒ String private
- #to_h ⇒ Hash{Symbol => DirectivesType} private
-
#uninstall_quit(*bundle_ids, command: nil, upgrade: false, **_kwargs) ⇒ void
private
:quit/:signal must come before :kext so the kext will not be in use by a running process.
Methods included from SystemCommand::Mixin
#command_sandbox, #system_command, #system_command!
Methods inherited from AbstractArtifact
#cask_sandbox, #config, dirmethod, dsl_key, english_article, english_name, read_script_arguments, #requires_sudo?, #run_cask_sandbox, #sort_order, #staged_path_join_executable, #to_args
Methods included from Utils::Output::Mixin
#issue_reporting_message, #odebug, #odeprecated, #odie, #odisabled, #ofail, #oh1, #oh1_title, #ohai, #ohai_title, #onoe, #opoo, #opoo_once, #opoo_outside_github_actions, #opoo_without_github_actions_annotation, #pretty_cannot_install, #pretty_deprecated, #pretty_disabled, #pretty_duration, #pretty_install_status, #pretty_installed, #pretty_uninstalled, #pretty_unmarked, #pretty_upgradable, #pretty_warning
Constructor Details
#initialize(cask, **directives) ⇒ void
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'cask/artifact/abstract_uninstall.rb', line 93 def initialize(cask, **directives) ::Utils::Data.assert_valid_keys(directives, *ORDERED_DIRECTIVES, *METADATA_KEYS) super directives[:signal] = Array(directives[:signal]).flatten.each_slice(2).to_a @directives = directives # This is already included when loading from the API. return if cask.loaded_from_api? return unless directives.key?(:kext) cask.caveats do T.bind(self, ::Cask::DSL::Caveats) kext end end |
Class Attribute Details
.ancestor_bundle_ids ⇒ Array<String>
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
Bundle IDs of the applications this brew process is running inside.
The ancestry of the brew process cannot change while it runs, so the
lookup is shared by every artifact of every cask in the same invocation.
436 437 438 439 440 441 442 443 444 445 446 |
# File 'cask/artifact/abstract_uninstall.rb', line 436 def ancestor_bundle_ids @ancestor_bundle_ids ||= begin pids = [Process.pid] # `launchd` (PID 1) reports a parent of `0` rather than failing. while (ppid = parent_pid(pids.last)) && ppid > 1 && pids.exclude?(ppid) pids << ppid end pids.filter_map { |pid| bundle_identifier_for_pid(pid) } end end |
Instance Attribute Details
#directives ⇒ Hash{Symbol => DirectivesType} (readonly)
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
90 91 92 |
# File 'cask/artifact/abstract_uninstall.rb', line 90 def directives @directives end |
Class Method Details
.bundle_identifier_for_pid(_pid) ⇒ String?
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
455 |
# File 'cask/artifact/abstract_uninstall.rb', line 455 def bundle_identifier_for_pid(_pid) = nil |
.dispatch_directives(artifacts, command:, deferred: false, force: false, successor: nil, upgrade: false, reinstall: false, quit: true) ⇒ void
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
This method returns an undefined value.
Dispatches the directives of one or more uninstall/zap stanzas in a single
ORDERED_DIRECTIVES pass, the earlier stanza's first at each step, so that
zapping runs zap directives alongside the uninstall stanza's. Each stanza's
deferred_directives are skipped, and are the only ones run when deferred:.
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'cask/artifact/abstract_uninstall.rb', line 64 def self.dispatch_directives(artifacts, command:, deferred: false, force: false, successor: nil, upgrade: false, reinstall: false, quit: true) ORDERED_DIRECTIVES.each do |directive_sym| next if directive_sym == :quit && !quit artifacts.each do |artifact| next if artifact.deferred_directives.include?(directive_sym) != deferred if (upgrade || reinstall) && UPGRADE_REINSTALL_SKIP_DIRECTIVES.include?(directive_sym) && Array(artifact.directives[:on_upgrade]).map { |name| name.to_s.to_sym }.exclude?(directive_sym) next end artifact.dispatch_uninstall_directive(directive_sym, command:, force:, successor:, upgrade:) end end end |
.from_args(cask, **directives) ⇒ AbstractUninstall
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
44 45 46 |
# File 'cask/artifact/abstract_uninstall.rb', line 44 def self.from_args(cask, **directives) new(cask, **directives) end |
.owner_uid(_pid) ⇒ Integer?
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
458 |
# File 'cask/artifact/abstract_uninstall.rb', line 458 def owner_uid(_pid) = nil |
.parent_pid(_pid) ⇒ Integer?
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
452 |
# File 'cask/artifact/abstract_uninstall.rb', line 452 def parent_pid(_pid) = nil |
Instance Method Details
#bundle_ids_to_reopen ⇒ Array<String>
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
121 122 123 |
# File 'cask/artifact/abstract_uninstall.rb', line 121 def bundle_ids_to_reopen @bundle_ids_to_reopen ||= T.let([], T.nilable(T::Array[String])) end |
#deferred_directives ⇒ Array<Symbol>
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
Directives that wait until the cask's artifacts have been removed and its
uninstall_postflight steps have run, so that directories which held only
those artifacts are seen as empty.
87 |
# File 'cask/artifact/abstract_uninstall.rb', line 87 def deferred_directives = [:rmdir] |
#dispatch_uninstall_directive(directive_sym, command:, force: false, successor: nil, upgrade: false) ⇒ void
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
This method returns an undefined value.
Runs this stanza's directive_sym directive, if it has one.
The uninstall_* methods are dispatched dynamically, so they take these
options uniformly and ignore the ones they do not need.
238 239 240 241 242 243 244 245 |
# File 'cask/artifact/abstract_uninstall.rb', line 238 def dispatch_uninstall_directive(directive_sym, command:, force: false, successor: nil, upgrade: false) return unless directives.key?(directive_sym) args = directives[directive_sym] send(:"uninstall_#{directive_sym}", *(args.is_a?(Hash) ? [args] : args), command:, force:, successor:, upgrade:) end |
#each_resolved_path(action, paths, &_block) ⇒ T.untyped
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
This returns T::Enumerable[[Pathname, T::Array[Pathname]]] when called without a block, but sorbet doesn't support overloads.
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'cask/artifact/abstract_uninstall.rb', line 182 def each_resolved_path(action, paths, &_block) return enum_for(:each_resolved_path, action, paths) unless block_given? paths.each do |path| resolved_path = Pathname.new(path.to_s.sub(%r{^~(?=(?:/|$))}, Dir.home)) if resolved_path.relative? opoo "Skipping #{Formatter.identifier(action)} for relative path '#{path}'." next end if resolved_path.each_filename.to_a.intersect?([".", ".."]) opoo "Skipping #{Formatter.identifier(action)} for path with relative segments '#{path}'." next end begin resolved_paths = Pathname.glob(resolved_path).reject do |target| next false unless undeletable?(target) opoo "Skipping #{Formatter.identifier(action)} for undeletable path '#{target}'." true end yield path, resolved_paths rescue Errno::EPERM raise if ::Cask::Utils.full_disk_access_enabled? odie "Unable to remove some files. Please enable Full Disk Access for your terminal under " \ "#{::Cask::Utils.privacy_security_preference_pane("Full Disk Access")}." end end end |
#find_launchctl_with_wildcard(search) ⇒ Array<String>
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
216 217 218 219 220 221 222 223 224 |
# File 'cask/artifact/abstract_uninstall.rb', line 216 def find_launchctl_with_wildcard(search) regex = wildcard_pattern(search) system_command!("/bin/launchctl", args: ["list"]) .stdout.lines.drop(1) # skip stdout column headers .filter_map do |line| pid, _state, id = line.chomp.split(/\s+/) id if pid.to_i.nonzero? && id&.match?(regex) end end |
#summarize ⇒ String
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
116 117 118 |
# File 'cask/artifact/abstract_uninstall.rb', line 116 def summarize to_h.flat_map { |key, val| Array(val).map { |v| "#{key.inspect} => #{v.inspect}" } }.join(", ") end |
#to_h ⇒ Hash{Symbol => DirectivesType}
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
111 112 113 |
# File 'cask/artifact/abstract_uninstall.rb', line 111 def to_h directives.to_h end |
#uninstall_quit(*bundle_ids, command: nil, upgrade: false, **_kwargs) ⇒ void
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
This method returns an undefined value.
:quit/:signal must come before :kext so the kext will not be in use by a running process
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'cask/artifact/abstract_uninstall.rb', line 134 def uninstall_quit(*bundle_ids, command: nil, upgrade: false, **_kwargs) bundle_ids = bundle_ids.flat_map { |bundle_id| (bundle_id) } bundle_ids.each do |bundle_id| next unless running?(bundle_id) unless User.current&.gui? opoo "Not logged into a GUI; skipping quitting application ID '#{bundle_id}'." next end if hosting_brew?(bundle_id) opoo "Skipping quitting application '#{bundle_id}' as `brew` is running inside it." next end ohai "Quitting application '#{bundle_id}'..." quit_succeeded = T.let(false, T::Boolean) begin Timeout.timeout(10) do Kernel.loop do next unless quit(bundle_id).success? next if running?(bundle_id) puts "Application '#{bundle_id}' quit successfully." quit_succeeded = true break end end rescue Timeout::Error opoo "Application '#{bundle_id}' did not quit. #{automation_access_instructions}" end bundle_ids_to_reopen << bundle_id if upgrade && quit_succeeded end end |