Initial commit

This commit is contained in:
sloum 2020-03-20 22:54:38 -07:00
commit 8c92ace89a
3 changed files with 316 additions and 0 deletions

244
main.go Normal file
View File

@ -0,0 +1,244 @@
package main
import (
"bufio"
"encoding/csv"
"fmt"
"os"
"os/user"
"path/filepath"
"strings"
)
var swPath, fPath string
///////////////////////////////
// Startup & helpers
//////////////////////////////
func ifErrExit(e error, msg string) {
if e != nil {
fmt.Fprintf(os.Stderr, "%s: %s\n", msg, e.Error())
os.Exit(1)
}
}
func earlyExit(msg string) {
fmt.Fprintf(os.Stderr, "Error: %s\n", msg)
os.Exit(1)
}
// validateDataPaths makes sure that the necessary data folders exist
// for the user running spacewalk. It builds them if they are not
// present and does an error exit if there is an error.
func validateDataPaths() {
xdgDataHome := os.Getenv("XDG_DATA_HOME")
if xdgDataHome == "" {
usr, _ := user.Current()
xdgDataHome = filepath.Join(usr.HomeDir, "/.local/share")
}
neededFolders := filepath.Join(xdgDataHome, "spacewalk")
neededFolders, _ = filepath.Abs(neededFolders)
swPath = neededFolders
neededFolders = filepath.Join(neededFolders, "flights")
fPath = neededFolders
err := os.MkdirAll(neededFolders, 0755)
ifErrExit(err, "Error validation data paths")
p := filepath.Join(swPath, "flight-manifest")
f, err := os.OpenFile(p, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
ifErrExit(err, "Could not create flight manifest")
f.Close()
}
func displayUsage() {
fmt.Println("spacewalk [stuff] [things]")
os.Exit(0)
}
// parseArgs is the main entry point into scbm and will run the appropriate functions
// based on the arguments passed in at run time.
func parseArgs() {
a := os.Args
if len(a) == 1 {
displayUsage()
}
switch a[1] {
case "create":
if len(a) == 3 {
create(a[2])
} else {
earlyExit("Missing flight name.\n- spacewalk create \033[3mflight\033[0m")
}
case "update":
if len(a) == 3 {
update(a[2])
} else {
earlyExit("Missing flight name.\n- spacewalk update \033[3mflight\033[0m")
}
case "remove":
if len(a) == 3 {
remove(a[2])
} else {
earlyExit("Missing flight name.\n- spacewalk remove \033[3mflight\033[0m")
}
case "add":
if len(a) == 5 {
add(a[2], a[3], a[4])
} else {
earlyExit("Incorrect syntax.\n- spacewalk add \033[3mflight url title\033[0m")
}
case "delete":
if len(a) == 4 {
del(a[2], a[3])
} else {
earlyExit("Incorrect syntax.\n- spacewalk delete \033[3mflight url|title\033[0m")
}
case "launch":
if len(a) == 2 {
launchFlights()
} else if len(a) == 3 {
launchFlight(a[2])
} else {
earlyExit("Incorrect syntax.\n- spacewalk launch [\033[3mflight\033[0m]")
}
case "show":
if len(a) == 2 {
showFlights("")
} else if len(a) == 3 {
showFlights(a[2])
} else {
earlyExit("Incorrect syntax.\n- spacewalk show [\033[3mflight\033[0m]")
}
default:
earlyExit(fmt.Sprintf("Unknown command %q", a[1]))
}
}
func getLine(prefix string) (string, error) {
reader := bufio.NewReader(os.Stdin)
fmt.Print(prefix)
text, err := reader.ReadString('\n')
if err != nil {
return "", err
}
return text[:len(text)-1], nil
}
func readManifest() [][]string {
p := filepath.Join(swPath, "flight-manifest")
f, err := os.Open(p)
ifErrExit(err, "Could not open flight manifest")
defer f.Close()
r := csv.NewReader(f)
records, err := r.ReadAll()
ifErrExit(err, "Could not read from flight manifest")
return records
}
///////////////////////////////
// Command Execution
//////////////////////////////
func create(flight string) {
var lp, hp, fp string
var err error
records := readManifest()
for _, r := range records {
if r[0] == flight {
earlyExit(fmt.Sprintf("There is already a flight with the name %q", flight))
}
}
fmt.Printf("Creating flight: %q\n", flight)
happy := false
for !happy {
lp, err = getLine("Enter the launch path (output path including file name): ")
ifErrExit(err, "Error reading from stdin")
if lp == "" {
fmt.Println("Launch path cannot be empty")
continue
}
hp, err = getLine("Enter the header path, or leave blank for none: ")
ifErrExit(err, "Error reading from stdin")
if hp == "" {
hp = "none"
}
fp, err = getLine("Enter the footer path, or leave blank for none: ")
ifErrExit(err, "Error reading from stdin")
if fp == "" {
fp = "none"
}
fmt.Println("Are you happy with the following:")
fmt.Printf("Launch path: %s\nHeader path: %s\nFooter path: %s\n", lp, hp, fp)
yesNo, err := getLine("Type 'yes' to accept, anything else to redo: ")
ifErrExit(err, "Error reading from stdin")
if strings.ToLower(yesNo) == "yes" {
happy = true
}
}
p := filepath.Join(swPath, "flight-manifest")
f, err := os.OpenFile(p, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
ifErrExit(err, "Could not open flight manifest")
defer f.Close()
ln := fmt.Sprintf("%s, %s, %s, %s\n", flight, lp, hp, fp)
_, err = f.WriteString(ln)
ifErrExit(err, "Unable to save new flight to data file")
fpath := filepath.Join(fPath, flight)
ff, err := os.OpenFile(fpath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
ifErrExit(err, fmt.Sprintf("Could not create flight log for %s", flight))
ff.Close()
}
func update(flight string) {
fmt.Println(flight)
}
func remove(flight string) {
fmt.Println(flight)
}
func add(flight, url, title string) {
p := filepath.Join(fPath, "flights", flight)
f, err := os.OpenFile(p, os.O_APPEND|os.O_WRONLY, 0644)
ifErrExit(err, fmt.Sprintf("Could not open flight log for %s", flight))
defer f.Close()
ln := fmt.Sprintf("%s, %s, %s, %s\n", title, url, "nil", "0")
_, err = f.WriteString(ln)
ifErrExit(err, "Unable to save new capsule to data file")
fmt.Printf("Capsule %q added to %s's flight log", title, flight)
}
func del(flight, item string) {
fmt.Println(flight, item)
}
func launchFlights() {
fmt.Println("Hello")
}
func launchFlight(flight string) {
fmt.Println(flight)
}
func showFlights(flight string) {
records := readManifest()
for _, row := range records {
if flight != "" && row[0] != flight {
continue
}
fmt.Printf("\033[1mFlight Name:\033[0m %s\n", row[0])
fmt.Printf("\033[1mLaunch Path:\033[0m %s\n", row[1])
fmt.Printf("\033[1mHeader Path:\033[0m %s\n", row[2])
fmt.Printf("\033[1mFooter Path:\033[0m %s\n--\n", row[3])
}
}
func main() {
validateDataPaths()
parseArgs()
}

BIN
spacewalk Executable file

Binary file not shown.

72
spacewalk.md Normal file
View File

@ -0,0 +1,72 @@
# spacewalk
This is intended to be a golang based moku-pona-_like_ program for gemini.
## commands
### create
Adds a new flight to the system's spacewalk flight list.
- spacewalk create _flight_
### update
Updates the settings for a flight
- spacewalk update _flight_
### remove
Removes an existing flight.
- spacewalk remove _flight_
### add
Adds a capsule to the a flight's feed. Requires the URL and a display name.
- spacewalk add flight _url_ _title_
### delete
Removes a capsule from the feed. Pass either a url or a display name.
- spacewalk delete flight _url|title_
### show
When called without further arguments, will list the available flights. When called with a flight as an argument will list the capsules for that flight.
- spacewalk show [flight]
### launch
Checks for updates and builds the directory capsule. Takes a flight name to launch just that flight or will launch all flights when not passed a flight name.
- spacewalk launch [flight]
## files
### flight config
Paths: $XDG\_DATA\_HOME/spacewalk/flight-config || ~/.local/share/spacewalk/flight-config
Format: csv
Structure: flight-name, flight-slug, launch-path, header-path, footer-path
### flight data
Paths: $XDG\_DATA\_HOME/spacewalk/flights/{flight-slug} || ~/.local/share/spacewalk/flights/{flight-slug}
Format: csv
Structure: capsule-name, capsule-url, checksum, timestamp
## glossary
capsule : a gemini site/page (a gemini URL)
flight : a collection of capsules for which spacewalk can generate directory capsules.