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  }