-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reimplement macOS application (.app) build scripts
- Loading branch information
1 parent
3690174
commit 210c475
Showing
16 changed files
with
544 additions
and
686 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
Orange macOS application (.app) build scripts | ||
--------------------------------------------- | ||
|
||
Contents: | ||
|
||
python-framework.sh | ||
Download, unpack and make relocatable the official python.org framework | ||
installers (used by build-macos-app.sh) | ||
|
||
build-macos-app.sh | ||
Build an Orange.app application bundle from scratch | ||
|
||
create-dmg-installer.sh | ||
Pack the Orange.app applicaiton into a .dmg installer disk image |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
#!/usr/bin/env bash | ||
|
||
set -e | ||
|
||
usage() { | ||
echo 'usage: build-macos-app.sh [--python-version VER] [--pip-arg ARG] APPPATH | ||
Create (build) an macOS application bundle | ||
Options: | ||
--python-version VERSION | ||
Python version to install in the application bundle (default: 3.6.1) | ||
--pip-arg ARG | ||
Pip install arguments to populate the python environemnt in the | ||
application bundle. Can be used multiple times. | ||
If not supplied then by default the latest PyPi published Orange3 and | ||
requirements as recorded in scripts/macos/requirements.txt are | ||
installed. | ||
-h|--help | ||
Print this help | ||
Examples | ||
build-macos-app.sh ~/Applications/Orange3.app | ||
Build the application using the latest published version on pypi | ||
build-macos-app.sh --pip-arg={Orange3==3.3.12,PyQt5} ~/Applications/Orange3.app | ||
Build the application using the specified Orange version | ||
build-macos-app.sh --pip-arg=path-tolocal-checkout ~/Applications/Orange3-Dev.app | ||
Build the application using a local source checkout | ||
build-macos-app.sh --pip-arg={-e,path-tolocal-checkout} ~/Applications/Orange3-Dev.app | ||
Build the application and install orange in editable mode | ||
buils-macos-app.sh --pip-arg={-r,requirements.txt} /Applications/Orange3.app | ||
Build the application using a fixed set of locked requirements. | ||
' | ||
} | ||
|
||
DIR=$(dirname "$0") | ||
|
||
# Python version in the bundled framework | ||
PYTHON_VERSION=3.6.1 | ||
|
||
# Pip arguments used to populate the python environment in the application | ||
# bundle | ||
PIP_REQ_ARGS=( ) | ||
|
||
while [[ "${1:0:1}" == "-" ]]; do | ||
case "${1}" in | ||
--python-version=*) | ||
PYTHON_VERSION=${1#*=} | ||
shift 1;; | ||
--python-version) | ||
PYTHON_VERSION=${2:?"--python-version requires an argument"} | ||
shift 2;; | ||
--pip-arg=*) | ||
PIP_REQ_ARGS+=( "${1#*=}" ) | ||
shift 1;; | ||
--pip-arg) | ||
PIP_REQ_ARGS+=( "${2:?"--pip-arg requires an argument"}" ) | ||
shift 2;; | ||
--help|-h) | ||
usage; exit 0;; | ||
-*) | ||
echo "Invalid argument ${1}" >&2; usage >&2; exit 1;; | ||
esac | ||
done | ||
|
||
APPDIR=${1:?"Target APPDIR argument is missing"} | ||
|
||
PYVER=${PYTHON_VERSION%.*} # Major.Minor | ||
|
||
if [[ ${#PIP_REQ_ARGS[@]} -eq 0 ]]; then | ||
PIP_REQ_ARGS+=( Orange3 -r "${DIR}"/requirements.txt ) | ||
fi | ||
|
||
mkdir -p "${APPDIR}"/Contents/MacOS | ||
mkdir -p "${APPDIR}"/Contents/Frameworks | ||
mkdir -p "${APPDIR}"/Contents/Resources | ||
|
||
cp -a "${DIR}"/skeleton.app/Contents/{Resources,Info.plist.in} \ | ||
"${APPDIR}"/Contents | ||
|
||
# Layout a 'relocatable' python framework in the app directory | ||
"${DIR}"/python-framework.sh \ | ||
--version "${PYTHON_VERSION}" \ | ||
"${APPDIR}"/Contents/Frameworks | ||
|
||
ln -fs ../Frameworks/Python.framework/Versions/${PYVER}/Resources/Python.app/Contents/MacOS/Python \ | ||
"${APPDIR}"/Contents/MacOS/PythonApp | ||
|
||
ln -fs ../Frameworks/Python.framework/Versions/${PYVER}/bin/python${PYVER} \ | ||
"${APPDIR}"/Contents/MacOS/python | ||
|
||
"${APPDIR}"/Contents/MacOS/python -m ensurepip | ||
"${APPDIR}"/Contents/MacOS/python -m pip install pip~=9.0 wheel | ||
|
||
# Python 3.6 on macOS no longer links the obsolete system libssl. | ||
# Instead it builds/ships a it's own which expects a cert.pem in hardcoded | ||
# /Library/Python.framework/3.6/etc/openssl/ path (but does no actually ship | ||
# the file in the framework installer). Instead a user is prompted during | ||
# .pkg install to run a script that pip install's certifi and links its | ||
# cacert.pem to the etc/openssl dir. We do the same but must also patch | ||
# ssl.py to load the cert store from a python prefix relative path (this is | ||
# done by python-framework.sh script). Another option would be to export system | ||
# certificates at runtime using the 'security' command line tool. | ||
"${APPDIR}"/Contents/MacOS/python -m pip install certifi | ||
# link the certifi supplied cert store to ${prefix}/etc/openssl/cert.pem | ||
ln -fs ../../lib/python${PYVER}/site-packages/certifi/cacert.pem \ | ||
"${APPDIR}"/Contents/Frameworks/Python.framework/Versions/${PYVER}/etc/openssl/cert.pem | ||
# sanity check | ||
test -r "${APPDIR}"/Contents/Frameworks/Python.framework/Versions/${PYVER}/etc/openssl/cert.pem | ||
|
||
cat <<'EOF' > "${APPDIR}"/Contents/MacOS/Orange | ||
#!/bin/bash | ||
DIR=$(dirname "$0") | ||
# LaunchServices passes the Carbon process identifier to the application with | ||
# -psn parameter - we do not want it | ||
if [[ "${1}" == -psn_* ]]; then | ||
shift 1 | ||
fi | ||
# Disable user site packages | ||
export PYTHONNOUSERSITE=1 | ||
exec "${DIR}"/PythonApp -m Orange.canvas "$@" | ||
EOF | ||
chmod +x "${APPDIR}"/Contents/MacOS/Orange | ||
|
||
cat <<'EOF' > "${APPDIR}"/Contents/MacOS/pip | ||
#!/bin/bash | ||
DIR=$(dirname "$0") | ||
# Disable user site packages | ||
export PYTHONNOUSERSITE=1 | ||
exec -a "$0" "${DIR}"/python -m pip "$@" | ||
EOF | ||
chmod +x "${APPDIR}"/Contents/MacOS/pip | ||
|
||
PYTHON="${APPDIR}"/Contents/MacOS/python | ||
|
||
"${PYTHON}" -m pip install "${PIP_REQ_ARGS[@]}" | ||
|
||
VERSION=$("${PYTHON}" -m pip show orange3 | grep -E '^Version:' | | ||
cut -d " " -f 2) | ||
|
||
m4 -D__VERSION__="${VERSION:?}" "${APPDIR}"/Contents/Info.plist.in \ | ||
> "${APPDIR}"/Contents/Info.plist | ||
|
||
# Sanity check | ||
"${PYTHON}" -m pip install --no-cache-dir --no-index orange3 PyQt5 | ||
"${PYTHON}" -m Orange.canvas --help > /dev/null |
Oops, something went wrong.