├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── conf ├── configuration.go └── oauth │ └── oauth.go ├── gist └── gist.go ├── gost.go ├── json ├── gist_json.go └── oauth │ └── OAuth.go └── utils └── utils.go /.gitignore: -------------------------------------------------------------------------------- 1 | gost 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | ## 0.5.0 (2015/12/06) 4 | 5 | Refactor: 6 | * listing your own gists will show both public and private 7 | * refactor clipboard operations (thanks @erikh) 8 | 9 | Bugfix: 10 | * FIX copy command on OSX (thanks @erikh) 11 | 12 | 13 | ## 0.4.0 (2015/01/25) 14 | 15 | Bugfix: 16 | 17 | * FIX opening browser on multiple OS (thanx @ramtiga) 18 | * ALLOW creating multiple tokens 19 | 20 | 21 | ## 0.3.0 (2014/06/06) 22 | 23 | New functionalities: 24 | 25 | * Creating a gist now copies it's url in the clipboard 26 | 27 | * Add flag `-o` to open gist in browser 28 | 29 | 30 | Refactor: 31 | 32 | Actions to an existing gist supports being passed either an url either a gist id 33 | 34 | 35 | ## 0.2.0 (2014/02/02) 36 | 37 | ADD missing common functionalities: 38 | 39 | * gist updating (`-u`) 40 | 41 | * gist downloading (`-g`) 42 | 43 | * gist deleting (`-D`) 44 | 45 | ADD two-factor authentication 46 | 47 | 48 | ## 0.1.0 (2013/12/29) 49 | 50 | First release! 51 | 52 | * Support getting an authentication token 53 | 54 | * Post gists 55 | 56 | * Read a user gists 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Maxime Demolin 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Gost 2 | 3 | *The gist client in go* 4 | 5 | Gost is a client for the gist API, 6 | it allows you to create and browse the gists of [https://gist.github.com/](https://gist.github.com/). 7 | 8 | # Installation 9 | 10 | You can grab a binary for your platform on the 11 | [releases page](https://github.com/MaximeD/gost/releases). 12 | 13 | 14 | Or else, you can install it from sources: 15 | 16 | ``` 17 | go get github.com/MaximeD/gost 18 | ``` 19 | 20 | 21 | # Usage 22 | 23 | ## Create gists 24 | 25 | ``` 26 | gost 27 | ``` 28 | 29 | You can supply as many files as you want here. 30 | 31 | 32 | Full example: 33 | 34 | ``` 35 | gost -p -d "rocking the casbah" fun.go love_gist.rb 36 | ``` 37 | 38 | will create a private gist with description "rocking the casbah" 39 | with two files `fun.go` and `love_gist.rb`. 40 | The resulting url will be copy to your clipboard. 41 | 42 | ### Command line options 43 | 44 | #### Private gists 45 | 46 | By default, your gists are public. 47 | If you want a private one, just add `-p` to your command. 48 | On first run, `gost` will create a prompt you for your credentials 49 | and store a token in it's configuration file, 50 | so that you will have to do this step only once. 51 | 52 | #### Description 53 | 54 | To give your gist a description use `-d `. 55 | 56 | #### Open result in browser 57 | 58 | To have your browser auto open on the url, use the flag `-o`. 59 | (It will rely on `xdg-open`). 60 | 61 | 62 | ## Update gist 63 | 64 | To update a gist: 65 | 66 | ``` 67 | gost -u 68 | ``` 69 | 70 | You can supply an optional `-d` flag to update the description of your gist. 71 | 72 | ``` 73 | gost -u -d 74 | ``` 75 | 76 | 77 | ## List gists 78 | 79 | You can list the gist of a user with the following: 80 | 81 | ``` 82 | gost -l 83 | ``` 84 | 85 | ## Download a gist 86 | 87 | ``` 88 | gost -g 89 | ``` 90 | 91 | ## Delete a gist 92 | 93 | Given you have the id of one of your gist and the right to delete it, use `-D` flag: 94 | 95 | ``` 96 | gost -D 97 | ``` 98 | -------------------------------------------------------------------------------- /conf/configuration.go: -------------------------------------------------------------------------------- 1 | package Configuration 2 | 3 | import ( 4 | "fmt" 5 | "github.com/MaximeD/gost/conf/oauth" 6 | "io/ioutil" 7 | "os" 8 | ) 9 | 10 | var homeDir string = os.Getenv("HOME") 11 | var configurationFilePath string = homeDir + "/.gost" 12 | 13 | func GetToken() (token string) { 14 | return readConf() 15 | } 16 | 17 | func readConf() (token string) { 18 | file, err := ioutil.ReadFile(configurationFilePath) 19 | 20 | if err != nil { 21 | // file does not exist 22 | return createConfigurationFile() 23 | } 24 | return string(file) 25 | } 26 | 27 | func createConfigurationFile() string { 28 | var OAuthToken string 29 | 30 | fmt.Println("You don't have any configuration file") 31 | fmt.Println("Do you want to create one? [Y/n]") 32 | var answer string 33 | fmt.Scanln(&answer) 34 | 35 | if answer == "y" || answer == "Y" || answer == "" { 36 | OAuthToken = OAuth.GetToken() 37 | ioutil.WriteFile(configurationFilePath, []byte(OAuthToken), 0660) 38 | fmt.Printf("[configuration file written to '%s']\n", configurationFilePath) 39 | } else { 40 | fmt.Println("Posting an anonymous gist...") 41 | fmt.Println("I'll ask you again next time!") 42 | } 43 | 44 | return OAuthToken 45 | } 46 | -------------------------------------------------------------------------------- /conf/oauth/oauth.go: -------------------------------------------------------------------------------- 1 | package OAuth 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/MaximeD/gost/json/oauth" 8 | "io/ioutil" 9 | "net/http" 10 | "os" 11 | "time" 12 | ) 13 | 14 | var baseUrl string = "https://api.github.com/" 15 | var authorizationUrl string = baseUrl + "authorizations" 16 | 17 | // GetToken will query github api to create an authentication token for gost. 18 | // This allows user to create gists on his behalf rather than anonymously. 19 | // It returns the created token. 20 | func GetToken() string { 21 | client := &http.Client{} 22 | var authorizationResponseBody []byte 23 | var twoFA string 24 | 25 | username, password := askUserForCredentials() 26 | authenticationJson := getAuthenticationJson(false) 27 | 28 | resp := makeBasicAuthRequest(client, username, password, authenticationJson, twoFA) 29 | defer resp.Body.Close() 30 | 31 | // check for 2fa 32 | if resp.StatusCode == 401 && resp.Header.Get("X-Github-Otp") != "" { 33 | twoFA = askUserForTwoFA() 34 | resp = makeBasicAuthRequest(client, username, password, authenticationJson, twoFA) 35 | defer resp.Body.Close() 36 | } 37 | 38 | // user might already have registered a token for this application 39 | if resp.StatusCode == 422 { 40 | authenticationJson = getAuthenticationJson(true) 41 | resp = makeBasicAuthRequest(client, username, password, authenticationJson, twoFA) 42 | defer resp.Body.Close() 43 | } 44 | 45 | if resp.StatusCode != 201 { 46 | fmt.Println("Sorry but we could not authenticate you.") 47 | fmt.Println("No gist were created...") 48 | os.Exit(1) 49 | } 50 | 51 | authorizationResponseBody, err := ioutil.ReadAll(resp.Body) 52 | if err != nil { 53 | fmt.Printf("%s\n", err) 54 | os.Exit(1) 55 | } 56 | 57 | var jsonRes OAuthJSON.GetSingleAuthResponse 58 | err = json.Unmarshal(authorizationResponseBody, &jsonRes) 59 | if err != nil { 60 | fmt.Printf("%s\n", err) 61 | os.Exit(1) 62 | } 63 | 64 | return jsonRes.Token 65 | } 66 | 67 | // askUserForCredentials will prompt the user to enter his username and password. 68 | // It returns user's username and user's password. 69 | func askUserForCredentials() (username string, password string) { 70 | fmt.Println("GitHub username:") 71 | fmt.Scanln(&username) 72 | fmt.Println("GitHub password:") 73 | fmt.Scanln(&password) 74 | 75 | return username, password 76 | } 77 | 78 | // makeBasicAuthRequest will create a POST request to create a new authorization 79 | // with basic auth enabled. 80 | // See: https://developer.github.com/v3/oauth_authorizations/#create-a-new-authorization 81 | // It takes user's username, user's password, marshalled json and 2fa code if user has enabled it. 82 | // It returns a new Request. 83 | func makeBasicAuthRequest(client *http.Client, username string, password string, marshalledJson []byte, twoFA string) *http.Response { 84 | jsonBody := bytes.NewBuffer(marshalledJson) 85 | 86 | req, err := http.NewRequest("POST", authorizationUrl, jsonBody) 87 | if err != nil { 88 | fmt.Printf("%s\n", err) 89 | os.Exit(1) 90 | } 91 | req.SetBasicAuth(username, password) 92 | if twoFA != "" { 93 | req.Header.Add("X-GitHub-OTP", twoFA) 94 | } 95 | 96 | resp, err := client.Do(req) 97 | if err != nil { 98 | fmt.Printf("%s\n", err) 99 | os.Exit(1) 100 | } 101 | 102 | return resp 103 | } 104 | 105 | // getAuthenticationJson creates a marshalled json to be used to create a new authorization. 106 | // See: https://developer.github.com/v3/oauth_authorizations/#create-a-new-authorization 107 | // It takes a boolean parameter telling if note should include a timestamp. 108 | // You will need this in case user already has a token for this application and needs to create a new one. 109 | // Otherwise github will return an empty token. 110 | // It returns the marshalled json. 111 | func getAuthenticationJson(withTimestamp bool) []byte { 112 | description := "gost" 113 | 114 | if withTimestamp { 115 | fmt.Println("You already have a personal access token for gost, though I cannot find it on your computer...") 116 | fmt.Println("I will create another access token for you.") 117 | fmt.Println("(You can see them here https://github.com/settings/applications)") 118 | description = fmt.Sprintf("%s (%s)", description, time.Now()) 119 | } 120 | 121 | authorization := OAuthJSON.GetSingleAuth{Scopes: []string{"gist"}, Note: description, NoteUrl: "https://github.com/MaximeD/gost"} 122 | marshalledJson, err := json.Marshal(authorization) 123 | if err != nil { 124 | fmt.Printf("%s\n", err) 125 | } 126 | 127 | return marshalledJson 128 | } 129 | 130 | // askUserForTwoFA will prompt user to enter his 2f-a code if GitHub requests one 131 | // It returns the 2f-a code. 132 | func askUserForTwoFA() string { 133 | var twoFA string 134 | 135 | fmt.Println("You have enabled two-factor authentication, please enter the code GitHub sent you:") 136 | fmt.Scanln(&twoFA) 137 | 138 | return twoFA 139 | } 140 | -------------------------------------------------------------------------------- /gist/gist.go: -------------------------------------------------------------------------------- 1 | package Gist 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/MaximeD/gost/json" 8 | "github.com/MaximeD/gost/utils" 9 | "io/ioutil" 10 | "net/http" 11 | "os" 12 | "path" 13 | "strings" 14 | "time" 15 | ) 16 | 17 | /* 18 | * Show all gists for a user. 19 | */ 20 | func List(url string, accessToken string) { 21 | if accessToken != "" { 22 | url = url + "?access_token=" + accessToken 23 | } 24 | 25 | res, err := http.Get(url) 26 | if err != nil { 27 | fmt.Printf("%s", err) 28 | os.Exit(1) 29 | } 30 | 31 | // close connexion 32 | defer res.Body.Close() 33 | body, err := ioutil.ReadAll(res.Body) 34 | if err != nil { 35 | fmt.Printf("%s", err) 36 | os.Exit(1) 37 | } 38 | 39 | var jsonRes []GistJSON.Response 40 | err = json.Unmarshal(body, &jsonRes) 41 | if err != nil { 42 | fmt.Printf("%s", err) 43 | os.Exit(1) 44 | } 45 | 46 | for _, val := range jsonRes { 47 | fmt.Printf("%s\n", val.HtmlUrl) 48 | fmt.Printf("(%s)\t%s\n", shortDate(val.CreatedAt), val.Description) 49 | fmt.Printf("\n") 50 | } 51 | } 52 | 53 | func Post(baseUrl string, accessToken string, isPublic bool, filesPath []string, description string, openBrowser bool) { 54 | files := make(map[string]GistJSON.File) 55 | 56 | for i := 0; i < len(filesPath); i++ { 57 | content, err := ioutil.ReadFile(filesPath[i]) 58 | if err != nil { 59 | fmt.Printf("%s", err) 60 | os.Exit(1) 61 | } 62 | fileName := path.Base(filesPath[i]) 63 | files[fileName] = GistJSON.File{Content: string(content)} 64 | } 65 | 66 | gist := GistJSON.Post{Desc: description, Public: isPublic, Files: files} 67 | 68 | // encode json 69 | buf, err := json.Marshal(gist) 70 | if err != nil { 71 | fmt.Printf("%s", err) 72 | } 73 | jsonBody := bytes.NewBuffer(buf) 74 | 75 | // post json 76 | postUrl := baseUrl + "gists" 77 | if accessToken != "" { 78 | postUrl = postUrl + "?access_token=" + accessToken 79 | } 80 | 81 | resp, err := http.Post(postUrl, "text/json", jsonBody) 82 | if err != nil { 83 | fmt.Printf("%s", err) 84 | os.Exit(1) 85 | } 86 | 87 | // close connexion 88 | defer resp.Body.Close() 89 | body, err := ioutil.ReadAll(resp.Body) 90 | if err != nil { 91 | fmt.Printf("%s", err) 92 | os.Exit(1) 93 | } 94 | 95 | var jsonRes GistJSON.Response 96 | err = json.Unmarshal(body, &jsonRes) 97 | if err != nil { 98 | fmt.Printf("%s", err) 99 | os.Exit(1) 100 | } 101 | 102 | // copy url to clipboard 103 | Utils.Copy(jsonRes.HtmlUrl) 104 | 105 | if openBrowser { 106 | Utils.OpenBrowser(jsonRes.HtmlUrl) 107 | } 108 | 109 | // display result 110 | fmt.Printf("%s\n", jsonRes.HtmlUrl) 111 | } 112 | 113 | func Update(baseUrl string, accessToken string, filesPath []string, gistUrl string, description string, openBrowser bool) { 114 | files := make(map[string]GistJSON.File) 115 | 116 | for i := 0; i < len(filesPath); i++ { 117 | content, err := ioutil.ReadFile(filesPath[i]) 118 | if err != nil { 119 | fmt.Printf("%s\n", err) 120 | os.Exit(1) 121 | } 122 | fileName := path.Base(filesPath[i]) 123 | files[fileName] = GistJSON.File{Content: string(content)} 124 | } 125 | 126 | gist := GistJSON.Patch{Desc: description, Files: files} 127 | 128 | // encode json 129 | buf, err := json.Marshal(gist) 130 | if err != nil { 131 | fmt.Printf("%s\n", err) 132 | } 133 | jsonBody := bytes.NewBuffer(buf) 134 | 135 | gistId := getGistId(gistUrl) 136 | 137 | // post json 138 | postUrl := baseUrl + "gists/" + gistId 139 | if accessToken != "" { 140 | postUrl = postUrl + "?access_token=" + accessToken 141 | } 142 | 143 | req, err := http.NewRequest("PATCH", postUrl, jsonBody) 144 | // handle err 145 | resp, err := http.DefaultClient.Do(req) 146 | defer resp.Body.Close() 147 | if err != nil { 148 | fmt.Printf("%s\n", err) 149 | os.Exit(1) 150 | } 151 | 152 | // close connexion 153 | defer resp.Body.Close() 154 | body, err := ioutil.ReadAll(resp.Body) 155 | if err != nil { 156 | fmt.Printf("%s\n", err) 157 | os.Exit(1) 158 | } 159 | 160 | var jsonErrorMessage GistJSON.MessageResponse 161 | err = json.Unmarshal(body, &jsonErrorMessage) 162 | if err != nil { 163 | fmt.Printf("%s\n", err) 164 | os.Exit(1) 165 | } 166 | if jsonErrorMessage.Message != "" { 167 | fmt.Printf("%s\n", jsonErrorMessage.Message) 168 | os.Exit(1) 169 | } 170 | 171 | var jsonRes GistJSON.Response 172 | err = json.Unmarshal(body, &jsonRes) 173 | if err != nil { 174 | fmt.Printf("%s\n", err) 175 | os.Exit(1) 176 | } 177 | 178 | // copy url to clipboard 179 | Utils.Copy(jsonRes.HtmlUrl) 180 | 181 | fmt.Printf("%s\n", jsonRes.HtmlUrl) 182 | revisionCount := len(jsonRes.History) 183 | lastHistoryStatus := jsonRes.History[0].ChangeStatus 184 | fmt.Printf("Revision %d (%d additions & %d deletions)\n", revisionCount, lastHistoryStatus.Deletions, lastHistoryStatus.Additions) 185 | 186 | if openBrowser { 187 | Utils.OpenBrowser(jsonRes.HtmlUrl) 188 | } 189 | } 190 | 191 | func Delete(baseUrl string, accessToken string, gistUrl string) { 192 | 193 | gistId := getGistId(gistUrl) 194 | 195 | deleteUrl := baseUrl + "gists/" + gistId 196 | if accessToken != "" { 197 | deleteUrl = deleteUrl + "?access_token=" + accessToken 198 | } 199 | req, err := http.NewRequest("DELETE", deleteUrl, nil) 200 | // handle err 201 | resp, err := http.DefaultClient.Do(req) 202 | if err != nil { 203 | fmt.Printf("%s", err) 204 | os.Exit(1) 205 | } 206 | 207 | // close connexion 208 | defer resp.Body.Close() 209 | if resp.StatusCode == 204 { 210 | fmt.Println("Gist deleted with success") 211 | } else { 212 | fmt.Printf("Could not find gist %s\n", gistId) 213 | } 214 | } 215 | 216 | func Download(baseUrl string, accessToken string, gistUrl string) { 217 | 218 | gistId := getGistId(gistUrl) 219 | 220 | downloadUrl := baseUrl + "gists/" + gistId 221 | if accessToken != "" { 222 | downloadUrl = downloadUrl + "?access_token=" + accessToken 223 | } 224 | res, err := http.Get(downloadUrl) 225 | if err != nil { 226 | fmt.Printf("%s", err) 227 | os.Exit(1) 228 | } 229 | 230 | // close connexion 231 | defer res.Body.Close() 232 | if res.StatusCode != 200 { 233 | printErrorMessage(res) 234 | os.Exit(1) 235 | } 236 | 237 | body, err := ioutil.ReadAll(res.Body) 238 | if err != nil { 239 | fmt.Printf("%s", err) 240 | os.Exit(1) 241 | } 242 | 243 | var jsonRes GistJSON.Response 244 | err = json.Unmarshal(body, &jsonRes) 245 | if err != nil { 246 | fmt.Printf("%s", err) 247 | os.Exit(1) 248 | } 249 | 250 | for _, file := range jsonRes.Files { 251 | fmt.Printf("Downloading %s\n", file.FileName) 252 | ioutil.WriteFile(file.FileName, []byte(file.Content), 0660) 253 | } 254 | } 255 | 256 | func shortDate(dateString string) string { 257 | date, err := time.Parse("2006-01-02T15:04:05Z07:00", dateString) 258 | if err != nil { 259 | fmt.Println(err) 260 | } 261 | return date.Format("2006-01-02") 262 | } 263 | 264 | func getGistId(urlOrId string) string { 265 | /* 266 | accepted gist format are full url: 267 | https://gist.github.com/a2a510376da5ffcb93f9 268 | or just id 269 | a2a510376da5ffcb93f9 270 | split on '/' to retreive only id 271 | */ 272 | splitted := strings.Split(urlOrId, "/") 273 | return splitted[len(splitted)-1] 274 | } 275 | 276 | func printErrorMessage(resp *http.Response) { 277 | var jsonRes GistJSON.MessageResponse 278 | body, err := ioutil.ReadAll(resp.Body) 279 | if err != nil { 280 | fmt.Printf("%s", err) 281 | os.Exit(1) 282 | } 283 | 284 | err = json.Unmarshal(body, &jsonRes) 285 | fmt.Printf("Sorry, %s\n", jsonRes.Message) 286 | } 287 | -------------------------------------------------------------------------------- /gost.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "github.com/MaximeD/gost/conf" 7 | "github.com/MaximeD/gost/gist" 8 | "os" 9 | ) 10 | 11 | var baseUrl string = "https://api.github.com/" 12 | 13 | // get command line arguments 14 | var deleteGistFlag = flag.String("delete", "", "Delete a gist") 15 | var downloadGistFlag = flag.String("get", "", "Get a single gist") 16 | var gistDescriptionFlag = flag.String("description", "", "Description of the gist") 17 | var gistPrivateFlag = flag.Bool("private", false, "Set gist to private") 18 | var listGistsFlag = flag.String("list", "", "List gists for a user") 19 | var openBrowserFlag = flag.Bool("open", false, "Open result in browser") 20 | var updateGistFlag = flag.String("update", "", "Update an existing gist") 21 | 22 | func init() { 23 | flag.BoolVar(gistPrivateFlag, "p", false, "Set gist to private") 24 | flag.BoolVar(openBrowserFlag, "o", false, "Open result in browser") 25 | flag.StringVar(deleteGistFlag, "D", "", "Delete a gist") 26 | flag.StringVar(downloadGistFlag, "g", "", "Get a single gist") 27 | flag.StringVar(gistDescriptionFlag, "d", "", "Description of the gist") 28 | flag.StringVar(listGistsFlag, "l", "", "List gists for a user") 29 | flag.StringVar(updateGistFlag, "u", "", "Update an existing gist") 30 | } 31 | 32 | func main() { 33 | flag.Parse() 34 | isPublic := !*gistPrivateFlag 35 | 36 | // if nothing was given, display help 37 | if (flag.NFlag() == 0) && (len(flag.Args()) == 0) { 38 | fmt.Println("No arguments or files given!") 39 | fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) 40 | flag.PrintDefaults() 41 | os.Exit(2) 42 | } 43 | 44 | token := Configuration.GetToken() 45 | 46 | if *listGistsFlag != "" { 47 | username := *listGistsFlag 48 | url := baseUrl + "users/" + username + "/gists" 49 | Gist.List(url, token) 50 | } else if *deleteGistFlag != "" { 51 | Gist.Delete(baseUrl, token, *deleteGistFlag) 52 | } else if *downloadGistFlag != "" { 53 | Gist.Download(baseUrl, token, *downloadGistFlag) 54 | } else { 55 | filesName := flag.Args() 56 | if len(filesName) == 0 && *updateGistFlag == "" { 57 | fmt.Println("No files given!") 58 | os.Exit(2) 59 | } 60 | if *updateGistFlag != "" { 61 | Gist.Update(baseUrl, token, filesName, *updateGistFlag, *gistDescriptionFlag, *openBrowserFlag) 62 | } else { 63 | Gist.Post(baseUrl, token, isPublic, filesName, *gistDescriptionFlag, *openBrowserFlag) 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /json/gist_json.go: -------------------------------------------------------------------------------- 1 | package GistJSON 2 | 3 | type Response struct { 4 | Url string `json:"url"` 5 | ForksUrl string `json:"forks_url"` 6 | CommitsUrl string `json:"commits_url"` 7 | Id string `json:"id"` 8 | GitPullUrl string `json:"git_pull_url"` 9 | GitPushUrl string `json:"git_push_url"` 10 | HtmlUrl string `json:"html_url"` 11 | Files map[string]FileDetails `json:"files"` 12 | Public bool `json:"public"` 13 | CreatedAt string `json:"created_at"` 14 | UpdatedAt string `json:"updated_at"` 15 | Description string `json:"description"` 16 | Comments int `json:"comments"` 17 | User User `json:"user"` 18 | CommentsUrl string `json:"comments_url"` 19 | History []History `json:"history"` 20 | } 21 | 22 | type User struct { 23 | Login string `json:"login"` 24 | Id int64 `json:"id"` 25 | AvatarUrl string `json:"avatar_url"` 26 | GravatarId string `json:"gravatar_id"` 27 | Url string `json:"url"` 28 | HtmlUrl string `json:"html_url"` 29 | FollowersUrl string `json:"followers_url"` 30 | FollowingUrl string `json:"followings_url"` 31 | GistsUrl string `json:"gists_url"` 32 | StarredUrl string `json:"starred_url"` 33 | SubscriptionsUrl string `json:"subscriptions_url"` 34 | OrganizationsUrl string `json:"organizations_url"` 35 | ReposUrl string `json:"repos_url"` 36 | EventsUrl string `json:"events_url"` 37 | ReceivedEventsUrl string `json:"received_events_url"` 38 | TypeUrl string `json:"type_url"` 39 | } 40 | 41 | type Post struct { 42 | Desc string `json:"description"` 43 | Public bool `json:"public"` 44 | Files map[string]File `json:"files"` 45 | } 46 | 47 | type Patch struct { 48 | Desc string `json:"description"` 49 | Files map[string]File `json:"files"` 50 | } 51 | 52 | type File struct { 53 | Content string `json:"content"` 54 | } 55 | 56 | type FileDetails struct { 57 | FileName string `json:"filename"` 58 | Type string `json:"type"` 59 | Language string `json:"language"` 60 | RawUrl string `json:"raw_url"` 61 | Size int `json:"size"` 62 | Content string `json:"content"` 63 | } 64 | 65 | type History struct { 66 | Url string `json:"url"` 67 | Version string `json:"version"` 68 | User User `json:"user"` 69 | ChangeStatus ChangeStatus `json:"change_status"` 70 | CommittedAt string `json:"committed_at"` 71 | } 72 | 73 | type ChangeStatus struct { 74 | Deletions int `json:"deletions"` 75 | Additions int `json:"additions"` 76 | Total int `json:"total"` 77 | } 78 | 79 | type MessageResponse struct { 80 | Message string `json:"message"` 81 | DocumentationUrl string `json:"documentation_url"` 82 | } 83 | -------------------------------------------------------------------------------- /json/oauth/OAuth.go: -------------------------------------------------------------------------------- 1 | package OAuthJSON 2 | 3 | type GetSingleAuth struct { 4 | Scopes []string `json:"scopes"` 5 | Note string `json:"note"` 6 | NoteUrl string `json:"note_url"` 7 | } 8 | 9 | type GetSingleAuthResponse struct { 10 | Id int 11 | Url string 12 | Scopes []string 13 | Token string 14 | App map[string]string 15 | Note string 16 | NoteUrl string 17 | CreatedAt string 18 | UpdatedAt string 19 | } 20 | -------------------------------------------------------------------------------- /utils/utils.go: -------------------------------------------------------------------------------- 1 | package Utils 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/exec" 7 | "runtime" 8 | ) 9 | 10 | func Copy(url string) { 11 | // usual clipboards commands 12 | clipboardCommands := []string{"xclip", "xsel", "pbcopy", "getclip"} 13 | 14 | // execute each clipboard command 15 | for _, command := range clipboardCommands { 16 | _, err := exec.LookPath(command) 17 | if err != nil { 18 | continue // we do not have access to this command to execute 19 | } 20 | 21 | cmd := exec.Command(command) 22 | w, err := cmd.StdinPipe() 23 | if err != nil { 24 | fmt.Fprintf(os.Stderr, "Could not copy to clipboard: %v", err) 25 | os.Exit(1) 26 | } 27 | 28 | if err := cmd.Start(); err != nil { 29 | fmt.Fprintf(os.Stderr, "Could not start clipboard command %q: %v", command, err) 30 | } 31 | 32 | if _, err := w.Write([]byte(url)); err != nil { 33 | fmt.Fprintf(os.Stderr, "Could not copy to clipboard: %v", err) 34 | os.Exit(1) 35 | } 36 | 37 | w.Close() 38 | 39 | cmd.Wait() 40 | } 41 | } 42 | 43 | func OpenBrowser(url string) { 44 | os := runtime.GOOS 45 | switch { 46 | case os == "windows": 47 | exec.Command("cmd", "/c", "start", url).Run() 48 | case os == "darwin": 49 | exec.Command("open", url).Run() 50 | case os == "linux": 51 | exec.Command("xdg-open", url).Run() 52 | } 53 | } 54 | --------------------------------------------------------------------------------