Basic steps working
This commit is contained in:
parent
9586a50c39
commit
5c818fc3d9
188
main.go
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() {
|
||||
|
|
|
@ -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…
Reference in New Issue