7

I want to package up a few shell scripts + support files into a homebrew formula that installs these scripts somewhere on the user $PATH. I will serve the formula from my own tap.

Reading through the formula cookbook the examples seem to assume cmake or autotools system in the upstream library. What if my project only consists of a few scripts and config files? Should I just manually copy those into #{prefix}/ in the Formula?

Jeroen Ooms
  • 31,998
  • 35
  • 134
  • 207

1 Answers1

10

There are two cases here:

Standalone Scripts

Install them under bin using bin.install. You can optionally rename them, e.g. to strip the extension:

class MyFormula < Formula
  # ...

  def install
    # move 'myscript.sh' under #{prefix}/bin/
    bin.install "myscript.sh"

    # OR move 'myscript.sh' to #{prefix}/bin/mybettername
    bin.install "myscript.sh" => "mybettername"

    # OR move *.sh under bin/
    bin.install Dir["*.sh"]
  end
end

Scripts with Support Files

This case is tricky because you need to get all the paths right. The simplest way is to install everything under #{libexec}/ then write exec scripts under #{bin}/. That’s a very common pattern in Homebrew formulae.

class MyFormula < Formula
  # ...

  def install
    # Move everything under #{libexec}/
    libexec.install Dir["*"]

    # Then write executables under #{bin}/
    bin.write_exec_script (libexec/"myscript.sh")
  end
end

Given a tarball (or a git repo) that contains the following content:

  • script.sh
  • supportfile.txt

The above formula will create the following hierarchy:

#{prefix}/
  libexec/
    script.sh
    supportfile.txt
  bin/
    script.sh

Homebrew creates that #{prefix}/bin/script.sh with the following content:

#!/bin/bash
exec "#{libexec}/script.sh" "$@"

This means that your script can expect to have a support file in its own directory while not polluting bin/ and not making any assumption regarding the install path (e.g. you don’t need to use things like ../libexec/supportfile.txt in your script).

See this answer of mine for an example with a Ruby script and that one for an example with manpages.

Note Homebrew also have other helpers to e.g. not only write an exec script but also set environment variables or execute a .jar.

bfontaine
  • 18,169
  • 13
  • 73
  • 107
  • 1
    It should be noted that the items in your first shell script example should be either/or, not using all three (install shell script OR install script and rename it in one go, OR install all *.sh files) – Justin Hammond Sep 16 '20 at 19:38
  • Thanks @JustinHammond; I clarified this. – bfontaine Sep 17 '20 at 08:35
  • Is there anywhere in homebrew's documentation that explains this pattern? Seems very common but it took me a while to find this. – wcarhart Oct 19 '20 at 20:20
  • @wcarhart Unfortunately I don’t see it in the documentation, even in the formula cookbook: https://docs.brew.sh/Formula-Cookbook. – bfontaine Oct 20 '20 at 07:13