Skip to content

Commit

Permalink
macOS .pkg improvements
Browse files Browse the repository at this point in the history
- don't include GitHub Actions credentials
- generate and include RTF version of Homebrew BSD license
- create nicer installer with `productbuild`
- customise welcome/conclusion messages
- add Homebrew logo as a background image
- remove unnecessary `preinstall` script
- cleanup `postinstall` script to pass `brew doctor`
- use `Distribution.xml` for a nicer installer
- require CLT or Xcode rather than using our hacks to try and install
  CLT during installation
  • Loading branch information
MikeMcQuaid committed Jul 25, 2023
1 parent db86a40 commit 408c5b4
Show file tree
Hide file tree
Showing 8 changed files with 203 additions and 86 deletions.
65 changes: 54 additions & 11 deletions .github/workflows/build-pkg.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,22 @@ jobs:
TEMPORARY_CERTIFICATE_FILE: 'homebrew_developer_id_installer_certificate.p12'
TEMPORARY_KEYCHAIN_FILE: 'homebrew_installer_signing.keychain-db'
MIN_MACOS_VERSION: '11.0'
PKG_APPLE_DEVELOPER_TEAM_ID: ${{ secrets.PKG_APPLE_DEVELOPER_TEAM_ID }}
steps:
- uses: actions/checkout@v3
- name: Checkout to brew subdirectory
uses: actions/checkout@v3
with:
path: brew
fetch-depth: 0
persist-credentials: false

- name: Get Homebrew version from Git
id: print-version
run: echo "version=$(git -C brew describe --tags --always)" >> "${GITHUB_OUTPUT}"

- name: Install Pandoc
run: brew install pandoc

- name: Create and unlock temporary macOS keychain
env:
PKG_KEYCHAIN_PASSWORD: ${{ secrets.PKG_KEYCHAIN_PASSWORD }}
Expand All @@ -38,12 +44,16 @@ jobs:
- name: Create temporary certificate file
env:
PKG_APPLE_SIGNING_CERTIFICATE_BASE64: ${{ secrets.PKG_APPLE_SIGNING_CERTIFICATE_BASE64 }}
run: echo -n "${PKG_APPLE_SIGNING_CERTIFICATE_BASE64}" | base64 --decode --output="${RUNNER_TEMP}/${TEMPORARY_CERTIFICATE_FILE}"
run: echo -n "${PKG_APPLE_SIGNING_CERTIFICATE_BASE64}" |
base64 --decode --output="${RUNNER_TEMP}/${TEMPORARY_CERTIFICATE_FILE}"

- name: Import certificate file into macOS keychain
env:
PKG_APPLE_SIGNING_CERTIFICATE_PASSWORD: ${{ secrets.PKG_APPLE_SIGNING_CERTIFICATE_PASSWORD }}
run: security import "${RUNNER_TEMP}/${TEMPORARY_CERTIFICATE_FILE}" -k "${RUNNER_TEMP}/${TEMPORARY_KEYCHAIN_FILE}" -t cert -f pkcs12 -P "${PKG_APPLE_SIGNING_CERTIFICATE_PASSWORD}" -A
run: security import "${RUNNER_TEMP}/${TEMPORARY_CERTIFICATE_FILE}"
-k "${RUNNER_TEMP}/${TEMPORARY_KEYCHAIN_FILE}"
-P "${PKG_APPLE_SIGNING_CERTIFICATE_PASSWORD}"
-t cert -f pkcs12 -A

- name: Clean up temporary certificate file
if: ${{ always() }}
Expand All @@ -52,25 +62,58 @@ jobs:
- name: Open macOS keychain
run: security list-keychain -d user -s "${RUNNER_TEMP}/${TEMPORARY_KEYCHAIN_FILE}"

- name: Build Homebrew installer package
env:
PKG_APPLE_DEVELOPER_TEAM_ID: ${{ secrets.PKG_APPLE_DEVELOPER_TEAM_ID }}
- name: Build Homebrew installer component package
# Note: `Library/Homebrew/test/support/fixtures/` contains unsigned
# binaries so it needs to be excluded from notarization.
run: pkgbuild --root brew --scripts brew/package/scripts --identifier "sh.brew.homebrew" --version ${{ steps.print-version.outputs.version }} --install-location "/tmp/brew" --filter .DS_Store --filter "(.*)/Library/Homebrew/test/support/fixtures/" --min-os-version "${MIN_MACOS_VERSION}" --sign "${PKG_APPLE_DEVELOPER_TEAM_ID}" Homebrew-${{ steps.print-version.outputs.version }}.pkg
run: pkgbuild --root brew
--scripts brew/package/scripts
--identifier "sh.brew.homebrew"
--version ${{ steps.print-version.outputs.version }}
--install-location "/opt/homebrew"
--filter .DS_Store
--filter "(.*)/Library/Homebrew/test/support/fixtures/"
--min-os-version "${MIN_MACOS_VERSION}"
--sign "${PKG_APPLE_DEVELOPER_TEAM_ID}" Homebrew.pkg

