From 29a7e1617d113d00254520fbd7fed8e18eeef72d Mon Sep 17 00:00:00 2001 From: Spenser Black Date: Tue, 13 Apr 2021 09:02:15 -0400 Subject: [PATCH 01/11] Use init function to add commands --- cmd/commands.go | 2 +- main.go | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/cmd/commands.go b/cmd/commands.go index 6b63537..af6764c 100644 --- a/cmd/commands.go +++ b/cmd/commands.go @@ -21,6 +21,6 @@ var Search = &cobra.Command{ }, } -func AddCommands() { +func init() { RootCmd.AddCommand(Search) } diff --git a/main.go b/main.go index c5d40c7..e2ea5b2 100644 --- a/main.go +++ b/main.go @@ -8,8 +8,6 @@ import ( ) func main() { - cmd.AddCommands() - if err := cmd.RootCmd.Execute(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) From e7890ddfdc53e9575ee20cf009ea72aba5585521 Mon Sep 17 00:00:00 2001 From: Spenser Black Date: Mon, 19 Apr 2021 12:58:31 -0400 Subject: [PATCH 02/11] Set const value for config dir path In anticipation of other config values being used. For #5 --- helpers/helpers.go | 3 +++ helpers/token.go | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 helpers/helpers.go diff --git a/helpers/helpers.go b/helpers/helpers.go new file mode 100644 index 0000000..040c425 --- /dev/null +++ b/helpers/helpers.go @@ -0,0 +1,3 @@ +package helpers + +const configPath = "/.config/octotui" diff --git a/helpers/token.go b/helpers/token.go index 97c0089..e04e5d2 100644 --- a/helpers/token.go +++ b/helpers/token.go @@ -9,7 +9,7 @@ import ( ) const ( - tokenPath = "/.config/octotui/token" + tokenPath = configPath + "/token" ) func LoadToken() string { From 2e979fba2c2fe3409cb0bed6d6b09a208c1ea4d2 Mon Sep 17 00:00:00 2001 From: Spenser Black Date: Mon, 19 Apr 2021 14:02:14 -0400 Subject: [PATCH 03/11] Create shared helper for opening config files In anticipation of other config options being added. For #5 --- helpers/helpers.go | 53 +++++++++++++++++++++++++++++++++++++++++++++- helpers/token.go | 39 +++++++--------------------------- 2 files changed, 60 insertions(+), 32 deletions(-) diff --git a/helpers/helpers.go b/helpers/helpers.go index 040c425..30d2836 100644 --- a/helpers/helpers.go +++ b/helpers/helpers.go @@ -1,3 +1,54 @@ package helpers -const configPath = "/.config/octotui" +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "path" + "strings" +) + +var configPath = path.Join(".config", "octotui") + +var errCreatedConfigFile error = errors.New("File created") + +func loadConfigFile(filename string) (contents string, createdPath string, err error) { + home, err := os.UserHomeDir() + + if err != nil { + err = fmt.Errorf("Unable to get home directory: %w", err) + return + } + + fullConfigPath := path.Join(home, configPath) + fullFilename := path.Join(fullConfigPath, filename) + + if _, innerErr := os.Stat(fullFilename); innerErr != nil { + if os.IsNotExist(innerErr) { + innerErr := os.Mkdir(fullConfigPath, 0755) + if innerErr != nil { + err = fmt.Errorf("Unable to create octotui folder in %v", fullConfigPath) + return + } + + blackListFile, innerErr := os.OpenFile(fullFilename, os.O_RDONLY|os.O_CREATE, 0644) + if innerErr != nil { + err = fmt.Errorf("Unable to create file %v: %w", fullFilename, innerErr) + return + } + blackListFile.Close() + + createdPath = fullFilename + err = errCreatedConfigFile + return + } else { + err = innerErr + return + } + } + + fileContents, err := ioutil.ReadFile(fullFilename) + contents = strings.TrimSpace(string(fileContents)) + return +} diff --git a/helpers/token.go b/helpers/token.go index e04e5d2..120dcea 100644 --- a/helpers/token.go +++ b/helpers/token.go @@ -2,44 +2,21 @@ package helpers import ( "fmt" - "io/ioutil" "log" - "os" - "strings" ) const ( - tokenPath = configPath + "/token" + tokenFilename = "token" ) func LoadToken() string { - home, err := os.UserHomeDir() - if err != nil { - log.Fatal(err) - } - - if _, err := os.Stat(home + tokenPath); err != nil { - if os.IsNotExist(err) { - err := os.Mkdir(home+"/.config/octotui", 0755) - if err != nil { - log.Fatal("Unable to create octotui folder in " + home + "/.config") - } - - blackListFile, err := os.OpenFile(home+tokenPath, os.O_RDONLY|os.O_CREATE, 0644) - if err != nil { - log.Fatal("Unable to create token file in " + home + tokenPath) - } - blackListFile.Close() + token, filepath, err := loadConfigFile(tokenFilename) - fmt.Println("Created token file in: " + home + tokenPath) - fmt.Println("Put your github token in this file") - } + if err == errCreatedConfigFile { + fmt.Printf("Created token file in: %v\n", filepath) + fmt.Println("Put your github token in this file") + } else if err != nil { + log.Fatalf("Unable to load/create token file: %v", err) } - - token, err := ioutil.ReadFile(home + tokenPath) - if err != nil { - log.Fatal("Can't read token file in: " + home + tokenPath) - } - - return strings.TrimSpace(string(token)) + return token } From fd544997f11d3e594af5f8b4022c2809d593c207 Mon Sep 17 00:00:00 2001 From: Spenser Black Date: Mon, 19 Apr 2021 14:16:07 -0400 Subject: [PATCH 04/11] Add helper for getting default owner --- cmd/root.go | 7 +++++++ helpers/default_owner.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 helpers/default_owner.go diff --git a/cmd/root.go b/cmd/root.go index e253510..208afea 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,11 +1,18 @@ package cmd import ( + "fmt" + "github.com/spf13/cobra" + + h "github.com/irevenko/octotui/helpers" ) var RootCmd = &cobra.Command{ Use: "octotui", Short: "GitHub stats in your terminal", Long: `Complete documentation is available at https://github.com/irevenko/octotui`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println(h.LoadOwner()) + }, } diff --git a/helpers/default_owner.go b/helpers/default_owner.go new file mode 100644 index 0000000..25f5487 --- /dev/null +++ b/helpers/default_owner.go @@ -0,0 +1,32 @@ +package helpers + +import ( + "fmt" + "log" +) + +const ( + ownerFilename = "default_owner" +) + +// OwnerType is the type of owner. Either "user" or "org". +type OwnerType string + +const ( + org OwnerType = "org" + user OwnerType = "user" +) + +// LoadOwner loads the config file for the default owner. +func LoadOwner() string { + owner, filepath, err := loadConfigFile(ownerFilename) + + if err == errCreatedConfigFile { + fmt.Printf("Created owner file in: %v\n", filepath) + fmt.Println("Put your owner in this file in the format \"name:type\"") + fmt.Printf("Where type is either %q or %q\n", org, user) + } else if err != nil { + log.Fatalf("Unable to load/create owner file: %v", err) + } + return owner +} From bdefb7e2950711a8dc712a1d17d2e6bfcc013277 Mon Sep 17 00:00:00 2001 From: Spenser Black Date: Mon, 19 Apr 2021 14:19:45 -0400 Subject: [PATCH 05/11] Prevent error out when directory already exists --- helpers/helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers/helpers.go b/helpers/helpers.go index 30d2836..9a2ef26 100644 --- a/helpers/helpers.go +++ b/helpers/helpers.go @@ -27,7 +27,7 @@ func loadConfigFile(filename string) (contents string, createdPath string, err e if _, innerErr := os.Stat(fullFilename); innerErr != nil { if os.IsNotExist(innerErr) { innerErr := os.Mkdir(fullConfigPath, 0755) - if innerErr != nil { + if innerErr != nil && !os.IsExist(innerErr) { err = fmt.Errorf("Unable to create octotui folder in %v", fullConfigPath) return } From 1471d440241626ce02d270eef3dd1e34f78ed0fb Mon Sep 17 00:00:00 2001 From: Spenser Black Date: Mon, 19 Apr 2021 14:20:02 -0400 Subject: [PATCH 06/11] Remove unnecessary else block --- helpers/helpers.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/helpers/helpers.go b/helpers/helpers.go index 9a2ef26..386c591 100644 --- a/helpers/helpers.go +++ b/helpers/helpers.go @@ -42,10 +42,9 @@ func loadConfigFile(filename string) (contents string, createdPath string, err e createdPath = fullFilename err = errCreatedConfigFile return - } else { - err = innerErr - return } + err = innerErr + return } fileContents, err := ioutil.ReadFile(fullFilename) From 653159f03558d8dc12151bcee40cbcfaa8c8689a Mon Sep 17 00:00:00 2001 From: Spenser Black Date: Mon, 19 Apr 2021 14:23:44 -0400 Subject: [PATCH 07/11] Fail when default owner file is empty --- cmd/root.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 208afea..fd67dc4 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,7 +1,7 @@ package cmd import ( - "fmt" + "log" "github.com/spf13/cobra" @@ -13,6 +13,10 @@ var RootCmd = &cobra.Command{ Short: "GitHub stats in your terminal", Long: `Complete documentation is available at https://github.com/irevenko/octotui`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(h.LoadOwner()) + owner := h.LoadOwner() + + if owner == "" { + log.Fatalf("Owner is empty. Either add data or use the search subcommand.") + } }, } From 5a21410808c4f7f820c6a67a855eb87a81b026ed Mon Sep 17 00:00:00 2001 From: Spenser Black Date: Mon, 19 Apr 2021 14:27:48 -0400 Subject: [PATCH 08/11] Export owner types --- helpers/default_owner.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/helpers/default_owner.go b/helpers/default_owner.go index 25f5487..ad151bc 100644 --- a/helpers/default_owner.go +++ b/helpers/default_owner.go @@ -13,8 +13,10 @@ const ( type OwnerType string const ( - org OwnerType = "org" - user OwnerType = "user" + // Org signifies that the owner type is a GitHub organization. + Org OwnerType = "org" + // User signifies that the owner type is a GitHub user. + User OwnerType = "user" ) // LoadOwner loads the config file for the default owner. @@ -24,7 +26,7 @@ func LoadOwner() string { if err == errCreatedConfigFile { fmt.Printf("Created owner file in: %v\n", filepath) fmt.Println("Put your owner in this file in the format \"name:type\"") - fmt.Printf("Where type is either %q or %q\n", org, user) + fmt.Printf("Where type is either %q or %q\n", Org, User) } else if err != nil { log.Fatalf("Unable to load/create owner file: %v", err) } From 2623cdfe78e04fcb000242e7ae8b0908a6c4e08e Mon Sep 17 00:00:00 2001 From: Spenser Black Date: Mon, 19 Apr 2021 14:28:38 -0400 Subject: [PATCH 09/11] Fatal log when owner doesn't match expected format --- cmd/root.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cmd/root.go b/cmd/root.go index fd67dc4..3f5f322 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -2,6 +2,7 @@ package cmd import ( "log" + "strings" "github.com/spf13/cobra" @@ -18,5 +19,11 @@ var RootCmd = &cobra.Command{ if owner == "" { log.Fatalf("Owner is empty. Either add data or use the search subcommand.") } + + nameAndType := strings.Split(owner, ":") + + if len(nameAndType) != 2 { + log.Fatalf("Default owner must be in format \"name:type\" where type is either %q or %q", h.Org, h.User) + } }, } From 626555ff543752c22cbf961ed1fd4fffc015154e Mon Sep 17 00:00:00 2001 From: Spenser Black Date: Mon, 19 Apr 2021 14:44:45 -0400 Subject: [PATCH 10/11] Export stat rendering functions --- tui/render_stats.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tui/render_stats.go b/tui/render_stats.go index 0258113..8d325c0 100644 --- a/tui/render_stats.go +++ b/tui/render_stats.go @@ -27,15 +27,15 @@ func RenderStats(username string, accType string, s *spinner.Spinner) { defer ui.Close() if accType == "(user)" { - renderUser(username, s) + RenderUser(username, s) } if accType == "(organization)" { - renderOrganization(username, s) + RenderOrganization(username, s) } } -func renderUser(username string, s *spinner.Spinner) { +func RenderUser(username string, s *spinner.Spinner) { user, err := g.UserDetails(qlClient, username) if err != nil { log.Fatalf("Couldn't get user details for: %v: %v", username, err) @@ -80,7 +80,7 @@ func renderUser(username string, s *spinner.Spinner) { } } -func renderOrganization(username string, s *spinner.Spinner) { +func RenderOrganization(username string, s *spinner.Spinner) { org, err := g.OrganizationDetails(qlClient, username) if err != nil { log.Fatalf("Couldn't get org details for: %v: %v", username, err) From 932a7e11fc9b9605f7c9585828378cab5b85377a Mon Sep 17 00:00:00 2001 From: Spenser Black Date: Mon, 19 Apr 2021 15:22:59 -0400 Subject: [PATCH 11/11] Render default user from config file --- cmd/root.go | 25 +++++++++++++++++++++++++ helpers/default_owner.go | 10 ++++++++++ 2 files changed, 35 insertions(+) diff --git a/cmd/root.go b/cmd/root.go index 3f5f322..6ac89db 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -3,10 +3,14 @@ package cmd import ( "log" "strings" + "time" + "github.com/briandowns/spinner" + ui "github.com/gizak/termui/v3" "github.com/spf13/cobra" h "github.com/irevenko/octotui/helpers" + tui "github.com/irevenko/octotui/tui" ) var RootCmd = &cobra.Command{ @@ -25,5 +29,26 @@ var RootCmd = &cobra.Command{ if len(nameAndType) != 2 { log.Fatalf("Default owner must be in format \"name:type\" where type is either %q or %q", h.Org, h.User) } + + name := nameAndType[0] + ownerType := h.OwnerType(nameAndType[1]) + + s := spinner.New(spinner.CharSets[30], 100*time.Millisecond) + s.Prefix = "fetching github data " + s.FinalMSG = "done" + if err := ui.Init(); err != nil { + log.Fatalf("failed to initialize termui: %v", err) + } + defer ui.Close() + switch { + case ownerType.IsOrg(): + s.Start() + tui.RenderOrganization(name, s) + case ownerType.IsUser(): + s.Start() + tui.RenderUser(name, s) + default: + log.Fatalf("Expected either %q or %q, got %q in default_owner config file", h.Org, h.User, ownerType) + } }, } diff --git a/helpers/default_owner.go b/helpers/default_owner.go index ad151bc..befa6d8 100644 --- a/helpers/default_owner.go +++ b/helpers/default_owner.go @@ -32,3 +32,13 @@ func LoadOwner() string { } return owner } + +// IsOrg checks if owner is a GitHub organization. +func (owner OwnerType) IsOrg() bool { + return owner == Org +} + +// IsUser checks if owner is a GitHub user. +func (owner OwnerType) IsUser() bool { + return owner == User +}