Skip to content

Commit

Permalink
Build flat package for macOS
Browse files Browse the repository at this point in the history
  • Loading branch information
ofek committed Sep 20, 2023
1 parent 166ddd1 commit a08e7fc
Show file tree
Hide file tree
Showing 9 changed files with 300 additions and 69 deletions.
81 changes: 35 additions & 46 deletions .github/workflows/build-hatch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -371,9 +371,6 @@ jobs:
- name: Install PyOxidizer ${{ env.PYOXIDIZER_VERSION }}
run: pip install pyoxidizer==${{ env.PYOXIDIZER_VERSION }}

- name: Install create-dmg
run: brew install create-dmg

# TODO: Use the next official release after 0.22.0 by removing these 2 blocks, uncommenting
# the following one, and changing the artifact name to reflect the next version. See:
# https://github.com/indygreg/apple-platform-rs/issues/82
Expand Down Expand Up @@ -409,10 +406,14 @@ jobs:
env:
APPLE_DEVELOPER_ID_APPLICATION_CERTIFICATE: "${{ secrets.APPLE_DEVELOPER_ID_APPLICATION_CERTIFICATE }}"
APPLE_DEVELOPER_ID_APPLICATION_PRIVATE_KEY: "${{ secrets.APPLE_DEVELOPER_ID_APPLICATION_PRIVATE_KEY }}"
APPLE_DEVELOPER_ID_INSTALLER_CERTIFICATE: "${{ secrets.APPLE_DEVELOPER_ID_INSTALLER_CERTIFICATE }}"
APPLE_DEVELOPER_ID_INSTALLER_PRIVATE_KEY: "${{ secrets.APPLE_DEVELOPER_ID_INSTALLER_PRIVATE_KEY }}"
APPLE_APP_STORE_CONNECT_API_DATA: "${{ secrets.APPLE_APP_STORE_CONNECT_API_DATA }}"
run: |-
echo "$APPLE_DEVELOPER_ID_APPLICATION_CERTIFICATE" > /tmp/certificate.pem
echo "$APPLE_DEVELOPER_ID_APPLICATION_PRIVATE_KEY" > /tmp/private-key.pem
echo "$APPLE_DEVELOPER_ID_APPLICATION_CERTIFICATE" > /tmp/certificate-application.pem
echo "$APPLE_DEVELOPER_ID_APPLICATION_PRIVATE_KEY" > /tmp/private-key-application.pem
echo "$APPLE_DEVELOPER_ID_INSTALLER_CERTIFICATE" > /tmp/certificate-installer.pem
echo "$APPLE_DEVELOPER_ID_INSTALLER_PRIVATE_KEY" > /tmp/private-key-installer.pem
echo "$APPLE_APP_STORE_CONNECT_API_DATA" > /tmp/app-store-connect.json
# We cannot use anchors because of https://github.com/actions/runner/issues/1182 and
Expand All @@ -437,8 +438,8 @@ jobs:
script<<INNER
for f in bin/*; do
rcodesign sign -vv \
--pem-source /tmp/certificate.pem \
--pem-source /tmp/private-key.pem \
--pem-source /tmp/certificate-application.pem \
--pem-source /tmp/private-key-application.pem \
--code-signature-flags runtime \
"$f"
done
Expand Down Expand Up @@ -528,65 +529,53 @@ jobs:
fi
done
- name: Build app bundle
- name: Build universal binary
run: >-
pyoxidizer build macos_app_bundle
pyoxidizer build macos_universal_binary
--release
--var version ${{ env.VERSION }}
- name: Stage app bundle
id: stage
- name: Prepare universal binary
id: binary
run: |-
mkdir staged
mkdir signed
mv build/*/release/*/*.app staged
app_bundle="$(ls staged)"
app_name="${app_bundle:0:${#app_bundle}-4}"
binary=$(echo build/*/release/*/${{ env.APP_NAME }})
chmod +x "$binary"
echo "path=$binary" >> "$GITHUB_OUTPUT"
echo "app-bundle=$app_bundle" >> "$GITHUB_OUTPUT"
echo "app-name=$app_name-${{ env.VERSION }}.dmg" >> "$GITHUB_OUTPUT"
echo "dmg-file=$app_name-${{ env.VERSION }}.dmg" >> "$GITHUB_OUTPUT"
- name: Sign app bundle
- name: Build PKG
run: >-
rcodesign sign -vv
--pem-source /tmp/certificate.pem
--pem-source /tmp/private-key.pem
"staged/${{ steps.stage.outputs.app-bundle }}"
"signed/${{ steps.stage.outputs.app-bundle }}"
python release/macos/build_pkg.py
--binary ${{ steps.binary.outputs.path }}
--version ${{ env.VERSION }}
staged
- name: Create DMG
run: >-
create-dmg
--volname "${{ steps.stage.outputs.app-name }}"
--hide-extension "${{ steps.stage.outputs.app-bundle }}"
--window-pos 200 120
--window-size 800 400
--icon-size 100
--app-drop-link 600 185
"${{ steps.stage.outputs.dmg-file }}"
signed
- name: Sign DMG
- name: Stage PKG
id: pkg
run: |-
mkdir signed
pkg_file="$(ls staged)"
echo "path=$pkg_file" >> "$GITHUB_OUTPUT"
- name: Sign PKG
run: >-
rcodesign sign -vv
--pem-source /tmp/certificate.pem
--pem-source /tmp/private-key.pem
"${{ steps.stage.outputs.dmg-file }}"
"${{ steps.stage.outputs.dmg-file }}"
--pem-source /tmp/certificate-installer.pem
--pem-source /tmp/private-key-installer.pem
"staged/${{ steps.pkg.outputs.path }}"
"signed/${{ steps.pkg.outputs.path }}"
- name: Notarize DMG
- name: Notarize PKG
run: >-
rcodesign notary-submit
--api-key-path /tmp/app-store-connect.json
--staple
"${{ steps.stage.outputs.dmg-file }}"
"signed/${{ steps.pkg.outputs.path }}"
- name: Upload installer
uses: actions/upload-artifact@v3
with:
name: installers
path: ${{ steps.stage.outputs.dmg-file }}
path: signed/${{ steps.pkg.outputs.path }}

publish:
name: Publish release
Expand Down
28 changes: 28 additions & 0 deletions docs/.hooks/inject_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import os
import subprocess
from functools import cache

MARKER = '<HATCH_LATEST_VERSION>'
SEMVER_PARTS = 3

# Ignore the current documentation environment so that the version
# command can execute as usual in the default build environment
os.environ.pop('HATCH_ENV_ACTIVE', None)


@cache
def get_latest_version():
output = subprocess.check_output(['hatch', 'version']).decode('utf-8').strip()

version = output.replace('dev', '')
parts = list(map(int, version.split('.')))
major, minor, patch = parts[:SEMVER_PARTS]
if len(parts) > SEMVER_PARTS:
patch -= 1

return f'{major}.{minor}.{patch}'


def on_page_read_source(page, config):
with open(page.file.abs_src_path, encoding='utf-8') as f:
return f.read().replace(MARKER, get_latest_version())
90 changes: 82 additions & 8 deletions docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,88 @@

-----

## GitHub releases

Each [release](https://github.com/pypa/hatch/releases) provides the following:

- Standalone binaries for Linux, Windows, and macOS
- Windows AMD64 (64-bit) MSI installer
- Windows x86 (32-bit) MSI installer
- Windows universal (AMD64+x86) EXE installer
## Installers

=== "macOS"
=== "GUI installer"
1. In your browser, download the `.pkg` file: [hatch-<HATCH_LATEST_VERSION>.pkg](https://github.com/pypa/hatch/releases/download/hatch-v<HATCH_LATEST_VERSION>/hatch-<HATCH_LATEST_VERSION>.pkg)
2. Run your downloaded file and follow the on-screen instructions.
3. Restart your terminal.
4. To verify that the shell can find and run the `hatch` command in your `PATH`, use the following command.

```
$ hatch --version
<HATCH_LATEST_VERSION>
```
=== "Command line installer"
1. Download the file using the `curl` command. The `-o` option specifies the file name that the downloaded package is written to. In this example, the file is written to `hatch-<HATCH_LATEST_VERSION>.pkg` in the current directory.

```
curl -o hatch-<HATCH_LATEST_VERSION>.pkg https://github.com/pypa/hatch/releases/download/hatch-v<HATCH_LATEST_VERSION>/hatch-<HATCH_LATEST_VERSION>.pkg
```
2. Run the standard macOS [`installer`](https://ss64.com/osx/installer.html) program, specifying the downloaded `.pkg` file as the source. Use the `-pkg` parameter to specify the name of the package to install, and the `-target /` parameter for the drive in which to install the package. The files are installed to `/usr/local/hatch`, and an entry is created at `/etc/paths.d/hatch` that instructs shells to add the `/usr/local/hatch` directory to. You must include sudo on the command to grant write permissions to those folders.

```
sudo installer -pkg ./hatch-<HATCH_LATEST_VERSION>.pkg -target /
```
3. Restart your terminal.
4. To verify that the shell can find and run the `hatch` command in your `PATH`, use the following command.

```
$ hatch --version
<HATCH_LATEST_VERSION>
```

=== "Windows"
=== "GUI installer"
1. In your browser, download one the `.msi` files:
- [hatch-<HATCH_LATEST_VERSION>-x64.msi](https://github.com/pypa/hatch/releases/download/hatch-v<HATCH_LATEST_VERSION>/hatch-<HATCH_LATEST_VERSION>-x64.msi)
- [hatch-<HATCH_LATEST_VERSION>-x86.msi](https://github.com/pypa/hatch/releases/download/hatch-v<HATCH_LATEST_VERSION>/hatch-<HATCH_LATEST_VERSION>-x86.msi)
2. Run your downloaded file and follow the on-screen instructions.
3. Restart your terminal.
4. To verify that the shell can find and run the `hatch` command in your `PATH`, use the following command.

```
$ hatch --version
<HATCH_LATEST_VERSION>
```
=== "Command line installer"
1. Download and run the installer using the standard Windows [`msiexec`](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/msiexec) program, specifying one of the `.msi` files as the source. Use the `/passive` and `/i` parameters to request an unattended, normal installation.

=== "x64"
```
msiexec /passive /i https://github.com/pypa/hatch/releases/download/hatch-v<HATCH_LATEST_VERSION>/hatch-<HATCH_LATEST_VERSION>-x64.msi
```
=== "x86"
```
msiexec /passive /i https://github.com/pypa/hatch/releases/download/hatch-v<HATCH_LATEST_VERSION>/hatch-<HATCH_LATEST_VERSION>-x86.msi
```
2. Restart your terminal.
3. To verify that the shell can find and run the `hatch` command in your `PATH`, use the following command.

```
$ hatch --version
<HATCH_LATEST_VERSION>
```

## Standalone binaries

After downloading the archive corresponding to your platform and architecture, extract the binary to a directory that is on your PATH and rename to `hatch`.

=== "macOS"
- [hatch-<HATCH_LATEST_VERSION>-aarch64-apple-darwin.tar.gz](https://github.com/pypa/hatch/releases/download/hatch-v<HATCH_LATEST_VERSION>/hatch-<HATCH_LATEST_VERSION>-aarch64-apple-darwin.tar.gz)
- [hatch-<HATCH_LATEST_VERSION>-x86_64-apple-darwin.tar.gz](https://github.com/pypa/hatch/releases/download/hatch-v<HATCH_LATEST_VERSION>/hatch-<HATCH_LATEST_VERSION>-x86_64-apple-darwin.tar.gz)

=== "Windows"
- [hatch-<HATCH_LATEST_VERSION>-x86_64-pc-windows-msvc.zip](https://github.com/pypa/hatch/releases/download/hatch-v<HATCH_LATEST_VERSION>/hatch-<HATCH_LATEST_VERSION>-x86_64-pc-windows-msvc.zip)
- [hatch-<HATCH_LATEST_VERSION>-i686-pc-windows-msvc.zip](https://github.com/pypa/hatch/releases/download/hatch-v<HATCH_LATEST_VERSION>/hatch-<HATCH_LATEST_VERSION>-i686-pc-windows-msvc.zip)

=== "Linux"
- [hatch-<HATCH_LATEST_VERSION>-aarch64-unknown-linux-gnu.tar.gz](https://github.com/pypa/hatch/releases/download/hatch-v<HATCH_LATEST_VERSION>/hatch-<HATCH_LATEST_VERSION>-aarch64-unknown-linux-gnu.tar.gz)
- [hatch-<HATCH_LATEST_VERSION>-x86_64-unknown-linux-gnu.tar.gz](https://github.com/pypa/hatch/releases/download/hatch-v<HATCH_LATEST_VERSION>/hatch-<HATCH_LATEST_VERSION>-x86_64-unknown-linux-gnu.tar.gz)
- [hatch-<HATCH_LATEST_VERSION>-x86_64-unknown-linux-musl.tar.gz](https://github.com/pypa/hatch/releases/download/hatch-v<HATCH_LATEST_VERSION>/hatch-<HATCH_LATEST_VERSION>-x86_64-unknown-linux-musl.tar.gz)
- [hatch-<HATCH_LATEST_VERSION>-i686-unknown-linux-gnu.tar.gz](https://github.com/pypa/hatch/releases/download/hatch-v<HATCH_LATEST_VERSION>/hatch-<HATCH_LATEST_VERSION>-i686-unknown-linux-gnu.tar.gz)
- [hatch-<HATCH_LATEST_VERSION>-powerpc64le-unknown-linux-gnu.tar.gz](https://github.com/pypa/hatch/releases/download/hatch-v<HATCH_LATEST_VERSION>/hatch-<HATCH_LATEST_VERSION>-powerpc64le-unknown-linux-gnu.tar.gz)

## pip

Expand Down
3 changes: 3 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ watch:
- backend/src/hatchling
- src/hatch

hooks:
- docs/.hooks/inject_version.py

plugins:
# Built-in
search: {}
Expand Down
18 changes: 3 additions & 15 deletions pyoxidizer.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,7 @@ def make_exe_installer():
return bundle


def make_macos_app_bundle():
# https://gregoryszorc.com/docs/pyoxidizer/main/tugger_starlark_type_macos_application_bundle_builder.html
bundle = MacOsApplicationBundleBuilder(DISPLAY_NAME)
bundle.set_info_plist_required_keys(
display_name=DISPLAY_NAME,
identifier="org.python." + APP_NAME,
version=VERSION,
signature="htch",
executable=APP_NAME,
)

def make_macos_universal_binary():
# https://gregoryszorc.com/docs/pyoxidizer/main/tugger_starlark_type_apple_universal_binary.html
universal = AppleUniversalBinary(APP_NAME)

Expand All @@ -83,12 +73,10 @@ def make_macos_app_bundle():

m = FileManifest()
m.add_file(universal.to_file_content())
bundle.add_macos_manifest(m)

return bundle
return m


register_target("windows_installers", make_exe_installer, default=True)
register_target("macos_app_bundle", make_macos_app_bundle)
register_target("macos_universal_binary", make_macos_universal_binary)

resolve_targets()
5 changes: 5 additions & 0 deletions release/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Release assets

-----

This directory stores files related to building binaries and installers for each platform.
Loading

0 comments on commit a08e7fc

Please sign in to comment.