- name: Convert Homebrew license file to RTF
run: (printf "### " && cat brew/LICENSE.txt) |
pandoc --from markdown --standalone --output brew/package/resources/LICENSE.rtf

- name: Build Homebrew installer package
run: productbuild --resources brew/package/resources
--distribution brew/package/Distribution.xml
--package-path Homebrew.pkg Homebrew-${{ steps.print-version.outputs.version }}.pkg
--sign "${PKG_APPLE_DEVELOPER_TEAM_ID}"

- name: Notarize Homebrew installer package
env:
PKG_APPLE_DEVELOPER_TEAM_ID: ${{ secrets.PKG_APPLE_DEVELOPER_TEAM_ID }}
PKG_APPLE_ID_USERNAME: ${{ secrets.PKG_APPLE_ID_USERNAME }}
PKG_APPLE_ID_APP_SPECIFIC_PASSWORD: ${{ secrets.PKG_APPLE_ID_APP_SPECIFIC_PASSWORD }}
run: xcrun notarytool submit Homebrew-${{ steps.print-version.outputs.version }}.pkg --team-id "${PKG_APPLE_DEVELOPER_TEAM_ID}" --apple-id "${PKG_APPLE_ID_USERNAME}" --password "${PKG_APPLE_ID_APP_SPECIFIC_PASSWORD}" --wait
run: xcrun notarytool submit Homebrew-${{ steps.print-version.outputs.version }}.pkg
--team-id "${PKG_APPLE_DEVELOPER_TEAM_ID}"
--apple-id "${PKG_APPLE_ID_USERNAME}"
--password "${PKG_APPLE_ID_APP_SPECIFIC_PASSWORD}"
--wait

- name: Clean up temporary macOS keychain
if: ${{ always() }}
run: test -f "${RUNNER_TEMP}/${TEMPORARY_KEYCHAIN_FILE}" && security delete-keychain "${RUNNER_TEMP}/${TEMPORARY_KEYCHAIN_FILE}"
run: |
if [[ -f "${RUNNER_TEMP}/${TEMPORARY_KEYCHAIN_FILE}" ]]
then
security delete-keychain "${RUNNER_TEMP}/${TEMPORARY_KEYCHAIN_FILE}"
fi
- uses: actions/upload-artifact@v3
- name: Upload installer to GitHub Actions
uses: actions/upload-artifact@v3
with:
name: Homebrew ${{ steps.print-version.outputs.version }}
path: Homebrew-${{ steps.print-version.outputs.version }}.pkg

- name: Upload installer to GitHub release
# if: startsWith(github.ref, 'refs/tags/')
env:
GH_TOKEN: ${{ github.token }}
run: |

Check failure on line 116 in .github/workflows/build-pkg.yml

View workflow job for this annotation

GitHub Actions / workflow_syntax

