forked from 1b-agent/fieldcraft-upstream
packaging: macOS app and dmg, Linux tar.gz and AppImage, Windows zip
packaging/macos/package.sh builds FieldCraft.app (io.github.jyviko.fieldcraft, with icon.icns and the layered Assets.car), signs it with a Developer ID and notarizes it when the credentials are there and ad-hoc otherwise, and puts it on a drag-to-Applications dmg that is mounted and checked; fieldcraft-cli goes in its own zip. packaging/linux/package.sh makes an FHS tar.gz (binaries, .desktop entry, hicolor icons, licences) and an AppImage made with appimagetool and the type 2 runtime at pinned, hash-checked releases. packaging/windows/package.ps1 zips fieldcraft.exe and fieldcraft-cli.exe (static CRT, checked PE headers and icon). Every package carries README.md, LICENSE-MIT, LICENSE-APACHE, NOTICE and THIRD-PARTY-LICENSES.txt (#72). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm
This commit is contained in:
1 parent
858b6e9dee
commit
0d7c881eea
13 files changed
+695
No files matched your search
@@ -1,2 +1,8 @@
|
||||
[alias]
|
||||
xtask = "run --package xtask --"
|
||||
|
||||
# Windows release binaries link the C runtime statically, so they run without the VC++
|
||||
# redistributable (packaging/windows/package.ps1 builds with --target, which keeps the flag
|
||||
# off build scripts and proc-macros).
|
||||
[target.x86_64-pc-windows-msvc]
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
@@ -154,6 +154,7 @@ is committed and listed here with its exports.
|
||||
| assets/app-icon/icon.iconset/icon_256x256@2x.png | FieldCraft contributors | sips export (512 px) of assets/app-icon/icon.png | MIT OR Apache-2.0 |
|
||||
| assets/app-icon/icon.iconset/icon_512x512.png | FieldCraft contributors | sips export (512 px) of assets/app-icon/icon.png | MIT OR Apache-2.0 |
|
||||
| assets/app-icon/icon.iconset/icon_512x512@2x.png | FieldCraft contributors | sips export (1024 px) of assets/app-icon/icon.png | MIT OR Apache-2.0 |
|
||||
| packaging/macos/README.txt, packaging/linux/io.github.jyviko.fieldcraft.desktop, packaging/macos/entitlements.plist | FieldCraft contributors | Original packaging text: the disk image's install note, the Linux desktop entry and the (empty) hardened-runtime entitlements | MIT OR Apache-2.0 |
|
||||
| crates/ui-egui/fonts/Inter-SemiBold.ttf | The Inter Project Authors | https://github.com/rsms/inter release v4.1 (Inter-4.1.zip, extras/ttf/Inter-SemiBold.ttf), unmodified; licence text in crates/ui-egui/fonts/OFL.txt; the interface's caps labels (theme::LABEL_FAMILY) | SIL OFL 1.1 |
|
||||
|
||||
## Adapted code
|
||||
@@ -171,6 +172,9 @@ is committed and listed here with its exports.
|
||||
| apps/fieldcraft/src/control_server.rs | SolidCraft `apps/solidcraft/src/control_server.rs` | MIT OR Apache-2.0 |
|
||||
| crates/mcp/src/ (JSON-RPC framing, MCP lifecycle, tool schema checks, the control-channel backend, base64) | SolidCraft `crates/mcp/src/` | MIT OR Apache-2.0 |
|
||||
| crates/io/src/roots.rs (the rules of read and write roots) | VectorCraft's automation roots (docs/mcp.md there) | MIT OR Apache-2.0 |
|
||||
| packaging/env.sh, packaging/macos/package.sh, packaging/macos/Info.plist.in, packaging/linux/package.sh, packaging/linux/AppRun, packaging/windows/package.ps1 | SolidCraft `packaging/` and VectorCraft `packaging/` (signing and notarization in macos/package.sh) | MIT OR Apache-2.0 |
|
||||
| packaging/macos/import-cert.sh | VectorCraft `packaging/macos/import-cert.sh` | MIT OR Apache-2.0 |
|
||||
| packaging/windows/check-exe.ps1 | SolidCraft `packaging/windows/check-icon.ps1` | MIT OR Apache-2.0 |
|
||||
|
||||
## Test oracles
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
# shellcheck shell=bash
|
||||
# Shared setup for the packaging scripts. Source it: `. "$(dirname "$0")/../env.sh"`.
|
||||
# Adapted from SolidCraft's and VectorCraft's packaging (MIT OR Apache-2.0; see ATTRIBUTION.md).
|
||||
#
|
||||
# Exports:
|
||||
# ROOT workspace root
|
||||
# VERSION [workspace.package] version from Cargo.toml (override: FIELDCRAFT_VERSION)
|
||||
# DIST output directory for release artifacts (default: $ROOT/dist/release)
|
||||
# FIELDCRAFT_BUILD_SHA the commit being packaged (recorded in the macOS Info.plist)
|
||||
# CARGO_TARGET_DIR cargo's target dir (default: $ROOT/target)
|
||||
# APP_ID the reverse-DNS id: macOS bundle id, Linux .desktop and icon name, and
|
||||
# the window's Wayland app_id / X11 class (apps/fieldcraft/src/main.rs)
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
export ROOT
|
||||
|
||||
# The version lives in one place: `[workspace.package] version` in the root Cargo.toml.
|
||||
workspace_version() {
|
||||
awk '
|
||||
/^\[/ { in_pkg = ($0 == "[workspace.package]") ; next }
|
||||
in_pkg && $1 == "version" { gsub(/[" ]/, "", $3); print $3; exit }
|
||||
' "$ROOT/Cargo.toml"
|
||||
}
|
||||
|
||||
VERSION="${FIELDCRAFT_VERSION:-$(workspace_version)}"
|
||||
if [ -z "$VERSION" ]; then
|
||||
echo "error: could not read [workspace.package] version from $ROOT/Cargo.toml" >&2
|
||||
exit 1
|
||||
fi
|
||||
export VERSION
|
||||
|
||||
DIST="${DIST:-$ROOT/dist/release}"
|
||||
mkdir -p "$DIST"
|
||||
DIST="$(cd "$DIST" && pwd)"
|
||||
export DIST
|
||||
|
||||
FIELDCRAFT_BUILD_SHA="${FIELDCRAFT_BUILD_SHA:-$(git -C "$ROOT" rev-parse HEAD 2>/dev/null || echo unknown)}"
|
||||
export FIELDCRAFT_BUILD_SHA
|
||||
export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$ROOT/target}"
|
||||
APP_ID=io.github.jyviko.fieldcraft
|
||||
export APP_ID
|
||||
|
||||
# Emit a GitHub Actions warning (plain stderr outside Actions).
|
||||
warn() {
|
||||
if [ -n "${GITHUB_ACTIONS:-}" ]; then echo "::warning::$*"; else echo "warning: $*" >&2; fi
|
||||
}
|
||||
|
||||
# The readme, licence, notice and third-party licence files every package carries
|
||||
# (packaging/windows/package.ps1 has the same list).
|
||||
DOC_FILES=(README.md LICENSE-MIT LICENSE-APACHE NOTICE THIRD-PARTY-LICENSES.txt)
|
||||
|
||||
# Copy DOC_FILES into a package directory.
|
||||
copy_docs() {
|
||||
local dest="$1" f
|
||||
for f in "${DOC_FILES[@]}"; do
|
||||
cp "$ROOT/$f" "$dest/"
|
||||
done
|
||||
}
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
# FieldCraft AppImage entry point (packaging/linux/AppRun; installed by package.sh): run the app
|
||||
# from the AppImage's own tree.
|
||||
set -eu
|
||||
APPDIR="$(dirname "$(readlink -f "$0")")"
|
||||
exec "$APPDIR/usr/bin/fieldcraft" "$@"
|
||||
@@ -0,0 +1,13 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=FieldCraft
|
||||
GenericName=Finite Element Modeler
|
||||
Comment=Turn geometry into finite element models: mesh, set up, solve and export decks
|
||||
Exec=fieldcraft %F
|
||||
TryExec=fieldcraft
|
||||
Icon=io.github.jyviko.fieldcraft
|
||||
Terminal=false
|
||||
StartupNotify=true
|
||||
StartupWMClass=io.github.jyviko.fieldcraft
|
||||
Categories=Science;Engineering;
|
||||
Keywords=cae;fea;fem;finite element;mesh;hex;tet;solver;abaqus;nastran;ls-dyna;
|
||||
Executable
+121
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build and package FieldCraft for Linux x86_64:
|
||||
#
|
||||
# $DIST/fieldcraft-<version>-linux-x86_64.tar.gz bin/fieldcraft, bin/fieldcraft-cli, the
|
||||
# .desktop entry, icons and licences
|
||||
# $DIST/fieldcraft-<version>-linux-x86_64.AppImage the app as one file (chmod +x, run)
|
||||
#
|
||||
# Usage: packaging/linux/package.sh [--skip-build] [--formats "tar appimage"]
|
||||
#
|
||||
# Build on an old distribution (CI: Ubuntu 22.04, glibc 2.35) so the binaries run on newer ones.
|
||||
# The AppImage uses appimagetool and the type 2 runtime at pinned releases, checked against their
|
||||
# SHA-256 (downloaded into $CARGO_TARGET_DIR). Optional: desktop-file-validate.
|
||||
# Adapted from SolidCraft's packaging/linux/package.sh (MIT OR Apache-2.0; see ATTRIBUTION.md).
|
||||
set -euo pipefail
|
||||
# shellcheck source=../env.sh
|
||||
. "$(dirname "${BASH_SOURCE[0]}")/../env.sh"
|
||||
HERE="$ROOT/packaging/linux"
|
||||
ICONSET="$ROOT/assets/app-icon/icon.iconset"
|
||||
|
||||
SKIP_BUILD=0
|
||||
FORMATS="tar appimage"
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--skip-build) SKIP_BUILD=1; shift ;;
|
||||
--formats) FORMATS="$2"; shift 2 ;;
|
||||
-h | --help) sed -n '2,13p' "$0"; exit 0 ;;
|
||||
*) echo "unknown argument: $1" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
has() { case " $FORMATS " in *" $1 "*) return 0 ;; *) return 1 ;; esac; }
|
||||
|
||||
ARCH="$(uname -m)"
|
||||
# The AppImage tools, pinned (github.com/AppImage/appimagetool, github.com/AppImage/type2-runtime;
|
||||
# MIT). A version bump changes the SHA-256 below too.
|
||||
APPIMAGETOOL_VERSION=1.9.1
|
||||
RUNTIME_VERSION=20251108
|
||||
case "$ARCH" in
|
||||
x86_64)
|
||||
APPIMAGETOOL_SHA256=ed4ce84f0d9caff66f50bcca6ff6f35aae54ce8135408b3fa33abfc3cb384eb0
|
||||
RUNTIME_SHA256=2fca8b443c92510f1483a883f60061ad09b46b978b2631c807cd873a47ec260d
|
||||
;;
|
||||
*) echo "unsupported architecture $ARCH (release builds are x86_64)" >&2; exit 2 ;;
|
||||
esac
|
||||
APPIMAGETOOL_URL="https://github.com/AppImage/appimagetool/releases/download/$APPIMAGETOOL_VERSION/appimagetool-$ARCH.AppImage"
|
||||
RUNTIME_URL="https://github.com/AppImage/type2-runtime/releases/download/$RUNTIME_VERSION/runtime-$ARCH"
|
||||
BASENAME="fieldcraft-$VERSION-linux-$ARCH"
|
||||
|
||||
echo "==> FieldCraft $VERSION for Linux $ARCH ($FORMATS)"
|
||||
if [ "$SKIP_BUILD" = 0 ]; then
|
||||
(cd "$ROOT" && cargo build --release --locked -p fieldcraft -p fieldcraft-cli)
|
||||
fi
|
||||
BIN="$CARGO_TARGET_DIR/release"
|
||||
WORK="$CARGO_TARGET_DIR/linux-package"
|
||||
STAGE="$WORK/root/usr"
|
||||
rm -rf "$WORK"
|
||||
|
||||
# ---- an FHS tree, shared by both formats --------------------------------------------------------
|
||||
install -Dm755 "$BIN/fieldcraft" "$STAGE/bin/fieldcraft"
|
||||
install -Dm755 "$BIN/fieldcraft-cli" "$STAGE/bin/fieldcraft-cli"
|
||||
strip "$STAGE/bin/fieldcraft" "$STAGE/bin/fieldcraft-cli"
|
||||
install -Dm644 "$HERE/$APP_ID.desktop" "$STAGE/share/applications/$APP_ID.desktop"
|
||||
# hicolor icons: <size> <the iconset export of that size>.
|
||||
while read -r size file; do
|
||||
install -Dm644 "$ICONSET/$file" "$STAGE/share/icons/hicolor/${size}x${size}/apps/$APP_ID.png"
|
||||
done <<'ICONS'
|
||||
16 icon_16x16.png
|
||||
32 icon_32x32.png
|
||||
64 [email protected]
|
||||
128 icon_128x128.png
|
||||
256 icon_256x256.png
|
||||
512 icon_512x512.png
|
||||
1024 [email protected]
|
||||
ICONS
|
||||
mkdir -p "$STAGE/share/doc/fieldcraft"
|
||||
copy_docs "$STAGE/share/doc/fieldcraft"
|
||||
if command -v desktop-file-validate >/dev/null; then
|
||||
desktop-file-validate "$STAGE/share/applications/$APP_ID.desktop"
|
||||
fi
|
||||
|
||||
# ---- .tar.gz ------------------------------------------------------------------------------------
|
||||
if has tar; then
|
||||
mkdir -p "$WORK/tar"
|
||||
cp -R "$STAGE" "$WORK/tar/$BASENAME"
|
||||
tar -C "$WORK/tar" -czf "$DIST/$BASENAME.tar.gz" "$BASENAME"
|
||||
echo "wrote $DIST/$BASENAME.tar.gz"
|
||||
fi
|
||||
|
||||
# ---- AppImage -----------------------------------------------------------------------------------
|
||||
# Usage: fetch <url> <sha256> <file>; downloads once and checks the hash every time.
|
||||
fetch() {
|
||||
if [ ! -s "$3" ]; then curl -fsSL -o "$3.part" "$1" && mv "$3.part" "$3"; fi
|
||||
if ! echo "$2 $3" | sha256sum --check --status; then
|
||||
echo "error: $3 does not match its pinned SHA-256 ($1)" >&2
|
||||
rm -f "$3"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
if has appimage; then
|
||||
TOOL="$CARGO_TARGET_DIR/appimagetool-$APPIMAGETOOL_VERSION-$ARCH.AppImage"
|
||||
RUNTIME="$CARGO_TARGET_DIR/appimage-runtime-$RUNTIME_VERSION-$ARCH"
|
||||
fetch "$APPIMAGETOOL_URL" "$APPIMAGETOOL_SHA256" "$TOOL"
|
||||
fetch "$RUNTIME_URL" "$RUNTIME_SHA256" "$RUNTIME"
|
||||
chmod +x "$TOOL"
|
||||
|
||||
APPDIR="$WORK/FieldCraft.AppDir"
|
||||
mkdir -p "$APPDIR"
|
||||
cp -R "$STAGE" "$APPDIR/usr"
|
||||
install -Dm755 "$HERE/AppRun" "$APPDIR/AppRun"
|
||||
cp "$HERE/$APP_ID.desktop" "$APPDIR/$APP_ID.desktop"
|
||||
cp "$ICONSET/icon_256x256.png" "$APPDIR/$APP_ID.png"
|
||||
ln -s "$APP_ID.png" "$APPDIR/.DirIcon"
|
||||
OUT="$DIST/$BASENAME.AppImage"
|
||||
rm -f "$OUT"
|
||||
# Extract-and-run: appimagetool is itself an AppImage, and CI runners have no FUSE.
|
||||
ARCH="$ARCH" APPIMAGE_EXTRACT_AND_RUN=1 "$TOOL" --no-appstream --runtime-file "$RUNTIME" "$APPDIR" "$OUT"
|
||||
echo "wrote $OUT"
|
||||
fi
|
||||
|
||||
"$STAGE/bin/fieldcraft-cli" --version
|
||||
echo "==> done"
|
||||
ls -lh "$DIST"
|
||||
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<!-- Template: packaging/macos/package.sh substitutes @APP_ID@, @VERSION@ (full, e.g. 0.2.0-rc.1),
|
||||
@SHORT_VERSION@ (numeric X.Y.Z), @BUILD_SHA@ and @MIN_MACOS@
|
||||
(MACOSX_DEPLOYMENT_TARGET). Adapted from SolidCraft's and VectorCraft's
|
||||
(MIT OR Apache-2.0; see ATTRIBUTION.md). -->
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>FieldCraft</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>FieldCraft</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>FieldCraft</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>@APP_ID@</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>@SHORT_VERSION@</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>@SHORT_VERSION@</string>
|
||||
<key>FieldCraftVersion</key>
|
||||
<string>@VERSION@</string>
|
||||
<key>FieldCraftBuildCommit</key>
|
||||
<string>@BUILD_SHA@</string>
|
||||
<!-- Contents/Resources/FieldCraft.icns (assets/app-icon/icon.icns) for macOS before 26, and the
|
||||
FieldCraft icon in Contents/Resources/Assets.car (assets/app-icon/Assets.car) from 26 on. -->
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>FieldCraft</string>
|
||||
<key>CFBundleIconName</key>
|
||||
<string>FieldCraft</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.graphics-design</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>@MIN_MACOS@</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © FieldCraft contributors. MIT OR Apache-2.0.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,13 @@
|
||||
Install FieldCraft
|
||||
|
||||
Drag FieldCraft.app onto Applications.
|
||||
|
||||
If this build is not notarized (the release notes say so), macOS blocks the first launch:
|
||||
right-click FieldCraft.app in Applications and choose Open, then Open again. Or run
|
||||
|
||||
xattr -dr com.apple.quarantine /Applications/FieldCraft.app
|
||||
|
||||
Updating: quit FieldCraft, drag FieldCraft.app from this disk image onto Applications and
|
||||
choose Replace.
|
||||
|
||||
The command-line tool, fieldcraft-cli, is a separate download (fieldcraft-cli-*-macos-*.zip).
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<!-- Hardened-runtime entitlements for FieldCraft. Deliberately empty: the app is pure Rust, loads
|
||||
no unsigned code, needs no JIT and is not sandboxed (it opens files by path, from the command
|
||||
line and drag-and-drop). Add an exception here only with a reason in a comment. -->
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
</dict>
|
||||
</plist>
|
||||
Executable
+52
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env bash
|
||||
# CI only: import the Developer ID certificate into a temporary keychain so codesign can use it.
|
||||
#
|
||||
# Adapted from VectorCraft's packaging/macos/import-cert.sh (MIT OR Apache-2.0; see ATTRIBUTION.md).
|
||||
#
|
||||
# Inputs (env): APPLE_CERTIFICATE (base64 .p12), APPLE_CERTIFICATE_PASSWORD, KEYCHAIN_PASSWORD
|
||||
# (optional; random if unset), RUNNER_TEMP (or TMPDIR).
|
||||
# Outputs: MACOS_SIGN_IDENTITY (SHA-1 of the identity) and MACOS_KEYCHAIN, appended to
|
||||
# $GITHUB_ENV when running in Actions, otherwise printed.
|
||||
#
|
||||
# Missing certificate: prints a warning and exits 0, so package.sh falls back to ad-hoc signing.
|
||||
set -euo pipefail
|
||||
umask 077
|
||||
# shellcheck source=../env.sh
|
||||
. "$(dirname "${BASH_SOURCE[0]}")/../env.sh"
|
||||
|
||||
if [ -z "${APPLE_CERTIFICATE:-}" ]; then
|
||||
warn "APPLE_CERTIFICATE is not set: macOS builds will be ad-hoc signed and not notarized"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
TMP="${RUNNER_TEMP:-${TMPDIR:-/tmp}}"
|
||||
KEYCHAIN="$TMP/fieldcraft-signing.keychain-db"
|
||||
CERT="$TMP/fieldcraft-signing.p12"
|
||||
KC_PASS="${KEYCHAIN_PASSWORD:-$(openssl rand -hex 24)}"
|
||||
|
||||
trap 'rm -f "$CERT"' EXIT
|
||||
printf '%s' "$APPLE_CERTIFICATE" | base64 --decode >"$CERT"
|
||||
security create-keychain -p "$KC_PASS" "$KEYCHAIN"
|
||||
security set-keychain-settings -lut 21600 "$KEYCHAIN"
|
||||
security unlock-keychain -p "$KC_PASS" "$KEYCHAIN"
|
||||
security import "$CERT" -P "${APPLE_CERTIFICATE_PASSWORD:-}" -T /usr/bin/codesign -T /usr/bin/security -t cert -f pkcs12 -k "$KEYCHAIN"
|
||||
rm -f "$CERT"
|
||||
# Let codesign use the key without a UI prompt.
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KC_PASS" "$KEYCHAIN" >/dev/null
|
||||
# Put it on the search list (keeping the login keychain) so codesign and notarytool find it.
|
||||
# shellcheck disable=SC2046
|
||||
security list-keychains -d user -s "$KEYCHAIN" $(security list-keychains -d user | tr -d '"')
|
||||
|
||||
IDENTITY="$(security find-identity -v -p codesigning "$KEYCHAIN" | awk '/Developer ID Application/ { print $2; exit }')"
|
||||
if [ -z "$IDENTITY" ]; then
|
||||
security find-identity -v -p codesigning "$KEYCHAIN" >&2
|
||||
echo "error: no 'Developer ID Application' identity in APPLE_CERTIFICATE" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Imported signing identity $IDENTITY"
|
||||
if [ -n "${GITHUB_ENV:-}" ]; then
|
||||
{ echo "MACOS_SIGN_IDENTITY=$IDENTITY"; echo "MACOS_KEYCHAIN=$KEYCHAIN"; } >>"$GITHUB_ENV"
|
||||
else
|
||||
echo "MACOS_SIGN_IDENTITY=$IDENTITY"
|
||||
echo "MACOS_KEYCHAIN=$KEYCHAIN"
|
||||
fi
|
||||
Executable
+216
@@ -0,0 +1,216 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build, sign and (with credentials) notarize FieldCraft for macOS:
|
||||
#
|
||||
# $DIST/fieldcraft-<version>-macos-<arch>.dmg FieldCraft.app on a drag-to-Applications DMG
|
||||
# $DIST/fieldcraft-cli-<version>-macos-<arch>.zip fieldcraft-cli with the licence files
|
||||
#
|
||||
# Usage: packaging/macos/package.sh [--arch universal|aarch64|x86_64] [--skip-build]
|
||||
#
|
||||
# Signing (env):
|
||||
# MACOS_SIGN_IDENTITY codesign identity (name or SHA-1). Default "-": ad-hoc, which Gatekeeper
|
||||
# blocks on other Macs until the user allows it. In CI, import-cert.sh sets
|
||||
# it from the APPLE_CERTIFICATE secret.
|
||||
# MACOS_KEYCHAIN keychain holding the identity (optional)
|
||||
# Notarization (env; all three, and a real identity): APPLE_ID, APPLE_PASSWORD (an app-specific
|
||||
# password), APPLE_TEAM_ID.
|
||||
#
|
||||
# Writes `signing=notarized|signed|adhoc` to $GITHUB_OUTPUT when run in GitHub Actions.
|
||||
# Adapted from SolidCraft's and VectorCraft's packaging/macos/package.sh (MIT OR Apache-2.0; see
|
||||
# ATTRIBUTION.md).
|
||||
set -euo pipefail
|
||||
# shellcheck source=../env.sh
|
||||
. "$(dirname "${BASH_SOURCE[0]}")/../env.sh"
|
||||
HERE="$ROOT/packaging/macos"
|
||||
ICONS="$ROOT/assets/app-icon"
|
||||
|
||||
ARCH=universal
|
||||
SKIP_BUILD=0
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--arch) ARCH="$2"; shift 2 ;;
|
||||
--skip-build) SKIP_BUILD=1; shift ;;
|
||||
-h | --help) sed -n '2,17p' "$0"; exit 0 ;;
|
||||
*) echo "unknown argument: $1" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
case "$ARCH" in
|
||||
universal) TARGETS=(aarch64-apple-darwin x86_64-apple-darwin); WANT=(arm64 x86_64) ;;
|
||||
aarch64) TARGETS=(aarch64-apple-darwin); WANT=(arm64) ;;
|
||||
x86_64) TARGETS=(x86_64-apple-darwin); WANT=(x86_64) ;;
|
||||
*) echo "unknown --arch $ARCH" >&2; exit 2 ;;
|
||||
esac
|
||||
|
||||
# The oldest macOS the binaries run on; also the Info.plist's LSMinimumSystemVersion.
|
||||
export MACOSX_DEPLOYMENT_TARGET=11.0
|
||||
IDENTITY="${MACOS_SIGN_IDENTITY:--}"
|
||||
SHORT_VERSION="${VERSION%%-*}"
|
||||
WORK="$CARGO_TARGET_DIR/macos-package"
|
||||
APP="$WORK/FieldCraft.app"
|
||||
DMG="$DIST/fieldcraft-$VERSION-macos-$ARCH.dmg"
|
||||
CLI_ZIP="$DIST/fieldcraft-cli-$VERSION-macos-$ARCH.zip"
|
||||
|
||||
NOTARIZE=0
|
||||
SIGNING=adhoc
|
||||
if [ "$IDENTITY" = "-" ]; then
|
||||
warn "macOS: ad-hoc signing (no MACOS_SIGN_IDENTITY); the app is not notarized"
|
||||
elif [ -n "${APPLE_ID:-}" ] && [ -n "${APPLE_PASSWORD:-}" ] && [ -n "${APPLE_TEAM_ID:-}" ]; then
|
||||
NOTARIZE=1
|
||||
SIGNING=notarized
|
||||
else
|
||||
SIGNING=signed
|
||||
warn "macOS: APPLE_ID / APPLE_PASSWORD / APPLE_TEAM_ID incomplete; signed but not notarized"
|
||||
fi
|
||||
|
||||
echo "==> FieldCraft $VERSION for macOS ($ARCH), identity: $IDENTITY, notarize: $NOTARIZE"
|
||||
|
||||
# ---- build -------------------------------------------------------------------------------------
|
||||
if [ "$SKIP_BUILD" = 0 ]; then
|
||||
args=()
|
||||
for t in "${TARGETS[@]}"; do args+=(--target "$t"); done
|
||||
(cd "$ROOT" && cargo build --release --locked -p fieldcraft -p fieldcraft-cli "${args[@]}")
|
||||
fi
|
||||
|
||||
rm -rf "$WORK"
|
||||
mkdir -p "$WORK/bin"
|
||||
for bin in fieldcraft fieldcraft-cli; do
|
||||
inputs=()
|
||||
for t in "${TARGETS[@]}"; do inputs+=("$CARGO_TARGET_DIR/$t/release/$bin"); done
|
||||
lipo -create -output "$WORK/bin/$bin" "${inputs[@]}"
|
||||
lipo -info "$WORK/bin/$bin"
|
||||
done
|
||||
|
||||
# ---- signing helpers ---------------------------------------------------------------------------
|
||||
sign() {
|
||||
# Hardened runtime and a secure timestamp for a real identity; ad-hoc can't be timestamped.
|
||||
local ts=(--timestamp)
|
||||
[ "$IDENTITY" = "-" ] && ts=(--timestamp=none)
|
||||
local kc=()
|
||||
[ -n "${MACOS_KEYCHAIN:-}" ] && kc=(--keychain "$MACOS_KEYCHAIN")
|
||||
codesign --force --sign "$IDENTITY" ${kc[@]+"${kc[@]}"} "${ts[@]}" "$@"
|
||||
}
|
||||
|
||||
notarize() {
|
||||
local file="$1" out id status
|
||||
echo "==> notarizing $(basename "$file") (this can take a few minutes)"
|
||||
out="$(xcrun notarytool submit "$file" --apple-id "$APPLE_ID" --password "$APPLE_PASSWORD" \
|
||||
--team-id "$APPLE_TEAM_ID" --wait --timeout 1h --output-format json)" || true
|
||||
echo "$out"
|
||||
id="$(printf '%s' "$out" | plutil -extract id raw -o - - 2>/dev/null || true)"
|
||||
status="$(printf '%s' "$out" | plutil -extract status raw -o - - 2>/dev/null || true)"
|
||||
if [ "$status" != "Accepted" ]; then
|
||||
if [ -n "$id" ]; then
|
||||
xcrun notarytool log "$id" --apple-id "$APPLE_ID" --password "$APPLE_PASSWORD" --team-id "$APPLE_TEAM_ID" || true
|
||||
fi
|
||||
echo "error: notarization of $(basename "$file") failed (status: ${status:-unknown})" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# hdiutil attaches a device while it works, which fails now and then on CI runners ("Resource
|
||||
# busy"). Usage: hdiutil_retry <hdiutil args…>; five tries with growing pauses.
|
||||
hdiutil_retry() {
|
||||
local what="$1" attempt
|
||||
for attempt in 1 2 3 4 5; do
|
||||
if hdiutil "$@"; then return 0; fi
|
||||
[ "$attempt" = 5 ] && { echo "hdiutil $what failed 5 times" >&2; return 1; }
|
||||
echo "hdiutil $what failed (attempt $attempt of 5); retrying in $((attempt * 10))s" >&2
|
||||
sleep $((attempt * 10))
|
||||
done
|
||||
}
|
||||
|
||||
# ---- FieldCraft.app ----------------------------------------------------------------------------
|
||||
echo "==> assembling $APP"
|
||||
mkdir -p "$APP/Contents/MacOS" "$APP/Contents/Resources/Licenses"
|
||||
# The executable and the icons carry the display name (CFBundleExecutable, CFBundleIconFile,
|
||||
# CFBundleIconName). Assets.car holds the layered icon for macOS 26 and later, the .icns the
|
||||
# icon for earlier versions (assets/app-icon/README.md).
|
||||
cp "$WORK/bin/fieldcraft" "$APP/Contents/MacOS/FieldCraft"
|
||||
cp "$ICONS/icon.icns" "$APP/Contents/Resources/FieldCraft.icns"
|
||||
cp "$ICONS/Assets.car" "$APP/Contents/Resources/Assets.car"
|
||||
copy_docs "$APP/Contents/Resources/Licenses"
|
||||
sed -e "s/@APP_ID@/$APP_ID/g" -e "s/@VERSION@/$VERSION/g" -e "s/@SHORT_VERSION@/$SHORT_VERSION/g" \
|
||||
-e "s/@BUILD_SHA@/$FIELDCRAFT_BUILD_SHA/g" -e "s/@MIN_MACOS@/$MACOSX_DEPLOYMENT_TARGET/g" "$HERE/Info.plist.in" >"$APP/Contents/Info.plist"
|
||||
plutil -lint "$APP/Contents/Info.plist"
|
||||
printf 'APPL????' >"$APP/Contents/PkgInfo"
|
||||
|
||||
# Sign inside-out: the executable, then the bundle (no --deep on the bundle's own signature).
|
||||
sign --options runtime --entitlements "$HERE/entitlements.plist" "$APP/Contents/MacOS/FieldCraft"
|
||||
sign --options runtime --entitlements "$HERE/entitlements.plist" "$APP"
|
||||
codesign --verify --strict --deep --verbose=2 "$APP"
|
||||
codesign -dv "$APP"
|
||||
|
||||
if [ "$NOTARIZE" = 1 ]; then
|
||||
ditto -c -k --keepParent "$APP" "$WORK/FieldCraft-notarize.zip"
|
||||
notarize "$WORK/FieldCraft-notarize.zip"
|
||||
xcrun stapler staple "$APP"
|
||||
xcrun stapler validate "$APP"
|
||||
spctl --assess --type execute -vvv "$APP"
|
||||
fi
|
||||
|
||||
# ---- DMG ---------------------------------------------------------------------------------------
|
||||
echo "==> building $DMG"
|
||||
STAGE="$WORK/dmg"
|
||||
mkdir -p "$STAGE"
|
||||
ditto "$APP" "$STAGE/FieldCraft.app"
|
||||
ln -s /Applications "$STAGE/Applications"
|
||||
cp "$HERE/README.txt" "$STAGE/README.txt"
|
||||
rm -f "$DMG"
|
||||
# `create -srcfolder` writes the files as they are; `makehybrid -hfs` gives every file a
|
||||
# com.apple.FinderInfo, which `codesign --verify --strict` rejects (VectorCraft found this).
|
||||
hdiutil_retry create -srcfolder "$STAGE" -volname "FieldCraft" -fs HFS+ -format UDZO \
|
||||
-imagekey zlib-level=9 -ov "$DMG"
|
||||
sign "$DMG"
|
||||
codesign --verify --strict --verbose=2 "$DMG"
|
||||
|
||||
# Check the image as a user gets it: mount it and look inside.
|
||||
MNT="$WORK/dmg-check"
|
||||
rm -rf "$MNT"
|
||||
mkdir -p "$MNT"
|
||||
hdiutil_retry attach -nobrowse -readonly -mountpoint "$MNT" "$DMG" >/dev/null
|
||||
# Detach on the way out, also when a check below fails and ends the script.
|
||||
trap 'hdiutil detach "$MNT" >/dev/null 2>&1 || true' EXIT
|
||||
M_APP="$MNT/FieldCraft.app"
|
||||
M_PLIST="$M_APP/Contents/Info.plist"
|
||||
test -L "$MNT/Applications"
|
||||
test "$(readlink "$MNT/Applications")" = /Applications
|
||||
cmp "$HERE/README.txt" "$MNT/README.txt"
|
||||
plutil -lint "$M_PLIST"
|
||||
for key in CFBundleName CFBundleDisplayName CFBundleExecutable CFBundleIconFile CFBundleIconName; do
|
||||
test "$(/usr/libexec/PlistBuddy -c "Print :$key" "$M_PLIST")" = FieldCraft
|
||||
done
|
||||
test "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleIdentifier' "$M_PLIST")" = "$APP_ID"
|
||||
test "$(/usr/libexec/PlistBuddy -c 'Print :FieldCraftVersion' "$M_PLIST")" = "$VERSION"
|
||||
cmp "$ICONS/icon.icns" "$M_APP/Contents/Resources/FieldCraft.icns"
|
||||
cmp "$ICONS/Assets.car" "$M_APP/Contents/Resources/Assets.car"
|
||||
for f in "${DOC_FILES[@]}"; do
|
||||
test -s "$M_APP/Contents/Resources/Licenses/$f"
|
||||
done
|
||||
for arch in "${WANT[@]}"; do lipo "$M_APP/Contents/MacOS/FieldCraft" -verify_arch "$arch"; done
|
||||
codesign --verify --strict --deep --verbose=2 "$M_APP"
|
||||
"$M_APP/Contents/MacOS/FieldCraft" --version
|
||||
hdiutil_retry detach "$MNT" >/dev/null
|
||||
trap - EXIT
|
||||
if [ "$NOTARIZE" = 1 ]; then
|
||||
notarize "$DMG"
|
||||
xcrun stapler staple "$DMG"
|
||||
xcrun stapler validate "$DMG"
|
||||
spctl --assess --type open --context context:primary-signature -vvv "$DMG"
|
||||
fi
|
||||
|
||||
# ---- CLI ---------------------------------------------------------------------------------------
|
||||
echo "==> building $CLI_ZIP"
|
||||
CLI_DIR="$WORK/fieldcraft-cli-$VERSION-macos-$ARCH"
|
||||
mkdir -p "$CLI_DIR"
|
||||
cp "$WORK/bin/fieldcraft-cli" "$CLI_DIR/"
|
||||
copy_docs "$CLI_DIR"
|
||||
sign --options runtime --identifier "$APP_ID.cli" "$CLI_DIR/fieldcraft-cli"
|
||||
codesign --verify --strict --verbose=2 "$CLI_DIR/fieldcraft-cli"
|
||||
rm -f "$CLI_ZIP"
|
||||
ditto -c -k --keepParent "$CLI_DIR" "$CLI_ZIP"
|
||||
# A bare Mach-O can't carry a stapled ticket; Gatekeeper looks the notarization up online.
|
||||
if [ "$NOTARIZE" = 1 ]; then notarize "$CLI_ZIP"; fi
|
||||
|
||||
"$CLI_DIR/fieldcraft-cli" --version
|
||||
if [ -n "${GITHUB_OUTPUT:-}" ]; then echo "signing=$SIGNING" >>"$GITHUB_OUTPUT"; fi
|
||||
echo "==> done (signing: $SIGNING)"
|
||||
ls -lh "$DMG" "$CLI_ZIP"
|
||||
@@ -0,0 +1,76 @@
|
||||
# Check an x64 executable: its PE machine, its subsystem (2 = GUI, so the app opens no console
|
||||
# window; 3 = console, so the CLI's output reaches the terminal) and, with -Icon, a well-formed
|
||||
# embedded application icon (RT_GROUP_ICON referring to RT_ICON images).
|
||||
# Adapted from SolidCraft's packaging/windows/check-icon.ps1 (MIT OR Apache-2.0; see ATTRIBUTION.md).
|
||||
param([Parameter(Mandatory)][string] $Path, [Parameter(Mandatory)][int] $Subsystem, [switch] $Icon)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$bytes = [IO.File]::ReadAllBytes((Resolve-Path -LiteralPath $Path))
|
||||
function U16([int] $At) { if ($At -lt 0 -or $At + 2 -gt $bytes.Length) { throw 'truncated PE' }; [BitConverter]::ToUInt16($bytes, $At) }
|
||||
function U32([int] $At) { if ($At -lt 0 -or $At + 4 -gt $bytes.Length) { throw 'truncated PE' }; [BitConverter]::ToUInt32($bytes, $At) }
|
||||
if ((U16 0) -ne 0x5A4D) { throw 'not an executable' }
|
||||
$pe = U32 0x3C
|
||||
if ((U32 $pe) -ne 0x4550) { throw 'missing PE signature' }
|
||||
$optional = $pe + 24
|
||||
$magic = U16 $optional
|
||||
if ((U16 ($pe + 4)) -ne 0x8664) { throw "$Path is for machine 0x$('{0:X}' -f (U16 ($pe + 4))), expected 0x8664 (x64)" }
|
||||
if ((U16 ($optional + 68)) -ne $Subsystem) { throw "$Path has PE subsystem $(U16 ($optional + 68)), expected $Subsystem" }
|
||||
Write-Output "ok x64, PE subsystem ${Subsystem}: $Path"
|
||||
if (-not $Icon) { return }
|
||||
$directories = switch ($magic) { 0x10B { $optional + 96 }; 0x20B { $optional + 112 }; default { throw 'unknown PE format' } }
|
||||
$resourceRva = U32 ($directories + 16)
|
||||
$resourceSize = U32 ($directories + 20)
|
||||
if (!$resourceRva -or !$resourceSize) { throw 'executable has no resources' }
|
||||
$sections = $optional + (U16 ($pe + 20))
|
||||
function RvaOffset([uint32] $Rva) {
|
||||
for ($i = 0; $i -lt (U16 ($pe + 6)); $i++) {
|
||||
$section = $sections + 40 * $i
|
||||
$start = U32 ($section + 12)
|
||||
$rawSize = U32 ($section + 16)
|
||||
if ($Rva -ge $start -and [uint64]$Rva -lt [uint64]$start + $rawSize) { return (U32 ($section + 20)) + ($Rva - $start) }
|
||||
}
|
||||
throw 'resource RVA outside file sections'
|
||||
}
|
||||
$base = RvaOffset $resourceRva
|
||||
function Entries([uint32] $Relative) {
|
||||
if ([uint64]$Relative + 16 -gt $resourceSize) { throw 'resource directory outside bounds' }
|
||||
$at = $base + $Relative
|
||||
$count = (U16 ($at + 12)) + (U16 ($at + 14))
|
||||
if ([uint64]$Relative + 16 + 8 * $count -gt $resourceSize) { throw 'resource entries outside bounds' }
|
||||
for ($i = 0; $i -lt $count; $i++) {
|
||||
$entry = $at + 16 + 8 * $i
|
||||
@{ Name = (U32 $entry); Offset = (U32 ($entry + 4)) }
|
||||
}
|
||||
}
|
||||
function Payloads($Entry) {
|
||||
if (!( $Entry.Offset -band 0x80000000L )) { throw 'expected resource directory' }
|
||||
foreach ($name in @(Entries ($Entry.Offset -band 0x7FFFFFFFL))) {
|
||||
if (!( $name.Offset -band 0x80000000L )) { throw 'expected resource language directory' }
|
||||
foreach ($language in @(Entries ($name.Offset -band 0x7FFFFFFFL))) {
|
||||
if ($language.Offset -band 0x80000000L) { throw 'unexpected nested resource directory' }
|
||||
if ([uint64]$language.Offset + 16 -gt $resourceSize) { throw 'resource data outside bounds' }
|
||||
$data = $base + $language.Offset
|
||||
$offset = RvaOffset (U32 $data)
|
||||
$length = U32 ($data + 4)
|
||||
if (!$length -or [uint64]$offset + $length -gt $bytes.Length) { throw 'empty or truncated icon resource' }
|
||||
@{ Id = $name.Name; At = $offset; Length = $length }
|
||||
}
|
||||
}
|
||||
}
|
||||
$root = @(Entries 0)
|
||||
$iconType = @($root | Where-Object Name -eq 3)
|
||||
$groupType = @($root | Where-Object Name -eq 14)
|
||||
if ($iconType.Count -ne 1 -or $groupType.Count -ne 1) { throw 'missing RT_ICON or RT_GROUP_ICON' }
|
||||
$icons = @(Payloads $iconType[0])
|
||||
$groups = @(Payloads $groupType[0])
|
||||
foreach ($group in $groups) {
|
||||
if ((U16 $group.At) -ne 0 -or (U16 ($group.At + 2)) -ne 1) { throw 'invalid icon group' }
|
||||
$count = U16 ($group.At + 4)
|
||||
if (!$count -or 6 + 14 * $count -gt $group.Length) { throw 'empty or truncated icon group' }
|
||||
for ($i = 0; $i -lt $count; $i++) {
|
||||
$entry = $group.At + 6 + 14 * $i
|
||||
$id = U16 ($entry + 12)
|
||||
$length = U32 ($entry + 8)
|
||||
if (!@($icons | Where-Object { $_.Id -eq $id -and $_.Length -eq $length }).Count) { throw 'icon group refers to missing image' }
|
||||
}
|
||||
}
|
||||
Write-Output "ok embedded app icon: $($icons.Count) images, $($groups.Count) group(s): $Path"
|
||||
@@ -0,0 +1,71 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Build and package FieldCraft for Windows x64.
|
||||
|
||||
.DESCRIPTION
|
||||
Produces, in $env:DIST (default: dist/release):
|
||||
fieldcraft-<version>-windows-x64.zip fieldcraft.exe, fieldcraft-cli.exe, README.md and the
|
||||
licence files (LICENSE-MIT, LICENSE-APACHE, NOTICE,
|
||||
THIRD-PARTY-LICENSES.txt)
|
||||
|
||||
The binaries link the C runtime statically (+crt-static, .cargo/config.toml), so nothing else
|
||||
needs installing.
|
||||
fieldcraft.exe carries the application icon (assets/app-icon/icon.ico, embedded by
|
||||
apps/fieldcraft/build.rs). Nothing is signed.
|
||||
|
||||
Adapted from SolidCraft's packaging/windows/package.ps1 (MIT OR Apache-2.0; see ATTRIBUTION.md).
|
||||
|
||||
.EXAMPLE
|
||||
pwsh packaging/windows/package.ps1
|
||||
#>
|
||||
param([switch] $SkipBuild)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$Root = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path
|
||||
|
||||
function Invoke-Native([string] $What, [scriptblock] $Block) {
|
||||
Write-Output "==> $What"
|
||||
& $Block
|
||||
if ($LASTEXITCODE -ne 0) { throw "$What failed with exit code $LASTEXITCODE" }
|
||||
}
|
||||
|
||||
# The version: FIELDCRAFT_VERSION (CI sets it), else [workspace.package] version in Cargo.toml.
|
||||
$Version = $env:FIELDCRAFT_VERSION
|
||||
if (-not $Version) {
|
||||
$meta = cargo metadata --no-deps --format-version 1 --manifest-path (Join-Path $Root 'Cargo.toml') | ConvertFrom-Json
|
||||
$Version = ($meta.packages | Where-Object name -eq 'fieldcraft').version
|
||||
}
|
||||
if (-not $Version) { throw 'could not read [workspace.package] version from Cargo.toml' }
|
||||
|
||||
$Arch = 'x64'
|
||||
$Target = 'x86_64-pc-windows-msvc'
|
||||
$Dist = if ($env:DIST) { $env:DIST } else { Join-Path $Root 'dist\release' }
|
||||
$TargetDir = if ($env:CARGO_TARGET_DIR) { $env:CARGO_TARGET_DIR } else { Join-Path $Root 'target' }
|
||||
New-Item -ItemType Directory -Force -Path $Dist | Out-Null
|
||||
Write-Output "FieldCraft $Version for Windows $Arch ($Target)"
|
||||
|
||||
if (-not $SkipBuild) {
|
||||
Invoke-Native "cargo build ($Target)" { cargo build --release --locked -p fieldcraft -p fieldcraft-cli --target $Target }
|
||||
}
|
||||
$Bin = Join-Path $TargetDir "$Target\release"
|
||||
|
||||
$Check = Join-Path $PSScriptRoot 'check-exe.ps1'
|
||||
& $Check -Path (Join-Path $Bin 'fieldcraft.exe') -Subsystem 2 -Icon
|
||||
& $Check -Path (Join-Path $Bin 'fieldcraft-cli.exe') -Subsystem 3
|
||||
|
||||
# ---- zip ---------------------------------------------------------------------------------------
|
||||
$Name = "fieldcraft-$Version-windows-$Arch"
|
||||
$Stage = Join-Path $TargetDir "windows-package\$Name"
|
||||
Remove-Item -Recurse -Force $Stage -ErrorAction SilentlyContinue
|
||||
New-Item -ItemType Directory -Force -Path $Stage | Out-Null
|
||||
Copy-Item (Join-Path $Bin 'fieldcraft.exe'), (Join-Path $Bin 'fieldcraft-cli.exe') $Stage
|
||||
# The files copy_docs (packaging/env.sh) puts in every package.
|
||||
foreach ($f in 'README.md', 'LICENSE-MIT', 'LICENSE-APACHE', 'NOTICE', 'THIRD-PARTY-LICENSES.txt') { Copy-Item (Join-Path $Root $f) $Stage }
|
||||
$Zip = Join-Path $Dist "$Name.zip"
|
||||
Remove-Item -Force $Zip -ErrorAction SilentlyContinue
|
||||
# Windows' own bsdtar writes the zip (-a: the format from the name; Compress-Archive is slow). By
|
||||
# full path, as Git for Windows puts a GNU tar without zip support on the PATH.
|
||||
$Tar = Join-Path $env:SystemRoot 'System32\tar.exe'
|
||||
Invoke-Native 'zip' { & $Tar -a -cf $Zip -C (Split-Path $Stage) $Name }
|
||||
|
||||
Invoke-Native 'fieldcraft-cli --version' { & (Join-Path $Stage 'fieldcraft-cli.exe') --version }
|
||||
Get-Item $Zip | Format-Table Name, Length
|
||||
Reference in new issue
Block a user