Merge branch 'master' into audit_line_rubocop_part_4_rebase_attempt_1
This commit is contained in:
		
						commit
						7fa51f71f1
					
				
							
								
								
									
										17
									
								
								.github/ISSUE_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								.github/ISSUE_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							@ -1,17 +1,22 @@
 | 
			
		||||
**Please note we will close your issue without comment if you delete, do not read or do not fill out the issue checklist below and provide ALL the requested information. If you repeatedly fail to use the issue template, we will block you from ever submitting issues to Homebrew again.**
 | 
			
		||||
 | 
			
		||||
# Please always follow these steps:
 | 
			
		||||
- [ ] Confirmed this is a problem with running a `brew` command and not `brew install`ing or the post-install behaviour of one or more formulae? If it's a formulae-specific problem please file this issue at https://github.com/Homebrew/homebrew-core/issues/new
 | 
			
		||||
- [ ] Confirmed this is a problem with running a `brew` command and not `brew install`ing or the post-install behaviour of one or more formulae? If it's a formulae-specific problem please file this issue at the relevant tap e.g. for Homebrew/homebrew-core https://github.com/Homebrew/homebrew-core/issues/new
 | 
			
		||||
- [ ] Ran `brew update` and retried your prior step?
 | 
			
		||||
- [ ] Ran `brew doctor`, fixed all issues and retried your prior step?
 | 
			
		||||
- [ ] Ran `brew config` and `brew doctor` and included their output with your issue?
 | 
			
		||||
 | 
			
		||||
**Please note we will close your issue without comment if you delete or do not fill out the issue checklist and provide ALL the requested information.**
 | 
			
		||||
 | 
			
		||||
To help us debug your issue please explain:
 | 
			
		||||
- What you were trying to do (and why)
 | 
			
		||||
- What happened (include command output)
 | 
			
		||||
- What you expected to happen
 | 
			
		||||
- Step-by-step reproduction instructions (by running `brew` commands)
 | 
			
		||||
 | 
			
		||||
# Or propose a feature:
 | 
			
		||||
Please replace this section with a detailed description of your proposed feature, the motivation for it, how it would be relevant to at least 90% of Homebrew users and alternatives considered.
 | 
			
		||||
Please note we will close this issue or ask you to create a pull-request if it's something we're not actively planning to work on.
 | 
			
		||||
# Features
 | 
			
		||||
Please replace this section with:
 | 
			
		||||
- a detailed description of your proposed feature
 | 
			
		||||
- the motivation for the feature
 | 
			
		||||
- how the feature would be relevant to at least 90% of Homebrew users
 | 
			
		||||
- what alternatives to the feature you have considered
 | 
			
		||||
 | 
			
		||||
We will close this issue or ask you to create a pull-request if it's something we're not actively planning to work on.
 | 
			
		||||
 | 
			
		||||
@ -11,30 +11,31 @@ matrix:
 | 
			
		||||
  fast_finish: true
 | 
			
		||||
  include:
 | 
			
		||||
    - os: osx
 | 
			
		||||
      osx_image: xcode8.3
 | 
			
		||||
      osx_image: xcode9
 | 
			
		||||
      rvm: system
 | 
			
		||||
    - os: linux
 | 
			
		||||
      sudo: false
 | 
			
		||||
      rvm: 2.0.0
 | 
			
		||||
      rvm: 2.3.3
 | 
			
		||||
 | 
			
		||||
before_install:
 | 
			
		||||
  - export HOMEBREW_NO_AUTO_UPDATE=1
 | 
			
		||||
  - export HOMEBREW_DEVELOPER=1
 | 
			
		||||
  - git clone --depth=1 https://github.com/Homebrew/homebrew-test-bot Library/Taps/homebrew/homebrew-test-bot
 | 
			
		||||
  - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then
 | 
			
		||||
      HOMEBREW_REPOSITORY="$(brew --repo)";
 | 
			
		||||
      sudo chown -R "$USER" "$HOMEBREW_REPOSITORY/Library/Taps";
 | 
			
		||||
      mv "$HOMEBREW_REPOSITORY/Library/Taps" "$PWD/Library";
 | 
			
		||||
      sudo rm -rf "$HOMEBREW_REPOSITORY";
 | 
			
		||||
      sudo ln -s "$PWD" "$HOMEBREW_REPOSITORY";
 | 
			
		||||
      git clone --depth=1 https://github.com/Homebrew/homebrew-test-bot Library/Taps/homebrew/homebrew-test-bot;
 | 
			
		||||
    else
 | 
			
		||||
      umask 022;
 | 
			
		||||
      git fetch --unshallow;
 | 
			
		||||
      export PATH="$PWD/bin:$PATH";
 | 
			
		||||
      HOMEBREW_CORE_TAP_DIR="$(brew --repo "homebrew/core")";
 | 
			
		||||
      mkdir -p "$HOMEBREW_CORE_TAP_DIR";
 | 
			
		||||
      git clone --depth=1 https://github.com/Homebrew/homebrew-test-bot Library/Taps/homebrew/homebrew-test-bot;
 | 
			
		||||
      HOMEBREW_TEST_BOT_TAP_DIR="$(brew --repo "homebrew/test-bot")";
 | 
			
		||||
      ln -s "$HOMEBREW_TEST_BOT_TAP_DIR/.git" "$HOMEBREW_TEST_BOT_TAP_DIR/Formula" "$HOMEBREW_CORE_TAP_DIR";
 | 
			
		||||
      umask 022;
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
script:
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
# Contributing to Homebrew
 | 
			
		||||