shellcheck reported issue in this script: SC2001:style:1:7: See if you can use ${variable//search/replace} instead
TAG=$(echo "${GITHUB_REF}" | sed -e 's|refs/tags/||g')
TAG="4.1.1"
gh release upload "$TAG" Homebrew-${{ steps.print-version.outputs.version }}.pkg
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@

# Unignore our packaging files
!/package
/package/resources/LICENSE.rtf

# Ignore generated documentation site
/docs/_site
Expand Down
47 changes: 47 additions & 0 deletions package/Distribution.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<installer-gui-script minSpecVersion="2">
<pkg-ref id="sh.brew.homebrew"/>
<options customize="never" hostArchitectures="x86_64,arm64" rootVolumeOnly="true"/>
<volume-check>
<allowed-os-versions>
<os-version min="11.0.0"/>
</allowed-os-versions>
</volume-check>
<choices-outline>
<line choice="default">
<line choice="sh.brew.homebrew"/>
</line>
</choices-outline>
<choice id="default"/>
<choice id="sh.brew.homebrew" visible="false">
<pkg-ref id="sh.brew.homebrew"/>
</choice>
<pkg-ref id="sh.brew.homebrew" onConclusion="none">Homebrew.pkg</pkg-ref>

<title>Homebrew</title>
<organization>sh.brew</organization>

<background file="Homebrew.png" alignment="bottomleft" scaling="proportional"/>
<background-darkAqua file="Homebrew.png" alignment="bottomleft" scaling="proportional"/>
<welcome file="WELCOME.rtf"/>
<license file="LICENSE.rtf"/>
<conclusion file="CONCLUSION.rtf" />
<allowed-os-versions>
<os-version min="11.0"/>
</allowed-os-versions>

<script>
function installation_check() {
if (system.files.fileExistsAtPath("/Library/Developer/CommandLineTools/usr/bin/git") ||
system.files.fileExistsAtPath("/Applications/Xcode.app/Contents/Developer/usr/bin/git")) {
return true;
} else {
my.result.title = "Xcode Command Line Tools (CLT) are missing";
my.result.message = "You must install the Xcode Command Line Tools (CLT) or Xcode before installing Homebrew. Install the CLT by running `xcode-select --install` from a Terminal.";
my.result.type = "Fatal";
return false;
}
}
</script>
<installation-check script="installation_check()" />
</installer-gui-script>
43 changes: 43 additions & 0 deletions package/resources/CONCLUSION.rtf
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{\rtf1\ansi\ansicpg1252\cocoartf2709
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica-Bold;\f1\fswiss\fcharset0 Helvetica;\f2\fnil\fcharset0 Menlo-Regular;
}
{\colortbl;\red255\green255\blue255;}
{\*\expandedcolortbl;;}
{\*\listtable{\list\listtemplateid1\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{hyphen\}}{\leveltext\leveltemplateid1\'01\uc0\u8259 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid1}
{\list\listtemplateid2\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{hyphen\}}{\leveltext\leveltemplateid101\'01\uc0\u8259 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid2}
{\list\listtemplateid3\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{hyphen\}}{\leveltext\leveltemplateid201\'01\uc0\u8259 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{hyphen\}}{\leveltext\leveltemplateid202\'01\uc0\u8259 ;}{\levelnumbers;}\fi-360\li1440\lin1440 }{\listname ;}\listid3}}
{\*\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}{\listoverride\listid2\listoverridecount0\ls2}{\listoverride\listid3\listoverridecount0\ls3}}
\paperw11900\paperh16840\margl1440\margr1440\vieww13440\viewh7240\viewkind0
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0

\f0\b\fs24 \cf0 Homebrew has enabled anonymous aggregate formulae and cask analytics.
\f1\b0 \
\
Read the analytics documentation (and how to opt-out) here:\
\pard\tx220\tx720\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li720\fi-720\pardirnatural\partightenfactor0
\ls1\ilvl0\cf0 {\listtext \uc0\u8259 }\ul https://docs.brew.sh/Analytics\
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0
\cf0 \ulnone No analytics data has been sent yet.\
\
Homebrew is run entirely by unpaid volunteers. Please consider donating:\
\pard\tx220\tx720\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li720\fi-720\pardirnatural\partightenfactor0
\ls2\ilvl0\cf0 {\listtext \uc0\u8259 }\ul https://github.com/Homebrew/brew#donations\
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0
\cf0 \ulc0 \
\ulnone Next steps:\ul \
\pard\tx220\tx720\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li720\fi-720\pardirnatural\partightenfactor0
\ls3\ilvl0\cf0 \ulnone {\listtext \uc0\u8259 }To add Homebrew to your
\f2 PATH
\f1 run
\f2 brew shellenv
\f1 in your shell profile (e.g.
\f2 ~/.bash_profile
\f1 or
\f2 ~/.zprofile
\f1 )\
{\listtext \uc0\u8259 }Run
\f2 brew help
\f1 to get started\
{\listtext \uc0\u8259 }Further documentation:\
\pard\tx940\tx1440\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li1440\fi-1440\pardirnatural\partightenfactor0
\ls3\ilvl1\cf0 {\listtext \uc0\u8259 }\ul https://docs.brew.sh}
Binary file added package/resources/Homebrew.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions package/resources/WELCOME.rtf
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{\rtf1\ansi\ansicpg1252\cocoartf2709
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fnil\fcharset0 Menlo-Regular;}
{\colortbl;\red255\green255\blue255;}
{\*\expandedcolortbl;;}
{\*\listtable{\list\listtemplateid1\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{hyphen\}}{\leveltext\leveltemplateid1\'01\uc0\u8259 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid1}}
{\*\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}}
\paperw11900\paperh16840\margl1440\margr1440\vieww13440\viewh7240\viewkind0
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0

\f0\fs24 \cf0 This package will install to:\
\pard\tx220\tx720\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li720\fi-720\pardirnatural\partightenfactor0
\ls1\ilvl0
\f1 \cf0 {\listtext \uc0\u8259 }/opt/homebrew
\f0 on Apple Silicon\
\ls1\ilvl0
\f1 {\listtext \uc0\u8259 }/usr/local/bin/brew
\f0 and
\f1 /usr/local/Homebrew
\f0 on Intel}
82 changes: 39 additions & 43 deletions package/scripts/postinstall
Original file line number Diff line number Diff line change
@@ -1,55 +1,51 @@
#!/bin/bash
# $1 Full path to the installer - unused
# $2 Location of the temporary brew install we're moving into place
# $3 Target install location - unused
# $4 System root directory - unused
set -e

# verify the files exist
tmp_brew="$2"
if [[ ! -d "${tmp_brew:?}" ]]
# $1 Full path to the installer (unused)
# $2 Location of the Homebrew installation we may need to move into place
# $3 Target install location (unused)
# $4 System root directory (unused)
set -xeuo pipefail

# disable analytics while installing
export HOMEBREW_NO_ANALYTICS_THIS_RUN=1
export HOMEBREW_NO_ANALYTICS_MESSAGE_OUTPUT=1

# verify the installation exists
homebrew_directory="$2"
if [[ ! -d "${homebrew_directory:?}" ]]
then
echo "no directory at ${tmp_brew}, exiting"
echo "no directory at ${homebrew_directory}!" >&2
exit 1
fi

# pick the correct target
# add Git to path
export PATH="/Library/Developer/CommandLineTools/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:${PATH}"

# reset Git repository
cd "${homebrew_directory}"
git reset --hard
git checkout master
git branch | grep -v '\*' | xargs -n 1 git branch -D

# move to /usr/local if on x86_64
if [[ $(uname -m) == "x86_64" ]]
then
target="/usr/local"
else
target="/opt/homebrew"
fi
mv "${homebrew_directory}" "/usr/local/Homebrew"
# create symlink to /usr/local/bin/brew
ln -s "/usr/local/Homebrew/bin/brew" "/usr/local/bin/brew"

loggedInUser=$(echo "show State:/Users/ConsoleUser" | scutil | awk '/Name :/ { print $3 }')
if [[ -f "${target}/bin/brew" ]]
then
if [[ $(sudo -u"${loggedInUser}" git -C "${target}" branch --show-current) != "master" ]]
then
echo "working on brew modifications, exiting"
rm -rf "${tmp_brew:?}/*"
exit 0
fi
if [[ $("${tmp_brew}/bin/brew" --version | head -n1) != $("${target}/bin/brew" --version | head -n1) ]]
then
echo "already an outdated install at ${target}, updating"
sudo -u"${loggedInUser}" "${target}/bin/brew" update --auto-update
else
echo "already an up-to-date install at ${target}, exiting"
fi

rm -rf "${tmp_brew:?}/*"
exit 0
homebrew_directory="/usr/local"
cd "${homebrew_directory}"
fi

group=$(id -gn "${loggedInUser}")

install -d -o "root" -g "wheel" -m "0755" "${target}"

cp -RX "${tmp_brew}/" "${target}"
# create missing directories
sudo mkdir -p Cellar Frameworks etc include lib opt sbin share var/homebrew/linked

# set permissions
chown -R "${loggedInUser}:${group}" "${target}/*"

# cleanup
rm -rf "${tmp_brew:?}/*"
logged_in_user=$(echo "show State:/Users/ConsoleUser" | scutil | awk '/Name :/ { print $3 }')
group=$(id -gn "${logged_in_user}")
if [[ "${homebrew_directory}" == "/usr/local" ]]
then
chown -R "${logged_in_user}:${group}" Cellar Frameworks Homebrew bin etc include lib sbin share var/homebrew/linked
else
chown -R "${logged_in_user}:${group}" .
fi
32 changes: 0 additions & 32 deletions package/scripts/preinstall

This file was deleted.

0 comments on commit 408c5b4

Please sign in to comment.