From fcc88f04bbecf07769dacd649ba47c712390d5c0 Mon Sep 17 00:00:00 2001 From: Kyle Allan Date: Sat, 8 Mar 2014 14:19:40 -0800 Subject: [PATCH 01/11] rename me.go to trackerapi.go --- trackerapi/{me.go => trackerapi.go} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename trackerapi/{me.go => trackerapi.go} (99%) diff --git a/trackerapi/me.go b/trackerapi/trackerapi.go similarity index 99% rename from trackerapi/me.go rename to trackerapi/trackerapi.go index 1bdf108..0b7321e 100644 --- a/trackerapi/me.go +++ b/trackerapi/trackerapi.go @@ -6,7 +6,7 @@ import ( "io/ioutil" "net/http" "os" - u "os/user" + "os/user" "github.com/GoBootcamp/clirescue/cmdutil" "github.com/GoBootcamp/clirescue/user" From b37cc4581a1b0fe6f4ea79585f5cf069aed5ecd8 Mon Sep 17 00:00:00 2001 From: Kyle Allan Date: Sat, 8 Mar 2014 14:25:44 -0800 Subject: [PATCH 02/11] rename user to pivotaluser and do some nice godoc --- user/user.go => pivotaluser/pivotaluser.go | 16 +++++++++++----- trackerapi/trackerapi.go | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) rename user/user.go => pivotaluser/pivotaluser.go (62%) diff --git a/user/user.go b/pivotaluser/pivotaluser.go similarity index 62% rename from user/user.go rename to pivotaluser/pivotaluser.go index 58b6d63..8bd1d8b 100644 --- a/user/user.go +++ b/pivotaluser/pivotaluser.go @@ -1,9 +1,9 @@ -package user +// Copyright 2013 -func New() *User { - return new(User) -} +// Package pivotaluser represents a pivotal user +package pivotaluser +// User represents a Pivotal Labs user. type User struct { Username string Password string @@ -18,7 +18,13 @@ type User struct { } `json:"time_zone"` } -func (u *User) Login(name, pass string) { +// New returns a *User. +func New() *User { + return new(User) +} + +// SetLogin sets the username and password. +func (u *User) SetLogin(name, pass string) { u.Username = name u.Password = pass } diff --git a/trackerapi/trackerapi.go b/trackerapi/trackerapi.go index 0b7321e..0a318c2 100644 --- a/trackerapi/trackerapi.go +++ b/trackerapi/trackerapi.go @@ -9,7 +9,7 @@ import ( "os/user" "github.com/GoBootcamp/clirescue/cmdutil" - "github.com/GoBootcamp/clirescue/user" + "github.com/GoBootcamp/clirescue/pivotaluser" ) var ( From 41bdd5bd14e3bdf9ccf9405c7aca2d4f62d14836 Mon Sep 17 00:00:00 2001 From: Kyle Allan Date: Sat, 8 Mar 2014 14:27:32 -0800 Subject: [PATCH 03/11] fix references to user and u to pivotaluser and u there is no real reason to clobber a standard package if you need it --- trackerapi/trackerapi.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/trackerapi/trackerapi.go b/trackerapi/trackerapi.go index 0a318c2..3e4fa07 100644 --- a/trackerapi/trackerapi.go +++ b/trackerapi/trackerapi.go @@ -13,10 +13,10 @@ import ( ) var ( - URL string = "https://www.pivotaltracker.com/services/v5/me" - FileLocation string = homeDir() + "/.tracker" - currentUser *user.User = user.New() - Stdout *os.File = os.Stdout + URL string = "https://www.pivotaltracker.com/services/v5/me" + FileLocation string = homeDir() + "/.tracker" + currentUser *pivotaluser.User = pivotaluser.New() + Stdout *os.File = os.Stdout ) func Me() { @@ -55,12 +55,12 @@ func setCredentials() { fmt.Fprint(Stdout, "Password: ") var password = cmdutil.ReadLine() - currentUser.Login(username, password) + currentUser.SetLogin(username, password) cmdutil.Unsilence() } func homeDir() string { - usr, _ := u.Current() + usr, _ := user.Current() return usr.HomeDir } From d295044b69d983ad2312cbdd6a28f3dbd016c13a Mon Sep 17 00:00:00 2001 From: Kyle Allan Date: Sat, 8 Mar 2014 14:42:57 -0800 Subject: [PATCH 04/11] move struct to the top; move main code into init --- main.go | 17 ++++++++++++----- trackerapi/trackerapi.go | 29 +++++++++++++++-------------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/main.go b/main.go index 012a948..d0af4a4 100644 --- a/main.go +++ b/main.go @@ -7,21 +7,28 @@ import ( "github.com/codegangsta/cli" ) -func main() { - app := cli.NewApp() +var ( + app *cli.App +) + +func init() { + + app = cli.NewApp() app.Name = "clirescue" app.Usage = "CLI tool to talk to the Pivotal Tracker's API" app.Commands = []cli.Command{ { - Name: "me", - Usage: "prints out Tracker's representation of your account", + Name: "login", + Usage: "Logs into your pivotal account and caches your credentials.", Action: func(c *cli.Context) { - trackerapi.Me() + trackerapi.CacheCredentials() }, }, } +} +func main() { app.Run(os.Args) } diff --git a/trackerapi/trackerapi.go b/trackerapi/trackerapi.go index 3e4fa07..a271d70 100644 --- a/trackerapi/trackerapi.go +++ b/trackerapi/trackerapi.go @@ -19,7 +19,21 @@ var ( Stdout *os.File = os.Stdout ) -func Me() { +// MeResponse . +type MeResponse struct { + APIToken string `json:"api_token"` + Username string `json:"username"` + Name string `json:"name"` + Email string `json:"email"` + Initials string `json:"initials"` + Timezone struct { + Kind string `json:"kind"` + Offset string `json:"offset"` + OlsonName string `json:"olson_name"` + } `json:"time_zone"` +} + +func CacheCredentials() { setCredentials() parse(makeRequest()) ioutil.WriteFile(FileLocation, []byte(currentUser.APIToken), 0644) @@ -63,16 +77,3 @@ func homeDir() string { usr, _ := user.Current() return usr.HomeDir } - -type MeResponse struct { - APIToken string `json:"api_token"` - Username string `json:"username"` - Name string `json:"name"` - Email string `json:"email"` - Initials string `json:"initials"` - Timezone struct { - Kind string `json:"kind"` - Offset string `json:"offset"` - OlsonName string `json:"olson_name"` - } `json:"time_zone"` -} From 634a7d5620b9df49d3a0b87c8bb4f5bae91fa089 Mon Sep 17 00:00:00 2001 From: Kyle Allan Date: Sat, 8 Mar 2014 14:58:20 -0800 Subject: [PATCH 05/11] use fewer packages and rename some methods --- cmdutil/cmdutil.go | 44 ------------------- trackerapi/trackerapi.go | 23 +++++----- .../pivotaluser.go => trackerapi/user.go | 11 ++--- trackerapi/util.go | 44 +++++++++++++++++++ 4 files changed, 57 insertions(+), 65 deletions(-) delete mode 100644 cmdutil/cmdutil.go rename pivotaluser/pivotaluser.go => trackerapi/user.go (76%) create mode 100644 trackerapi/util.go diff --git a/cmdutil/cmdutil.go b/cmdutil/cmdutil.go deleted file mode 100644 index ffd8775..0000000 --- a/cmdutil/cmdutil.go +++ /dev/null @@ -1,44 +0,0 @@ -package cmdutil - -import ( - "bufio" - "fmt" - "os" - "os/exec" - "strings" -) - -var ( - InputFile *os.File = os.Stdin - inputBuffer *bufio.Reader -) - -func ReadLine() string { - buf := buffer() - line, err := buf.ReadString('\n') - if err != nil { - fmt.Println(err) - } - return strings.TrimSpace(string(line)) -} - -func Silence() { - runCommand(exec.Command("stty", "-echo")) -} - -func Unsilence() { - runCommand(exec.Command("stty", "echo")) -} - -func runCommand(command *exec.Cmd) { - command.Stdin = os.Stdin - command.Stdout = os.Stdout - command.Run() -} - -func buffer() *bufio.Reader { - if inputBuffer == nil { - inputBuffer = bufio.NewReader(InputFile) - } - return inputBuffer -} diff --git a/trackerapi/trackerapi.go b/trackerapi/trackerapi.go index a271d70..655449a 100644 --- a/trackerapi/trackerapi.go +++ b/trackerapi/trackerapi.go @@ -7,16 +7,13 @@ import ( "net/http" "os" "os/user" - - "github.com/GoBootcamp/clirescue/cmdutil" - "github.com/GoBootcamp/clirescue/pivotaluser" ) var ( - URL string = "https://www.pivotaltracker.com/services/v5/me" - FileLocation string = homeDir() + "/.tracker" - currentUser *pivotaluser.User = pivotaluser.New() - Stdout *os.File = os.Stdout + URL = "https://www.pivotaltracker.com/services/v5/me" + FileLocation = homeDir() + "/.tracker" + currentUser = new(pivotalUser) + Stdout = os.Stdout ) // MeResponse . @@ -35,11 +32,11 @@ type MeResponse struct { func CacheCredentials() { setCredentials() - parse(makeRequest()) + parse(makeMeRequest()) ioutil.WriteFile(FileLocation, []byte(currentUser.APIToken), 0644) } -func makeRequest() []byte { +func makeMeRequest() []byte { client := &http.Client{} req, err := http.NewRequest("GET", URL, nil) req.SetBasicAuth(currentUser.Username, currentUser.Password) @@ -64,13 +61,13 @@ func parse(body []byte) { func setCredentials() { fmt.Fprint(Stdout, "Username: ") - var username = cmdutil.ReadLine() - cmdutil.Silence() + var username = readLine() + silenceStty() fmt.Fprint(Stdout, "Password: ") - var password = cmdutil.ReadLine() + var password = readLine() currentUser.SetLogin(username, password) - cmdutil.Unsilence() + unsilenceStty() } func homeDir() string { diff --git a/pivotaluser/pivotaluser.go b/trackerapi/user.go similarity index 76% rename from pivotaluser/pivotaluser.go rename to trackerapi/user.go index 8bd1d8b..11690f3 100644 --- a/pivotaluser/pivotaluser.go +++ b/trackerapi/user.go @@ -1,10 +1,10 @@ // Copyright 2013 // Package pivotaluser represents a pivotal user -package pivotaluser +package trackerapi // User represents a Pivotal Labs user. -type User struct { +type pivotalUser struct { Username string Password string APIToken string @@ -18,13 +18,8 @@ type User struct { } `json:"time_zone"` } -// New returns a *User. -func New() *User { - return new(User) -} - // SetLogin sets the username and password. -func (u *User) SetLogin(name, pass string) { +func (u *pivotalUser) SetLogin(name, pass string) { u.Username = name u.Password = pass } diff --git a/trackerapi/util.go b/trackerapi/util.go new file mode 100644 index 0000000..a15344d --- /dev/null +++ b/trackerapi/util.go @@ -0,0 +1,44 @@ +package trackerapi + +import ( + "bufio" + "fmt" + "os" + "os/exec" + "strings" +) + +var ( + InputFile *os.File = os.Stdin + inputBuffer *bufio.Reader +) + +func readLine() string { + buf := buffer() + line, err := buf.ReadString('\n') + if err != nil { + fmt.Println(err) + } + return strings.TrimSpace(string(line)) +} + +func silence() { + runCommand(exec.Command("stty", "-echo")) +} + +func unsilence() { + runCommand(exec.Command("stty", "echo")) +} + +func runCommand(command *exec.Cmd) { + command.Stdin = os.Stdin + command.Stdout = os.Stdout + command.Run() +} + +func buffer() *bufio.Reader { + if inputBuffer == nil { + inputBuffer = bufio.NewReader(InputFile) + } + return inputBuffer +} From 06f9576bc5275c90d9fef4a9c0ab50d7f226f8da Mon Sep 17 00:00:00 2001 From: Kyle Allan Date: Sat, 8 Mar 2014 15:05:34 -0800 Subject: [PATCH 06/11] rename functions and remove 3rd party dependency --- main.go | 34 ++++++++++------------------------ trackerapi/util.go | 4 ++-- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/main.go b/main.go index d0af4a4..10f37fe 100644 --- a/main.go +++ b/main.go @@ -1,34 +1,20 @@ package main import ( + "log" "os" "github.com/GoBootcamp/clirescue/trackerapi" - "github.com/codegangsta/cli" ) -var ( - app *cli.App -) - -func init() { - - app = cli.NewApp() - - app.Name = "clirescue" - app.Usage = "CLI tool to talk to the Pivotal Tracker's API" - - app.Commands = []cli.Command{ - { - Name: "login", - Usage: "Logs into your pivotal account and caches your credentials.", - Action: func(c *cli.Context) { - trackerapi.CacheCredentials() - }, - }, - } -} - func main() { - app.Run(os.Args) + if len(os.Args) < 2 { + log.Fatal("Command required") + } + switch os.Args[1] { + case "login": + trackerapi.CacheCredentials() + default: + log.Fatal("Unknown Command: ", os.Args[1]) + } } diff --git a/trackerapi/util.go b/trackerapi/util.go index a15344d..66cee53 100644 --- a/trackerapi/util.go +++ b/trackerapi/util.go @@ -22,11 +22,11 @@ func readLine() string { return strings.TrimSpace(string(line)) } -func silence() { +func silenceStty() { runCommand(exec.Command("stty", "-echo")) } -func unsilence() { +func unsilenceStty() { runCommand(exec.Command("stty", "echo")) } From decae971c167e127385fdf29e986100ff0ab06d5 Mon Sep 17 00:00:00 2001 From: Kyle Allan Date: Sat, 8 Mar 2014 15:35:59 -0800 Subject: [PATCH 07/11] URL is capitalized and not a constant, anyone can change it --- trackerapi/trackerapi.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trackerapi/trackerapi.go b/trackerapi/trackerapi.go index 655449a..b2e3156 100644 --- a/trackerapi/trackerapi.go +++ b/trackerapi/trackerapi.go @@ -9,8 +9,9 @@ import ( "os/user" ) +const URL string = "https://www.pivotaltracker.com/services/v5/me" + var ( - URL = "https://www.pivotaltracker.com/services/v5/me" FileLocation = homeDir() + "/.tracker" currentUser = new(pivotalUser) Stdout = os.Stdout From 33c07d91a2cea17c2e6e0ac63e1148c8e4eeae15 Mon Sep 17 00:00:00 2001 From: Kyle Allan Date: Sat, 8 Mar 2014 15:49:28 -0800 Subject: [PATCH 08/11] major refactor of util, error passing, and defer unsilence --- main.go | 5 ++++- trackerapi/trackerapi.go | 27 +++++++++++++++++---------- trackerapi/util.go | 22 ++++------------------ 3 files changed, 25 insertions(+), 29 deletions(-) diff --git a/main.go b/main.go index 10f37fe..5a8e9d0 100644 --- a/main.go +++ b/main.go @@ -13,7 +13,10 @@ func main() { } switch os.Args[1] { case "login": - trackerapi.CacheCredentials() + err := trackerapi.CacheCredentials() + if err != nil { + panic(err) + } default: log.Fatal("Unknown Command: ", os.Args[1]) } diff --git a/trackerapi/trackerapi.go b/trackerapi/trackerapi.go index b2e3156..28949c3 100644 --- a/trackerapi/trackerapi.go +++ b/trackerapi/trackerapi.go @@ -31,16 +31,17 @@ type MeResponse struct { } `json:"time_zone"` } -func CacheCredentials() { - setCredentials() - parse(makeMeRequest()) +func CacheCredentials() error { + usr, pwd, err := getCredentials() + parse(makeMeRequest(usr, pwd)) ioutil.WriteFile(FileLocation, []byte(currentUser.APIToken), 0644) + return err } -func makeMeRequest() []byte { +func makeMeRequest(usr, pwd string) []byte { client := &http.Client{} req, err := http.NewRequest("GET", URL, nil) - req.SetBasicAuth(currentUser.Username, currentUser.Password) + req.SetBasicAuth(usr, pwd) resp, err := client.Do(req) body, err := ioutil.ReadAll(resp.Body) if err != nil { @@ -60,15 +61,21 @@ func parse(body []byte) { currentUser.APIToken = meResp.APIToken } -func setCredentials() { +func getCredentials() (usr, pwd string, err error) { fmt.Fprint(Stdout, "Username: ") - var username = readLine() + usr, err = readLine() + + if err != nil { + return + } + silenceStty() + defer unsilenceStty() + fmt.Fprint(Stdout, "Password: ") + pwd, err = readLine() - var password = readLine() - currentUser.SetLogin(username, password) - unsilenceStty() + return usr, pwd, err } func homeDir() string { diff --git a/trackerapi/util.go b/trackerapi/util.go index 66cee53..49f69f1 100644 --- a/trackerapi/util.go +++ b/trackerapi/util.go @@ -2,24 +2,17 @@ package trackerapi import ( "bufio" - "fmt" "os" "os/exec" "strings" ) -var ( - InputFile *os.File = os.Stdin - inputBuffer *bufio.Reader -) - -func readLine() string { - buf := buffer() - line, err := buf.ReadString('\n') +func readLine() (string, error) { + line, err := bufio.NewReader(os.Stdin).ReadString('\n') if err != nil { - fmt.Println(err) + return "", err } - return strings.TrimSpace(string(line)) + return strings.TrimSpace(string(line)), nil } func silenceStty() { @@ -35,10 +28,3 @@ func runCommand(command *exec.Cmd) { command.Stdout = os.Stdout command.Run() } - -func buffer() *bufio.Reader { - if inputBuffer == nil { - inputBuffer = bufio.NewReader(InputFile) - } - return inputBuffer -} From 2c1c7c74d382caa0550320edb91306d455c734af Mon Sep 17 00:00:00 2001 From: Kyle Allan Date: Sat, 8 Mar 2014 15:59:59 -0800 Subject: [PATCH 09/11] error handling seems redundant --- trackerapi/trackerapi.go | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/trackerapi/trackerapi.go b/trackerapi/trackerapi.go index 28949c3..497fc3f 100644 --- a/trackerapi/trackerapi.go +++ b/trackerapi/trackerapi.go @@ -33,32 +33,45 @@ type MeResponse struct { func CacheCredentials() error { usr, pwd, err := getCredentials() - parse(makeMeRequest(usr, pwd)) + body, err := makeMeRequest(usr, pwd) + if err != nil { + return err + } + parse(body) + + fmt.Println(string(body)) ioutil.WriteFile(FileLocation, []byte(currentUser.APIToken), 0644) return err } -func makeMeRequest(usr, pwd string) []byte { +func makeMeRequest(usr, pwd string) ([]byte, error) { client := &http.Client{} req, err := http.NewRequest("GET", URL, nil) + if err != nil { + return nil, err + } + req.SetBasicAuth(usr, pwd) resp, err := client.Do(req) + if err != nil { + return nil, err + } + body, err := ioutil.ReadAll(resp.Body) if err != nil { - fmt.Print(err) + return nil, err } - fmt.Printf("\n****\nAPI response: \n%s\n", string(body)) - return body + return body, nil } -func parse(body []byte) { - var meResp = new(MeResponse) +func parse(body []byte) (string, error) { + var meResp MeResponse err := json.Unmarshal(body, &meResp) if err != nil { - fmt.Println("error:", err) + return "", err } - currentUser.APIToken = meResp.APIToken + return meResp.APIToken, nil } func getCredentials() (usr, pwd string, err error) { From 892618cb2fcf65b980d32fb5f9f8d11f5e7a619c Mon Sep 17 00:00:00 2001 From: Kyle Allan Date: Sat, 8 Mar 2014 16:08:17 -0800 Subject: [PATCH 10/11] remove parse method and just write the token --- trackerapi/trackerapi.go | 39 +++++++++++---------------------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/trackerapi/trackerapi.go b/trackerapi/trackerapi.go index 497fc3f..76199e7 100644 --- a/trackerapi/trackerapi.go +++ b/trackerapi/trackerapi.go @@ -17,60 +17,43 @@ var ( Stdout = os.Stdout ) -// MeResponse . -type MeResponse struct { - APIToken string `json:"api_token"` - Username string `json:"username"` - Name string `json:"name"` - Email string `json:"email"` - Initials string `json:"initials"` - Timezone struct { - Kind string `json:"kind"` - Offset string `json:"offset"` - OlsonName string `json:"olson_name"` - } `json:"time_zone"` -} - func CacheCredentials() error { usr, pwd, err := getCredentials() - body, err := makeMeRequest(usr, pwd) + apiToken, err := getAPIToken(usr, pwd) if err != nil { return err } - parse(body) - fmt.Println(string(body)) - ioutil.WriteFile(FileLocation, []byte(currentUser.APIToken), 0644) + ioutil.WriteFile(FileLocation, []byte(apiToken), 0644) return err } -func makeMeRequest(usr, pwd string) ([]byte, error) { +func getAPIToken(usr, pwd string) (string, error) { client := &http.Client{} req, err := http.NewRequest("GET", URL, nil) if err != nil { - return nil, err + return "", err } req.SetBasicAuth(usr, pwd) resp, err := client.Do(req) if err != nil { - return nil, err + return "", err } body, err := ioutil.ReadAll(resp.Body) if err != nil { - return nil, err + return "", err + } + + var meResp struct { + APIToken string `json:"api_token"` } - return body, nil -} -func parse(body []byte) (string, error) { - var meResp MeResponse - err := json.Unmarshal(body, &meResp) + err = json.Unmarshal(body, &meResp) if err != nil { return "", err } - return meResp.APIToken, nil } From e73cec52d9c6770dd6fae84eaaa335af203be890 Mon Sep 17 00:00:00 2001 From: Kyle Allan Date: Mon, 10 Mar 2014 13:39:58 -0700 Subject: [PATCH 11/11] finish refactoring --- NOTES.txt | 123 +++++++++++++++++++++++++++++++++++++++ trackerapi/trackerapi.go | 45 +++++++------- 2 files changed, 148 insertions(+), 20 deletions(-) create mode 100644 NOTES.txt diff --git a/NOTES.txt b/NOTES.txt new file mode 100644 index 0000000..4f4e752 --- /dev/null +++ b/NOTES.txt @@ -0,0 +1,123 @@ +http://www.golangbootcamp.com/book/basic_concepts +https://github.com/mitchellh/gox +https://generalassemb.ly/los-angeles +https://gophercasts.io/ +http://play.golang.org/ + +Other classes happening in here make it really loud. + +last name at the end of the import is the package name! +externally visible things in a package are always capitalized. Capitalized functions are essentially public. Lower case are private. +all variables have a zero type when initialized. a bool is false, an integer is 0, etc. +variable shadowing an interesting concept. can be dangerous, but possibly useful(?). A locally scoped variable will override a higher scoped variable. + +Silly, valid Go code. + +const ever = true + +for ever { + +} + +variables can be declared specifically in front of an if statement, and that variable will be in scope only for the if + +if x := 5 + y; x < 10 { + return "horray!" +} + +newton approximation. Kinda interesting / hard + +package main + +import ( + "fmt" + "math" +) + +const delta = 1e-5 + +func Sqrt(x float64) float64 { + z := 1.0 + for { + nz := z - (z*z-x)/(2*z) + if d := nz - z; math.Abs(d) < delta { + return z + } + z = nz + } +} + +func main() { + fmt.Println(Sqrt(9)) +} + + +"Go compiles itself (the standard library) in less than one minute" + +Classes have behavior, structs are a package of data and behavior. Behavior can be attached to any type. + + +Some sort-of useful debugging output +fmt.Printf("%+v", Vertex{1, 2}) +fmt.Printf("%#v", Vertex{1, 2}) +fmt.Printf("%q", Vertex{1, 2}) +v := Vertex{Y: 2, X: 1} +fmt.Printf("%+v", v) + +Go copies the object when you pass it around, so that is why you would want to prefer Pointers +Functions that want to modify an object passed in (as a side-effect), you need to pass through a pointer +Can you dangle a pointer by pointing to a variable, and losing scope to that variable? No, Go is garbage collected and that variable will continue to exist. + +When you really code in Go, you will almost never use arrays. Really? You would use slices. +Slices are the powerful way to interact with arrays. Has len(), cap(), and append() +A for loop over a slice uses 2 parameters, index and value when using range + +Table testing - https://code.google.com/p/go-tour/source/browse/wc/wc.go + +Jeremy Saenz +Martini - reuseable web components in Go. Very cool. + +Lambdas first class citizen. Neat little debug trick. +func main() { + hypot := func(x, y float64) float64 { + return math.Sqrt(x*x + y*y) + } + + fmt.Printf("%T", hypot) +} +func(float64, float64) float64 + + +Functions that return functions. Confusing but interesting. +fibbinocci closure is interesting + +Difference between passing a pointer or a value to a defined function. http://tour.golang.org/#54. Pointers allow you to modify, values do not. + +https://github.com/mitchellh/goxc + GOOS="OPERATING SYSTEM" go build a main package +GOOS="windows" /usr/local/Cellar/go/1.2/libexec/src/make.bash +for loop on GOOS to cross compile things + +Kelsey Hightower - @kelseyhightower +http://www.freedesktop.org/software/systemd/man/systemd-nspawn.html +https://github.com/kelseyhightower/confd + +http://www.reddit.com/r/golang/ + +Channel of channels. +Channels are interesting. +Each request sent to a Go web server is its own goroutine. + +Don't use . when doing imports and aliases. + + + +Lots of Ruby devs in here. Lots of web developers as well. + +Systemd and your service just logs to stdout. forget about writing logs, just pipe them somewhere or allow some way to aggregate em. + + + + + + + diff --git a/trackerapi/trackerapi.go b/trackerapi/trackerapi.go index 76199e7..955cf8d 100644 --- a/trackerapi/trackerapi.go +++ b/trackerapi/trackerapi.go @@ -7,58 +7,60 @@ import ( "net/http" "os" "os/user" + "path/filepath" ) const URL string = "https://www.pivotaltracker.com/services/v5/me" -var ( - FileLocation = homeDir() + "/.tracker" - currentUser = new(pivotalUser) - Stdout = os.Stdout -) +var FileLocation string = fromHome("/.tracker") func CacheCredentials() error { - usr, pwd, err := getCredentials() - apiToken, err := getAPIToken(usr, pwd) + apiToken, err := getAPIToken() if err != nil { return err } - - ioutil.WriteFile(FileLocation, []byte(apiToken), 0644) + fmt.Println(string(apiToken)) return err } -func getAPIToken(usr, pwd string) (string, error) { +func getAPIToken() ([]byte, error) { + + if _, err := os.Stat(FileLocation); err == nil { + return ioutil.ReadFile(FileLocation) + } + + usr, pwd, err := getCredentials() client := &http.Client{} req, err := http.NewRequest("GET", URL, nil) if err != nil { - return "", err + return nil, err } req.SetBasicAuth(usr, pwd) resp, err := client.Do(req) if err != nil { - return "", err + return nil, err } body, err := ioutil.ReadAll(resp.Body) if err != nil { - return "", err + return nil, err } var meResp struct { - APIToken string `json:"api_token"` + APIToken []byte `json:"api_token"` } err = json.Unmarshal(body, &meResp) if err != nil { - return "", err + return nil, err } + ioutil.WriteFile(FileLocation, []byte(meResp.APIToken), 0644) return meResp.APIToken, nil } func getCredentials() (usr, pwd string, err error) { - fmt.Fprint(Stdout, "Username: ") + fmt.Fprint(os.Stdout, "Username: ") usr, err = readLine() if err != nil { @@ -68,13 +70,16 @@ func getCredentials() (usr, pwd string, err error) { silenceStty() defer unsilenceStty() - fmt.Fprint(Stdout, "Password: ") + fmt.Fprint(os.Stdout, "Password: ") pwd, err = readLine() return usr, pwd, err } -func homeDir() string { - usr, _ := user.Current() - return usr.HomeDir +func fromHome(file string) string { + usr, err := user.Current() + if err != nil { + panic(err) + } + return filepath.Join(usr.HomeDir, file) }