small pixel drawing of a pufferfish zoa

main.go

package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"

	"j3s.sh/zoa/env"
	"j3s.sh/zoa/shell"

	"mvdan.cc/sh/v3/interp"
)

func main() {
	if len(os.Args) <= 1 {
		printUsageExit()
	}

	command := os.Args[1]
	switch command {
	case "deploy":
		zoaDeployShitty()
	case "run":
		zoaRun()
	case "version":
		fmt.Println("0.1.0")
		os.Exit(0)
	default:
		printUsageExit()
	}
}

func zoaRun() {
	if len(os.Args) <= 2 {
		fmt.Println("run requires 1 argument: the path to a posix shell script")
		os.Exit(1)
	}
	path := os.Args[2]

	envs, err := env.GenerateEnv()
	if err != nil {
		log.Fatal(err)
	}

	r, err := interp.New(
		// TODO: make quiet flag silence stdout
		interp.StdIO(nil, os.Stdout, os.Stdout),
		interp.CallHandler(shell.CallHandler),
		interp.Env(envs),
	)
	if err != nil {
		log.Fatal(err)
	}

	session := &shell.Session{
		ScriptPath:    path,
		ScriptBaseDir: filepath.Dir(path),
		Runner:        r,
		SubShell:      false,
	}

	// todo: err?
	session.Run()
}

// ignore this for now, i'll make it better i promise 🥺
func zoaDeployShitty() {
	if len(os.Args) <= 2 {
		fmt.Println("deploy requires 1+ arguments: hostnames to deploy + run zoa on")
		os.Exit(1)
	}
	hosts := os.Args[2:]

	zoaPath, err := exec.LookPath("zoa")
	if err != nil {
		log.Fatal("(TODO) please install zoa to /usr/local/bin and ensure it's in your PATH")
	}

	// TODO: replace remote binary if newer
	// err = shell.SSH("command -v zoa", hosts)
	// if err != nil {
	// Install Zoa
	err = shell.SCP(zoaPath, hosts)
	if err != nil {
		log.Fatal(err)
	}
	err = shell.SSH("chmod +x zoa", hosts)
	if err != nil {
		log.Fatal(err)
	}
	err = shell.SSH("mv zoa /usr/local/bin/", hosts)
	if err != nil {
		subErr := shell.SSH("sudo mv zoa /usr/local/bin/", hosts)
		if subErr != nil {
			log.Fatal(err)
		}
	}

	err = shell.SCP("main", hosts)
	if err != nil {
		log.Fatal(err)
	}
	err = shell.SCPDir("scripts", hosts)
	if err != nil {
		log.Fatal(err)
	}
	err = shell.SCPDir("files", hosts)
	if err != nil {
		log.Fatal(err)
	}
	err = shell.SSH("sudo zoa .", hosts)
	if err != nil {
		log.Fatal(err)
	}
	os.Exit(0)
}

func printUsageExit() {
	// TODO: -v -h
	fmt.Println(`usage: zoa <command> [arguments]

commands:
  deploy <hostname/ip> - install zoa on the given host & execute
  run    <script>      - execute the given zoa script
  version              - print zoa version

examples:
  zoa run config-my-shit-pwease
  zoa run /var/lib/my-zoa-repo/main
  zoa deploy . web.j3s.sh git.j3s.sh`)
	os.Exit(1)
}