From 2dcd2645270f3aa969acf04c2638c93039c15b0f Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Sun, 20 Jun 2021 13:49:05 +0100 Subject: [PATCH] GetGitignore initial build Basic go program with readme --- .gitignore | 16 +++++++ README.md | 29 ++++++++++++ gitignore/gitignore.go | 100 +++++++++++++++++++++++++++++++++++++++++ go.mod | 3 ++ main.go | 100 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 248 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 gitignore/gitignore.go create mode 100644 go.mod create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f1266a3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +# Binaries for programs and plugins +getgitignore +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +vendor/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..9979c2f --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# GetGitIgnore + +Tool to get Git Ignore files from [GitHub GitIgnore](https://github.com/github/gitignore) + +## Features + +* Outputs to stdout by default +* list subcommand - lists all gitignores +* search subcommand - searches gitignores + +## TODO + +* arg to inteligently append to file + * don't duplicate if header comment found +* no get args == inteligent mode - finds types of files and gets appropriate ignores +* add in headers comment with commit hash above each ignore content +* Follows structure in github/gitignore +* Use Go Releaser +* Use Github Actions +* Add to Brew +* If finds a GITHUB_TOKEN env var, try use it +* Do a case insesitive search +* Move cli logic out of gitignore package +* If it's go: + * guess the compiled binary name and add to ignore + * remove comment against vendor/ +* remove panics +* Case insensitive search +* rename to "gitignore"? diff --git a/gitignore/gitignore.go b/gitignore/gitignore.go new file mode 100644 index 0000000..73ccab8 --- /dev/null +++ b/gitignore/gitignore.go @@ -0,0 +1,100 @@ +package gitignore + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "strings" +) + +type file struct { + Path string `json:"path"` + Mode string `json:"mode"` + Type string `json:"type"` + Sha string `json:"sha"` + Url string `json:"url"` +} + +type tree struct { + Sha string `json:"sha"` + Url string `json:"url"` + Tree []file `json:"tree"` +} + +var github = map[string]string{ + "rawUrl": "https://raw.githubusercontent.com", + "reposApi": "https://api.github.com/repos", + "repo": "github/gitignore", + "branch": "master", +} + +func Get(query string) ([]byte, error) { + url := fmt.Sprintf("%s/%s/%s/%s.gitignore", github["rawUrl"], github["repo"], github["branch"], query) + resp, err := http.Get(url) + if err != nil { + panic(err) + } + defer resp.Body.Close() + + // TODO prepend header to bytes + var ignore []byte + if resp.StatusCode == http.StatusOK { + ignore, err = ioutil.ReadAll(resp.Body) + if err != nil { + fmt.Printf("Error: %s\n", err) + } + return ignore, err + } + + return nil, fmt.Errorf("could not find gitignore for %s", query) +} + +func List() []string { + return getAllGitignores() +} + +func Search(query string) ([]string, error) { + gitignores := getAllGitignores() + + var ignores []string + for _, file := range gitignores { + if strings.Contains(file, query) { + ignores = append(ignores, file) + } + + } + if len(ignores) == 0 { + return nil, fmt.Errorf("no gitignore found for: %s", query) + } + return ignores, nil +} + +func getAllGitignores() []string { + url := fmt.Sprintf("%s/%s/git/trees/%s?recursive=1", github["reposApi"], github["repo"], github["branch"]) + resp, err := http.Get(url) + if err != nil { + panic(err) + } + defer resp.Body.Close() + + repoTreeResponse, err := ioutil.ReadAll(resp.Body) + if err != nil { + panic(err) + } + + var repoTree tree + err = json.Unmarshal([]byte(repoTreeResponse), &repoTree) + if err != nil { + panic(err) + } + + var fileList []string + for _, v := range repoTree.Tree { + if strings.Contains(v.Path, ".gitignore") { + fileList = append(fileList, strings.ReplaceAll(v.Path, ".gitignore", "")) + } + } + + return fileList +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..38e5275 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/joeds13/getgitignore + +go 1.16 diff --git a/main.go b/main.go new file mode 100644 index 0000000..8a8140c --- /dev/null +++ b/main.go @@ -0,0 +1,100 @@ +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "os" + + "github.com/joeds13/getgitignore/gitignore" +) + +var ( + version = "dev" + commit = "none" + date = "unknown" +) + +const ( + usage = `usage: %s +Get GitIgnore Files + +` +) + +func main() { + getCmd := flag.NewFlagSet("get", flag.ExitOnError) + getFile := getCmd.Bool("file", false, "TODO: file usage") + listCmd := flag.NewFlagSet("list", flag.ExitOnError) + searchCmd := flag.NewFlagSet("search", flag.ExitOnError) + + flag.Usage = func() { + fmt.Fprintf(flag.CommandLine.Output(), usage, os.Args[0]) + getCmd.Usage() + // listCmd.Usage() + // searchCmd.Usage() + } + + if len(os.Args) < 2 { + flag.Usage() + os.Exit(1) + } + + switch os.Args[1] { + case "get": + getCmd.Parse(os.Args[2:]) + if len(os.Args[2:]) != 1 { + flag.Usage() + os.Exit(1) + } + + ignore, err := gitignore.Get(os.Args[2]) + if err != nil { + fmt.Printf("Error: %s\n", err) + os.Exit(1) + } + + if *getFile { + // TODO handle appending to gitignore + err := ioutil.WriteFile(".gitignore", ignore, 0644) + if err != nil { + panic(err) + } + } else { + fmt.Printf("%s\n", ignore) + } + + case "list": + listCmd.Parse(os.Args[2:]) + if len(listCmd.Args()) > 0 { + flag.Usage() + os.Exit(1) + } + ignores := gitignore.List() + for _, file := range ignores { + fmt.Printf("%s\n", file) + } + + case "search": + searchCmd.Parse(os.Args[2:]) + if len(searchCmd.Args()) > 1 { + flag.Usage() + os.Exit(1) + } + ignores, err := gitignore.Search(searchCmd.Args()[0]) + if err != nil { + fmt.Printf("Error: %s\n", err) + os.Exit(1) + } + for _, file := range ignores { + fmt.Printf("%s\n", file) + } + + case "version": + fmt.Printf("Version: %s\nCommit: %s\nBuilt at: %s\n", version, commit, date) + + default: + flag.Usage() + os.Exit(1) + } +}