First time contributing to Homebrew? Read our [Code of Conduct](https://github.com/Homebrew/brew/blob/master/CODEOFCONDUCT.md#code-of-conduct).
 | 
			
		||||
First time contributing to Homebrew? Read our [Code of Conduct](https://github.com/Homebrew/brew/blob/master/CODE_OF_CONDUCT.md#code-of-conduct).
 | 
			
		||||
 | 
			
		||||
### Report a bug
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
AllCops:
 | 
			
		||||
  TargetRubyVersion: 2.0
 | 
			
		||||
  TargetRubyVersion: 2.3
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - '**/Casks/**/*'
 | 
			
		||||
    - '**/vendor/**/*'
 | 
			
		||||
@ -123,7 +123,7 @@ Style/Tab:
 | 
			
		||||
  Enabled: true
 | 
			
		||||
 | 
			
		||||
# dashes in filenames are typical
 | 
			
		||||
Style/FileName:
 | 
			
		||||
Naming/FileName:
 | 
			
		||||
  Regex: !ruby/regexp /^[\w\@\-\+\.]+(\.rb)?$/
 | 
			
		||||
 | 
			
		||||
# falsely flags e.g. curl formatting arguments as format strings
 | 
			
		||||
@ -193,8 +193,25 @@ Style/TrailingCommaInArguments:
 | 
			
		||||
  EnforcedStyleForMultiline: comma
 | 
			
		||||
 | 
			
		||||
# we have too many variables like sha256 where this harms readability
 | 
			
		||||
Style/VariableNumber:
 | 
			
		||||
Naming/VariableNumber:
 | 
			
		||||
  Enabled: false
 | 
			
		||||
 | 
			
		||||
Style/WordArray:
 | 
			
		||||
  MinSize: 4
 | 
			
		||||
 | 
			
		||||
# we want to add this slowly and manually
 | 
			
		||||
Style/FrozenStringLiteralComment:
 | 
			
		||||
  Enabled: false
 | 
			
		||||
 | 
			
		||||
# generally rescuing StandardError is fine
 | 
			
		||||
Lint/RescueWithoutErrorClass:
 | 
			
		||||
  Enabled: false
 | 
			
		||||
 | 
			
		||||
# implicitly allow EOS as we use it everywhere
 | 
			
		||||
Naming/HeredocDelimiterNaming:
 | 
			
		||||
  Blacklist:
 | 
			
		||||
    - END, EOD, EOF
 | 
			
		||||
 | 
			
		||||
# we output how to use interpolated strings too often
 | 
			
		||||
Lint/InterpolationCheck:
 | 
			
		||||
  Enabled: false
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
inherit_from:
 | 
			
		||||
  - ../.rubocop.yml
 | 
			
		||||
  - .rubocop_todo.yml
 | 
			
		||||
 | 
			
		||||
AllCops:
 | 
			
		||||
  Include:
 | 
			
		||||
@ -26,12 +25,30 @@ Lint/NestedMethodDefinition:
 | 
			
		||||
Lint/ParenthesesAsGroupedExpression:
 | 
			
		||||
  Enabled: true
 | 
			
		||||
 | 
			
		||||
Metrics/BlockNesting:
 | 
			
		||||
  Max: 5
 | 
			
		||||
 | 
			
		||||
Metrics/ModuleLength:
 | 
			
		||||
  Max: 360
 | 
			
		||||
 | 
			
		||||
Metrics/ParameterLists:
 | 
			
		||||
  CountKeywordArgs: false
 | 
			
		||||
 | 
			
		||||
# we won't change backward compatible method names
 | 
			
		||||
Naming/MethodName:
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - 'compat/**/*'
 | 
			
		||||
 | 
			
		||||
# we won't change backward compatible predicate names
 | 
			
		||||
Naming/PredicateName:
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - 'compat/**/*'
 | 
			
		||||
  NameWhitelist: is_32_bit?, is_64_bit?
 | 
			
		||||
 | 
			
		||||
Style/BlockDelimiters:
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - '**/*_spec.rb'
 | 
			
		||||
    - '**/shared_examples/**/*.rb'
 | 
			
		||||
 | 
			
		||||
# so many of these in formulae but none in here
 | 
			
		||||
Style/GuardClause:
 | 
			
		||||
@ -40,14 +57,3 @@ Style/GuardClause:
 | 
			
		||||
# hash-rockets preferred for formulae, a: 1 preferred elsewhere
 | 
			
		||||
Style/HashSyntax:
 | 
			
		||||
  EnforcedStyle: ruby19_no_mixed_keys
 | 
			
		||||
 | 
			
		||||
# we won't change backward compatible method names
 | 
			
		||||
Style/MethodName:
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - 'compat/**/*'
 | 
			
		||||
 | 
			
		||||
# we won't change backward compatible predicate names
 | 
			
		||||
Style/PredicateName:
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - 'compat/**/*'
 | 
			
		||||
  NameWhitelist: is_32_bit?, is_64_bit?
 | 
			
		||||
 | 
			
		||||
@ -1,145 +0,0 @@
 | 
			
		||||
# This configuration was generated by
 | 
			
		||||
# `rubocop --auto-gen-config --exclude-limit 100`
 | 
			
		||||
# on 2017-01-27 21:44:55 +0000 using RuboCop version 0.47.1.
 | 
			
		||||
# The point is for the user to remove these configuration records
 | 
			
		||||
# one by one as the offenses are removed from the code base.
 | 
			
		||||
# Note that changes in the inspected code, or installation of new
 | 
			
		||||
# versions of RuboCop, may require this file to be generated again.
 | 
			
		||||
 | 
			
		||||
# Offense count: 17
 | 
			
		||||
Lint/HandleExceptions:
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - 'cmd/install.rb'
 | 
			
		||||
    - 'cmd/reinstall.rb'
 | 
			
		||||
    - 'cmd/tap.rb'
 | 
			
		||||
    - 'cmd/update-report.rb'
 | 
			
		||||
    - 'cmd/upgrade.rb'
 | 
			
		||||
    - 'cmd/uses.rb'
 | 
			
		||||
    - 'descriptions.rb'
 | 
			
		||||
    - 'diagnostic.rb'
 | 
			
		||||
    - 'extend/ENV/super.rb'
 | 
			
		||||
    - 'extend/pathname.rb'
 | 
			
		||||
    - 'formula.rb'
 | 
			
		||||
    - 'formula_versions.rb'
 | 
			
		||||
    - 'test/ENV_test.rb'
 | 
			
		||||
 | 
			
		||||
# Offense count: 3
 | 
			
		||||
Lint/IneffectiveAccessModifier:
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - 'formula.rb'
 | 
			
		||||
    - 'version.rb'
 | 
			
		||||
 | 
			
		||||
# Offense count: 1
 | 
			
		||||
Lint/Loop:
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - 'patch.rb'
 | 
			
		||||
 | 
			
		||||
# Offense count: 28
 | 
			
		||||
Lint/RescueException:
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - 'brew.rb'
 | 
			
		||||
    - 'build.rb'
 | 
			
		||||
    - 'cmd/fetch.rb'
 | 
			
		||||
    - 'cmd/reinstall.rb'
 | 
			
		||||
    - 'cmd/update-report.rb'
 | 
			
		||||
    - 'debrew.rb'
 | 
			
		||||
    - 'dev-cmd/pull.rb'
 | 
			
		||||
    - 'dev-cmd/test.rb'
 | 
			
		||||
    - 'formula.rb'
 | 
			
		||||
    - 'formula_installer.rb'
 | 
			
		||||
    - 'migrator.rb'
 | 
			
		||||
    - 'postinstall.rb'
 | 
			
		||||
    - 'readall.rb'
 | 
			
		||||
    - 'test.rb'
 | 
			
		||||
    - 'test/ENV_test.rb'
 | 
			
		||||
    - 'utils/fork.rb'
 | 
			
		||||
 | 
			
		||||
# Offense count: 1
 | 
			
		||||
Lint/ShadowedException:
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - 'utils/fork.rb'
 | 
			
		||||
 | 
			
		||||
# Offense count: 13
 | 
			
		||||
# Configuration parameters: CountBlocks.
 | 
			
		||||
Metrics/BlockNesting:
 | 
			
		||||
  Max: 5
 | 
			
		||||
 | 
			
		||||
# Offense count: 19
 | 
			
		||||
# Configuration parameters: CountComments.
 | 
			
		||||
Metrics/ModuleLength:
 | 
			
		||||
  Max: 400
 | 
			
		||||
 | 
			
		||||
# Offense count: 1
 | 
			
		||||
# Configuration parameters: CountKeywordArgs.
 | 
			
		||||
Metrics/ParameterLists:
 | 
			
		||||
  Max: 6
 | 
			
		||||
 | 
			
		||||
# Offense count: 2
 | 
			
		||||
Security/MarshalLoad:
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - 'dependency.rb'
 | 
			
		||||
    - 'utils/fork.rb'
 | 
			
		||||
 | 
			
		||||
# Offense count: 1
 | 
			
		||||
Style/AccessorMethodName:
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - 'extend/ENV/super.rb'
 | 
			
		||||
 | 
			
		||||
# Offense count: 6
 | 
			
		||||
Style/ClassVars:
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - 'dev-cmd/audit.rb'
 | 
			
		||||
    - 'formula_installer.rb'
 | 
			
		||||
    - 'test/support/helper/fs_leak_logger.rb'
 | 
			
		||||
 | 
			
		||||
# Offense count: 13
 | 
			
		||||
# Cop supports --auto-correct.
 | 
			
		||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
 | 
			
		||||
# SupportedStyles: compact, expanded
 | 
			
		||||
Style/EmptyMethod:
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - 'debrew/irb.rb'
 | 
			
		||||
    - 'download_strategy.rb'
 | 
			
		||||
    - 'extend/ENV/super.rb'
 | 
			
		||||
    - 'formula.rb'
 | 
			
		||||
    - 'patch.rb'
 | 
			
		||||
 | 
			
		||||
# Offense count: 13
 | 
			
		||||
# Configuration parameters: AllowedVariables.
 | 
			
		||||
Style/GlobalVars:
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - 'diagnostic.rb'
 | 
			
		||||
    - 'utils.rb'
 | 
			
		||||
 | 
			
		||||
# Offense count: 1
 | 
			
		||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
 | 
			
		||||
# SupportedStyles: module_function, extend_self
 | 
			
		||||
Style/ModuleFunction:
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - 'os/mac/xcode.rb'
 | 
			
		||||
 | 
			
		||||
# Offense count: 8
 | 
			
		||||
Style/MultilineBlockChain:
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - 'cmd/search.rb'
 | 
			
		||||
    - 'dev-cmd/aspell-dictionaries.rb'
 | 
			
		||||
    - 'dev-cmd/audit.rb'
 | 
			
		||||
    - 'dev-cmd/man.rb'
 | 
			
		||||
    - 'diagnostic.rb'
 | 
			
		||||
    - 'test/patching_test.rb'
 | 
			
		||||
 | 
			
		||||
# Offense count: 4
 | 
			
		||||
# Cop supports --auto-correct.
 | 
			
		||||
Style/MutableConstant:
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - 'dependency_collector.rb'
 | 
			
		||||
    - 'formulary.rb'
 | 
			
		||||
    - 'tab.rb'
 | 
			
		||||
    - 'tap.rb'
 | 
			
		||||
 | 
			
		||||
# Offense count: 8
 | 
			
		||||
Style/OpMethod:
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - 'dependencies.rb'
 | 
			
		||||
    - 'install_renamed.rb'
 | 
			
		||||
    - 'options.rb'
 | 
			
		||||
@ -11,11 +11,6 @@ SimpleCov.start do
 | 
			
		||||
  # tests to be dropped. This causes random fluctuations in test coverage.
 | 
			
		||||
  merge_timeout 86400
 | 
			
		||||
 | 
			
		||||
  add_filter "/Homebrew/compat/"
 | 
			
		||||
  add_filter "/Homebrew/dev-cmd/tests.rb"
 | 
			
		||||
  add_filter "/Homebrew/test/"
 | 
			
		||||
  add_filter "/Homebrew/vendor/"
 | 
			
		||||
 | 
			
		||||
  if ENV["HOMEBREW_INTEGRATION_TEST"]
 | 
			
		||||
    command_name "#{ENV["HOMEBREW_INTEGRATION_TEST"]} (#{$PROCESS_ID})"
 | 
			
		||||
 | 
			
		||||
@ -33,22 +28,32 @@ SimpleCov.start do
 | 
			
		||||
    end
 | 
			
		||||
  else
 | 
			
		||||
    command_name "#{command_name} (#{$PROCESS_ID})"
 | 
			
		||||
 | 
			
		||||
    subdirs = Dir.chdir(SimpleCov.root) { Dir.glob("*") }
 | 
			
		||||
                 .reject { |d| d.end_with?(".rb") || ["test", "vendor"].include?(d) }
 | 
			
		||||
                 .map { |d| "#{d}/**/*.rb" }.join(",")
 | 
			
		||||
 | 
			
		||||
    # Not using this during integration tests makes the tests 4x times faster
 | 
			
		||||
    # without changing the coverage.
 | 
			
		||||
    track_files "#{SimpleCov.root}/**/*.rb"
 | 
			
		||||
    track_files "#{SimpleCov.root}/{#{subdirs},*.rb}"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  add_filter %r{^/compat/}
 | 
			
		||||
  add_filter %r{^/dev-cmd/tests.rb$}
 | 
			
		||||
  add_filter %r{^/test/}
 | 
			
		||||
  add_filter %r{^/vendor/}
 | 
			
		||||
 | 
			
		||||
  # Add groups and the proper project name to the output.
 | 
			
		||||
  project_name "Homebrew"
 | 
			
		||||
  add_group "Cask", "/Homebrew/cask/"
 | 
			
		||||
  add_group "Commands", %w[/Homebrew/cmd/ /Homebrew/dev-cmd/]
 | 
			
		||||
  add_group "Extensions", "/Homebrew/extend/"
 | 
			
		||||
  add_group "OS", %w[/Homebrew/extend/os/ /Homebrew/os/]
 | 
			
		||||
  add_group "Requirements", "/Homebrew/requirements/"
 | 
			
		||||
  add_group "Scripts", %w[
 | 
			
		||||
    /Homebrew/brew.rb
 | 
			
		||||
    /Homebrew/build.rb
 | 
			
		||||
    /Homebrew/postinstall.rb
 | 
			
		||||
    /Homebrew/test.rb
 | 
			
		||||
  add_group "Cask", %r{^/cask/}
 | 
			
		||||
  add_group "Commands", [%r{/cmd/}, %r{^/dev-cmd/}]
 | 
			
		||||
  add_group "Extensions", %r{^/extend/}
 | 
			
		||||
  add_group "OS", [%r{^/extend/os/}, %r{^/os/}]
 | 
			
		||||
  add_group "Requirements", %r{^/requirements/}
 | 
			
		||||
  add_group "Scripts", [
 | 
			
		||||
    %r{^/brew.rb$},
 | 
			
		||||
    %r{^/build.rb$},
 | 
			
		||||
    %r{^/postinstall.rb$},
 | 
			
		||||
    %r{^/test.rb$},
 | 
			
		||||
  ]
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -5,8 +5,12 @@ end
 | 
			
		||||
std_trap = trap("INT") { exit! 130 } # no backtrace thanks
 | 
			
		||||
 | 
			
		||||
# check ruby version before requiring any modules.
 | 
			
		||||
RUBY_TWO = RUBY_VERSION.split(".").first.to_i >= 2
 | 
			
		||||
raise "Homebrew must be run under Ruby 2!" unless RUBY_TWO
 | 
			
		||||
RUBY_VERSION_SPLIT = RUBY_VERSION.split "."
 | 
			
		||||
RUBY_X = RUBY_VERSION_SPLIT[0].to_i
 | 
			
		||||
RUBY_Y = RUBY_VERSION_SPLIT[1].to_i
 | 
			
		||||
if RUBY_X < 2 || (RUBY_X == 2 && RUBY_Y < 3)
 | 
			
		||||
  raise "Homebrew must be run under Ruby 2.3!"
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
require "pathname"
 | 
			
		||||
HOMEBREW_LIBRARY_PATH = Pathname.new(__FILE__).realpath.parent
 | 
			
		||||
@ -105,7 +109,8 @@ begin
 | 
			
		||||
    possible_tap = OFFICIAL_CMD_TAPS.find { |_, cmds| cmds.include?(cmd) }
 | 
			
		||||
    possible_tap = Tap.fetch(possible_tap.first) if possible_tap
 | 
			
		||||
 | 
			
		||||
    if possible_tap && !possible_tap.installed?
 | 
			
		||||
    odie "Unknown command: #{cmd}" if !possible_tap || possible_tap.installed?
 | 
			
		||||
 | 
			
		||||
    brew_uid = HOMEBREW_BREW_FILE.stat.uid
 | 
			
		||||
    tap_commands = []
 | 
			
		||||
    if Process.uid.zero? && !brew_uid.zero?
 | 
			
		||||
@ -114,9 +119,6 @@ begin
 | 
			
		||||
    tap_commands += %W[#{HOMEBREW_BREW_FILE} tap #{possible_tap}]
 | 
			
		||||
    safe_system(*tap_commands)
 | 
			
		||||
    exec HOMEBREW_BREW_FILE, cmd, *ARGV
 | 
			
		||||
    else
 | 
			
		||||
      odie "Unknown command: #{cmd}"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
rescue UsageError => e
 | 
			
		||||
  require "cmd/help"
 | 
			
		||||
@ -144,7 +146,7 @@ rescue MethodDeprecatedError => e
 | 
			
		||||
    $stderr.puts "  #{Formatter.url(e.issues_url)}"
 | 
			
		||||
  end
 | 
			
		||||
  exit 1
 | 
			
		||||
rescue Exception => e
 | 
			
		||||
rescue Exception => e # rubocop:disable Lint/RescueException
 | 
			
		||||
  onoe e
 | 
			
		||||
  if internal_cmd && defined?(OS::ISSUES_URL) &&
 | 
			
		||||
     !ENV["HOMEBREW_NO_AUTO_UPDATE"]
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,7 @@ HOMEBREW_VERSION="$(git -C "$HOMEBREW_REPOSITORY" describe --tags --dirty --abbr
 | 
			
		||||
HOMEBREW_USER_AGENT_VERSION="$HOMEBREW_VERSION"
 | 
			
		||||
if [[ -z "$HOMEBREW_VERSION" ]]
 | 
			
		||||
then
 | 
			
		||||
  HOMEBREW_VERSION=">1.2.0 (no git repository)"
 | 
			
		||||
  HOMEBREW_VERSION=">1.2.0 (shallow or no git repository)"
 | 
			
		||||
  HOMEBREW_USER_AGENT_VERSION="1.X.Y"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
@ -105,7 +105,14 @@ then
 | 
			
		||||
  HOMEBREW_OS_USER_AGENT_VERSION="Mac OS X $HOMEBREW_MACOS_VERSION"
 | 
			
		||||
 | 
			
		||||
  printf -v HOMEBREW_MACOS_VERSION_NUMERIC "%02d%02d%02d" ${HOMEBREW_MACOS_VERSION//./ }
 | 
			
		||||
  if [[ "$HOMEBREW_MACOS_VERSION_NUMERIC" -lt "100900" &&
 | 
			
		||||
  if [[ "$HOMEBREW_MACOS_VERSION_NUMERIC" -lt "101000" ]]
 | 
			
		||||
  then
 | 
			
		||||
    HOMEBREW_SYSTEM_CURL_TOO_OLD="1"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # The system Curl is too old for some modern HTTPS certificates on
 | 
			
		||||
  # older macOS versions.
 | 
			
		||||
  if [[ -n "$HOMEBREW_SYSTEM_CURL_TOO_OLD" &&
 | 
			
		||||
        -x "$HOMEBREW_PREFIX/opt/curl/bin/curl" ]]
 | 
			
		||||
  then
 | 
			
		||||
    HOMEBREW_CURL="$HOMEBREW_PREFIX/opt/curl/bin/curl"
 | 
			
		||||
 | 
			
		||||
@ -112,6 +112,10 @@ class Build
 | 
			
		||||
      formula.extend(Debrew::Formula) if ARGV.debug?
 | 
			
		||||
 | 
			
		||||
      formula.brew do |_formula, staging|
 | 
			
		||||
        # For head builds, HOMEBREW_FORMULA_PREFIX should include the commit,
 | 
			
		||||
        # which is not known until after the formula has been staged.
 | 
			
		||||
        ENV["HOMEBREW_FORMULA_PREFIX"] = formula.prefix
 | 
			
		||||
 | 
			
		||||
        staging.retain! if ARGV.keep_tmp?
 | 
			
		||||
        formula.patch
 | 
			
		||||
 | 
			
		||||
@ -186,7 +190,7 @@ begin
 | 
			
		||||
  options = Options.create(ARGV.flags_only)
 | 
			
		||||
  build   = Build.new(formula, options)
 | 
			
		||||
  build.install
 | 
			
		||||
rescue Exception => e
 | 
			
		||||
rescue Exception => e # rubocop:disable Lint/RescueException
 | 
			
		||||
  Marshal.dump(e, error_pipe)
 | 
			
		||||
  error_pipe.close
 | 
			
		||||
  exit! 1
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,6 @@ require "hbc/scopes"
 | 
			
		||||
require "hbc/staged"
 | 
			
		||||
require "hbc/system_command"
 | 
			
		||||
require "hbc/topological_hash"
 | 
			
		||||
require "hbc/underscore_supporting_uri"
 | 
			
		||||
require "hbc/url"
 | 
			
		||||
require "hbc/utils"
 | 
			
		||||
require "hbc/verify"
 | 
			
		||||
 | 
			
		||||
@ -25,47 +25,5 @@ require "hbc/artifact/zap"
 | 
			
		||||
 | 
			
		||||
module Hbc
 | 
			
		||||
  module Artifact
 | 
			
		||||
    # NOTE: Order is important here!
 | 
			
		||||
    #
 | 
			
		||||
    # The `uninstall` stanza should be run first, as it may
 | 
			
		||||
    # depend on other artifacts still being installed.
 | 
			
		||||
    #
 | 
			
		||||
    # We want to extract nested containers before we
 | 
			
		||||
    # handle any other artifacts.
 | 
			
		||||
    #
 | 
			
		||||
    TYPES = [
 | 
			
		||||
      PreflightBlock,
 | 
			
		||||
      Uninstall,
 | 
			
		||||
      NestedContainer,
 | 
			
		||||
      Installer,
 | 
			
		||||
      App,
 | 
			
		||||
      Suite,
 | 
			
		||||
      Artifact, # generic 'artifact' stanza
 | 
			
		||||
      Colorpicker,
 | 
			
		||||
      Pkg,
 | 
			
		||||
      Prefpane,
 | 
			
		||||
      Qlplugin,
 | 
			
		||||
      Dictionary,
 | 
			
		||||
      Font,
 | 
			
		||||
      Service,
 | 
			
		||||
      StageOnly,
 | 
			
		||||
      Binary,
 | 
			
		||||
      InputMethod,
 | 
			
		||||
      InternetPlugin,
 | 
			
		||||
      AudioUnitPlugin,
 | 
			
		||||
      VstPlugin,
 | 
			
		||||
      Vst3Plugin,
 | 
			
		||||
      ScreenSaver,
 | 
			
		||||
      PostflightBlock,
 | 
			
		||||
      Zap,
 | 
			
		||||
    ].freeze
 | 
			
		||||
 | 
			
		||||
    def self.for_cask(cask, options = {})
 | 
			
		||||
      odebug "Determining which artifacts are present in Cask #{cask}"
 | 
			
		||||
 | 
			
		||||
      TYPES
 | 
			
		||||
        .select { |klass| klass.me?(cask) }
 | 
			
		||||
        .map { |klass| klass.new(cask, options) }
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										109
									
								
								Library/Homebrew/cask/lib/hbc/artifact/abstract_artifact.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								Library/Homebrew/cask/lib/hbc/artifact/abstract_artifact.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,109 @@
 | 
			
		||||
module Hbc
 | 
			
		||||
  module Artifact
 | 
			
		||||
    class AbstractArtifact
 | 
			
		||||
      include Comparable
 | 
			
		||||
      extend Predicable
 | 
			
		||||
 | 
			
		||||
      def self.english_name
 | 
			
		||||
        @english_name ||= name.sub(/^.*:/, "").gsub(/(.)([A-Z])/, '\1 \2')
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def self.english_article
 | 
			
		||||
        @english_article ||= (english_name =~ /^[aeiou]/i) ? "an" : "a"
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def self.dsl_key
 | 
			
		||||
        @dsl_key ||= name.sub(/^.*:/, "").gsub(/(.)([A-Z])/, '\1_\2').downcase.to_sym
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def self.dirmethod
 | 
			
		||||
        @dirmethod ||= "#{dsl_key}dir".to_sym
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def <=>(other)
 | 
			
		||||
        return unless other.class < AbstractArtifact
 | 
			
		||||
        return 0 if self.class == other.class
 | 
			
		||||
 | 
			
		||||
        @@sort_order ||= [ # rubocop:disable Style/ClassVars
 | 
			
		||||
          PreflightBlock,
 | 
			
		||||
          # The `uninstall` stanza should be run first, as it may
 | 
			
		||||
          # depend on other artifacts still being installed.
 | 
			
		||||
          Uninstall,
 | 
			
		||||
          # We want to extract nested containers before we
 | 
			
		||||
          # handle any other artifacts.
 | 
			
		||||
          NestedContainer,
 | 
			
		||||
          Installer,
 | 
			
		||||
          [
 | 
			
		||||
            App,
 | 
			
		||||
            Suite,
 | 
			
		||||
            Artifact,
 | 
			
		||||
            Colorpicker,
 | 
			
		||||
            Prefpane,
 | 
			
		||||
            Qlplugin,
 | 
			
		||||
            Dictionary,
 | 
			
		||||
            Font,
 | 
			
		||||
            Service,
 | 
			
		||||
            InputMethod,
 | 
			
		||||
            InternetPlugin,
 | 
			
		||||
            AudioUnitPlugin,
 | 
			
		||||
            VstPlugin,
 | 
			
		||||
            Vst3Plugin,
 | 
			
		||||
            ScreenSaver,
 | 
			
		||||
          ],
 | 
			
		||||
          # `pkg` should be run before `binary`, so
 | 
			
		||||
          # targets are created prior to linking.
 | 
			
		||||
          Pkg,
 | 
			
		||||
          Binary,
 | 
			
		||||
          PostflightBlock,
 | 
			
		||||
          Zap,
 | 
			
		||||
        ].each_with_index.flat_map { |classes, i| [*classes].map { |c| [c, i] } }.to_h
 | 
			
		||||
 | 
			
		||||
        (@@sort_order[self.class] <=> @@sort_order[other.class]).to_i
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # 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)
 | 
			
		||||
        # TODO: when stanza names are harmonized with class names,
 | 
			
		||||
        #       stanza may not be needed as an explicit argument
 | 
			
		||||
        description = key ? "#{stanza} #{key.inspect}" : stanza.to_s
 | 
			
		||||
 | 
			
		||||
        # backward-compatible string value
 | 
			
		||||
        arguments = { executable: arguments } if arguments.is_a?(String)
 | 
			
		||||
 | 
			
		||||
        # key sanity
 | 
			
		||||
        permitted_keys = [:args, :input, :executable, :must_succeed, :sudo, :print_stdout, :print_stderr]
 | 
			
		||||
        unknown_keys = arguments.keys - permitted_keys
 | 
			
		||||
        unless unknown_keys.empty?
 | 
			
		||||
          opoo %Q{Unknown arguments to #{description} -- #{unknown_keys.inspect} (ignored). Running "brew update; brew cleanup; brew cask cleanup" will likely fix it.}
 | 
			
		||||
        end
 | 
			
		||||
        arguments.select! { |k| permitted_keys.include?(k) }
 | 
			
		||||
 | 
			
		||||
        # key warnings
 | 
			
		||||
        override_keys = override_arguments.keys
 | 
			
		||||
        ignored_keys = arguments.keys & override_keys
 | 
			
		||||
        unless ignored_keys.empty?
 | 
			
		||||
          onoe "Some arguments to #{description} will be ignored -- :#{unknown_keys.inspect} (overridden)."
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        # extract executable
 | 
			
		||||
        executable = arguments.key?(:executable) ? arguments.delete(:executable) : nil
 | 
			
		||||
 | 
			
		||||
        arguments = default_arguments.merge arguments
 | 
			
		||||
        arguments.merge! override_arguments
 | 
			
		||||
 | 
			
		||||
        [executable, arguments]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      attr_reader :cask
 | 
			
		||||
 | 
			
		||||
      def initialize(cask)
 | 
			
		||||
        @cask = cask
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def to_s
 | 
			
		||||
        "#{summarize} (#{self.class.english_name})"
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@ -1,39 +1,45 @@
 | 
			
		||||
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}")
 | 
			
		||||
      attr_reader :directives
 | 
			
		||||
 | 
			
		||||
      def initialize(cask, **directives)
 | 
			
		||||
        super(cask)
 | 
			
		||||
        @directives = directives
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def self.me?(cask)
 | 
			
		||||
        cask.artifacts[artifact_dsl_key].any? ||
 | 
			
		||||
          cask.artifacts[uninstall_artifact_dsl_key].any?
 | 
			
		||||
      def install_phase(**)
 | 
			
		||||
        abstract_phase(self.class.dsl_key)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def install_phase
 | 
			
		||||
        abstract_phase(self.class.artifact_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
 | 
			
		||||
 | 
			
		||||
@ -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]
 | 
			
		||||
        ohai "Running #{stanza} process for #{@cask}; your password may be necessary"
 | 
			
		||||
 | 
			
		||||
        directives_set.each do |directives|
 | 
			
		||||
          warn_for_unknown_directives(directives)
 | 
			
		||||
      def self.from_args(cask, **directives)
 | 
			
		||||
        new(cask, directives)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
        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))
 | 
			
		||||
      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.flat_map { |key, val| [*val].map { |v| "#{key.inspect} => #{v.inspect}" } }.join(", ")
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      def dispatch_uninstall_directives(**options)
 | 
			
		||||
        ohai "Running #{stanza} process for #{@cask}; your password may be necessary"
 | 
			
		||||
 | 
			
		||||
        warn_for_unknown_directives(directives)
 | 
			
		||||
 | 
			
		||||
        ORDERED_DIRECTIVES.each do |directive_sym|
 | 
			
		||||
          next unless directives.key?(directive_sym)
 | 
			
		||||
          args = directives[directive_sym]
 | 
			
		||||
          send("uninstall_#{directive_sym}", *(args.is_a?(Hash) ? [args] : args), **options)
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      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,19 +86,19 @@ 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
 | 
			
		||||
      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|
 | 
			
		||||
@ -92,16 +108,16 @@ module Hbc
 | 
			
		||||
      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, **_)
 | 
			
		||||
        result = 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)
 | 
			
		||||
@ -250,7 +267,7 @@ module Hbc
 | 
			
		||||
                set trashedItem to POSIX path of (item i of trashedItems as string)
 | 
			
		||||
                set output to output & trashedItem
 | 
			
		||||
                if i < count trashedItems then
 | 
			
		||||
                  set output to output & (do shell script "printf \"\\0\"")
 | 
			
		||||
                  set output to output & character id 0
 | 
			
		||||
                end if
 | 
			
		||||
              end repeat
 | 
			
		||||
 | 
			
		||||
@ -258,9 +275,12 @@ module Hbc
 | 
			
		||||
            end tell
 | 
			
		||||
          end run
 | 
			
		||||
        EOS
 | 
			
		||||
 | 
			
		||||
        # Remove AppleScript's automatic newline.
 | 
			
		||||
        result.tap { |r| r.stdout.sub!(/\n$/, "") }
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def uninstall_rmdir(*directories)
 | 
			
		||||
      def uninstall_rmdir(*directories, command: nil, **_)
 | 
			
		||||
        return if directories.empty?
 | 
			
		||||
 | 
			
		||||
        ohai "Removing directories if empty:"
 | 
			
		||||
@ -268,10 +288,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
 | 
			
		||||
@ -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
 | 
			
		||||
      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
 | 
			
		||||
 | 
			
		||||
@ -1,80 +0,0 @@
 | 
			
		||||
module Hbc
 | 
			
		||||
  module Artifact
 | 
			
		||||
    class Base
 | 
			
		||||
      extend Predicable
 | 
			
		||||
 | 
			
		||||
      def self.artifact_name
 | 
			
		||||
        @artifact_name ||= name.sub(/^.*:/, "").gsub(/(.)([A-Z])/, '\1_\2').downcase
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def self.artifact_english_name
 | 
			
		||||
        @artifact_english_name ||= name.sub(/^.*:/, "").gsub(/(.)([A-Z])/, '\1 \2')
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def self.artifact_english_article
 | 
			
		||||
        @artifact_english_article ||= (artifact_english_name =~ /^[aeiou]/i) ? "an" : "a"
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def self.artifact_dsl_key
 | 
			
		||||
        @artifact_dsl_key ||= artifact_name.to_sym
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def self.artifact_dirmethod
 | 
			
		||||
        @artifact_dirmethod ||= "#{artifact_name}dir".to_sym
 | 
			
		||||
      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)
 | 
			
		||||
        # TODO: when stanza names are harmonized with class names,
 | 
			
		||||
        #       stanza may not be needed as an explicit argument
 | 
			
		||||
        description = key ? "#{stanza} #{key.inspect}" : stanza.to_s
 | 
			
		||||
 | 
			
		||||
        # backward-compatible string value
 | 
			
		||||
        arguments = { executable: arguments } if arguments.is_a?(String)
 | 
			
		||||
 | 
			
		||||
        # key sanity
 | 
			
		||||
        permitted_keys = [:args, :input, :executable, :must_succeed, :sudo, :print_stdout, :print_stderr]
 | 
			
		||||
        unknown_keys = arguments.keys - permitted_keys
 | 
			
		||||
        unless unknown_keys.empty?
 | 
			
		||||
          opoo %Q{Unknown arguments to #{description} -- #{unknown_keys.inspect} (ignored). Running "brew update; brew cleanup; brew cask cleanup" will likely fix it.}
 | 
			
		||||
        end
 | 
			
		||||
        arguments.select! { |k| permitted_keys.include?(k) }
 | 
			
		||||
 | 
			
		||||
        # key warnings
 | 
			
		||||
        override_keys = override_arguments.keys
 | 
			
		||||
        ignored_keys = arguments.keys & override_keys
 | 
			
		||||
        unless ignored_keys.empty?
 | 
			
		||||
          onoe "Some arguments to #{description} will be ignored -- :#{unknown_keys.inspect} (overridden)."
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        # extract executable
 | 
			
		||||
        executable = arguments.key?(:executable) ? arguments.delete(:executable) : nil
 | 
			
		||||
 | 
			
		||||
        arguments = default_arguments.merge arguments
 | 
			
		||||
        arguments.merge! override_arguments
 | 
			
		||||
 | 
			
		||||
        [executable, arguments]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def summary
 | 
			
		||||
        {}
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      attr_predicate :force?, :verbose?
 | 
			
		||||
 | 
			
		||||
      def initialize(cask, command: SystemCommand, force: false, verbose: false)
 | 
			
		||||
        @cask = cask
 | 
			
		||||
        @command = command
 | 
			
		||||
        @force = force
 | 
			
		||||
        @verbose = verbose
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
    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
 | 
			
		||||
            To complete the installation of Cask #{cask}, you must also
 | 
			
		||||
            run the installer at
 | 
			
		||||
 | 
			
		||||
                '#{@cask.staged_path.join(artifact.manual)}'
 | 
			
		||||
 | 
			
		||||
              '#{path}'
 | 
			
		||||
          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)
 | 
			
		||||
          end
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -1,23 +1,35 @@
 | 
			
		||||
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 extract(container_relative_path)
 | 
			
		||||
        source = @cask.staged_path.join(container_relative_path)
 | 
			
		||||
        container = Container.for_path(source, @command)
 | 
			
		||||
      def install_phase(**options)
 | 
			
		||||
        extract(**options)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      def summarize
 | 
			
		||||
        path.relative_path_from(cask.staged_path).to_s
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      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
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
require "hbc/artifact/base"
 | 
			
		||||
require "hbc/artifact/abstract_artifact"
 | 
			
		||||
 | 
			
		||||
require "hbc/utils/hash_validator"
 | 
			
		||||
 | 
			
		||||
@ -6,62 +6,61 @@ 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, **stanza_options)
 | 
			
		||||
        stanza_options.extend(HashValidator).assert_valid_keys(
 | 
			
		||||
          :allow_untrusted, :choices
 | 
			
		||||
        )
 | 
			
		||||
        new(cask, path, **stanza_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, :stanza_options
 | 
			
		||||
 | 
			
		||||
      def initialize(cask, path, **stanza_options)
 | 
			
		||||
        super(cask)
 | 
			
		||||
        @path = cask.staged_path.join(path)
 | 
			
		||||
        @stanza_options = stanza_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
 | 
			
		||||
        if stanza_options.fetch(:allow_untrusted, false)
 | 
			
		||||
          args << "-allowUntrusted"
 | 
			
		||||
        end
 | 
			
		||||
        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 = stanza_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
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -8,47 +8,18 @@ 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
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      def link
 | 
			
		||||
        unless source.exist?
 | 
			
		||||
          raise CaskError, "It seems the #{self.class.link_type_english_name.downcase} source '#{source}' is not there."
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        if target.exist? && !target.symlink?
 | 
			
		||||
          raise CaskError, "It seems there is already #{self.class.artifact_english_article} #{self.class.artifact_english_name} at '#{target}'; not linking."
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        ohai "Linking #{self.class.artifact_english_name} '#{source.basename}' to '#{target}'."
 | 
			
		||||
        create_filesystem_link(source, target)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def unlink
 | 
			
		||||
        return unless target.symlink?
 | 
			
		||||
        ohai "Unlinking #{self.class.artifact_english_name} '#{target}'."
 | 
			
		||||
        target.delete
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def create_filesystem_link(source, target)
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
      def summarize_installed
 | 
			
		||||
        if target.symlink? && target.exist? && target.readlink.exist?
 | 
			
		||||
          "#{printable_target} -> #{target.readlink} (#{target.readlink.abv})"
 | 
			
		||||
        else
 | 
			
		||||
@ -61,6 +32,33 @@ module Hbc
 | 
			
		||||
          Formatter.error(string, label: "Broken Link")
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      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.english_article} #{self.class.english_name} at '#{target}'; not linking."
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        ohai "Linking #{self.class.english_name} '#{source.basename}' to '#{target}'."
 | 
			
		||||
        create_filesystem_link(**options)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def unlink(**)
 | 
			
		||||
        return unless target.symlink?
 | 
			
		||||
        ohai "Unlinking #{self.class.english_name} '#{target}'."
 | 
			
		||||
        target.delete
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      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, command: command)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -70,12 +70,16 @@ module Hbc
 | 
			
		||||
      previous_cask_contents = Git.last_revision_of_file(tap.path, @cask.sourcefile_path, before_commit: commit_range)
 | 
			
		||||
      return if previous_cask_contents.empty?
 | 
			
		||||
 | 
			
		||||
      previous_cask = CaskLoader.load_from_string(previous_cask_contents)
 | 
			
		||||
      begin
 | 
			
		||||
        previous_cask = CaskLoader.load(previous_cask_contents)
 | 
			
		||||
 | 
			
		||||
        return unless previous_cask.version == cask.version
 | 
			
		||||
        return if previous_cask.sha256 == cask.sha256
 | 
			
		||||
 | 
			
		||||
        add_error "only sha256 changed (see: https://github.com/caskroom/homebrew-cask/blob/master/doc/cask_language_reference/stanzas/sha256.md)"
 | 
			
		||||
      rescue CaskError => e
 | 
			
		||||
        add_warning "Skipped version and checksum comparison. Reading previous version failed: #{e}"
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def check_version
 | 
			
		||||
