Browse Source

Basic steps working

master
sloum 2 years ago
parent
commit
5c818fc3d9
  1. 188
      main.go
  2. 2
      spacewalk.md

188
main.go

@ -2,12 +2,19 @@ package main
import (
"bufio"
"bytes"
"crypto/md5"
"crypto/tls"
"encoding/csv"
"fmt"
"io"
"io/ioutil"
"os"
"os/user"
"path/filepath"
"sort"
"strings"
"time"
)
var swPath, fPath string
@ -137,6 +144,119 @@ func readManifest() [][]string {
return records
}
func writeFlight(flight string, records [][]string) error {
p := filepath.Join(fPath, flight)
f, err := os.OpenFile(p, os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer f.Close()
w := csv.NewWriter(f)
w.WriteAll(records)
if err := w.Error(); err != nil {
return err
}
return nil
}
func readFlightLog(flight string) [][]string {
p := filepath.Join(fPath, flight)
f, err := os.Open(p)
ifErrExit(err, "Could not open flight log")
defer f.Close()
r := csv.NewReader(f)
records, err := r.ReadAll()
ifErrExit(err, "Could not read from flight log")
return records
}
func findItemRow(name string, position int, csv [][]string) []string {
for _, row := range csv {
if len(row)-1 < position {
earlyExit("Invalid array position passed to findItemRow")
}
if row[position] == name {
return row
}
}
earlyExit(fmt.Sprintf("Item %q was not found", name))
return []string{}
}
func retrieve(addr string) (string, error) {
addr = strings.TrimSpace(addr)
noprot := strings.Replace(addr, "gemini://", "", 1)
hostResource := strings.SplitN(noprot, "/", 2)
if strings.LastIndex(hostResource[0], ":") == -1 {
hostResource[0] = hostResource[0] + "1965"
}
conf := &tls.Config{
InsecureSkipVerify: true,
}
conn, err := tls.Dial("tcp", hostResource[0], conf)
if err != nil {
return "", fmt.Errorf("TLS Dial Error: %s", err.Error())
}
defer conn.Close()
send := "gemini://" + hostResource[0] + "/" + hostResource[1] + "\r\n"
_, err = conn.Write([]byte(send))
if err != nil {
return "", err
}
result, err := ioutil.ReadAll(conn)
if err != nil {
return "", err
}
resp := strings.SplitN(string(result), "\r\n", 2)
if resp[0][0] != '2' || len(resp) < 2 {
return "", fmt.Errorf("Invalid server response")
}
h := md5.New()
io.WriteString(h, resp[1])
return string(h.Sum(nil)), nil
}
func checkForUpdate(c []string, r chan []string) {
chksum, err := retrieve(c[1])
if err != nil {
fmt.Fprintf(os.Stderr, "Error updating capsule %q: %s\n", c[0], err.Error())
r <- c
return
}
if chksum == c[2] {
r <- c
return
}
c[2] = chksum
currentTime := time.Now()
c[3] = currentTime.Format("2006-01-02")
r <- c
}
func getHeaderFooter(addr string) []byte {
addr = strings.TrimSpace(addr)
if addr == "none" {
return make([]byte, 0)
}
content, err := ioutil.ReadFile(addr)
if err != nil {
fmt.Fprintf(os.Stderr, "Error reading %q\n", addr)
return make([]byte, 0)
}
return content
}
///////////////////////////////
// Command Execution
//////////////////////////////
@ -152,6 +272,7 @@ func create(flight string) {
}
fmt.Printf("Creating flight: %q\n", flight)
usr, _ := user.Current()
happy := false
for !happy {
@ -161,16 +282,20 @@ func create(flight string) {
fmt.Println("Launch path cannot be empty")
continue
}
lp = strings.Replace(lp, "~", usr.HomeDir, -1)
hp, err = getLine("Enter the header path, or leave blank for none: ")
ifErrExit(err, "Error reading from stdin")
if hp == "" {
hp = "none"
}
hp = strings.Replace(hp, "~", usr.HomeDir, -1)
fp, err = getLine("Enter the footer path, or leave blank for none: ")
ifErrExit(err, "Error reading from stdin")
if fp == "" {
fp = "none"
}
fp = strings.Replace(fp, "~", usr.HomeDir, -1)
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: ")
@ -203,14 +328,14 @@ func remove(flight string) {
}
func add(flight, url, title string) {
p := filepath.Join(fPath, "flights", flight)
p := filepath.Join(fPath, 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)
fmt.Printf("Capsule %q added to %s's flight log\n", title, flight)
}
func del(flight, item string) {
@ -218,11 +343,57 @@ func del(flight, item string) {
}
func launchFlights() {
fmt.Println("Hello")
records := readManifest()
fmt.Println("Launching all flights")
for _, fl := range records {
launchFlight(fl[0])
}
fmt.Println("All flights have been launched and statuses displayed")
}
func launchFlight(flight string) {
fmt.Println(flight)
fmt.Printf("Launching %s\n", flight)
manifest := findItemRow(flight, 0, readManifest())
data := readFlightLog(flight)
ch := make(chan []string)
count := 0
for _, capsule := range data {
go checkForUpdate(capsule, ch)
count++
}
updatedData := make([][]string, 0, count)
for count > 0 {
row := <-ch
updatedData = append(updatedData, row)
count--
}
sort.SliceStable(updatedData, func(i, j int) bool { return updatedData[i][3] > updatedData[j][3] })
err := writeFlight(flight, updatedData)
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR: Unable to write %s to file. Continuing with launch, but data will be out of date at next launch. %s\n", flight, err.Error())
}
header := getHeaderFooter(manifest[2])
footer := getHeaderFooter(manifest[3])
var out bytes.Buffer
out.Write(header)
for _, capsule := range updatedData {
ln := fmt.Sprintf("=> %s %s - %s\r\n", capsule[1], capsule[3], capsule[0])
out.WriteString(ln)
}
out.Write(footer)
err = ioutil.WriteFile(strings.TrimSpace(manifest[1]), out.Bytes(), 0644)
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR, cannot launch %q: %s\n", flight, err.Error())
}
}
func showFlights(flight string) {
@ -236,6 +407,15 @@ func showFlights(flight string) {
fmt.Printf("\033[1mHeader Path:\033[0m %s\n", row[2])
fmt.Printf("\033[1mFooter Path:\033[0m %s\n--\n", row[3])
}
if flight != "" {
fmt.Println()
r := readFlightLog(flight)
for _, fl := range r {
fmt.Printf("\033[1m%s\033[0m: %s\n", fl[0], fl[1])
}
}
}
func main() {

2
spacewalk.md

@ -54,7 +54,7 @@ Checks for updates and builds the directory capsule. Takes a flight name to laun
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
Structure: flight-name, launch-path, header-path, footer-path
### flight data

Loading…
Cancel
Save