Class: Cask::Artifact::App Private

Inherits:
Moved show all
Defined in:
cask/artifact/app.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.

Artifact corresponding to the app stanza.

Constant Summary

Constants inherited from AbstractArtifact

Cask::Artifact::AbstractArtifact::DirectivesType

Instance Attribute Summary

Attributes inherited from AbstractArtifact

#cask

Instance Method Summary collapse

Methods inherited from Moved

#adopted?, #backup_copy_args, english_description, #summarize_installed, #uninstall_phase

Methods included from OS::Linux::Cask::Artifact::Moved

#backup_copy_args

Methods included from OS::Mac::Cask::Artifact::Moved

#backup_copy_args, #undeletable?

Methods inherited from Relocated

#add_altname_metadata, from_args, #initialize, #resolve_target, #source, #summarize, #target, #to_a

Methods included from OS::Linux::Cask::Artifact::Relocated

#add_altname_metadata

Methods inherited from AbstractArtifact

#cask_sandbox, #config, dirmethod, dsl_key, english_article, english_name, #initialize, read_script_arguments, #requires_sudo?, #run_cask_sandbox, #sort_order, #staged_path_join_executable, #summarize, #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_removed, #pretty_uninstalled, #pretty_unmarked, #pretty_upgradable, #pretty_warning

Constructor Details

This class inherits a constructor from Cask::Artifact::Relocated

Instance Method Details

#install_phase(adopt: false, auto_updates: false, force: false, verbose: false, predecessor: nil, successor: nil, reinstall: false, command: SystemCommand) ⇒ 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.

Parameters:

  • adopt (Boolean) (defaults to: false)
  • auto_updates (Boolean, nil) (defaults to: false)
  • force (Boolean) (defaults to: false)
  • verbose (Boolean) (defaults to: false)
  • predecessor (Cask, nil) (defaults to: nil)
  • successor (Cask, nil) (defaults to: nil)
  • reinstall (Boolean) (defaults to: false)
  • command (T.class_of(SystemCommand)) (defaults to: SystemCommand)


23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'cask/artifact/app.rb', line 23

def install_phase(
  adopt: false,
  auto_updates: false,
  force: false,
  verbose: false,
  predecessor: nil,
  successor: nil,
  reinstall: false,
  command: SystemCommand
)
  # Prepare leading script permissions before App Management protects the installed app.
  # Keeping this in the normal sandbox avoids giving postflight code inherited TCC access.
  if !adopt && target.extname == ".app" && target.dirname == cask.config.appdir &&
     source.directory? && !source.symlink? && source.realpath.ascend.include?(cask.staged_path.realpath)
    cask.artifacts.grep(PostflightSteps).flat_map(&:steps).each do |step|
      permissions = step["permissions"]
      break if step["type"] != "set_permissions" || step["non_recursive"] != true || step["guards"].present?
      # 0755 survives the app permission normalisation below without granting group/world writes.
      break if !permissions.is_a?(String) || !permissions.match?(/\A0?[0-7]{3}\z/) || permissions.oct != 0755

      paths = step["paths"]
      break unless paths.is_a?(Array)

      first_spec = paths.first
      break unless first_spec.is_a?(Hash)

      step_app = cask.artifacts.grep(App).find do |app|
        app.target.dirname == cask.config.appdir && app.target.extname == ".app" &&
          app.target.basename.to_s == first_spec.fetch("path").split("/", 2).first
      end
      break unless step_app

      staged_paths = paths.filter_map do |spec|
        next if !spec.is_a?(Hash) || spec["base"] != "appdir"
        next if spec.fetch("path").match?(/[*?\[\]{}]/)

        components = spec.fetch("path").split("/", -1)
        next if components.length < 2 || components.first != step_app.target.basename.to_s ||
                components.intersect?(::Utils::INVALID_PATH_COMPONENTS)

        path = step_app.source.join(*components.drop(1))
        next if !path.file? || path.symlink? || path.stat.nlink != 1 ||
                path.realpath.ascend.exclude?(step_app.source.realpath)

        { "base" => "staged_path", "path" => path.relative_path_from(cask.staged_path).to_s }
      end
      break if staged_paths.length != paths.length
      # Use identity because app artefacts compare equal for installation order.
      next unless step_app.equal?(self)

      break unless Sandbox.use_for?("preparing cask app permissions", warn_without_sandbox: false)

      PreflightSteps.new(cask, [step.slice("type", "permissions", "non_recursive")
                                   .merge("paths" => staged_paths)]).install_phase(command:)
    end
  end

  super

  odebug "Fixing up '#{target}' permissions for installation to '#{target.parent}'"
  system_dir = target.ascend
                     .take_while { it.to_s != Dir.home && (it.to_s != "/" || it == target.parent) }
                     .any? { OS::Mac.system_dir?(it) }
  permissions = "go-w"
  # Ensure that globally installed applications can be accessed by all users.
  permissions = "a+rX,#{permissions}" if system_dir

  # We shell out to `chmod` instead of using `FileUtils.chmod` so that using `+X` works correctly.
  command.run!("chmod", args: ["-R", permissions, target], sudo: nil)

  sudo = false unless system_dir
  command.run("chgrp", args: ["-hR", Caskroom.expected_caskroom_group, target],
                       sudo:, must_succeed: system_dir, print_stderr: system_dir)
end