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