Homebrew/homebrew-cask

Separate the Ruby backend from internal Homebrew dependencies

Closed this issue · 6 comments

Background

Homebrew-cask is implemented as a Homebrew external command, in the form of
brew-cask.rb, which is required by the brew command. This means that
Homebrew-cask has full access to, and is constrained by, the Ruby runtime
provided by Homebrew.

Initially it was thought that Homebrew-cask would re-use much of Homebrew's
code internally. That turned out not to be the case in practice, largely
because Homebrew's code is organized around the Formula.

Proposal

brew-cask.rb should be re-implemented as an executable brew-cask, which
would be invoked by Homebrew rather than required. brew-cask would
then execute completely independently of Homebrew's Ruby environment.

This would be an internal-only change. The user interface would stay the
same. Commands would still be invoked via brew cask <verb>, and we would
still piggyback on brew update to get new Casks.

Advantages

  • Stability. Homebrew does not guarantee any internal APIs.
    Homebrew-cask frequently breaks due to changes within Homebrew
    (#4732, #4982, #4229, many others).
  • Clarity. Where we do re-use Homebrew's classes (such as for
    downloading), we do so only partially, with some methods overridden.
    This needlessly obscures what the code is doing, making it more difficult
    to diagnose bugs or develop new functionality.
  • Error Reporting. Both Homebrew and Homebrew-cask attempt to
    rescue exceptions and direct users to the relevant issues URL. @voanhduy1512
    did some good work on this problem, but it still crops up as in #5108. Every
    misdirected report is a drain on maintainers (in both projects).
  • Cleanup. Currently brew cask cleanup works in a roundabout
    way (using tracking symlinks) because we share a download location
    with Homebrew. It would be more robust to maintain our own download
    cache.
  • Ruby 2.0. We would have the choice to be more aggressive about
    switching to Ruby 2.0 (say, 6 months after Yosemite is released). We
    could require Mountain Lion and earlier to install Ruby 2.0 as a
    prerequisite. This would not only gain us access to new language
    features, but reduce the currently-imposed burden of maintaining
    compatibility across Ruby 1.8 and 2.0.
  • Freedom. Currently we are constrained by Homebrew's decisions with
    regard to character encodings, interpreter version, monkeypatching -- all
    things that, once inherited, we cannot easily undo.

Disadvantages

  • Tap Migration. We have sometimes used internal interfaces to Homebrew
    which are not available externally, as with the tap migration code (#4169).
    However, this also could have been accomplished by copying the relevant
    logic from Homebrew.
  • Integration for files in /usr/local. Some Casks install files into /usr/local,
    which causes brew doctor to complain as in #2350 and others. Currently
    we have a caveats warning for this, which is not really a fix. As mentioned
    in #3693, we could fully resolve the problem by installing files to a Homebrew
    Cellar, and then symlinking into the Cellar as with any other Homebrew
    installation. Such a technique would become more difficult if we could not
    call directly into Homebrew.
    • However, it also seems that nobody is working on that implementation.
    • There are other possible approaches, such as generating an ad hoc Formula.

Places where we currently re-use Homebrew's code (incomplete)

  • global methods such as onoe (example install.rb)
    • these are mostly trivial
    • relevant code would have to be forked from Homebrew
    • in some cases, we can simplify and/or get more desirable behavior
  • monkeypatched methods on Pathname ?
    • preferable to remove these where they may exist
    • we at least use our own variant monkeypatch cabv (#2991)
  • implicit tapping (#2303)
    • can be replaced by invoking brew tap <Tapname>
  • downloading, eg Cask::CurlDownloadStrategy (see comments in download_strategy.rb)
    • relevant code would have to be forked from Homebrew
  • calculation of checksums
    • would be simplified, as our project only uses one checksum type
  • depends_on_formula (#2305)
    • can be replaced by invoking brew install <formula>
  • automatic tap migration (#4169)
    • this code was meant to be temporary in any case
  • test suite
    • we have also been discussing rearchitecting the test suite to use RSpec

Tracker

Edits:

  • added Disadvantage / Integration for files in /usr/local
  • added Tracker
  • added Error Reporting
  • renamed Plan to Tracker; filled out Tracker details

and add:

Advantages:
standalone: just install cask without the need to install brew

just install cask without the need to install brew

Not exactly. From the post:

we would still piggyback on brew update to get new Casks.

if brew is in stalled then piggyback on brew update and for without brew add a cask update

@jawshooah Since we now want to go in the opposite direction, should we close this, or is it still useful in some way?

No use in leaving it open.