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 (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/tls"
|
||||||
"encoding/csv"
|
"encoding/csv"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var swPath, fPath string
|
var swPath, fPath string
|
||||||
|
@ -137,6 +144,119 @@ func readManifest() [][]string {
|
||||||
return records
|
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
|
// Command Execution
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
|
@ -152,6 +272,7 @@ func create(flight string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Creating flight: %q\n", flight)
|
fmt.Printf("Creating flight: %q\n", flight)
|
||||||
|
usr, _ := user.Current()
|
||||||
|
|
||||||
happy := false
|
happy := false
|
||||||
for !happy {
|
for !happy {
|
||||||
|
@ -161,16 +282,20 @@ func create(flight string) {
|
||||||
fmt.Println("Launch path cannot be empty")
|
fmt.Println("Launch path cannot be empty")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
lp = strings.Replace(lp, "~", usr.HomeDir, -1)
|
||||||
|
|
||||||
hp, err = getLine("Enter the header path, or leave blank for none: ")
|
hp, err = getLine("Enter the header path, or leave blank for none: ")
|
||||||
ifErrExit(err, "Error reading from stdin")
|
ifErrExit(err, "Error reading from stdin")
|
||||||
if hp == "" {
|
if hp == "" {
|
||||||
hp = "none"
|
hp = "none"
|
||||||
}
|
}
|
||||||
|
hp = strings.Replace(hp, "~", usr.HomeDir, -1)
|
||||||
fp, err = getLine("Enter the footer path, or leave blank for none: ")
|
fp, err = getLine("Enter the footer path, or leave blank for none: ")
|
||||||
ifErrExit(err, "Error reading from stdin")
|
ifErrExit(err, "Error reading from stdin")
|
||||||
if fp == "" {
|
if fp == "" {
|
||||||
fp = "none"
|
fp = "none"
|
||||||
}
|
}
|
||||||
|
fp = strings.Replace(fp, "~", usr.HomeDir, -1)
|
||||||
fmt.Println("Are you happy with the following:")
|
fmt.Println("Are you happy with the following:")
|
||||||
fmt.Printf("Launch path: %s\nHeader path: %s\nFooter path: %s\n", lp, hp, fp)
|
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: ")
|
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) {
|
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)
|
f, err := os.OpenFile(p, os.O_APPEND|os.O_WRONLY, 0644)
|
||||||
ifErrExit(err, fmt.Sprintf("Could not open flight log for %s", flight))
|
ifErrExit(err, fmt.Sprintf("Could not open flight log for %s", flight))
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
ln := fmt.Sprintf("%s, %s, %s, %s\n", title, url, "nil", "0")
|
ln := fmt.Sprintf("%s, %s, %s, %s\n", title, url, "nil", "0")
|
||||||
_, err = f.WriteString(ln)
|
_, err = f.WriteString(ln)
|
||||||
ifErrExit(err, "Unable to save new capsule to data file")
|
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) {
|
func del(flight, item string) {
|
||||||
|
@ -218,11 +343,57 @@ func del(flight, item string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func launchFlights() {
|
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) {
|
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) {
|
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[1mHeader Path:\033[0m %s\n", row[2])
|
||||||
fmt.Printf("\033[1mFooter Path:\033[0m %s\n--\n", row[3])
|
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() {
|
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
|
Paths: $XDG\_DATA\_HOME/spacewalk/flight-config || ~/.local/share/spacewalk/flight-config
|
||||||
Format: csv
|
Format: csv
|
||||||
Structure: flight-name, flight-slug, launch-path, header-path, footer-path
|
Structure: flight-name, launch-path, header-path, footer-path
|
||||||
|
|
||||||
### flight data
|
### flight data
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue