This commit is contained in:
AnastasiaSulyagina 2016-08-18 22:11:42 +03:00
parent 5c7c9de669
commit e81f4ab7de
480 changed files with 22337 additions and 0 deletions

View File

@ -0,0 +1,9 @@
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

1
Library/Homebrew/cask/.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
* text=auto

View File

@ -0,0 +1,9 @@
Before writing your issue, check our instructions for [reporting bugs](https://github.com/caskroom/homebrew-cask#reporting-bugs) or [making requests](https://github.com/caskroom/homebrew-cask#requests), as appropriate. Those will walk you through the process.
If none of those is appropriate, then **delete all this pre-inserted template text** and tell us your issue in as much detail as possible.
Please note that if it is apparent you ignored the instructions for reporting issues, your issue may be closed without review. When the guide isnt followed we get the same issues over and over. Having to repeatedly deal with the same solved and documented problems leads to maintainer burnout and a lot of wasted hours that could instead have been spent improving Homebrew-Cask itself and fixing real bugs.
If the guide itself was unclear, open *first* an issue or pull request stating what you found was confusing *and only then* your other issue.
Thank you for taking the time to make a correct report.

View File

@ -0,0 +1,27 @@
##### Instructions
- Look for and complete the section relevant to your submission. Delete the others, including these `Instructions`.
- `{{cask_file}}` represents the cask file youre submitting/editing (if applicable).
- If theres a checkbox you cant complete for any reason, thats OK. Just explain in detail why you werent able to do so.
### Changes to a cask
#### Editing an existing cask
- [ ] Commit message includes casks name (and new version, if applicable).
- [ ] `brew cask audit --download {{cask_file}}` is error-free.
- [ ] `brew cask style --fix {{cask_file}}` left no offenses.
#### Adding a new cask
- [ ] Checked there arent open [pull requests](https://github.com/caskroom/homebrew-cask/pulls) for the same cask.
- [ ] Checked there arent closed [issues](https://github.com/caskroom/homebrew-cask/issues) where that cask was already refused.
- [ ] When naming the cask, followed the [token reference](https://github.com/caskroom/homebrew-cask/blob/master/doc/cask_language_reference/token_reference.md).
- [ ] Commit message includes casks name.
- [ ] `brew cask audit --download {{cask_file}}` is error-free.
- [ ] `brew cask style --fix {{cask_file}}` left no offenses.
- [ ] `brew cask install {{cask_file}}` worked successfully.
- [ ] `brew cask uninstall {{cask_file}}` worked successfully.
### Changes to the core
- [ ] Followed [hacking.md](https://github.com/caskroom/homebrew-cask/blob/master/doc/development/hacking.md).

10
Library/Homebrew/cask/.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
# toplevel
/.bundle/
/bin/
/vendor/
# anywhere in the tree
*~
.DS_Store
.ruby-version
coverage

View File

@ -0,0 +1,2 @@
--color
--require spec_helper

View File

@ -0,0 +1,89 @@
require: 'rubocop-cask'
AllCops:
TargetRubyVersion: 2.0
Exclude:
- '**/Casks/**/*'
- 'developer/**/*'
- '**/vendor/**/*'
Metrics/AbcSize:
Enabled: false
Metrics/ClassLength:
Enabled: false
Metrics/CyclomaticComplexity:
Enabled: false
Metrics/MethodLength:
Enabled: false
Metrics/PerceivedComplexity:
Enabled: false
Metrics/ModuleLength:
CountComments: false
Exclude:
- 'lib/hbc/locations.rb'
- 'lib/hbc/macos.rb'
- 'lib/hbc/utils.rb'
Style/BlockDelimiters:
EnforcedStyle: semantic
FunctionalMethods:
- expect
- let
- let!
- subject
- watch
- inject
- map
- map!
- collect
- collect!
- reject
- reject!
- delete_if
- with_object
ProceduralMethods:
- after
- at_exit
- before
- benchmark
- bm
- bmbm
- capture_io
- capture_output
- capture_subprocess_io
- chdir
- context
- create
- each_with_object
- fork
- measure
- new
- open
- realtime
- shutup
- tap
- each
- reverse_each
IgnoredMethods:
- it
- its
- lambda
- proc
Style/ClassAndModuleChildren:
EnforcedStyle: compact
Style/PredicateName:
NameWhitelist: is_32_bit?, is_64_bit?
Style/RaiseArgs:
EnforcedStyle: exploded
Style/StringLiterals:
EnforcedStyle: double_quotes

View File

@ -0,0 +1,8 @@
SimpleCov.start do
add_filter 'bin/'
add_filter 'Casks/'
add_filter 'developer/'
add_filter 'doc/'
add_filter 'spec/'
add_filter 'test/'
end

View File

@ -0,0 +1,57 @@
language: ruby
sudo: false
env:
global:
- LANG=en_US.UTF-8
- LANGUAGE=en_US.UTF-8
- LC_ALL=en_US.UTF-8
matrix:
include:
- env: OSX=10.11 HOMEBREW_RUBY=2.0.0
os: osx
osx_image: xcode7.3
rvm: system
- env: OSX=10.10 HOMEBREW_RUBY=2.0.0
os: osx
osx_image: xcode7.1
rvm: system
fast_finish: true
branches:
only:
- master
cache:
directories:
- $HOME/.gem
before_install:
- . ci/travis/before_install.sh
install:
- . ci/travis/install.sh
before_script:
- . ci/travis/before_script.sh
script:
- . ci/travis/script.sh
notifications:
email: false
irc:
channels:
- "chat.freenode.net#homebrew-cask"
template:
- "(%{repository_name}) %{build_number}: %{branch}@%{commit} %{author} -> %{message} %{build_url}"
use_notice: true
skip_join: true
webhooks:
urls:
- "https://webhooks.gitter.im/e/712d699360b239db14a5"
on_success: change
on_failure: always
on_start: never

View File

@ -0,0 +1,74 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team. All complaints will be reviewed and
investigated and will result in a response that is deemed necessary and
appropriate to the circumstances. The project team is obligated to maintain
confidentiality with regard to the reporter of an incident. Further details of
specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@ -0,0 +1,71 @@
# How To Contribute
:+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
* [Updating a Cask](#updating-a-cask)
* [Getting Set Up To Contribute](#getting-set-up-to-contribute)
* [Adding a Cask](#adding-a-cask)
* [Style guide](#style-guide)
* [Reporting Bugs](README.md#reporting-bugs)
## Updating a Cask
Notice an application that's out-of-date in Homebrew-Cask? In most cases, it's very simple to update it. We have a [script](https://github.com/vitorgalvao/tiny-scripts/blob/master/cask-repair) that will ask for the new version number, and take care of updating the Cask file and submitting a pull request to us:
```bash
# install and setup script - only needed once
brew install vitorgalvao/tiny-scripts/cask-repair
cask-repair --help
# fork homebrew-cask to your account - only needed once
cd "$(brew --repository)/Library/Taps/caskroom/homebrew-cask/Casks"
hub fork
# use to update <outdated_cask>
outdated_cask='<the-cask-i-want-to-update>'
github_user='<my-github-username>'
cd "$(brew --repository)/Library/Taps/caskroom/homebrew-cask/Casks"
cask-repair --pull origin --push $github_user $outdated_cask
```
If there is a more complicated change, or there is a case where `cask-repair` fails, you can also follow the steps in [Adding a Cask](doc/development/adding_a_cask.md) to do the same thing manually. Remember to update the `version` and `shasum` values, as well as the appcast [`checkpoint`](doc/cask_language_reference/stanzas/appcast.md), if there is one.
## Getting Set Up To Contribute
For manual updates, you'll need to fork the repository and add your copy as a remote (can also be done with `hub fork`).
1. Fork the repository in GitHub with the `Fork` button.
2. Add your GitHub fork as a remote for your homebrew-cask Tap:
```bash
$ github_user='<my-github-username>'
$ cd "$(brew --repository)"/Library/Taps/caskroom/homebrew-cask
$ git remote add "$github_user" "https://github.com/$github_user/homebrew-cask"
```
3. Switch to a new branch (ie. `new-feature`), and work from there: `git checkout -b new-feature`
## Adding a Cask
Notice an application that's not in Homebrew-Cask yet? Make sure it's not yet in [Homebrew-Versions](https://github.com/caskroom/homebrew-versions) (can be searched from the Github repository page) or [Homebrew](https://github.com/Homebrew/homebrew) (can be searched with `brew search`). Mac App Store apps can't be installed via Homebrew-Cask, but check out [mas](https://github.com/argon/mas) for an alternative.
With a bit of work, you can create a Cask for it. [This document](doc/development/adding_a_cask.md) will walk you through creating a new Cask, testing it, and submitting it to us.
## Style guide
Some style guidelines:
* All Casks and code should be indented using two spaces (never tabs)
* There should not be any extraneous comments - the only comments that should be used are the ones explicitly defined in the [Cask Language Reference](doc/cask_language_reference)
* The stanza order and position of newlines is important to make things easier (See [Stanza order](doc/cask_language_reference/#stanza-order))
* Use string manipulations to improve the maintainability of your Cask (See [`version` methods](doc/cask_language_reference/stanzas/version.md#version-methods))
* Test your cask using `brew cask audit/style` (See [testing](doc/development/adding_a_cask.md#testing-your-new-cask))
* Make one Pull Request per Cask change
* Squash commits after updating a Pull Request
* Use descriptive commit messages - mention app name and version (ie. `Upgrade Transmission.app to v2.82`)

View File

@ -0,0 +1,26 @@
source "https://rubygems.org"
gem "rake"
group :debug do
gem "pry"
gem "pry-byebug", platforms: :mri
end
group :development do
gem "rubocop-cask", "~> 0.8.3"
end
group :release do
gem "ronn", "0.7.3"
end
group :test do
gem "coveralls", require: false
gem "minitest", "5.4.1"
gem "minitest-reporters"
gem "mocha", "1.1.0", require: false
gem "rspec", "~> 3.0.0"
gem "rspec-its", require: false
gem "rspec-wait", require: false
end

View File

@ -0,0 +1,119 @@
GEM
remote: https://rubygems.org/
specs:
ansi (1.5.0)
ast (2.3.0)
builder (3.2.2)
byebug (8.2.1)
coderay (1.1.0)
coveralls (0.8.10)
json (~> 1.8)
rest-client (>= 1.6.8, < 2)
simplecov (~> 0.11.0)
term-ansicolor (~> 1.3)
thor (~> 0.19.1)
tins (~> 1.6.0)
diff-lcs (1.2.5)
docile (1.1.5)
domain_name (0.5.25)
unf (>= 0.0.5, < 1.0.0)
hpricot (0.8.6)
http-cookie (1.0.2)
domain_name (~> 0.5)
json (1.8.3)
metaclass (0.0.4)
method_source (0.8.2)
mime-types (2.99)
minitest (5.4.1)
minitest-reporters (1.1.7)
ansi
builder
minitest (>= 5.0)
ruby-progressbar
mocha (1.1.0)
metaclass (~> 0.0.1)
mustache (1.0.2)
netrc (0.11.0)
parser (2.3.1.2)
ast (~> 2.2)
powerpack (0.1.1)
pry (0.10.3)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
pry-byebug (3.3.0)
byebug (~> 8.0)
pry (~> 0.10)
public_suffix (2.0.2)
rainbow (2.1.0)
rake (10.4.2)
rdiscount (2.1.8)
rest-client (1.8.0)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 3.0)
netrc (~> 0.7)
ronn (0.7.3)
hpricot (>= 0.8.2)
mustache (>= 0.7.0)
rdiscount (>= 1.5.8)
rspec (3.0.0)
rspec-core (~> 3.0.0)
rspec-expectations (~> 3.0.0)
rspec-mocks (~> 3.0.0)
rspec-core (3.0.4)
rspec-support (~> 3.0.0)
rspec-expectations (3.0.4)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.0.0)
rspec-its (1.2.0)
rspec-core (>= 3.0.0)
rspec-expectations (>= 3.0.0)
rspec-mocks (3.0.4)
rspec-support (~> 3.0.0)
rspec-support (3.0.4)
rspec-wait (0.0.8)
rspec (>= 2.11, < 3.5)
rubocop (0.41.2)
parser (>= 2.3.1.1, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
rubocop-cask (0.8.3)
public_suffix (~> 2.0)
rubocop (~> 0.41.1)
ruby-progressbar (1.8.1)
simplecov (0.11.1)
docile (~> 1.1.0)
json (~> 1.8)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.0)
slop (3.6.0)
term-ansicolor (1.3.2)
tins (~> 1.0)
thor (0.19.1)
tins (1.6.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.1)
unicode-display_width (1.1.0)
PLATFORMS
ruby
DEPENDENCIES
coveralls
minitest (= 5.4.1)
minitest-reporters
mocha (= 1.1.0)
pry
pry-byebug
rake
ronn (= 0.7.3)
rspec (~> 3.0.0)
rspec-its
rspec-wait
rubocop-cask (~> 0.8.3)
BUNDLED WITH
1.12.5

View File

@ -0,0 +1,23 @@
Copyright © 2013-2016, Paul Hinze & Contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,76 @@
# Homebrew-Cask
_“To install, drag this icon…” no more!_
Homebrew-Cask extends [Homebrew](http://brew.sh) and brings its elegance, simplicity, and speed to the installation and management of GUI macOS applications such as Google Chrome and Adium.
We do this by providing a friendly Homebrew-style CLI workflow for the administration of macOS applications distributed as binaries.
Its implemented as a `homebrew` [external command](https://github.com/Homebrew/brew/blob/master/share/doc/homebrew/External-Commands.md) called `cask`.
[![Build Status](https://img.shields.io/travis/caskroom/homebrew-cask/master.svg)](https://travis-ci.org/caskroom/homebrew-cask)
[![Code Climate](https://img.shields.io/codeclimate/github/caskroom/homebrew-cask.svg)](https://codeclimate.com/github/caskroom/homebrew-cask)
[![Coverage Status](https://img.shields.io/coveralls/caskroom/homebrew-cask.svg)](https://coveralls.io/r/caskroom/homebrew-cask)
[![Join the chat at https://gitter.im/caskroom/homebrew-cask](https://img.shields.io/badge/gitter-join%20chat-blue.svg)](https://gitter.im/caskroom/homebrew-cask)
## Lets try it!
To start using Homebrew-Cask, you just need [Homebrew](http://brew.sh/) installed.
<img src="https://i.imgur.com/WYa2557.gif" width="450px" alt="Installing Atom (animated gif)">
Slower, now:
```
$ brew cask install atom
==> Satisfying dependencies
complete
==> Downloading https://github.com/atom/atom/releases/download/v1.8.0/atom-mac.zip
######################################################################## 100.0%
==> Verifying checksum for Cask atom
==> Moving App 'Atom.app' to '/Applications/Atom.app'
==> Symlinking Binary 'apm' to '/usr/local/bin/apm'
==> Symlinking Binary 'atom.sh' to '/usr/local/bin/atom'
🍺 atom was successfully installed!
```
And there we have it. Atom installed with one quick command: no clicking, no dragging, no dropping.
## Learn More
* Find basic documentation on using Homebrew-Cask in [USAGE.md](USAGE.md)
* Want to contribute a Cask? Awesome! See [CONTRIBUTING.md](CONTRIBUTING.md)
* Want to hack on our code? Also awesome! See [hacking.md](doc/development/hacking.md)
* More project-related details and discussion are available in the [documentation](doc)
## Reporting bugs
Like most pieces of software, Homebrew-Cask has bugs — and we are busy fixing them! If you find a new bug tell us about it, but before you do make sure the problem isnt simply an outdated setup on your side, by following [this guide](doc/reporting_bugs/pre_bug_report.md).
If your issue persists, follow these instructions to the appropriate course of action:
* [A cask fails to install](doc/reporting_bugs/a_cask_fails_to_install.md)
* [`brew cask list` shows wrong information](doc/reporting_bugs/brew_cask_list_shows_wrong_information.md)
* [`uninstall` wrongly reports cask as not installed](doc/reporting_bugs/uninstall_wrongly_reports_cask_as_not_installed.md)
* [My problem isnt listed][bug_report_template]
## Requests
* Start an issue on GitHub following one of these templates:
* [Feature request][feature_request_template]
* [Cask request][cask_request_template]
## Questions? Wanna chat?
Were really rather friendly! Here are the best places to talk about the project:
* If none of the templates above is appropriate, [open an issue](https://github.com/caskroom/homebrew-cask/issues/new).
* Join us (and [caskbot](https://github.com/passcod/caskbot)) on IRC at `#homebrew-cask` on Freenode
* Join us on [Gitter](https://gitter.im/caskroom/homebrew-cask)
## License
Code is under the [BSD 2 Clause (NetBSD) license](LICENSE)
[bug_report_template]: https://github.com/caskroom/homebrew-cask/issues/new?title=Bug%20report%3A&body=Remember%20to%20follow%20the%20%5Bpre%20bug%20report%5D%28https%3A%2F%2Fgithub.com%2Fcaskroom%2Fhomebrew-cask%2Fblob%2Fmaster%2Fdoc%2Freporting_bugs%2Fpre_bug_report.md%29%20guide%20beforehand.%20Failure%20to%20do%20so%20might%20get%20your%20issue%20closed.%0A%0A%23%23%23%23%20Description%20of%20issue%0A%0A%5Binsert%20a%20detailed%20description%20of%20your%20issue%20here%5D%0A%0A%3Cdetails%3E%3Csummary%3EOutput%20of%20%60brew%20cask%20%3Ccommand%3E%20--verbose%60%3C%2Fsummary%3E%0A%0A%60%60%60%0A%5Bpaste%20output%20here%5D%0A%60%60%60%0A%3C%2Fdetails%3E%0A%0A%3Cdetails%3E%3Csummary%3EOutput%20of%20%60brew%20doctor%60%3C%2Fsummary%3E%0A%0A%60%60%60%0A%5Bpaste%20output%20here%5D%0A%60%60%60%0A%3C%2Fdetails%3E%0A%0A%3Cdetails%3E%3Csummary%3EOutput%20of%20%60brew%20cask%20doctor%60%3C%2Fsummary%3E%0A%0A%60%60%60%0A%5Bpaste%20output%20here%5D%0A%60%60%60%0A%3C%2Fdetails%3E%0A
[cask_request_template]: https://github.com/caskroom/homebrew-cask/issues/new?title=Cask%20request%3A&body=%23%23%23%20Cask%20details%0A%0A%28Please%20fill%20out%20as%20much%20as%20possible%29%0A%0A%2A%2AName%2A%2A%20-%0A%0A%2A%2AHomepage%2A%2A%20-%0A%0A%2A%2ALicense%2A%2A%20-%0A%0A%2A%2ADownload%20URL%2A%2A%20-%0A%0A%2A%2ADescription%2A%2A%20-%0A
[feature_request_template]: https://github.com/caskroom/homebrew-cask/issues/new?title=Feature%20request%3A&body=%23%23%23%20Description%20of%20feature%2Fenhancement%0A%0A%0A%0A%23%23%23%20Justification%0A%0A%0A%0A%23%23%23%20Example%20use%20case%0A%0A%0A%0A

View File

@ -0,0 +1,52 @@
require "coveralls/rake/task"
require "rake/testtask"
require "rspec/core/rake_task"
require "rubocop/rake_task"
homebrew_repo = `brew --repository`.chomp
$LOAD_PATH.unshift(File.expand_path("#{homebrew_repo}/Library/Homebrew"))
$LOAD_PATH.unshift(File.expand_path("../lib", __FILE__))
namespace :test do
Rake::TestTask.new(:minitest) do |t|
# TODO: setting the --seed here is an ugly temporary hack, to remain only
# until test-suite glitches are fixed.
ENV["TESTOPTS"] = "--seed=14830" if ENV["TRAVIS"]
t.pattern = "test/**/*_test.rb"
t.libs << "test"
end
RSpec::Core::RakeTask.new(:rspec)
desc "Run tests for minitest and RSpec with coverage"
task :coverage do
ENV["COVERAGE"] = "1"
Rake::Task[:test].invoke
end
end
desc "Run tests for minitest and RSpec"
task test: ["test:minitest", "test:rspec"]
Coveralls::RakeTask.new
RuboCop::RakeTask.new(:rubocop) do |t|
t.options = ["--force-exclusion"]
end
task default: [:test, :rubocop]
desc "Open a REPL for debugging and experimentation"
task :console do
require "pry"
require "pry-byebug"
require "hbc"
ARGV.clear
Hbc.pry
end
desc "Generate man page from Markdown source"
task :man do
sh "ronn --roff --pipe --organization=Homebrew-Cask --manual=brew-cask " \
"doc/man_page/brew-cask.1.md > man/man1/brew-cask.1"
end

View File

@ -0,0 +1,230 @@
# How to Use Homebrew-Cask
## Getting Started
First ensure you have Homebrew version `0.9.5` or higher:
```bash
$ brew --version
0.9.5
```
## Frequently Used Commands
Homebrew-Cask is implemented as a subcommand of Homebrew. All Homebrew-Cask commands begin with `brew cask`. Homebrew-Cask has its own set of command verbs many of which are similar to Homebrews. The most frequently-used
commands are:
* `search` — searches all known Casks
* `install` — installs the given Cask
* `uninstall` — uninstalls the given Cask
## Searching for Casks
The `brew cask search` command accepts a series of substring arguments, and returns tokens representing matching Casks. Lets see if theres a Cask for Google Chrome:
```bash
$ brew cask search chrome
google-chrome
```
A `search` command with no search term will list all available Casks:
```bash
$ brew cask search
# <list of all available Casks>
```
## Installing Casks
The command `brew cask install` accepts a Cask token as returned by `brew cask search`. Lets try to install Google Chrome:
```bash
$ brew cask install google-chrome
==> Downloading https://dl.google.com/chrome/mac/stable/GGRO/googlechrome.dmg
==> Moving App 'Google Chrome.app' to '/Applications/Google Chrome.app'
🍺 google-chrome was successfully installed!
```
## Uninstalling Casks
Easy peasy:
```bash
$ brew cask uninstall google-chrome
```
This will both uninstall the Cask and remove applications which were moved to `/Applications`.
To uninstall all versions of a Cask, use `--force`:
```bash
$ brew cask uninstall --force google-chrome
```
Note that `uninstall --force` is currently imperfect. See the man page for more information.
## Other Commands
* `info` — displays information about the given Cask
* `list` — with no args, lists installed Casks; given installed Casks, lists staged files
* `fetch` — downloads remote application files for the given Cask to the local cache (with `--force`, re-download even if already cached)
* `doctor` — checks for configuration issues
* `cleanup` — cleans up cached downloads (with `--outdated`, only cleans old downloads)
* `home` — opens the homepage of the given Cask; or with no arguments, the Homebrew-Cask project page
* `update` — a synonym for `brew update`
* `zap` — try to remove *all* files associated with a Cask (may include resources shared with other applications)
The following commands are for Cask authors:
* `audit` — verifies installability of Casks
* `cat` — dumps the given Cask to the standard output
* `create` — creates a Cask and opens it in an editor
* `edit` — edits the given Cask
The following aliases and abbreviations are provided for convenience:
* `ls``list`
* `-S``search`
* `rm`, `remove``uninstall`
* `up``update`
* `dr``doctor`
## Tab Completion
[Homebrew/homebrew-completions](https://github.com/Homebrew/homebrew-completions) supports `bash` and `fish` completions (only for `brew-cask` right now). Install them with:
```bash
$ brew install homebrew/completions/brew-cask-completion
```
For `zsh` completion support, simply run:
```bash
$ brew install zsh-completions
```
## Inspecting Installed Casks
List all installed Casks:
```bash
$ brew cask list
adium google-chrome onepassword
```
Show details about a specific Cask:
```bash
$ brew cask info caffeine
caffeine: 1.1.1
http://lightheadsw.com/caffeine/
Not installed
From: https://github.com/caskroom/homebrew-cask/blob/master/Casks/caffeine.rb
==> Name
Caffeine
==> Artifacts
Caffeine.app (app)
```
## Updating/Upgrading Casks
Since the Homebrew-Cask repository is a Homebrew Tap, youll pull down the latest Casks every time you issue the regular Homebrew command `brew update`. Currently, Homebrew-Cask cannot always detect if an application has been updated. You can force an update via the command `brew cask install --force`. We are working on improving this.
It is generally safe to run updates from within an application.
## Updating/Upgrading the Homebrew-Cask Tool
Homebrew [automatically taps and keeps Homebrew-Cask updated](https://github.com/caskroom/homebrew-cask/pull/15381). `brew update` is all that is required.
## Additional Taps (optional)
The primary Homebrew-Cask Tap includes most of the Casks that a typical user will be interested in. There are a few additional Taps where we store different kinds of Casks.
| Tap name | description |
| -------- | ----------- |
| [caskroom/versions](https://github.com/caskroom/homebrew-versions) | contains alternate versions of Casks (e.g. betas, nightly releases, old versions)
| [caskroom/fonts](https://github.com/caskroom/homebrew-fonts) | contains Casks that install fonts, which are kept separate so we can educate users about the different licensing landscape around font installation/usage
| [caskroom/eid](https://github.com/caskroom/homebrew-eid) | contains Casks that install electronic identity card software of various countries
You can tap any of the above with a `brew tap` command:
```bash
$ brew tap <tap_name>
```
after which, Casks from the new Tap will be available to `search` or `install` just like Casks from the main Tap. `brew update` will automatically keep your new Tap up to date.
You may also specify a fully-qualified Cask token (which includes the Tap) for any `brew cask` command. This will implicitly add the Tap if you have not previously added it with `brew tap`:
```bash
$ brew cask install caskroom/fonts/font-symbola
```
## Options
`brew cask` accepts a number of options:
* `--version`: print version and exit
* `--debug`: output debug information
* `--no-binaries`: skip symlinking executable binaries into `/usr/local/bin`
* `--require-sha`: abort installation of cask if no checksum is defined
You can also modify the default installation locations used when issuing `brew cask install`:
* `--caskroom=/my/path` determines where the actual applications will be located.
Default is `$(brew --repository)/Caskroom`
* `--appdir=/my/path` changes the path where the applications (above)
will be moved. Default is `/Applications`.
* `--prefpanedir=/my/path` changes the path for PreferencePanes.
Default is `~/Library/PreferencePanes`
* `--qlplugindir=/my/path` changes the path for Quicklook Plugins.
Default is `~/Library/QuickLook`
* `--fontdir=/my/path` changes the path for Fonts.
Default is `~/Library/Fonts`
* `--input_methoddir=/my/path` changes the path for Input Methods.
Default is `~/Library/Input Methods`
* `--screen_saverdir=/my/path` changes the path for Screen Savers.
Default is `~/Library/Screen Savers`
To make these settings persistent, you might want to add the following line to your `.bash_profile` or `.zshenv`:
```bash
# Specify your defaults in this environment variable
export HOMEBREW_CASK_OPTS="--appdir=~/Applications --caskroom=/etc/Caskroom"
```
Note that you still can override the environment variable `HOMEBREW_CASK_OPTS` by _explicitly_ providing options in the command line:
```bash
# Will force the Chrome app to be moved to /Applications
# even though HOMEBREW_CASK_OPTS specified ~/Applications
$ brew cask install --appdir="/Applications" google-chrome
```
## Advanced Searching
The default search algorithm is a lax substring approach, which does not use the command-line arguments exactly as given. If you need to specify a search more precisely, a single search argument enclosed in `/` characters will be taken as a Ruby regular expression:
```bash
$ brew cask search '/^google.c[a-z]rome$/'
google-chrome
```
## Other Ways to Specify a Cask
Most `brew cask` commands can accept a Cask token as an argument. As described above, the token on the command line can take the form of:
* A token as returned by `brew cask search`, _eg_: `google-chrome`.
* A fully-qualified token which includes the Tap, _eg_: `caskroom/fonts/font-symbola`.
`brew cask` also accepts three other forms as arguments:
* A path to a Cask file, _eg_: `/usr/local/Library/Taps/caskroom/homebrew-cask/Casks/google-chrome.rb`.
* A `curl`-retrievable URI to a Cask file, _eg_: `https://raw.githubusercontent.com/caskroom/homebrew-cask/f25b6babcd398abf48e33af3d887b2d00de1d661/Casks/google-chrome.rb`.
* A file in the current working directory, _eg_: `my-modfied-google-chrome.rb`. Note that matching Tapped Cask tokens will be preferred over this form when there is a conflict. To force the use of a Cask file in the current directory, specify a pathname with slashes, _eg_: `./google-chrome.rb`.
The last three forms are intended for users who wish to maintain private Casks.
## Taps
You can add Casks to your existing (or new) Taps: just create a directory named `Casks` inside your Tap, put your Cask files there, and everything will just work.

View File

@ -0,0 +1,20 @@
require "English"
repo_root = Pathname(__FILE__).realpath.parent.parent
repo_root.cd do
ENV["HOMEBREW_NO_ANALYTICS_THIS_RUN"] = "1"
Homebrew.install_gem_setup_path! "bundler"
unless quiet_system("bundle", "check")
system "bundle", "install", "--path", "vendor/bundle"
end
test_task = "test"
%w[rspec minitest coverage].each do |subtask|
next unless ARGV.flag?("--#{subtask}")
test_task = "test:#{subtask}"
end
system "bundle", "exec", "rake", test_task
Homebrew.failed = !$CHILD_STATUS.success?
end

View File

@ -0,0 +1,12 @@
require "pathname"
$LOAD_PATH.unshift(File.expand_path("../../lib", Pathname.new(__FILE__).realpath))
require "hbc"
begin
Hbc::CLI.process(ARGV)
rescue Interrupt
puts
exit 130
end

View File

@ -0,0 +1,190 @@
#!/bin/bash
set -o pipefail
readonly program="$(basename "$0")"
skip_curl_verify=0
verbose=0
syntax_error() {
echo "$program: $1" >&2
echo "Try \`$program --help\` for more information." >&2
exit 1
}
depends_on() {
formula="$1"
[[ "$#" -eq 2 ]] && cmd="$2" || cmd=$(basename "${formula}")
if [[ ! $(which ${cmd}) ]]; then
echo -e "$(tput setaf 1)
This script depends on '${cmd}'.
If you have [Homebrew](http://brew.sh), you can install it with 'brew install ${formula}'.
$(tput sgr0)" | sed -E 's/ {6}//' >&2
exit 1
fi
}
depends_on 'tsparber/tiny-scripts/curl-check-url'
usage() {
echo "
This script changes the url, appcast and homepage stanzas to https
After changing to https a HTTP GET request is performed to verify if the url is reachable.
If the https url is not reachable it is reverted to the previous version.
Known Issues: If multiple url/appcast stanzas are present, all urls are changed but only
those for the current os are verified.
If no cask name is given the current work directory is scanned with the given options.
usage: $program [options] [<cask_name>]
options:
-s, --skip-verify Skip checking for a HTTP 200 Status Code using curl.
--verbose Show more verbose output.
-h, --help Show this help.
Based on: https://github.com/vitorgalvao/tiny-scripts/blob/master/cask-repair
" | sed -E 's/^ {4}//'
}
# available flags
while [[ "$1" ]]; do
case "$1" in
-h | --help)
usage
exit 0
;;
-s | --skip-verify)
skip_curl_verify=1
;;
--verbose)
verbose=1
;;
-*)
syntax_error "unrecognized option: $1"
;;
*)
break
;;
esac
shift
done
# define function to check if given URL exists and is reachable using HTTPS
check_url_for_https() {
cask_url="$1"
verbose_option=""
[[ ${verbose} -ne 0 ]] && verbose_option="-v "
# check if the URL sends a 200 HTTP code, else abort
curl-check-url ${verbose_option} "${cask_url}" > /dev/null
exit_code=$?
if [[ exit_code -ne 0 ]]; then
echo "curl returned ${exit_code}: FAIL for ${cask_url}"
return 1
fi
return 0
}
# define function to modify part of stanza
replace_protocol_of_stanza() {
cask_file="$1"
stanza="$2"
old_value="$3"
new_value="$4"
sed "s|${stanza} \(['\"]\)${old_value}://|${stanza} \1${new_value}://|g" "${cask_file}" > tmpfile
mv tmpfile "${cask_file}"
}
# define abort function, that will reset the state
finish() {
# show message
if [[ "$1" == 'abort' ]]; then
echo -e "$(tput setaf 1)$2$(tput sgr0)\n"
[[ ! -z "${cask_file}" ]] && git checkout -- "${cask_file}"
exit 1
elif [[ "$1" == 'success' ]]; then
echo -e "$(tput setaf 2)Updated: ${cask_name} is now using HTTPS$(tput sgr0)\n"
exit 0
fi
}
# cleanup if aborted with ⌃C
trap 'finish abort "You aborted"' SIGINT
# exit if not inside a 'homebrew-*/Casks' directory
casks_dir=$(pwd | perl -ne 'print m{homebrew-[^/]+/Casks}')
if [[ -z "${casks_dir}" ]]; then
echo -e "\n$(tput setaf 1)You need to be inside a '/homebrew-*/Casks' directory$(tput sgr0)\n"
exit 1
fi
# exit if no argument was given: Run in current directory
if [[ -z "$1" ]]; then
options=""
[[ ${skip_curl_verify} -ne 0 ]] && options+=" --skip-verify"
[[ ${verbose} -ne 0 ]] && options+=" --verbose"
for file in *.rb;
do
"$0" ${options} ${file}
done
exit 0
fi
# clean the cask's name, and check if it is valid
cask_name="$1"
[[ "${cask_name}" == *'.rb' ]] && cask_name=$(echo "${cask_name}" | sed 's|\.rb$||')
cask_file="./${cask_name}.rb"
[[ ! -f "${cask_file}" ]] && finish abort 'There is no such cask'
# initial tasks
git checkout -- "${cask_file}"
# check if a http url exists
cask_contains_http=$(grep "['\"]http://" "${cask_file}")
if [[ -z ${cask_contains_http} ]]; then
echo -e "Skipped ${cask_name} no http found\n"
exit 0
fi
updated_stanzas=0
for stanza in url appcast homepage; do
# Check if the stanza exists
stanza_contained=$(grep "${stanza} ['\"]" "${cask_file}")
[[ -z ${stanza_contained} ]] && continue
stanza_contains_https=$(grep "${stanza} ['\"]http://" "${cask_file}")
if [[ -z ${stanza_contains_https} ]]; then
# echo "Skipped stanza ${stanza} in ${cask_name} no http url found"
continue
fi
replace_protocol_of_stanza ${cask_file} ${stanza} "http" "https"
if [[ ${skip_curl_verify} -eq 0 ]]; then
check_url_for_https $(brew cask _stanza ${stanza} "${cask_name}")
else
true
fi
if [[ $? -ne 0 ]]; then
echo "Restored original value for stanza ${stanza} as curl check failed"
replace_protocol_of_stanza ${cask_file} ${stanza} "https" "http"
else
updated_stanzas=$((updated_stanzas+1))
fi
done
if [[ ${updated_stanzas} -ne 0 ]]; then
finish success
else
finish abort "no updated stanzas after verify for ${cask_name}"
fi

View File

@ -0,0 +1,199 @@
#!/bin/bash
#
# develop_brew_cask
#
# Called via symlink as:
# production_brew_cask
#
called_as="$(basename "$0")"
###
### settings
###
set -e # exit on any uncaught error
set +o histexpand # don't expand history expressions
shopt -s nocasematch # case-insensitive regular expressions
###
### configurable global variables
###
taps_subdir="Library/Taps"
cask_tap_subdir="caskroom/homebrew-cask"
dev_links=("cmd" "lib" "Casks")
###
### functions
###
warn () {
local message="$*"
message="${message//\\t/$'\011'}"
message="${message//\\n/$'\012'}"
message="${message%${message##*[![:space:]]}}"
printf "%s\n" "$message" 1>&2
}
die () {
warn "$@"
exit 1
}
cd_to_project_root () {
local script_dir git_root
script_dir="$(/usr/bin/dirname "$0")"
cd "$script_dir"
git_root="$(git rev-parse --show-toplevel)"
if [[ -z "$git_root" ]]; then
die "ERROR: Could not find git project root"
fi
cd "$git_root"
}
cd_to_tap_dir () {
local taps_dir="$1"
local tap_dir="$2"
if [[ ! -d "$tap_dir" ]]; then
die "ERROR: Could not find tap dir under $taps_dir/"
fi
cd "$tap_dir"
}
not_inside_homebrew () {
local tap_dir="$1"
local git_root="$2"
if [[ "$(/usr/bin/stat -L -f '%i' -- "$tap_dir")" -eq "$(/usr/bin/stat -L -f '%i' -- "$git_root")" ]]; then
die "\nERROR: Run this script in your private repo, not inside Homebrew.\n"
fi
}
remove_dev_links () {
for link_name in "${dev_links[@]}"; do
remove_dev_link "$link_name"
done
printf "brew-cask is now in production mode\n"
printf "It is safe to run 'brew update' if you are in production mode for all Caskroom repos.\n"
}
create_dev_links () {
local git_root="$1"
for link_name in "${dev_links[@]}"; do
create_dev_link "$git_root" "$link_name"
done
printf "brew-cask is now in development mode\n"
printf "Note: it is not safe to run 'brew update' while in development mode\n"
}
remove_dev_link () {
local link_name="$1"
/bin/rm -- "$link_name"
/bin/mv -- "production_$link_name" "$link_name"
}
create_dev_link () {
local git_root="$1"
local link_name="$2"
/bin/mv -- "$link_name" "production_$link_name"
/bin/ln -s -- "$git_root/$link_name" .
}
###
### main
###
_develop_brew_cask_develop_action () {
die "brew-cask is already set up for development"
}
_develop_brew_cask_production_action () {
create_dev_links "$git_root"
}
_production_brew_cask_develop_action () {
remove_dev_links
}
_production_brew_cask_production_action () {
die "brew-cask is already set up for production"
}
_main () {
local git_root brew_repository taps_dir tap_dir
# initialization
cd_to_project_root
git_root="$(/bin/pwd)"
brew_repository="$(brew --repository)"
taps_dir="$brew_repository/$taps_subdir"
tap_dir="$taps_dir/$cask_tap_subdir"
# sanity check
not_inside_homebrew "$tap_dir" "$git_root"
# action
cd_to_tap_dir "$taps_dir" "$tap_dir"
if [[ -e "production_lib" ]]; then
eval "_${called_as}_develop_action"
else
eval "_${called_as}_production_action"
fi
}
_develop_brew_cask_usage () {
printf "develop_brew_cask
Symlink private repo directories into Homebrew's Cellar, so
that the 'brew cask' command will use code and Casks from
the current development branch in your private repo.
Saves the production Homebrew directories under new names.
You can reverse this operation with 'production_brew_cask'.
Note: it is not safe to run 'brew update' while development
mode is in effect.
"
}
_production_brew_cask_usage () {
printf "production_brew_cask
Undo all symlinks created by 'develop_brew_cask' so that the
'brew cask' command will use only released code and Casks
within Homebrew.
After running this command it is safe to run 'brew update',
unless you are using similar scripts to create symlinks into
other Caskroom development repos.
"
}
# ensure we're called by a valid name
case "${called_as}" in
develop_brew_cask) ;;
production_brew_cask) ;;
*)
die "ERROR: name ${called_as} not recognized"
;;
esac
# process args
if [[ $1 =~ ^-+h(elp)?$ ]]; then
eval "_${called_as}_usage"
exit
fi
# dispatch main
_main "${@}"
#

View File

@ -0,0 +1,121 @@
#!/bin/bash
readonly caskroom_online='https://github.com/caskroom'
readonly caskroom_repos_dir='/tmp/caskroom_repos'
readonly caskroom_repos=(homebrew-cask homebrew-versions homebrew-fonts homebrew-eid)
readonly curl_flags=(--silent --location --header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36')
inaccessible_appcasts=()
if [[ ! $(which 'ghi') ]] || ! security find-internet-password -s github.com -l 'ghi token' &> /dev/null; then
echo -e "$(tput setaf 1)
This script requires 'ghi' installed and configured.
If you have [Homebrew](http://brew.sh), you can install it with 'brew install ghi'.
To configure it, run 'ghi config --auth <username>'. Your Github password will be required, but is never stored.
$(tput sgr0)" | sed -E 's/ {4}//' >&2
exit 1
fi
function message {
echo "${1}"
}
function go_to_repos_dir {
[[ ! -d "${caskroom_repos_dir}" ]] && mkdir -p "${caskroom_repos_dir}"
cd "${caskroom_repos_dir}" || exit 1
}
function go_to_repo_and_update {
local repo_name repo_dir casks_dir
repo_name="${1}"
repo_dir="${caskroom_repos_dir}/${repo_name}"
casks_dir="${repo_dir}/Casks"
if [[ ! -d "${repo_dir}" ]]; then
go_to_repos_dir
message "Cloning ${repo_name}…"
git clone "https://github.com/caskroom/${repo_name}.git" --quiet
cd "${casks_dir}" || exit 1
else
cd "${casks_dir}" || exit 1
message "Updating ${repo_name}…"
git pull --rebase origin master --quiet
fi
}
function open_issue {
local repo_name cask_name cask_url version appcast_url issue_number
repo_name="${1}"
cask_name="${2}"
cask_url="${caskroom_online}/${repo_name}/blob/master/Casks/${cask_name}.rb"
version="${3}"
appcast_url="${4}"
message="$(echo "Outdated cask: ${cask_name}
Outdated cask: [\`${cask_name}\`](${cask_url}).
Info:
+ version: \`${version}\`.
+ appcast url: ${appcast_url}.
" | sed -E 's/^ {4}//')"
issue_number=$(ghi open --label 'outdated appcast' --message "${message}" | head -1 | perl -pe 's/^#(\d+): .*/\1/')
message "Opened issue: https://github.com/caskroom/${repo_name}/issues/${issue_number}."
}
function is_appcast_available {
local appcast_url
appcast_url="${1}"
http_status="$(curl "${curl_flags[@]}" --head --write-out '%{http_code}' "${appcast_url}" -o '/dev/null')"
[[ "${http_status}" == 200 ]]
}
function report_outdated_appcasts {
local repo_name cask_name appcast_url current_checkpoint new_checkpoint version
repo_name="${1}"
for cask_file in ./*; do
appcast_url="$(brew cask _stanza appcast "${cask_file}")"
[[ -z "${appcast_url}" ]] && continue # skip early if there is no appcast
cask_name="$(basename "${cask_file%.*}")"
message "Verifying appcast checkpoint for ${cask_name}…"
if is_appcast_available "${appcast_url}"; then
current_checkpoint="$(brew cask _stanza --yaml appcast "${cask_file}" | grep '^- :checkpoint' | awk '{print $3}')"
new_checkpoint="$(curl "${curl_flags[@]}" --compressed "${appcast_url}" | sed 's|<pubDate>[^<]*</pubDate>||g' | shasum --algorithm 256 | awk '{ print $1 }')"
else
message "There was an error checking the appcast for ${cask_name}."
inaccessible_appcasts+=("${repo_name}/${cask_name}")
continue
fi
if [[ "${current_checkpoint}" != "${new_checkpoint}" ]]; then
version="$(brew cask _stanza version "${cask_file}")"
message "${cask_name} is outdated. Opening issue in ${repo_name}…"
open_issue "${repo_name}" "${cask_name}" "${version}" "${appcast_url}"
fi
done
}
for repo in "${caskroom_repos[@]}"; do
go_to_repo_and_update "${repo}"
report_outdated_appcasts "${repo}"
done
if [[ ${#inaccessible_appcasts[@]} -gt 0 ]];then
echo # empty line
message 'Some casks have appcasts that errored out, and may need to be rechecked:'
printf '%s\n' "${inaccessible_appcasts[@]}"
fi

View File

@ -0,0 +1,68 @@
#!/bin/bash
readonly user_agent=(--user-agent 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36')
usage() {
local program exit_status
program="$(basename "$0")"
exit_status="$1"
echo "usage: ${program} <path_to_app>"
exit "${exit_status}"
}
absolute_path() {
echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
}
appcast_found_error() {
local error_reason="$1"
echo "An appcast was found pointing to ${appcast_url}, but it ${error_reason}. You should:
1. Check your internet connection.
2. Try again later.
3. Contact the developer."
exit 1
}
# exit if no argument (or more than one) was given
if [[ -z "$1" ]] || [[ -n "$2" ]]; then
usage 1
fi
# get plist
path_to_app="$(absolute_path "$1")"
path_to_plist="${path_to_app}/Contents/Info.plist"
if [[ ! -f "${path_to_plist}" ]]; then
echo 'You need to use this on a .app bundle. Please verify your target.'
usage 1
fi
# get appcast
appcast_url="$(defaults read "${path_to_plist}" 'SUFeedURL' 2>/dev/null)"
if [[ -z "${appcast_url}" ]]; then
echo 'It appears this app does not have a Sparkle appcast'
exit 0
fi
# validate appcast
appcast_http_response="$(curl --silent --head "${user_agent[@]}" --write-out '%{http_code}' "${appcast_url}" -o /dev/null)"
[[ "${appcast_http_response}" != '200' ]] && appcast_found_error "returned a non-200 (OK) HTTP response code (${appcast_http_response})"
appcast_checkpoint=$(curl --silent --compressed --location "${user_agent[@]}" "${appcast_url}" | sed 's|<pubDate>[^<]*</pubDate>||g' | shasum --algorithm 256 | awk '{ print $1 }')
[[ "${appcast_checkpoint}" == 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' ]] && appcast_found_error 'seems to be empty'
# output appcast
echo "A Sparkle appcast was found. You should add it to your cask as
appcast '${appcast_url}',
checkpoint: '${appcast_checkpoint}'
You should likely also add 'auto_updates true'"
exit 0

View File

@ -0,0 +1,78 @@
#!/bin/bash
IFS=$'\n'
readonly caskroom_repos_dir='/tmp/caskroom_repos'
readonly caskroom_repos=(homebrew-cask homebrew-versions homebrew-fonts homebrew-eid)
if [[ ! $(which 'ghi') ]] || ! security find-internet-password -s github.com -l 'ghi token' &> /dev/null; then
echo -e "$(tput setaf 1)
This script requires 'ghi' installed and configured.
If you have [Homebrew](http://brew.sh), you can install it with 'brew install ghi'.
To configure it, run 'ghi config --auth <username>'. Your Github password will be required, but is never stored.
$(tput sgr0)" | sed -E 's/ {4}//' >&2
exit 1
fi
if [[ ! $(which 'cask-repair') ]]; then
echo -e "$(tput setaf 1)
This script requires 'cask-repair'.
If you have [Homebrew](http://brew.sh), you can install it with 'brew install vitorgalvao/tiny-scripts/cask-repair'.
$(tput sgr0)" | sed -E 's/ {4}//' >&2
exit 1
fi
function message {
echo "${1}"
}
function go_to_repos_dir {
[[ ! -d "${caskroom_repos_dir}" ]] && mkdir -p "${caskroom_repos_dir}"
cd "${caskroom_repos_dir}" || exit 1
}
function go_to_repo_and_update {
local repo_name repo_dir casks_dir
repo_name="${1}"
repo_dir="${caskroom_repos_dir}/${repo_name}"
casks_dir="${repo_dir}/Casks"
if [[ ! -d "${repo_dir}" ]]; then
go_to_repos_dir
message "Cloning ${repo_name}…"
git clone "https://github.com/caskroom/${repo_name}.git" --quiet
cd "${casks_dir}" || exit 1
else
cd "${casks_dir}" || exit 1
message "Updating ${repo_name}…"
git pull --rebase origin master --quiet
fi
}
function fix_outdated_appcasts {
local issue_number cask_name pr_number
for line in $(ghi list --state open --no-pulls --label 'outdated appcast' --reverse | tail +2); do
[[ "${line}" == 'None.' ]] && break # exit early if there are no relevant issues in repo
issue_number="$(awk '{print $1}' <<< "${line}")"
cask_name="$(awk '{print $4}' <<< "${line}")"
cask-repair --pull origin --push origin --open-appcast --closes-issue "${issue_number}" --blind-submit "${cask_name}"
if [[ "$?" -eq 0 ]]; then
pr_number="$(ghi list --pulls --creator | sed -n 2p | awk '{print $1}')"
ghi edit --label 'outdated appcast' "${pr_number}" &>/dev/null
ghi comment --close --message "Closing in favour of #${pr_number}." "${issue_number}" &>/dev/null
fi
done
}
for repo in "${caskroom_repos[@]}"; do
go_to_repo_and_update "${repo}"
fix_outdated_appcasts
done

View File

@ -0,0 +1,418 @@
#!/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/ruby
#
# generate_cask_token
#
# todo:
#
# remove Ruby 2.0 dependency and change shebang line
#
# detect Cask files which differ only by the placement of hyphens.
#
# merge entirely into "brew cask create" command
#
###
### dependencies
###
require "pathname"
require "open3"
begin
# not available by default
require "active_support/inflector"
rescue LoadError
end
###
### configurable constants
###
EXPANDED_SYMBOLS = {
"+" => "plus",
"@" => "at",
}.freeze
CASK_FILE_EXTENSION = ".rb".freeze
# Hardcode App names that cannot be transformed automatically.
# Example: in "x48.app", "x48" is not a version number.
# The value in the hash should be a valid Cask token.
APP_EXCEPTION_PATS = {
# looks like a trailing version, but is not.
%r{\Aiterm\Z}i => "iterm2",
%r{\Aiterm2\Z}i => "iterm2",
%r{\Apgadmin3\Z}i => "pgadmin3",
%r{\Ax48\Z}i => "x48",
%r{\Avitamin-r[\s\d\.]*\Z}i => "vitamin-r",
%r{\Aimagealpha\Z}i => "imagealpha",
# upstream is in the midst of changing branding
%r{\Abitcoin-?qt\Z}i => "bitcoin-core",
# "mac" cannot be separated from the name because it is in an English phrase
%r{\Aplayonmac\Z}i => "playonmac",
%r{\Acleanmymac[\s\d\.]*\Z}i => "cleanmymac",
# arguably we should not have kept these two exceptions
%r{\Akismac\Z}i => "kismac",
%r{\Avoicemac\Z}i => "voicemac",
}.freeze
# Preserve trailing patterns on App names that could be mistaken
# for version numbers, etc
PRESERVE_TRAILING_PATS = [
%r{id3}i,
%r{mp3}i,
%r{3[\s-]*d}i,
%r{diff3}i,
%r{\A[^\d]+\+\Z}i,
].freeze
# The code that employs these patterns against App names
# - hacks a \b (word-break) between CamelCase and snake_case transitions
# - anchors the pattern to end-of-string
# - applies the patterns repeatedly until there is no match
REMOVE_TRAILING_PATS = [
# spaces
%r{\s+}i,
# generic terms
%r{\bapp}i,
%r{\b(?:quick[\s-]*)?launcher}i,
# "mac", "for mac", "for OS X", "macOS", "for macOS".
%r{\b(?:for)?[\s-]*mac(?:intosh|OS)?}i,
%r{\b(?:for)?[\s-]*os[\s-]*x}i,
# hardware designations such as "for x86", "32-bit", "ppc"
%r{(?:\bfor\s*)?x.?86}i,
%r{(?:\bfor\s*)?\bppc}i,
%r{(?:\bfor\s*)?\d+.?bits?}i,
# frameworks
%r{\b(?:for)?[\s-]*(?:oracle|apple|sun)*[\s-]*(?:jvm|java|jre)}i,
%r{\bgtk}i,
%r{\bqt}i,
%r{\bwx}i,
%r{\bcocoa}i,
# localizations
%r{en\s*-\s*us}i,
# version numbers
%r{[^a-z0-9]+}i,
%r{\b(?:version|alpha|beta|gamma|release|release.?candidate)(?:[\s\.\d-]*\d[\s\.\d-]*)?}i,
%r{\b(?:v|ver|vsn|r|rc)[\s\.\d-]*\d[\s\.\d-]*}i,
%r{\d+(?:[a-z\.]\d+)*}i,
%r{\b\d+\s*[a-z]}i,
%r{\d+\s*[a-c]}i, # constrained to a-c b/c of false positives
].freeze
# Patterns which are permitted (undisturbed) following an interior version number
AFTER_INTERIOR_VERSION_PATS = [
%r{ce}i,
%r{pro}i,
%r{professional}i,
%r{client}i,
%r{server}i,
%r{host}i,
%r{viewer}i,
%r{launcher}i,
%r{installer}i,
].freeze
###
### classes
###
class AppName < String
def self.remove_trailing_pat
@@remove_trailing_pat ||= %r{(?<=.)(?:#{REMOVE_TRAILING_PATS.join('|')})\Z}i
end
def self.preserve_trailing_pat
@@preserve_trailing_pat ||= %r{(?:#{PRESERVE_TRAILING_PATS.join('|')})\Z}i
end
def self.after_interior_version_pat
@@after_interior_version_pat ||= %r{(?:#{AFTER_INTERIOR_VERSION_PATS.join('|')})}i
end
def english_from_app_bundle
return self if ascii_only?
return self unless File.exist?(self)
# check Info.plist CFBundleDisplayName
bundle_name = Open3.popen3(*%w[
/usr/libexec/PlistBuddy -c
],
"Print CFBundleDisplayName",
Pathname.new(self).join("Contents", "Info.plist").to_s) do |_stdin, stdout, _stderr|
begin
stdout.gets.force_encoding("UTF-8").chomp
rescue
end
end
return AppName.new(bundle_name) if bundle_name && bundle_name.ascii_only?
# check Info.plist CFBundleName
bundle_name = Open3.popen3(*%w[
/usr/libexec/PlistBuddy -c
],
"Print CFBundleName",
Pathname.new(self).join("Contents", "Info.plist").to_s) do |_stdin, stdout, _stderr|
begin
stdout.gets.force_encoding("UTF-8").chomp
rescue
end
end
return AppName.new(bundle_name) if bundle_name && bundle_name.ascii_only?
# check localization strings
local_strings_file = Pathname.new(self).join("Contents", "Resources", "en.lproj", "InfoPlist.strings")
local_strings_file = Pathname.new(self).join("Contents", "Resources", "English.lproj", "InfoPlist.strings") unless local_strings_file.exist?
if local_strings_file.exist?
bundle_name = File.open(local_strings_file, "r:UTF-16LE:UTF-8") do |fh|
%r{\ACFBundle(?:Display)?Name\s*=\s*"(.*)";\Z}.match(fh.readlines.grep(%r{^CFBundle(?:Display)?Name\s*=\s*}).first) do |match|
match.captures.first
end
end
return AppName.new(bundle_name) if bundle_name && bundle_name.ascii_only?
end
# check Info.plist CFBundleExecutable
bundle_name = Open3.popen3(*%w[
/usr/libexec/PlistBuddy -c
],
"Print CFBundleExecutable",
Pathname.new(self).join("Contents", "Info.plist").to_s) do |_stdin, stdout, _stderr|
begin
stdout.gets.force_encoding("UTF-8").chomp
rescue
end
end
return AppName.new(bundle_name) if bundle_name && bundle_name.ascii_only?
self
end
def basename
if Pathname.new(self).exist?
AppName.new(Pathname.new(self).basename.to_s)
else
self
end
end
def remove_extension
sub(%r{\.app\Z}i, "")
end
def decompose_to_ascii
# crudely (and incorrectly) decompose extended latin characters to ASCII
return self if ascii_only?
return self unless respond_to?(:mb_chars)
AppName.new(mb_chars.normalize(:kd).each_char.select(&:ascii_only?).join)
end
def hardcoded_exception
APP_EXCEPTION_PATS.each do |regexp, exception|
return AppName.new(exception) if regexp.match(self)
end
nil
end
def insert_vertical_tabs_for_camel_case
app_name = AppName.new(self)
if app_name.sub!(%r{(#{self.class.preserve_trailing_pat})\Z}i, "")
trailing = Regexp.last_match(1)
end
app_name.gsub!(%r{([^A-Z])([A-Z])}, "\\1\v\\2")
app_name.sub!(%r{\Z}, trailing) if trailing
app_name
end
def insert_vertical_tabs_for_snake_case
gsub(%r{_}, "\v")
end
def clean_up_vertical_tabs
gsub(%r{\v}, "")
end
def remove_interior_versions!
# done separately from REMOVE_TRAILING_PATS because this
# requires a substitution with a backreference
sub!(%r{(?<=.)[\.\d]+(#{self.class.after_interior_version_pat})\Z}i, '\1')
sub!(%r{(?<=.)[\s\.\d-]*\d[\s\.\d-]*(#{self.class.after_interior_version_pat})\Z}i, '-\1')
end
def remove_trailing_strings_and_versions
app_name = insert_vertical_tabs_for_camel_case
.insert_vertical_tabs_for_snake_case
while self.class.remove_trailing_pat.match(app_name) &&
!self.class.preserve_trailing_pat.match(app_name)
app_name.sub!(self.class.remove_trailing_pat, "")
end
app_name.remove_interior_versions!
app_name.clean_up_vertical_tabs
end
def simplified
return @simplified if @simplified
@simplified = english_from_app_bundle
.basename
.decompose_to_ascii
.remove_extension
@simplified = @simplified.hardcoded_exception || @simplified.remove_trailing_strings_and_versions
@simplified
end
end
class CaskFileName < String
def spaces_to_hyphens
gsub(%r{ +}, "-")
end
def delete_invalid_chars
gsub(%r{[^a-z0-9-]+}, "")
end
def collapse_multiple_hyphens
gsub(%r{--+}, "-")
end
def delete_leading_hyphens
gsub(%r{^--+}, "")
end
def delete_hyphens_before_numbers
gsub(%r{-([0-9])}, '\1')
end
def spell_out_symbols
cask_file_name = self
EXPANDED_SYMBOLS.each do |k, v|
cask_file_name.gsub!(k, " #{v} ")
end
cask_file_name.sub(%r{ +\Z}, "")
end
def add_extension
sub(%r{(?:#{escaped_cask_file_extension})?\Z}i, CASK_FILE_EXTENSION)
end
def remove_extension
sub(%r{#{escaped_cask_file_extension}\Z}i, "")
end
def from_simplified_app_name
return @from_simplified_app_name if @from_simplified_app_name
@from_simplified_app_name = if APP_EXCEPTION_PATS.rassoc(remove_extension)
remove_extension
else
remove_extension
.downcase
.spell_out_symbols
.spaces_to_hyphens
.delete_invalid_chars
.collapse_multiple_hyphens
.delete_leading_hyphens
.delete_hyphens_before_numbers
end
raise "Could not determine Simplified App name" if @from_simplified_app_name.empty?
@from_simplified_app_name.add_extension
end
end
###
### methods
###
def project_root
Dir.chdir File.dirname(File.expand_path(__FILE__))
@git_root ||= Open3.popen3(*%w[
git rev-parse --show-toplevel
]) do |_stdin, stdout, _stderr|
begin
Pathname.new(stdout.gets.chomp)
rescue
raise "could not find project root"
end
end
raise "could not find project root" unless @git_root.exist?
@git_root
end
def escaped_cask_file_extension
@escaped_cask_file_extension ||= Regexp.escape(CASK_FILE_EXTENSION)
end
def simplified_app_name
@simplified_app_name ||= AppName.new(ARGV.first.dup.force_encoding("UTF-8")).simplified
end
def cask_file_name
@cask_file_name ||= CaskFileName.new(simplified_app_name).from_simplified_app_name
end
def cask_token
@cask_token ||= cask_file_name.remove_extension
end
def warnings
return @warnings if @warnings
@warnings = []
unless APP_EXCEPTION_PATS.rassoc(cask_token)
if %r{\d} =~ cask_token
@warnings.push "WARNING: '#{cask_token}' contains digits. Digits which are version numbers should be removed."
end
end
filename = project_root.join("Casks", cask_file_name)
if filename.exist?
@warnings.push "WARNING: the file '#{filename}' already exists. Prepend the vendor name if this is not a duplicate."
end
@warnings
end
def report
puts "Proposed Simplified App name: #{simplified_app_name}" if $debug
puts "Proposed token: #{cask_token}"
puts "Proposed file name: #{cask_file_name}"
puts "Cask Header Line: cask '#{cask_token}' do"
unless warnings.empty?
$stderr.puts "\n"
$stderr.puts warnings
$stderr.puts "\n"
exit 1
end
end
###
### main
###
usage = <<-EOS
Usage: generate_cask_token [ -debug ] <application.app>
Given an Application name or a path to an Application, propose a
Cask token, filename, and header line.
With -debug, also provide the internal "Simplified App Name".
EOS
if ARGV.first =~ %r{^-+h(elp)?$}i
puts usage
exit 0
end
if ARGV.first =~ %r{^-+debug?$}i
$debug = 1
ARGV.shift
end
unless ARGV.length == 1
puts usage
exit 1
end
report

View File

@ -0,0 +1,74 @@
#!/usr/bin/env ruby
#
# generate_issue_template_urls
#
###
### dependencies
###
require "erb"
###
### constants
###
BASE_URL = "https://github.com/caskroom/homebrew-cask/issues/new".freeze
###
### methods
###
def main(args)
args.each do |file|
File.read(file).scan(%r{(.*?)\n(.*)}m) do |title, body|
puts generate_url(title, body)
end
end
end
def generate_url(title, body)
encoded_title = url_encode(title)
encoded_body = url_encode(body)
if $debug
puts "Encoded title: #{encoded_title}"
puts "Encoded body: #{encoded_body}"
end
"#{BASE_URL}?title=#{encoded_title}&body=#{encoded_body}"
end
def url_encode(unencoded_str)
ERB::Util.url_encode(unencoded_str)
end
###
### main
###
usage = <<-EOS
Usage: generate_issue_template_urls <issue_template.md> ...
Given one or more GitHub issue template files, generate encoded URLs for each
and print, separated by newlines. The first line of a template file should be
the issue title.
With -debug, print out the encoded title and body individually as well.
EOS
if ARGV.first =~ %r{^-+h(elp)?$}i
puts usage
exit 0
end
if ARGV.first =~ %r{^-+debug?$}i
$debug = 1
ARGV.shift
end
if ARGV.empty?
puts usage
exit 1
end
main(ARGV)

View File

@ -0,0 +1,133 @@
#!/bin/bash
#
# irregular_cask_whitespace
#
# find irregular whitespace in Cask files
#
# notes
#
# requires a recent-ish Perl with Unicode support, probably 5.14
# or better.
#
# bugs
#
# todo
#
###
### settings
###
set -e
set -o pipefail
set +o histexpand
set -o nounset
shopt -s nocasematch
shopt -s nullglob
###
### functions
###
warn () {
local message="$@"
message="${message//\\t/$'\011'}"
message="${message//\\n/$'\012'}"
message="${message%"${message##*[![:space:]]}"}"
printf "%s\n" "$message" 1>&2
}
die () {
warn "$@"
exit 1
}
###
### main
###
_irregular_cask_whitespace () {
local directory="$1"
cd "$directory" || die "Could not cd to '$directory'"
printf "# No trailing newline at EOF\n"
perl -C32 -0777 -ne 'print " $ARGV\n" if m{[^\n]\z}s' -- ./*.rb
printf "\n# Extra trailing newline at EOF\n"
perl -C32 -0777 -ne 'print " $ARGV\n" if m{\n{2}\z}s' -- ./*.rb
printf "\n# Final 'end' indented\n"
perl -C32 -0777 -ne 'print " $ARGV\n" if m{ end\s+\z}s' -- ./*.rb
printf "\n# Extra newline before final end\n"
perl -C32 -0777 -ne 'print " $ARGV\n" if m{\n\nend\s+\z}s' -- ./*.rb
printf "\n# Extra newline before header\n"
perl -C32 -0777 -ne 'print " $ARGV\n" if m{\n\ncask\s+:v\d\S*\s+=>}s' -- ./*.rb
printf "\n# Extra newline after header\n"
perl -C32 -0777 -ne 'print " $ARGV\n" if m{(?:\A|\n)cask\s+:v\d\S*\s+=>[^\n]+\n\n\s*(\S+)}s and $1 ne "if"' -- ./*.rb
printf "\n# No empty line before uninstall\n"
perl -C32 -0777 -ne 'print " $ARGV\n" if m{\n[^\n]+\n +uninstall }s' -- ./*.rb
# todo?
# printf "\n# No empty line before caveats\n"
# perl -C32 -0777 -ne 'print " $ARGV\n" if m{\n[^\n]+\n +caveats }s' -- ./*.rb
printf "\n# Extra interior newlines\n"
perl -C32 -0777 -ne 'print " $ARGV\n" if m{\n{3,}}s' -- ./*.rb
printf "\n# Leading whitespace at BOF\n"
perl -C32 -0777 -ne 'print " $ARGV\n" if m{\A\s}s' -- ./*.rb
printf "\n# Trailing whitespace at EOL (includes Tab/CR)\n"
perl -C32 -ne 'print " $ARGV\n" if m{\s\n}s' -- ./*.rb | sort | uniq
printf "\n# Tabs\n"
perl -C32 -0777 -ne 'print " $ARGV\n" if m{\t}s' -- ./*.rb
printf "\n# Carriage Returns\n"
perl -C32 -0777 -ne 'print " $ARGV\n" if m{\r}s' -- ./*.rb
printf "\n# Misc Control Characters\n"
perl -C32 -0777 -ne 'print " $ARGV\n" if m{[\x00-\x08\x0B-\x0C\x0E\x1F]}s' -- ./*.rb
printf "\n# First indent not 2\n"
perl -C32 -0777 -ne 's{\A(.*?\n)?cask\s+[^\n]+\n+}{}s; print " $ARGV\n" unless m{\A \S}s' -- ./*.rb
printf "\n# Indents not multiple of 2\n"
perl -C32 -0777 -ne 'print " $ARGV\n" if m{\n(?: ){0,} [a-z]}s' -- ./*.rb
printf "\n# Unicode Space Characters\n"
# \x{0085}\x{0088}\x{0089}
perl -C32 -0777 -ne 'print " $ARGV\n" if m{[\x{008a}\x{00a0}\x{1680}\x{180e}\x{2000}\x{2001}\x{2002}\x{2003}\x{2004}\x{2005}\x{2006}\x{2007}\x{2008}\x{2009}\x{200a}\x{200b}\x{2028}\x{2029}\x{202f}\x{205f}\x{2060}\x{3000}\x{feff}\x{e0020}]}s' -- ./*.rb
}
###
### argument processing
###
if [[ "${1:-}" =~ ^-+h(elp)?$ ]]; then
printf "irregular_cask_whitespace <dir>
Find irregular whitespace in Cask files within <dir>
"
exit
fi
if [ "$#" -ne 1 ]; then
die "Single directory argument required"
elif ! [ -d "$1" ]; then
die "No directory found at '$1'"
fi
###
### dispatch
###
_irregular_cask_whitespace "${@:-}"
#

View File

@ -0,0 +1,166 @@
#!/bin/bash
#
# list_apps_in_pkg
#
###
### settings
###
set -e # exit on any uncaught error
set +o histexpand # don't expand history expressions
shopt -s nocasematch # case-insensitive regular expressions
###
### global variables
###
opt_lax=''
opt_pkg=''
pkgdir=''
# prefer GNU xargs
xargs="$(/usr/bin/which gxargs || printf '/usr/bin/xargs')"
###
### functions
###
warn () {
local message="$@"
message="${message//\\t/$'\011'}"
message="${message//\\n/$'\012'}"
message="${message%"${message##*[![:space:]]}"}"
printf "%s\n" "$message" 1>&2
}
die () {
warn "$@"
exit 1
}
app_source_1 () {
/usr/bin/find "$pkgdir" -name PackageInfo -print0 | \
"$xargs" -0 /usr/bin/perl -0777 -ne \
'while (m{<pkg-info[^\n]*install-location="/Applications".*?path\s*=\s*"([^"]+)"}sg) { my $p = $1; $p =~ s{\A.*/}{}; print "$p\n" }';
}
app_source_2 () {
/usr/bin/find "$pkgdir" -name PackageInfo -print0 | \
"$xargs" -0 /usr/bin/perl -0777 -ne \
'while (m{<pkg-info[^\n]*install-location="/".*?path\s*=\s*"./Applications/([^"]+)"}sg) { my $p = $1; $p =~ s{\A.*/}{}; print "$p\n" }';
}
app_source_3 () {
/usr/bin/find "$pkgdir" -type d -name '*.app' | \
perl -pe 's{\A.*/}{}';
}
app_source_4 () {
/usr/bin/find "$pkgdir" -name PackageInfo -print0 | \
"$xargs" -0 /usr/bin/perl -0777 -ne \
'while (m{path\s*=\s*"([^"]+\.app)"}sg) { my $p = $1; $p =~ s{\A.*/}{}; print "$p\n" }';
}
app_source_5 () {
/usr/bin/find "$pkgdir" -name Archive.pax.gz -print0 | \
"$xargs" -0 -n1 -I{} /bin/bash -c \
"/usr/bin/gunzip -c '{}' | /bin/pax | /usr/bin/egrep '\.app'" | \
/usr/bin/perl -pe 's{\A.*/([^/]+\.app).*\Z}{$1}';
}
merge_sources () {
/usr/bin/sort | /usr/bin/uniq
}
mark_up_sources () {
/usr/bin/perl -pe 's{\n}{\000}sg' | \
"$xargs" -0 -I{} -n1 /bin/bash -c \
'printf "{}"; /bin/test -n "$(/usr/bin/find /Applications -type d -maxdepth 3 -name "{}" -print0; /usr/bin/find ~/Applications -type d -maxdepth 3 -name "{}")" && printf " (+)"; printf "\n"'
}
process_args () {
local arg
if [[ "$#" -eq 0 ]]; then
die "ERROR: A file argument is required"
else
opt_pkg="${!#}" # last arg
fi
for arg in "$@"; do
if [[ $arg =~ ^-+h(elp)?$ ]]; then
printf "list_apps_in_pkg [ -lax ] <file.pkg>
Given a package file, extract a list of candidate App names from
inside the pkg, which may be useful for naming a Cask.
The given package file need not be installed.
If an App of the listed name is already installed in /Applications
or ~/Applications, it will be followed by a plus symbol '(+)' in
the output. This can be verified via 'ls' or the Finder.
Arguments
-lax Be less selective in looking for App names. Generate
more, but less accurate, guesses.
Bugs: This script is imperfect.
- It does not fully parse PackageInfo files
- An App can be hidden within a nested archive and not found
- Some pkg files simply don't contain any Apps
See CONTRIBUTING.md and 'man pkgutil' for more information.
"
exit
elif [[ $arg =~ ^-+lax$ ]]; then
opt_lax='true'
elif [[ "$arg" = "$opt_pkg" ]]; then
true
else
die "ERROR: Unknown argument '$arg'"
fi
done
if [[ -h "$opt_pkg" ]]; then
opt_pkg="$(/usr/bin/readlink "$opt_pkg")"
fi
if ! [[ -e "$opt_pkg" ]]; then
die "ERROR: No such pkg file: '$opt_pkg'"
fi
}
###
### main
###
_list_apps_in_pkg () {
if [[ -d "$opt_pkg" ]]; then
pkgdir="$opt_pkg"
else
local tmpdir="$(/usr/bin/mktemp -d -t list_ids_in_pkg)"
trap "/bin/rm -rf -- '$tmpdir'" EXIT
pkgdir="$tmpdir/unpack"
/usr/sbin/pkgutil --expand "$opt_pkg" "$tmpdir/unpack" "$pkgdir"
fi
{
# strings that look like App names (Something.app)
app_source_1;
app_source_2;
app_source_3;
if [[ -n "$opt_lax" ]]; then
app_source_4;
app_source_5;
fi
} | \
merge_sources | \
mark_up_sources
}
process_args "${@}"
# dispatch main
_list_apps_in_pkg
#

View File

@ -0,0 +1,93 @@
#!/bin/bash
#
# list_id_in_kext
#
###
### settings
###
set -e # exit on any uncaught error
set +o histexpand # don't expand history expressions
shopt -s nocasematch # case-insensitive regular expressions
###
### global variables
###
kextdir=''
# prefer GNU xargs
xargs="$(/usr/bin/which gxargs || printf '/usr/bin/xargs')"
###
### functions
###
bundle_id_source_1 () {
/usr/bin/find "$kextdir" -name Info.plist -print0 | \
"$xargs" -0 -I {} /usr/libexec/PlistBuddy {} -c 'Print :CFBundleIdentifier'
}
merge_sources () {
/usr/bin/sort | /usr/bin/uniq
}
clean_sources () {
/usr/bin/egrep -v '^com\.apple\.'
}
mark_up_sources () {
/usr/bin/perl -pe 's{\n}{\000}sg' | \
"$xargs" -0 -I{} -n1 /bin/bash -c \
'printf "{}"; /bin/test "$(/usr/sbin/kextstat -kl -b "{}" | /usr/bin/wc -l)" -gt 0 && printf " (+)"; printf "\n"'
}
###
### main
###
_list_id_in_kext () {
kextdir="$1"
if [[ -h "$kextdir" ]]; then
kextdir="$(/usr/bin/readlink "$kextdir")"
fi
{
# emit strings that look like bundle ids
bundle_id_source_1;
} | \
clean_sources | \
merge_sources | \
mark_up_sources
}
# process args
if [[ $1 =~ ^-+h(elp)?$ || -z "$1" ]]; then
printf "list_id_in_kext <file.kext>
Given a Kernel Extension (kext) bundle dir on disk, extract the
associated kext Bundle ID, which may be useful in a Cask uninstall
stanza, eg
uninstall :kext => 'kext.id.goes.here'
The kext need not be loaded for this script to work.
If a given kext is currently loaded, it will be followed by a plus
symbol '(+)' in the output. This can be verified via the command
/usr/sbin/kextstat -kl -b 'kext.id.goes.here'
See CONTRIBUTING.md and 'man kextstat' for more information.
"
exit
fi
# dispatch main
_list_id_in_kext "${@}"
#

View File

@ -0,0 +1,162 @@
#!/bin/bash
#
# list_ids_in_app
#
###
### settings
###
set -e # exit on any uncaught error
set +o histexpand # don't expand history expressions
shopt -s nocasematch # case-insensitive regular expressions
###
### global variables
###
appdir=''
scriptdir="$(dirname "$0")"
# prefer GNU xargs
xargs="$(/usr/bin/which gxargs || printf '/usr/bin/xargs')"
###
### functions
###
bundle_id_source_1 () {
/usr/bin/find "$appdir" -name Info.plist -print0 | \
"$xargs" -0 -I {} /usr/libexec/PlistBuddy {} -c 'Print :CFBundleIdentifier'
}
merge_sources () {
/usr/bin/sort | /usr/bin/uniq
}
clean_sources () {
/usr/bin/egrep -v '^com\.apple\.' | \
/usr/bin/egrep -vi '^org\.andymatuschak\.Sparkle' | \
/usr/bin/egrep -vi '^(SDL|SDL_net|TDParseKit)$' | \
/usr/bin/egrep -vi '^com\.growl\.(growlframework|WebKit|iCal|GrowlAction|GrowlLauncher|GrowlPlugins)' | \
/usr/bin/egrep -vi '^com\.adobe\.(ACE|AGM|AXE8SharedExpat|AdobeExtendScript|AdobeScCore|AdobeXMPCore|BIB|BIBUtils|CoolType|ESD\.AdobeUpdaterLibFramework|JP2K|adobe_caps|AcrobatPlugin|AdobeResourceSynchronizer|ICUConverter|ICUData|acrobat\.assert|acrobat\.pdfviewerNPAPI|adobepdf417pmp|ahclientframework|datamatrixpmp|eulaframework|framework|linguistic|qrcodepmp)' | \
/usr/bin/egrep -vi '^com\.microsoft\.(Automator|certificate\.framework|chart|converterlib|converters|excel\.pde|grammar|igx|mcp|merp|msls3|netlib|officeart|ole|oleo|powerplant|powerplantcore|powerpoint\.pde|speller|thesaurus|urlmon|wizard|wordforms|MSCommon|mbuinstrument_framework|mbukernel_framework|rdpkit)' | \
/usr/bin/egrep -vi '^com\.google\.(Chrome\.framework|Chrome\.helper|Keystone|BreakpadFramework|GDataFramework|Reporter)' | \
/usr/bin/egrep -vi '^atmo\.mac\.macho' | \
/usr/bin/egrep -vi '^com\.3dconnexion\.driver\.client' | \
/usr/bin/egrep -vi '^com\.Breakpad\.crash_report_sender' | \
/usr/bin/egrep -vi '^com\.Cycling74\.driver\.Soundflower' | \
/usr/bin/egrep -vi '^com\.HumbleDaisy\.HDCrashReporter' | \
/usr/bin/egrep -vi '^com\.amazon\.JSONKit' | \
/usr/bin/egrep -vi '^com\.bensyverson\..*dvmatte' | \
/usr/bin/egrep -vi '^com\.binarymethod\.BGHUDAppKit' | \
/usr/bin/egrep -vi '^com\.blacktree\.(QSCore|QSEffects|QSFoundation|QSInterface)' | \
/usr/bin/egrep -vi '^com\.brandonwalkin\.BWToolkitFramework' | \
/usr/bin/egrep -vi '^com\.cruzapp\.TDWebThumbnail' | \
/usr/bin/egrep -vi '^com\.cycling74\.QTExportTool' | \
/usr/bin/egrep -vi '^com\.fluidapp\.(BrowserBrowserPlugIn|FluidInstance|ThumbnailPlugIn)' | \
/usr/bin/egrep -vi '^com\.github\.ObjectiveGit' | \
/usr/bin/egrep -vi '^com\.heroku\.RedisAdapter' | \
/usr/bin/egrep -vi '^com\.instinctivecode\.MGScopeBar' | \
/usr/bin/egrep -vi '^com\.intel\.nw\.helper' | \
/usr/bin/egrep -vi '^com\.joshaber\.RockemSockem' | \
/usr/bin/egrep -vi '^com\.katidev\.KTUIKit' | \
/usr/bin/egrep -vi '^com\.kirin\.plugin\.adapter' | \
/usr/bin/egrep -vi '^com\.lextek\.onix' | \
/usr/bin/egrep -vi '^com\.macromedia\.(Flash Player\.authplaylib|PepperFlashPlayer)' | \
/usr/bin/egrep -vi '^com\.mainconcept\.mc\.enc\.avc' | \
/usr/bin/egrep -vi '^com\.netscape\.(DefaultPlugin|MRJPlugin)' | \
/usr/bin/egrep -vi '^com\.nxtbgthng\.JSONKit' | \
/usr/bin/egrep -vi '^com\.omnigroup\.(OmniAppKit|OmniInspector|framework)' | \
/usr/bin/egrep -vi '^com\.oracle\.java\..*\.jdk' | \
/usr/bin/egrep -vi '^com\.panic\.(PanicCore|automator|CodaScriptPlugIn)' | \
/usr/bin/egrep -vi '^com\.pixelespresso\.cocoafob' | \
/usr/bin/egrep -vi '^com\.positivespinmedia\.(PSMTabBarControlFramework|PSMTabBarFramework)' | \
/usr/bin/egrep -vi '^com\.softube\.(Amplifier|Cabinet)' | \
/usr/bin/egrep -vi '^com\.sonic\.(AS_Storage|AuthorScriptHDMV)' | \
/usr/bin/egrep -vi '^com\.soundcloud\.Share-on-SoundCloud' | \
/usr/bin/egrep -vi '^com\.stuffit\.(format|sdk|stuffitcore)' | \
/usr/bin/egrep -vi '^com\.sun\.Scintilla' | \
/usr/bin/egrep -vi '^com\.yourcompany' | \
/usr/bin/egrep -vi '^coop\.plausible\.(CrashReporter|PLWeakCompatibility)' | \
/usr/bin/egrep -vi '^de\.buzzworks\.Quincy' | \
/usr/bin/egrep -vi '^de\.dstoecker\.xadmaster' | \
/usr/bin/egrep -vi '^isao\.sonobe\.OgreKit' | \
/usr/bin/egrep -vi '^jp\.hmdt\.framework\.hmdtblkappkit' | \
/usr/bin/egrep -vi '^net\.hockeyapp\.sdk\.mac' | \
/usr/bin/egrep -vi '^net\.java\.openjdk\.jre' | \
/usr/bin/egrep -vi '^net\.liquidx\.EyeTunes' | \
/usr/bin/egrep -vi '^net\.sourceforge\.Log4Cocoa' | \
/usr/bin/egrep -vi '^net\.sourceforge\.munt\.MT32Emu' | \
/usr/bin/egrep -vi '^net\.sourceforge\.skim-app\.framework' | \
/usr/bin/egrep -vi '^net\.wafflesoftware\.ShortcutRecorder\.framework' | \
/usr/bin/egrep -vi '^org\.AFNetworking\.AFNetworking' | \
/usr/bin/egrep -vi '^org\.boredzo\.(LMX|ISO8601DateFormatter)' | \
/usr/bin/egrep -vi '^org\.dribin\.dave\.DDHidLib' | \
/usr/bin/egrep -vi '^org\.linkbackproject\.LinkBack' | \
/usr/bin/egrep -vi '^org\.mozilla\.(crashreporter|plugincontainer|universalchardet|updater)' | \
/usr/bin/egrep -vi '^org\.python\.(python|PythonLauncher|buildapplet)' | \
/usr/bin/egrep -vi '^org\.remotesensing\.libtiff' | \
/usr/bin/egrep -vi '^org\.vafer\.FeedbackReporter' | \
/usr/bin/egrep -vi '^org\.xiph\.(ogg|vorbis)' | \
/usr/bin/egrep -vi '^se\.propellerheads\..*\.library$'
}
mark_up_sources () {
/usr/bin/perl -pe 's{\n}{\000}sg' | \
"$xargs" -0 -I{} -n1 /bin/bash -c \
"printf '{}'; $scriptdir/list_running_app_ids -t '{}' >/dev/null 2>&1 && printf ' (+)'; printf "\\\\n""
}
###
### main
###
_list_ids_in_app () {
appdir="$1"
if [[ -h "$appdir" ]]; then
appdir="$(/usr/bin/readlink "$appdir")"
fi
{
# emit strings that look like bundle ids
bundle_id_source_1;
} | \
clean_sources | \
merge_sources | \
mark_up_sources
}
# process args
if [[ $1 =~ ^-+h(elp)?$ || -z "$1" ]]; then
printf "list_ids_in_app <path.app>
Given a Application (app) bundle directory on disk, extract the
associated app Bundle ID, which may be useful in a Cask uninstall
stanza, eg
uninstall quit: 'app.id.goes.here'
The app need not be running for this script to work.
Bundle IDs attributed to Apple and common developer frameworks
are excluded from the output.
If a given app is currently running, it will be followed by a plus
symbol '(+)' in the output. This can be verified via the command
list_running_app_ids | grep 'app.id.goes.here'
See CONTRIBUTING.md for more information.
"
exit
fi
# dispatch main
_list_ids_in_app "${@}"
#

View File

@ -0,0 +1,115 @@
#!/bin/bash
#
# list_ids_in_pkg
#
###
### settings
###
set -e # exit on any uncaught error
set +o histexpand # don't expand history expressions
shopt -s nocasematch # case-insensitive regular expressions
###
### global variables
###
pkgdir=''
# prefer GNU xargs
xargs="$(/usr/bin/which gxargs || printf '/usr/bin/xargs')"
###
### functions
###
bundle_id_source_1 () {
/usr/bin/find "$pkgdir" -name PackageInfo -print0 | \
"$xargs" -0 /usr/bin/perl -0777 -ne \
'while (m{<pkg-info.*?\sid(?:entifier)?\s*=\s*"([^"]*?)"}sg) { print "$1\n" }'
}
bundle_id_source_2 () {
/usr/bin/find "$pkgdir" -name Info.plist -print0 | \
"$xargs" -0 -I {} /usr/libexec/PlistBuddy {} -c 'Print :CFBundleIdentifier'
}
merge_sources () {
/usr/bin/sort | /usr/bin/uniq
}
clean_sources () {
/usr/bin/egrep -v '^com\.apple\.' | \
/usr/bin/egrep -v 'sparkle\.finish-installation$'
}
mark_up_sources () {
/usr/bin/perl -pe 's{\n}{\000}sg' | \
"$xargs" -0 -I{} -n1 /bin/bash -c \
'printf "{}"; /usr/sbin/pkgutil --pkg-info "{}" >/dev/null 2>&1 && printf " (+)"; printf "\n"'
}
###
### main
###
_list_ids_in_pkg () {
if [[ -d "$1" ]]; then
pkgdir="$1"
if [[ -h "$pkgdir" ]]; then
pkgdir="$(/usr/bin/readlink "$pkgdir")"
fi
else
local tmpdir="$(/usr/bin/mktemp -d -t list_ids_in_pkg)"
trap "/bin/rm -rf -- '$tmpdir'" EXIT
pkgdir="$tmpdir/unpack"
/usr/sbin/pkgutil --expand "$1" "$tmpdir/unpack" "$pkgdir"
fi
{
# emit strings that look like bundle ids
bundle_id_source_1;
bundle_id_source_2;
} | \
merge_sources | \
clean_sources | \
mark_up_sources
}
# process args
if [[ $1 =~ ^-+h(elp)?$ || -z "$1" ]]; then
printf "list_ids_in_pkg <file.pkg>
Given a package file, extract a list of candidate Package IDs
which may be useful in a Cask uninstall stanza, eg
uninstall pkgutil: 'package.id.goes.here'
The given package file need not be installed.
The output of this script should be overly inclusive -- not
every candidate package id in the output will be needed at
uninstall time.
Package IDs designated by Apple or common development frameworks
will be excluded from the output.
If a package id is already installed, it will be followed by
a plus symbol '(+)' in the output. This can be verified via
the command
/usr/sbin/pkgutil --pkg-info 'package.id.goes.here'
See CONTRIBUTING.md and 'man pkgutil' for more information.
"
exit
fi
# dispatch main
_list_ids_in_pkg "${@}"
#

View File

@ -0,0 +1,90 @@
#!/bin/bash
#
# list_installed_launchjob_ids
#
###
### settings
###
set -e # exit on any uncaught error
set +o histexpand # don't expand history expressions
shopt -s nocasematch # case-insensitive regular expressions
###
### global variables
###
# prefer GNU xargs
xargs="$(/usr/bin/which gxargs || printf '/usr/bin/xargs')"
###
### functions
###
launchjob_id_source_1 () {
/usr/bin/find ~/Library/LaunchAgents/ \
~/Library/LaunchDaemons/ \
/Library/LaunchAgents/ \
/Library/LaunchDaemons/ \
-type f -print0 2>/dev/null | \
"$xargs" -0 /usr/bin/perl -0777 -ne \
'while (m{<key>\s*Label\s*</key>\s*<string>([^<]+?)</string>}sg) { print "$1\n" }'
}
merge_sources () {
/usr/bin/sort | /usr/bin/uniq
}
clean_sources () {
/usr/bin/egrep -v '^com\.apple\.'
}
mark_up_sources () {
/usr/bin/perl -pe 's{\n}{\000}sg' | \
"$xargs" -0 -I{} -n1 /bin/bash -c \
'printf "{}"; /bin/launchctl list "{}" >/dev/null 2>&1 && printf " (+)"; printf "\n"'
}
###
### main
###
_list_installed_launchjob_ids () {
{
launchjob_id_source_1;
} | \
merge_sources | \
clean_sources | \
mark_up_sources
}
# process args
if [[ $1 =~ ^-+h(elp)?$ ]]; then
printf "list_installed_launchjob_ids
List all installed launchjob IDs, which may be useful
in a Cask uninstall stanza, eg
uninstall launchctl: 'job.id.goes.here'
Launchctl jobs attributed to Apple will be ommitted.
If a launchctl job is currently loaded, and visible to the current
user, it will be followed by a plus symbol '(+)' in the output.
This can be verified via the command
/bin/launchctl list 'job.id.goes.here'
See CONTRIBUTING.md and 'man launchctl' for more information.
"
exit
fi
# dispatch main
_list_installed_launchjob_ids "${@}"
#

View File

@ -0,0 +1,45 @@
#!/bin/bash
#
# list_loaded_kext_ids
#
###
### settings
###
set -e # exit on any uncaught error
set +o histexpand # don't expand history expressions
shopt -s nocasematch # case-insensitive regular expressions
###
### main
###
_list_loaded_kext_ids () {
/usr/sbin/kextstat -kl | \
/usr/bin/cut -c53- | \
/usr/bin/cut -f1 -d' ' | \
/usr/bin/egrep -v '^com\.apple\.'
}
# process args
if [[ $1 =~ ^-+h(elp)?$ ]]; then
printf "list_loaded_kext_ids
Print Bundle IDs for currently loaded Kernel Extensions (kexts)
which may be useful in a Cask uninstall stanza, eg
uninstall kext: 'kext.bundle.id.goes.here'
Kexts attributed to Apple are excluded from the output.
See CONTRIBUTING.md for more information.
"
exit
fi
# dispatch main
_list_loaded_kext_ids "${@}"
#

View File

@ -0,0 +1,84 @@
#!/bin/bash
#
# list_loaded_launchjob_ids
#
###
### settings
###
set -e # exit on any uncaught error
set +o histexpand # don't expand history expressions
shopt -s nocasematch # case-insensitive regular expressions
###
### global variables
###
###
### functions
###
launchjob_id_source_1 () {
if [[ "$EUID" -ne 0 ]]; then
/usr/bin/sudo -p 'Optionally give your sudo password: ' -- /bin/launchctl list | /usr/bin/cut -f3
fi
}
launchjob_id_source_2 () {
/bin/launchctl list | /usr/bin/cut -f3
}
merge_sources () {
/usr/bin/sort | /usr/bin/uniq
}
clean_sources () {
/usr/bin/egrep -v '^Label$' | \
/usr/bin/egrep -v '^com\.apple\.' | \
/usr/bin/egrep -v '^0x[0-9a-f]+\.anonymous\.' | \
/usr/bin/egrep -v '^\[0x' | \
/usr/bin/egrep -v '\.[0-9]+$'
}
###
### main
###
_list_loaded_launchjob_ids () {
{
launchjob_id_source_1;
launchjob_id_source_2;
} | \
clean_sources | \
merge_sources
}
# process args
if [[ $1 =~ ^-+h(elp)?$ ]]; then
printf "list_loaded_launchjob_ids
List IDs for currently-loaded launchctl jobs, which may be useful
in a Cask uninstall stanza, eg
uninstall launchctl: 'job.id.goes.here'
If this command is not run as the superuser, you will be prompted
for a password to run a subcommand using 'sudo'. The password is
not required, but supplying it may reveal additional job ids. To
skip using the password, press <return> repeatedly.
Launchctl jobs attributed to Apple are excluded from the output.
See CONTRIBUTING.md and 'man launchctl' for more information.
"
exit
fi
# dispatch main
_list_loaded_launchjob_ids "${@}"
#

View File

@ -0,0 +1,64 @@
#!/usr/bin/env ruby
#
# list_login_items_for_app
#
###
### dependencies
###
require "open3"
###
### methods
###
def usage
<<-EOS
Usage: list_login_items_for_app <path.app>
Given an Application (app) bundle directory on disk, find all
login items associated with that app, which you can use in a
Cask uninstall stanza, eg
uninstall login_item: 'login item name'
Note that you will likely need to have opened the app at least
once for any login items to be present.
See CONTRIBUTING.md for more information.
EOS
end
def process_args
if ARGV.first =~ %r{^-+h(?:elp)?$}
puts usage
exit 0
elsif ARGV.length == 1
$app_path = ARGV.first
else
puts usage
exit 1
end
end
def list_login_items_for_app(app_path)
out, err, status = Open3.capture3(
"/usr/bin/osascript", "-e",
"tell application \"System Events\" to get the name of every login item " \
"whose path contains \"#{File.basename(app_path)}\""
)
if status.exitstatus > 0
$stderr.puts err
exit status.exitstatus
end
puts out.gsub(", ", "\n")
end
###
### main
###
process_args
list_login_items_for_app $app_path

View File

@ -0,0 +1,126 @@
#!/bin/bash
#
# list_payload_in_pkg
#
###
### settings
###
set -e # exit on any uncaught error
set +o histexpand # don't expand history expressions
shopt -s nocasematch # case-insensitive regular expressions
###
### global variables
###
pkg_arg=''
tmp_boms=''
# prefer GNU xargs
xargs="$(/usr/bin/which gxargs || printf '/usr/bin/xargs')"
trap cleanup_tmp_boms EXIT
###
### functions
###
cleanup_tmp_boms () {
if [[ -n "$tmp_boms" ]]; then
# tmpfile ensures that rmdir -p is not too destructive
local tmpfile="/tmp/list_payload_in_pkg.$$";
/usr/bin/touch "$tmpfile";
echo "$tmp_boms" | \
/usr/bin/perl -pe 's{\n}{\000}sg' | \
"$xargs" -0 /bin/rm -f --;
{
echo "$tmp_boms" | \
/usr/bin/perl -pe 's{[^/]+\n}{\000}sg' | \
"$xargs" -0 /bin/rmdir -p -- || true
} 2>/dev/null
/bin/rm -- "$tmpfile";
fi
}
bom_source_1 () {
/usr/bin/find "$pkg_arg" -iname '*.pkg' -print0 | \
"$xargs" -0 -I{} -n1 /usr/sbin/pkgutil --bom "{}" 2>/dev/null
}
bom_source_2 () {
/usr/bin/find "$pkg_arg" -name '*.bom'
}
expand_sources () {
/usr/bin/perl -pe 's{\n}{\000}sg' | \
"$xargs" -0 lsbom --
}
merge_sources () {
/usr/bin/sort | /usr/bin/uniq
}
clean_sources () {
/usr/bin/cut -f1 | \
/usr/bin/perl -pe 's{\A\.}{}' | \
/usr/bin/egrep '.'
}
mark_up_sources () {
/usr/bin/perl -pe 's{\n}{\000}sg' | \
"$xargs" -0 -I{} -n1 /bin/bash -c \
'printf "{}"; /bin/test -e "{}" >/dev/null 2>&1 && printf " (+)"; printf "\n"'
}
###
### main
###
_list_payload_in_pkg () {
pkg_arg="$1"
if [[ -h "$pkg_arg" ]]; then
pkg_arg="$(/usr/bin/readlink "$pkg_arg")"
fi
tmp_boms="$(bom_source_1)";
{
# find BOM files
echo "$tmp_boms";
bom_source_2;
} | \
expand_sources | \
clean_sources | \
merge_sources | \
mark_up_sources
}
# process args
if [[ $1 =~ ^-+h(elp)?$ || -z "$1" ]]; then
printf "list_payload_in_pkg <file.pkg>
Given a package file, show what files may be installed by that
pkg, which may be useful when writing a Cask uninstall stanza.
The given package file need not be installed.
The output attempts to be overly inclusive. However, since
pkg files are allowed to run arbitrary scripts, there can be
no guarantee that the output is exact.
If a given file is already installed, it will be followed by
a plus symbol '(+)' in the output.
See CONTRIBUTING.md and 'man pkgutil' for more information.
"
exit
fi
# dispatch main
_list_payload_in_pkg "${@}"
#

View File

@ -0,0 +1,83 @@
#!/bin/bash
#
# list_pkg_ids_by_regexp
#
###
### settings
###
set -e # exit on any uncaught error
set +o histexpand # don't expand history expressions
shopt -s nocasematch # case-insensitive regular expressions
###
### functions
###
warn () {
local message="$@"
message="${message//\\t/$'\011'}"
message="${message//\\n/$'\012'}"
message="${message%"${message##*[![:space:]]}"}"
printf "%s\n" "$message" 1>&2
}
die () {
warn "$@"
exit 1
}
fail_informatively () {
local message="No match."
if ! [[ "$1" =~ '*' ]]; then
message="$message Suggestion: try '${1}.*'"
fi
die "$message"
}
analyze_regexp () {
if [[ "$1" =~ ^\^ ]]; then
warn "Note: pkgutil regular expressions are implicitly anchored with '^' at start"
fi
if [[ "$1" =~ \$$ ]]; then
warn "Note: pkgutil regular expressions are implicitly anchored with '$' at end"
fi
}
###
### main
###
_list_pkg_ids_by_regexp () {
analyze_regexp "$1"
if ! /usr/sbin/pkgutil --pkgs="$1"; then
fail_informatively "$1"
fi
}
# process args
if [[ $1 =~ ^-+h(elp)?$ || $# -ne 1 ]]; then
printf "list_pkg_ids_by_regexp <regexp>
Print pkg receipt IDs for installed packages matching a regular
expression, which may be useful in a Cask uninstall stanza, eg
uninstall pkgutil: 'pkg.regexp.goes.here'
Unlike most other scripts in this directory, package IDs attributed to
Apple are NOT excluded from the output. This is to avoid uninstalling
essential system files due to an exuberant regexp.
For more information, see
https://github.com/caskroom/homebrew-cask/blob/master/doc/cask_language_reference/stanzas/uninstall.md
"
exit
fi
# dispatch main
_list_pkg_ids_by_regexp "${@}"
#

View File

@ -0,0 +1,46 @@
#!/bin/bash
#
# list_recent_pkg_ids
#
###
### settings
###
set -e # exit on any uncaught error
set +o histexpand # don't expand history expressions
shopt -s nocasematch # case-insensitive regular expressions
###
### main
###
_list_recent_pkg_ids () {
/bin/ls -t /var/db/receipts | \
/usr/bin/egrep '\.plist$' | \
/usr/bin/perl -pe 's{\A([^/]+)\.plist\Z}{$1}sg' | \
/usr/bin/egrep -v '^com\.apple\.' | \
/usr/bin/head -10
}
# process args
if [[ $1 =~ ^-+h(elp)?$ ]]; then
printf "list_recent_pkg_ids
Print pkg receipt IDs for the 10 most-recently-installed packages,
which may be useful in a Cask uninstall stanza, eg
uninstall pkgutil: 'pkg.receipt.id.goes.here'
Package IDs attributed to Apple are excluded from the output.
See CONTRIBUTING.md for more information.
"
exit
fi
# dispatch main
_list_recent_pkg_ids "${@}"
#

View File

@ -0,0 +1,115 @@
#!/usr/bin/env ruby
#
# list_running_app_ids
#
###
### dependencies
###
require "open3"
require "set"
###
### globals
###
$opt_test = nil
###
### methods
###
def check_ruby
if RUBY_VERSION.to_f < 2.0
print "You are currently using Ruby ", RUBY_VERSION, ", but version 2.0 or above is required."
exit 1
end
end
def usage
<<-EOS
list_running_app_ids [ -t <bundle-id> ]
Print a list of currently running Applications and associated
Bundle IDs, which may be useful in a Cask uninstall stanza, eg
uninstall quit: 'bundle.id.goes.here'
Applications attributed to Apple are excluded from the output.
With optional "-t <bundle-id>", silently test if a given app
is running, exiting with an error code if not.
See CONTRIBUTING.md for more information.
EOS
end
def process_args
until ARGV.empty?
if ARGV.first =~ %r{^-+t(?:est)?$} && ARGV.length > 1
ARGV.shift
$opt_test = ARGV.shift
elsif ARGV.first =~ %r{^-+h(?:elp)?$}
puts usage
exit 0
else
puts usage
exit 1
end
end
end
def load_apps
out, err, status = Open3.capture3("/usr/bin/osascript", "-e", 'tell application "System Events" to get (name, bundle identifier, unix id) of every process')
if status.exitstatus > 0
puts err
exit status.exitstatus
end
out = out.split(", ")
one_third = out.length / 3
@app_names = out.shift(one_third)
@bundle_ids = out.shift(one_third)
@unix_ids = out.shift(one_third)
end
def test_app(bundle)
@bundle_ids.include?(bundle) ? 0 : 1
end
def excluded_bundle_id(bundle_id)
%r{^com\.apple\.}.match(bundle_id)
end
def excluded_app_name(app_name)
%r{^osascript$}.match(app_name) # this script itself
end
def report_apps
running = Set.new
@app_names.zip(@bundle_ids, @unix_ids).each do |app_name, bundle_id, _unix_id|
next if excluded_bundle_id bundle_id
next if excluded_app_name app_name
bundle_id.gsub!(%r{^(missing value)$}, '<\1>')
running.add "#{bundle_id}\t#{app_name}"
end
puts "bundle_id\tapp_name\n"
puts "--------------------------------------\n"
puts running.to_a.sort
end
###
### main
###
check_ruby
process_args
load_apps
if $opt_test
exit test_app($opt_test)
else
report_apps
end

View File

@ -0,0 +1,84 @@
#!/bin/bash
#
# list_url_attributes_on_file
#
###
### settings
###
set -e # exit on any uncaught error
set +o histexpand # don't expand history expressions
shopt -s nocasematch # case-insensitive regular expressions
###
### global variables
###
file_arg=''
attribute_1='com.apple.metadata:kMDItemWhereFroms'
###
### functions
###
warn () {
local message="$@"
message="${message//\\t/$'\011'}"
message="${message//\\n/$'\012'}"
message="${message%"${message##*[![:space:]]}"}"
printf "%s\n" "$message" 1>&2
}
die () {
warn "$@"
exit 1
}
xml_source_1 () {
if /usr/bin/xattr -p "$attribute_1" "$file_arg" > /dev/null 2>&1; then
/usr/bin/xattr -p "$attribute_1" "$file_arg" | /usr/bin/xxd -r -p | /usr/bin/plutil -convert xml1 -o - - 2> /dev/null
fi
}
extract_string_elements () {
/usr/bin/perl -ne 'print "$1\n" if m{\A\s*<\s*string\s*>(.+?)<\s*/\s*string\s*>\Z}'
}
###
### main
###
_list_url_attributes_on_file () {
file_arg="$1"
{
xml_source_1;
} | \
extract_string_elements
}
# process_args
if [[ $1 =~ ^-+h(elp)?$ || -z "$1" ]]; then
printf "list_url_attributes_on_file <file>
Given a downloaded file, extract possible sources from macOS extended
attributes, which may be useful in a Cask url stanza.
Currently the only attribute examined is
com.apple.metadata:kMDItemWhereFroms
This attribute will typically be set if the file was downloaded via a
browser, but not if the file was downloaded by a CLI utility such as
curl.
See CONTRIBUTING.md for more information.
"
exit
fi
# dispatch main
_list_url_attributes_on_file "${@}"
#

View File

@ -0,0 +1,99 @@
#!/bin/bash
IFS=$'\n'
readonly caskroom_online='https://github.com/caskroom'
readonly caskroom_repos_dir='/tmp/caskroom_repos'
readonly caskroom_repos=(homebrew-cask homebrew-versions homebrew-fonts homebrew-eid)
if [[ ! $(which 'ghi') ]] || ! security find-internet-password -s github.com -l 'ghi token' &> /dev/null; then
echo -e "$(tput setaf 1)
This script requires 'ghi' installed and configured.
If you have [Homebrew](http://brew.sh), you can install it with 'brew install ghi'.
To configure it, run 'ghi config --auth <username>'. Your Github password will be required, but is never stored.
$(tput sgr0)" | sed -E 's/ {4}//' >&2
exit 1
fi
if [[ ! $(which 'fastmerge') ]]; then
echo -e "$(tput setaf 1)
This script requires 'fastmerge'.
If you have [Homebrew](http://brew.sh), you can install it with 'brew install vitorgalvao/tiny-scripts/fastmerge'.
$(tput sgr0)" | sed -E 's/ {4}//' >&2
exit 1
fi
function message {
echo "${1}"
}
function go_to_repos_dir {
[[ ! -d "${caskroom_repos_dir}" ]] && mkdir -p "${caskroom_repos_dir}"
cd "${caskroom_repos_dir}" || exit 1
}
function go_to_repo_and_update {
local repo_name repo_dir casks_dir
repo_name="${1}"
repo_dir="${caskroom_repos_dir}/${repo_name}"
casks_dir="${repo_dir}/Casks"
if [[ ! -d "${repo_dir}" ]]; then
go_to_repos_dir
message "Cloning ${repo_name}…"
git clone "https://github.com/caskroom/${repo_name}.git" --quiet
cd "${casks_dir}" || exit 1
else
cd "${casks_dir}" || exit 1
message "Updating ${repo_name}…"
git pull --rebase origin master --quiet
fi
}
function delete_current_branch {
local current_branch
current_branch="$(git rev-parse --abbrev-ref HEAD)"
git checkout master --quiet
git branch -D "${current_branch}" --quiet
}
function delete_cask_repair_branches {
[[ $(ghi list --state open --pulls --label 'outdated appcast' | tail -1) == 'None.' ]] && cask-repair --push origin --delete-branches
}
function merge_outdated_appcasts {
local repo_name pr_number cask_name pr_url last_commit
repo_name="${1}"
for line in $(ghi list --state open --pulls --label 'outdated appcast' --reverse | tail +2); do
[[ "${line}" == 'None.' ]] && break # exit early if there are no relevant issues in repo
pr_number="$(awk '{print $1}' <<< "${line}")"
cask_name="$(awk '{print $3}' <<< "${line}")"
pr_url="${caskroom_online}/${repo_name}/pull/${pr_number}"
hub checkout "${pr_url}" &>/dev/null
last_commit="$(git log -n 1 --pretty=format:'%H')"
delete_current_branch
if [[ "$(hub ci-status "${last_commit}")" == 'success' ]]; then
message "Merging pull request for ${cask_name}…"
fastmerge --maintainer --remote origin "${pr_url}"
else
continue
fi
done
}
for repo in "${caskroom_repos[@]}"; do
go_to_repo_and_update "${repo}"
merge_outdated_appcasts "${repo}"
delete_cask_repair_branches
git gc
done

View File

@ -0,0 +1 @@
develop_brew_cask

View File

@ -0,0 +1,234 @@
#!/bin/bash
#
# project_stats
#
# stats on project/release from git database
#
###
### settings
###
set -e # exit on any uncaught error
set +o histexpand # don't expand history expressions
shopt -s nocasematch # case-insensitive regular expressions
###
### configurable global variables
###
# these paths relative to project root
declare -a cask_paths=(Casks)
declare -a code_paths=(bin developer lib spec test brew-cask.rb Rakefile Gemfile Gemfile.lock .travis.yml .gitignore)
declare -a doc_paths=(doc LICENSE "*.md")
end_object="HEAD"
###
### global variables
###
cask_authors=''
# prefer GNU xargs
xargs="$(/usr/bin/which gxargs || printf '/usr/bin/xargs')"
###
### functions
###
warn () {
local message="$@"
message="${message//\\t/$'\011'}"
message="${message//\\n/$'\012'}"
message="${message%"${message##*[![:space:]]}"}"
printf "%s\n" "$message" 1>&2
}
die () {
warn "$@"
exit 1
}
cd_to_project_root () {
local script_dir="$(/usr/bin/dirname "$0")"
cd "$script_dir"
local git_root="$(git rev-parse --show-toplevel)"
if [[ -z "$git_root" ]]; then
die "ERROR: Could not find git project root"
fi
cd "$git_root"
}
warn_if_off_branch () {
local wanted_branch='master'
if [[ -n "$1" ]]; then
wanted_branch="$1"
fi
local current_branch="$(git rev-parse --abbrev-ref HEAD)"
if ! [[ "$current_branch" = "$wanted_branch" ]]; then
warn "\nWARNING: you are running from branch '$current_branch', not '$wanted_branch'\n\n"
fi
}
verify_git_object () {
local object="$1"
if ! git rev-parse --verify "$object" -- >/dev/null 2>&1; then
die "\nERROR: No such commit object: '$object'\n\n"
fi
}
print_contributor_stats () {
local start_object="$1"
local initial_commit="$2"
printf "====================\n"
printf "Contributors\n"
printf "====================\n"
local -a git_log_cmd=("git" "log" "--no-merges" "--format='%ae'" "${start_object}..${end_object}")
printf "Unique contributors"
if ! [[ "$start_object" = "$initial_commit" ]]; then
printf " since %s" "${start_object#v}"
fi
printf "\n"
cask_authors="$("${git_log_cmd[@]}" -- "${cask_paths[@]}" | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l)"
printf " Casks\t%s\n" "$cask_authors"
printf " code\t"
"${git_log_cmd[@]}" -- "${code_paths[@]}" | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l
printf " docs\t"
"${git_log_cmd[@]}" -- "${doc_paths[@]}" | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l
printf " any\t"
"${git_log_cmd[@]}" -- . | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l
if ! [[ "$start_object" = "$initial_commit" ]]; then
local alltime_contribs="$(git log --no-merges --format='%ae' "${initial_commit}".."${end_object}" -- . | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l)"
local prior_contribs="$(git log --no-merges --format='%ae' "${initial_commit}".."${start_object}" -- . | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l)"
# arithmetic removes whitespace
((alltime_contribs += 0))
((new_contribs = alltime_contribs - prior_contribs))
printf "\nAll-time contributors\t%s\n" "$alltime_contribs"
printf "New contributors since %s\t%s\n" "${start_object#v}" "$new_contribs"
fi
printf "\n"
}
print_commit_stats () {
local start_object="$1"
local initial_commit="$2"
printf "====================\n"
printf "Commits\n"
printf "====================\n"
local -a git_log_cmd=("git" "log" "--no-merges" "--format='%ae'" "${start_object}..${end_object}")
printf "Commit count"
if ! [[ "$start_object" = "$initial_commit" ]]; then
printf " since %s" "${start_object#v}"
fi
printf "\n"
printf " Casks\t"
"${git_log_cmd[@]}" -- "${cask_paths[@]}" | /usr/bin/wc -l
printf " code\t"
"${git_log_cmd[@]}" -- "${code_paths[@]}" | /usr/bin/wc -l
printf " docs\t"
"${git_log_cmd[@]}" -- "${doc_paths[@]}" | /usr/bin/wc -l
printf " any\t"
"${git_log_cmd[@]}" -- . | /usr/bin/wc -l
if ! [[ "$start_object" = "$initial_commit" ]]; then
printf "\nAll-time commits\t"
git log --no-merges --format='%ae' "${initial_commit}".."${end_object}" -- . | /usr/bin/wc -l
fi
printf "\n"
}
print_doc_stats () {
local start_object="$1"
local initial_commit="$2"
printf "====================\n"
printf "Docs\n"
printf "====================\n"
local -a git_log_cmd=("git" "log" "--no-merges" "--format='%ae'" "${start_object}..${end_object}")
printf "Doc contributors"
if ! [[ "$start_object" = "$initial_commit" ]]; then
printf " since %s" "${start_object#v}"
fi
printf "\n "
"${git_log_cmd[@]}" -- "${doc_paths[@]}" | /usr/bin/sort | /usr/bin/uniq | \
/usr/bin/egrep -v $'^\'(paul\\.t\\.hinze@gmail\\.com|fanquake@users\\.noreply\\.github\\.com|fanquake@gmail\\.com|info@vitorgalvao\\.com|calebcenter@live\\.com|hagins\\.josh@gmail\\.com|dragon\\.vctr@gmail\\.com|github@adityadalal\\.com|adityadalal924@users\\.noreply\\.github\\.com)\'$' | \
"$xargs" | /usr/bin/perl -pe 's{ }{, }g' # '
printf "\n"
}
print_cask_stats () {
local start_object="$1"
local initial_commit="$2"
printf "====================\n"
printf "Casks\n"
printf "====================\n"
if ! [[ "$start_object" = "$initial_commit" ]]; then
local new_casks="$(git diff --name-status "$start_object" "$end_object" -- "${cask_paths[@]}" | /usr/bin/grep '^A.*\.rb' | cut -f2 | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l)"
local deleted_casks="$(git diff --name-status "$start_object" "$end_object" -- "${cask_paths[@]}" | /usr/bin/grep '^D.*\.rb' | cut -f2 | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l)"
local updated_casks="$(git diff --name-status "$start_object" "$end_object" -- "${cask_paths[@]}" | /usr/bin/grep '^M.*\.rb' | cut -f2 | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l)"
# arithmetic removes whitespace
((cask_authors += 0))
((deleted_casks += 0))
((new_casks -= deleted_casks))
((updated_casks += 0))
printf "%s Casks added (%s updated) by %s contributors since %s\n" "$new_casks" "$updated_casks" "$cask_authors" "${start_object#v}"
fi
printf "Total current Casks in HEAD\t"
/usr/bin/find "${cask_paths[@]}" -name '*.rb' | /usr/bin/wc -l
printf "\n"
}
###
### main
###
_project_stats () {
local arg_object="$1"
cd_to_project_root
warn_if_off_branch 'master'
local initial_commit="$(git log --pretty=format:%H -- | /usr/bin/tail -1)"
verify_git_object "$initial_commit"
local start_object="$initial_commit"
if [[ "$arg_object" = 'release' ]]; then
start_object="$(./developer/bin/get_release_tag)"
elif [[ -n "$arg_object" ]]; then
start_object="$arg_object"
fi
verify_git_object "$start_object"
print_contributor_stats "$start_object" "$initial_commit"
print_commit_stats "$start_object" "$initial_commit"
print_doc_stats "$start_object" "$initial_commit"
print_cask_stats "$start_object" "$initial_commit"
}
# process args
if [[ $1 =~ ^-+h(elp)?$ ]]; then
printf "project_stats [ <commit-object> ]
With optional single argument, (eg a tag or commit-hash)
show statistics since that commit object.
Use the special argument 'release' to calculate since the
most recent tag (usually the same as the last release).
Without argument, show statistics since first commit.
"
exit
fi
# dispatch main
_project_stats "${@}"

View File

@ -0,0 +1,252 @@
#!/usr/bin/env ruby
#
# the_long_tail
#
# A histogram view on contributor stats
#
# notes
#
# Since this script does not track file-renames in the git history, the
# dependence of Casks upon occasional contributors/non-maintainers can
# only be expressed as a range or lower bound.
#
###
### dependencies
###
require "open3"
require "set"
###
### configurable constants
###
BINS = [
(1..10).to_a,
100,
1000,
].flatten
OCCASIONAL_CUTOFF = 5
CASK_PATH = "Casks".freeze
# all maintainers, past and present
MAINTAINERS = %w[
paul.t.hinze@gmail.com
fanquake@users.noreply.github.com
fanquake@gmail.com
kevin@suttle.io
leoj3n@gmail.com
nano@fdp.io
nanoid.xd@gmail.com
me@passcod.name
walker@pobox.com
info@vitorgalvao.com
calebcenter@live.com
ndr@qef.io
josh@joshbutts.com
goxberry@gmail.com
radek.simko@gmail.com
federicobond@gmail.com
claui@users.noreply.github.com
amorymeltzer@gmail.com
hagins.josh@gmail.com
dragon.vctr@gmail.com
mail@sebastianroeder.de
github@adityadalal.com
adityadalal924@users.noreply.github.com
].freeze
###
### git methods
###
def cd_to_project_root
Dir.chdir File.dirname(File.expand_path(__FILE__))
@git_root ||= Open3.popen3(*%w[
git rev-parse --show-toplevel
]) do |_stdin, stdout, _stderr|
begin
stdout.gets.chomp
rescue
end
end
Dir.chdir @git_root
@git_root
end
def authors
@authors ||= Open3.popen3(*%w[
git log --no-merges --format=%ae --
]) do |_stdin, stdout, _stderr|
h = {}
stdout.each_line do |line|
line.chomp!
h[line] ||= 0
h[line] += 1
end
h
end
end
def casks_by_author
@casks_by_author ||= Open3.popen3(*%w[
git log --no-merges --name-only --format=%ae --
],
CASK_PATH) do |_stdin, stdout, _stderr|
email = nil
h = {}
stdout.each_line.to_a.join("").split("\n\n").each do |paragraph|
if paragraph.include?("Casks/")
lines = paragraph.split("\n")
email = lines.pop
h[email] ||= Set.new
h[email].merge(lines.compact)
else
email = paragraph.chomp
end
end
h
end
end
###
### filesystem methods
###
def all_casks
@all_casks ||= Open3.popen2("/usr/bin/find",
CASK_PATH,
*%w[-type f -name *.rb]) do |_stdin, stdout|
stdout.each_line.map(&:chomp)
end
end
###
### analysis and report methods
###
def histogram
if @histogram.nil?
@histogram = Hash[*BINS.map { |elt| [elt, 0] }.flatten]
authors.each do |_name, num_commits|
bottom = 0
BINS.each do |top|
@histogram[bottom] += 1 if num_commits >= bottom && num_commits < top
bottom = top
end
end
end
@histogram
end
def historic_occasional_cask_set
@historic_occasional_cask_set = authors.each.collect do |name, num_commits|
if num_commits > OCCASIONAL_CUTOFF
nil
elsif !casks_by_author.key?(name)
nil
else
casks_by_author[name].to_a
end
end.flatten.compact.to_set
end
def extant_occasional_cask_count
# avoid double-counting renames by intersecting with extant Casks
historic_occasional_cask_set.intersection(all_casks).count
end
def historic_nonmaintainer_cask_set
@historic_nonmaintainer_cask_set = authors.each.collect do |name, _num_commits|
if MAINTAINERS.include?(name)
nil
else
casks_by_author[name].to_a
end
end.flatten.compact.to_set
end
def extant_nonmaintainer_cask_count
# avoid double-counting renames by intersecting with extant Casks
historic_nonmaintainer_cask_set.intersection(all_casks).count
end
def extant_occasional_cask_percentage
@extant_occasional_cask_percentage ||= (100 * extant_occasional_cask_count / all_casks.count).to_i
end
def historic_occasional_cask_percentage
@historic_occasional_cask_percentage ||= (100 * historic_occasional_cask_set.count / all_casks.count).to_i
end
def extant_nonmaintainer_cask_percentage
@extant_nonmaintainer_cask_percentage ||= (100 * extant_nonmaintainer_cask_count / all_casks.count).to_i
end
def historic_nonmaintainer_cask_percentage
# this is so large, it might cross 100%
@historic_nonmaintainer_cask_percentage ||= [100, (100 * historic_nonmaintainer_cask_set.count / all_casks.count).to_i].min
end
def onetime_author_percentage
@onetime_author_percentage ||= (100 *
histogram[1] /
authors.length).to_i
end
def occasional_author_percentage
# why is it so hard to slice a hash?
@occasional_author_percentage ||= (100 *
(1..OCCASIONAL_CUTOFF).to_a.collect { |bin| histogram[bin] }.reduce(:+) /
authors.length).to_i
end
def graph_width
if @graph_width.nil?
@graph_width = `/bin/stty size 2>/dev/null`.chomp.split(" ").last.to_i
@graph_width = 80 if @graph_width <= 0
@graph_width -= 20 if @graph_width > 20
end
@graph_width
end
def graph_normalization
@graph_normalization ||= histogram.values.max.to_f
end
def print_header
puts "Commits\tContributors"
puts "---------------------"
end
def print_table
BINS.each do |bin|
plural = (bin % 10) == 0 ? "'s" : ""
graph = "." * ((histogram[bin] / graph_normalization) * graph_width)
puts "#{bin}#{plural}\t#{histogram[bin]}\t#{graph}"
end
end
def print_footer
puts %Q{\n#{occasional_author_percentage}% of contributors are "occasional" (with <= #{OCCASIONAL_CUTOFF} commits)}
puts "\n#{onetime_author_percentage}% of contributors commit only once"
puts "\n#{extant_occasional_cask_percentage}% - #{historic_occasional_cask_percentage}% of Casks depend on an occasional contributor"
puts "\n#{extant_nonmaintainer_cask_percentage}% - #{historic_nonmaintainer_cask_percentage}% of Casks depend on a contributor who is not a maintainer"
puts "\n"
end
def generate_report
print_header
print_table
print_footer
end
###
### main
###
cd_to_project_root
generate_report

View File

@ -0,0 +1,106 @@
#!/usr/bin/env bash
#
# update_issue_template_urls
#
###
### settings
###
set -e # exit on uncaught error
set +o histexpand # don't expand history expressions
shopt -s nocasematch # case-insensitive regular expressions
###
### constants
###
script_subdir='developer/bin'
template_subdir='doc/issue_templates'
generate_url_script='generate_issue_template_urls'
files_to_update=('README.md')
###
### functions
###
warn () {
local message="$*"
message="${message//\\t/$'\011'}"
message="${message//\\n/$'\012'}"
message="${message%${message##*[![:space:]]}}"
printf "%s\n" "$message" 1>&2
}
die () {
warn "$@"
exit 1
}
usage () {
printf "update_issue_template_urls
Regenerate issue template URLs and update them in relevant files.
Note: docs using issue template URLs must use a specific format.
If the template file is called 'bug_report.md', the URL must be
referenced in the doc as follows:
[Some link text][bug_report_template]
...
[bug_report_template]: (auto-generated-url)
"
}
cd_to_project_root () {
local script_dir git_root
script_dir="$(/usr/bin/dirname "$0")"
cd "$script_dir"
git_root="$(git rev-parse --show-toplevel)"
if [[ -z "$git_root" ]]; then
die "ERROR: Could not find git project root"
fi
cd "$git_root"
}
generate_template_url () {
local template_file="$1"
"$script_subdir/$generate_url_script" "$template_file"
}
update_template_url () {
local template_name="$1"
local template_url="$2"
local escaped_template_url="${template_url/&/\\&}"
/usr/bin/sed -i '' \
-e "s|^\\(\\[${template_name}_template\\]: \\).*$|\\1${escaped_template_url}|g" \
-- "${files_to_update[@]}"
}
###
### main
###
_update_issue_template_urls () {
local template_file template_name template_url
cd_to_project_root
for template_file in ./$template_subdir/*; do
template_name="${template_file##*/}"
template_name="${template_name%%.*}"
template_url="$(generate_template_url "$template_file")"
update_template_url "$template_name" "$template_url"
done
}
# process args
if [[ $1 =~ ^-+h(elp)?$ ]]; then
usage
exit
fi
# dispatch main
_update_issue_template_urls

View File

@ -0,0 +1,43 @@
#!/usr/bin/env ruby
#
# Generously contributed by Markus Doits
# https://github.com/doits
# (c) 2014 MIT license
#
require "rubygems"
class Hbc
def installed_version?
!installed_version.nil?
end
def installed_version
# returns latest installed version if possible
Pathname.glob(caskroom_path.join("*")).map(&:basename).sort do |x, y|
Gem::Version.new(x) <=> Gem::Version.new(y) # throws exception if invalid version is provided ...
end.last
rescue
nil
# ... return nil in this case
end
def update_available?
Gem::Version.correct?(version) && # we have something to compare against in Cask file ...
installed_version? && # ... we can determine current installed version ...
Gem::Version.new(installed_version) < Gem::Version.new(version) # ... compare
end
end
module Hbc::Scopes
module ClassMethods
def upgradable
Hbc.installed.select(&:update_available?)
end
end
end
upgradable_casks = Hbc.upgradable
puts upgradable_casks.empty? && "No outdated packages" || upgradable_casks

View File

@ -0,0 +1,16 @@
# brewcask-dumpcask
#
# A trivial `brew cask` external command, implemented in Ruby.
# Loads a Cask definition, then dumps it in YAML format.
# Example usage:
#
# brew cask dumpcask google-chrome
#
command_name = ARGV.shift
cask_token = ARGV.shift
cask = Hbc.load(cask_token)
Hbc.debug = true
cask.dumpcask

View File

@ -0,0 +1,16 @@
#!/bin/bash
#
# brewcask-showargs
#
# A trivial `brew cask` external command, implemented in bash.
# Displays the arguments passed to it. Example usage:
#
# brew cask showargs these were my args
#
set -e; # exit on uncaught error
set +o histexpand; # don't expand history expressions
echo "$@";
#

View File

@ -0,0 +1,59 @@
# All stanzas
## Required Stanzas
Each of the following stanzas is required for every Cask.
| name | multiple occurrences allowed? | value |
| ------------------ |------------------------------ | ----------- |
| `version` | no | application version; give value of `:latest` if versioned downloads are not offered
| `sha256` | no | SHA-256 checksum of the file downloaded from `url`, calculated by the command `shasum -a 256 <file>`. Can be suppressed by using the special value `:no_check` (see also [Checksum Stanza Details](stanzas/sha256.md))
| `url` | no | URL to the `.dmg`/`.zip`/`.tgz`/`.tbz2` file that contains the application.<br />A [comment](stanzas/url.md#when-url-and-homepage-hostnames-differ-add-a-comment) should be added if the hostnames in the `url` and `homepage` stanzas differ. Block syntax should be used for URLs that change on every visit.<br />See [URL Stanza Details](stanzas/url.md) for more information.
| `name` | yes | a string providing the full and proper name defined by the vendor (see also [Name Stanza Details](stanzas/name.md))
| `homepage` | no | application homepage; used for the `brew cask home` command
| `license` | no | a symbol identifying the license category for the application (see also [License Stanza Details](stanzas/license.md))
## At Least One Artifact Stanza Is Also Required
Each Cask must declare one or more *artifacts* (i.e. something to install).
| name | multiple occurrences allowed? | value |
| ------------------ |------------------------------ | ----------- |
| `app` | yes | relative path to an `.app` that should be moved into the `/Applications` folder on installation (see also [App Stanza Details](stanzas/app.md))
| `pkg` | yes | relative path to a `.pkg` file containing the distribution (see also [Pkg Stanza Details](stanzas/pkg.md))
| `binary` | yes | relative path to a Binary that should be linked into the `/usr/local/bin` folder on installation
| `colorpicker` | yes | relative path to a ColorPicker plugin that should be linked into the `~/Library/ColorPickers` folder on installation
| `font` | yes | relative path to a Font that should be linked into the `~/Library/Fonts` folder on installation
| `input_method` | yes | relative path to a Input Method that should be linked into the `~/Library/Input Methods` folder on installation
| `internet_plugin` | yes | relative path to a Service that should be linked into the `~/Library/Internet Plug-Ins` folder on installation
| `prefpane` | yes | relative path to a Preference Pane that should be linked into the `~/Library/PreferencePanes` folder on installation
| `qlplugin` | yes | relative path to a QuickLook Plugin that should be linked into the `~/Library/QuickLook` folder on installation
| `screen_saver` | yes | relative path to a Screen Saver that should be linked into the `~/Library/Screen Savers` folder on installation
| `service` | yes | relative path to a Service that should be linked into the `~/Library/Services` folder on installation
| `audio_unit_plugin`| yes | relative path to an Audio Unit plugin that should be linked into the `~/Library/Audio/Components` folder on installation
| `vst_plugin` | yes | relative path to a VST Plugin that should be linked into the `~/Library/Audio/VST` folder on installation
| `vst3_plugin` | yes | relative path to a VST3 Plugin that should be linked into the `~/Library/Audio/VST3` folder on installation
| `suite` | yes | relative path to a containing directory that should be moved into the `/Applications` folder on installation (see also [Suite Stanza Details](stanzas/suite.md))
| `artifact` | yes | relative path to an arbitrary path that should be symlinked on installation. Must provide an absolute path as a `target` (example [alcatraz.rb](https://github.com/caskroom/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/alcatraz.rb#L12)). This is only for unusual cases. The `app` stanza is strongly preferred when linking `.app` bundles.
| `installer` | yes | describes an executable which must be run to complete the installation (see [Installer Stanza Details](stanzas/installer.md))
| `stage_only` | no | `true`. Assert that the Cask contains no activatable artifacts.
## Optional Stanzas
| name | multiple occurrences allowed? | value |
| ---------------------- |------------------------------ | ----------- |
| `uninstall` | yes | procedures to uninstall a Cask. Optional unless the `pkg` stanza is used. (see also [Uninstall Stanza Details](stanzas/uninstall.md))
| `zap` | yes | additional procedures for a more complete uninstall, including user files and shared resources (see also [Zap Stanza Details](stanzas/zap.md))
| `appcast` | no | a URL providing an appcast feed to find updates for this Cask (see also [Appcast Stanza Details](stanzas/appcast.md))
| `depends_on` | yes | a list of dependencies and requirements for this Cask (see also [Depends_on Stanza Details](stanzas/depends_on.md))
| `conflicts_with` | yes | a list of conflicts with this Cask (*not yet functional* see also [Conflicts_with Stanza Details](stanzas/conflicts_with.md))
| `caveats` | yes | a string or Ruby block providing the user with Cask-specific information at install time (see also [Caveats Stanza Details](stanzas/caveats.md))
| `preflight` | yes | a Ruby block containing preflight install operations (needed only in very rare cases)
| `postflight` | yes | a Ruby block containing postflight install operations (see also [Postflight Stanza Details](stanzas/flight.md))
| `uninstall_preflight` | yes | a Ruby block containing preflight uninstall operations (needed only in very rare cases)
| `uninstall_postflight` | yes | a Ruby block containing postflight uninstall operations
| `accessibility_access` | no | `true` if the application should be granted accessibility access
| `container nested:` | no | relative path to an inner container that must be extracted before moving on with the installation; this allows us to support dmg inside tar, zip inside dmg, etc.
| `container type:` | no | a symbol to override container-type autodetect. May be one of: `:air`, `:bz2`, `:cab`, `:dmg`, `:generic_unar`, `:gzip`, `:otf`, `:pkg`, `:rar`, `:seven_zip`, `:sit`, `:tar`, `:ttf`, `:xar`, `:zip`, `:naked`. (example [parse.rb](https://github.com/caskroom/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/parse.rb#L11))
| `gpg` | no | *stub: not yet functional.* (see also [GPG Stanza Details](stanzas/gpg.md))
| `auto_updates` | no | `true`. Assert the Cask artifacts auto-update. (Use if `Check for Updates…` or similar is present in app menu)

View File

@ -0,0 +1,175 @@
# Synopsis
## Casks Are Ruby Blocks
Each Cask is a Ruby block, beginning with a special header line. The Cask definition itself is always enclosed in a `do … end` block. Example:
```ruby
cask 'alfred' do
version '2.7.1_387'
sha256 'a3738d0513d736918a6d71535ef3d85dd184af267c05698e49ac4c6b48f38e17'
url "https://cachefly.alfredapp.com/Alfred_#{version}.zip"
name 'Alfred'
homepage 'https://www.alfredapp.com/'
license :freemium
app 'Alfred 2.app'
app 'Alfred 2.app/Contents/Preferences/Alfred Preferences.app'
postflight do
suppress_move_to_applications key: 'suppressMoveToApplications'
end
end
```
## The Cask Language Is Declarative
Each Cask contains a series of stanzas (or “fields”) which *declare* how the software is to be obtained and installed. In a declarative language, the author does not need to worry about **order**. As long as all the needed fields are present, Homebrew-Cask will figure out what needs to be done at install time.
To make maintenance easier, the most-frequently-updated stanzas are usually placed at the top. But thats a convention, not a rule.
Exception: `do` blocks such as `postflight` may enclose a block of pure Ruby code. Lines within that block follow a procedural (order-dependent) paradigm.
## Conditional Statements
### Efficiency
Conditional statements are permitted, but only if they are very efficient.
Tests on the following values are known to be acceptable:
| value | examples
| ----------------------------|--------------------------------------
| `MacOS.version` | [macports.rb](https://github.com/caskroom/homebrew-cask/blob/9eae0af0daf9b55f81a3af010cca3b0b1272e2db/Casks/macports.rb#L4#L20), [coconutbattery.rb](https://github.com/caskroom/homebrew-cask/blob/2c801af44be29fff7f3cb2996455fce5dd95d1cc/Casks/coconutbattery.rb#L3#L17)
| `Hardware::CPU.is_32_bit?` | [vuescan.rb](https://github.com/caskroom/homebrew-cask/blob/655bfe48b41ae94cb81b1003182b8de5fa2995ef/Casks/vuescan.rb#L5#L9)
| `Hardware::CPU.is_64_bit?` | none, see [Always Fall Through to the Newest Case](#always-fall-through-to-the-newest-case)
### Version Comparisons
Tests against `MacOS.version` may use either symbolic names or version
strings with numeric comparison operators:
```ruby
if MacOS.version <= :mavericks # symbolic name
```
```ruby
if MacOS.version <= '10.9' # version string
```
The available symbols for macOS versions are: `:cheetah`, `:puma`, `:jaguar`, `:panther`, `:tiger`, `:leopard`, `:snow_leopard`, `:lion`, `:mountain_lion`, `:mavericks`, `:yosemite`, `:el_capitan`, and `:sierra`. The corresponding numeric version strings should given as major releases containing a single dot.
### Always Fall Through to the Newest Case
Conditionals should be constructed so that the default is the newest OS version or hardware type. When using an `if` statement, test for older versions, and then let the `else` statement hold the latest and greatest. This makes it more likely that the Cask will work without alteration when a new OS is released. Example (from [coconutbattery.rb](https://github.com/caskroom/homebrew-cask/blob/2c801af44be29fff7f3cb2996455fce5dd95d1cc/Casks/coconutbattery.rb)):
```ruby
if MacOS.version <= :tiger
# ...
elsif MacOS.version <= :snow_leopard
# ...
else
# ...
end
```
## Arbitrary Ruby Methods
In the exceptional case that the Cask DSL is insufficient, it is possible to define arbitrary Ruby variables and methods inside the Cask by creating a `Utils` namespace. Example:
```ruby
cask 'myapp' do
module Utils
def self.arbitrary_method
...
end
end
name 'MyApp'
version '1.0'
sha256 'a32565cdb1673f4071593d4cc9e1c26bc884218b62fef8abc450daa47ba8fa92'
license :unknown
url "https://#{Utils.arbitrary_method}"
homepage 'https://www.example.com/'
...
end
```
This should be used sparingly: any method which is needed by two or more Casks should instead be rolled into the core. Care must also be taken that such methods be very efficient.
Variables and methods should not be defined outside the `Utils` namespace, as they may collide with Homebrew-Cask internals.
## Header Line Details
The first non-comment line in a Cask follows the form:
```ruby
cask '<cask-token>' do
```
[`<cask-token>`](token_reference.md) should match the Cask filename, without the `.rb` extension,
enclosed in single quotes.
The header line is not entirely strict Ruby: no comma is required after the Cask token.
There are currently some arbitrary limitations on Cask tokens which are in the process of being removed. The Travis bot will catch any errors during the transition.
## Stanza order
Having a common order for stanzas makes Casks easier to update and parse. Below is the the complete stanza sequence (no Cask will have all stanzas). The empty lines shown here are also important, as they help to visually delineate information.
```
version
sha256
url
appcast,
checkpoint: # shown here as it is required with `appcast`
name
homepage
license
gpg, key_id: # on same line, since first part is typically small
auto_updates
accessibility_access
conflicts_with
depends_on
container
suite
app
pkg
installer
binary
colorpicker
font
input_method
internet_plugin
prefpane
qlplugin
screen_saver
service
audio_unit_plugin
vst_plugin
vst3_plugin
artifact, target: # :target shown here as is required with `artifact`
stage_only
preflight
postflight
uninstall_preflight
uninstall_postflight
uninstall
zap
caveats
```
Note that every stanza that has additional parameters (`:symbols` after a `,`) shall have them on separate lines, one per line, in alphabetical order. Exceptions are `gpg` and `target:` (when not applied to `url`) which typically consist of short lines.

View File

@ -0,0 +1,43 @@
# app
In the simple case of a string argument to `app`, the source file is moved to the target `~/Applications` directory. For example:
```ruby
app 'Alfred 2.app'
```
moves the source to:
```bash
/Applications/Alfred 2.app
```
from a source file such as:
```bash
/usr/local/Caskroom/alfred/2.8.2_431/Alfred 2.app
```
## Renaming the Target
You can rename the target which appears in your `/Applications` directory by adding a `target:` key to `app`. Example (from [scala-ide.rb](https://github.com/caskroom/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/scala-ide.rb#L21)):
```ruby
app 'eclipse/Eclipse.app', target: 'Scala IDE.app'
```
## target: May Contain an Absolute Path
If `target:` has a leading slash, it is interpreted as an absolute path. The containing directory for the absolute path will be created if it does not already exist. Example (from [manopen.rb](https://github.com/caskroom/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/manopen.rb#L12)):
```ruby
artifact 'openman.1', target: '/usr/local/share/man/man1/openman.1'
```
## target: Works on Most Artifact Types
The `target:` key works similarly for most Cask artifacts, such as `app`, `binary`, `colorpicker`, `font`, `input_method`, `prefpane`, `qlplugin`, `service`, `suite`, and `artifact`.
## target: Should Only Be Used in Select Cases
Dont use `target:` for aesthetic reasons, like removing version numbers (`app "Slack #{version}.app", target: 'Slack.app'`). With `app`, use it when it makes sense functionally and document your reason cleary in the Cask: was it [for clarity](https://github.com/caskroom/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/imagemin.rb#L12); [for consistency](https://github.com/caskroom/homebrew-cask/blob/d2a6b26df69fc28c4d84d6f5198b2b652c2f414d/Casks/devonthink-pro-office.rb#L16); [to prevent conflicts](https://github.com/caskroom/homebrew-cask/blob/bd6dc1a64e0bdd35ba0e20789045ea023b0b6aed/Casks/flash-player-debugger.rb#L11#L12); [due to developer suggestion](https://github.com/caskroom/homebrew-cask/blob/ff3e9c4a6623af44b8a071027e8dcf3f4edfc6d9/Casks/kivy.rb#L12)? With `binary` you can take some extra liberties to be consistent with other command-line tools, like [changing case](https://github.com/caskroom/homebrew-cask/blob/6e4eb6ba58ca0d9e6d42a1d78856cc8a35cf5fce/Casks/diffmerge.rb#L11) or [removing an extension](https://github.com/caskroom/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/filebot.rb#L12).

View File

@ -0,0 +1,23 @@
# appcast
The value of the `appcast` stanza is a string, holding the URL for an appcast which provides information on future updates.
## Required Appcast Parameters
| key | value |
| ------------- | ----------- |
| `checkpoint:` | a string holding a custom checksum of the most recent appcast which matches the current Cask versioning. Use `curl --compressed --location --user-agent 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36' "{{appcast_url}}" | sed 's|<pubDate>[^<]*</pubDate>||g' | shasum --algorithm 256` to calculate it.
Example: [`atom`](https://github.com/caskroom/homebrew-cask/blob/161f85b605e160ff96e7dd11732d85609e13dc51/Casks/atom.rb#L7L8)
There are a few different ways the `appcast` can be determined:
* If the app is distributed via GitHub releases, the `appcast` will be of the form `https://github.com/{{user}}/{{project}}/releases.atom`. (Example Cask: [`electron`](https://github.com/caskroom/homebrew-cask/blob/161f85b605e160ff96e7dd11732d85609e13dc51/Casks/electron.rb#L6L7))
* The popular update framework [Sparkle](https://sparkle-project.org/) generally uses the `SUFeedURL` property in `Contents/Info.plist` inside `.app` bundles. You can use the script [`find_sparkle_appcast`](https://github.com/caskroom/homebrew-cask/blob/master/developer/bin/find_sparkle_appcast) to add this automatically. (Example Cask: [`glyphs`](https://github.com/caskroom/homebrew-cask/blob/161f85b605e160ff96e7dd11732d85609e13dc51/Casks/glyphs.rb#L6L7))
* Sourceforge projects follow the form `https://downloads.sourceforge.net/projects/{{project_name}}/rss`. A more specific page can be used as needed, pointing to a specific directory structure: `https://sourceforge.net/projects/{{project_name}}/rss?path=/{{path_here}}`. (Example Cask: [`seashore`](https://github.com/caskroom/homebrew-cask/blob/bcff548278a6776fc57439603442a8b23c76bd8b/Casks/seashore.rb#L6L7))
* HockeyApp URLs are of the form `https://rink.hockeyapp.net/api/2/apps/HEXADECIMAL_STRING<SOMETHING_ELSE>`. For the `appcast`, remove `<SOMETHING_ELSE>` (ending up with `https://rink.hockeyapp.net/api/2/apps/HEXADECIMAL_STRING`. (Example Cask: [`iconjar`](https://github.com/caskroom/homebrew-cask/blob/bcff548278a6776fc57439603442a8b23c76bd8b/Casks/iconjar.rb#L7L8))
* An appcast can be any URL hosted by the apps developer that changes every time a new release is out (e.g. a changelog HTML page). (Example Cask: [`shortcat`](https://github.com/caskroom/homebrew-cask/blob/161f85b605e160ff96e7dd11732d85609e13dc51/Casks/shortcat.rb#L6L7))

View File

@ -0,0 +1,53 @@
# caveats
Sometimes there are particularities with the installation of a piece of software that cannot or should not be handled programatically by Homebrew-Cask. In those instances, `caveats` is the way to inform the user. Information in `caveats` is displayed when a cask is invoked with either `install` or `info`.
To avoid flooding users with too many messages (thus desensitising them to the important ones), `caveats` should be used sparingly and exclusively for installation-related matters. If youre not sure a `caveat` you find pertinent is installation-related or not, ask a maintainer. As a general rule, if your case isnt already covered in our comprehensive [`caveats Mini-DSL`](#caveats-mini-dsl), its unlikely to be accepted.
## caveats as a String
When `caveats` is a string, it is evaluated at compile time. The following methods are available for interpolation if `caveats` is placed in its customary position at the end of the Cask:
| method | description |
| ------------------ | ----------- |
| `token` | the Cask token
| `version` | the Cask version
| `homepage` | the Cask homepage
| `caskroom_path` | the containing directory for all staged Casks, typically `/usr/local/Caskroom` (only available with block form)
| `staged_path` | the staged location for this Cask, including version number, *eg* `/usr/local/Caskroom/adium/1.5.10` (only available with block form)
Example:
```ruby
caveats "Using #{token} is hazardous to your health."
```
## caveats as a Block
When `caveats` is a Ruby block, evaluation is deferred until install time. Within a block you may refer to the `@cask` instance variable, and invoke any method available on `@cask`.
## caveats Mini-DSL
There is a mini-DSL available within `caveats` blocks.
The following methods may be called to generate standard warning messages:
| method | description |
| --------------------------------- | ----------- |
| `path_environment_variable(path)` | users should make sure `path` is in their `$PATH` environment variable
| `zsh_path_helper(path)` | zsh users must take additional steps to make sure `path` is in their `$PATH` environment variable
| `depends_on_java(version)` | users should make sure they have the specified version of java installed. `version` can be exact (e.g. `6`), a minimum (e.g. `7+`), or omitted (when any version works).
| `logout` | users should log out and log back in to complete installation
| `reboot` | users should reboot to complete installation
| `files_in_usr_local` | the Cask installs files to `/usr/local`, which may confuse Homebrew
| `discontinued` | all software development has been officially discontinued upstream
| `free_license(web_page)` | users may get an official license to use the software at `web_page`
| `malware(radar_number)` | app has been reported to bundle malware. See [the FAQ](https://github.com/caskroom/homebrew-cask/blob/master/doc/faq/apps_with_malware.md) for the necessary steps.
Example:
```ruby
caveats do
path_environment_variable '/usr/texbin'
end
```

View File

@ -0,0 +1,14 @@
# conflicts_with
`conflicts_with` is used to declare conflicts that keep a Cask from installing or working correctly.
Several keys are accepted by `conflicts_with`, but none of them are yet enforced by the backend implementation. It is fine to proactively add `conflicts_with` stanzas to Casks in anticipation of future backend support; they are currently just a type of structured comment.
| key | description |
| ---------- | ----------- |
| `formula:` | *stub - not yet functional*
| `cask:` | *stub - not yet functional*
| `macos:` | *stub - not yet functional*
| `arch:` | *stub - not yet functional*
| `x11:` | *stub - not yet functional*
| `java:` | *stub - not yet functional*

View File

@ -0,0 +1,109 @@
# depends_on
`depends_on` is used to declare dependencies and requirements for a Cask.
`depends_on` is not consulted until `install` is attempted.
## depends_on cask:
The value should be another Cask token, needed by the current Cask.
Example use: [`SSHFS`](https://github.com/caskroom/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/sshfs.rb#L12) depends on OSXFUSE:
```ruby
depends_on cask: 'osxfuse'
```
## depends_on formula:
The value should name a Homebrew Formula needed by the Cask.
Example use: some distributions are contained in archive formats such as `7z` which are not supported by stock Apple tools. For these cases, a more capable archive reader may be pulled in at install time by declaring a dependency on the Homebrew Formula `unar`:
```ruby
depends_on formula: 'unar'
```
## depends_on macos:
### Requiring an Exact macOS Release
The value for `depends_on macos:` may be a symbol, string, or an array, listing the exact compatible macOS releases.
The available values for macOS releases are:
| symbol | corresponding string
| -------------------|----------------------
| `:cheetah` | `'10.0'`
| `:puma` | `'10.1'`
| `:jaguar` | `'10.2'`
| `:panther` | `'10.3'`
| `:tiger` | `'10.4'`
| `:leopard` | `'10.5'`
| `:snow_leopard` | `'10.6'`
| `:lion` | `'10.7'`
| `:mountain_lion` | `'10.8'`
| `:mavericks` | `'10.9'`
| `:yosemite` | `'10.10'`
| `:el_capitan` | `'10.11'`
| `:sierra` | `'10.12'`
Only major releases are covered (version numbers containing a single dot). The symbol form is preferred for readability. The following are all valid ways to enumerate the exact macOS release requirements for a Cask:
```ruby
depends_on macos: :yosemite
depends_on macos: [:mavericks, :yosemite]
depends_on macos: '10.9'
depends_on macos: ['10.9', '10.10']
```
### Setting a Minimum macOS Release
`depends_on macos:` can also accept a string starting with a comparison operator such as `>=`, followed by an macOS release in the form above. The following are both valid expressions meaning “at least macOS 10.9”:
```ruby
depends_on macos: '>= :mavericks'
depends_on macos: '>= 10.9'
```
A comparison expression cannot be combined with any other form of `depends_on macos:`.
## depends_on arch:
The value for `depends_on arch:` may be a symbol or an array of symbols, listing the hardware compatibility requirements for a Cask. The requirement is satisfied at install time if any one of multiple `arch:` value matches the users hardware.
The available symbols for hardware are:
| symbol | meaning |
| ---------- | -------------- |
| `:i386` | 32-bit Intel |
| `:x86_64` | 64-bit Intel |
| `:ppc_7400`| 32-bit PowerPC |
| `:ppc_64` | 64-bit PowerPC |
| `:intel` | Any Intel |
| `:ppc` | Any PowerPC |
The following are all valid expressions:
```ruby
depends_on arch: :x86_64
depends_on arch: [:x86_64] # same meaning as above
depends_on arch: :intel
depends_on arch: [:i386, :x86_64] # same meaning as above
```
Since PowerPC hardware is no longer common, the expression most frequently needed will be:
```ruby
depends_on arch: :x86_64
```
## All depends_on Keys
| key | description |
| ---------- | ----------- |
| `formula:` | a Homebrew Formula
| `cask:` | a Cask token
| `macos:` | a symbol, string, array, or comparison expression defining macOS release requirements
| `arch:` | a symbol or array defining hardware requirements
| `x11:` | a Boolean indicating a dependency on X11
| `java:` | *stub - not yet functional*

View File

@ -0,0 +1,24 @@
# \*flight
## Evaluation of Blocks is Always Deferred
The Ruby blocks defined by `preflight`, `postflight`, `uninstall_preflight`, and `uninstall_postflight` are not evaluated until install time or uninstall time. Within a block, you may refer to the `@cask` instance variable, and invoke any method available on `@cask`.
## \*flight Mini-DSL
There is a mini-DSL available within these blocks.
The following methods may be called to perform standard tasks:
| method | availability | description |
| ----------------------------------------- | ------------------------------------------------ | ----------- |
| `plist_set(key, value)` | `preflight`, `postflight`, `uninstall_preflight` | set a value in the `Info.plist` file for the app bundle. Example: [`rubymine.rb`](https://github.com/caskroom/homebrew-cask/blob/c5dbc58b7c1b6290b611677882b205d702b29190/Casks/rubymine.rb#L12)
| `set_ownership(paths)` | `preflight`, `postflight`, `uninstall_preflight` | set user and group ownership of `paths`. Example: [`unifi-controller.rb`](https://github.com/caskroom/homebrew-cask/blob/8a452a41707af6a661049da6254571090fac5418/Casks/unifi-controller.rb#L13)
| `set_permissions(paths, permissions_str)` | `preflight`, `postflight`, `uninstall_preflight` | set permissions in `paths` to `permissions_str`. Example: [`docker-machine.rb`](https://github.com/caskroom/homebrew-cask/blob/8a452a41707af6a661049da6254571090fac5418/Casks/docker-machine.rb#L16)
| `suppress_move_to_applications` | `postflight` | suppress a dialog asking the user to move the app to the `/Applications` folder. Example: [`github.rb`](https://github.com/caskroom/homebrew-cask/blob/c5dbc58b7c1b6290b611677882b205d702b29190/Casks/github.rb#L13)
`plist_set` currently has the limitation that it only operates on the bundle indicated by the first `app` stanza (and the Cask must contain an `app` stanza).
`set_ownership(paths)` defaults user ownership to the current user and group ownership to `staff`. These can be changed by passing in extra options: `set_ownership(paths, user: 'user', group: 'group')`.
`suppress_move_to_applications` optionally accepts a `:key` parameter for apps which use a nonstandard `defaults` key. Example: [`alfred.rb`](https://github.com/caskroom/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/alfred.rb#L16).

View File

@ -0,0 +1,11 @@
# gpg Stanza Details
**This is a stub for upcoming functionality, and is not fully documented**.
The `gpg` stanza contains signature information for GPG-signed distributions. The form is:
```ruby
gpg <signature>, <parameter>: <value>
```
where `<parameter>` is one of `key_id:` or `key_url:`, and `<signature>` points to the detached signature of the distribution. Commonly, the signature follows the `url` value. Example: [libreoffice.rb](https://github.com/caskroom/homebrew-cask/blob/42abacc85798d8c0b8d3f47c70b62ee65ce5ceaa/Casks/libreoffice.rb#L16#L17).

View File

@ -0,0 +1,33 @@
# installer
This stanza must always be accompanied by [`uninstall`](uninstall.md).
The `installer` stanza takes a series of key-value pairs, the first key of which must be `manual:` or `script:`.
## installer manual:
`installer manual:` takes a single string value, describing a GUI installer which must be run by the user at a later time. The path may be absolute, or relative to the Cask. Example (from [little-snitch.rb](https://github.com/caskroom/homebrew-cask/blob/818047bf488be92923c8770ef3df8007a0db7704/Casks/little-snitch.rb#L10)):
```ruby
installer manual: 'Little Snitch Installer.app'
```
## installer script:
`installer script:` introduces a series of key-value pairs describing a command which will automate completion of the install. The form is similar to `uninstall script:`:
| key | value
| ----------------|------------------------------
| `script:` | path to an install script to be run via `sudo`. (Required first key.)
| `args:` | array of arguments to the install script
| `input:` | array of lines of input to be sent to `stdin` of the script
| `must_succeed:` | set to `false` if the script is allowed to fail
| `sudo:` | set to `false` if the script does not need `sudo`
The path may be absolute, or relative to the Cask. Example (from [adobe-air.rb](https://github.com/caskroom/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/adobe-air.rb#L10-#L12)):
```ruby
installer script: 'Adobe AIR Installer.app/Contents/MacOS/Adobe AIR Installer',
args: %w[-silent],
sudo: true
```

View File

@ -0,0 +1,47 @@
# license
The `license` stanza is not free-form. A single value must be chosen from a list of valid symbols.
The values for `license` are categories, rather than fully-specified licenses. For example, `:gpl` is a category; we do not distinguish between versions of the GPL. Similarly, `:cc` and `:bsd` comprise many variants. They must always pertain to the license of the software itself, not the vendors business model (a free app to access a paid service is still `:gratis`, not `:freemium`).
The `license` stanza is intended as an aid to search/filtering of Casks. For full and complete information, the user must always rely on the vendors homepage.
Note that `brew cask search` and `brew cask list` are not yet capable of using the information stored in the `license` stanza.
## Generic Category Licenses
Cask authors should use the most specific license category which is also correct. Generic categories are provided for difficult cases. `:unknown` is also perfectly fine if you are unsure.
Example: [Chromium](https://www.chromium.org/chromium-os/licenses) includes code with multiple licenses, all of which are open source. Chromium licensing is described by the generic category [`:oss`](https://github.com/caskroom/homebrew-cask/blob/54a79f7dcceea9a922a5b608ac99466b9d10a191/Casks/chromium.rb#L7).
| symbol | meaning |
| ----------- | ----------- |
| `:oss` | open-source software
| `:closed` | closed-source software
| `:unknown` | license unknown
| `:other` | license is known, but fits no category
## Valid Licenses
| symbol | generic category | meaning | URL |
| ---------------- | ---------------- | ------------------------------------------------------------------ | ----------- |
| `:gratis` | `:closed` | free-to-use, closed source | <none>
| `:commercial` | `:closed` | not free to use | <none>
| `:freemium` | `:closed` | free-to-use, payment required for full or additional functionality | <https://en.wikipedia.org/wiki/Freemium>
| `:affero` | `:oss` | Affero General Public License | <https://gnu.org/licenses/agpl.html>
| `:apache` | `:oss` | Apache Public License | <https://www.apache.org/licenses/>
| `:arphic` | `:oss` | Arphic Public License | <http://www.arphic.com/tw/download/public_license.rar>
| `:artistic` | `:oss` | Artistic License | <https://dev.perl.org/licenses/artistic.html>
| `:bsd` | `:oss` | BSD License | <http://www.linfo.org/bsdlicense.html>
| `:cc` | `:oss` | Creative Commons License | <https://creativecommons.org/licenses/>
| `:eclipse` | `:oss` | Eclipse Public License | <https://www.eclipse.org/legal/eplfaq.php>
| `:gpl` | `:oss` | GNU Public License | <https://www.gnu.org/copyleft/gpl.html>
| `:isc` | `:oss` | Internet Systems Consortium License | <https://www.isc.org/downloads/software-support-policy/isc-license/>
| `:lppl` | `:oss` | LaTeX Project Public License | <https://latex-project.org/lppl/>
| `:ncsa` | `:oss` | University of Illinois/NCSA Open Source License | <http://otm.illinois.edu/uiuc_openSource>
| `:mit` | `:oss` | MIT License | <https://opensource.org/licenses/MIT>
| `:mpl` | `:oss` | Mozilla Public License | <https://www.mozilla.org/MPL/>
| `:ofl` | `:oss` | SIL Open Font License | <https://scripts.sil.org/OFL>
| `:public_domain` | `:oss` | not copyrighted | <https://creativecommons.org/publicdomain/zero/1.0/legalcode>
| `:ubuntu_font` | `:oss` | Ubuntu Font License | <http://font.ubuntu.com/licence/>
| `:x11` | `:oss` | X Consortium License | <http://www.xfree86.org/3.3.6/COPYRIGHT2.html>

View File

@ -0,0 +1,9 @@
# name
`name` accepts a UTF-8 string defining the full name of the software, and is used to help with searchability and disambiguation. It can be repeated multiple times if there are useful alternative names.
Its first instance should use the latin alphabet, include the software vendors name, and be as verbose as possible while still making sense.
A good example is [`pycharm-ce`](https://github.com/caskroom/homebrew-cask/blob/fc05c0353aebb28e40db72faba04b82ca832d11a/Casks/pycharm-ce.rb#L6#L7). `Jetbrains PyCharm Community Edition` makes sense even though it is likely never referenced as such anywhere, but `Jetbrains PyCharm Community Edition CE` doesnt, hence why it has a second line. Another example are casks whose original names do not use the latin alphabet, like [`cave-story`](https://github.com/caskroom/homebrew-cask/blob/0fe48607f5656e4f1de58c6884945378b7e6f960/Casks/cave-story.rb#L7#L9).
Note that `brew cask search` and `brew cask list` are not yet capable of using the information stored in the `name` stanza.

View File

@ -0,0 +1,19 @@
# pkg
This stanza must always be accompanied by [`uninstall`](uninstall.md)
The first argument to the `pkg` stanza should be a relative path to the `.pkg` file to be installed. For example:
```ruby
pkg 'Unity.pkg'
```
Subsequent arguments to `pkg` are key/value pairs which modify the install process. Currently supported keys are:
* `allow_untrusted:` — pass `-allowUntrusted` to `/usr/sbin/installer`
Example (from [alinof-timer.rb](https://github.com/caskroom/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/alinof-timer.rb#L10)):
```ruby
pkg 'AlinofTimer.pkg', allow_untrusted: true
```

View File

@ -0,0 +1,17 @@
# sha256
## Calculating the SHA256
The `sha256` value is usually calculated by the command:
```bash
$ shasum -a 256 <file>
```
## Special Value `:no_check`
The special value `sha256 :no_check` is used to turn off SHA checking whenever checksumming is impractical due to the upstream configuration.
`version :latest` requires `sha256 :no_check`, and this pairing is common. However, `sha256 :no_check` does not require `version :latest`.
We use a checksum whenever possible.

View File

@ -0,0 +1,11 @@
# suite
Some distributions provide a suite of multiple applications, or an application with required data, to be installed together in a subdirectory of `/Applications`.
For these Casks, use the `suite` stanza to define the directory containing the application suite. Example (from [sketchup.rb](https://github.com/caskroom/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/sketchup.rb#L12)):
```ruby
suite 'SketchUp 2016'
```
The value of `suite` is never an `.app` bundle, but a plain directory.

View File

@ -0,0 +1,199 @@
# uninstall
IF YOU CANNOT DESIGN A WORKING `UNINSTALL` STANZA, PLEASE SUBMIT YOUR CASK ANYWAY. The maintainers will help you write an `uninstall` stanza, just ask!
## uninstall pkgutil: Is The Easiest and Most Useful
`pkgutil:` is the easiest and most useful `uninstall` directive. See [Uninstall Key pkgutil:](#uninstall-key-pkgutil).
## uninstall Is Required for Casks That Install a pkg or installer manual:
For most Casks, uninstall actions are determined automatically, and an explicit `uninstall` stanza is not needed. However, a Cask which uses the `pkg` or `installer manual:` stanzas will **not** know how to uninstall correctly unless an `uninstall` stanza is given.
So, while the Cask language does not enforce the requirement, it is much better for end-users if every `pkg` and `installer manual:` has a corresponding `uninstall`.
The `uninstall` stanza is available for non-`pkg` Casks, and is useful for a few corner cases. However, the documentation below concerns the typical case of using `uninstall` to define procedures for a `pkg`.
## There Are Multiple Uninstall Techniques
Since `pkg` installers can do arbitrary things, different techniques are needed to uninstall in each case. You may need to specify one, or several, of the following key/value pairs as arguments to `uninstall`.
## Summary of Keys
* `early_script:` (string or hash) - like `script:`, but runs early (for special cases, best avoided)
* `launchctl:` (string or array) - ids of `launchctl` jobs to remove
* `quit:` (string or array) - bundle ids of running applications to quit
* `signal:` (array of arrays) - signal numbers and bundle ids of running applications to send a Unix signal to (used when `quit:` does not work)
* `login_item:` (string or array) - names of login items to remove
* `kext:` (string or array) - bundle ids of kexts to unload from the system
* `pkgutil:` (string, regexp or array of strings and regexps) - strings or regexps matching bundle ids of packages to uninstall using `pkgutil`
* `script:` (string or hash) - relative path to an uninstall script to be run via sudo; use hash if args are needed
- `executable:` - relative path to an uninstall script to be run via sudo (required for hash form)
- `args:` - array of arguments to the uninstall script
- `input:` - array of lines of input to be sent to `stdin` of the script
- `must_succeed:` - set to `false` if the script is allowed to fail
- `sudo:` - set to `false` if the script does not need `sudo`
* `delete:` (string or array) - single-quoted, absolute paths of files or directory trees to remove. `delete:` should only be used as a last resort. `pkgutil:` is strongly preferred.
* `rmdir:` (string or array) - single-quoted, absolute paths of directories to remove if empty
* `trash:` (string or array) - currently a synonym for `delete:`. In the future this will cause files to be moved to the Trash.
Each `uninstall` technique is applied according to the order above. The order in which `uninstall` keys appear in the Cask file is ignored.
For assistance filling in the right values for `uninstall` keys, there are several helper scripts found under `developer/bin` in the Homebrew-Cask repository. Each of these scripts responds to the `-help` option with additional documentation.
The easiest way to work out an `uninstall` stanza is on a system where the `pkg` is currently installed and operational. To operate on an uninstalled `pkg` file, see [Working With a pkg File Manually](#working-with-a-pkg-file-manually), below.
## uninstall Key pkgutil:
This is the most useful uninstall key. `pkgutil:` is often sufficient to completely uninstall a `pkg`, and is strongly preferred over `delete:`.
IDs for the most recently-installed packages can be listed using the command:
```bash
$ ./developer/bin/list_recent_pkg_ids
```
`pkgutil:` also accepts a regular expression match against multiple package IDs. The regular expressions are somewhat nonstandard. To test a `pkgutil:` regular expression against currently-installed packages, use the command:
```bash
$ ./developer/bin/list_pkg_ids_by_regexp <regular-expression>
```
## List Files Associated With a pkg Id
Once you know the ID for an installed package, (above), you can list all files on your system associated with that package ID using the macOS command:
```bash
$ pkgutil --files <package.id.goes.here>
```
Listing the associated files can help you assess whether the package included any `launchctl` jobs or kernel extensions (kexts).
## uninstall Key launchctl:
IDs for currently loaded `launchctl` jobs can be listed using the command:
```bash
$ ./developer/bin/list_loaded_launchjob_ids
```
IDs for all installed `launchctl` jobs can be listed using the command:
```bash
$ ./developer/bin/list_installed_launchjob_ids
```
## uninstall Key quit:
Bundle IDs for currently running Applications can be listed using the command:
```bash
$ ./developer/bin/list_running_app_ids
```
Bundle IDs inside an Application bundle on disk can be listed using the command:
```bash
$ ./developer/bin/list_ids_in_app </path/to/application.app>
```
## uninstall Key signal:
`signal:` should only be needed in the rare case that a process does not respond to `quit:`.
Bundle IDs for `signal:` targets may be obtained as for `quit:`. The value for `signal:` is an array-of-arrays, with each cell containing two elements: the desired Unix signal followed by the corresponding bundle ID.
The Unix signal may be given in numeric or string form (see the `kill` man page for more details).
The elements of the `signal:` array are applied in order, only if there is an existing process associated the bundle ID, and stopping when that process terminates. A bundle ID may be repeated to send more than one signal to the same process.
It is better to use the least-severe signals which are sufficient to stop a process. The `KILL` signal in particular can have unwanted side-effects.
An example, with commonly-used signals in ascending order of severity:
```ruby
uninstall signal: [
['TERM', 'fr.madrau.switchresx.daemon'],
['QUIT', 'fr.madrau.switchresx.daemon'],
['INT', 'fr.madrau.switchresx.daemon'],
['HUP', 'fr.madrau.switchresx.daemon'],
['KILL', 'fr.madrau.switchresx.daemon'],
]
```
Note that when multiple running processes match the given Bundle ID, all matching processes will be signaled.
Unlike `quit:` directives, Unix signals originate from the current user, not from the superuser. This is construed as a safety feature, since the superuser is capable of bringing down the system via signals. However, this inconsistency may also be considered a bug, and should be addressed in some fashion in a future version.
## uninstall key login_item:
Login items associated with an Application bundle on disk can be listed using the command:
```bash
$ ./developer/bin/list_login_items_for_app </path/to/application.app>
```
Note that you will likely need to have opened the app at least once for any login items to be present.
## uninstall Key kext:
IDs for currently loaded kernel extensions can be listed using the command:
```bash
$ ./developer/bin/list_loaded_kext_ids
```
IDs inside a kext bundle you have located on disk can be listed using the command:
```bash
$ ./developer/bin/list_id_in_kext </path/to/name.kext>
```
## uninstall Key delete:
`delete:` should only be used as a last resort, if other `uninstall` methods are insufficient.
Arguments to `uninstall delete:` should be static, single-quoted, absolute paths.
* Only single quotes should be used.
* Double-quotes should not be used. `ENV['HOME']` and other variables
should not be interpolated in the value.
* Basic tilde expansion is performed on paths, i.e., leading `~` is expanded to the home directory.
* Only absolute paths should be given.
* No glob expansion is performed (*eg* `*` characters are literal), though glob expansion is a desired future feature.
To remove user-specific files, use the `zap` stanza.
## uninstall Key trash:
*stub* - currently a synonym for `delete:`. In the future this will cause files to be moved to the Trash. It is best not to use this stub until it gains the proper functionality.
## Working With a pkg File Manually
Advanced users may wish to work with a `pkg` file manually, without having the package installed.
A list of files which may be installed from a `pkg` can be extracted using the command:
```bash
$ ./developer/bin/list_payload_in_pkg </path/to/my.pkg>
```
Candidate application names helpful for determining the name of a Cask may be extracted from a `pkg` file using the command:
```bash
$ ./developer/bin/list_apps_in_pkg </path/to/my.pkg>
```
Candidate package IDs which may be useful in a `pkgutil:` key may be extracted from a `pkg` file using the command:
```bash
$ ./developer/bin/list_ids_in_pkg </path/to/my.pkg>
```
A fully manual method for finding bundle ids in a package file follows:
1. Unpack `/path/to/my.pkg` (replace with your package name) with `pkgutil --expand /path/to/my.pkg /tmp/expanded.unpkg`.
2. The unpacked package is a folder. Bundle ids are contained within files named `PackageInfo`. These files can be found with the command `find /tmp/expanded.unpkg -name PackageInfo`.
3. `PackageInfo` files are XML files, and bundle ids are found within the `identifier` attributes of `<pkg-info>` tags that look like `<pkg-info ... identifier="com.oracle.jdk7u51" ... >`, where extraneous attributes have been snipped out and replaced with ellipses.
4. Kexts inside packages are also described in `PackageInfo` files. If any kernel extensions are present, the command `find /tmp/expanded.unpkg -name PackageInfo -print0 | xargs -0 grep -i kext` should return a `<bundle id>` tag with a `path` attribute that contains a `.kext` extension, for example `<bundle id="com.wavtap.driver.WavTap" ... path="./WavTap.kext" ... />`.
5. Once bundle ids have been identified, the unpacked package directory can be deleted.

View File

@ -0,0 +1,132 @@
# url
## HTTPS URLs are Preferred
If available, an HTTPS URL is preferred. A plain HTTP URL should only be used in the absence of a secure alternative.
## Additional HTTP/S URL Parameters
When a plain URL string is insufficient to fetch a file, additional information may be provided to the `curl`-based downloader, in the form of key/value pairs appended to `url`:
| key | value |
| ------------------ | ----------- |
| `using:` | the symbol `:post` is the only legal value
| `cookies:` | a hash of cookies to be set in the download request
| `referer:` | a string holding the URL to set as referrer in the download request
| `user_agent:` | a string holding the user agent to set for the download request. Can also be set to the symbol `:fake`, which will use a generic Browser-like user agent string. We prefer `:fake` when the server does not require a specific user agent.
| `data:` | a hash of parameters to be set in the POST request
Example of using `cookies:`: [java.rb](https://github.com/caskroom/homebrew-cask/blob/472930df191d66747a57d5c96c0d00511d56e21b/Casks/java.rb#L5#L8)
Example of using `referer:`: [rrootage.rb](https://github.com/caskroom/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/rrootage.rb#L5)
## When URL and Homepage Hostnames Differ, Add a Comment
When the hostnames of `url` and `homepage` differ, the discrepancy should be documented with a comment of the form:
```
# URL_SECTION was verified as official when first introduced to the cask
```
Where `URL_SECTION` is the smallest possible portion of the URL that uniquely identifies the app or vendor. Examples can be seen in [`airfoil.rb`](https://github.com/caskroom/homebrew-cask/blob/1666993ee93e2a43f00a4dfc3c727da7c0b5ada9/Casks/airfoil.rb#L5), [`knockknock.rb`](https://github.com/caskroom/homebrew-cask/blob/6645a6090d1cb8fc026f243a47048749b31c32bf/Casks/knockknock.rb#L5), [`lightpaper.rb`](https://github.com/caskroom/homebrew-cask/blob/7a75f4e84c01bf192bd55f251b96cf2c1e086281/Casks/lightpaper.rb#L5), [`airtool.rb`](https://github.com/caskroom/homebrew-cask/blob/355211a8a3ea54046ae45022bcf71980bd2d5432/Casks/airtool.rb#L5), [`screencat.rb`](https://github.com/caskroom/homebrew-cask/blob/5fc818752c30c156c00f79b04b66406189ab2f30/Casks/screencat.rb#L5), [`0ad.rb`](https://github.com/caskroom/homebrew-cask/blob/7a75f4e84c01bf192bd55f251b96cf2c1e086281/Casks/0ad.rb#L5).
These comments must be added so a user auditing the cask knows the URL was verified by the Homebrew-Cask team as the one provided by the vendor, even though it may look unofficial or suspicious. It is our responsibility as Homebrew-Cask maintainers to verify both the `url` and `homepage` information when first added (or subsequently modified, apart from versioning).
The comment doesnt mean you should trust the source blindly, but we only approve casks in which users can easily verify its authenticity with basic means, such as checking the official homepage or public repository. occasionally, slightly more elaborate techniques may be used, such as inspecting an [`appcast`](appcast.md) we established as official. Cases where such quick verifications arent possible (e.g. when the download URL is behind a registration wall) are [treated in a stricter manner](../../development/adding-a-cask.md#unofficial-vendorless-and-walled-builds).
## Difficulty Finding a URL
Web browsers may obscure the direct `url` download location for a variety of reasons. Homebrew-Cask supplies a script which can read extended file attributes to extract the actual source URL for most files downloaded by a browser on macOS. The script usually emits multiple candidate URLs; you may have to test each of them:
```bash
$ $(brew --repository)/Library/Taps/caskroom/homebrew-cask/developer/bin/list_url_attributes_on_file <file>
```
## Subversion URLs
In rare cases, a distribution may not be available over ordinary HTTP/S. Subversion URLs are also supported, and can be specified by appending the following key/value pairs to `url`:
| key | value |
| ------------------ | ----------- |
| `using:` | the symbol `:svn` is the only legal value
| `revision:` | a string identifying the subversion revision to download
| `trust_cert:` | set to `true` to automatically trust the certificate presented by the server (avoiding an interactive prompt)
## SourceForge/OSDN URLs
SourceForge and OSDN (formerly SourceForge.JP) projects are common ways to distribute binaries, but they provide many different styles of URLs to get to the goods.
We prefer URLs of this format:
```
https://downloads.sourceforge.net/{{project_name}}/{{filename}}.{{ext}}
```
Or, if its from [OSDN](https://osdn.jp/):
```
http://{{subdomain}}.osdn.jp/{{project_name}}/{{release_id}}/{{filename}}.{{ext}}
```
`{{subdomain}}` is typically of the form `dl` or `{{user}}.dl`.
If these formats are not available, and the application is macOS-exclusive (otherwise a command-line download defaults to the Windows version) we prefer the use of this format:
```
https://sourceforge.net/projects/{{project_name}}/files/latest/download
```
## Personal Hosting Such as Dropbox
URLs from dropbox.com or cl.ly/cloudapp.com are not readily distinguishable as being controlled by the original software vendor. These URLs should be used only when given as such on the official project website.
Also make sure to give the URL for the binary download itself, rather than a preview page. (See <https://www.dropbox.com/help/201/en>.)
## Some Providers Block Command-line Downloads
Some hosting providers actively block command-line HTTP clients. Such URLs cannot be used in Casks.
Some providers do not actively block command-line HTTP clients but use URLs that change periodically, or even on each visit (example: FossHub). For those, see section [URLs that Change on Every Visit](#urls-that-change-on-every-visit).
## Vendor URLs Are Preferred
When possible, it is best to use a download URL from the original developer or vendor, rather than an aggregator such as `macupdate.com`.
## URLs that Change on Every Visit
Some providers use disposable URLs, which a Cask author cannot know in advance. Such URLs may change daily, or on every visit, and sometimes need to be dynamically obtained from a landing site.
### The Problem
In theory, one can write arbitrary Ruby code right in the Cask definition to fetch and construct a disposable URL.
However, this typically involves an HTTP/S round trip to a landing site, which may take a long time. Because of the way Homebrew-Cask loads and parses Casks, it is not acceptable that such expensive operations be performed directly in the body of a Cask definition.
### Using a Block to Defer Code Execution
Similar to the `preflight`, `postflight`, `uninstall_preflight`, and `uninstall_postflight` blocks, the `url` stanza offers an optional _block syntax_:
```rb
url do
# No known stable URL; fetching disposable URL from landing site
open('https://example.com/app/landing') do |landing_page|
content = landing_page.read
parse(content) # => https://example.com/download?23309800482283
end
end
```
The block is only evaluated when needed, for example on download time or when auditing a Cask.
Inside a block, you may safely do things such as HTTP/S requests that may take a long time to execute. You may also refer to the `@cask` instance variable, and invoke any method available on `@cask`.
The block will be called immediately before downloading; its result value will be assumed to be a `String` and subsequently used as a download URL.
You can use the `url` stanza with either a direct argument or a block but not with both.
Example for using the block syntax: [audacity.rb](https://github.com/caskroom/homebrew-cask/blob/c389d9ccbb46d30b6ac1cbdbadf49591ca8ff6cd/Casks/audacity.rb#L5-L15)
### Mixing Additional URL Parameters With the Block Syntax
In rare cases, you might need to set URL parameters like `cookies` or `referer` while also using the block syntax.
This is possible by returning a two-element array as a block result. The first element of the array must be the download URL; the second element must be a `Hash` containing the parameters.

View File

@ -0,0 +1,53 @@
# version
`version`, while related to the apps own versioning, doesnt have to follow it exactly. It is common to change it slightly so it can be [interpolated](https://en.wikipedia.org/wiki/String_interpolation#Ruby) in other stanzas, usually in `url` to create a Cask that only needs `version` and `sha256` changes when updated. This can be taken further, when needed, with [ruby String methods](https://ruby-doc.org/core/String.html).
For example:
Instead of
```ruby
version '1.2.3'
url 'http://example.com/file-version-123.dmg'
```
We can use
```ruby
version '1.2.3'
url "http://example.com/file-version-#{version.delete('.')}.dmg"
```
We can also leverage the power of regular expressions. So instead of
```ruby
version '1.2.3build4'
url 'http://example.com/1.2.3/file-version-1.2.3build4.dmg'
```
We can use
```ruby
version '1.2.3build4'
url "http://example.com/#{version.sub(%r{build\d+}, '')}/file-version-#{version}.dmg"
```
## version methods
The examples above can become hard to read, however. Since many of these changes are common, we provide a number of helpers to clearly interpret otherwise obtuse cases:
| Method | Input | Output |
|--------------------------|--------------------|--------------------|
| `major` | `1.2.3-a45,ccdd88` | `1` |
| `minor` | `1.2.3-a45,ccdd88` | `2` |
| `patch` | `1.2.3-a45,ccdd88` | `3` |
| `major_minor` | `1.2.3-a45,ccdd88` | `1.2` |
| `major_minor_patch` | `1.2.3-a45,ccdd88` | `1.2.3` |
| `before_comma` | `1.2.3-a45,ccdd88` | `1.2.3-a45` |
| `after_comma` | `1.2.3-a45,ccdd88` | `ccdd88` |
| `dots_to_hyphens` | `1.2.3-a45,ccdd88` | `1-2-3-a45,ccdd88` |
| `no_dots` | `1.2.3-a45,ccdd88` | `123-a45,ccdd88` |
Similar to `dots_to_hyphens`, we provide all logical permutations of `{dots,hyphens,underscores,slashes}_to_{dots,hyphens,underscores,slashes}`. The same applies to `no_dots` in the form of `no_{dots,hyphens,underscores,slashes}`, with an extra `no_dividers` that applies all of those at once.
Finally, there are `before_colon` and `after_colon` that act like their `comma` counterparts. These four are extra special to allow for otherwise complex cases, and should be used sparingly. There should be no more than one of `,` and `:` per `version`. Use `,` first, and `:` only if absolutely necessary.

View File

@ -0,0 +1,24 @@
# zap
## zap Stanza Purpose
The `zap` stanza describes a more complete uninstallation of files associated with a Cask. The `zap` procedures will never be performed by default, but only if the user invokes the `zap` verb:
```bash
$ brew cask zap td-toolbelt # also removes org.ruby-lang.installer
```
`zap` stanzas may remove:
* Preference files and caches stored within the users `~/Library` directory.
* Shared resources such as application updaters. Since shared resources may be removed, other applications may be affected by `brew cask zap`. Understanding that is the responsibility of the end user.
`zap` stanzas should not remove:
* Files created by the user directly.
## zap Stanza Syntax
The form of `zap` stanza follows the [`uninstall` stanza](uninstall.md). All of the same directives are available. Unlike with `uninstall`, however, `delete:` is not discouraged in `zap`.
Example: [injection.rb](https://github.com/caskroom/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/injection.rb#L16)

View File

@ -0,0 +1,127 @@
# Cask Token Reference
This document describes the algorithm implemented in the `generate_cask_token` script, and covers detailed rules and exceptions which are not needed in most cases.
* [Purpose](#purpose)
* [Finding the Simplified Name of the Vendors Distribution](#finding-the-simplified-name-of-the-vendors-distribution)
* [Converting the Simplified Name To a Token](#converting-the-simplified-name-to-a-token)
* [Cask Filenames](#cask-filenames)
* [Cask Headers](#cask-headers)
* [Cask Token Examples](#cask-token-examples)
* [Token Overlap](#token-overlap)
## Purpose
The purpose of these stringent conventions is to:
* Unambiguously boil down the name of the software into a unique identifier
* Minimize renaming events
* Prevent duplicate submissions
The token itself should be:
* Suitable for use as a filename
* Mnemonic
Details of software names and brands will inevitably be lost in the conversion to a minimal token. To capture the vendors full name for a distribution, use the [`name`](https://github.com/caskroom/homebrew-cask/blob/master/doc/cask_language_reference/stanzas/name.md) within a Cask. `name` accepts an unrestricted UTF-8 string.
## Finding the Simplified Name of the Vendors Distribution
### Simplified Names of Apps
* Start with the exact name of the Application bundle as it appears on disk, such as `Google Chrome.app`.
* If the name uses letters outside A-Z, convert it to ASCII as described in [Converting to ASCII](#converting-to-ascii).
* Remove `.app` from the end.
* Remove from the end: the string “app”, if the vendor styles the name like “Software App.app”. Exception: when “app” is an inseparable part of the name, without which the name would be inherently nonsensical, as in [rcdefaultapp.rb](../../Casks/rcdefaultapp.rb).
* Remove from the end: version numbers or incremental release designations such as “alpha”, “beta”, or “release candidate”. Strings which distinguish different capabilities or codebases such as “Community Edition” are currently accepted. Exception: when a number is not an incremental release counter, but a differentiator for a different product from a different vendor, as in [pgadmin3.rb](../../Casks/pgadmin3.rb).
* If the version number is arranged to occur in the middle of the App name, it should also be removed. Example: [IntelliJ IDEA 13 CE.app](../../../../../homebrew-versions/tree/master/Casks/intellij-idea-ce.rb).
* Remove from the end: “Launcher”, “Quick Launcher”.
* Remove from the end: strings such as “Mac”, “for Mac”, “for OS X”, “macOS”, “for macOS”. These terms are generally added to ported software such as “MAME OS X.app”. Exception: when the software is not a port, and “Mac” is an inseparable part of the name, without which the name would be inherently nonsensical, as in [PlayOnMac.app](../../Casks/playonmac.rb).
* Remove from the end: hardware designations such as “for x86”, “32-bit”, “ppc”.
* Remove from the end: software framework names such as “Cocoa”, “Qt”, “Gtk”, “Wx”, “Java”, “Oracle JVM”, etc. Exception: the framework is the product being Casked, as in [java.rb](../../Casks/java.rb).
* Remove from the end: localization strings such as “en-US”.
* If the result of that process is a generic term, such as “Macintosh Installer”, try prepending the name of the vendor or developer, followed by a hyphen. If that doesnt work, then just create the best name you can, based on the vendors web page.
* If the result conflicts with the name of an existing Cask, make yours unique by prepending the name of the vendor or developer, followed by a hyphen. Example: [unison.rb](../../Casks/unison.rb) and [panic-unison.rb](../../Casks/panic-unison.rb).
* Inevitably, there are a small number of exceptions not covered by the rules. Dont hesitate to [contact the maintainers](../../../../issues) if you have a problem.
### Converting to ASCII
* If the vendor provides an English localization string, that is preferred. Here are the places it may be found, in order of preference:
- `CFBundleDisplayName` in the main `Info.plist` file of the app bundle
- `CFBundleName` in the main `Info.plist` file of the app bundle
- `CFBundleDisplayName` in `InfoPlist.strings` of an `en.lproj` localization directory
- `CFBundleName` in `InfoPlist.strings` of an `en.lproj` localization directory
- `CFBundleDisplayName` in `InfoPlist.strings` of an `English.lproj` localization directory
- `CFBundleName` in `InfoPlist.strings` of an `English.lproj` localization directory
* When there is no vendor localization string, romanize the name by transliteration or decomposition.
* As a last resort, translate the name of the app bundle into English.
### Simplified Names of `pkg`-based Installers
* The Simplified Name of a `pkg` may be more tricky to determine than that of an App. If a `pkg` installs an App, then use that App name with the rules above. If not, just create the best name you can, based on the vendors web page.
### Simplified Names of non-App Software
* Currently, rules for generating a token are not well-defined for Preference Panes, QuickLook plugins, and several other types of software installable by Homebrew-Cask. Just create the best name you can, based on the filename on disk or the vendors web page. Watch out for duplicates.
Non-app tokens should become more standardized in the future.
## Converting the Simplified Name To a Token
The token is the primary identifier for a package in our project. Its the unique string users refer to when operating on the Cask.
To convert the Apps Simplified Name (above) to a token:
* Convert all letters to lower case.
* Expand the `+` symbol into a separated English word: `-plus-`.
* Expand the `@` symbol into a separated English word: `-at-`.
* Spaces become hyphens.
* Hyphens stay hyphens.
* Digits stay digits.
* Delete any character which is not alphanumeric or a hyphen.
* Collapse a series of multiple hyphens into one hyphen.
* Delete a leading or trailing hyphen.
We avoid defining Cask tokens in the repository which differ only by the placement of hyphens. Prepend the vendor name if needed to disambiguate the token.
## Cask Filenames
Casks are stored in a Ruby file named after the token, with the file extension `.rb`.
## Cask Headers
The token is also given in the header line for each Cask.
## Cask Token Examples
These illustrate most of the rules for generating a token:
App Name on Disk | Simplified App Name | Cask Token | Filename
-----------------------|---------------------|------------------|----------------------
`Audio Hijack Pro.app` | Audio Hijack Pro | audio-hijack-pro | `audio-hijack-pro.rb`
`VLC.app` | VLC | vlc | `vlc.rb`
`BetterTouchTool.app` | BetterTouchTool | bettertouchtool | `bettertouchtool.rb`
`LPK25 Editor.app` | LPK25 Editor | lpk25-editor | `lpk25-editor.rb`
`Sublime Text 2.app` | Sublime Text | sublime-text | `sublime-text.rb`
# Token Overlap
When the token for a new Cask would otherwise conflict with the token of an already existing Cask, the nature of that overlap dictates the token (for possibly both Casks). See [Finding a Home For Your Cask](../development/adding_a_cask.md#finding-a-home-for-your-cask) for information on how to proceed.
# <3 THANK YOU TO ALL CONTRIBUTORS! <3

View File

@ -0,0 +1,314 @@
## Adding a Cask
Making a new Cask is easy. Follow the directions in [Getting Set Up To Contribute](../../CONTRIBUTING.md#getting-set-up-to-contribute) to begin.
### Examples
Heres a Cask for `shuttle` as an example. Note the comment above `url`, which is needed when [the url and homepage hostnames differ](../cask_language_reference/stanzas/url.md#when-url-and-homepage-hostnames-differ-add-a-comment)
```ruby
cask 'shuttle' do
version '1.2.6'
sha256 '7b54529cd00332e423839cf768b732ac6c42e17de9325d0a093764180deeb611'
# github.com/fitztrev/shuttle was verified as official when first introduced to the cask
url "https://github.com/fitztrev/shuttle/releases/download/v#{version}/Shuttle.zip"
appcast 'https://github.com/fitztrev/shuttle/releases.atom',
checkpoint: 'c3dea2ed479b3ebba7c56ace6040901795f6dc6be92f9ffc30cc808d31723f17'
name 'Shuttle'
homepage 'https://fitztrev.github.io/shuttle/'
license :mit
app 'Shuttle.app'
zap delete: '~/.shuttle.json'
end
```
And here is one for `airstream`. Note that it has an unversioned download (the download `url` does not contain the version number, unlike the example above). It also suppresses the checksum with `sha256 :no_check` (necessary since the checksum will change when a new distribution is made available). This combination of `version :latest` and `sha256 :no_check` is currently the preferred mechanism when a versioned download URL is not available.
```ruby
cask 'airstream' do
version :latest
sha256 :no_check
# amazonaws.com/airstream-clients was verified as official when first introduced to the cask
url 'https://s3-us-west-2.amazonaws.com/airstream-clients/mac/airstream-mac.dmg'
name 'AirStream'
homepage 'http://airstream.io/download/'
license :gratis
app 'AirStream.app'
caveats do
depends_on_java('6')
end
end
```
Here is a last example for `airdisplay`, which uses a `pkg` installer to install the application instead of a stand-alone application bundle (`.app`). Note the [`uninstall pkgutil` stanza](../cask_language_reference/stanzas/uninstall.md#uninstall-key-pkgutil), which is needed to uninstall all files which were installed using the installer.
```ruby
cask 'airdisplay' do
version '3.0.3'
sha256 'db84a66fe3522929a0afa58a4fe0189977baded89df0035ead1ccd334f7b8126'
url "https://www.avatron.com/updates/software/airdisplay/ad#{version.no_dots}.zip"
appcast 'https://avatron.com/updates/software/airdisplay/appcast.xml',
checkpoint: '938bdb9fbee793dce92818366cb2c19ba84c5b0cd6853fd893897d4a40689bc2'
name 'Air Display'
homepage 'https://avatron.com/apps/air-display/'
license :commercial
pkg 'Air Display Installer.pkg'
uninstall pkgutil: 'com.avatron.pkg.AirDisplay'
end
```
### Generating a Token for the Cask
The Cask **token** is the mnemonic string people will use to interact with the Cask via `brew cask install`, `brew cask search`, etc. The name of the Cask **file** is simply the token with the extension `.rb` appended.
The easiest way to generate a token for a Cask is to run this command:
```bash
$ "$(brew --repository)/Library/Taps/caskroom/homebrew-cask/developer/bin/generate_cask_token" '/full/path/to/new/software.app'
```
If the software you wish to Cask is not installed, or does not have an associated App bundle, just give the full proper name of the software instead of a pathname:
```bash
$ "$(brew --repository)/Library/Taps/caskroom/homebrew-cask/developer/bin/generate_cask_token" 'Google Chrome'
```
If the `generate_cask_token` script does not work for you, see [Cask Token Details](#cask-token-details).
### The `brew cask create` Command
Once you know the token, create your Cask with the handy-dandy `brew cask create` command:
```bash
$ brew cask create my-new-cask
```
This will open `$EDITOR` with a template for your new Cask, to be stored in the file `my-new-cask.rb`. Running the `create` command above will get you a template that looks like this:
```ruby
cask 'my-new-cask' do
version ''
sha256 ''
url ''
name ''
homepage ''
license :unknown # TODO: change license and remove this comment; ':unknown' is a machine-generated placeholder
app ''
end
```
### Cask Stanzas
Fill in the following stanzas for your Cask:
| name | value |
| ------------------ | ----------- |
| `version` | application version; give the value `:latest` if only an unversioned download is available
| `sha256` | SHA-256 checksum of the file downloaded from `url`, calculated by the command `shasum -a 256 <file>`. Can be suppressed by using the special value `:no_check`. (see [sha256](../cask_language_reference/stanzas/sha256.md))
| `url` | URL to the `.dmg`/`.zip`/`.tgz`/`.tbz2` file that contains the application.<br />A [comment](../cask_language_reference/stanzas/url.md#when-url-and-homepage-hostnames-differ-add-a-comment) should be added if the hostnames in the `url` and `homepage` stanzas differ. Block syntax should be used for URLs that change on every visit.<br />See [URL Stanza Details](../cask_language_reference/stanzas/url.md) for more information.
| `name` | the full and proper name defined by the vendor, and any useful alternate names (see [Name Stanza Details](../cask_language_reference/stanzas/name.md))
| `homepage` | application homepage; used for the `brew cask home` command
| `license` | a symbol identifying the license for the application. Valid category licenses include `:oss`, `:closed`, and `:unknown`. It is OK to leave as `:unknown`. (see [License Stanza Details](../cask_language_reference/stanzas/license.md))
| `app` | relative path to an `.app` bundle that should be moved into the `/Applications` folder on installation (see [App Stanza Details](../cask_language_reference/stanzas/app.md))
Other commonly-used stanzas are:
| name | value |
| ------------------ | ----------- |
| `appcast` | a URL providing an appcast feed to find updates for this Cask. (see [Appcast Stanza Details](../cask_language_reference/stanzas/appcast.md))
| `pkg` | relative path to a `.pkg` file containing the distribution (see [Pkg Stanza Details](../cask_language_reference/stanzas/pkg.md))
| `caveats` | a string or Ruby block providing the user with Cask-specific information at install time (see [Caveats Stanza Details](../cask_language_reference/stanzas/caveats.md))
| `uninstall` | procedures to uninstall a Cask. Optional unless the `pkg` stanza is used. (see [Uninstall Stanza Details](../cask_language_reference/stanzas/uninstall.md))
Additional `artifact` stanzas you might need for special use-cases can be found [here](../cask_language_reference/all_stanzas.md#at-least-one-artifact-stanza-is-also-required). Even more special-use stanzas are listed at [Optional Stanzas](../cask_language_reference/all_stanzas.md#optional-stanzas).
### Cask Token Details
If a token conflicts with an already-existing Cask, authors should manually make the new token unique by prepending the vendor name. Example: [unison.rb](../../Casks/unison.rb) and [panic-unison.rb](../../Casks/panic-unison.rb).
If possible, avoid creating tokens which differ only by the placement of hyphens.
To generate a token manually, or to learn about exceptions for unusual cases, see [token_reference.md](../cask_language_reference/token_reference.md).
### Archives With Subfolders
When a downloaded archive expands to a subfolder, the subfolder name must be included in the `app` value.
Example:
1. Texmaker is downloaded to the file `TexmakerMacosxLion.zip`.
2. `TexmakerMacosxLion.zip` unzips to a folder called `TexmakerMacosxLion`.
3. The folder `TexmakerMacosxLion` contains the application `texmaker.app`.
4. So, the `app` stanza should include the subfolder as a relative path:
```ruby
app 'TexmakerMacosxLion/texmaker.app'
```
## Testing Your New Cask
Give it a shot with `brew cask install my-new-cask`.
Did it install? If something went wrong, `brew cask uninstall my-new-cask` and edit your Cask with `brew cask edit my-new-cask` to fix it.
If everything looks good, youll also want to make sure your Cask passes audit with:
```bash
brew cask audit my-new-cask --download
```
You should also check stylistic details with `brew cask style`:
```bash
$ cd "$(brew --repository)"/Library/Taps/caskroom/homebrew-cask
$ brew cask style Casks/my-new-cask.rb [--fix]
```
Keep in mind all of these checks will be made when you submit your PR, so by doing them in advance youre saving everyone a lot of time and trouble.
If your application and Homebrew-Cask do not work well together, feel free to [file an issue](https://github.com/caskroom/homebrew-cask#reporting-bugs) after checking out open issues.
## Finding a Home For Your Cask
We maintain separate Taps for different types of binaries. Our nomenclature is:
+ **Stable**: The latest version provided by the developer defined by them as such.
+ **Beta, Development, Unstable**: Subsequent versions to **stable**, yet incomplete and under development, aiming to eventually become the new **stable**.
+ **Nightly**: Constantly up-to-date versions of the current development state.
+ **Legacy**: Any **stable** version that is not the most recent.
+ **Alternative**: Alternative edition of an existing app, by the same vendor (developer editions, community editions, pro editions, …).
+ **Regional, Localized**: Any version that isnt the US English one, when that exists.
+ **Trial**: Date-limited version that stops working entirely after it expires, requiring payment to lift the limitation.
+ **Freemium**: Gratis version that works indefinitely but with limitations that can be removed by paying.
+ **Fork**: An alternate version of an existing project, with a based-on but modified source and binary.
+ **Unofficial**: An *allegedly* unmodified compiled binary, by a third-party, of a binary that has no existing build by the owner of the source code.
+ **Vendorless**: A binary distributed without an official website, like a forum posting.
+ **Walled**: When the download URL is both behind a login/registration form and from a host that differs from the homepage.
### Stable Versions
Stable versions live in the main repository at [caskroom/homebrew-cask](https://github.com/caskroom/homebrew-cask). They should run on the latest release of macOS or the previous point release (in 2015, for example, that meant El Capitan and Yosemite).
### But There Is No Stable Version!
When an App is only available as beta, development, or unstable versions, or in cases where such a version is the general standard, then said version can go into the main repo.
### Beta, Unstable, Development, Nightly, Legacy, or Alternative Versions
When an App has a principal stable version, alternative versions should be submitted to [caskroom/homebrew-versions](https://github.com/caskroom/homebrew-versions).
### Regional and Localized
When an App exists in more than one language or has different regional editions, the US English one belongs in the main repo, and all the others in [caskroom/homebrew-versions](https://github.com/caskroom/homebrew-versions). When not already part of the name of the App, a [regional identifier](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) and a [language code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) are to be appended to the Casks token (both when available, or just the appropriate one when not).
### Trial and Freemium Versions
Before submitting a trial, make sure it can be made into a full working version without the need to be redownloaded. If an App provides a trial but the only way to buy the full version is via the Mac App Store, it does not belong in any of the official repos. Freemium versions are fine.
### Forks and Apps with Conflicting Names
Forks should have the vendors name as a prefix on the Casks file name and token. For unrelated Apps that share a name, the most popular one (usually the one already present) stays unprefixed. Since this can be subjective, if you disagree with a decision open an issue and make your case to the maintainers.
### Unofficial, Vendorless, and Walled Builds
We do not accept these casks since they offer a higher-than-normal security risk. [alehouse/homebrew-unofficial](https://github.com/alehouse/homebrew-unofficial) is a sister repo where you may wish to submit your cask.
### Fonts
Font Casks live in the [caskroom/homebrew-fonts](https://github.com/caskroom/homebrew-fonts) repository. See the font repo [CONTRIBUTING.md](../../../../../homebrew-fonts/blob/master/CONTRIBUTING.md)
for details.
## Submitting Your Changes
Hop into your Tap and check to make sure your new Cask is there:
```bash
$ cd "$(brew --repository)"/Library/Taps/caskroom/homebrew-cask
$ git status
# On branch master
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# Casks/my-new-cask.rb
```
So far, so good. Now make a feature branch that youll use in your pull request:
```bash
$ git checkout -b my-new-cask
Switched to a new branch 'my-new-cask'
```
Stage your Cask with `git add Casks/my-new-cask.rb`. You can view the changes that are to be committed with `git diff --cached`.
Commit your changes with `git commit -v`.
### Commit Messages
For any git project, some good rules for commit messages are:
* The first line is commit summary, 50 characters or less,
* Followed by an empty line,
* Followed by an explanation of the commit, wrapped to 72 characters.
See [a note about git commit messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) for more.
The first line of a commit message becomes the **title** of a pull request on GitHub, like the subject line of an email. Including the key info in the first line will help us respond faster to your pull.
For Cask commits in the Homebrew-Cask project, we like to include the Application name, version number (or `:latest`), and purpose of the commit in the first line.
Examples of good, clear commit summaries:
* `Add Transmission.app v1.0`
* `Upgrade Transmission.app to v2.82`
* `Fix checksum in Transmission.app Cask`
* `Add CodeBox Latest`
Examples of difficult, unclear commit summaries:
* `Upgrade to v2.82`
* `Checksum was bad`
### Pushing
Push your changes to your GitHub account:
```bash
$ github_user='<my-github-username>'
$ git push "$github_user" my-new-cask
```
If you are using [GitHub two-factor authentication](https://help.github.com/articles/about-two-factor-authentication/) and set your remote repository as HTTPS you will need to set up a personal access token and use that instead of your password. Further information [here](https://help.github.com/articles/https-cloning-errors/#provide-access-token-if-2fa-enabled).
### Squashing
If your pull request has multiple commits which revise the same lines of code, or if you make some changes after comments from one of the maintainers, it is better to [squash](https://davidwalsh.name/squash-commits-git) those commits together into one logical unit.
But you dont always have to squash — it is fine for a pull request to contain multiple commits when there is a logical reason for the separation.
### Filing a Pull Request on GitHub
Now go to the [`homebrew-cask` GitHub repository](https://github.com/caskroom/homebrew-cask). GitHub will often show your `my-new-cask` branch with a handy button to `Compare & pull request`. Otherwise, click the `New pull request` button and choose to `compare across forks`. The base fork should be `caskroom/homebrew-cask @ master`, and the head fork should be `my-github-username/homebrew-cask @ my-new-cask`. You can also add any further comments to your pull request at this stage.
Congratulations! You are done now, and your Cask should be pulled in or otherwise noticed in a while. If a maintainer suggests some changes, just make them on the `my-new-cask` branch locally, [squash](#squashing), and [push](#pushing).
## Cleaning up
After your Pull Request is submitted, you should get yourself back onto `master`, so that `brew update` will pull down new Casks properly:
```bash
cd "$(brew --repository)"/Library/Taps/caskroom/homebrew-cask
git checkout master
```

View File

@ -0,0 +1,160 @@
# Hacking on Homebrew-Cask
If youd like to hack on the Ruby code that drives this project, please join us, wed love to have you!
## Goals, Design, and Philosophy
Homebrew-Cask is an attempt to make a Linux-style package manager for precompiled macOS software. Homebrew-Cask is not yet as featureful as `apt` or `yum`, but we are trying to be as close as we can get to those tools from the users point of view.
We manage installed files via the “symlink farm” method, like [GNU Stow](https://www.gnu.org/software/stow/) and [Homebrew](http://brew.sh/). Similarly, we try to avoid `sudo` where possible.
Homebrew-Cask is designed to work like a traditional Unix tool:
* All functionality should be accessible from the CLI. The user should be freed (**freed!**) from interacting with a GUI.
* Homebrew-Cask should itself be scriptable.
## Project Status
Homebrew-Cask is still young, and should be considered in alpha.
We have good support for a variety of artifacts: apps, pkgs, binaries, plugins, and [fonts](https://github.com/caskroom/homebrew-fonts/). Homebrew-Cask can install and uninstall any of those. However, these commands dont work well with multiple versions, and most importantly, we currently cant `upgrade`.
Since upgrading is a core feature of every package manager, the implementation of an `upgrade` verb is our top priority. For `upgrade` to work reliably, we must:
* Maintain unequivocal version information from a variety of sources,
* Track version-specific uninstallation,
* Play nice with self-updating software.
These and more requirements are tracked in our [`upgrade` roadmap](https://github.com/caskroom/homebrew-cask/issues/4678). If youd like to contribute to `upgrade`, thats an excellent place to start.
## Homebrew and Homebrew-Cask
Homebrew-Cask is independent of Homebrew as a project.
The Homebrew-Cask CLI is implemented as a Homebrew subcommand, so we try to match semantics wherever possible. That means that similar functionality should have similar flags and parameters.
However, very little backend code is shared between the two projects. The Homebrew codebase is based on how Homebrew Formulae work, and our Casks are very different from Formulae.
### Casks and Formulae
Homebrew Formulae deal with many different build processes, and often include arbitrary Ruby code.
Casks, by contrast, only need to support the few installation methods used by apps, pkg installers, and so on, making them suitable for a [declarative DSL](../cask_language_reference/).
We encourage Cask authors to use the DSL as much as possible, since that makes things easier for everyone: from maintainers who review pull requests, to first-time contributors, to people who are unfamiliar with Ruby but would like to help.
For software with unusual needs that are not covered by the DSL, we generally accept Casks containing small hacks or arbitrary code. If the hack becomes common enough, we extend the DSL with a simple shorthand that offers the same (or better) functionality.
## Contributing
### Setup
Cask authors often work directly within the Homebrew directory under `/usr/local`. For coding, that is usually not sufficient.
We recommend the following:
1. Fork our repo: <https://github.com/caskroom/homebrew-cask/fork>
2. Clone a private copy of the repo:
```bash
git clone https://github.com/<username>/homebrew-cask.git
```
3. Add the official repo as the `upstream` remote:
```bash
cd homebrew-cask
git remote add upstream https://github.com/caskroom/homebrew-cask.git
```
4. Now you have two copies of the Homebrew-Cask codebase on disk: the released version in `/usr/local/Library/Taps/caskroom/homebrew-cask`, and a development version in your private repo. To symlink the `Casks` and `rubylib` folders from `/usr/local/...` into your private repo, run the following script:
```bash
/<path>/<to>/<private>/<repo>/developer/bin/develop_brew_cask
```
Now you can hack on your private repo, and use the `brew cask` CLI like normal — it will interact with your latest code.
5. Important: while in development mode, you cant safely run Homebrews `brew update` command. To switch back to production mode, run:
```bash
/<path>/<to>/<private>/<repo>/developer/bin/production_brew_cask
```
### Forcing a Ruby interpreter
You can force a specific version of the Ruby interpreter, and/or an alternate version of the `brew-cask` subcommand, by invoking `brew cask` with fully-qualified paths, like this:
```bash
$ /System/Library/Frameworks/Ruby.framework/Versions/Current/usr/bin/ruby /usr/local/Library/Taps/caskroom/homebrew-cask/cmd/brew-cask.rb help
```
### Forcing a Specific Homebrew-Cask Subcommand
If you are developing a subcommand, you can force `brew cask` to dispatch a specific file by giving a fully-qualified path to the file containing the subcommand, like this:
```bash
$ brew cask /usr/local/Library/Taps/caskroom/homebrew-cask/lib/hbc/cli/info.rb google-chrome
```
This form can also be combined with a specific Ruby interpreter as above.
### Forcing a Specific macOS Release
The environment variable `$MACOS_RELEASE` can be overridden at the command line for test purposes:
```bash
$ MACOS_RELEASE=10.9 brew cask info <cask>
```
The environment variable `$MACOS_RELEASE_WITH_PATCHLEVEL` is also available, though not consulted directly. Use `$MACOS_RELEASE` for testing.
### Target Ruby Versions
Homebrew-Cask requires a Ruby interpreter version 2.0 or above. This is the default system Ruby on Mavericks (10.9) and later.
### Submitting Your Changes
See [the relevant section in `adding_a_cask.md`](adding_a_cask.md#submitting-your-changes).
#### Commit Messages
The first line of a commit message (the summary line) is like the subject line of an email. (See [`adding_a_cask.md`](adding_a_cask.md#commit-messages)). A short but complete summary line helps the maintainers respond to your pull request more quickly.
#### Mind the test suite!
If youre making changes - please write some tests for them! Install dependencies and run the whole test suite with:
```bash
brew cask-tests
```
Be sure to run the test suite before submitting. If you forget, Travis-CI will do that for you and embarrass you in front of all your friends. :)
You may also use a set of environment variables to increase verbosity:
* `TESTOPTS`, `TEST` etc. for the old [minitest suites](https://www.ruby-doc.org/stdlib-2.0.0/libdoc/rake/rdoc/Rake/TestTask.html)
* `SPEC_OPTS`, `SPEC` etc. for [rspec suites](http://apidock.com/rspec/Spec/Rake/SpecTask)
* `VERBOSE_TESTS` to see the standard output from the actual code = ignore the `shutup` helper
Example of a very verbose output:
```shell
TESTOPTS='-v' SPEC_OPTS='-fd' VERBOSE_TESTS=1 brew cask-tests
```
#### External Commands
Advanced users may create their own external commands for Homebrew-Cask by following conventions similar to external commands for git or Homebrew. An external command may be any executable on your `$PATH` which follows the form `brewcask-<command>`. (So long as `<command>` does not conflict with an existing command verb.) The command will be invoked by `exec` and passed any unprocessed arguments from the original command-line. An external command may also be implemented as an executable Ruby file, on your `$PATH`, which follows the form `brewcask-<command>.rb`. The Ruby file will be `required` and will have full access to the Ruby environments of both Homebrew-Cask and Homebrew. Example external commands may be found in `developer/examples`.
## Hanging out on IRC
Were on IRC at `#homebrew-cask` on Freenode. If you are going to develop for Homebrew-Cask, its a great idea to hang out with us there. Heres why:
* Discuss your thoughts before coding and maybe get new ideas
* Get feedback from the Travis-CI bot on build failures
* Talk to [caskbot](https://github.com/passcod/caskbot) about checksums, version info, and releases
* Just to be social!
# <3 THANK YOU! <3

View File

@ -0,0 +1,79 @@
# Maintaining Homebrew-Cask
__vv NOTE - DRAFT DOC! vv__
This doc is just at a starting point. The maintainers team will be collaborating on it and well remove this header when we feel like its stable.
__^^ NOTE - DRAFT DOC! ^^__
As a relatively large open source project with plenty of daily activity, Homebrew-Cask requires regular care and feeding. This includes reviewing and merging PRs, diagnosing bugs, improving documentation, discussing project policy and features, and plenty more!
This responsibility is shared by @caskroom/maintainers - a team of humans spanning the globe each of whom has agreed to dedicate some of their spare time to helping our dear users. What a kind and friendly bunch they must be! (Its true, they are.)
As the project matures and grows, so does the team of maintainers. Its becoming more and more important to write down things that once were done ad-hoc.
So here is where we are gathering details about how we maintain the project.
## Things we focus on
* We favor the user above all.
* Any user that submits a PR to our little old project is solid gold - we do everything we can to make sure they have a good experience and that their work is appreciated.
* Friendliness. In our minds, we are in a *friendliness contest* against other open-source projects. We want to be the nicest, most fun, most easygoing project in the universe.
* Supporting each other. Help the other maintainers, and spread out the workload.
## Reviewing Incoming Casks
Casks are the lifeblood of this project, and they generate the most maintenance-requiring activity on the project.
While we started as a tool for convenience, were working on adding safety and security to the list of things we do for our users. That means things like verifying download URLs, working to figure out file checksums when possible, *etc*.
__TODO__: Maybe one of our more active Cask reviewers can fill in the things they look for in incoming Casks.
## Labels
Every open issue and pull request must have a label added to it, unless the maintainer immediately acts on it (closing/merging) after looking at it. Labels should be consistent across repositories: not every repository needs every label, but their meaning and color must be the same throughout. Currently, our labels are:
Label | Description | Issues | Pull Requests
----- | ----------- | :----: | :-----------:
**bug** | Something isnt working as expected. A modification/addition/removal. Must always be accompanied by **cask** or **core** | &#x2713; | &#x2713;
**cask** | Relates directly to a cask. Must always be accompanied by **bug** or **enhancement**. | &#x2713; | &#x2713;
**cask request** | Either a request for a new cask or a call for correction in an existing one. | &#x2713; |
**outdated appcast** | An automated label, handled by the various scripts geared towards updating casks with outdated appcasts. Should never be applied manually. | &#x2713; | &#x2713;
**chief bug** | When multiple people open new issues for the same bug, the main issue where its progression is being tracked should have this label. Every other one should be marked **duplicate** and closed. | &#x2713; |
**core** | Relates directly to the code of the core, Homebrew-Cask itself. Must always be accompanied by **bug** or **enhancement**. | &#x2713; | &#x2713;
**discussion** | A matter that benefits from discussion before a decision is to be made. Any opinion should be given by users and maintainers alike, even if that opinion is “I have no strong feelings on the matter”. | &#x2713; |
**documentation** | Relates to the documentation. | &#x2713; | &#x2713;
**duplicate** | An issue or pull request that is essentially the same as another. Should be immediately closed. | &#x2713; | &#x2713;
**enhancement** | Something we want implemented. Must always be accompanied by **cask** or **core**. | &#x2713; | &#x2713;
**future** | Something that can currently only be referenced and will only be possible to act upon in the future, after certain conditions are met. Currently references [changes to the installation behaviour](https://github.com/caskroom/homebrew-cask/issues/13201). To be used sparingly. | &#x2713; | &#x2713;
**meta** | Relates to Homebrew-Cask itself as a project and its policies/decisions. | &#x2713; |
**on hold** | A pull request that depends on another being merged before it itself can be as well. | | &#x2713;
**roadmap** | Roadmap for feature implementation. | &#x2713; |
**ready to implement** | Usually accompanied by the closing of a **discussion** issue. It succinctly describes in points the implementation of something yet to be written, be it a feature or a documentation section. Anyone looking at such an issue can safely ignore every post following the top one, as it should always be kept up-to-date with the discussion. | &#x2713; |
**travis** | Bug related to [Travis CI](https://travis-ci.org/). Must always be accompanied by **bug** or **enhancement**. | &#x2713; | &#x2713;
**upstream** | Something we have no hand in, and can only be fixed with intervention from developers outside Homebrew-Cask. Always refers to a cask, and never to the core. | &#x2713; | &#x2713;
**awaiting maintainer feedback** | A maintainer requires input from other maintainers to proceed. Other maintainers should occasionaly check this label and give their feedback on the subject, if able. | &#x2713; | &#x2713;
**awaiting user reply** | A maintainer requires further action or information from the original poster to proceed. Particularly useful to weed out those cases where issues and pull requests would otherwise be left open indefinitely because the original poster never replies. | &#x2713; | &#x2713;
## Reviewing Core PRs
Occasionally well get submissions from users that fix bugs or add features to Homebrew-Cask itself. There is a subset of our maintainers who are less familiar with Ruby and prefer to leave these review to folks with more experience with the language. This is AOK!
## Handling Cask Update PRs
The most common pull requests we get are to add or update Casks. [Vítor Galvão](https://github.com/vitorgalvao) has created [some excellent scripts](https://github.com/vitorgalvao/tiny-scripts) to make these rote changes more painless. You can use [`fastmerge`](https://github.com/vitorgalvao/tiny-scripts/blob/master/fastmerge) if the PR is ready to merge (everything looks fine, all tests passed). Sometimes, new contributors aren't aware of how to squash commits, posting something like “Please [squash your commits](https://davidwalsh.name/squash-commits-git). Thanks!” should help them out.
If the PR has an error, you can use [`prfixmaster`](https://github.com/vitorgalvao/tiny-scripts/blob/master/prfixmaster) to make any necessary changes.
Lastly, if you see an outdated cask that just needs a version bump, you can use [`cask-repair`](https://github.com/vitorgalvao/tiny-scripts/blob/master/cask-repair) to make the PR yourself quickly.
## Tips
* To keep your repository up to date with caskroom/master, you can create a custom bash function to save some typing. Feel free to adapt the following set of commands to your specific needs --> `cd "$(brew --repository)"/Library/Taps/caskroom/homebrew-cask; git checkout master; git pull origin; git push "$GITHUB_USERNAME" master; git remote prune origin; git fetch -p origin; git remote update --prune`
## Ideas for other things to include here
* Productivity enhancing tips / tools / scripts that help with PR review, cask testing, etc.
* General policies.
* Documenting important decisions that have been made.
* Maybe some philosophical points about the project.

View File

@ -0,0 +1,13 @@
# Apps that bundle malware
Unfortunately, in the world of software there are bad actors that bundle malware with their apps. Even so, Homebrew-Cask has long decided it is not a gatekeeper ([macOS already has one](https://support.apple.com/en-us/HT202491)) and [users are expected to know about the software they are installing](not_a_discoverability_service.md). This means we will not remove casks that link to these apps. We have several reasons for this, summarised in [a comment on issue #21399](https://github.com/caskroom/homebrew-cask/issues/21399#issuecomment-223148829).
Within that context, we would still like for users to enjoy some kind of protection while minimising occurrences of legitimate developers being branded as malware carriers. We feel removing casks is an ineffective band-aid and the issue needs to be tackled earlier in the chain: at the macOS level.
If an app that bundles malware was not signed with an Apple Developer ID and you purposefully disabled or bypassed Gatekeeper, no action will be taken on our part. When you disable security features, you do so at your own risk. If, however, an app that bundles malware is signed, Apple can revoke its permissions and it will no longer run on the computers of users that keep security features on — we all benefit, Homebrew-Cask users or not. **Note that for the time being, Homebrew-Cask will not quarantine download files. See [issue #22388](https://github.com/caskroom/homebrew-cask/issues/22388)**.
To report a signed app that bundles malware, follow these steps:
* Go to [Apples Bug Reporter](https://bugreport.apple.com/) and report the app that bundles malware. Be as precise as possible about how you know it bundles malware, and what steps reproduce your conclusions. Be sure to include relevant URLs, such as the apps homepage.
* Make the report public at [Open Radar](http://www.openradar.me/).
* Submit a pull request with a [`malware` `caveat`](https://github.com/caskroom/homebrew-cask/blob/master/doc/cask_language_reference/stanzas/caveats.md#caveats-mini-dsl).

View File

@ -0,0 +1,15 @@
# Homebrew-Cask is not a discoverability service
Ever since the inception of Homebrew-Cask, various requests fell under the umbrella of this reply. Though a somewhat popular request, after careful consideration on multiple occasions weve always come back to the same conclusion: were not a discoverability service and our users are expected to have reasonable knowledge about the apps theyre installing through us before doing so.
Examples of requests under this same theme:
+ [Separate by categories](https://github.com/caskroom/homebrew-cask/issues/5425).
+ [Rank by popularity](https://github.com/caskroom/homebrew-cask/issues/4323).
+ [Add descriptions](https://github.com/caskroom/homebrew-cask/issues/16089).
Amongst other things, the logistics of such requests are unsustainable for Homebrew-Cask. Before making a request of this nature, you must read through those issues, as well as any other issues they link to, to get a full understanding of why that is the case, and why “but project *x* does *y*” arguments arent applicable, and not every package manager is the same.
You should also be able to present clear actionable fixes to those concerns. Simply asking for it without solutions will get your issue closed.
There is a difference between discoverability and searchability, however, and while the former (finding new apps you didnt know about) is unlikely to ever become part of our goals, the later (identifying the app you know about and want to install) is indeed important to us, and we continue to work on it.

View File

@ -0,0 +1,19 @@
# Rejected Casks
Before submitting a Cask to any of our repos, you must read [our documentation on acceptable Casks](../development/adding_a_cask.md#finding-a-home-for-your-cask) and perform a (at least quick) search to see if there were any previous attempts to introduce it.
Common reasons to reject a Cask entirely:
+ We have strong reasons to believe including the Cask can put the whole project at risk. Happened only once so far, [with Popcorn Time](https://github.com/caskroom/homebrew-cask/pull/3954).
+ The app is a trial version, and the only way to acquire the full version is through the Mac App Store ([documented](../development/adding_a_cask.md#trial-and-freemium-versions)).
+ Similarly (and trickier to spot), the app has moved to the Mac App Store but still provides old versions via direct download. We reject these in all official repos so users dont get stuck using an old version, wrongly thinking theyre using the most up-to-date one (which, amongst other things, might be a security risk).
+ The app is both open-source and CLI-only (i.e. it only uses the `binary` artifact). In that case, and [in the spirit of deduplication](https://github.com/caskroom/homebrew-cask/issues/15603), submit it first to [Homebrew](https://github.com/Homebrew/homebrew). If it is rejected there, you may then try again in Homebrew-Cask (link us to the issue on Homebrew so we can see their reasoning for rejection).
+ The app is open-source and has a GUI but no compiled versions (or only old ones) are provided. Its better to have them in [Homebrew](https://github.com/Homebrew/homebrew) so users dont get perpetually outdated versions. Examples include [`mpv`](https://github.com/caskroom/homebrew-cask/pull/20483) and [`gedit`](https://github.com/caskroom/homebrew-cask/pull/23360).
+ The app has been rejected before due to an issue we cannot fix, and this new submission doesnt fix that . An example would be [the first submission of `soapui`](https://github.com/caskroom/homebrew-cask/pull/4939), whose installation problems were not fixed in the two subsequent submissions ([#9969](https://github.com/caskroom/homebrew-cask/pull/9969), [#10606](https://github.com/caskroom/homebrew-cask/pull/10606)).
+ The Cask is a duplicate. These submissions mostly occur when the [token reference](../cask_language_reference/token_reference.md) was not followed.
+ The download URL for the app is both behind a login/registration form and from a host that differs from the homepage, meaning users cant easily verify its authenticity. [alehouse/homebrew-unofficial](https://github.com/alehouse/homebrew-unofficial) is a sister repo where you may wish to submit your cask.
+ The author has [specifically asked us not to include it](https://github.com/caskroom/homebrew-cask/pull/5342).
Common reasons to reject a Cask from the main repo:
+ The app is an alternate edition or a legacy or development version of a Cask already in the main repo, and as such should be submitted to [caskroom/versions](https://github.com/caskroom/homebrew-versions) ([documented](../development/adding_a_cask.md#beta-unstable-development-nightly-legacy-or-alternative-versions)). Common offenders include [Sublime Text 3](https://github.com/caskroom/homebrew-cask/search?utf8=%E2%9C%93&q=sublime+text+3&type=Issues) and [Firefox Developer Edition](https://github.com/caskroom/homebrew-cask/search?q=firefox+developer+edition&type=Issues&utf8=%E2%9C%93).

View File

@ -0,0 +1,27 @@
Bug report:
Remember to follow the [pre bug report](https://github.com/caskroom/homebrew-cask/blob/master/doc/reporting_bugs/pre_bug_report.md) guide beforehand. Failure to do so might get your issue closed.
#### Description of issue
[insert a detailed description of your issue here]
<details><summary>Output of `brew cask <command> --verbose`</summary>
```
[paste output here]
```
</details>
<details><summary>Output of `brew doctor`</summary>
```
[paste output here]
```
</details>
<details><summary>Output of `brew cask doctor`</summary>
```
[paste output here]
```
</details>

View File

@ -0,0 +1,14 @@
Cask request:
### Cask details
(Please fill out as much as possible)
**Name** -
**Homepage** -
**License** -
**Download URL** -
**Description** -

View File

@ -0,0 +1,13 @@
Feature request:
### Description of feature/enhancement
### Justification
### Example use case

View File

@ -0,0 +1,8 @@
Dead app:
* Insert the name of the cask in the title, after the `:`.
* Insert the name of the cask and a link to it in the body of this issue (example: [`alfred`](https://github.com/caskroom/homebrew-cask/blob/master/Casks/alfred.rb)).
* Insert a link to the page that informs about the app being dead.
* After all that **delete all this pre-inserted template text**.
Failure to follow these instructions may get your issue closed without further explanation. Thank you for taking the time to correctly report the issue.

View File

@ -0,0 +1,8 @@
Outdated cask:
* Insert the name of the cask in the title, after the `:`.
* Insert the name of the cask and a link to it in the body of this issue (example: [`alfred`](https://github.com/caskroom/homebrew-cask/blob/master/Casks/alfred.rb)).
* Insert the new version of the app.
* After all that **delete all this pre-inserted template text**.
Failure to follow these instructions may get your issue closed without further explanation. Thank you for taking the time to correctly report the issue.

View File

@ -0,0 +1,8 @@
Outdated cask but cannot find link:
* Insert the name of the cask in the title, after the `:`.
* Insert the name of the cask and a link to it in the body of this issue (example: [`alfred`](https://github.com/caskroom/homebrew-cask/blob/master/Casks/alfred.rb)).
* Insert a detailed explanation of what you tried to do and why you failed to find the download link.
* After all that **delete all this pre-inserted template text**.
Failure to follow these instructions may get your issue closed without further explanation. Thank you for taking the time to correctly report the issue.

View File

@ -0,0 +1,8 @@
Source not there and cannot find it:
* Insert the name of the cask in the title, after the `:`.
* Insert the name of the cask and a link to it in the body of this issue (example: [`alfred`](https://github.com/caskroom/homebrew-cask/blob/master/Casks/alfred.rb)).
* Insert a detailed explanation of what you tried to do and why you failed to find the new artifact source.
* After all that **delete all this pre-inserted template text**.
Failure to follow these instructions may get your issue closed without further explanation. Thank you for taking the time to correctly report the issue.

View File

@ -0,0 +1,267 @@
brew-cask(1) - a friendly binary installer for macOS
========================================================
## SYNOPSIS
`brew cask` command [options] [ <token> ... ]
## DESCRIPTION
Homebrew-Cask is a tool for installing precompiled macOS binaries (such as
Applications) from the command line. The user is never required to use the
graphical user interface.
## ALPHA-QUALITY SOFTWARE
Homebrew-Cask works robustly enough that we welcome new users, but the
project is still in early development. That means command names, option
names, and other aspects of this manual are still subject to change.
## FREQUENTLY USED COMMANDS
* `install [--force] [--skip-cask-deps] [--require-sha]` <token> [ <token> ... ]:
Install Cask identified by <token>.
* `uninstall [--force]` <token> [ <token> ... ]:
Uninstall Cask identified by <token>.
* `search` <text> | /<regexp>/:
Perform a substring search of known Cask tokens for <text>. If the text
is delimited by slashes, it is interpreted as a Ruby regular expression.
The tokens returned by `search` are suitable as arguments for most other
commands, such as `install` or `uninstall`.
## COMMANDS
* `audit` [ <token> ... ]:
Check the given Casks for installability.
If no tokens are given on the command line, all Casks are audited.
* `cat` <token> [ <token> ... ]:
Dump the given Cask definition file to the standard output.
* `cleanup` [--outdated]:
Clean up cached downloads and tracker symlinks. With `--outdated`,
only clean up cached downloads older than 10 days old.
* `create` <token>:
Generate a Cask definition file for the Cask identified by <token>
and open a template for it in your favorite editor.
* `doctor` or `dr`:
Check for configuration issues. Can be useful to upload as a gist for
developers along with a bug report.
* `edit` <token>:
Open the given Cask definition file for editing.
* `fetch` [--force] <token> [ <token> ... ]:
Download remote application files for the given Cask to the local
cache. With `--force`, force re-download even if the files are already
cached.
* `home` or `homepage` [ <token> ... ]:
Display the homepage associated with a given Cask in a browser.
With no arguments, display the project page <http://caskroom.io>.
* `info` or `abv` <token> [ <token> ... ]:
Display information about the given Cask.
* `install [--force] [--skip-cask-deps] [--require-sha]` <token> [ <token> ... ]:
Install the given Cask. With `--force`, re-install even if the Cask
appears to be already present. With `--skip-cask-deps`, skip any Cask
dependencies. `--require-sha` will abort installation if the Cask does not
have a checksum defined.
<token> is usually the ID of a Cask as returned by `brew cask search`,
but see [OTHER WAYS TO SPECIFY A CASK][] for variations.
* `list` or `ls` [-1 | -l] [ <token> ... ]:
Without any arguments, list all installed Casks. With `-1`, always
format the output in a single column. With `-l`, give a more detailed
listing.
If <token> is given, summarize the staged files associated with the
given Cask.
* `search` or `-S`:
Display all Casks available for install.
* `search` or `-S` <text> | /<regexp>/:
Perform a substring search of known Cask tokens for <text>. If the text
is delimited by slashes, it is interpreted as a Ruby regular expression.
* `style` [--fix] [ <token> ... ]:
Check the given Casks for correct style using [RuboCop Cask](https://github.com/caskroom/rubocop-cask).
If no tokens are given on the command line, all Casks are checked.
With `--fix`, auto-correct any style errors if possible.
* `uninstall [--force]` or `rm` or `remove` <token> [ <token> ... ]:
Uninstall the given Cask. With `--force`, uninstall even if the Cask
does not appear to be present.
Note that `uninstall --force` is currently imperfect. It will follow
the `uninstall` instructions from *newest* Cask definition, even if
the given Cask has changed since you installed it. The result is that
`uninstall --force` will always succeed in removing relevant files
under `<Caskroom_path>`, but will sometimes fail to remove relevant
installed files outside of it. This issue is being
addressed.
`uninstall` without `--force` is also imperfect. It may be unable to
perform an `uninstall` operation if the given Cask has changed since you
installed it. This issue is being addressed.
* `update`:
For convenience. `brew cask update` is a synonym for `brew update`.
* `zap` <token> [ <token> ... ]:
Unconditionally remove _all_ files associated with the given Cask.
Implicitly performs all actions associated with `uninstall`, even if
the Cask does not appear to be currently installed.
Removes all staged versions of the Cask distribution found under
`<Caskroom_path>/<token>`.
If the Cask definition contains a `zap` stanza, performs additional
`zap` actions as defined there, such as removing local preference
files. `zap` actions are variable, depending on the level of detail
defined by the Cask author.
**`zap` may remove files which are shared between applications.**
## OPTIONS
To make these options persistent, see the ENVIRONMENT section, below.
Some of these (such as `--prefpanedir`) may be subject to removal
in a future version.
* `--force`:
Force an install to proceed even when a previously-existing install
is detected.
* `--skip-cask-deps`:
Skip Cask dependencies when installing.
* `--require-sha`:
Abort Cask installation if the Cask does not have a checksum defined.
* `--caskroom=<path>`:
Location of the Caskroom, where all binaries are stored. The default value is: `$(brew --repository)/Caskroom`.
* `--verbose`:
Give additional feedback during installation.
* `--appdir=<path>`:
Target location for Applications. The default value is `/Applications`.
* `--colorpickerdir=<path>`:
Target location for Color Pickers. The default value is `~/Library/ColorPickers`.
* `--prefpanedir=<path>`:
Target location for Preference Panes. The default value is `~/Library/PreferencePanes`.
* `--qlplugindir=<path>`:
Target location for QuickLook Plugins. The default value is `~/Library/QuickLook`.
* `--fontdir=<path>`:
Target location for Fonts. The default value is `~/Library/Fonts`.
* `--servicedir=<path>`:
Target location for Services. The default value is `~/Library/Services`.
* `--input_methoddir=<path>`:
Target location for Input Methods. The default value is `~/Library/Input Methods`.
* `--internet_plugindir=<path>`:
Target location for Internet Plugins. The default value is `~/Library/Internet Plug-Ins`.
* `--audio_unit_plugindir=<path>`:
Target location for Audio Unit Plugins. The default value is `~/Library/Audio/Plug-Ins/Components`.
* `--vst_plugindir=<path>`:
Target location for VST Plugins. The default value is `~/Library/Audio/Plug-Ins/VST`.
* `--vst3_plugindir=<path>`:
Target location for VST3 Plugins. The default value is `~/Library/Audio/Plug-Ins/VST3`.
* `--screen_saverdir=<path>`:
Target location for Screen Savers. The default value is `~/Library/Screen Savers`.
* `--no-binaries`:
Do not link "helper" executables to `/usr/local/bin`.
* `--debug`:
Output debugging information of use to Cask authors and developers.
## INTERACTION WITH HOMEBREW
Homebrew-Cask is implemented as a external command for Homebrew. That means
this project is entirely built upon the Homebrew infrastructure. For
example, upgrades to the Homebrew-Cask tool are received through Homebrew:
brew update; brew cleanup; brew cask cleanup
And updates to individual Cask definitions are received whenever you issue
the Homebrew command:
brew update
## OTHER WAYS TO SPECIFY A CASK
Most Homebrew-Cask commands can accept a Cask token as an argument. As
described above, the argument can take the form of:
* A token as returned by `brew cask search`, _eg_ `google-chrome`
Homebrew-Cask also accepts three other forms in place of plain tokens:
* A fully-qualified token which includes the Tap name, _eg_
`caskroom/fonts/font-symbola`
* A fully-qualified pathname to a Cask file, _eg_
`/usr/local/Library/Taps/caskroom/homebrew-cask/Casks/google-chrome.rb`
* A `curl`-retrievable URI to a Cask file, _eg_
`https://raw.githubusercontent.com/caskroom/homebrew-cask/f25b6babcd398abf48e33af3d887b2d00de1d661/Casks/google-chrome.rb`
## ENVIRONMENT
Homebrew-Cask respects many of the environment variables used by the
parent command `brew`. Please refer to the `brew`(1) man page for more
information.
Environment variables specific to Homebrew-Cask:
* HOMEBREW\_CASK\_OPTS:
This variable may contain any arguments normally used as options on
the command-line. This is particularly useful to make options persistent.
For example, you might add to your .bash_profile or .zshenv something like:
`export HOMEBREW_CASK_OPTS='--appdir=/Applications --caskroom=/etc/Caskroom'`.
## SEE ALSO
The Homebrew-Cask home page: <http://caskroom.io>.
The Homebrew-Cask GitHub page: <https://github.com/caskroom/homebrew-cask>.
`brew`(1), `curl`(1)
## AUTHORS
Paul Hinze and Contributors.
Man page format based on `brew.1.md` from Homebrew.
## BUGS
We still have bugs — and we are busy fixing them! If you have a problem, dont
be shy about reporting it on our [GitHub issues page](https://github.com/caskroom/homebrew-cask/issues?state=open).
When reporting bugs, remember that Homebrew-Cask is an independent project from
Homebrew. Do your best to direct bug reports to the appropriate project. If
your command-line started with `brew cask`, bring the bug to us first!

View File

@ -0,0 +1,12 @@
# Cask Language Reference
+ [Synopsis](cask_language_reference/readme.md)
+ [Token reference](cask_language_reference/token_reference.md)
+ [Stanza list](cask_language_reference/all_stanzas.md)
+ [Stanza documentation](cask_language_reference/stanzas/)
# Contributing
+ [Contributing to the core](development/hacking.md)
+ [Adding a new Cask](development/adding_a_cask.md)
+ [Meta information on the projects structure](development/maintaining.md)

View File

@ -0,0 +1,79 @@
<sup><sub>[Go back](../../README.md#reporting-bugs)</sup></sub>
# A cask fails to install
Possible reasons:
* [`curl` error](#curl-error)
* [`Permission denied` error](#permission-denied-error)
* [`sha256 mismatch` error](#sha256-mismatch-error)
* [`source is not there` error](#source-is-not-there-error)
* [Unlisted reason](#unlisted-reason)
---
#### `curl` error:
If the error output includes something like
```
curl: (22) The requested URL returned error: 403 Forbidden
```
the problem was with the downloading itself (see how the error came from `curl`). Homebrew-Cask itself is fine and the problem is generally one of:
1. App vendor or file in their server is down.
2. Cask is outdated.
3. A problem in your setup or connection.
[Continue to the fix](curl_error_fix_curlrc.md)
---
#### `Permission denied` error:
If the error output includes something like
```
Error: Permission denied - (/usr/local/Caskroom/someapp/0.1/Someapp.app, /Applications/Someapp.app)
```
the problem isnt with Homebrew-Cask itself, but some permissions on your system.
[Continue to the fix](permission_denied_error_fix_appdir.md)
---
#### `sha256 mismatch` error
If the error output includes something like
```
Error: sha256 mismatch
Expected: 3dbc6c2205af35db5370c7642b9a2b833668880569b9c64a7f5a670bf9911130
Actual: 526d747d99a93b760f7965e25a57ed61de9b93d566a0ba0c5f1c7e83719b20fd
```
Either your download was incomplete/corrupt or the cask is outdated.
[Continue to the fix](sha256_mismatch_error_fix_icomplete.md)
---
#### `source is not there` error
If the error output includes something like
```
Error: It seems the App source is not there: '/usr/local/Caskroom/…'
```
the directory structure inside the apps archive changed in some way. It must be fixed in Homebrew-Cask.
[Continue to the fix](source_is_not_there_fix.md)
---
#### Unlisted reason
If your issue isnt listed here, [go back](../../README.md#reporting-bugs) and pick `My problem isnt listed`.

View File

@ -0,0 +1,7 @@
<sup><sub>[Go back](../../README.md#reporting-bugs)</sup></sub>
# `brew cask list` shows wrong information
We know. [`brew cask list` is broken](https://github.com/caskroom/homebrew-cask/issues/14058) and has been for quite a while. Pull requests to fix the outstanding problems are welcome.
**Do not open an issue.**

View File

@ -0,0 +1,5 @@
<sup><sub>[Go back](a_cask_fails_to_install.md#curl-error)</sup></sub>
First, lets tackle a common problem: do you have a `.curlrc` file? Those are a frequent cause of issues of this nature. Before anything else, remove that file and try again. If it now works, do not open an issue. Incompatible `.curlrc` configurations must be fixed on your side.
If, however, you do not have a `.curlrc` or removing it did not work, lets [continue our diagnose](curl_error_fix_vendor.md).

View File

@ -0,0 +1,10 @@
<sup><sub>[Go back](curl_error_fix_vendor.md)</sup></sub>
There are a few reasons why you might not be finding a download:
* You cant access the vendors website at all. [Continue here](curl_error_fix_wont_fix.md).
* You can access the vendors site but theyre informing you the app is now discontinued. Submit a pull request deleting the cask or [open an issue informing us of the situation][issue_dead_app].
* You can access the vendors site but you cannot find the download link. [Open an issue][issue_outdated_cask_but_cannot_find_link] and detail all your steps so far.
[issue_dead_app]: https://github.com/caskroom/homebrew-cask/issues/new?title=Dead%20app%3A%20&body=%0A%2A%20Insert%20the%20name%20of%20the%20cask%20in%20the%20title%2C%20after%20the%20%60%3A%60.%0A%2A%20Insert%20the%20name%20of%20the%20cask%20and%20a%20link%20to%20it%20in%20the%20body%20of%20this%20issue%20%28example%3A%20%5B%60alfred%60%5D%28https%3A%2F%2Fgithub.com%2Fcaskroom%2Fhomebrew-cask%2Fblob%2Fmaster%2FCasks%2Falfred.rb%29%29.%0A%2A%20Insert%20a%20link%20to%20the%20page%20that%20informs%20about%20the%20app%20being%20dead.%0A%2A%20After%20all%20that%20%2A%2Adelete%20all%20this%20pre-inserted%20template%20text%2A%2A.%0A%0AFailure%20to%20follow%20these%20instructions%20may%20get%20your%20issue%20closed%20without%20further%20explanation.%20Thank%20you%20for%20taking%20the%20time%20to%20correctly%20report%20the%20issue.
[issue_outdated_cask_but_cannot_find_link]: https://github.com/caskroom/homebrew-cask/issues/new?title=Outdated%20cask%20but%20cannot%20find%20link%3A%20&body=%0A%2A%20Insert%20the%20name%20of%20the%20cask%20in%20the%20title%2C%20after%20the%20%60%3A%60.%0A%2A%20Insert%20the%20name%20of%20the%20cask%20and%20a%20link%20to%20it%20in%20the%20body%20of%20this%20issue%20%28example%3A%20%5B%60alfred%60%5D%28https%3A%2F%2Fgithub.com%2Fcaskroom%2Fhomebrew-cask%2Fblob%2Fmaster%2FCasks%2Falfred.rb%29%29.%0A%2A%20Insert%20a%20detailed%20explanation%20of%20what%20you%20tried%20to%20do%20and%20why%20you%20failed%20to%20find%20the%20download%20link.%0A%2A%20After%20all%20that%20%2A%2Adelete%20all%20this%20pre-inserted%20template%20text%2A%2A.%0A%0AFailure%20to%20follow%20these%20instructions%20may%20get%20your%20issue%20closed%20without%20further%20explanation.%20Thank%20you%20for%20taking%20the%20time%20to%20correctly%20report%20the%20issue.

View File

@ -0,0 +1,11 @@
<sup><sub>[Go back](curl_error_fix_vendor.md)</sup></sub>
Since the download started, it likely means the cask is outdated. Lets fix it:
1. Look around the apps website and find out what the latest version is. It will likely be expressed in the URL used to download it.
2. Take a look at the casks version (`brew cask _stanza version {{cask_name}}`) and verify it is indeed outdated.
* If the apps version is `latest`, it means the `url` itself is outdated. It will need to be changed to the new one.
If it is outdated, start by trying to [submit a fix](../../CONTRIBUTING.md#updating-a-cask). If youre having trouble, [open an issue][issue_outdated_cask] explaining your steps so far and why youre having trouble submitting the update.
[issue_outdated_cask]: https://github.com/caskroom/homebrew-cask/issues/new?title=Outdated%20cask%20but%20cannot%20find%20link%3A%20&body=%0A%2A%20Insert%20the%20name%20of%20the%20cask%20in%20the%20title%2C%20after%20the%20%60%3A%60.%0A%2A%20Insert%20the%20name%20of%20the%20cask%20and%20a%20link%20to%20it%20in%20the%20body%20of%20this%20issue%20%28example%3A%20%5B%60alfred%60%5D%28https%3A%2F%2Fgithub.com%2Fcaskroom%2Fhomebrew-cask%2Fblob%2Fmaster%2FCasks%2Falfred.rb%29%29.%0A%2A%20Insert%20a%20detailed%20explanation%20of%20what%20you%20tried%20to%20do%20and%20why%20you%20failed%20to%20find%20the%20download%20link.%0A%2A%20After%20all%20that%20%2A%2Adelete%20all%20this%20pre-inserted%20template%20text%2A%2A.%0A%0AFailure%20to%20follow%20these%20instructions%20may%20get%20your%20issue%20closed%20without%20further%20explanation.%20Thank%20you%20for%20taking%20the%20time%20to%20correctly%20report%20the%20issue.

View File

@ -0,0 +1,8 @@
<sup><sub>[Go back](curl_error_fix_curlrc)</sup></sub>
Lets now see if the issue is upstream:
1. Got to the vendors website (`brew cask home {{cask_name}}`).
2. Find the download link for the app and click on it.
Does it download? [Yes](curl_error_fix_outdated.md) | [No](curl_error_fix_wont_fix.md) | [There is nothing to download](curl_error_fix_no_download.md)

View File

@ -0,0 +1,9 @@
<sup><sub>[Go back](curl_error_fix_vendor.md)</sup></sub>
This means the issue isnt in any way related to Homebrew-Cask, but with the vendor or your connection.
Start by diagnosing your connection (try to download other casks, go around the web). If the problem is with your connection, try a website like [Ask Different](https://apple.stackexchange.com/) to ask for advice.
If youre sure the issue is not with your connection, contact the apps vendor and let them know their link is down, so they can fix it.
**Do not open an issue.**

View File

@ -0,0 +1,7 @@
<sup><sub>[Go back](a_cask_fails_to_install.md#permission-denied-error)</sup></sub>
In this case, its likely youre a standard user and dont have permissions to write to `/Applications` (which is now our default). If you never changed your default installation directory for apps and were using Homebrew-Cask before we changed our behaviour to moving apps instead of linking, you should have some symlinks in your `~/Applications` directory, which you do have permission to write to.
You can use `--appdir=~/Applications` when installing to bring back the old behaviour. For a permanent change, [follow the `Options` section in `USAGE.md`](https://github.com/caskroom/homebrew-cask/blob/1de4657a0ed35463602b31061b0c16dc9078b8a0/USAGE.md#options). Specifically, youll want to set `export HOMEBREW_CASK_OPTS="--appdir=~/Applications"` in your shells startup file.
If `--appdir` doesnt fix the issue or you do have write permissions to `/Applications`, the problem may lie [in the app bundle itself](permission_denied_error_fix_bundle.md).

View File

@ -0,0 +1,5 @@
<sup><sub>[Go back](permission_denied_error_fix_appdir.md)</sup></sub>
Some app bundles dont have certain permissions that might be necessary for us to move them to the appropriate location. You may check such permissions with `ls -ls {{path_to_app_bundle}}`. If you see something like `dr-xr-xr-x` at the start of the output, that may be the cause. To fix it, we simply change the app bundles permission to allow us to move it, and then set it back to what it was (in case the developer set those permissions deliberately). See [`licoin`](https://github.com/caskroom/homebrew-cask/blob/0cde71f1fea8ad62d6ec4732fcf35ac0c52d8792/Casks/litecoin.rb#L14L20) for an example of such a cask.
If the issue persists, [go back](../../README.md#reporting-bugs) and pick `My problem isnt listed`. Be sure to mention all your steps so far and what youre having difficulties with.

View File

@ -0,0 +1,15 @@
Before reporting a bug, lets make sure everything is right with your setup.
When reporting bugs, remember that Homebrew-Cask is an independent project from Homebrew. Do your best to direct bug reports to the appropriate project. If your command started with `brew cask`, bring the bug to us first.
Start by searching for your issue before posting a new one. If you find an open issue and have any new information not reported in the original, please add your insights. If you find a closed issue, try the solutions there. If the issue is still not solved, open a new one with your new information and a link back to the old related issue.
If you did not find your particular bug, before reporting it make sure you have the latest versions of Homebrew, Homebrew-Cask, and all Taps by running the following commands. These will also fix some other issues:
```bash
$ brew update; brew cleanup; brew cask cleanup
$ brew uninstall --force brew-cask; brew update
$ brew untap phinze/cask; brew untap caskroom/cask; brew update
```
Retry your failing command. If the issue persists, [go back](../../README.md#reporting-bugs) and pick the appropriate instructions for your problem.

View File

@ -0,0 +1,5 @@
<sup><sub>[Go back](a_cask_fails_to_install.md#sha256-mismatch-error)</sup></sub>
First, lets see if the problem was with your download. Delete the downloaded file (its location will be pointed out right under the `Actual` shasum line) and try again.
If the problem persists, [the cask must be outdated](sha256_mismatch_error_fix_outdated.md).

View File

@ -0,0 +1,13 @@
<sup><sub>[Go back](sha256_mismatch_error_fix_icomplete.md)</sup></sub>
Lets bring the cask up to date. Itll likely need a new version, but its possible the version has remained the same (happens occasionally when the vendor updates the app in place).
1. Got to the vendors website (`brew cask home {{cask_name}}`).
* Alternatively, if it has an `appcast`, read that (`curl "$(brew cask _stanza appcast {{cask_name}})"`).
2. Find out what the latest version is. It will likely be expressed in the URL used to download it.
3. Take a look at the casks version (`brew cask _stanza version {{cask_name}}`) and verify it is indeed outdated.
* If the apps version is `latest`, it means the `url` itself is outdated. It will need to be changed to the new one.
If it is outdated, start by trying to [submit a fix](../../CONTRIBUTING.md#updating-a-cask). If youre having trouble, [open an issue][issue_outdated_cask] explaining your steps so far and why youre having trouble submitting the update.
[issue_outdated_cask]: https://github.com/caskroom/homebrew-cask/issues/new?title=Outdated%20cask%20but%20cannot%20find%20link%3A%20&body=%0A%2A%20Insert%20the%20name%20of%20the%20cask%20in%20the%20title%2C%20after%20the%20%60%3A%60.%0A%2A%20Insert%20the%20name%20of%20the%20cask%20and%20a%20link%20to%20it%20in%20the%20body%20of%20this%20issue%20%28example%3A%20%5B%60alfred%60%5D%28https%3A%2F%2Fgithub.com%2Fcaskroom%2Fhomebrew-cask%2Fblob%2Fmaster%2FCasks%2Falfred.rb%29%29.%0A%2A%20Insert%20a%20detailed%20explanation%20of%20what%20you%20tried%20to%20do%20and%20why%20you%20failed%20to%20find%20the%20download%20link.%0A%2A%20After%20all%20that%20%2A%2Adelete%20all%20this%20pre-inserted%20template%20text%2A%2A.%0A%0AFailure%20to%20follow%20these%20instructions%20may%20get%20your%20issue%20closed%20without%20further%20explanation.%20Thank%20you%20for%20taking%20the%20time%20to%20correctly%20report%20the%20issue.

View File

@ -0,0 +1,28 @@
<sup><sub>[Go back](a_cask_fails_to_install.md#source-is-not-there-error)</sup></sub>
First, you need to identify which artifact is not being handled correctly anymore. Its explicit in the error message: if it says `Error: It seems the App source…'` the problem is [`app`](https://github.com/caskroom/homebrew-cask/blob/master/doc/cask_language_reference/stanzas/app.md). The pattern is the same across all artifacts.
Fixing this error is typically easy, and requires only a bit of time on your part. Start by downloading the package for the cask: `brew cask fetch {{cask_name}}`. The last line of output will inform you of the location of the download. Navigate there and manually unpack it. As an example, lets say the structure inside the archive is as follows:
```
.
├─ Files/SomeApp.app
├─ Files/script.sh
└─ README.md
```
Now, lets look at the cask (`brew cask cat {{cask_name}}`:
```
(…)
app 'SomeApp.app'
(…)
```
The cask was expecting `SomeApp.app` to be in the top directory of the archive (see how it says simply `SomeApp.app`) but the developer changed it to inside a `Files` directory. All we have to do is update that line of the cask to follow the new structure: `app 'Files/SomeApp.app'`.
Note that occasionally the apps name changes completely (from `SomeApp.app` to `OtherApp.app`, lets say). In these instances, the filename of the cask itself, as well as its token, must also change. Consult the [`token reference`](https://github.com/caskroom/homebrew-cask/blob/master/doc/cask_language_reference/token_reference.md) for complete instructions on the new name.
Follow the instructions to [submit a fix](../../CONTRIBUTING.md#updating-a-cask), and make the change to the cask. If using `cask-repair`, you may give it the `--edit-cask` flag when calling it on the command-line to step right into editing it. If youre having trouble, [open an issue][issue_source_not_there_and_cannot_find_it] explaining your steps so far and why youre having trouble submitting the update.
[issue_source_not_there_and_cannot_find_it]: https://github.com/caskroom/homebrew-cask/issues/new?title=Source%20not%20there%20and%20cannot%20find%20it%3A%20&body=%0A%2A%20Insert%20the%20name%20of%20the%20cask%20in%20the%20title%2C%20after%20the%20%60%3A%60.%0A%2A%20Insert%20the%20name%20of%20the%20cask%20and%20a%20link%20to%20it%20in%20the%20body%20of%20this%20issue%20%28example%3A%20%5B%60alfred%60%5D%28https%3A%2F%2Fgithub.com%2Fcaskroom%2Fhomebrew-cask%2Fblob%2Fmaster%2FCasks%2Falfred.rb%29%29.%0A%2A%20Insert%20a%20detailed%20explanation%20of%20what%20you%20tried%20to%20do%20and%20why%20you%20failed%20to%20find%20the%20new%20artifact%20source.%0A%2A%20After%20all%20that%20%2A%2Adelete%20all%20this%20pre-inserted%20template%20text%2A%2A.%0A%0AFailure%20to%20follow%20these%20instructions%20may%20get%20your%20issue%20closed%20without%20further%20explanation.%20Thank%20you%20for%20taking%20the%20time%20to%20correctly%20report%20the%20issue.

View File

@ -0,0 +1,11 @@
<sup><sub>[Go back](../../README.md#reporting-bugs)</sup></sub>
# `uninstall` wrongly reports cask as not installed
Reports of this bug are usually accompanied with the output of `brew cask list` showing the cask is indeed installed. [You should not rely on `brew cask list`](https://github.com/caskroom/homebrew-cask/issues/14058) anyway, and this error is somewhat related to it.
This is prone to happen when you try to uninstall a cask that has been updated since you last installed, or when a cask no longer exists in the repo (`brew cask list` will show it with `(!)`). Were working to handle those situations better.
For now, rerun your command with `--force`, or uninstall manually.
**Do not open an issue.**

View File

@ -0,0 +1,60 @@
module Hbc; end
require "hardware"
require "hbc/extend"
require "hbc/artifact"
require "hbc/audit"
require "hbc/auditor"
require "hbc/cache"
require "hbc/cask"
require "hbc/without_source"
require "hbc/caskroom"
require "hbc/checkable"
require "hbc/cli"
require "hbc/cask_dependencies"
require "hbc/caveats"
require "hbc/container"
require "hbc/download"
require "hbc/download_strategy"
require "hbc/exceptions"
require "hbc/fetcher"
require "hbc/installer"
require "hbc/locations"
require "hbc/macos"
require "hbc/options"
require "hbc/pkg"
require "hbc/qualified_token"
require "hbc/scopes"
require "hbc/source"
require "hbc/staged"
require "hbc/system_command"
require "hbc/topological_hash"
require "hbc/underscore_supporting_uri"
require "hbc/url"
require "hbc/url_checker"
require "hbc/utils"
require "hbc/verify"
require "hbc/version"
require "vendor/plist"
module Hbc
include Hbc::Locations
include Hbc::Scopes
include Hbc::Options
include Hbc::Utils
def self.init
Hbc::Cache.ensure_cache_exists
Hbc::Cache.migrate_legacy_cache
Hbc::Caskroom.ensure_caskroom_exists
end
def self.load(query)
odebug "Loading Cask definitions"
cask = Hbc::Source.for_query(query).load
cask.dumpcask
cask
end
end

View File

@ -0,0 +1,65 @@
module Hbc::Artifact; end
require "hbc/artifact/app"
require "hbc/artifact/artifact" # generic 'artifact' stanza
require "hbc/artifact/binary"
require "hbc/artifact/colorpicker"
require "hbc/artifact/font"
require "hbc/artifact/input_method"
require "hbc/artifact/installer"
require "hbc/artifact/internet_plugin"
require "hbc/artifact/audio_unit_plugin"
require "hbc/artifact/vst_plugin"
require "hbc/artifact/vst3_plugin"
require "hbc/artifact/nested_container"
require "hbc/artifact/pkg"
require "hbc/artifact/postflight_block"
require "hbc/artifact/preflight_block"
require "hbc/artifact/prefpane"
require "hbc/artifact/qlplugin"
require "hbc/artifact/screen_saver"
require "hbc/artifact/service"
require "hbc/artifact/stage_only"
require "hbc/artifact/suite"
require "hbc/artifact/uninstall"
require "hbc/artifact/zap"
module Hbc::Artifact
# NOTE: order is important here, since we want to extract nested containers
# before we handle any other artifacts
def self.artifacts
[
Hbc::Artifact::PreflightBlock,
Hbc::Artifact::NestedContainer,
Hbc::Artifact::Installer,
Hbc::Artifact::App,
Hbc::Artifact::Suite,
Hbc::Artifact::Artifact, # generic 'artifact' stanza
Hbc::Artifact::Colorpicker,
Hbc::Artifact::Pkg,
Hbc::Artifact::Prefpane,
Hbc::Artifact::Qlplugin,
Hbc::Artifact::Font,
Hbc::Artifact::Service,
Hbc::Artifact::StageOnly,
Hbc::Artifact::Binary,
Hbc::Artifact::InputMethod,
Hbc::Artifact::InternetPlugin,
Hbc::Artifact::AudioUnitPlugin,
Hbc::Artifact::VstPlugin,
Hbc::Artifact::Vst3Plugin,
Hbc::Artifact::ScreenSaver,
Hbc::Artifact::Uninstall,
Hbc::Artifact::PostflightBlock,
Hbc::Artifact::Zap,
]
end
def self.for_cask(cask)
odebug "Determining which artifacts are present in Cask #{cask}"
artifacts.select do |artifact|
odebug "Checking for artifact class #{artifact}"
artifact.me?(cask)
end
end
end

View File

@ -0,0 +1,36 @@
require "hbc/artifact/base"
class Hbc::Artifact::AbstractFlightBlock < Hbc::Artifact::Base
def self.artifact_dsl_key
super.to_s.sub(%r{_block$}, "").to_sym
end
def self.uninstall_artifact_dsl_key
artifact_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}")
end
def self.me?(cask)
cask.artifacts[artifact_dsl_key].any? ||
cask.artifacts[uninstall_artifact_dsl_key].any?
end
def install_phase
abstract_phase(self.class.artifact_dsl_key)
end
def uninstall_phase
abstract_phase(self.class.uninstall_artifact_dsl_key)
end
private
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
end
end

Some files were not shown because too many files have changed in this diff Show More