#!/usr/bin/env bash # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. # # zsetup — prepare a project for local dev: create its Python venv and install # dependencies (python kind), or run `npm install` (vite/nextjs). Idempotent - # safe to re-run to refresh deps. `zstart` only warns when a venv is missing; # this is the command that creates it. # # Usage: # zsetup [ ...] # zsetup --force # recreate the python venv from scratch # # Python install command (first match wins): # 1. the project's "install" config field (e.g. "-e backend", "-r reqs.txt") # 2. auto: pyproject.toml / setup.py -> "-e ." | requirements.txt -> "-r requirements.txt" set -uo pipefail source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/zhelpers.sh" z_track_start "$@" z_need_config projects=(); force=0 while [ $# -gt 0 ]; do case "$1" in --force) force=1; shift ;; -*) err "Unknown option: $1"; exit 1 ;; *) projects+=("$1"); shift ;; esac done if [ "${#projects[@]}" -eq 0 ]; then printf '\n'; warn "Usage: zsetup [ ...] [--force]" dim " Projects in zconfig.json: $(zproj_csv)" dim " Creates the python venv + installs deps (or runs npm install for vite/nextjs)." exit 1 fi # pip install args for a python project (one per line): config .install, else # auto-detect a root pyproject.toml/setup.py or requirements.txt. Empty = unknown. py_install_args() { # local key="$1" root="$2" cfg cfg="$(zproj "$key" .install)" if [ -n "$cfg" ]; then printf '%s\n' $cfg; return 0; fi if [ -f "$root/pyproject.toml" ] || [ -f "$root/setup.py" ]; then printf '%s\n' -e .; return 0; fi if [ -f "$root/requirements.txt" ]; then printf '%s\n' -r requirements.txt; return 0; fi return 0 } setup_python() { # local key="$1" root="$2" venv="$2/.venv" args=() a z_require python3 while IFS= read -r a; do [ -n "$a" ] && args+=("$a"); done < <(py_install_args "$key" "$root") if [ "${#args[@]}" -eq 0 ]; then err " Can't determine dependencies for '$key' (no pyproject.toml/setup.py/requirements.txt at $root)." dim " Add an \"install\" field to the project, e.g. \"install\": \"-e backend\" or \"-r requirements.txt\"." return 1 fi if [ "$force" -eq 1 ] && [ -d "$venv" ]; then dim " Removing existing venv (--force)..."; rm -rf "$venv"; fi if [ ! -x "$venv/bin/python" ]; then info " Creating venv: $venv" python3 -m venv "$venv" || { err " venv creation failed"; return 1; } else dim " venv exists: $venv (installing/updating deps)" fi info " pip install ${args[*]}" ( cd "$root" && "$venv/bin/pip" install "${args[@]}" ) || { err " pip install failed"; return 1; } ok " $key ready - zstart $key will use $venv/bin/python." } setup_node() { # local key="$1" root="$2" [ -f "$root/package.json" ] || { err " No package.json in $root"; return 1; } z_require npm info " npm install (in $root)..." ( cd "$root" && npm install ) || { err " npm install failed"; return 1; } ok " $key node_modules ready." } rc=0 for key in "${projects[@]}"; do zproj_require "$key" kind="$(zproj "$key" .kind)" root="$(zproj_root "$key")" printf '\n'; info "=== zsetup ($(zproj "$key" .label)) ===" [ -d "$root" ] || { err " Project root not found: $root"; rc=1; continue; } case "$kind" in python) setup_python "$key" "$root" || rc=1 ;; vite|nextjs) setup_node "$key" "$root" || rc=1 ;; *) dim " kind '$kind' - nothing to set up locally." ;; esac done printf '\n' exit "$rc"