small pixel drawing of a pufferfish enby

bleh
Jes Olson j3s@c3f.net
Mon, 02 Jan 2023 23:58:52 -0800
commit

d22f1a3f600a8c6c163488bdb671759ddfd205d2

parent

6e1cab0265213628c8014f1e8665914d36cc87c4

7 files changed, 164 insertions(+), 124 deletions(-)

jump to
M READMEREADME

@@ -35,4 +35,4 @@ fail on bsd?

credits - inspiration from pf, smtpd, kanshi, nomad + inspiration from pf, smtpd, kanshi, nomad, caddy
A config/config.go

@@ -0,0 +1,113 @@

+package config + +import ( + "bufio" + "fmt" + "io" + "os" + "strings" +) + +// Block is a list of directives. +type Block []*Binary + +type Fetch struct { + Url string + Every string +} + +// Binary is a configuration directive. +type Binary struct { + Name string + Fetch Fetch + Build string + Args []string +} + +// Load loads a configuration file. +func Load(path string) (Block, error) { + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + + return Read(f) +} + +// Read parses a configuration file from an io.Reader. +func Read(r io.Reader) (Block, error) { + scanner := bufio.NewScanner(r) + + block, closingBrace, err := readBlock(scanner) + if err != nil { + return nil, err + } else if closingBrace { + return nil, fmt.Errorf("unexpected '}'") + } + + return block, scanner.Err() +} + +// readBlock reads a block. closingBrace is true if parsing stopped on '}' +// (otherwise, it stopped on Scanner.Scan). +func readBlock(scanner *bufio.Scanner) (block Block, closingBrace bool, err error) { + for scanner.Scan() { + l := scanner.Text() + words := strings.Split(l, " ") + if err != nil { + return nil, false, fmt.Errorf("failed to parse configuration file: %v", err) + } + + if len(words) == 0 { + continue + } + + if len(words) == 1 && l == "" { + continue + } + + if len(words) == 1 && l[len(l)-1] == '}' { + closingBrace = true + break + } + + if words[0] == "#" { + continue + } + + var fetch Fetch + if strings.Contains(words[0], "fetch") { + fmt.Println("fetchin") + fetch.Url = words[1] + fetch.Every = words[3] + } + + var d *Binary + if words[len(words)-1] == "{" && l[len(l)-1] == '{' { + name := words[0] + + childBlock, childClosingBrace, err := readBlock(scanner) + if err != nil { + return nil, false, err + } else if !childClosingBrace { + return nil, false, io.ErrUnexpectedEOF + } + + // Allows callers to tell apart "no block" and "empty block" + if childBlock == nil { + childBlock = Block{} + } + + d = &Binary{Name: name} + } else { + d = &Binary{Name: words[0], Fetch: fetch} + fmt.Printf("d: %v\n", d) + } + block = append(block, d) + fmt.Printf("block: %v\n", block) + } + + return block, closingBrace, nil +} +
A enby

@@ -0,0 +1,14 @@

+#!/bin/sh + + printf %s "\ + enby + a simple binary runner + + commands + [d]aemon <config> - Run enby in daemon-mode. + [l]ogs <binary> - Print stdout/stderr for a binary. + [r]eload - Reload config file. + [s]tatus - Check the status of all binaries. +" + exit 0 +}
M example-configexample-config

@@ -1,112 +1,15 @@

-# todo: consider var support -# todo: auto-fetch - -# stored in /var/lib/wuji/artifact/??? -object prometheus url https://github.com/prometheus/prometheus/releases/download/v2.41.0/prometheus-2.41.0.linux-amd64.tar.gz \ - extract prometheus promtool - -action gobuild exec go build . - -process fetch prometheus exec ./prometheus - -wuji prometheus { - fetch object prometheus every 60m - exec ./prometheus +# fetch <url> [every <interval>] +# - if you use the "every" param, your binary will rebuild & restart +# when a new version is available. +# build <cmd1> [cmd2...] +j3s.sh { +# bananas + fetch https://git.j3s.sh/j3s.sh every 60s + build go build . } -wuji j3s.sh { - fetch artifact.prometheus - exec go run . +legit { + fetch https://git.icyphox.com/legit every 60s + build go build . + args -config /etc/legit/config.yaml } - -wuji cake-timer { - every 6m - action send-email -} - -task prometheus { - artifact url https://github.com/prometheus/prometheus/releases/download/v2.41.0/prometheus-2.41.0.linux-amd64.tar.gz -} - - - - - - - - - - - - - - - -examples: - - task run my website { - fetch https://git.j3s.sh/j3s.sh protocol git - run go run . - } - watch /var/lib/sqlite.db - -action blocks define actions - they're basically -little shell snippets. - -you connect them by specifying actions -in your watch blocks. - -this is very simple in concept, but incredibly -useful in practice. - -# comments are shell-style - -j3s = "https://git.j3s.sh/j3s.sh" -every 5m fetch j3s - -watch(3m) https://git.j3s.sh/j3s.sh -action go run . - -wuji watch https://git.j3s.sh/j3s.sh every 5m action go-build - -wuji fetch https://git.j3s.sh/j3s.sh every 5m - > created wuji resource - - -when resource. - - - - - - - -# task params -# fetch [url]: fetch resource from url -# every [interval]: execute this task every $interval -# exec -# - - - -# fetch params -# changed: what to do if the remote file changes -binary j3s.sh { - fetch https://git.j3s.sh/j3s.sh - exec go build . -} - -task run my website { - require binary j3s.sh - if binary j3s.sh changes restart task - command j3s.sh - env whatever - args -one -two -three -} - - -fetch an artifact -run a process -when the fetched artifact changes, restart the process - -
A go.mod

@@ -0,0 +1,3 @@

+module git.j3s.sh/enby + +go 1.19
A main.go

@@ -0,0 +1,21 @@

+package main + +import ( + "fmt" + "log" + + "git.j3s.sh/enby/config" +) + +func main() { + cfg, err := config.Load("example-config") + if err != nil { + log.Fatal(err) + } + + fmt.Printf("%+v\n", cfg) + for _, b := range cfg { + fmt.Printf("%+v\n", b) + fmt.Printf("%+v\n", b.Name) + } +}
D shrapnl

@@ -1,14 +0,0 @@

-#!/bin/sh - - printf %s "\ - shrapnl - a simple task machine - - commands - [d]aemon [config] - Run shrapnl in daemon-mode. - [l]ogs [task] - Print stdout/stderr for a task. - [r]eload - Reload config file. - [s]tatus - Check the status of all tasks. -" - exit 0 -}