From 826d262d42ffb302e1c89be9b98630da59892520 Mon Sep 17 00:00:00 2001 From: Elia el Lazkani Date: Sat, 29 Feb 2020 12:17:14 +0100 Subject: [PATCH] [Breaking Change] Another overhaul of the code This was made possible by the previous overhaul and cleanup * Code now uses strings.Builder instead of slices * Fixed --add-frame flag to only work for PNG * Moved --format to only work as ?format= * Added --free-style to replace previous --format functionality * Added explicit --download flag to download instead of print * Added explicit --file-name flag to specify a file name to use * Renamed --extra-information to --export-mode * Updated the --export-mode with more useful information --- main.go | 173 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 118 insertions(+), 55 deletions(-) diff --git a/main.go b/main.go index 1c4b0b7..ea7217c 100644 --- a/main.go +++ b/main.go @@ -79,12 +79,17 @@ func (w weather) print(resp *http.Response) { // `weather` method to download the weather func (w weather) download(resp *http.Response) { - splitURL := strings.Split(w.url, "/") - filename := splitURL[len(splitURL)-1] + var fName string + if *fileName != "" { + fName = *fileName + } else { + splitURL := strings.Split(w.url, "/") + fName = splitURL[len(splitURL)-1] + } - f, err := os.Create(filename) + f, err := os.Create(fName) if err != nil { - return + log.Fatal(err) } defer f.Close() @@ -104,76 +109,116 @@ func getWheather(url string, headers map[string]string, download bool) { // This will figure out if we need to download the PNG image // as well. func generateParamFormat() (string, bool, error) { - var params []string - var prefix []string - var download bool + var params strings.Builder + var prefix = "?" + var downloadMode = *download - prefix = append(prefix, "?") - - // If --format is specified, let's not bother and simply return it - if *format != "" { - return *format, false, nil + // If --free-syle is specified, let's not bother and simply return it + if *freeStyle != "" { + return *freeStyle, downloadMode, nil } + // If --format is specified, let's return the format the user wants + if *format != "" { + var str strings.Builder + str.WriteString("?format=\"") + str.WriteString(*format) + str.WriteString("\"") + return str.String(), downloadMode, nil + } // If --one-liner is specified, we know the format is set so let's return it if *oneLiner { - return "?format=3", false, nil + return "?format=3", downloadMode, nil } for i := range switches { if *switches[i] { - params = append(params, switchesFlags[i]) + params.WriteString(switchesFlags[i]) } } if *png { - prefix[0] = "_" + prefix = "_" - if *transparency >= 0 && *transparency <= 100 { - params = append(params, strings.Join([]string{"_transparency=", string(*transparency)}, "")) + if *addFrame { + params.WriteString(switchesFlags[12]) } - params = append(params, ".png") - download = true + if *transparency >= 0 && *transparency <= 255 { + params.WriteString("_transparency=") + params.WriteString(string(*transparency)) + } + + params.WriteString(".png") + downloadMode = true } - params = append(prefix, strings.Join(params, "")) + var affix strings.Builder + affix.WriteString(prefix) + affix.WriteString(params.String()) - return strings.Join(params, ""), download, nil + return affix.String(), downloadMode, nil } // Defining the command-line interface var ( app = kingpin.New("go-cmw", "A small terminal wrapper around the wttr.in weather endpoint.") + location = app.Flag("location", "Specify explicite location").Short('L').OverrideDefaultFromEnvar("GO_CMW_LOCATION").String() + language = app.Flag("language", "Specify explicite language").Short('l').OverrideDefaultFromEnvar("GO_CMW_LANGUAGE").String() + v2 = app.Flag("v2", "Display Data-Rich output").Default("false").Bool() switches = [13]*bool{ app.Flag("metric", "Display weather in metric").Short('m').Default("false").Bool(), app.Flag("uscs", "Display weather in imperial").Short('u').Default("false").Bool(), app.Flag("meter-second", "Display wind in m/s").Short('M').Default("false").Bool(), - app.Flag("zero", "Show the weather now").Short('z').Default("false").Bool(), - app.Flag("one", "Show the weather for one day").Short('o').Default("false").Bool(), - app.Flag("two", "Show the weather for two days").Short('w').Default("false").Bool(), - app.Flag("ignore-user-agent", "Request ignoring the user agent").Short('A').Default("false").Bool(), - app.Flag("follow-link", "Follow link redirect").Short('F').Default("true").Bool(), - app.Flag("narrow", "Display weather in narrow view").Short('n').Default("false").Bool(), - app.Flag("quiet", "Add the quiet flag").Short('q').Default("false").Bool(), - app.Flag("super-quiet", "Add the super quiet flag").Short('Q').Default("false").Bool(), - app.Flag("no-colors", "Disable displaying colors (always enabled on windows").Short('N').Default("false").Bool(), - app.Flag("add-frame", "Add a frame to the output").Short('p').Default("false").Bool()} - png = app.Flag("png", "Download a weather PNG image").Short('P').Default("false").Bool() - v2 = app.Flag("v2", "Use the v2 endpoint").Default("false").Bool() - transparency = app.Flag("transparency", "Set transparency level (0-100) (PNG only)").Short('t').Default("0").Int() - format = app.Flag("format", "Query format (overrides everything else)").Short('f').OverrideDefaultFromEnvar("GO_CMW_FORMAT").String() - location = app.Flag("location", "Specify explicite location").Short('L').OverrideDefaultFromEnvar("GO_CMW_LOCATION").String() - language = app.Flag("language", "Specify explicite language").Short('l').OverrideDefaultFromEnvar("GO_CMW_LANGUAGE").String() - oneLiner = app.Flag("one-liner", "One liner outpet (for the terminal multiplexer lovers out there)").Short('O').Default("false").Bool() - extraInformation = app.Flag("extra-information", "Print extra information").Default("false").Bool() + app.Flag("zero", "Display current weather").Short('z').Default("false").Bool(), + app.Flag("one", "Display current weather + 1 day").Short('o').Default("false").Bool(), + app.Flag("two", "Display current weather + 2 days").Short('w').Default("false").Bool(), + app.Flag("ignore-user-agent", "Ignore User-Agent and force ANSI output").Short('A').Default("false").Bool(), + app.Flag("follow-link", "Do not display the 'Follow' line").Short('F').Default("true").Bool(), + app.Flag("narrow", "Display narrow view (only day/night)").Short('n').Default("false").Bool(), + app.Flag("quiet", "Display quiet version (no weather report)").Short('q').Default("false").Bool(), + app.Flag("super-quiet", "Display super quiet version (no weather report and no city)").Short('Q').Default("false").Bool(), + app.Flag("no-colors", "Display no colors (always enabled on windows").Short('N').Default("false").Bool()} + + png = app.Flag("png", "Download a weather PNG image").Short('P').Default("false").Bool() + addFrame = app.Flag("add-frame", "Add a frame to the output (PNG only)").Short('p').Default("false").Bool() + transparency = app.Flag("transparency", "Set transparency level (0-255) (PNG only)").OverrideDefaultFromEnvar("GO_CMW_TRANSPARENCY").Short('t').Default("0").Int() + download = app.Flag("download", "Enables download mode").Short('d').Default("false").Bool() + fileName = app.Flag("file-name", "Name download file").OverrideDefaultFromEnvar("GO_CMW_FILE_NAME").Default("").String() + oneLiner = app.Flag("one-liner", "One liner outpet (for the terminal multiplexer lovers out there)").Short('O').Default("false").Bool() + format = app.Flag("format", "Specify a format query (e.g. \"%l:+%c+%t\") (--expert-mode)").OverrideDefaultFromEnvar("GO_CMW_FORMAT").String() + freeStyle = app.Flag("free-style", "Specify a free-style API call (--expert-mode)").OverrideDefaultFromEnvar("GO_CMW_FREE_STYLE").String() + expertMode = app.Flag("expert-mode", "Print expert mode information").Default("false").Bool() ) // Special help menu -func printExtraInformation() { +func printExpertMode() { eInfo := ` +Expert Mode +----------- + +All commands flagged with --expert-mode override +values/flags added by go-cmw. + +This gives the user full control over +the queries requested. + +Environment Variables +--------------------- + +go-cmw makes use of the following environment +variables: + +* GO_CMW_LOCATION for --location +* GO_CMW_LANGUAGE for --language +* GO_CMW_FORMAT for --format +* GO_CMW_FREE_STYLE for --free-style +* GO_CMW_FILE_NAME for --file-name +* GO_CMW_TRANSPARENCY for --transparency + Supported Location Types ------------------------ + City name: Paris Unicode name: Москва Airport code (3 letters): muc @@ -183,16 +228,33 @@ GPS coordinates: -78.46,106.79 Special Location ---------------- + Moon phase (add ,+US or ,+France for these cities): moon Moon phase for a date: moon@2016-10-25 +Format Flags (--format) +------------ + +c Weather condition +C Weather condition textual name +h Humidity +t Temperature +w Wind +l Location +m Moonphase +M Moonday +p precipitation (mm) +o Probability of Precipitation +P pressure (hPa) + Supported languages ------------------- -Supported: af da de el et fr fa hu id it nb nl - pl pt-br ro ru tr uk vi - ` +Supported: af be ca da de el et fr fa hu id it + nb nl pl pt-br ro ru tr th uk vi + zh-cn zh-tw +` println(eInfo) } @@ -206,8 +268,8 @@ func flagParser() { kingpin.MustParse(app.Parse(os.Args[1:])) - if *extraInformation { - printExtraInformation() + if *expertMode { + printExpertMode() os.Exit(0) } @@ -219,38 +281,39 @@ func flagParser() { } // Create a function to generate the url that we'll be calling shortly. -func generateURL(domain string, v2 bool, location string, lang string, affix string) ([]string, map[string]string) { - var link []string +func generateURL(domain string, v2 bool, location string, lang string, affix string) (string, map[string]string) { + var link strings.Builder var headers = make(map[string]string) - link = append(link, "https://") + link.WriteString("https://") if v2 { - link = append(link, "v2.") + link.WriteString("v2.") } - link = append(link, domain, "/") + link.WriteString(domain) + link.WriteString("/") if location != "" { - link = append(link, location) + link.WriteString(location) } if affix != "" { - link = append(link, affix) + link.WriteString(affix) } if lang != "" { headers["Accept-Language"] = lang } - return link, headers + return link.String(), headers } // This is the main function that glues everything together. func main() { var domain string = "wttr.in" flagParser() - affix, download, _ := generateParamFormat() + affix, downloadFile, _ := generateParamFormat() link, headers := generateURL(domain, *v2, *location, *language, affix) - getWheather(strings.Join(link, ""), headers, download) + getWheather(link, headers, downloadFile) }