#!/usr/bin/env bash # Install farm on macOS or Linux: # # curl -fsSL https://farm.kylesoft.com/install.sh | bash # # Puts farm in ~/buildfarm (or --dir / $FARM_HOME) and a `farm` command in ~/.local/bin. # No sudo, nothing outside those two places (plus one PATH line in your shell profile if # ~/.local/bin isn't on your PATH yet). Running it again updates farm and keeps your # machines, builds and settings. set -euo pipefail VERSION="0.2.0" SHA256="303d6181bf955b987665fa53ccc8f8cff3de19cd6a4e8371552f4bda2a320928" SITE="${FARM_SITE:-https://farm.kylesoft.com}" # Where release files live (this site today; maybe a storage bucket later). DOWNLOADS="${FARM_DOWNLOADS:-${FARM_SITE:-https://farm.kylesoft.com}}" DIR="${FARM_HOME:-$HOME/buildfarm}" SETUP=ask while [ $# -gt 0 ]; do case "$1" in --dir) DIR="$2"; shift 2 ;; --no-setup) SETUP=no; shift ;; --setup) SETUP=yes; shift ;; -h|--help) echo "usage: install.sh [--dir DIR] [--setup|--no-setup]"; exit 0 ;; *) echo "install.sh: unknown option $1" >&2; exit 2 ;; esac done say() { printf '\033[1m==>\033[0m %s\n' "$*"; } note() { printf ' %s\n' "$*"; } die() { printf 'install.sh: %s\n' "$*" >&2; exit 1; } OS="$(uname -s)" [ "$OS" = Linux ] || [ "$OS" = Darwin ] || die "this installer is for macOS and Linux; on Windows use install.ps1" [ "$(id -u)" != 0 ] || die "install farm as your normal user, not root" # ------------------------------------------------------------------ what farm needs missing=() py="" for c in python3 python; do if command -v "$c" >/dev/null && "$c" -c 'import sys; sys.exit(sys.version_info < (3, 8))' 2>/dev/null; then py="$c"; break; fi done [ -n "$py" ] || missing+=(python3) command -v git >/dev/null || missing+=(git) command -v ssh >/dev/null || missing+=(ssh) if [ ${#missing[@]} -gt 0 ]; then echo "farm needs: ${missing[*]}" >&2 if [ "$OS" = Darwin ]; then echo "Install Apple's command line tools (they include all three), then run this again:" >&2 echo " xcode-select --install" >&2 else echo "Install them with your package manager, then run this again. For example:" >&2 echo " sudo apt install python3 git openssh-client # Debian, Ubuntu" >&2 echo " sudo dnf install python3 git openssh-clients # Fedora" >&2 echo " sudo pacman -S python git openssh # Arch" >&2 fi exit 1 fi if [ -d "$DIR/.git" ]; then die "$DIR is a git checkout of farm; update it with git pull instead" fi # ------------------------------------------------------------------ download and check tmp="$(mktemp -d)" trap 'rm -rf "$tmp"' EXIT tarball="farm-$VERSION.tar.gz" say "Downloading farm $VERSION" curl -fsSL --proto '=https' --tlsv1.2 -o "$tmp/$tarball" "$DOWNLOADS/$tarball" if command -v sha256sum >/dev/null; then got="$(sha256sum "$tmp/$tarball" | awk '{print $1}')" else got="$(shasum -a 256 "$tmp/$tarball" | awk '{print $1}')"; fi [ "$got" = "$SHA256" ] || die "the download doesn't match its checksum (got $got). Nothing was installed." note "checksum ok" mkdir -p "$tmp/x" tar -xzf "$tmp/$tarball" -C "$tmp/x" src="$tmp/x/farm-$VERSION" [ -x "$src/bin/farm" ] || die "unexpected archive layout" # ------------------------------------------------------------------ install say "Installing into $DIR" mkdir -p "$DIR" # Replace farm's own files; hosts.toml, state/, artifacts/ and work/ are yours and stay. for d in bin lib bootstrap templates join; do rm -rf "${DIR:?}/$d"; cp -R "$src/$d" "$DIR/$d"; done cp "$src/README.md" "$src/hosts.example.toml" "$DIR/" [ -f "$src/LICENSE" ] && cp "$src/LICENSE" "$DIR/" chmod +x "$DIR/bin/farm" # Use the Python we found, whatever it's called here. if [ "$py" != python3 ]; then sed -i.bak "1s|.*|#!/usr/bin/env $py|" "$DIR/bin/farm" && rm -f "$DIR/bin/farm.bak"; fi mkdir -p "$HOME/.local/bin" ln -sf "$DIR/bin/farm" "$HOME/.local/bin/farm" note "farm command: ~/.local/bin/farm" case ":$PATH:" in *":$HOME/.local/bin:"*) ;; *) if [ "$OS" = Darwin ] || [ "${SHELL##*/}" = zsh ]; then rc="$HOME/.zshrc"; else rc="$HOME/.bashrc"; fi [ "${SHELL##*/}" = fish ] && rc="" if [ -n "$rc" ] && ! grep -qs 'added by farm' "$rc"; then # shellcheck disable=SC2016 # written literally, expanded by the shell later printf '\nexport PATH="$HOME/.local/bin:$PATH" # added by farm\n' >> "$rc" note "added ~/.local/bin to your PATH in $rc (open a new terminal for it to apply)" else note "add ~/.local/bin to your PATH to run farm by name" fi ;; esac "$DIR/bin/farm" version >/dev/null || die "farm was copied but doesn't start; please report this" echo say "farm $VERSION is installed." if [ "$SETUP" = ask ] && [ -r /dev/tty ] && [ -t 1 ]; then read -r -p "Set it up now (check this computer, add a build machine)? [Y/n] " a < /dev/tty || a=n case "$a" in n*|N*) SETUP=no ;; *) SETUP=yes ;; esac fi if [ "$SETUP" = yes ]; then "$DIR/bin/farm" setup < /dev/tty else echo echo "Next:" echo " farm setup check this computer and add a build machine" echo " farm ui or do everything from your browser" fi