@ -143,7 +147,15 @@ module Hbc
 | 
			
		||||
 | 
			
		||||
    def check_appcast_http_code
 | 
			
		||||
      odebug "Verifying appcast returns 200 HTTP response code"
 | 
			
		||||
      result = @command.run("/usr/bin/curl", args: ["--compressed", "--location", "--user-agent", URL::FAKE_USER_AGENT, "--output", "/dev/null", "--write-out", "%{http_code}", cask.appcast], print_stderr: false)
 | 
			
		||||
 | 
			
		||||
      curl_executable, *args = curl_args(
 | 
			
		||||
        "--compressed", "--location", "--fail",
 | 
			
		||||
        "--write-out", "%{http_code}",
 | 
			
		||||
        "--output", "/dev/null",
 | 
			
		||||
        cask.appcast,
 | 
			
		||||
        user_agent: :fake
 | 
			
		||||
      )
 | 
			
		||||
      result = @command.run(curl_executable, args: args, print_stderr: false)
 | 
			
		||||
      if result.success?
 | 
			
		||||
        http_code = result.stdout.chomp
 | 
			
		||||
        add_warning "unexpected HTTP response code retrieving appcast: #{http_code}" unless http_code == "200"
 | 
			
		||||
@ -206,12 +218,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.select { |a| a.is_a?(Hbc::Artifact::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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -43,7 +43,7 @@ module Hbc
 | 
			
		||||
    def audit_languages(languages)
 | 
			
		||||
      ohai "Auditing language: #{languages.map { |lang| "'#{lang}'" }.join(", ")}"
 | 
			
		||||
      MacOS.instance_variable_set(:@languages, languages)
 | 
			
		||||
      audit_cask_instance(CaskLoader.load_from_file(cask.sourcefile_path))
 | 
			
		||||
      audit_cask_instance(CaskLoader.load(cask.sourcefile_path))
 | 
			
		||||
    ensure
 | 
			
		||||
      CLI::Cleanup.run(cask.token) if audit_download?
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,18 @@ module Hbc
 | 
			
		||||
    class FromContentLoader
 | 
			
		||||
      attr_reader :content
 | 
			
		||||
 | 
			
		||||
      def self.can_load?(ref)
 | 
			
		||||
        return false unless ref.respond_to?(:to_str)
 | 
			
		||||
        content = ref.to_str
 | 
			
		||||
 | 
			
		||||
        token  = /(?:"[^"]*"|'[^']*')/
 | 
			
		||||
        curly  = /\(\s*#{token}\s*\)\s*\{.*\}/
 | 
			
		||||
        do_end = /\s+#{token}\s+do(?:\s*;\s*|\s+).*end/
 | 
			
		||||
        regex  = /\A\s*cask(?:#{curly.source}|#{do_end.source})\s*\Z/m
 | 
			
		||||
 | 
			
		||||
        content.match?(regex)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def initialize(content)
 | 
			
		||||
        @content = content
 | 
			
		||||
      end
 | 
			
		||||
@ -56,7 +68,8 @@ module Hbc
 | 
			
		||||
 | 
			
		||||
    class FromURILoader < FromPathLoader
 | 
			
		||||
      def self.can_load?(ref)
 | 
			
		||||
        ref.to_s.match?(::URI.regexp)
 | 
			
		||||
        uri_regex = ::URI::DEFAULT_PARSER.make_regexp
 | 
			
		||||
        ref.to_s.match?(Regexp.new('\A' + uri_regex.source + '\Z', uri_regex.options))
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      attr_reader :url
 | 
			
		||||
@ -71,7 +84,7 @@ module Hbc
 | 
			
		||||
 | 
			
		||||
        begin
 | 
			
		||||
          ohai "Downloading #{url}."
 | 
			
		||||
          curl url, "-o", path
 | 
			
		||||
          curl_download url, to: path
 | 
			
		||||
        rescue ErrorDuringExecution
 | 
			
		||||
          raise CaskUnavailableError.new(token, "Failed to download #{Formatter.url(url)}.")
 | 
			
		||||
        end
 | 
			
		||||
@ -116,6 +129,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
 | 
			
		||||
@ -131,14 +160,6 @@ module Hbc
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def self.load_from_file(path)
 | 
			
		||||
      FromPathLoader.new(path).load
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def self.load_from_string(content)
 | 
			
		||||
      FromContentLoader.new(content).load
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def self.path(ref)
 | 
			
		||||
      self.for(ref).path
 | 
			
		||||
    end
 | 
			
		||||
@ -149,6 +170,8 @@ module Hbc
 | 
			
		||||
 | 
			
		||||
    def self.for(ref)
 | 
			
		||||
      [
 | 
			
		||||
        FromInstanceLoader,
 | 
			
		||||
        FromContentLoader,
 | 
			
		||||
        FromURILoader,
 | 
			
		||||
        FromTapLoader,
 | 
			
		||||
        FromTapPathLoader,
 | 
			
		||||
 | 
			
		||||
@ -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.each do |cask_or_token|
 | 
			
		||||
          begin
 | 
			
		||||
            yield cask_or_token.respond_to?(:token) ? cask_or_token : CaskLoader.load(cask_or_token)
 | 
			
		||||
            count += 1
 | 
			
		||||
        @casks = casks.map { |cask| CaskLoader.load(cask) }
 | 
			
		||||
      rescue CaskUnavailableError => e
 | 
			
		||||
            cask_token = cask_or_token
 | 
			
		||||
            self.class.warn_unavailable_with_suggestion cask_token, e
 | 
			
		||||
          rescue CaskError => e
 | 
			
		||||
            onoe e.message
 | 
			
		||||
          end
 | 
			
		||||
        reason = [e.reason, suggestion_message(e.token)].join(" ")
 | 
			
		||||
        raise e.class.new(e.token, reason)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
        return :empty if casks.length.zero?
 | 
			
		||||
        (count == casks.length) ? :complete : :incomplete
 | 
			
		||||
      def suggestion_message(cask_token)
 | 
			
		||||
        exact_match, partial_matches = Search.search(cask_token)
 | 
			
		||||
 | 
			
		||||
        if exact_match.nil? && partial_matches.count == 1
 | 
			
		||||
          exact_match = partial_matches.first
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -4,23 +4,20 @@ 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
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
        odebug "Opening editor for Cask #{cask_token}"
 | 
			
		||||
        exec_editor cask_path
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def self.help
 | 
			
		||||
        "edits the given Cask"
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -23,6 +23,7 @@ module Hbc
 | 
			
		||||
        installation_info(cask)
 | 
			
		||||
        repo_info(cask)
 | 
			
		||||
        name_info(cask)
 | 
			
		||||
        language_info(cask)
 | 
			
		||||
        artifact_info(cask)
 | 
			
		||||
        Installer.print_caveats(cask)
 | 
			
		||||
      end
 | 
			
		||||
@ -51,6 +52,13 @@ module Hbc
 | 
			
		||||
        puts cask.name.empty? ? Formatter.error("None") : cask.name
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def self.language_info(cask)
 | 
			
		||||
        return if cask.languages.empty?
 | 
			
		||||
 | 
			
		||||
        ohai "Languages"
 | 
			
		||||
        puts cask.languages.join(", ")
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def self.repo_info(cask)
 | 
			
		||||
        user, repo, token = QualifiedToken.parse(Hbc.all_tokens.detect { |t| t.split("/").last == cask.token })
 | 
			
		||||
 | 
			
		||||
@ -69,12 +77,10 @@ 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
 | 
			
		||||
        cask.artifacts.each do |artifact|
 | 
			
		||||
          next unless artifact.respond_to?(:install_phase)
 | 
			
		||||
          next unless DSL::ORDINARY_ARTIFACT_CLASSES.include?(artifact.class)
 | 
			
		||||
          puts artifact.to_s
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -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?,
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -59,7 +59,7 @@ module Hbc
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def modified_cask_files
 | 
			
		||||
        @modified_cask_files ||= git_filter_cask_files("AM")
 | 
			
		||||
        @modified_cask_files ||= git_filter_cask_files("AMR")
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def added_cask_files
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
          if @format
 | 
			
		||||
            puts value.send(@format)
 | 
			
		||||
          elsif artifact_name || value.is_a?(Symbol)
 | 
			
		||||
                [k, v]
 | 
			
		||||
              end
 | 
			
		||||
            ]
 | 
			
		||||
 | 
			
		||||
            value = value.fetch(artifact_name) if artifact_name
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          if format
 | 
			
		||||
            puts value.send(format)
 | 
			
		||||
          elsif value.is_a?(Symbol)
 | 
			
		||||
            puts value.inspect
 | 
			
		||||
          else
 | 
			
		||||
            puts value.to_s
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
@ -23,16 +23,16 @@ module Hbc
 | 
			
		||||
          elsif versions?
 | 
			
		||||
            puts self.class.format_versioned(cask)
 | 
			
		||||
          else
 | 
			
		||||
            cask = CaskLoader.load_from_file(cask.installed_caskfile)
 | 
			
		||||
            cask = CaskLoader.load(cask.installed_caskfile)
 | 
			
		||||
            self.class.list_artifacts(cask)
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      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?
 | 
			
		||||
        cask.artifacts.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)
 | 
			
		||||
 | 
			
		||||
@ -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?,
 | 
			
		||||
 | 
			
		||||
@ -2,9 +2,13 @@ module Hbc
 | 
			
		||||
  class CLI
 | 
			
		||||
    class Search < AbstractCommand
 | 
			
		||||
      def run
 | 
			
		||||
        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)
 | 
			
		||||
        if string =~ %r{^/(.*)/$}
 | 
			
		||||
@ -15,8 +19,18 @@ module Hbc
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def self.search_remote(query)
 | 
			
		||||
        matches = GitHub.search_code("user:caskroom", "path:Casks", "filename:#{query}", "extension:rb")
 | 
			
		||||
        [*matches].map do |match|
 | 
			
		||||
        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?
 | 
			
		||||
          "#{tap.name}/#{File.basename(match["path"], ".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}"
 | 
			
		||||
 | 
			
		||||
@ -20,7 +16,7 @@ module Hbc
 | 
			
		||||
 | 
			
		||||
          if cask.installed? && !cask.installed_caskfile.nil?
 | 
			
		||||
            # use the same cask file that was used for installation, if possible
 | 
			
		||||
            cask = CaskLoader.load_from_file(cask.installed_caskfile) if cask.installed_caskfile.exist?
 | 
			
		||||
            cask = CaskLoader.load(cask.installed_caskfile) if cask.installed_caskfile.exist?
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          Installer.new(cask, binaries: binaries?, verbose: verbose?, force: force?).uninstall
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ require "hbc/container/bzip2"
 | 
			
		||||
require "hbc/container/cab"
 | 
			
		||||
require "hbc/container/criteria"
 | 
			
		||||
require "hbc/container/dmg"
 | 
			
		||||
require "hbc/container/directory"
 | 
			
		||||
require "hbc/container/executable"
 | 
			
		||||
require "hbc/container/generic_unar"
 | 
			
		||||
require "hbc/container/gpg"
 | 
			
		||||
@ -14,6 +15,7 @@ require "hbc/container/otf"
 | 
			
		||||
require "hbc/container/pkg"
 | 
			
		||||
require "hbc/container/seven_zip"
 | 
			
		||||
require "hbc/container/sit"
 | 
			
		||||
require "hbc/container/svn_repository"
 | 
			
		||||
require "hbc/container/tar"
 | 
			
		||||
require "hbc/container/ttf"
 | 
			
		||||
require "hbc/container/rar"
 | 
			
		||||
@ -43,6 +45,7 @@ module Hbc
 | 
			
		||||
        Xz,    # pure xz
 | 
			
		||||
        Gpg,   # GnuPG signed data
 | 
			
		||||
        Executable,
 | 
			
		||||
        SvnRepository,
 | 
			
		||||
      ]
 | 
			
		||||
      # for explicit use only (never autodetected):
 | 
			
		||||
      # Hbc::Container::Naked
 | 
			
		||||
 | 
			
		||||
