├── .gitignore ├── list.go ├── LICENSE ├── create.go ├── README.md └── main.go /.gitignore: -------------------------------------------------------------------------------- 1 | ########## 2 | # Go # 3 | ########## 4 | 5 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 6 | *.o 7 | *.a 8 | *.so 9 | 10 | # Folders 11 | _obj 12 | _test 13 | 14 | # Architecture specific extensions/prefixes 15 | *.[568vq] 16 | [568vq].out 17 | 18 | *.cgo1.go 19 | *.cgo2.c 20 | _cgo_defun.c 21 | _cgo_gotypes.go 22 | _cgo_export.* 23 | 24 | _testmain.go 25 | 26 | *.exe -------------------------------------------------------------------------------- /list.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | var cmdList = &Command{ 6 | UsageLine: "list", 7 | Short: "list all of the available .gitignore templates", 8 | Long: ` 9 | Lists all of the available .gitignore templates from 10 | https://github.com/github/gitignore. 11 | 12 | Example usage: 13 | 14 | gitignorer list 15 | 16 | `, 17 | } 18 | 19 | func init() { 20 | cmdList.Run = runList 21 | } 22 | 23 | func runList(cmd *Command, args []string) { 24 | templates, _, err := client.Gitignores.List() 25 | if err != nil { 26 | fmt.Println(err) 27 | return 28 | } 29 | 30 | for _, t := range *templates { 31 | fmt.Println(t) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Zachary Latta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /create.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/zachlatta/go-github/github" 6 | "io/ioutil" 7 | "os" 8 | "strings" 9 | "sync" 10 | ) 11 | 12 | var cmdCreate = &Command{ 13 | UsageLine: "create [languages]", 14 | Short: "create a .gitignore file", 15 | Long: ` 16 | Create downloads the .gitignore templates for the languages specified from 17 | https://github.com/github/gitignore and mashes them together into a .gitignore 18 | file. 19 | 20 | Example usage: 21 | 22 | gitignorer create go 23 | 24 | `, 25 | } 26 | 27 | func init() { 28 | cmdCreate.Run = runCreate 29 | } 30 | 31 | func runCreate(cmd *Command, args []string) { 32 | if _, err := os.Stat(".gitignore"); err == nil { 33 | fmt.Println("Error: A .gitignore file already exists.") 34 | os.Exit(2) 35 | } 36 | 37 | availableLanguages, _, err := client.Gitignores.List() 38 | if err != nil { 39 | fmt.Fprintf(os.Stderr, "%s\n", err) 40 | os.Exit(2) 41 | } 42 | 43 | chosenLanguages := make([]*string, len(args)) 44 | OUTER: 45 | for i, n := range args { 46 | for _, a := range *availableLanguages { 47 | if strings.ToLower(n) == strings.ToLower(a) { 48 | chosenLanguages[i] = &a 49 | continue OUTER 50 | } 51 | } 52 | // Uh oh, looks like the language the user gave us isn't valid. 53 | fmt.Fprintf(os.Stderr, "%s is not a valid template!\n", n) 54 | os.Exit(2) 55 | } 56 | 57 | var wg sync.WaitGroup 58 | 59 | gitignores := make([]*github.Gitignore, len(chosenLanguages)) 60 | for index, name := range chosenLanguages { 61 | wg.Add(1) 62 | 63 | go func(n string, i int, gitignores []*github.Gitignore) { 64 | defer wg.Done() 65 | 66 | fmt.Println("Fetching template for " + n + "...") 67 | gitignore, _, err := client.Gitignores.Get(n) 68 | if err != nil { 69 | fmt.Println(err) 70 | return 71 | } 72 | gitignores[i] = gitignore 73 | }(*name, index, gitignores) 74 | } 75 | 76 | wg.Wait() 77 | 78 | var fileContents string 79 | for _, g := range gitignores { 80 | header := header(*g.Name) 81 | fileContents += header + "\n\n" + *g.Source + "\n\n" 82 | } 83 | 84 | fileContents = strings.TrimSpace(fileContents) 85 | 86 | fmt.Println("Writing .gitignore file...") 87 | err = ioutil.WriteFile(".gitignore", []byte(fileContents), 0644) 88 | if err != nil { 89 | fmt.Println("Error writing .gitignore file!") 90 | os.Exit(2) 91 | } 92 | fmt.Println("Done!") 93 | } 94 | 95 | // Returns something akin to the following: 96 | // 97 | // ########## 98 | // # Go # 99 | // ########## 100 | func header(name string) string { 101 | line := strings.Repeat("#", len(name)+8) 102 | mid := "# " + name + " #" 103 | return line + "\n" + mid + "\n" + line 104 | } 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gitignorer 2 | 3 | Gitignorer is the easiest way to create `.gitignore` files. 4 | 5 | ## Usage 6 | 7 | $ gitignorer [options] 8 | 9 | ### Examples 10 | 11 | Ignore extraneous files from Go, Java, and Ruby. 12 | 13 | $ gitignorer create go java ruby 14 | 15 | List all available templates. 16 | 17 | $ gitignorer list 18 | 19 | ## Installation 20 | 21 | ### Linux 22 | 23 | #### Ubuntu/Debian 24 | 25 | ##### 64 Bit 26 | 27 | $ wget -P /tmp https://github.com/zachlatta/gitignorer/releases/download/1.0.1/gitignorer_1.0.1_amd64.deb; sudo dpkg -i /tmp/gitignorer_1.0.1_amd64.deb 28 | 29 | ##### 32 Bit 30 | 31 | $ wget -P /tmp https://github.com/zachlatta/gitignorer/releases/download/1.0.1/gitignorer_1.0.1_i386.deb; sudo dpkg -i /tmp/gitignorer_1.0.1_i386.deb 32 | 33 | #### Other Linux 34 | 35 | Binaries for other Linux flavors are available on the 36 | [releases page](https://github.com/zachlatta/gitignorer/releases). 37 | 38 | ### Mac OS X 39 | 40 | $ brew update 41 | $ brew tap zachlatta/gitignorer 42 | $ brew install gitignorer 43 | 44 | ### Other 45 | 46 | Binaries for all major platforms are available on the 47 | [releases page](https://github.com/zachlatta/gitignorer/releases). 48 | 49 | ### Manually 50 | 51 | You'll need Go for this. You can grab it over at http://golang.org/. 52 | 53 | $ go get github.com/zachlatta/gitignorer 54 | $ go install github.com/zachlatta/gitignorer 55 | 56 | ## Contributing 57 | 58 | 1. Fork it 59 | 2. Create your feature branch (`git checkout -b my-new-feature`) 60 | 3. Commit your changes (`git commit -am 'Add some feature'`) 61 | 4. Push to the branch (`git push origin my-new-feature`) 62 | 5. Create new Pull Request 63 | 64 | ## License 65 | 66 | Copyright (c) 2013 Zachary Latta 67 | 68 | Permission is hereby granted, free of charge, to any person obtaining a copy of 69 | this software and associated documentation files (the "Software"), to deal in 70 | the Software without restriction, including without limitation the rights to 71 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 72 | of the Software, and to permit persons to whom the Software is furnished to do 73 | so, subject to the following conditions: 74 | 75 | The above copyright notice and this permission notice shall be included in all 76 | copies or substantial portions of the Software. 77 | 78 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 79 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 80 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 81 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 82 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 83 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 84 | SOFTWARE. 85 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "github.com/zachlatta/go-github/github" 7 | "io" 8 | "os" 9 | "strings" 10 | "sync" 11 | "text/template" 12 | "unicode" 13 | "unicode/utf8" 14 | ) 15 | 16 | // A command is an implementation of a gitignorer command, like 'gitignorer 17 | // create' 18 | type Command struct { 19 | // Run runs the command. 20 | // The args are the arguments after the command name. 21 | Run func(cmd *Command, args []string) 22 | 23 | // UsageLine is the one-line usage message. 24 | // The first word in the line is taken to be the command name. 25 | UsageLine string 26 | 27 | // Short is the short description shown in the 'help' output. 28 | Short string 29 | 30 | // Long is the long message shown in the 'help ' output. 31 | Long string 32 | 33 | // Flag is a set of flags specific to this command 34 | Flag flag.FlagSet 35 | 36 | // CustomFlags indicates that the command will do its own flag parsing. 37 | CustomFlags bool 38 | } 39 | 40 | // Name returns the command's name: the first word in the command's usage line. 41 | func (c *Command) Name() string { 42 | name := c.UsageLine 43 | i := strings.Index(name, " ") 44 | if i >= 0 { 45 | name = name[:i] 46 | } 47 | return name 48 | } 49 | 50 | // Usage prints the command's usage to stderr and exists the program with exit 51 | // code 2 52 | func (c *Command) Usage() { 53 | fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine) 54 | fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long)) 55 | os.Exit(2) 56 | } 57 | 58 | // Runnable repotrs whether the command can be run; otherwise it is a 59 | // documentatino pseudo-command. 60 | func (c *Command) Runnable() bool { 61 | return c.Run != nil 62 | } 63 | 64 | var commands = []*Command{ 65 | cmdCreate, 66 | cmdList, 67 | } 68 | 69 | var exitStatus = 0 70 | var exitMu sync.Mutex 71 | 72 | func setExitStatus(n int) { 73 | exitMu.Lock() 74 | if exitStatus < n { 75 | exitStatus = n 76 | } 77 | exitMu.Unlock() 78 | } 79 | 80 | var client = github.NewClient(nil) 81 | 82 | func main() { 83 | flag.Usage = usage 84 | flag.Parse() 85 | 86 | args := flag.Args() 87 | if len(args) < 1 { 88 | usage() 89 | } 90 | 91 | if args[0] == "help" { 92 | help(args[1:]) 93 | return 94 | } 95 | 96 | for _, cmd := range commands { 97 | if cmd.Name() == args[0] && cmd.Run != nil { 98 | cmd.Flag.Usage = func() { cmd.Usage() } 99 | if cmd.CustomFlags { 100 | args = args[1:] 101 | } else { 102 | cmd.Flag.Parse(args[1:]) 103 | args = cmd.Flag.Args() 104 | } 105 | cmd.Run(cmd, args) 106 | exit() 107 | return 108 | } 109 | } 110 | 111 | errMsg := "gitignorer: unknown subcommand %q\nRun 'gitignorer help` for usage.\n" 112 | 113 | fmt.Fprintf(os.Stderr, errMsg, args[0]) 114 | } 115 | 116 | var usageTemplate = `Gitignorer makes creating .gitignore files easy. 117 | 118 | Usage: 119 | 120 | gitignorer command [arguments] 121 | 122 | The commands are: 123 | {{range .}}{{if .Runnable}} 124 | {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}} 125 | 126 | Use "gitignorer help [command]" for more information about a command. 127 | 128 | ` 129 | 130 | var helpTemplate = `{{if .Runnable}}usage: gitignorer {{.UsageLine}} 131 | 132 | {{end}}{{.Long | trim}} 133 | 134 | ` 135 | 136 | // tmpl executes the given template text on data, writing the result to w. 137 | func tmpl(w io.Writer, text string, data interface{}) { 138 | t := template.New("top") 139 | t.Funcs(template.FuncMap{ 140 | "trim": strings.TrimSpace, 141 | "capitalize": capitalize, 142 | }) 143 | template.Must(t.Parse(text)) 144 | if err := t.Execute(w, data); err != nil { 145 | panic(err) 146 | } 147 | } 148 | 149 | func capitalize(s string) string { 150 | if s == "" { 151 | return s 152 | } 153 | r, n := utf8.DecodeRuneInString(s) 154 | return string(unicode.ToTitle(r)) + s[n:] 155 | } 156 | 157 | func printUsage(w io.Writer) { 158 | tmpl(w, usageTemplate, commands) 159 | } 160 | 161 | func usage() { 162 | printUsage(os.Stderr) 163 | os.Exit(2) 164 | } 165 | 166 | // help implements the 'help' command. 167 | func help(args []string) { 168 | if len(args) == 0 { 169 | printUsage(os.Stdout) 170 | // not exit 2: succeeded at 'gitignorer help' 171 | return 172 | } 173 | if len(args) != 1 { 174 | errMsg := "usage: gitignorer help command\n\nToo many arguments given.\n" 175 | fmt.Fprintf(os.Stderr, errMsg) 176 | os.Exit(2) // failed at 'gitignorer help' 177 | } 178 | 179 | arg := args[0] 180 | 181 | for _, cmd := range commands { 182 | if cmd.Name() == arg { 183 | tmpl(os.Stdout, helpTemplate, cmd) 184 | // not exit 2: succeeded at 'gitignorer help cmd'. 185 | return 186 | } 187 | } 188 | 189 | errMsg := "Unknown help topic %#q. Run 'gitignorer help'.\n" 190 | fmt.Fprintf(os.Stderr, errMsg, arg) 191 | os.Exit(2) // failed at 'go help cmd' 192 | } 193 | 194 | var atexitFuncs []func() 195 | 196 | func atexit(f func()) { 197 | atexitFuncs = append(atexitFuncs, f) 198 | } 199 | 200 | func exit() { 201 | for _, f := range atexitFuncs { 202 | f() 203 | } 204 | os.Exit(exitStatus) 205 | } 206 | --------------------------------------------------------------------------------