Class: Cask::Artifact::AbstractUninstall Private

Inherits:
AbstractArtifact show all
Includes:
OS::Mac::Cask::Artifact::AbstractUninstall, SystemCommand::Mixin
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.

Direct Known Subclasses

Uninstall, Zap

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

Constants inherited from AbstractArtifact

Cask::Artifact::AbstractArtifact::DirectivesType

Class Attribute Summary collapse

Instance Attribute Summary collapse

Attributes inherited from AbstractArtifact

#cask

Class Method Summary collapse

Instance Method Summary collapse

Methods included from SystemCommand::Mixin

#system_command, #system_command!

Methods inherited from AbstractArtifact

#cask_sandbox, #config, dirmethod, dsl_key, english_article, english_name, read_script_arguments, #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_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.

Parameters:



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'cask/artifact/abstract_uninstall.rb', line 50

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_idsArray<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.

Returns:



380
381
382
383
384
385
386
387
388
389
390
# File 'cask/artifact/abstract_uninstall.rb', line 380

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

#directivesHash{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.

Returns:



47
48
49
# File 'cask/artifact/abstract_uninstall.rb', line 47

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.

Parameters:

Returns:



399
# File 'cask/artifact/abstract_uninstall.rb', line 399

def bundle_identifier_for_pid(_pid) = nil

.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.

Parameters:

Returns:



42
43
44
# File 'cask/artifact/abstract_uninstall.rb', line 42

def self.from_args(cask, **directives)
  new(cask, **directives)
end

.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.

Parameters:

Returns:



396
# File 'cask/artifact/abstract_uninstall.rb', line 396

def parent_pid(_pid) = nil

Instance Method Details

#bundle_ids_to_reopenArray<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.

Returns:



78
79
80
# File 'cask/artifact/abstract_uninstall.rb', line 78

def bundle_ids_to_reopen
  @bundle_ids_to_reopen ||= T.let([], T.nilable(T::Array[String]))
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.

Parameters:

Returns:

  • (T.untyped)


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
# File 'cask/artifact/abstract_uninstall.rb', line 139

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.

Parameters:

Returns:



173
174
175
176
177
178
179
180
181
# File 'cask/artifact/abstract_uninstall.rb', line 173

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

#summarizeString

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.

Returns:



73
74
75
# File 'cask/artifact/abstract_uninstall.rb', line 73

def summarize
  to_h.flat_map { |key, val| Array(val).map { |v| "#{key.inspect} => #{v.inspect}" } }.join(", ")
end

#to_hHash{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.

Returns:



68
69
70
# File 'cask/artifact/abstract_uninstall.rb', line 68

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

Parameters:

  • bundle_ids (String)
  • command (T.class_of(SystemCommand), nil) (defaults to: nil)
  • upgrade (Boolean) (defaults to: false)
  • _kwargs (T.anything)


91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'cask/artifact/abstract_uninstall.rb', line 91

def uninstall_quit(*bundle_ids, command: nil, upgrade: false, **_kwargs)
  bundle_ids = bundle_ids.flat_map { |bundle_id| expand_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