@ -20,7 +20,7 @@ module Hbc
 | 
			
		||||
 | 
			
		||||
        unless children.count == 1 &&
 | 
			
		||||
               !nested_container.directory? &&
 | 
			
		||||
               @cask.artifacts[:nested_container].empty? &&
 | 
			
		||||
               @cask.artifacts.none? { |a| a.is_a?(Artifact::NestedContainer) } &&
 | 
			
		||||
               extract_nested_container(nested_container)
 | 
			
		||||
 | 
			
		||||
          children.each do |src|
 | 
			
		||||
 | 
			
		||||
@ -13,9 +13,11 @@ module Hbc
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def magic_number(regex)
 | 
			
		||||
        return false if path.directory?
 | 
			
		||||
 | 
			
		||||
        # 262: length of the longest regex (currently: Hbc::Container::Tar)
 | 
			
		||||
        @magic_number ||= File.open(@path, "rb") { |f| f.read(262) }
 | 
			
		||||
        @magic_number =~ regex
 | 
			
		||||
        @magic_number ||= File.open(path, "rb") { |f| f.read(262) }
 | 
			
		||||
        @magic_number.match?(regex)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										24
									
								
								Library/Homebrew/cask/lib/hbc/container/directory.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								Library/Homebrew/cask/lib/hbc/container/directory.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
require "hbc/container/base"
 | 
			
		||||
 | 
			
		||||
