diff --git a/.github/workflows/sapling-cli-homebrew-macos-arm64-release.yml b/.github/workflows/sapling-cli-homebrew-macos-arm64-release.yml index 0df99b240f571..2d21378f65a04 100644 --- a/.github/workflows/sapling-cli-homebrew-macos-arm64-release.yml +++ b/.github/workflows/sapling-cli-homebrew-macos-arm64-release.yml @@ -16,10 +16,20 @@ jobs: - name: set-env SAPLING_VERSION shell: bash run: echo "SAPLING_VERSION=$(ci/tag-name.sh)" >> $GITHUB_ENV + - name: Tap homebrew-core + run: brew tap homebrew/core + - name: Prepare build environment + run: 'eden/scm/packaging/mac/prepare_formula.py \ + + -t aarch64-apple-darwin \ + + -r ${{ env.SAPLING_VERSION }} \ + + -o $(brew --repository)/Library/Taps/homebrew/homebrew-core/Formula/s/sapling.rb' - name: Install and build Sapling bottle - run: brew install --build-bottle sapling + run: HOMEBREW_NO_INSTALL_FROM_API=1 brew install --build-bottle sapling - name: Create Sapling bottle - run: brew bottle sapling + run: HOMEBREW_NO_INSTALL_FROM_API=1 brew bottle sapling - name: Rename bottle to some platform specific name run: mv sapling*ventura.bottle*.tar.gz sapling_${{ env.SAPLING_VERSION }}.arm64_ventura.bottle.tar.gz - name: Upload Artifact diff --git a/.github/workflows/sapling-cli-homebrew-macos-x86-release.yml b/.github/workflows/sapling-cli-homebrew-macos-x86-release.yml index 54390b84196ac..90446be1f088c 100644 --- a/.github/workflows/sapling-cli-homebrew-macos-x86-release.yml +++ b/.github/workflows/sapling-cli-homebrew-macos-x86-release.yml @@ -16,10 +16,20 @@ jobs: - name: set-env SAPLING_VERSION shell: bash run: echo "SAPLING_VERSION=$(ci/tag-name.sh)" >> $GITHUB_ENV + - name: Tap homebrew-core + run: brew tap homebrew/core + - name: Prepare build environment + run: 'eden/scm/packaging/mac/prepare_formula.py \ + + -t x86_64-apple-darwin \ + + -r ${{ env.SAPLING_VERSION }} \ + + -o $(brew --repository)/Library/Taps/homebrew/homebrew-core/Formula/s/sapling.rb' - name: Install and build Sapling bottle - run: brew install --build-bottle sapling + run: HOMEBREW_NO_INSTALL_FROM_API=1 brew install --build-bottle sapling - name: Create Sapling bottle - run: brew bottle sapling + run: HOMEBREW_NO_INSTALL_FROM_API=1 brew bottle sapling - name: Rename bottle to some platform specific name run: mv sapling*monterey.bottle*.tar.gz sapling_${{ env.SAPLING_VERSION }}.monterey.bottle.tar.gz - name: Upload Artifact diff --git a/ci/gen_workflows.py b/ci/gen_workflows.py index e28b3b23932ae..b05308a6948eb 100755 --- a/ci/gen_workflows.py +++ b/ci/gen_workflows.py @@ -41,10 +41,12 @@ MACOS_RELEASES = { "x86": { + "target": "x86_64-apple-darwin", "runson": "macos-12", "mac_release": "monterey", }, "arm64": { + "target": "aarch64-apple-darwin", "runson": "macos-13-xlarge", "mac_release": "ventura", }, @@ -345,7 +347,7 @@ def gen_windows_release(self) -> str: } self._write_file("sapling-cli-windows-amd64-release.yml", gh_action) - def gen_homebrew_macos_release(self, arch, runson, mac_release) -> str: + def gen_homebrew_macos_release(self, arch, target, runson, mac_release) -> str: BUILD = "build" artifact_key = f"macos-homebrew-{arch}-bottle" extension = f"{mac_release}.bottle.tar.gz" @@ -358,13 +360,24 @@ def gen_homebrew_macos_release(self, arch, runson, mac_release) -> str: {"name": "Checkout Code", "uses": "actions/checkout@v3"}, grant_repo_access(), create_set_env_step(SAPLING_VERSION, "$(ci/tag-name.sh)"), + { + "name": "Tap homebrew-core", + "run": "brew tap homebrew/core", + }, + { + "name": "Prepare build environment", + "run": "eden/scm/packaging/mac/prepare_formula.py \\\n" + + f"-t {target} \\\n" + + "-r ${{ env.SAPLING_VERSION }} \\\n" + + "-o $(brew --repository)/Library/Taps/homebrew/homebrew-core/Formula/s/sapling.rb", + }, { "name": "Install and build Sapling bottle", - "run": "brew install --build-bottle sapling", + "run": "HOMEBREW_NO_INSTALL_FROM_API=1 brew install --build-bottle sapling", }, { "name": "Create Sapling bottle", - "run": "brew bottle sapling", + "run": "HOMEBREW_NO_INSTALL_FROM_API=1 brew bottle sapling", }, { "name": "Rename bottle to some platform specific name", diff --git a/eden/scm/packaging/mac/brew_formula.rb b/eden/scm/packaging/mac/brew_formula.rb index 0193ef17e8101..01e21438c1851 100644 --- a/eden/scm/packaging/mac/brew_formula.rb +++ b/eden/scm/packaging/mac/brew_formula.rb @@ -16,7 +16,7 @@ class Sapling < Formula depends_on "python@3.11" depends_on "node" - depends_on "openssl@1.1" + depends_on "openssl@3" depends_on "gh" depends_on "cmake" => :build depends_on "rustup-init" => :build @@ -29,7 +29,7 @@ def install # force some specific location by setting the OPENSSL_DIR environment # variable. This is necessary since the installed OpenSSL library # might not match the architecture of the destination one. - ENV["OPENSSL_DIR"] = "%TMPDIR%/openssl@1.1/1.1.1s" + ENV["OPENSSL_DIR"] = Formula["openssl@3"].opt_prefix ENV["PYTHON_SYS_EXECUTABLE"] = Formula["python@3.11"].opt_prefix/"bin/python3.11" ENV["PYTHON"] = Formula["python@3.11"].opt_prefix/"bin/python3.11" ENV["PYTHON3"] = Formula["python@3.11"].opt_prefix/"bin/python3.11" diff --git a/eden/scm/packaging/mac/prepare_formula.py b/eden/scm/packaging/mac/prepare_formula.py new file mode 100755 index 0000000000000..43d540a4d31f0 --- /dev/null +++ b/eden/scm/packaging/mac/prepare_formula.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2. + +import argparse +import os +import re +import shutil +import subprocess +import tempfile +from typing import List + + +# Create the parser +parser = argparse.ArgumentParser( + description="""Creates a homebrew bottle for the specified architecture + +Also downloads additional brew bottles as required. +""" +) + +parser.add_argument( + "-t", + "--target", + default=None, + type=str, + help="Compilation target (e.g. aarch64-apple-darwin)", + required=True, +) + +parser.add_argument( + "-r", + "--release-version", + default=None, + type=str, + help="Version for Sapling", + required=True, +) + +parser.add_argument( + "-d", + "--dotdir", + default="git", + type=str, + help="Dot directory of the current repo (e.g. .git, .hg, .sl)", + required=False, +) + +parser.add_argument( + "-o", + "--formula-out", + default="sapling.rb", + type=str, + help="Location of the resultant filled in formula", + required=False, +) + + +def run_cmd(cmd: List[str]) -> str: + return subprocess.check_output(cmd).decode("utf-8").rstrip() + + +def create_repo_tarball(dotdir): + run_cmd( + [ + "tar", + "--exclude", + f".{dotdir}/**", + "--exclude", + "sapling.tar.gz", + "-czf", + "./sapling.tar.gz", + ".", + ] + ) + + +def fill_in_formula_template(target, version, tmpdir, filled_formula_dir): + brew_formula_rb = os.path.join(os.path.dirname(__file__), "brew_formula.rb") + with open(brew_formula_rb, "r") as f: + formula = f.read() + sha256 = run_cmd(["shasum", "-a", "256", "./sapling.tar.gz"]).split()[0] + cachedir = run_cmd(["brew", "--cache"]) + formula = formula.replace( + "%URL%", + f"file://{os.path.join(os.path.abspath(os.getcwd()), 'sapling.tar.gz')}", + ) + formula = formula.replace("%VERSION%", version) + formula = formula.replace("%SHA256%", sha256) + formula = formula.replace("%TMPDIR%", tmpdir) + formula = formula.replace("%TARGET%", target) + formula = formula.replace("%CACHEDIR%", cachedir) + with open(filled_formula_dir, "w") as f: + f.write(formula) + + +if __name__ == "__main__": + args = parser.parse_args() + tmpdir = tempfile.mkdtemp() + create_repo_tarball(args.dotdir) + fill_in_formula_template( + args.target, args.release_version, tmpdir, args.formula_out + )