#!/usr/bin/env bash # Push the app plus its artifacts to a Hugging Face Space. # # scripts/deploy_space.sh / [--ssh] # # --ssh pushes over git@hf.co using your SSH key. Without it the remote is # HTTPS and git prompts for a password -- that is a Hugging Face access token, # and it should be a fine-grained one scoped to write on this Space, not a # classic full-access token. # # Test the image locally the way the Space runs it: # # docker build -t mss-space . # docker run -p 7860:7860 mss-space # http://localhost:7860 # # data/ and models/ are gitignored, so they never reach the origin remote. The # commit is assembled in a temporary index and pushed straight from its SHA: # nothing is checked out, no branch is created, and the working tree is never # touched. set -euo pipefail SPACE="" USE_SSH=0 for arg in "$@"; do case "$arg" in --ssh) USE_SSH=1 ;; -*) echo "unknown option: $arg" >&2; exit 1 ;; *) SPACE="$arg" ;; esac done if [[ -z "$SPACE" || "$SPACE" != */* ]]; then echo "usage: $0 / [--ssh]" >&2 exit 1 fi if (( USE_SSH )); then REMOTE="git@hf.co:spaces/$SPACE" else REMOTE="https://huggingface.co/spaces/$SPACE" fi command -v git-lfs >/dev/null || { echo "git-lfs is required for the 220MB of previews." >&2 echo " brew install git-lfs && git lfs install" >&2 exit 1 } [[ -z "$(git status --porcelain)" ]] || { echo "working tree is dirty -- commit or stash first" >&2 exit 1 } for path in data/voices models/text_int8.onnx models/tokenizer.json; do [[ -e "$path" ]] || { echo "missing $path -- run \`mss fetch\` and \`mss export\` first" >&2 exit 1 } done # Reset rather than add: the URL changes when --ssh is toggled or the Space # is renamed, and a stale remote pushes to the wrong place. if git remote get-url space >/dev/null 2>&1; then git remote set-url space "$REMOTE" else git remote add space "$REMOTE" fi if (( USE_SSH )); then echo "checking SSH access to hf.co ..." ssh -o StrictHostKeyChecking=accept-new -T git@hf.co 2>&1 | head -1 fi # A scratch index, so `git add -f` cannot disturb the real one. Checking out a # branch that tracks these paths would delete them from the working tree on the # way back, which is why nothing here changes branches. INDEX="$(mktemp -t mss-deploy-index)" export GIT_INDEX_FILE="$INDEX" trap 'rm -f "$INDEX"' EXIT git read-tree HEAD git add -f data/voices models TREE="$(git write-tree)" # Parentless on purpose. The Space is a deployment target, not a mirror of this # repo's history, and pushing that history drags along every blob ever # committed -- which Hugging Face rejects for any binary not in LFS at the time # it was written. COMMIT="$(git commit-tree "$TREE" \ -m "Deploy: catalog, vectors, previews and ONNX export")" echo "pushing to $REMOTE ..." git push -f space "$COMMIT:main" echo "done -> https://huggingface.co/spaces/$SPACE"