module Hbc
 | 
			
		||||
  class Container
 | 
			
		||||
    class Directory < Base
 | 
			
		||||
      def self.me?(*)
 | 
			
		||||
        false
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def extract
 | 
			
		||||
        @path.children.each do |child|
 | 
			
		||||
          next if skip_path?(child)
 | 
			
		||||
          FileUtils.cp child, @cask.staged_path
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      def skip_path?(*)
 | 
			
		||||
        false
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@ -8,7 +8,7 @@ module Hbc
 | 
			
		||||
        return true if criteria.magic_number(/^#!\s*\S+/)
 | 
			
		||||
 | 
			
		||||
        begin
 | 
			
		||||
          MachO.open(criteria.path).header.executable?
 | 
			
		||||
          criteria.path.file? && MachO.open(criteria.path).header.executable?
 | 
			
		||||
        rescue MachO::MagicError
 | 
			
		||||
          false
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								Library/Homebrew/cask/lib/hbc/container/svn_repository.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								Library/Homebrew/cask/lib/hbc/container/svn_repository.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
require "hbc/container/directory"
 | 
			
		||||
 | 
			
		||||
module Hbc
 | 
			
		||||
  class Container
 | 
			
		||||
    class SvnRepository < Directory
 | 
			
		||||
      def self.me?(criteria)
 | 
			
		||||
        criteria.path.join(".svn").directory?
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def skip_path?(path)
 | 
			
		||||
        path.basename.to_s == ".svn"
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@ -10,7 +10,7 @@ module Hbc
 | 
			
		||||
  class AbstractDownloadStrategy
 | 
			
		||||
    attr_reader :cask, :name, :url, :uri_object, :version
 | 
			
		||||
 | 
			
		||||
    def initialize(cask, command = SystemCommand)
 | 
			
		||||
    def initialize(cask, command: SystemCommand)
 | 
			
		||||
      @cask       = cask
 | 
			
		||||
      @command    = command
 | 
			
		||||
      # TODO: this excess of attributes is a function of integrating
 | 
			
		||||
@ -33,8 +33,8 @@ module Hbc
 | 
			
		||||
  class HbVCSDownloadStrategy < AbstractDownloadStrategy
 | 
			
		||||
    REF_TYPES = [:branch, :revision, :revisions, :tag].freeze
 | 
			
		||||
 | 
			
		||||
    def initialize(cask, command = SystemCommand)
 | 
			
		||||
      super
 | 
			
		||||
    def initialize(*args, **options)
 | 
			
		||||
      super(*args, **options)
 | 
			
		||||
      @ref_type, @ref = extract_ref
 | 
			
		||||
      @clone = Hbc.cache.join(cache_filename)
 | 
			
		||||
    end
 | 
			
		||||
@ -64,11 +64,6 @@ module Hbc
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  class CurlDownloadStrategy < AbstractDownloadStrategy
 | 
			
		||||
    # TODO: should be part of url object
 | 
			
		||||
    def mirrors
 | 
			
		||||
      @mirrors ||= []
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def tarball_path
 | 
			
		||||
      @tarball_path ||= Hbc.cache.join("#{name}--#{version}#{ext}")
 | 
			
		||||
    end
 | 
			
		||||
@ -95,13 +90,8 @@ module Hbc
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def downloaded_size
 | 
			
		||||
      temporary_path.size? || 0
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def _fetch
 | 
			
		||||
      odebug "Calling curl with args #{cask_curl_args}"
 | 
			
		||||
      curl(*cask_curl_args)
 | 
			
		||||
      curl_download url, *cask_curl_args, to: temporary_path, user_agent: uri_object.user_agent
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def fetch
 | 
			
		||||
@ -131,33 +121,12 @@ module Hbc
 | 
			
		||||
        ignore_interrupts { temporary_path.rename(tarball_path) }
 | 
			
		||||
      end
 | 
			
		||||
      tarball_path
 | 
			
		||||
    rescue CurlDownloadStrategyError
 | 
			
		||||
      raise if mirrors.empty?
 | 
			
		||||
      puts "Trying a mirror..."
 | 
			
		||||
      @url = mirrors.shift
 | 
			
		||||
      retry
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
    def cask_curl_args
 | 
			
		||||
      default_curl_args.tap do |args|
 | 
			
		||||
        args.concat(user_agent_args)
 | 
			
		||||
        args.concat(cookies_args)
 | 
			
		||||
        args.concat(referer_args)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def default_curl_args
 | 
			
		||||
      [url, "-C", downloaded_size, "-o", temporary_path]
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def user_agent_args
 | 
			
		||||
      if uri_object.user_agent
 | 
			
		||||
        ["-A", uri_object.user_agent]
 | 
			
		||||
      else
 | 
			
		||||
        []
 | 
			
		||||
      end
 | 
			
		||||
      cookies_args + referer_args
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def cookies_args
 | 
			
		||||
@ -191,8 +160,7 @@ module Hbc
 | 
			
		||||
 | 
			
		||||
  class CurlPostDownloadStrategy < CurlDownloadStrategy
 | 
			
		||||
    def cask_curl_args
 | 
			
		||||
      super
 | 
			
		||||
      default_curl_args.concat(post_args)
 | 
			
		||||
      super.concat(post_args)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def post_args
 | 
			
		||||
@ -225,8 +193,8 @@ module Hbc
 | 
			
		||||
 | 
			
		||||
    # super does not provide checks for already-existing downloads
 | 
			
		||||
    def fetch
 | 
			
		||||
      if tarball_path.exist?
 | 
			
		||||
        puts "Already downloaded: #{tarball_path}"
 | 
			
		||||
      if cached_location.directory?
 | 
			
		||||
        puts "Already downloaded: #{cached_location}"
 | 
			
		||||
      else
 | 
			
		||||
        @url = @url.sub(/^svn\+/, "") if @url =~ %r{^svn\+http://}
 | 
			
		||||
        ohai "Checking out #{@url}"
 | 
			
		||||
@ -252,9 +220,8 @@ module Hbc
 | 
			
		||||
        else
 | 
			
		||||
          fetch_repo @clone, @url
 | 
			
		||||
        end
 | 
			
		||||
        compress
 | 
			
		||||
      end
 | 
			
		||||
      tarball_path
 | 
			
		||||
      cached_location
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # This primary reason for redefining this method is the trust_cert
 | 
			
		||||
@ -288,10 +255,6 @@ module Hbc
 | 
			
		||||
                    print_stderr: false)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def tarball_path
 | 
			
		||||
      @tarball_path ||= cached_location.dirname.join(cached_location.basename.to_s + "-#{@cask.version}.tar")
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def shell_quote(str)
 | 
			
		||||
      # Oh god escaping shell args.
 | 
			
		||||
      # See http://notetoself.vrensk.com/2008/08/escaping-single-quotes-in-ruby-harder-than-expected/
 | 
			
		||||
@ -304,35 +267,5 @@ module Hbc
 | 
			
		||||
        yield name, url
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
    # TODO/UPDATE: the tar approach explained below is fragile
 | 
			
		||||
    # against challenges such as case-sensitive filesystems,
 | 
			
		||||
    # and must be re-implemented.
 | 
			
		||||
    #
 | 
			
		||||
    # Seems nutty: we "download" the contents into a tape archive.
 | 
			
		||||
    # Why?
 | 
			
		||||
    # * A single file is tractable to the rest of the Cask toolchain,
 | 
			
		||||
    # * An alternative would be to create a Directory container type.
 | 
			
		||||
    #   However, some type of file-serialization trick would still be
 | 
			
		||||
    #   needed in order to enable calculating a single checksum over
 | 
			
		||||
    #   a directory.  So, in that alternative implementation, the
 | 
			
		||||
    #   special cases would propagate outside this class, including
 | 
			
		||||
    #   the use of tar or equivalent.
 | 
			
		||||
    # * SubversionDownloadStrategy.cached_location is not versioned
 | 
			
		||||
    # * tarball_path provides a needed return value for our overridden
 | 
			
		||||
    #   fetch method.
 | 
			
		||||
    # * We can also take this private opportunity to strip files from
 | 
			
		||||
    #   the download which are protocol-specific.
 | 
			
		||||
 | 
			
		||||
    def compress
 | 
			
		||||
      Dir.chdir(cached_location) do
 | 
			
		||||
        @command.run!("/usr/bin/tar",
 | 
			
		||||
                      args:         ['-s/^\.//', "--exclude", ".svn", "-cf", Pathname.new(tarball_path), "--", "."],
 | 
			
		||||
                      print_stderr: false)
 | 
			
		||||
      end
 | 
			
		||||
      clear_cache
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
    ACTIVATABLE_ARTIFACT_CLASSES = ORDINARY_ARTIFACT_CLASSES - [Artifact::StageOnly]
 | 
			
		||||
 | 
			
		||||
    SPECIAL_ARTIFACT_TYPES = [
 | 
			
		||||
      :uninstall,
 | 
			
		||||
      :zap,
 | 
			
		||||
    ].freeze
 | 
			
		||||
 | 
			
		||||
    ARTIFACT_BLOCK_TYPES = [
 | 
			
		||||
      :preflight,
 | 
			
		||||
      :postflight,
 | 
			
		||||
      :uninstall_preflight,
 | 
			
		||||
      :uninstall_postflight,
 | 
			
		||||
    ARTIFACT_BLOCK_CLASSES = [
 | 
			
		||||
      Artifact::PreflightBlock,
 | 
			
		||||
      Artifact::PostflightBlock,
 | 
			
		||||
    ].freeze
 | 
			
		||||
 | 
			
		||||
    DSL_METHODS = Set.new [
 | 
			
		||||
@ -66,21 +63,23 @@ module Hbc
 | 
			
		||||
      :gpg,
 | 
			
		||||
      :homepage,
 | 
			
		||||
      :language,
 | 
			
		||||
      :languages,
 | 
			
		||||
      :name,
 | 
			
		||||
      :sha256,
 | 
			
		||||
      :staged_path,
 | 
			
		||||
      :url,
 | 
			
		||||
      :version,
 | 
			
		||||
      :appdir,
 | 
			
		||||
      *ORDINARY_ARTIFACT_TYPES,
 | 
			
		||||
      *ACTIVATABLE_ARTIFACT_TYPES,
 | 
			
		||||
      *SPECIAL_ARTIFACT_TYPES,
 | 
			
		||||
      *ARTIFACT_BLOCK_TYPES,
 | 
			
		||||
      *ORDINARY_ARTIFACT_CLASSES.map(&:dsl_key),
 | 
			
		||||
      *ACTIVATABLE_ARTIFACT_CLASSES.map(&:dsl_key),
 | 
			
		||||
      *ARTIFACT_BLOCK_CLASSES.flat_map { |klass| [klass.dsl_key, klass.uninstall_dsl_key] },
 | 
			
		||||
    ].freeze
 | 
			
		||||
 | 
			
		||||
    attr_reader :token
 | 
			
		||||
    def initialize(token)
 | 
			
		||||
      @token = token
 | 
			
		||||
    attr_reader :cask, :token
 | 
			
		||||
 | 
			
		||||
    def initialize(cask)
 | 
			
		||||
      @cask = cask
 | 
			
		||||
      @token = cask.token
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def name(*args)
 | 
			
		||||
@ -93,12 +92,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)
 | 
			
		||||
@ -106,19 +107,21 @@ module Hbc
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def language(*args, default: false, &block)
 | 
			
		||||
      if !args.empty? && block_given?
 | 
			
		||||
      if args.empty?
 | 
			
		||||
        language_eval
 | 
			
		||||
      elsif block_given?
 | 
			
		||||
        @language_blocks ||= {}
 | 
			
		||||
        @language_blocks[args] = block
 | 
			
		||||
 | 
			
		||||
        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
 | 
			
		||||
      else
 | 
			
		||||
        language_eval
 | 
			
		||||
        raise CaskInvalidError.new(cask, "No block given to language stanza.")
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -127,6 +130,10 @@ module Hbc
 | 
			
		||||
 | 
			
		||||
      return @language = nil if @language_blocks.nil? || @language_blocks.empty?
 | 
			
		||||
 | 
			
		||||
      if @language_blocks.default.nil?
 | 
			
		||||
        raise CaskInvalidError.new(cask, "No default language specified.")
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      MacOS.languages.map(&Locale.method(:parse)).each do |locale|
 | 
			
		||||
        key = @language_blocks.keys.detect do |strings|
 | 
			
		||||
          strings.any? { |string| locale.include?(string) }
 | 
			
		||||
@ -140,6 +147,12 @@ module Hbc
 | 
			
		||||
      @language = @language_blocks.default.call
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def languages
 | 
			
		||||
      return [] if @language_blocks.nil?
 | 
			
		||||
 | 
			
		||||
      @language_blocks.keys.flatten
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def url(*args, &block)
 | 
			
		||||
      set_unique_stanza(:url, args.empty? && !block_given?) do
 | 
			
		||||
        begin
 | 
			
		||||
@ -162,8 +175,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.add(Artifact::NestedContainer.new(cask, container.nested))
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
@ -173,7 +186,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 +195,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 +208,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
 | 
			
		||||
@ -206,7 +219,7 @@ module Hbc
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def artifacts
 | 
			
		||||
      @artifacts ||= Hash.new { |hash, key| hash[key] = Set.new }
 | 
			
		||||
      @artifacts ||= SortedSet.new
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def caskroom_path
 | 
			
		||||
@ -237,39 +250,27 @@ module Hbc
 | 
			
		||||
      set_unique_stanza(:auto_updates, auto_updates.nil?) { auto_updates }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    ORDINARY_ARTIFACT_TYPES.each do |type|
 | 
			
		||||
      define_method(type) do |*args|
 | 
			
		||||
        if type == :stage_only
 | 
			
		||||
          if args != [true]
 | 
			
		||||
            raise CaskInvalidError.new(token, "'stage_only' takes a single argument: true")
 | 
			
		||||
    ORDINARY_ARTIFACT_CLASSES.each do |klass|
 | 
			
		||||
      define_method(klass.dsl_key) do |*args|
 | 
			
		||||
        begin
 | 
			
		||||
          if [*artifacts.map(&:class), klass].include?(Artifact::StageOnly) && (artifacts.map(&:class) & ACTIVATABLE_ARTIFACT_CLASSES).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
 | 
			
		||||
        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)
 | 
			
		||||
          artifacts.add(klass.from_args(cask, *args))
 | 
			
		||||
        rescue CaskInvalidError
 | 
			
		||||
          raise
 | 
			
		||||
        rescue StandardError => e
 | 
			
		||||
      raise CaskInvalidError.new(token, e)
 | 
			
		||||
          raise CaskInvalidError.new(cask, "invalid '#{klass.dsl_key}' stanza: #{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.add(klass.new(cask, dsl_key => block))
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -3,16 +3,20 @@ require "hbc/system_command"
 | 
			
		||||
module Hbc
 | 
			
		||||
  class DSL
 | 
			
		||||
    class Appcast
 | 
			
		||||
      attr_reader :parameters, :checkpoint
 | 
			
		||||
      attr_reader :uri, :checkpoint, :parameters
 | 
			
		||||
 | 
			
		||||
      def initialize(uri, parameters = {})
 | 
			
		||||
      def initialize(uri, **parameters)
 | 
			
		||||
        @uri        = URI(uri)
 | 
			
		||||
        @parameters = parameters
 | 
			
		||||
        @uri            = UnderscoreSupportingURI.parse(uri)
 | 
			
		||||
        @checkpoint     = @parameters[:checkpoint]
 | 
			
		||||
        @checkpoint = parameters[:checkpoint]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def calculate_checkpoint
 | 
			
		||||
        result = SystemCommand.run("/usr/bin/curl", args: ["--compressed", "--location", "--user-agent", URL::FAKE_USER_AGENT, "--fail", @uri], print_stderr: false)
 | 
			
		||||
        curl_executable, *args = curl_args(
 | 
			
		||||
          "--compressed", "--location", "--fail", uri,
 | 
			
		||||
          user_agent: :fake
 | 
			
		||||
        )
 | 
			
		||||
        result = SystemCommand.run(curl_executable, args: args, print_stderr: false)
 | 
			
		||||
 | 
			
		||||
        checkpoint = if result.success?
 | 
			
		||||
          processed_appcast_text = result.stdout.gsub(%r{<pubDate>[^<]*</pubDate>}m, "")
 | 
			
		||||
@ -26,11 +30,11 @@ module Hbc
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def to_yaml
 | 
			
		||||
        [@uri, @parameters].to_yaml
 | 
			
		||||
        [uri, parameters].to_yaml
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def to_s
 | 
			
		||||
        @uri.to_s
 | 
			
		||||
        uri.to_s
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -10,14 +10,14 @@ module Hbc
 | 
			
		||||
 | 
			
		||||
      def_delegators :@cask, :token, :version, :caskroom_path, :staged_path, :appdir, :language
 | 
			
		||||
 | 
			
		||||
      def system_command(executable, options = {})
 | 
			
		||||
        @command.run!(executable, options)
 | 
			
		||||
      def system_command(executable, **options)
 | 
			
		||||
        @command.run!(executable, **options)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def method_missing(method, *)
 | 
			
		||||
        if method
 | 
			
		||||
          underscored_class = self.class.name.gsub(/([[:lower:]])([[:upper:]][[:lower:]])/, '\1_\2').downcase
 | 
			
		||||
          section = underscored_class.downcase.split("::").last
 | 
			
		||||
          section = underscored_class.split("::").last
 | 
			
		||||
          Utils.method_missing_message(method, @cask.to_s, section)
 | 
			
		||||
          nil
 | 
			
		||||
        else
 | 
			
		||||
 | 
			
		||||
@ -48,7 +48,7 @@ module Hbc
 | 
			
		||||
            brew cask install java
 | 
			
		||||
 | 
			
		||||
          EOS
 | 
			
		||||
        elsif java_version.include?("8") || java_version.include?("+")
 | 
			
		||||
        elsif java_version.include?("9") || java_version.include?("+")
 | 
			
		||||
          puts <<-EOS.undent
 | 
			
		||||
          #{@cask} requires Java #{java_version}. You can install the latest version with
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -10,24 +10,19 @@ module Hbc
 | 
			
		||||
        :java,
 | 
			
		||||
      ]
 | 
			
		||||
 | 
			
		||||
      attr_accessor(*VALID_KEYS)
 | 
			
		||||
      attr_accessor :pairs
 | 
			
		||||
      attr_reader *VALID_KEYS
 | 
			
		||||
 | 
			
		||||
      def initialize(pairs = {})
 | 
			
		||||
        @pairs = pairs
 | 
			
		||||
 | 
			
		||||
        VALID_KEYS.each do |key|
 | 
			
		||||
          instance_variable_set("@#{key}", Set.new)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        pairs.each do |key, value|
 | 
			
		||||
          raise "invalid conflicts_with key: '#{key.inspect}'" unless VALID_KEYS.include?(key)
 | 
			
		||||
          writer_method = "#{key}=".to_sym
 | 
			
		||||
          send(writer_method, value)
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def to_yaml
 | 
			
		||||
        @pairs.to_yaml
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def to_s
 | 
			
		||||
        @pairs.inspect
 | 
			
		||||
          instance_variable_set("@#{key}", instance_variable_get("@#{key}").merge([*value]))
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -14,11 +14,11 @@ module Hbc
 | 
			
		||||
 | 
			
		||||
      def initialize(signature, parameters = {})
 | 
			
		||||
        @parameters = parameters
 | 
			
		||||
        @signature = UnderscoreSupportingURI.parse(signature)
 | 
			
		||||
        @signature = URI(signature)
 | 
			
		||||
        parameters.each do |hkey, hvalue|
 | 
			
		||||
          raise "invalid 'gpg' parameter: '#{hkey.inspect}'" unless VALID_PARAMETERS.include?(hkey)
 | 
			
		||||
          writer_method = "#{hkey}=".to_sym
 | 
			
		||||
          hvalue = UnderscoreSupportingURI.parse(hvalue) if hkey == :key_url
 | 
			
		||||
          hvalue = URI(hvalue) if hkey == :key_url
 | 
			
		||||
          valid_id?(hvalue) if hkey == :key_id
 | 
			
		||||
          send(writer_method, hvalue)
 | 
			
		||||
        end
 | 
			
		||||
@ -35,7 +35,7 @@ module Hbc
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def to_yaml
 | 
			
		||||
        # bug, :key_url value is not represented as an instance of Hbc::UnderscoreSupportingURI
 | 
			
		||||
        # bug, :key_url value is not represented as an instance of URI
 | 
			
		||||
        [@signature, @parameters].to_yaml
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
@ -49,7 +49,7 @@ module Hbc
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      DIVIDERS.keys.each do |divider|
 | 
			
		||||
      DIVIDERS.each_key do |divider|
 | 
			
		||||
        define_divider_methods(divider)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,19 @@ module Hbc
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  class CaskConflictError < AbstractCaskErrorWithToken
 | 
			
		||||
    attr_reader :conflicting_cask
 | 
			
		||||
 | 
			
		||||
    def initialize(token, conflicting_cask)
 | 
			
		||||
      super(token)
 | 
			
		||||
      @conflicting_cask = conflicting_cask
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def to_s
 | 
			
		||||
      "Cask '#{token}' conflicts with '#{conflicting_cask}'."
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  class CaskUnavailableError < AbstractCaskErrorWithToken
 | 
			
		||||
    def to_s
 | 
			
		||||
      "Cask '#{token}' is unavailable" << (reason.empty? ? "." : ": #{reason}")
 | 
			
		||||
 | 
			
		||||
@ -86,6 +86,8 @@ module Hbc
 | 
			
		||||
        raise CaskAlreadyInstalledError, @cask
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      check_conflicts
 | 
			
		||||
 | 
			
		||||
      print_caveats
 | 
			
		||||
      fetch
 | 
			
		||||
      uninstall_existing_cask if @reinstall
 | 
			
		||||
