Recently I had the need to create a homebrew external command to extend homebrew default behavior. My goal is to extend
brew deps command by creating a new command
brew deps-group. Executing the command will list all top-level packages in homebrew that is related to each other by common dependencies, doing so will let me know if it safe for me to actually delete the package without breaking other packages.
To achieve this, the overall file structure consist of:
- Formula - this tells homebrew about where to get file for your packages and their dependencies.
- Application - actual implementation and I wrote my simple app in Python.
homebrew-deps-group/ |------ Formula/ | |--- brew-deps-group.rb |------ brew-deps-group.rb |------ brew-deps-group.py
I noticed that your package needs to start with
Explanation in comments
require "formula" # this will translate to brew-deps-group as the formula name class BrewDepsGroup < Formula homepage "https://github.com/shulhi/homebrew-deps-group" # this is the source of your package # when you run brew install, it will be installed from this source url "https://github.com/shulhi/homebrew-deps-group.git" # my package depends on python depends_on :python if MacOS.version <= :snow_leopard # this is the dependency for my formula resource "networkx" do url "https://pypi.python.org/packages/source/n/networkx/networkx-1.9.1.tar.gz" sha1 "ac2db3b29c7c4d16435f2a7ebe90fc8bd687b59c" end # skip cleaning path in formula skip_clean "bin" def install # since my python application has other dependency, we need to install it # and ensure it is installed in /vendor # to avoid pollution with system packages ENV.prepend_create_path "PYTHONPATH", libexec/"vendor/lib/python2.7/site-packages" %w[networkx].each do |r| resource(r).stage do system "python", *Language::Python.setup_install_args(libexec/"vendor") end end # if your python application has setup.py, then uncomment this line # this will install your application in the correct location # ENV.prepend_create_path "PYTHONPATH", libexec/"lib/python2.7/site-packages" # system "python", *Language::Python.setup_install_args(libexec) # copies your python application to bin # since we don't have any, I don't need this # instead, we are just going to copy the actual file (see next section below) # bin.install Dir[libexec/"bin/*"] # bin.env_script_all_files(libexec/"bin", :PYTHONPATH => ENV["PYTHONPATH"]) # copies all files to bin so we can execute the files from other scripts bin.install 'brew-deps-group.py' bin.install 'brew-deps-group.rb' (bin + 'brew-deps-group.py').chmod 0755 (bin + 'brew-deps-group.rb').chmod 0755 end end
So our application/command needs an entry point, i.e. when I run
brew deps-group, some file should be executed right? In our case, this will call
brew-deps-group.rb which in turn will call up
require 'keg' require 'formula' module BrewDepsGroup module_function def run if ['-h', '?', '--help'].include? ARGV.first puts USAGE exit 0 end if ['-a', '--all'].include? ARGV.first # call our python executable file # we don't need python file.py since the file is already executable and is in our path system "brew-deps-group.py", "all" end end end BrewDepsGroup.run exit 0
#! /usr/bin/env python # our dependency we declared in our formula can now be used import networkx as nx def main(argv): option = argv # do something print "hello world" if __name__ == '__main__': main(sys.argv[1:])
If you need the full source code, you can find it here