From 53d4a70ed2d1db9e7ebb98ec734d414539a74fc8 Mon Sep 17 00:00:00 2001 From: Andinus Date: Fri, 24 Apr 2020 19:52:18 +0530 Subject: Move app func to main --- apod.go | 169 +++++++++++++++++++++++++++++++++++++++++++++++++++++ bpod.go | 140 ++++++++++++++++++++++++++++++++++++++++++++ cmd/cetus/apod.go | 169 ----------------------------------------------------- cmd/cetus/app.go | 99 ------------------------------- cmd/cetus/bpod.go | 140 -------------------------------------------- cmd/cetus/env.go | 18 ------ cmd/cetus/main.go | 47 --------------- cmd/cetus/usage.go | 15 ----- env.go | 18 ++++++ main.go | 78 +++++++++++++++++++++++++ parseargs.go | 70 ++++++++++++++++++++++ usage.go | 15 +++++ 12 files changed, 490 insertions(+), 488 deletions(-) create mode 100644 apod.go create mode 100644 bpod.go delete mode 100644 cmd/cetus/apod.go delete mode 100644 cmd/cetus/app.go delete mode 100644 cmd/cetus/bpod.go delete mode 100644 cmd/cetus/env.go delete mode 100644 cmd/cetus/main.go delete mode 100644 cmd/cetus/usage.go create mode 100644 env.go create mode 100644 main.go create mode 100644 parseargs.go create mode 100644 usage.go diff --git a/apod.go b/apod.go new file mode 100644 index 0000000..2c0f2a0 --- /dev/null +++ b/apod.go @@ -0,0 +1,169 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "os" + + "tildegit.org/andinus/cetus/apod" + "tildegit.org/andinus/cetus/background" + "tildegit.org/andinus/cetus/cache" + "tildegit.org/andinus/cetus/notification" +) + +func execAPOD() { + apodApi := getEnv("APOD_API", "https://api.nasa.gov/planetary/apod") + apodKey := getEnv("APOD_KEY", "DEMO_KEY") + + // reqInfo holds all the parameters that needs to be sent with + // the request. GetJson() will pack apiKey & date in params + // map before sending it to another function. Adding params + // here will not change the behaviour of the function, changes + // have to be made in GetJson() too. + reqInfo = make(map[string]string) + reqInfo["api"] = apodApi + reqInfo["apiKey"] = apodKey + reqInfo["date"] = apodDate + + if random { + reqInfo["date"] = apod.RandDate() + } + + cacheDir := fmt.Sprintf("%s/%s", cache.GetDir(), "apod") + os.MkdirAll(cacheDir, os.ModePerm) + + // Check if the file is available locally, if it is then don't + // download it again and get it from disk + file = fmt.Sprintf("%s/%s.json", cacheDir, reqInfo["date"]) + + if _, err := os.Stat(file); err == nil { + data, err := ioutil.ReadFile(file) + + // Not being able to read from the cache file is a + // small error and the program shouldn't exit but + // should continue after printing the log so that the + // user can investigate it later. + if err != nil { + err = fmt.Errorf("%s%s\n%s", + "apod.go: failed to read file to data: ", file, + err.Error()) + log.Println(err) + dlAndCacheAPODBody() + } + body = string(data) + + } else if os.IsNotExist(err) { + dlAndCacheAPODBody() + + } else { + // If file existed then that is handled by the if + // block, if it didn't exist then that is handled by + // the else if block. If we reach here then that means + // it's Schrödinger's file & something else went + // wrong. + log.Fatal(err) + } + + if dump { + fmt.Println(body) + } + + res := apod.APOD{} + err = apod.UnmarshalJson(&res, body) + if err != nil { + log.Fatal(err) + } + + // res.Msg will be returned when there is error on user input + // or the api server. + if len(res.Msg) != 0 { + fmt.Printf("Message: %s", res.Msg) + os.Exit(1) + } + + // Send a desktop notification if notify flag was passed. + if notify { + n := notification.Notif{} + n.Title = res.Title + n.Message = fmt.Sprintf("%s\n\n%s", + res.Date, + res.Explanation) + + err = n.Notify() + if err != nil { + log.Println(err) + } + } + + if print { + fmt.Printf("Title: %s\n\n", res.Title) + if len(res.Copyright) != 0 { + fmt.Printf("Copyright: %s\n", res.Copyright) + } + fmt.Printf("Date: %s\n\n", res.Date) + fmt.Printf("Media Type: %s\n", res.MediaType) + if res.MediaType == "image" { + fmt.Printf("URL: %s\n\n", res.HDURL) + } else { + fmt.Printf("URL: %s\n\n", res.URL) + } + fmt.Printf("Explanation: %s\n", res.Explanation) + } + + // Proceed only if the command was set because if it was fetch + // then it's already finished & should exit now. + if os.Args[1] == "fetch" { + os.Exit(0) + } + + // Try to set background only if the media type is an image. + // First it downloads the image to the cache directory and + // then tries to set it with feh. If the download fails then + // it exits with a non-zero exit code. + if res.MediaType != "image" { + os.Exit(0) + } + imgFile := fmt.Sprintf("%s/%s", cacheDir, res.Title) + + // Check if the file is available locally, if it is then don't + // download it again and set it from disk. + if _, err := os.Stat(imgFile); os.IsNotExist(err) { + err = background.Download(imgFile, res.HDURL) + if err != nil { + log.Fatal(err) + } + } else { + if err != nil { + log.Fatal(err) + } + } + + err = background.SetFromFile(imgFile) + if err != nil { + log.Fatal(err) + } +} + +func dlAndCacheAPODBody() { + body, err = apod.GetJson(reqInfo) + if err != nil { + err = fmt.Errorf("%s\n%s", + "apod.go: failed to get json response from api", + err.Error()) + log.Fatal(err) + } + + // Write body to the cache so that it can be read later. + err = ioutil.WriteFile(file, []byte(body), 0644) + + // Not being able to write to the cache file is a small error + // and the program shouldn't exit but should continue after + // printing the log so that the user can investigate it later. + if err != nil { + err = fmt.Errorf("%s%s\n%s", + "apod.go: failed to write body to file: ", file, + err.Error()) + log.Println(err) + } +} diff --git a/bpod.go b/bpod.go new file mode 100644 index 0000000..7aa0a1b --- /dev/null +++ b/bpod.go @@ -0,0 +1,140 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "os" + "time" + + "tildegit.org/andinus/cetus/background" + "tildegit.org/andinus/cetus/bpod" + "tildegit.org/andinus/cetus/cache" + "tildegit.org/andinus/cetus/notification" +) + +func execBPOD() { + bpodApi := getEnv("BPOD_API", "https://www.bing.com/HPImageArchive.aspx") + + // reqInfo holds all the parameters that needs to be sent with + // the request. GetJson() will pack apiKey & date in params + // map before sending it to another function. Adding params + // here will not change the behaviour of the function, changes + // have to be made in GetJson() too. + reqInfo = make(map[string]string) + reqInfo["api"] = bpodApi + + if random { + reqInfo["random"] = "true" + } + + cacheDir := fmt.Sprintf("%s/%s", cache.GetDir(), "bpod") + os.MkdirAll(cacheDir, os.ModePerm) + + body, err = bpod.GetJson(reqInfo) + if err != nil { + err = fmt.Errorf("%s\n%s", + "bpod.go: failed to get json response from api", + err.Error()) + log.Fatal(err) + } + + if dump { + fmt.Println(body) + } + + res, err := bpod.UnmarshalJson(body) + if err != nil { + log.Fatal(err) + } + + // Correct format + res.URL = fmt.Sprintf("%s%s", "https://www.bing.com", res.URL) + dt, err := time.Parse("20060102", res.StartDate) + if err != nil { + log.Fatal(err) + } + res.StartDate = dt.Format("2006-01-02") + + // Save response in cache after marshalling it again, we do + // this instead of saving the response so as to not break the + // format in which cache is saved. If random flag was passed + // then the response will contain all 7 values so we have to + // marshal it but why not save non-random directly? Because + // that means the format in which both are saved will be + // different. One will be the raw response whereas other will + // be marshalled response. We're currently not using this body + // cache but this is just to save information. + file := fmt.Sprintf("%s/%s.json", cacheDir, res.StartDate) + body, err = bpod.MarshalJson(res) + if err != nil { + // We should warn the user if this returns an error + // but the program shouldn't exit. + log.Println("bpod.go: failed to marshal res to body, not saving cache") + } else { + err = ioutil.WriteFile(file, []byte(body), 0644) + // Not being able to write to the cache file is a + // small error and the program shouldn't exit but + // should continue after printing the log so that the + // user can investigate it later. + if err != nil { + err = fmt.Errorf("%s%s\n%s", + "bpod.go: failed to write body to file: ", file, + err.Error()) + log.Println(err) + } + } + + // Send a desktop notification if notify flag was passed. + if notify { + n := notification.Notif{} + n.Title = res.Title + n.Message = fmt.Sprintf("%s\n\n%s", + res.StartDate, + res.Copyright) + + err = n.Notify() + if err != nil { + log.Println(err) + } + } + + if print { + fmt.Printf("Title: %s\n\n", res.Title) + fmt.Printf("Copyright: %s\n", res.Copyright) + fmt.Printf("Copyright Link: %s\n", res.CopyrightLink) + fmt.Printf("Date: %s\n\n", res.StartDate) + fmt.Printf("URL: %s\n", res.URL) + } + + // Proceed only if the command was set because if it was fetch + // then it's already finished & should exit now. + if os.Args[1] == "fetch" { + os.Exit(0) + } + + // Try to set background only if the media type is an image. + // First it downloads the image to the cache directory and + // then tries to set it with feh. If the download fails then + // it exits with a non-zero exit code. + imgFile := fmt.Sprintf("%s/%s", cacheDir, res.Title) + + // Check if the file is available locally, if it is then don't + // download it again and set it from disk + if _, err := os.Stat(imgFile); os.IsNotExist(err) { + err = background.Download(imgFile, res.URL) + if err != nil { + log.Fatal(err) + } + + } else { + if err != nil { + log.Fatal(err) + } + } + + err = background.SetFromFile(imgFile) + if err != nil { + log.Fatal(err) + } +} diff --git a/cmd/cetus/apod.go b/cmd/cetus/apod.go deleted file mode 100644 index 2c0f2a0..0000000 --- a/cmd/cetus/apod.go +++ /dev/null @@ -1,169 +0,0 @@ -package main - -import ( - "fmt" - "io/ioutil" - "log" - "os" - - "tildegit.org/andinus/cetus/apod" - "tildegit.org/andinus/cetus/background" - "tildegit.org/andinus/cetus/cache" - "tildegit.org/andinus/cetus/notification" -) - -func execAPOD() { - apodApi := getEnv("APOD_API", "https://api.nasa.gov/planetary/apod") - apodKey := getEnv("APOD_KEY", "DEMO_KEY") - - // reqInfo holds all the parameters that needs to be sent with - // the request. GetJson() will pack apiKey & date in params - // map before sending it to another function. Adding params - // here will not change the behaviour of the function, changes - // have to be made in GetJson() too. - reqInfo = make(map[string]string) - reqInfo["api"] = apodApi - reqInfo["apiKey"] = apodKey - reqInfo["date"] = apodDate - - if random { - reqInfo["date"] = apod.RandDate() - } - - cacheDir := fmt.Sprintf("%s/%s", cache.GetDir(), "apod") - os.MkdirAll(cacheDir, os.ModePerm) - - // Check if the file is available locally, if it is then don't - // download it again and get it from disk - file = fmt.Sprintf("%s/%s.json", cacheDir, reqInfo["date"]) - - if _, err := os.Stat(file); err == nil { - data, err := ioutil.ReadFile(file) - - // Not being able to read from the cache file is a - // small error and the program shouldn't exit but - // should continue after printing the log so that the - // user can investigate it later. - if err != nil { - err = fmt.Errorf("%s%s\n%s", - "apod.go: failed to read file to data: ", file, - err.Error()) - log.Println(err) - dlAndCacheAPODBody() - } - body = string(data) - - } else if os.IsNotExist(err) { - dlAndCacheAPODBody() - - } else { - // If file existed then that is handled by the if - // block, if it didn't exist then that is handled by - // the else if block. If we reach here then that means - // it's Schrödinger's file & something else went - // wrong. - log.Fatal(err) - } - - if dump { - fmt.Println(body) - } - - res := apod.APOD{} - err = apod.UnmarshalJson(&res, body) - if err != nil { - log.Fatal(err) - } - - // res.Msg will be returned when there is error on user input - // or the api server. - if len(res.Msg) != 0 { - fmt.Printf("Message: %s", res.Msg) - os.Exit(1) - } - - // Send a desktop notification if notify flag was passed. - if notify { - n := notification.Notif{} - n.Title = res.Title - n.Message = fmt.Sprintf("%s\n\n%s", - res.Date, - res.Explanation) - - err = n.Notify() - if err != nil { - log.Println(err) - } - } - - if print { - fmt.Printf("Title: %s\n\n", res.Title) - if len(res.Copyright) != 0 { - fmt.Printf("Copyright: %s\n", res.Copyright) - } - fmt.Printf("Date: %s\n\n", res.Date) - fmt.Printf("Media Type: %s\n", res.MediaType) - if res.MediaType == "image" { - fmt.Printf("URL: %s\n\n", res.HDURL) - } else { - fmt.Printf("URL: %s\n\n", res.URL) - } - fmt.Printf("Explanation: %s\n", res.Explanation) - } - - // Proceed only if the command was set because if it was fetch - // then it's already finished & should exit now. - if os.Args[1] == "fetch" { - os.Exit(0) - } - - // Try to set background only if the media type is an image. - // First it downloads the image to the cache directory and - // then tries to set it with feh. If the download fails then - // it exits with a non-zero exit code. - if res.MediaType != "image" { - os.Exit(0) - } - imgFile := fmt.Sprintf("%s/%s", cacheDir, res.Title) - - // Check if the file is available locally, if it is then don't - // download it again and set it from disk. - if _, err := os.Stat(imgFile); os.IsNotExist(err) { - err = background.Download(imgFile, res.HDURL) - if err != nil { - log.Fatal(err) - } - } else { - if err != nil { - log.Fatal(err) - } - } - - err = background.SetFromFile(imgFile) - if err != nil { - log.Fatal(err) - } -} - -func dlAndCacheAPODBody() { - body, err = apod.GetJson(reqInfo) - if err != nil { - err = fmt.Errorf("%s\n%s", - "apod.go: failed to get json response from api", - err.Error()) - log.Fatal(err) - } - - // Write body to the cache so that it can be read later. - err = ioutil.WriteFile(file, []byte(body), 0644) - - // Not being able to write to the cache file is a small error - // and the program shouldn't exit but should continue after - // printing the log so that the user can investigate it later. - if err != nil { - err = fmt.Errorf("%s%s\n%s", - "apod.go: failed to write body to file: ", file, - err.Error()) - log.Println(err) - } -} diff --git a/cmd/cetus/app.go b/cmd/cetus/app.go deleted file mode 100644 index 32225d7..0000000 --- a/cmd/cetus/app.go +++ /dev/null @@ -1,99 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "math/rand" - "os" - "time" -) - -var ( - version string = "v0.6.7" - dump bool - random bool - notify bool - print bool - - err error - body string - file string - reqInfo map[string]string - - apodDate string -) - -func app() { - // Early Check: If command was not passed then print usage and - // exit. Later command & service both are checked, this check - // is for version command. If not checked then running cetus - // without any args will fail because os.Args[1] will panic - // the program & produce runtime error. - if len(os.Args) == 1 { - printUsage() - os.Exit(0) - } - - parseArgs() -} - -// parseArgs will be parsing the arguments, it will verify if they are -// correct. Flag values are also set by parseArgs. -func parseArgs() { - // Running just `cetus` would've paniced the program if length - // of os.Args was not checked beforehand because there would - // be no os.Args[1]. - switch os.Args[1] { - case "version", "-version", "--version", "-v": - fmt.Printf("Cetus %s\n", version) - os.Exit(0) - - case "help", "-help", "--help", "-h": - // If help was passed then the program shouldn't exit - // with non-zero error code. - printUsage() - os.Exit(0) - - case "set", "fetch": - // If command & service was not passed then print - // usage and exit. - if len(os.Args) < 3 { - printUsage() - os.Exit(1) - } - - default: - fmt.Printf("Invalid command: %q\n", os.Args[1]) - printUsage() - os.Exit(1) - } - - rand.Seed(time.Now().Unix()) - - // If the program has reached this far then that means a valid - // command was passed & now we should check if a valid service - // was passed and parse the flags. - cetus := flag.NewFlagSet("cetus", flag.ExitOnError) - - // We first declare common flags then service specific flags. - cetus.BoolVar(&dump, "dump", false, "Dump the response") - cetus.BoolVar(¬ify, "notify", false, "Send a desktop notification with info") - cetus.BoolVar(&print, "print", false, "Print information") - cetus.BoolVar(&random, "random", false, "Choose a random image") - - switch os.Args[2] { - case "apod", "nasa": - defDate := time.Now().UTC().Format("2006-01-02") - cetus.StringVar(&apodDate, "date", defDate, "Date of NASA APOD to retrieve") - cetus.Parse(os.Args[3:]) - - execAPOD() - case "bpod", "bing": - cetus.Parse(os.Args[3:]) - execBPOD() - default: - fmt.Printf("Invalid service: %q\n", os.Args[2]) - printUsage() - os.Exit(1) - } -} diff --git a/cmd/cetus/bpod.go b/cmd/cetus/bpod.go deleted file mode 100644 index 7aa0a1b..0000000 --- a/cmd/cetus/bpod.go +++ /dev/null @@ -1,140 +0,0 @@ -package main - -import ( - "fmt" - "io/ioutil" - "log" - "os" - "time" - - "tildegit.org/andinus/cetus/background" - "tildegit.org/andinus/cetus/bpod" - "tildegit.org/andinus/cetus/cache" - "tildegit.org/andinus/cetus/notification" -) - -func execBPOD() { - bpodApi := getEnv("BPOD_API", "https://www.bing.com/HPImageArchive.aspx") - - // reqInfo holds all the parameters that needs to be sent with - // the request. GetJson() will pack apiKey & date in params - // map before sending it to another function. Adding params - // here will not change the behaviour of the function, changes - // have to be made in GetJson() too. - reqInfo = make(map[string]string) - reqInfo["api"] = bpodApi - - if random { - reqInfo["random"] = "true" - } - - cacheDir := fmt.Sprintf("%s/%s", cache.GetDir(), "bpod") - os.MkdirAll(cacheDir, os.ModePerm) - - body, err = bpod.GetJson(reqInfo) - if err != nil { - err = fmt.Errorf("%s\n%s", - "bpod.go: failed to get json response from api", - err.Error()) - log.Fatal(err) - } - - if dump { - fmt.Println(body) - } - - res, err := bpod.UnmarshalJson(body) - if err != nil { - log.Fatal(err) - } - - // Correct format - res.URL = fmt.Sprintf("%s%s", "https://www.bing.com", res.URL) - dt, err := time.Parse("20060102", res.StartDate) - if err != nil { - log.Fatal(err) - } - res.StartDate = dt.Format("2006-01-02") - - // Save response in cache after marshalling it again, we do - // this instead of saving the response so as to not break the - // format in which cache is saved. If random flag was passed - // then the response will contain all 7 values so we have to - // marshal it but why not save non-random directly? Because - // that means the format in which both are saved will be - // different. One will be the raw response whereas other will - // be marshalled response. We're currently not using this body - // cache but this is just to save information. - file := fmt.Sprintf("%s/%s.json", cacheDir, res.StartDate) - body, err = bpod.MarshalJson(res) - if err != nil { - // We should warn the user if this returns an error - // but the program shouldn't exit. - log.Println("bpod.go: failed to marshal res to body, not saving cache") - } else { - err = ioutil.WriteFile(file, []byte(body), 0644) - // Not being able to write to the cache file is a - // small error and the program shouldn't exit but - // should continue after printing the log so that the - // user can investigate it later. - if err != nil { - err = fmt.Errorf("%s%s\n%s", - "bpod.go: failed to write body to file: ", file, - err.Error()) - log.Println(err) - } - } - - // Send a desktop notification if notify flag was passed. - if notify { - n := notification.Notif{} - n.Title = res.Title - n.Message = fmt.Sprintf("%s\n\n%s", - res.StartDate, - res.Copyright) - - err = n.Notify() - if err != nil { - log.Println(err) - } - } - - if print { - fmt.Printf("Title: %s\n\n", res.Title) - fmt.Printf("Copyright: %s\n", res.Copyright) - fmt.Printf("Copyright Link: %s\n", res.CopyrightLink) - fmt.Printf("Date: %s\n\n", res.StartDate) - fmt.Printf("URL: %s\n", res.URL) - } - - // Proceed only if the command was set because if it was fetch - // then it's already finished & should exit now. - if os.Args[1] == "fetch" { - os.Exit(0) - } - - // Try to set background only if the media type is an image. - // First it downloads the image to the cache directory and - // then tries to set it with feh. If the download fails then - // it exits with a non-zero exit code. - imgFile := fmt.Sprintf("%s/%s", cacheDir, res.Title) - - // Check if the file is available locally, if it is then don't - // download it again and set it from disk - if _, err := os.Stat(imgFile); os.IsNotExist(err) { - err = background.Download(imgFile, res.URL) - if err != nil { - log.Fatal(err) - } - - } else { - if err != nil { - log.Fatal(err) - } - } - - err = background.SetFromFile(imgFile) - if err != nil { - log.Fatal(err) - } -} diff --git a/cmd/cetus/env.go b/cmd/cetus/env.go deleted file mode 100644 index 9288c35..0000000 --- a/cmd/cetus/env.go +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import "os" - -// getEnv will check if the the key exists, if it does then it'll -// return the value otherwise it will return fallback string. -func getEnv(key, fallback string) string { - // We use os.LookupEnv instead of using os.GetEnv and checking - // if the length equals 0 because environment variable can be - // set and be of length 0. User could've set key="" which - // means the variable was set but the length is 0. There is no - // reason why user would want to do this over here though. - value, exists := os.LookupEnv(key) - if !exists { - value = fallback - } - return value -} diff --git a/cmd/cetus/main.go b/cmd/cetus/main.go deleted file mode 100644 index b8098be..0000000 --- a/cmd/cetus/main.go +++ /dev/null @@ -1,47 +0,0 @@ -package main - -import ( - "log" - - "tildegit.org/andinus/cetus/cache" - "tildegit.org/andinus/lynx" -) - -func main() { - unveil() - app() -} - -func unveil() { - paths := make(map[string]string) - - paths[cache.Dir()] = "rwc" - paths["/dev/null"] = "rw" // required by feh - paths["/etc/resolv.conf"] = "r" - - // ktrace output - paths["/usr/libexec/ld.so"] = "r" - paths["/var/run/ld.so.hints"] = "r" - paths["/usr/lib"] = "r" - paths["/dev/urandom"] = "r" - paths["/etc/hosts"] = "r" - paths["/etc/ssl"] = "r" - - err := lynx.UnveilPaths(paths) - if err != nil { - log.Fatal(err) - } - - commands := []string{"feh", "gsettings", "pcmanfm", "notify-send"} - - err = lynx.UnveilCommands(commands) - if err != nil { - log.Fatal(err) - } - - // Block further unveil calls - err = lynx.UnveilBlock() - if err != nil { - log.Fatal(err) - } -} diff --git a/cmd/cetus/usage.go b/cmd/cetus/usage.go deleted file mode 100644 index e9e2f71..0000000 --- a/cmd/cetus/usage.go +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import "fmt" - -func printUsage() { - fmt.Println("Usage: cetus []") - fmt.Println("\nCommands: ") - fmt.Println(" set Set the background") - fmt.Println(" fetch Fetch the response only") - fmt.Println(" help Print help") - fmt.Println(" version Print Cetus version") - fmt.Println("\nServices: ") - fmt.Println(" apod NASA Astronomy Picture of the Day") - fmt.Println(" bpod Bing Photo of the Day") -} diff --git a/env.go b/env.go new file mode 100644 index 0000000..9288c35 --- /dev/null +++ b/env.go @@ -0,0 +1,18 @@ +package main + +import "os" + +// getEnv will check if the the key exists, if it does then it'll +// return the value otherwise it will return fallback string. +func getEnv(key, fallback string) string { + // We use os.LookupEnv instead of using os.GetEnv and checking + // if the length equals 0 because environment variable can be + // set and be of length 0. User could've set key="" which + // means the variable was set but the length is 0. There is no + // reason why user would want to do this over here though. + value, exists := os.LookupEnv(key) + if !exists { + value = fallback + } + return value +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..dfe208c --- /dev/null +++ b/main.go @@ -0,0 +1,78 @@ +package main + +import ( + "log" + "os" + + "tildegit.org/andinus/cetus/cache" + "tildegit.org/andinus/lynx" +) + +var ( + version string = "v0.6.7" + dump bool + random bool + notify bool + print bool + + err error + body string + file string + reqInfo map[string]string + + apodDate string +) + +func main() { + initCetus() + + // Early Check: If command was not passed then print usage and + // exit. Later command & service both are checked, this check + // is for version command. If not checked then running cetus + // without any args will fail because os.Args[1] will panic + // the program & produce runtime error. + if len(os.Args) == 1 { + printUsage() + os.Exit(0) + } + + parseArgs() +} + +func initCetus() { + unveil() +} + +func unveil() { + paths := make(map[string]string) + + paths[cache.Dir()] = "rwc" + paths["/dev/null"] = "rw" // required by feh + paths["/etc/resolv.conf"] = "r" + + // ktrace output + paths["/usr/libexec/ld.so"] = "r" + paths["/var/run/ld.so.hints"] = "r" + paths["/usr/lib"] = "r" + paths["/dev/urandom"] = "r" + paths["/etc/hosts"] = "r" + paths["/etc/ssl"] = "r" + + err := lynx.UnveilPaths(paths) + if err != nil { + log.Fatal(err) + } + + commands := []string{"feh", "gsettings", "pcmanfm", "notify-send"} + + err = lynx.UnveilCommands(commands) + if err != nil { + log.Fatal(err) + } + + // Block further unveil calls + err = lynx.UnveilBlock() + if err != nil { + log.Fatal(err) + } +} diff --git a/parseargs.go b/parseargs.go new file mode 100644 index 0000000..d47d30d --- /dev/null +++ b/parseargs.go @@ -0,0 +1,70 @@ +package main + +import ( + "flag" + "fmt" + "math/rand" + "os" + "time" +) + +// parseArgs will be parsing the arguments, it will verify if they are +// correct. Flag values are also set by parseArgs. +func parseArgs() { + // Running just `cetus` would've paniced the program if length + // of os.Args was not checked beforehand because there would + // be no os.Args[1]. + switch os.Args[1] { + case "version", "-version", "--version", "-v": + fmt.Printf("Cetus %s\n", version) + os.Exit(0) + + case "help", "-help", "--help", "-h": + // If help was passed then the program shouldn't exit + // with non-zero error code. + printUsage() + os.Exit(0) + + case "set", "fetch": + // If command & service was not passed then print + // usage and exit. + if len(os.Args) < 3 { + printUsage() + os.Exit(1) + } + + default: + fmt.Printf("Invalid command: %q\n", os.Args[1]) + printUsage() + os.Exit(1) + } + + rand.Seed(time.Now().Unix()) + + // If the program has reached this far then that means a valid + // command was passed & now we should check if a valid service + // was passed and parse the flags. + cetus := flag.NewFlagSet("cetus", flag.ExitOnError) + + // We first declare common flags then service specific flags. + cetus.BoolVar(&dump, "dump", false, "Dump the response") + cetus.BoolVar(¬ify, "notify", false, "Send a desktop notification with info") + cetus.BoolVar(&print, "print", false, "Print information") + cetus.BoolVar(&random, "random", false, "Choose a random image") + + switch os.Args[2] { + case "apod", "nasa": + defDate := time.Now().UTC().Format("2006-01-02") + cetus.StringVar(&apodDate, "date", defDate, "Date of NASA APOD to retrieve") + cetus.Parse(os.Args[3:]) + + execAPOD() + case "bpod", "bing": + cetus.Parse(os.Args[3:]) + execBPOD() + default: + fmt.Printf("Invalid service: %q\n", os.Args[2]) + printUsage() + os.Exit(1) + } +} diff --git a/usage.go b/usage.go new file mode 100644 index 0000000..e9e2f71 --- /dev/null +++ b/usage.go @@ -0,0 +1,15 @@ +package main + +import "fmt" + +func printUsage() { + fmt.Println("Usage: cetus []") + fmt.Println("\nCommands: ") + fmt.Println(" set Set the background") + fmt.Println(" fetch Fetch the response only") + fmt.Println(" help Print help") + fmt.Println(" version Print Cetus version") + fmt.Println("\nServices: ") + fmt.Println(" apod NASA Astronomy Picture of the Day") + fmt.Println(" bpod Bing Photo of the Day") +} -- cgit 1.4.1-2-gfad0