@ -98,6 +100,21 @@ module Hbc
 | 
			
		||||
      puts summary
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def check_conflicts
 | 
			
		||||
      return unless @cask.conflicts_with
 | 
			
		||||
 | 
			
		||||
      @cask.conflicts_with.cask.each do |conflicting_cask|
 | 
			
		||||
        begin
 | 
			
		||||
          conflicting_cask = CaskLoader.load(conflicting_cask)
 | 
			
		||||
          if conflicting_cask.installed?
 | 
			
		||||
            raise CaskConflictError.new(@cask, conflicting_cask)
 | 
			
		||||
          end
 | 
			
		||||
        rescue CaskUnavailableError
 | 
			
		||||
          next # Ignore conflicting Casks that do not exist.
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def reinstall
 | 
			
		||||
      odebug "Hbc::Installer#reinstall"
 | 
			
		||||
      @reinstall = true
 | 
			
		||||
@ -109,7 +126,7 @@ module Hbc
 | 
			
		||||
 | 
			
		||||
      # use the same cask file that was used for installation, if possible
 | 
			
		||||
      installed_caskfile = @cask.installed_caskfile
 | 
			
		||||
      installed_cask = installed_caskfile.exist? ? CaskLoader.load_from_file(installed_caskfile) : @cask
 | 
			
		||||
      installed_cask = installed_caskfile.exist? ? CaskLoader.load(installed_caskfile) : @cask
 | 
			
		||||
 | 
			
		||||
      # Always force uninstallation, ignore method parameter
 | 
			
		||||
      Installer.new(installed_cask, binaries: binaries?, verbose: verbose?, force: true).uninstall
 | 
			
		||||
@ -142,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)
 | 
			
		||||
@ -160,7 +177,7 @@ module Hbc
 | 
			
		||||
      already_installed_artifacts = []
 | 
			
		||||
 | 
			
		||||
      odebug "Installing artifacts"
 | 
			
		||||
      artifacts = Artifact.for_cask(@cask, command: @command, verbose: verbose?, force: force?)
 | 
			
		||||
      artifacts = @cask.artifacts
 | 
			
		||||
      odebug "#{artifacts.length} artifact/s defined", artifacts
 | 
			
		||||
 | 
			
		||||
      artifacts.each do |artifact|
 | 
			
		||||
@ -171,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
 | 
			
		||||
@ -179,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
 | 
			
		||||
@ -344,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
 | 
			
		||||
@ -357,25 +374,27 @@ module Hbc
 | 
			
		||||
 | 
			
		||||
    def uninstall_artifacts
 | 
			
		||||
      odebug "Un-installing artifacts"
 | 
			
		||||
      artifacts = Artifact.for_cask(@cask, command: @command, verbose: verbose?, force: force?)
 | 
			
		||||
      artifacts = @cask.artifacts
 | 
			
		||||
 | 
			
		||||
      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 = @cask.artifacts.select { |a| a.is_a?(Artifact::Zap) }).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
 | 
			
		||||
 | 
			
		||||
@ -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.select { |a| a.is_a?(Artifact::App) }.at(index).target.join("Contents", "Info.plist")
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def plist_exec(cmd)
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -112,11 +112,7 @@ module Hbc
 | 
			
		||||
                 processed_output[:stderr],
 | 
			
		||||
                 processed_status.exitstatus)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
module Hbc
 | 
			
		||||
  class SystemCommand
 | 
			
		||||
    class Result
 | 
			
		||||
      attr_accessor :command, :stdout, :stderr, :exit_status
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,28 +0,0 @@
 | 
			
		||||
require "uri"
 | 
			
		||||
 | 
			
		||||
module Hbc
 | 
			
		||||
  module UnderscoreSupportingURI
 | 
			
		||||
    def self.parse(maybe_uri)
 | 
			
		||||
      return nil if maybe_uri.nil?
 | 
			
		||||
      URI.parse(maybe_uri)
 | 
			
		||||
    rescue URI::InvalidURIError => e
 | 
			
		||||
      scheme, host, path = simple_parse(maybe_uri)
 | 
			
		||||
      raise e unless path && host.include?("_")
 | 
			
		||||
      URI.parse(without_host_underscores(scheme, host, path)).tap do |uri|
 | 
			
		||||
        uri.instance_variable_set("@host", host)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def self.simple_parse(maybe_uri)
 | 
			
		||||
      scheme, host_and_path = maybe_uri.split("://")
 | 
			
		||||
      host, path = host_and_path.split("/", 2)
 | 
			
		||||
      [scheme, host, path]
 | 
			
		||||
    rescue StandardError
 | 
			
		||||
      nil
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def self.without_host_underscores(scheme, host, path)
 | 
			
		||||
      ["#{scheme}:/", host.tr("_", "-"), path].join("/")
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@ -1,8 +1,6 @@
 | 
			
		||||
module Hbc
 | 
			
		||||
  class URL
 | 
			
		||||
    FAKE_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10) https://caskroom.github.io".freeze
 | 
			
		||||
 | 
			
		||||
    attr_reader :using, :revision, :trust_cert, :uri, :cookies, :referer, :data
 | 
			
		||||
    attr_reader :using, :revision, :trust_cert, :uri, :cookies, :referer, :data, :user_agent
 | 
			
		||||
 | 
			
		||||
    extend Forwardable
 | 
			
		||||
    def_delegators :uri, :path, :scheme, :to_s
 | 
			
		||||
@ -16,8 +14,8 @@ module Hbc
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def initialize(uri, options = {})
 | 
			
		||||
      @uri        = Hbc::UnderscoreSupportingURI.parse(uri)
 | 
			
		||||
      @user_agent = options[:user_agent]
 | 
			
		||||
      @uri        = URI(uri)
 | 
			
		||||
      @user_agent = options.fetch(:user_agent, :default)
 | 
			
		||||
      @cookies    = options[:cookies]
 | 
			
		||||
      @referer    = options[:referer]
 | 
			
		||||
      @using      = options[:using]
 | 
			
		||||
@ -25,10 +23,5 @@ module Hbc
 | 
			
		||||
      @trust_cert = options[:trust_cert]
 | 
			
		||||
      @data       = options[:data]
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def user_agent
 | 
			
		||||
      return FAKE_USER_AGENT if @user_agent == :fake
 | 
			
		||||
      @user_agent
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,7 @@ module Hbc
 | 
			
		||||
        meta_dir = cached || cask.metadata_subdir("gpg", :now, true)
 | 
			
		||||
        sig_path = meta_dir.join("signature.asc")
 | 
			
		||||
 | 
			
		||||
        curl(cask.gpg.signature, "-o", sig_path.to_s) unless cached || force
 | 
			
		||||
        curl_download cask.gpg.signature, to: sig_path unless cached || force
 | 
			
		||||
 | 
			
		||||
        sig_path
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
@ -163,7 +163,7 @@ class Caveats
 | 
			
		||||
 | 
			
		||||
  def plist_caveats
 | 
			
		||||
    s = []
 | 
			
		||||
    if f.plist || (keg && keg.plist_installed?)
 | 
			
		||||
    if f.plist || (keg&.plist_installed?)
 | 
			
		||||
      plist_domain = f.plist_path.basename(".plist")
 | 
			
		||||
 | 
			
		||||
      # we readlink because this path probably doesn't exist since caveats
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,10 @@ module Homebrew
 | 
			
		||||
  module Cleanup
 | 
			
		||||
    @disk_cleanup_size = 0
 | 
			
		||||
 | 
			
		||||
    class << self
 | 
			
		||||
      attr_reader :disk_cleanup_size
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    module_function
 | 
			
		||||
 | 
			
		||||
    def cleanup
 | 
			
		||||
@ -21,10 +25,6 @@ module Homebrew
 | 
			
		||||
      @disk_cleanup_size += path_size
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def disk_cleanup_size
 | 
			
		||||
      @disk_cleanup_size
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def unremovable_kegs
 | 
			
		||||
      @unremovable_kegs ||= []
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
#:  * `deps` [`--1`] [`-n`] [`--union`] [`--full-name`] [`--installed`] [`--include-build`] [`--include-optional`] [`--skip-recommended`] <formulae>:
 | 
			
		||||
#:  * `deps` [`--1`] [`-n`] [`--union`] [`--full-name`] [`--installed`] [`--include-build`] [`--include-optional`] [`--skip-recommended`] [`--include-requirements`] <formulae>:
 | 
			
		||||
#:    Show dependencies for <formulae>. When given multiple formula arguments,
 | 
			
		||||
#:    show the intersection of dependencies for <formulae>.
 | 
			
		||||
#:
 | 
			
		||||
@ -19,15 +19,22 @@
 | 
			
		||||
#:    <formulae>. To include the `:build` type dependencies, pass `--include-build`.
 | 
			
		||||
#:    Similarly, pass `--include-optional` to include `:optional` dependencies.
 | 
			
		||||
#:    To skip `:recommended` type dependencies, pass `--skip-recommended`.
 | 
			
		||||
#:    To include requirements in addition to dependencies, pass `--include-requirements`.
 | 
			
		||||
#:
 | 
			
		||||
#:  * `deps` `--tree` [<filters>] (<formulae>|`--installed`):
 | 
			
		||||
#:  * `deps` `--tree` [`--1`] [<filters>] [`--annotate`] (<formulae>|`--installed`):
 | 
			
		||||
#:    Show dependencies as a tree. When given multiple formula arguments, output
 | 
			
		||||
#:    individual trees for every formula.
 | 
			
		||||
#:
 | 
			
		||||
#:    If `--1` is passed, only one level of children is displayed.
 | 
			
		||||
#:
 | 
			
		||||
#:    If `--installed` is passed, output a tree for every installed formula.
 | 
			
		||||
#:
 | 
			
		||||
#:    The <filters> placeholder is any combination of options `--include-build`,
 | 
			
		||||
#:    `--include-optional`, and `--skip-recommended` as documented above.
 | 
			
		||||
#:    `--include-optional`, `--skip-recommended`, and `--include-requirements` as
 | 
			
		||||
#:    documented above.
 | 
			
		||||
#:
 | 
			
		||||
#:    If `--annotate` is passed, the build, optional, and recommended dependencies
 | 
			
		||||
#:    are marked as such in the output.
 | 
			
		||||
#:
 | 
			
		||||
#:  * `deps` [<filters>] (`--installed`|`--all`):
 | 
			
		||||
#:    Show dependencies for installed or all available formulae. Every line of
 | 
			
		||||
@ -37,6 +44,10 @@
 | 
			
		||||
#:    The <filters> placeholder is any combination of options `--include-build`,
 | 
			
		||||
#:    `--include-optional`, and `--skip-recommended` as documented above.
 | 
			
		||||
 | 
			
		||||
# The undocumented `--for-each` option will switch into the mode used by `deps --all`,
 | 
			
		||||
# but only list dependencies for specified formula, one specified formula per line.
 | 
			
		||||
# This is used for debugging the `--installed`/`--all` display mode.
 | 
			
		||||
 | 
			
		||||
# encoding: UTF-8
 | 
			
		||||
 | 
			
		||||
require "formula"
 | 
			
		||||
@ -52,20 +63,26 @@ module Homebrew
 | 
			
		||||
      all?: ARGV.include?("--all"),
 | 
			
		||||
      topo_order?: ARGV.include?("-n"),
 | 
			
		||||
      union?: ARGV.include?("--union"),
 | 
			
		||||
      for_each?: ARGV.include?("--for-each"),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    if mode.installed? && mode.tree?
 | 
			
		||||
      puts_deps_tree Formula.installed
 | 
			
		||||
    if mode.tree?
 | 
			
		||||
      if mode.installed?
 | 
			
		||||
        puts_deps_tree Formula.installed, !ARGV.one?
 | 
			
		||||
      else
 | 
			
		||||
        raise FormulaUnspecifiedError if ARGV.named.empty?
 | 
			
		||||
        puts_deps_tree ARGV.formulae, !ARGV.one?
 | 
			
		||||
      end
 | 
			
		||||
    elsif mode.all?
 | 
			
		||||
      puts_deps Formula
 | 
			
		||||
    elsif mode.tree?
 | 
			
		||||
      raise FormulaUnspecifiedError if ARGV.named.empty?
 | 
			
		||||
      puts_deps_tree ARGV.formulae
 | 
			
		||||
    elsif ARGV.named.empty?
 | 
			
		||||
      raise FormulaUnspecifiedError unless mode.installed?
 | 
			
		||||
      puts_deps Formula.installed
 | 
			
		||||
    elsif mode.for_each?
 | 
			
		||||
      puts_deps ARGV.formulae
 | 
			
		||||
    else
 | 
			
		||||
      all_deps = deps_for_formulae(ARGV.formulae, !ARGV.one?, &(mode.union? ? :| : :&))
 | 
			
		||||
      all_deps = condense_requirements(all_deps)
 | 
			
		||||
      all_deps = all_deps.select(&:installed?) if mode.installed?
 | 
			
		||||
      all_deps = all_deps.map(&method(:dep_display_name)).uniq
 | 
			
		||||
      all_deps.sort! unless mode.topo_order?
 | 
			
		||||
@ -73,24 +90,59 @@ module Homebrew
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def dep_display_name(d)
 | 
			
		||||
    ARGV.include?("--full-name") ? d.to_formula.full_name : d.name
 | 
			
		||||
  def condense_requirements(deps)
 | 
			
		||||
    if ARGV.include?("--include-requirements")
 | 
			
		||||
      deps
 | 
			
		||||
    else
 | 
			
		||||
      deps.map do |dep|
 | 
			
		||||
        if dep.is_a? Dependency
 | 
			
		||||
          dep
 | 
			
		||||
        elsif dep.default_formula?
 | 
			
		||||
          dep.to_dependency
 | 
			
		||||
        end
 | 
			
		||||
      end.compact
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def dep_display_name(dep)
 | 
			
		||||
    str = if dep.is_a? Requirement
 | 
			
		||||
      if ARGV.include?("--include-requirements")
 | 
			
		||||
        if dep.default_formula?
 | 
			
		||||
          ":#{dep.display_s} (#{dep_display_name(dep.to_dependency)})"
 | 
			
		||||
        else
 | 
			
		||||
          ":#{dep.display_s}"
 | 
			
		||||
        end
 | 
			
		||||
      elsif dep.default_formula?
 | 
			
		||||
        dep_display_name(dep.to_dependency)
 | 
			
		||||
      else
 | 
			
		||||
        # This shouldn't happen, but we'll put something here to help debugging
 | 
			
		||||
        "::#{dep.name}"
 | 
			
		||||
      end
 | 
			
		||||
    else
 | 
			
		||||
      ARGV.include?("--full-name") ? dep.to_formula.full_name : dep.name
 | 
			
		||||
    end
 | 
			
		||||
    if ARGV.include?("--annotate")
 | 
			
		||||
      str = "#{str}  [build]" if dep.build?
 | 
			
		||||
      str = "#{str}  [optional" if dep.optional?
 | 
			
		||||
      str = "#{str}  [recommended]" if dep.recommended?
 | 
			
		||||
    end
 | 
			
		||||
    str
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def deps_for_formula(f, recursive = false)
 | 
			
		||||
    includes = []
 | 
			
		||||
    ignores = []
 | 
			
		||||
    if ARGV.include? "--include-build"
 | 
			
		||||
    if ARGV.include?("--include-build")
 | 
			
		||||
      includes << "build?"
 | 
			
		||||
    else
 | 
			
		||||
      ignores << "build?"
 | 
			
		||||
    end
 | 
			
		||||
    if ARGV.include? "--include-optional"
 | 
			
		||||
    if ARGV.include?("--include-optional")
 | 
			
		||||
      includes << "optional?"
 | 
			
		||||
    else
 | 
			
		||||
      ignores << "optional?"
 | 
			
		||||
    end
 | 
			
		||||
    ignores << "recommended?" if ARGV.include? "--skip-recommended"
 | 
			
		||||
    ignores << "recommended?" if ARGV.include?("--skip-recommended")
 | 
			
		||||
 | 
			
		||||
    if recursive
 | 
			
		||||
      deps = f.recursive_dependencies do |dependent, dep|
 | 
			
		||||
@ -120,7 +172,7 @@ module Homebrew
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    deps + reqs.select(&:default_formula?).map(&:to_dependency)
 | 
			
		||||
    deps + reqs.to_a
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def deps_for_formulae(formulae, recursive = false, &block)
 | 
			
		||||
@ -129,41 +181,55 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
  def puts_deps(formulae)
 | 
			
		||||
    formulae.each do |f|
 | 
			
		||||
      deps = deps_for_formula(f).sort_by(&:name).map(&method(:dep_display_name))
 | 
			
		||||
      deps = deps_for_formula(f)
 | 
			
		||||
      deps = condense_requirements(deps)
 | 
			
		||||
      deps = deps.sort_by(&:name).map(&method(:dep_display_name))
 | 
			
		||||
      puts "#{f.full_name}: #{deps.join(" ")}"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def puts_deps_tree(formulae)
 | 
			
		||||
  def puts_deps_tree(formulae, recursive = false)
 | 
			
		||||
    formulae.each do |f|
 | 
			
		||||
      puts "#{f.full_name} (required dependencies)"
 | 
			
		||||
      recursive_deps_tree(f, "")
 | 
			
		||||
      puts f.full_name
 | 
			
		||||
      @dep_stack = []
 | 
			
		||||
      recursive_deps_tree(f, "", recursive)
 | 
			
		||||
      puts
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def recursive_deps_tree(f, prefix)
 | 
			
		||||
    reqs = f.requirements.select(&:default_formula?)
 | 
			
		||||
    deps = f.deps.default
 | 
			
		||||
    max = reqs.length - 1
 | 
			
		||||
    reqs.each_with_index do |req, i|
 | 
			
		||||
      chr = if i == max && deps.empty?
 | 
			
		||||
  def recursive_deps_tree(f, prefix, recursive)
 | 
			
		||||
    reqs = f.requirements
 | 
			
		||||
    deps = f.deps
 | 
			
		||||
    dependables = reqs + deps
 | 
			
		||||
    dependables = dependables.reject(&:optional?) unless ARGV.include?("--include-optional")
 | 
			
		||||
    dependables = dependables.reject(&:build?) unless ARGV.include?("--include-build")
 | 
			
		||||
    dependables = dependables.reject(&:recommended?) if ARGV.include?("--skip-recommended")
 | 
			
		||||
    max = dependables.length - 1
 | 
			
		||||
    @dep_stack.push f.name
 | 
			
		||||
    dependables.each_with_index do |dep, i|
 | 
			
		||||
      next if !ARGV.include?("--include-requirements") && dep.is_a?(Requirement) && !dep.default_formula?
 | 
			
		||||
      tree_lines = if i == max
 | 
			
		||||
        "└──"
 | 
			
		||||
      else
 | 
			
		||||
        "├──"
 | 
			
		||||
      end
 | 
			
		||||
      puts prefix + "#{chr} :#{dep_display_name(req.to_dependency)}"
 | 
			
		||||
    end
 | 
			
		||||
    max = deps.length - 1
 | 
			
		||||
    deps.each_with_index do |dep, i|
 | 
			
		||||
      chr = if i == max
 | 
			
		||||
        "└──"
 | 
			
		||||
      display_s = "#{tree_lines} #{dep_display_name(dep)}"
 | 
			
		||||
      is_circular = @dep_stack.include?(dep.name)
 | 
			
		||||
      display_s = "#{display_s} (CIRCULAR DEPENDENCY)" if is_circular
 | 
			
		||||
      puts "#{prefix}#{display_s}"
 | 
			
		||||
      next if !recursive || is_circular
 | 
			
		||||
      prefix_addition = if i == max
 | 
			
		||||
        "    "
 | 
			
		||||
      else
 | 
			
		||||
        "├──"
 | 
			
		||||
        "│   "
 | 
			
		||||
      end
 | 
			
		||||
      prefix_ext = (i == max) ? "    " : "│   "
 | 
			
		||||
      puts prefix + "#{chr} #{dep_display_name(dep)}"
 | 
			
		||||
      recursive_deps_tree(Formulary.factory(dep.name), prefix + prefix_ext)
 | 
			
		||||
      if dep.is_a?(Requirement) && dep.default_formula?
 | 
			
		||||
        recursive_deps_tree(Formulary.factory(dep.to_dependency.name), prefix + prefix_addition, true)
 | 
			
		||||
      end
 | 
			
		||||
      if dep.is_a? Dependency
 | 
			
		||||
        recursive_deps_tree(Formulary.factory(dep.name), prefix + prefix_addition, true)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
    @dep_stack.pop
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -49,8 +49,10 @@ module Homebrew
 | 
			
		||||
      if fetch_bottle?(f)
 | 
			
		||||
        begin
 | 
			
		||||
          fetch_formula(f.bottle)
 | 
			
		||||
        rescue Exception => e
 | 
			
		||||
          raise if ARGV.homebrew_developer? || e.is_a?(Interrupt)
 | 
			
		||||
        rescue Interrupt
 | 
			
		||||
          raise
 | 
			
		||||
        rescue => e
 | 
			
		||||
          raise if ARGV.homebrew_developer?
 | 
			
		||||
          fetched_bottle = false
 | 
			
		||||
          onoe e.message
 | 
			
		||||
          opoo "Bottle fetch failed: fetching the source."
 | 
			
		||||
 | 
			
		||||
@ -219,6 +219,7 @@ module Homebrew
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      return if formulae.empty?
 | 
			
		||||
      perform_preinstall_checks
 | 
			
		||||
 | 
			
		||||
      formulae.each do |f|
 | 
			
		||||
@ -338,6 +339,7 @@ module Homebrew
 | 
			
		||||
  rescue FormulaInstallationAlreadyAttemptedError
 | 
			
		||||
    # We already attempted to install f as part of the dependency tree of
 | 
			
		||||
    # another formula. In that case, don't generate an error, just move on.
 | 
			
		||||
    return
 | 
			
		||||
  rescue CannotInstallFormulaError => e
 | 
			
		||||
    ofail e.message
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -19,15 +19,13 @@ class String
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
def cask
 | 
			
		||||
  $LOAD_PATH.unshift("#{HOMEBREW_LIBRARY_PATH}/cask/lib")
 | 
			
		||||
  require "hbc"
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
module Homebrew
 | 
			
		||||
  module_function
 | 
			
		||||
 | 
			
		||||
  def irb
 | 
			
		||||
    $LOAD_PATH.unshift("#{HOMEBREW_LIBRARY_PATH}/cask/lib")
 | 
			
		||||
    require "hbc"
 | 
			
		||||
 | 
			
		||||
    if ARGV.include? "--examples"
 | 
			
		||||
      puts "'v8'.f # => instance of the v8 formula"
 | 
			
		||||
      puts ":hub.f.installed?"
 | 
			
		||||
 | 
			
		||||
@ -39,15 +39,7 @@ module Homebrew
 | 
			
		||||
      filtered_list
 | 
			
		||||
    elsif ARGV.named.empty?
 | 
			
		||||
      if ARGV.include? "--full-name"
 | 
			
		||||
        full_names = Formula.installed.map(&:full_name).sort do |a, b|
 | 
			
		||||
          if a.include?("/") && !b.include?("/")
 | 
			
		||||
            1
 | 
			
		||||
          elsif !a.include?("/") && b.include?("/")
 | 
			
		||||
            -1
 | 
			
		||||
          else
 | 
			
		||||
            a <=> b
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
        full_names = Formula.installed.map(&:full_name).sort &tap_and_name_comparison
 | 
			
		||||
        return if full_names.empty?
 | 
			
		||||
        puts Formatter.columns(full_names)
 | 
			
		||||
      else
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
#:  * `pin` <formulae>:
 | 
			
		||||
#:    Pin the specified <formulae>, preventing them from being upgraded when
 | 
			
		||||
#:    issuing the `brew upgrade` command. See also `unpin`.
 | 
			
		||||
#:    issuing the `brew upgrade <formulae>` command (but can still be upgraded
 | 
			
		||||
#:    as dependencies for other formulae). See also `unpin`.
 | 
			
		||||
 | 
			
		||||
require "formula"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -29,8 +29,6 @@ module Homebrew
 | 
			
		||||
      args << "--devel"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    Sandbox.print_sandbox_message if Sandbox.formula?(formula)
 | 
			
		||||
 | 
			
		||||
    Utils.safe_fork do
 | 
			
		||||
      if Sandbox.formula?(formula)
 | 
			
		||||
        sandbox = Sandbox.new
 | 
			
		||||
 | 
			
		||||
@ -55,7 +55,7 @@ module Homebrew
 | 
			
		||||
      else
 | 
			
		||||
        n, d = ObserverPathnameExtension.counts
 | 
			
		||||
        print "Pruned #{n} symbolic links "
 | 
			
		||||
        print "and #{d} directories " if d > 0
 | 
			
		||||
        print "and #{d} directories " if d.positive?
 | 
			
		||||
        puts "from #{HOMEBREW_PREFIX}"
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -47,8 +47,8 @@ module Homebrew
 | 
			
		||||
    fi.install
 | 
			
		||||
    fi.finish
 | 
			
		||||
  rescue FormulaInstallationAlreadyAttemptedError
 | 
			
		||||
    # next
 | 
			
		||||
  rescue Exception
 | 
			
		||||
    return
 | 
			
		||||
  rescue Exception # rubocop:disable Lint/RescueException
 | 
			
		||||
    ignore_interrupts { restore_backup(keg, keg_was_linked) }
 | 
			
		||||
    raise
 | 
			
		||||
  else
 | 
			
		||||
 | 
			
		||||
@ -34,38 +34,40 @@ module Homebrew
 | 
			
		||||
    elsif ARGV.include? "--opensuse"
 | 
			
		||||
      exec_browser "https://software.opensuse.org/search?q=#{ARGV.next}"
 | 
			
		||||
    elsif ARGV.include? "--fedora"
 | 
			
		||||
      exec_browser "https://admin.fedoraproject.org/pkgdb/packages/%2A#{ARGV.next}%2A/"
 | 
			
		||||
      exec_browser "https://apps.fedoraproject.org/packages/s/#{ARGV.next}"
 | 
			
		||||
    elsif ARGV.include? "--ubuntu"
 | 
			
		||||
      exec_browser "http://packages.ubuntu.com/search?keywords=#{ARGV.next}&searchon=names&suite=all§ion=all"
 | 
			
		||||
      exec_browser "https://packages.ubuntu.com/search?keywords=#{ARGV.next}&searchon=names&suite=all§ion=all"
 | 
			
		||||
    elsif ARGV.include? "--desc"
 | 
			
		||||
      query = ARGV.next
 | 
			
		||||
      regex = query_regexp(query)
 | 
			
		||||
      Descriptions.search(regex, :desc).print
 | 
			
		||||
    elsif ARGV.first =~ HOMEBREW_TAP_FORMULA_REGEX
 | 
			
		||||
      query = ARGV.first
 | 
			
		||||
      user, repo, name = query.split("/", 3)
 | 
			
		||||
 | 
			
		||||
      begin
 | 
			
		||||
        result = Formulary.factory(query).name
 | 
			
		||||
        results = Array(result)
 | 
			
		||||
      rescue FormulaUnavailableError
 | 
			
		||||
        result = search_tap(user, repo, name)
 | 
			
		||||
        _, _, name = query.split("/", 3)
 | 
			
		||||
        results = search_taps(name)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      results = Array(result)
 | 
			
		||||
      puts Formatter.columns(results) unless results.empty?
 | 
			
		||||
    else
 | 
			
		||||
      query = ARGV.first
 | 
			
		||||
      regex = query_regexp(query)
 | 
			
		||||
      local_results = search_formulae(regex)
 | 
			
		||||
      puts Formatter.columns(local_results) unless local_results.empty?
 | 
			
		||||
 | 
			
		||||
      tap_results = search_taps(query)
 | 
			
		||||
      puts Formatter.columns(tap_results) unless tap_results.empty?
 | 
			
		||||
 | 
			
		||||
      if $stdout.tty?
 | 
			
		||||
        count = local_results.length + tap_results.length
 | 
			
		||||
 | 
			
		||||
        ohai "Searching blacklisted, migrated and deleted formulae..."
 | 
			
		||||
        if reason = Homebrew::MissingFormula.reason(query, silent: true)
 | 
			
		||||
          if count > 0
 | 
			
		||||
          if count.positive?
 | 
			
		||||
            puts
 | 
			
		||||
            puts "If you meant #{query.inspect} specifically:"
 | 
			
		||||
          end
 | 
			
		||||
@ -100,10 +102,18 @@ module Homebrew
 | 
			
		||||
    odie "#{query} is not a valid regex"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def search_taps(query)
 | 
			
		||||
  def search_taps(query, silent: false)
 | 
			
		||||
    return [] if ENV["HOMEBREW_NO_GITHUB_API"]
 | 
			
		||||
 | 
			
		||||
    # Use stderr to avoid breaking parsed output
 | 
			
		||||
    unless silent
 | 
			
		||||
      $stderr.puts Formatter.headline("Searching taps on GitHub...", color: :blue)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    valid_dirnames = ["Formula", "HomebrewFormula", "Casks", "."].freeze
 | 
			
		||||
    matches = GitHub.search_code("user:Homebrew", "user:caskroom", "filename:#{query}", "extension:rb")
 | 
			
		||||
    [*matches].map do |match|
 | 
			
		||||
    matches = GitHub.search_code(user: ["Homebrew", "caskroom"], filename: query, extension: "rb")
 | 
			
		||||
 | 
			
		||||
    matches.map do |match|
 | 
			
		||||
      dirname, filename = File.split(match["path"])
 | 
			
		||||
      next unless valid_dirnames.include?(dirname)
 | 
			
		||||
      tap = Tap.fetch(match["repository"]["full_name"])
 | 
			
		||||
@ -113,6 +123,9 @@ module Homebrew
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def search_formulae(regex)
 | 
			
		||||
    # Use stderr to avoid breaking parsed output
 | 
			
		||||
    $stderr.puts Formatter.headline("Searching local taps...", color: :blue)
 | 
			
		||||
 | 
			
		||||
    aliases = Formula.alias_full_names
 | 
			
		||||
    results = (Formula.full_names + aliases).grep(regex).sort
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -117,12 +117,13 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
    case output_type
 | 
			
		||||
    when :print
 | 
			
		||||
      args << "--debug" if ARGV.debug?
 | 
			
		||||
      args << "--display-cop-names" if ARGV.include? "--display-cop-names"
 | 
			
		||||
      args << "--format" << "simple" if files
 | 
			
		||||
      system(cache_env, "rubocop", *args)
 | 
			
		||||
      system(cache_env, "rubocop", "_#{HOMEBREW_RUBOCOP_VERSION}_", *args)
 | 
			
		||||
      !$CHILD_STATUS.success?
 | 
			
		||||
    when :json
 | 
			
		||||
      json, _, status = Open3.capture3(cache_env, "rubocop", "--format", "json", *args)
 | 
			
		||||
      json, _, status = Open3.capture3(cache_env, "rubocop", "_#{HOMEBREW_RUBOCOP_VERSION}_", "--format", "json", *args)
 | 
			
		||||
      # exit status of 1 just means violations were found; other numbers mean
 | 
			
		||||
      # execution errors.
 | 
			
		||||
      # exitstatus can also be nil if RuboCop process crashes, e.g. due to
 | 
			
		||||
 | 
			
		||||
@ -64,10 +64,10 @@ module Homebrew
 | 
			
		||||
        if tap.installed?
 | 
			
		||||
          info += tap.pinned? ? "pinned" : "unpinned"
 | 
			
		||||
          info += ", private" if tap.private?
 | 
			
		||||
          if (formula_count = tap.formula_files.size) > 0
 | 
			
		||||
          if (formula_count = tap.formula_files.size).positive?
 | 
			
		||||
            info += ", #{Formatter.pluralize(formula_count, "formula")}"
 | 
			
		||||
          end
 | 
			
		||||
          if (command_count = tap.command_files.size) > 0
 | 
			
		||||
          if (command_count = tap.command_files.size).positive?
 | 
			
		||||
            info += ", #{Formatter.pluralize(command_count, "command")}"
 | 
			
		||||
          end
 | 
			
		||||
          info += ", no formulae/commands" if (formula_count + command_count).zero?
 | 
			
		||||
 | 
			
		||||
