#!/usr/bin/env python3 # Yes, this is a Python program writing a Ruby program. import argparse import hashlib import sys import os parser = argparse.ArgumentParser() parser.add_argument("--url-base", default = "https://brew.cryptech.is/tarballs/") parser.add_argument("--tarball", required = True) parser.add_argument("--package", required = True) parser.add_argument("--version", required = True) parser.add_argument("--formula", type = argparse.FileType("w"), nargs = "?", default = sys.stdout) parser.add_argument("--conflicts", default = "") args = parser.parse_args() template = '''\ # This Homebrew forumula was automatically generated by a script. # You might not want to edit it manually. # # Installation is a bit complex due to the way Homebrew handles Python # library dependencies and due to our stuff being a mixture of Python # and C. It's also painfully slow, because we're not using bottles, # due to lack of a MacOS build farm. Sorry. # # Per Homebrew expectations, we install copies of external Python # libraries ("resources") in our own private library directory, using # Homebrew's hack to run our executable Python scripts with PYTHONPATH # pointing to our private library directory. Our own Python library # code, however, is what Homebrew considers "bindings", so we install # those where user scripts as well as our own can find them...then we # add a symlink so that our scripts can find our bindings regardless # of which copy of Python Homebrew decides we should use this week. # # We have to build our own software before installing our Python code, # because at least one of the Python modules we install # (cryptech.py11.attribute_map) is generated during the build. # # Reference for all the documented Python Homebrew voodoo: # # http://docs.brew.sh/Python-for-Formula-Authors.html # # Reference for undocumented Python Homebrew voodoo: # # /usr/local/Homebrew/Library/Homebrew/language/python.rb class {classname} < Formula desc "Software for working with Cryptech Alpha board HSM" homepage "https://cryptech.is/" version "{version}" url "{url}" sha256 "{sha256}" depends_on "python@3.8" {conflicts} resource "pyserial" do url "https://pypi.python.org/packages/3c/d8/a9fa247ca60b02b3bebbd61766b4f321393b57b13c53b18f6f62cf172c08/pyserial-3.1.1.tar.gz" sha256 "d657051249ce3cbd0446bcfb2be07a435e1029da4d63f53ed9b4cdde7373364c" end resource "PyYAML" do url "http://pyyaml.org/download/pyyaml/PyYAML-3.11.tar.gz" sha256 "c36c938a872e5ff494938b33b14aaa156cb439ec67548fcab3535bb78b0846e8" end resource "tornado" do url "https://files.pythonhosted.org/packages/source/t/tornado/tornado-4.4.3.tar.gz" sha256 "f267acc96d5cf3df0fd8a7bfb5a91c2eb4ec81d5962d1a7386ceb34c655634a8" end resource "singledispatch" do url "https://pypi.python.org/packages/source/s/singledispatch/singledispatch-3.4.0.3.tar.gz" sha256 "5b06af87df13818d14f08a028e42f566640aef80805c3b50c5056b086e3c2b9c" end resource "backports_abc" do url "https://files.pythonhosted.org/packages/source/b/backports_abc/backports_abc-0.5.tar.gz" sha256 "033be54514a03e255df75c5aee8f9e672f663f93abb723444caec8fe43437bde" end resource "pycrypto" do url "https://pypi.python.org/packages/source/p/pycrypto/pycrypto-2.6.1.tar.gz" sha256 "f2ce1e989b272cfcb677616763e0a2e7ec659effa67a88aa92b3a65528f60a3c" end def install xy = Language::Python.major_minor_version "python3" ENV.prepend_create_path "PYTHONPATH", libexec/"vendor/lib/python#{{xy}}/site-packages" resources.each do |r| r.stage do system "python3", *Language::Python.setup_install_args(libexec/"vendor") end end ohai "Building PKCS #11 code (including crypto and bignum libraries) from source, this is slow, please be patient..." ENV.deparallelize system "make", "-C", "sw/pkcs11" system "python", *Language::Python.setup_install_args(prefix) bin.env_script_all_files(libexec/"bin", :PYTHONPATH => ENV["PYTHONPATH"]) ln_s lib/"python#{{xy}}/site-packages/cryptech", libexec/"vendor/lib/python#{{xy}}/site-packages/cryptech" share.install "cryptech-alpha-firmware.tar.gz" lib.install "sw/pkcs11/libcryptech-pkcs11.dylib" end end ''' with open(args.tarball, "rb") as f: digest = hashlib.sha256(f.read()).hexdigest() classname = "".join(word.capitalize() for word in args.package.split("-")) conflicts = "".join(" conflicts_with \"{}\", :because => \"HSM firmware and PKCS #11 library must match\"\n".format(conflict) for conflict in args.conflicts.split()) url = os.path.join(args.url_base, os.path.basename(args.tarball)) args.formula.write(template.format( version = args.version, url = url, sha256 = digest, classname = classname, conflicts = conflicts))