Skip to content

Commit

Permalink
feat: Add script to build a macOS installer (#83)
Browse files Browse the repository at this point in the history
  • Loading branch information
patricksanders authored Aug 26, 2021
1 parent 6a530ff commit 280d941
Show file tree
Hide file tree
Showing 12 changed files with 390 additions and 3 deletions.
61 changes: 61 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,64 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
-
name: Store Binaries
uses: actions/upload-artifact@v2
with:
name: binaries
path: dist/bin/
retention-days: 5
package:
needs: goreleaser
runs-on: macos-latest
environment: Signing
steps:
-
name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
-
name: Retrieve Binaries
uses: actions/download-artifact@v2
with:
name: binaries
path: dist/bin/
-
name: Import Signing Certificates
uses: apple-actions/import-codesign-certs@v1
with:
p12-file-base64: ${{ secrets.CERTIFICATES_P12 }}
p12-password: ${{ secrets.CERTIFICATES_P12_PASSWORD }}
-
name: Build, Sign, & Notarize Package
env:
AC_PASSWORD: ${{ secrets.AC_PASSWORD }}
VERSION: ${{ env.GITHUB_REF }}
run: |
./build/build_package.sh
-
name: Store Package
uses: actions/upload-artifact@v2
with:
name: package
path: dist/macos/*.pkg
upload:
needs: package
runs-on: ubuntu-latest
steps:
-
name: Retrieve Package
uses: actions/download-artifact@v2
with:
name: package
path: dist/macos/
-
name: Upload package to release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: dist/macos/*.pkg
file_glob: true
tag: ${{ github.ref }}
overwrite: true
7 changes: 4 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ dist/
# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Generated source files
pkged.go

# Dependency directories (remove the comment below to include it)
# vendor/

# IDE configs
.idea/

# Build files
build/package/macos/tmp/
build/package/macos/application/bin/
4 changes: 4 additions & 0 deletions build/.goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ builds:
-X github.com/netflix/weep/internal/metadata.Commit={{.CommitDate}}
-X github.com/netflix/weep/internal/metadata.Date={{.Date}}
mod_timestamp: '{{ .CommitTimestamp }}'
no_unique_dist_dir: true
binary: 'bin/{{ .Target }}/weep'
-
id: demo
env:
Expand All @@ -35,6 +37,8 @@ builds:
-X github.com/netflix/weep/metadata.Commit={{.CommitDate}}
-X github.com/netflix/weep/metadata.Date={{.Date}}
mod_timestamp: '{{ .CommitTimestamp }}'
no_unique_dist_dir: true
binary: 'bin/demo/{{ .Target }}/weep'
archives:
-
builds:
Expand Down
149 changes: 149 additions & 0 deletions build/build_package.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
#!/usr/bin/env bash
##############################################################################
# Build a macOS installer package containing a weep universal binary
# Author: Patrick Sanders <[email protected]>
##############################################################################
set -euo pipefail

BASE_DIR="build/package/macos"
APP_DIR="$BASE_DIR/application"
BIN_DIR="$APP_DIR/bin"
BUILD_DIR="$BASE_DIR/tmp"
PKG_DIR="$BUILD_DIR/darwinpkg"
OUT_DIR="dist/macos"
VERSION=${VERSION:=dev}
FINAL_PACKAGE="$OUT_DIR/weep-installer-macos-$VERSION.pkg"

rm -rf "$BIN_DIR"
rm -rf "$BUILD_DIR"
mkdir -p "$BIN_DIR"
mkdir -p "$OUT_DIR"
mkdir -p "$PKG_DIR"

cp -r "$BASE_DIR/darwin" "$BUILD_DIR/"
chmod -R 755 "$BUILD_DIR/darwin/scripts"
chmod 755 "$BUILD_DIR/darwin/Distribution.xml"

printf "🟢 starting build for %s\n" "$FINAL_PACKAGE"

function prep_package() {
# Prepare package structure
mkdir -p "$BUILD_DIR/darwinpkg/Library/weep"
cp -a "$APP_DIR/." "$BUILD_DIR/darwinpkg/Library/weep"
chmod -R 755 "$BUILD_DIR/darwinpkg/Library/weep"

# Replace tokens in package files
sed -i '' -e "s/__VERSION__/$VERSION/g" ${BUILD_DIR}/darwin/Resources/*.html
}

function combine_binaries() {
printf "🦾 creating universal binary..."
output=$1
bin1=$2
bin2=$3
lipo -create -output "$output" "$bin1" "$bin2"
printf " done ✅ \n"
}

function sign_binary() {
printf "🔏 signing binary..."
binary=$1
codesign \
--options runtime \
--sign "Developer ID Application: Netflix, Inc." \
--force \
--timestamp=http://timestamp.apple.com/ts01 \
"$binary" > /dev/null 2>&1
printf " done ✅ \n"
}

function build_package() {
printf "📦 building package..."
pkgbuild --identifier "com.netflix.weep" \
--version "$VERSION" \
--scripts "$BUILD_DIR/darwin/scripts" \
--root "$BUILD_DIR/darwinpkg" \
weep.pkg > /dev/null 2>&1

productbuild --distribution "$BUILD_DIR/darwin/Distribution.xml" \
--resources "$BUILD_DIR/darwin/Resources" \
--package-path "$BUILD_DIR/package" \
"$OUT_DIR/weep-$VERSION-unsigned.pkg" > /dev/null 2>&1
printf " done ✅ \n"
}

function sign_package() {
printf "🔏 signing package..."
productsign --sign "Developer ID Installer: Netflix, Inc." \
"$OUT_DIR/weep-$VERSION-unsigned.pkg" \
"$FINAL_PACKAGE" > /dev/null 2>&1

pkgutil --check-signature "$FINAL_PACKAGE" > /dev/null 2>&1
printf " done ✅ \n"
}

function notarize() {
printf "🔐 notarizing package..."
output=$(xcrun altool \
--notarize-app \
--primary-bundle-id "com.netflix.weep" \
--username "[email protected]" \
--password "$AC_PASSWORD" \
--file "$FINAL_PACKAGE")
printf " done ✅ \n"
request_id=$(echo "$output" | grep RequestUUID | awk '{ print $3 }')
printf "💡 notarize request id is %s\n" "$request_id"
# give the server side a few seconds to sort things out
sleep 3
while true; do
status=$(check_notarize_status "$request_id")
printf "👀 current status \"%s\"" "$status"
case "$status" in
"success")
printf ", done ✅ \n"
break
;;
"failure")
printf ", exiting! 🔴\n"
exit 1
;;
*)
printf ", not ready yet 😴\n"
sleep 5
;;
esac
done
}

function check_notarize_status() {
request_id=$1
output=$(xcrun altool \
--notarization-info "$request_id" \
--username "[email protected]" \
--password "$AC_PASSWORD")
status=$(echo "$output" | grep "Status:" | awk '{ for (i=2; i<=NF; i++) printf("%s ", $i) }' | awk '{$1=$1;print}')
echo "$status"
}

function staple() {
printf "📎 stapling..."
xcrun stapler staple "$FINAL_PACKAGE" > /dev/null 2>&1
printf " done ✅ \n"
}

function cleanup() {
rm dist/macos/*-unsigned.pkg
}

combine_binaries "$BIN_DIR/weep-universal" \
dist/bin/darwin_amd64/weep \
dist/bin/darwin_arm64/weep
sign_binary "$BIN_DIR/weep-universal"
prep_package
build_package
sign_package
notarize
staple
cleanup

printf "🙌 successfully built and notarized %s 🎉 \n" "$FINAL_PACKAGE"
46 changes: 46 additions & 0 deletions build/package/macos/application/uninstall.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/bin/bash

#Check running user
if (( $EUID != 0 )); then
echo "Please run as root."
exit
fi

echo "Welcome to the Weep Uninstaller"
echo "The following packages will be REMOVED:"
echo " weep"
while true; do
read -p "Do you wish to continue [Y/n]?" answer
[[ $answer == "y" || $answer == "Y" || $answer == "" ]] && break
[[ $answer == "n" || $answer == "N" ]] && exit 0
echo "Please answer with 'y' or 'n'"
done


echo "Uninstalling Weep"
# remove binary symlink
if rm -rf "/usr/local/bin/weep"
then
echo "[1/3] [DONE] Successfully deleted shortcut links"
else
echo "[1/3] [ERROR] Could not delete shortcut links" >&2
fi

#forget from pkgutil
if pkgutil --forget "com.netflix.weep" > /dev/null 2>&1
then
echo "[2/3] [DONE] Successfully deleted application information"
else
echo "[2/3] [ERROR] Could not delete application information" >&2
fi

#remove application source distribution
if rm -rf "/Library/weep"
then
echo "[3/3] [DONE] Successfully deleted application"
else
echo "[3/3] [ERROR] Could not delete application" >&2
fi

echo "Application uninstall process finished"
exit 0
29 changes: 29 additions & 0 deletions build/package/macos/darwin/Distribution.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<installer-script minSpecVersion="1.000000">
<title>Weep</title>
<background mime-type="image/png" alignment="bottomleft" file="banner.png" scaling="proportional"/>
<welcome file="welcome.html" mime-type="text/html" />
<conclusion file="conclusion.html" mime-type="text/html" />
<license file="LICENSE"/>
<options customize="never" allow-external-scripts="no"/>
<domains enable_localSystem="true" />
<installation-check script="installCheck();"/>
<script>
function installCheck() {
if(system.files.fileExistsAtPath('/Library/weep/')) {
my.result.title = 'Previous Installation Detected';
my.result.message = 'A previous installation of Weep exists at /Library/weep. This installer will remove the previous installation prior to installing.';
my.result.type = 'Warning';
return false;
}
return true;
}
</script>
<choices-outline>
<line choice="Weep"/>
</choices-outline>
<choice id="Weep" title="Weep">
<pkg-ref id="weep.pkg"/>
</choice>
<pkg-ref id="weep.pkg" auth="Root">weep.pkg</pkg-ref>
</installer-script>
1 change: 1 addition & 0 deletions build/package/macos/darwin/Resources/LICENSE
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
50 changes: 50 additions & 0 deletions build/package/macos/darwin/Resources/conclusion.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Install Weep</title>
<style>
body {
font-family: Helvetica, sans-serif;
}
p {
color: #020202;
}
code {
color: #c6a72b;
font-size: 11px;
font-family: Menlo, monospace;
}
div {
padding-left: 10px;
}
.footer {
font-size: 10px;
position: absolute;
bottom: 25px;
left: 10px;
width: 100%;
height: 10px;
}
</style>
</head>
<body>
<div>
<p>Thank you for installing Weep.</p>
<h4>Run Weep</h4>
<p>Open a new terminal and run the following command to get started with Weep:</p>
<code>&nbsp; $ <span style="color: #abb0b0">weep --help</span></code>
</div>
<div>
<br/>
<h4>Uninstall Weep</h4>
<p>Run the following command to uninstall Weep: <br />
<code><br />&nbsp; $ <span style="color: #abb0b0">sudo /Library/weep/uninstall.sh</span></code>
</p>
</div>
<div class="footer">
<p>Copyright © 2021 Netflix, Inc. All rights reserved.</p>
<p>Take care. Stay rad.</p>
</div>
</body>
</html>
Loading

0 comments on commit 280d941

Please sign in to comment.