@ -54,8 +54,7 @@ module Homebrew
 | 
			
		||||
                    quiet: ARGV.quieter?
 | 
			
		||||
      rescue TapRemoteMismatchError => e
 | 
			
		||||
        odie e
 | 
			
		||||
      rescue TapAlreadyTappedError, TapAlreadyUnshallowError
 | 
			
		||||
        # Do nothing.
 | 
			
		||||
      rescue TapAlreadyTappedError, TapAlreadyUnshallowError # rubocop:disable Lint/HandleExceptions
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -77,7 +77,7 @@ module Homebrew
 | 
			
		||||
  def unlinkapps_unlink?(target_app, opts = {})
 | 
			
		||||
    # Skip non-symlinks and symlinks that don't point into the Homebrew prefix.
 | 
			
		||||
    app = target_app.readlink.to_s if target_app.symlink?
 | 
			
		||||
    return false unless app && app.start_with?(*UNLINKAPPS_PREFIXES)
 | 
			
		||||
    return false unless app&.start_with?(*UNLINKAPPS_PREFIXES)
 | 
			
		||||
 | 
			
		||||
    if opts.fetch(:prune, false)
 | 
			
		||||
      !File.exist?(app) # Remove only broken symlinks in prune mode.
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
#:  * `unpin` <formulae>:
 | 
			
		||||
#:    Unpin <formulae>, allowing them to be upgraded by `brew upgrade`. See also
 | 
			
		||||
#:    `pin`.
 | 
			
		||||
#:    Unpin <formulae>, allowing them to be upgraded by `brew upgrade <formulae>`.
 | 
			
		||||
#:    See also `pin`.
 | 
			
		||||
 | 
			
		||||
require "formula"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -124,7 +124,7 @@ module Homebrew
 | 
			
		||||
    return if ENV["HOMEBREW_UPDATE_TEST"]
 | 
			
		||||
    core_tap = CoreTap.instance
 | 
			
		||||
    return if core_tap.installed?
 | 
			
		||||
    CoreTap.ensure_installed! quiet: false
 | 
			
		||||
    CoreTap.ensure_installed!
 | 
			
		||||
    revision = core_tap.git_head
 | 
			
		||||
    ENV["HOMEBREW_UPDATE_BEFORE_HOMEBREW_HOMEBREW_CORE"] = revision
 | 
			
		||||
    ENV["HOMEBREW_UPDATE_AFTER_HOMEBREW_HOMEBREW_CORE"] = revision
 | 
			
		||||
@ -203,6 +203,7 @@ module Homebrew
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    new_homebrew_repository = Pathname.new "/usr/local/Homebrew"
 | 
			
		||||
    new_homebrew_repository.rmdir_if_possible
 | 
			
		||||
    if new_homebrew_repository.exist?
 | 
			
		||||
      ofail <<-EOS.undent
 | 
			
		||||
        #{new_homebrew_repository} already exists.
 | 
			
		||||
@ -371,7 +372,7 @@ class Reporter
 | 
			
		||||
          new_version = formula.pkg_version
 | 
			
		||||
          old_version = FormulaVersions.new(formula).formula_at_revision(@initial_revision, &:pkg_version)
 | 
			
		||||
          next if new_version == old_version
 | 
			
		||||
        rescue Exception => e
 | 
			
		||||
        rescue Exception => e # rubocop:disable Lint/RescueException
 | 
			
		||||
          onoe "#{e.message}\n#{e.backtrace.join "\n"}" if ARGV.homebrew_developer?
 | 
			
		||||
        end
 | 
			
		||||
        @report[:M] << tap.formula_file_to_name(src)
 | 
			
		||||
@ -459,7 +460,7 @@ class Reporter
 | 
			
		||||
          unless Formulary.factory(new_full_name).keg_only?
 | 
			
		||||
            system HOMEBREW_BREW_FILE, "link", new_full_name, "--overwrite"
 | 
			
		||||
          end
 | 
			
		||||
        rescue Exception => e
 | 
			
		||||
        rescue Exception => e # rubocop:disable Lint/RescueException
 | 
			
		||||
          onoe "#{e.message}\n#{e.backtrace.join "\n"}" if ARGV.homebrew_developer?
 | 
			
		||||
        end
 | 
			
		||||
        next
 | 
			
		||||
@ -520,7 +521,7 @@ class Reporter
 | 
			
		||||
 | 
			
		||||
      begin
 | 
			
		||||
        f = Formulary.factory(new_full_name)
 | 
			
		||||
      rescue Exception => e
 | 
			
		||||
      rescue Exception => e # rubocop:disable Lint/RescueException
 | 
			
		||||
        onoe "#{e.message}\n#{e.backtrace.join "\n"}" if ARGV.homebrew_developer?
 | 
			
		||||
        next
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
@ -385,6 +385,12 @@ EOS
 | 
			
		||||
 | 
			
		||||
  if ! git --version >/dev/null 2>&1
 | 
			
		||||
  then
 | 
			
		||||
    # we need a new enough curl to install git
 | 
			
		||||
    if [[ -n "$HOMEBREW_SYSTEM_CURL_TOO_OLD" &&
 | 
			
		||||
        ! -x "$HOMEBREW_PREFIX/opt/curl/bin/curl" ]]
 | 
			
		||||
    then
 | 
			
		||||
      brew install curl
 | 
			
		||||
    fi
 | 
			
		||||
    # we cannot install brewed git if homebrew/core is unavailable.
 | 
			
		||||
    [[ -d "$HOMEBREW_LIBRARY/Taps/homebrew/homebrew-core" ]] && brew install git
 | 
			
		||||
    unset GIT_EXECUTABLE
 | 
			
		||||
@ -564,6 +570,7 @@ EOS
 | 
			
		||||
        -d "$HOMEBREW_LIBRARY/LinkedKegs" ||
 | 
			
		||||
        (-n "$HOMEBREW_DEVELOPER" && -z "$HOMEBREW_UPDATE_PREINSTALL") ]]
 | 
			
		||||
  then
 | 
			
		||||
    unset HOMEBREW_RUBY_PATH
 | 
			
		||||
    brew update-report "$@"
 | 
			
		||||
    return $?
 | 
			
		||||
  elif [[ -z "$HOMEBREW_UPDATE_PREINSTALL" ]]
 | 
			
		||||
 | 
			
		||||
@ -150,6 +150,7 @@ module Homebrew
 | 
			
		||||
  rescue FormulaInstallationAlreadyAttemptedError
 | 
			
		||||
    # We already attempted to upgrade f as part of the dependency tree of
 | 
			
		||||
    # another formula. In that case, don't generate an error, just move on.
 | 
			
		||||
    return
 | 
			
		||||
  rescue CannotInstallFormulaError => e
 | 
			
		||||
    ofail e
 | 
			
		||||
  rescue BuildError => e
 | 
			
		||||
 | 
			
		||||
@ -74,12 +74,13 @@ module Homebrew
 | 
			
		||||
              end
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            dep_formulae = deps.map do |dep|
 | 
			
		||||
            dep_formulae = deps.flat_map do |dep|
 | 
			
		||||
              begin
 | 
			
		||||
                dep.to_formula
 | 
			
		||||
              rescue
 | 
			
		||||
                []
 | 
			
		||||
              end
 | 
			
		||||
            end
 | 
			
		||||
            end.compact
 | 
			
		||||
 | 
			
		||||
            reqs_by_formula = ([f] + dep_formulae).flat_map do |formula|
 | 
			
		||||
              formula.requirements.map { |req| [formula, req] }
 | 
			
		||||
@ -118,6 +119,7 @@ module Homebrew
 | 
			
		||||
        rescue FormulaUnavailableError
 | 
			
		||||
          # Silently ignore this case as we don't care about things used in
 | 
			
		||||
          # taps that aren't currently tapped.
 | 
			
		||||
          next
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -13,16 +13,16 @@ if [[ -n "$HOMEBREW_MACOS" ]]
 | 
			
		||||
then
 | 
			
		||||
  if [[ "$HOMEBREW_PROCESSOR" = "Intel" ]]
 | 
			
		||||
  then
 | 
			
		||||
    ruby_URL="https://homebrew.bintray.com/bottles-portable/portable-ruby-2.0.0-p648.leopard_64.bottle.tar.gz"
 | 
			
		||||
    ruby_SHA="5c1240abe4be91c9774a0089c2a38a8ccfff87c009e8e5786730c659d5e633f7"
 | 
			
		||||
    ruby_URL="https://homebrew.bintray.com/bottles-portable/portable-ruby-2.3.3.leopard_64.bottle.1.tar.gz"
 | 
			
		||||
    ruby_SHA="34ce9e4c9c1be28db564d744165aa29291426f8a3d2ef806ba4f0b9175aedb2b"
 | 
			
		||||
  else
 | 
			
		||||
    ruby_URL=""
 | 
			
		||||
    ruby_SHA=""
 | 
			
		||||
  fi
 | 
			
		||||
elif [[ -n "$HOMEBREW_LINUX" ]]
 | 
			
		||||
then
 | 
			
		||||
  ruby_URL="https://homebrew.bintray.com/bottles-portable/portable-ruby-2.0.0-p648.x86_64_linux.bottle.tar.gz"
 | 
			
		||||
  ruby_SHA="dbb5118a22a6a75cc77e62544a3d8786d383fab1bdaf8c154951268807357bf0"
 | 
			
		||||
  ruby_URL="https://homebrew.bintray.com/bottles-portable/portable-ruby-2.3.3.x86_64_linux.bottle.tar.gz"
 | 
			
		||||
  ruby_SHA="543c18bd33a300e6c16671437b1e0f17b03bb64e6a485fc15ff7de1eb1a0bc2a"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
fetch() {
 | 
			
		||||
@ -45,20 +45,25 @@ fetch() {
 | 
			
		||||
    curl_args[${#curl_args[*]}]="--progress-bar"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [[ "$HOMEBREW_MACOS_VERSION_NUMERIC" -lt "100600" ]]
 | 
			
		||||
  then
 | 
			
		||||
    curl_args[${#curl_args[*]}]="--insecure"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  temporary_path="$CACHED_LOCATION.incomplete"
 | 
			
		||||
 | 
			
		||||
  mkdir -p "$HOMEBREW_CACHE"
 | 
			
		||||
  [[ -n "$HOMEBREW_QUIET" ]] || echo "==> Downloading $VENDOR_URL"
 | 
			
		||||
  [[ -n "$HOMEBREW_QUIET" ]] || echo "==> Downloading $VENDOR_URL" >&2
 | 
			
		||||
  if [[ -f "$CACHED_LOCATION" ]]
 | 
			
		||||
  then
 | 
			
		||||
    [[ -n "$HOMEBREW_QUIET" ]] || echo "Already downloaded: $CACHED_LOCATION"
 | 
			
		||||
    [[ -n "$HOMEBREW_QUIET" ]] || echo "Already downloaded: $CACHED_LOCATION" >&2
 | 
			
		||||
  else
 | 
			
		||||
    if [[ -f "$temporary_path" ]]
 | 
			
		||||
    then
 | 
			
		||||
      "$HOMEBREW_CURL" "${curl_args[@]}" -C - "$VENDOR_URL" -o "$temporary_path"
 | 
			
		||||
      if [[ $? -eq 33 ]]
 | 
			
		||||
      then
 | 
			
		||||
        [[ -n "$HOMEBREW_QUIET" ]] || echo "Trying a full download"
 | 
			
		||||
        [[ -n "$HOMEBREW_QUIET" ]] || echo "Trying a full download" >&2
 | 
			
		||||
        rm -f "$temporary_path"
 | 
			
		||||
        "$HOMEBREW_CURL" "${curl_args[@]}" "$VENDOR_URL" -o "$temporary_path"
 | 
			
		||||
      fi
 | 
			
		||||
@ -135,7 +140,7 @@ install() {
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  safe_cd "$VENDOR_DIR"
 | 
			
		||||
  [[ -n "$HOMEBREW_QUIET" ]] || echo "==> Unpacking $(basename "$VENDOR_URL")"
 | 
			
		||||
  [[ -n "$HOMEBREW_QUIET" ]] || echo "==> Pouring $(basename "$VENDOR_URL")" >&2
 | 
			
		||||
  tar "$tar_args" "$CACHED_LOCATION"
 | 
			
		||||
  safe_cd "$VENDOR_DIR/portable-$VENDOR_NAME"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -3,4 +3,8 @@ module SharedEnvExtension
 | 
			
		||||
    odeprecated "ENV.j1", "ENV.deparallelize"
 | 
			
		||||
    deparallelize
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def java_cache
 | 
			
		||||
    # odeprecated "ENV.java_cache"
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,7 @@ end
 | 
			
		||||
# This formula serves as the base class for several very similar
 | 
			
		||||
# formulae for Amazon Web Services related tools.
 | 
			
		||||
class AmazonWebServicesFormula < Formula
 | 
			
		||||
  # Use this method to peform a standard install for Java-based tools,
 | 
			
		||||
  # Use this method to perform a standard install for Java-based tools,
 | 
			
		||||
  # keeping the .jars out of HOMEBREW_PREFIX/lib
 | 
			
		||||
  def install
 | 
			
		||||
    odeprecated "AmazonWebServicesFormula#install", "Formula#install"
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,5 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
# RuboCop version used for `brew style` and `brew cask style`
 | 
			
		||||
HOMEBREW_RUBOCOP_VERSION = "0.49.1".freeze
 | 
			
		||||
HOMEBREW_RUBOCOP_CASK_VERSION = "~> 0.13.1".freeze # has to be updated when RuboCop version changes
 | 
			
		||||
HOMEBREW_RUBOCOP_VERSION = "0.50.0"
 | 
			
		||||
HOMEBREW_RUBOCOP_CASK_VERSION = "~> 0.14.2" # has to be updated when RuboCop version changes
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@ module Debrew
 | 
			
		||||
  module Raise
 | 
			
		||||
    def raise(*)
 | 
			
		||||
      super
 | 
			
		||||
    rescue Exception => e
 | 
			
		||||
    rescue Exception => e # rubocop:disable Lint/RescueException
 | 
			
		||||
      e.extend(Ignorable)
 | 
			
		||||
      super(e) unless Debrew.debug(e) == :ignore
 | 
			
		||||
    end
 | 
			
		||||
@ -57,7 +57,7 @@ module Debrew
 | 
			
		||||
        input.chomp!
 | 
			
		||||
 | 
			
		||||
        i = input.to_i
 | 
			
		||||
        if i > 0
 | 
			
		||||
        if i.positive?
 | 
			
		||||
          choice = menu.entries[i - 1]
 | 
			
		||||
        else
 | 
			
		||||
          possible = menu.entries.find_all { |e| e.name.start_with?(input) }
 | 
			
		||||
@ -92,7 +92,7 @@ module Debrew
 | 
			
		||||
      yield
 | 
			
		||||
    rescue SystemExit
 | 
			
		||||
      original_raise
 | 
			
		||||
    rescue Exception => e
 | 
			
		||||
    rescue Exception => e # rubocop:disable Lint/RescueException
 | 
			
		||||
      debug(e)
 | 
			
		||||
    ensure
 | 
			
		||||
      @active = false
 | 
			
		||||
@ -119,7 +119,7 @@ module Debrew
 | 
			
		||||
          if e.is_a?(Ignorable)
 | 
			
		||||
            menu.choice(:irb) do
 | 
			
		||||
              puts "When you exit this IRB session, execution will continue."
 | 
			
		||||
              set_trace_func proc { |event, _, _, id, binding, klass|
 | 
			
		||||
              set_trace_func proc { |event, _, _, id, binding, klass| # rubocop:disable Metrics/ParameterLists
 | 
			
		||||
                if klass == Raise && id == :raise && event == "return"
 | 
			
		||||
                  set_trace_func(nil)
 | 
			
		||||
                  synchronize { IRB.start_within(binding) }
 | 
			
		||||
 | 
			
		||||
@ -4,8 +4,7 @@ module IRB
 | 
			
		||||
  @setup_done = false
 | 
			
		||||
 | 
			
		||||
  extend Module.new {
 | 
			
		||||
    def parse_opts
 | 
			
		||||
    end
 | 
			
		||||
    def parse_opts; end
 | 
			
		||||
 | 
			
		||||
    def start_within(binding)
 | 
			
		||||
      unless @setup_done
 | 
			
		||||
@ -16,7 +15,7 @@ module IRB
 | 
			
		||||
      workspace = WorkSpace.new(binding)
 | 
			
		||||
      irb = Irb.new(workspace)
 | 
			
		||||
 | 
			
		||||
      @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
 | 
			
		||||
      @CONF[:IRB_RC]&.call(irb.context)
 | 
			
		||||
      @CONF[:MAIN_CONTEXT] = irb.context
 | 
			
		||||
 | 
			
		||||
      trap("SIGINT") do
 | 
			
		||||
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user