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/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/main.go b/main.go index 012a948..5a8e9d0 100644 --- a/main.go +++ b/main.go @@ -1,27 +1,23 @@ package main import ( + "log" "os" "github.com/GoBootcamp/clirescue/trackerapi" - "github.com/codegangsta/cli" ) func main() { - 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", - Action: func(c *cli.Context) { - trackerapi.Me() - }, - }, + if len(os.Args) < 2 { + log.Fatal("Command required") + } + switch os.Args[1] { + case "login": + err := trackerapi.CacheCredentials() + if err != nil { + panic(err) + } + default: + log.Fatal("Unknown Command: ", os.Args[1]) } - - app.Run(os.Args) } diff --git a/trackerapi/me.go b/trackerapi/me.go deleted file mode 100644 index 1bdf108..0000000 --- a/trackerapi/me.go +++ /dev/null @@ -1,78 +0,0 @@ -package trackerapi - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - "os" - u "os/user" - - "github.com/GoBootcamp/clirescue/cmdutil" - "github.com/GoBootcamp/clirescue/user" -) - -var ( - URL string = "https://www.pivotaltracker.com/services/v5/me" - FileLocation string = homeDir() + "/.tracker" - currentUser *user.User = user.New() - Stdout *os.File = os.Stdout -) - -func Me() { - setCredentials() - parse(makeRequest()) - ioutil.WriteFile(FileLocation, []byte(currentUser.APIToken), 0644) -} - -func makeRequest() []byte { - client := &http.Client{} - req, err := http.NewRequest("GET", URL, nil) - req.SetBasicAuth(currentUser.Username, currentUser.Password) - resp, err := client.Do(req) - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - fmt.Print(err) - } - fmt.Printf("\n****\nAPI response: \n%s\n", string(body)) - return body -} - -func parse(body []byte) { - var meResp = new(MeResponse) - err := json.Unmarshal(body, &meResp) - if err != nil { - fmt.Println("error:", err) - } - - currentUser.APIToken = meResp.APIToken -} - -func setCredentials() { - fmt.Fprint(Stdout, "Username: ") - var username = cmdutil.ReadLine() - cmdutil.Silence() - fmt.Fprint(Stdout, "Password: ") - - var password = cmdutil.ReadLine() - currentUser.Login(username, password) - cmdutil.Unsilence() -} - -func homeDir() string { - usr, _ := u.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"` -} diff --git a/trackerapi/trackerapi.go b/trackerapi/trackerapi.go new file mode 100644 index 0000000..955cf8d --- /dev/null +++ b/trackerapi/trackerapi.go @@ -0,0 +1,85 @@ +package trackerapi + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "os" + "os/user" + "path/filepath" +) + +const URL string = "https://www.pivotaltracker.com/services/v5/me" + +var FileLocation string = fromHome("/.tracker") + +func CacheCredentials() error { + apiToken, err := getAPIToken() + if err != nil { + return err + } + fmt.Println(string(apiToken)) + return err +} + +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 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 { + return nil, err + } + + var meResp struct { + APIToken []byte `json:"api_token"` + } + + err = json.Unmarshal(body, &meResp) + if err != nil { + return nil, err + } + ioutil.WriteFile(FileLocation, []byte(meResp.APIToken), 0644) + return meResp.APIToken, nil +} + +func getCredentials() (usr, pwd string, err error) { + fmt.Fprint(os.Stdout, "Username: ") + usr, err = readLine() + + if err != nil { + return + } + + silenceStty() + defer unsilenceStty() + + fmt.Fprint(os.Stdout, "Password: ") + pwd, err = readLine() + + return usr, pwd, err +} + +func fromHome(file string) string { + usr, err := user.Current() + if err != nil { + panic(err) + } + return filepath.Join(usr.HomeDir, file) +} diff --git a/user/user.go b/trackerapi/user.go similarity index 57% rename from user/user.go rename to trackerapi/user.go index 58b6d63..11690f3 100644 --- a/user/user.go +++ b/trackerapi/user.go @@ -1,10 +1,10 @@ -package user +// Copyright 2013 -func New() *User { - return new(User) -} +// Package pivotaluser represents a pivotal user +package trackerapi -type User struct { +// User represents a Pivotal Labs user. +type pivotalUser struct { Username string Password string APIToken string @@ -18,7 +18,8 @@ type User struct { } `json:"time_zone"` } -func (u *User) Login(name, pass string) { +// SetLogin sets the username and password. +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..49f69f1 --- /dev/null +++ b/trackerapi/util.go @@ -0,0 +1,30 @@ +package trackerapi + +import ( + "bufio" + "os" + "os/exec" + "strings" +) + +func readLine() (string, error) { + line, err := bufio.NewReader(os.Stdin).ReadString('\n') + if err != nil { + return "", err + } + return strings.TrimSpace(string(line)), nil +} + +func silenceStty() { + runCommand(exec.Command("stty", "-echo")) +} + +func unsilenceStty() { + runCommand(exec.Command("stty", "echo")) +} + +func runCommand(command *exec.Cmd) { + command.Stdin = os.Stdin + command.Stdout = os.Stdout + command.Run() +}