github.com/andrewhsu/cli/v2@v2.0.1-0.20210910131313-d4b4061f5b89/pkg/cmd/gist/shared/shared.go (about) 1 package shared 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "net/http" 8 "net/url" 9 "strings" 10 "time" 11 12 "github.com/andrewhsu/graphql" 13 "github.com/andrewhsu/cli/v2/api" 14 "github.com/andrewhsu/cli/v2/internal/ghinstance" 15 "github.com/gabriel-vasile/mimetype" 16 "github.com/shurcooL/githubv4" 17 ) 18 19 type GistFile struct { 20 Filename string `json:"filename,omitempty"` 21 Type string `json:"type,omitempty"` 22 Language string `json:"language,omitempty"` 23 Content string `json:"content"` 24 } 25 26 type GistOwner struct { 27 Login string `json:"login,omitempty"` 28 } 29 30 type Gist struct { 31 ID string `json:"id,omitempty"` 32 Description string `json:"description"` 33 Files map[string]*GistFile `json:"files"` 34 UpdatedAt time.Time `json:"updated_at"` 35 Public bool `json:"public"` 36 HTMLURL string `json:"html_url,omitempty"` 37 Owner *GistOwner `json:"owner,omitempty"` 38 } 39 40 var NotFoundErr = errors.New("not found") 41 42 func GetGist(client *http.Client, hostname, gistID string) (*Gist, error) { 43 gist := Gist{} 44 path := fmt.Sprintf("gists/%s", gistID) 45 46 apiClient := api.NewClientFromHTTP(client) 47 err := apiClient.REST(hostname, "GET", path, nil, &gist) 48 if err != nil { 49 var httpErr api.HTTPError 50 if errors.As(err, &httpErr) && httpErr.StatusCode == 404 { 51 return nil, NotFoundErr 52 } 53 return nil, err 54 } 55 56 return &gist, nil 57 } 58 59 func GistIDFromURL(gistURL string) (string, error) { 60 u, err := url.Parse(gistURL) 61 if err == nil && strings.HasPrefix(u.Path, "/") { 62 split := strings.Split(u.Path, "/") 63 64 if len(split) > 2 { 65 return split[2], nil 66 } 67 68 if len(split) == 2 && split[1] != "" { 69 return split[1], nil 70 } 71 } 72 73 return "", fmt.Errorf("Invalid gist URL %s", u) 74 } 75 76 func ListGists(client *http.Client, hostname string, limit int, visibility string) ([]Gist, error) { 77 type response struct { 78 Viewer struct { 79 Gists struct { 80 Nodes []struct { 81 Description string 82 Files []struct { 83 Name string 84 } 85 IsPublic bool 86 Name string 87 UpdatedAt time.Time 88 } 89 PageInfo struct { 90 HasNextPage bool 91 EndCursor string 92 } 93 } `graphql:"gists(first: $per_page, after: $endCursor, privacy: $visibility, orderBy: {field: CREATED_AT, direction: DESC})"` 94 } 95 } 96 97 perPage := limit 98 if perPage > 100 { 99 perPage = 100 100 } 101 102 variables := map[string]interface{}{ 103 "per_page": githubv4.Int(perPage), 104 "endCursor": (*githubv4.String)(nil), 105 "visibility": githubv4.GistPrivacy(strings.ToUpper(visibility)), 106 } 107 108 gql := graphql.NewClient(ghinstance.GraphQLEndpoint(hostname), client) 109 110 gists := []Gist{} 111 pagination: 112 for { 113 var result response 114 err := gql.QueryNamed(context.Background(), "GistList", &result, variables) 115 if err != nil { 116 return nil, err 117 } 118 119 for _, gist := range result.Viewer.Gists.Nodes { 120 files := map[string]*GistFile{} 121 for _, file := range gist.Files { 122 files[file.Name] = &GistFile{ 123 Filename: file.Name, 124 } 125 } 126 127 gists = append( 128 gists, 129 Gist{ 130 ID: gist.Name, 131 Description: gist.Description, 132 Files: files, 133 UpdatedAt: gist.UpdatedAt, 134 Public: gist.IsPublic, 135 }, 136 ) 137 if len(gists) == limit { 138 break pagination 139 } 140 } 141 142 if !result.Viewer.Gists.PageInfo.HasNextPage { 143 break 144 } 145 variables["endCursor"] = githubv4.String(result.Viewer.Gists.PageInfo.EndCursor) 146 } 147 148 return gists, nil 149 } 150 151 func IsBinaryFile(file string) (bool, error) { 152 detectedMime, err := mimetype.DetectFile(file) 153 if err != nil { 154 return false, err 155 } 156 157 isBinary := true 158 for mime := detectedMime; mime != nil; mime = mime.Parent() { 159 if mime.Is("text/plain") { 160 isBinary = false 161 break 162 } 163 } 164 return isBinary, nil 165 } 166 167 func IsBinaryContents(contents []byte) bool { 168 isBinary := true 169 for mime := mimetype.Detect(contents); mime != nil; mime = mime.Parent() { 170 if mime.Is("text/plain") { 171 isBinary = false 172 break 173 } 174 } 175 return isBinary 176 }