Skip to content

Commit

Permalink
Update hacking.md
Browse files Browse the repository at this point in the history
Closes #28964 and #17007.
  • Loading branch information
miccal authored Jan 26, 2017
1 parent ee905e1 commit 9d8b3aa
Showing 1 changed file with 36 additions and 62 deletions.
98 changes: 36 additions & 62 deletions doc/development/hacking.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ If you’d like to hack on the Ruby code that drives this project, please join u

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 user’s 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.
We manage installed files via methods like [Homebrew](http://brew.sh/). Similarly, we try to avoid `sudo` where possible.

Homebrew-Cask is designed to work like a traditional Unix tool:

Expand All @@ -15,8 +15,6 @@ Homebrew-Cask is designed to work like a traditional Unix tool:

## 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 don’t work well with multiple versions, and most importantly, we currently can’t `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:
Expand All @@ -25,13 +23,11 @@ Since upgrading is a core feature of every package manager, the implementation o
* 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 you’d like to contribute to `upgrade`, that’s an excellent place to start.
These and more requirements are tracked in our `upgrade` roadmaps discussed [here](https://github.com/caskroom/homebrew-cask/issues/4678) and [here](https://github.com/caskroom/homebrew-cask/issues/29301). If you’d like to contribute to `upgrade`, that’s 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.
Homebrew-Cask is implemented as a Homebrew [external command](http://docs.brew.sh/External-Commands.html) called `cask`, and we try to match semantics with Homebrew 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.

Expand All @@ -43,59 +39,28 @@ Casks, by contrast, only need to support the few installation methods used by ap

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.
For software with unusual needs that are not covered by the DSL, we generally accept Casks containing small hacks or arbitrary code (for example, though the use of [shims scripts](https://github.com/caskroom/homebrew-cask/issues/18809)). 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 can’t safely run Homebrew’s `brew update` command. To switch back to production mode, run:

```bash
/<path>/<to>/<private>/<repo>/developer/bin/production_brew_cask
```
The setup is similar to that for contibuting to the core code of Homebrew - consult Homebrew's [documentation for maintainers]( https://github.com/Homebrew/brew/tree/master/docs#maintainers) for more information.

### 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
$ /System/Library/Frameworks/Ruby.framework/Versions/Current/usr/bin/ruby /usr/local/Homebrew/Library/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
$ brew cask /usr/local/Homebrew/Library/Homebrew/cask/lib/hbc/cli/info.rb google-chrome
```

This form can also be combined with a specific Ruby interpreter as above.
Expand All @@ -122,39 +87,48 @@ See [the relevant section in `adding_a_cask.md`](adding_a_cask.md#submitting-you

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

### The External Command `_stanza`

If you’re making changes - please write some tests for them! Install dependencies and run the whole test suite with:
[`_stanza`](https://github.com/Homebrew/brew/blob/master/Library/Homebrew/cask/lib/hbc/cli/internal_stanza.rb) is an incredibly useful command to contributors who want to build a tool that leans on the information from Homebrew-Cask. It extracts and renders a specific stanza for either a given Cask, or for every Cask.

The syntax is

```bash
brew cask-tests
brew cask _stanza <stanza_name> [ --table | --yaml | --inspect | --quiet ] [ <cask_token> ... ]
```

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:
If no `<cask_token>`'s are given, then data for all Casks is returned. On failure, a blank line is returned on the standard output.

* `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
For example, `brew cask _stanza appcast atom` outputs the `appcast` for the Cask [atom.rb](https://github.com/caskroom/homebrew-cask/blob/43ad9d8ddbad71fbeee42710d567861f080fedf8/Casks/atom.rb#L7), namely `https://github.com/atom/atom/releases.atom`.

Example of a very verbose output:
The command `brew cask _stanza app --table --yaml alfred google-chrome adium voicemac logisim` outputs a human-readable data table of the `app` stanzas for the given Casks:

```shell
TESTOPTS='-v' SPEC_OPTS='-fd' VERBOSE_TESTS=1 brew cask-tests
```bash
alfred ---
- Alfred 3.app
google-chrome ---
- Google Chrome.app
adium ---
- Adium.app
voicemac ---
- VoiceMac/VoiceMac.app
logisim ---
- Logisim.app
```

#### 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`.
As a final example, the command `brew cask _stanza homepage > homepage_list.txt` will output the `homepage` of every Cask into the text file `homepage_list.txt`.

## Hanging out on IRC
## Be social

We’re on IRC at `#homebrew-cask` on Freenode. If you are going to develop for Homebrew-Cask, it’s a great idea to hang out with us there. Here’s why:
If you are going to develop for Homebrew-Cask, it’s a great idea to chat with us first. Here’s why:

* Discuss your thoughts before coding and maybe get new ideas
* Discuss your thoughts before coding by [opening an issue](https://github.com/caskroom/homebrew-cask/issues/new) 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!
* 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)

# <3 THANK YOU! <3

0 comments on commit 9d8b3aa

Please sign in to comment.