├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── joe.go ├── tool.sh └── utils.go /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # Unix-style newlines with a newline ending every file 5 | [*] 6 | end_of_line = lf 7 | insert_final_newline = true 8 | 9 | # Matches multiple files with brace expansion notation 10 | # Set default charset 11 | [*.{py}] 12 | charset = utf-8 13 | 14 | # 4 space indentation 15 | [*.py] 16 | indent_style = space 17 | indent_size = 2 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #### joe made this: http://goel.io/joe 2 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 3 | *.o 4 | *.a 5 | *.so 6 | 7 | # Folders 8 | _obj 9 | _test 10 | 11 | # Architecture specific extensions/prefixes 12 | *.[568vq] 13 | [568vq].out 14 | 15 | *.cgo1.go 16 | *.cgo2.c 17 | _cgo_defun.c 18 | _cgo_gotypes.go 19 | _cgo_export.* 20 | 21 | _testmain.go 22 | 23 | *.exe 24 | *.test 25 | *.prof 26 | 27 | build/ 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Karan Goel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do 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 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](http://i.imgur.com/y8g506n.png?1) 2 | 3 | # joe 4 | 5 | A `.gitignore` magician in your command line. Joe generates `.gitignore` files from the command line for you. 6 | 7 | ![](http://i.imgur.com/2tAksHG.gif) 8 | 9 | ## Features 10 | 11 | - Written in uncomplicated Go (Golang) 12 | - No installation necessary - just use the [binary](https://github.com/karan/joe#installation). 13 | - Stupidly [easy to use](https://github.com/karan/joe#usage) 14 | - Supports all Github-supported [`.gitignore` files](https://github.com/karan/joe#list-all-available-files) 15 | - Works on Mac, Linux and (maybe) Windows 16 | - Supports other version control systems (`.hgignore`) 17 | 18 | ## Installation 19 | 20 | After install, make sure to run `joe u`. This will download all `.gitignore` files in `~/joe-data/` folder. 21 | 22 | ### Option 1: Binary 23 | 24 | `joe` is available for OSX (macOS), Linux and Windows. 25 | 26 | Download the latest binary from the [Releases page](https://github.com/karan/joe/releases). It's the easiest way to get started with `joe`. 27 | 28 | Make sure to add the location of the binary to your `$PATH`. 29 | 30 | ### Option 2: From source 31 | 32 | ```bash 33 | $ git clone git@github.com:karan/joe.git 34 | $ cd joe/ 35 | $ chmod +x tool.sh 36 | $ ./tool.sh build 37 | ``` 38 | 39 | ## Usage 40 | 41 | ### Commands: 42 | 43 | ``` 44 | ls | list list all available files 45 | u | update update all available gitignore files 46 | g | generate generate gitignore files 47 | ``` 48 | 49 | ### Basic usage 50 | 51 | ```bash 52 | $ joe g java # outputs .gitignore file for java to stdout 53 | ``` 54 | 55 | To update your `.gitignore` files at any time, simply run: 56 | 57 | ```bash 58 | $ joe u 59 | ``` 60 | 61 | ### Overwrite existing `.gitignore` file 62 | 63 | ```bash 64 | $ joe g java > .gitignore # saves a new .gitignore file for java 65 | ``` 66 | 67 | ### Append to existing `.gitignore` file 68 | 69 | ```bash 70 | $ joe g java >> .gitignore # appends to an existing .gitignore file 71 | ``` 72 | 73 | ### Multiple languages 74 | 75 | ```bash 76 | $ joe g java,node,osx > .gitignore # saves a new .gitignore file for multiple languages 77 | ``` 78 | 79 | ### Create and append to a global .gitignore file 80 | 81 | You can also use joe to append to a global .gitignore. These can be helpful when you want to ignore files generated by an IDE, OS, or otherwise. 82 | 83 | ```bash 84 | $ git config --global core.excludesfile ~/.gitignore # Optional if you have not yet created a global .gitignore 85 | $ joe g OSX,SublimeText >> ~/.gitignore 86 | ``` 87 | 88 | ### List all available files 89 | 90 | ```bash 91 | $ joe ls # OR `joe list` 92 | ``` 93 | 94 | Output: 95 | 96 | > actionscript, ada, agda, android, anjuta, appceleratortitanium, archives, archlinuxpackages, autotools, bricxcc, c, c++, cakephp, cfwheels, chefcookbook, clojure, cloud9, cmake, codeigniter, codekit, commonlisp, composer, concrete5, coq, craftcms, cvs, dart, darteditor, delphi, dm, dreamweaver, drupal, eagle, eclipse, eiffelstudio, elisp, elixir, emacs, ensime, episerver, erlang, espresso, expressionengine, extjs, fancy, finale, flexbuilder, forcedotcom, fortran, fuelphp, gcov, gitbook, go, gradle, grails, gwt, haskell, idris, igorpro, ipythonnotebook, java, jboss, jdeveloper, jekyll, jetbrains, joomla, jython, kate, kdevelop4, kohana, labview, laravel, lazarus, leiningen, lemonstand, libreoffice, lilypond, linux, lithium, lua, lyx, magento, matlab, maven, mercurial, mercury, metaprogrammingsystem, meteor, microsoftoffice, modelsim, momentics, monodevelop, nanoc, netbeans, nim, ninja, node, notepadpp, objective-c, ocaml, opa, opencart, oracleforms, osx, packer, perl, phalcon, playframework, plone, prestashop, processing, python, qooxdoo, qt, r, rails, redcar, redis, rhodesrhomobile, ros, ruby, rust, sass, sbt, scala, scons, scrivener, sdcc, seamgen, sketchup, slickedit, stella, sublimetext, sugarcrm, svn, swift, symfony, symphonycms, tags, tex, textmate, textpattern, tortoisegit, turbogears2, typo3, umbraco, unity, vagrant, vim, virtualenv, visualstudio, vvvv, waf, webmethods, windows, wordpress, xcode, xilinxise, xojo, yeoman, yii, zendframework, zephir 97 | 98 | ### BONUS ROUND: Alternate version control software 99 | 100 | Joe isn't **just** a generator for `.gitignore` files. You can use it and its output wherever a SCM is used. 101 | 102 | ```bash 103 | $ joe g java > .hgignore 104 | ``` 105 | 106 | ## Contributing 107 | 108 | #### Bug Reports & Feature Requests 109 | 110 | Please use the [issue tracker](https://github.com/karan/joe/issues) to report any bugs or file feature requests. 111 | 112 | #### Developing 113 | 114 | PRs are welcome. To begin developing, do this: 115 | 116 | ```bash 117 | $ git clone git@github.com:karan/joe.git 118 | $ cd joe/ 119 | $ go run *.go 120 | ``` 121 | 122 | #### `tool.sh` 123 | 124 | This is a handy script that automates a lot of developing steps. 125 | 126 | 127 | ```bash 128 | USAGE: 129 | $ $tool [-h|--help] COMMAND 130 | 131 | EXAMPLES: 132 | $ $tool deps Install dependencies for joe 133 | $ $tool build Build a binary 134 | $ $tool run Build and run the binary 135 | ``` 136 | -------------------------------------------------------------------------------- /joe.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/codegangsta/cli" 6 | "io/ioutil" 7 | "log" 8 | "os" 9 | "path" 10 | "path/filepath" 11 | "sort" 12 | "strings" 13 | ) 14 | 15 | const joe string = ` 16 | ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ 17 | ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌ 18 | ▀▀▀▀▀█░█▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀▀▀ 19 | ▐░▌ ▐░▌ ▐░▌▐░▌ 20 | ▐░▌ ▐░▌ ▐░▌▐░█▄▄▄▄▄▄▄▄▄ 21 | ▐░▌ ▐░▌ ▐░▌▐░░░░░░░░░░░▌ 22 | ▐░▌ ▐░▌ ▐░▌▐░█▀▀▀▀▀▀▀▀▀ 23 | ▐░▌ ▐░▌ ▐░▌▐░▌ 24 | ▄▄▄▄▄█░▌ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄▄▄ 25 | ▐░░░░░░░▌ ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌ 26 | ▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ 27 | ` 28 | const version string = "1.0.0" 29 | const gitignoreUrl = "https://github.com/github/gitignore/archive/master.zip" 30 | const dataDir string = ".joe-data" 31 | 32 | var dataPath = path.Join(os.Getenv("HOME"), dataDir) 33 | 34 | func findGitignores() (a map[string]string, err error) { 35 | _, err = ioutil.ReadDir(dataPath) 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | filelist := make(map[string]string) 41 | filepath.Walk(dataPath, func(filepath string, info os.FileInfo, err error) error { 42 | if strings.HasSuffix(info.Name(), ".gitignore") { 43 | name := strings.ToLower(strings.Replace(info.Name(), ".gitignore", "", 1)) 44 | filelist[name] = filepath 45 | } 46 | return nil 47 | }) 48 | return filelist, nil 49 | } 50 | 51 | func availableFiles() (a []string, err error) { 52 | gitignores, err := findGitignores() 53 | if err != nil { 54 | return nil, err 55 | } 56 | 57 | availableGitignores := []string{} 58 | for key, _ := range gitignores { 59 | availableGitignores = append(availableGitignores, key) 60 | } 61 | 62 | return availableGitignores, nil 63 | } 64 | 65 | func generate(args string) { 66 | names := strings.Split(args, ",") 67 | 68 | gitignores, err := findGitignores() 69 | if err != nil { 70 | log.Fatal(err) 71 | } 72 | 73 | notFound := []string{} 74 | output := "" 75 | for index, name := range names { 76 | if filepath, ok := gitignores[strings.ToLower(name)]; ok { 77 | bytes, err := ioutil.ReadFile(filepath) 78 | if err == nil { 79 | output += "\n#### " + name + " ####\n" 80 | output += string(bytes) 81 | if index < len(names) - 1 { 82 | output += "\n" 83 | } 84 | continue 85 | } 86 | } else { 87 | notFound = append(notFound, name) 88 | } 89 | } 90 | 91 | if len(notFound) > 0 { 92 | fmt.Printf("Unsupported files: %s\n", strings.Join(notFound, ", ")) 93 | fmt.Println("Run `joe ls` to see list of available gitignores.") 94 | output = "" 95 | } 96 | if len(output) > 0 { 97 | output = "#### joe made this: http://goel.io/joe\n" + output 98 | } 99 | fmt.Print(output) 100 | } 101 | 102 | func main() { 103 | app := cli.NewApp() 104 | app.Name = joe 105 | app.Usage = "generate .gitignore files from the command line" 106 | app.UsageText = "joe command [arguments...]" 107 | app.Version = version 108 | app.Commands = []cli.Command{ 109 | { 110 | Name: "ls", 111 | Aliases: []string{"list"}, 112 | Usage: "list all available files", 113 | Action: func(c *cli.Context) error { 114 | availableGitignores, err := availableFiles() 115 | if err != nil { 116 | log.Fatal(err) 117 | return err 118 | } 119 | fmt.Printf("%d supported .gitignore files:\n", len(availableGitignores)) 120 | sort.Strings(availableGitignores) 121 | fmt.Printf("%s\n", strings.Join(availableGitignores, ", ")) 122 | return nil 123 | }, 124 | }, 125 | { 126 | Name: "u", 127 | Aliases: []string{"update"}, 128 | Usage: "update all available gitignore files", 129 | Action: func(c *cli.Context) error { 130 | fmt.Println("Updating gitignore files..") 131 | err := RemoveContents(dataPath) 132 | if err != nil { 133 | log.Fatal(err) 134 | } 135 | err = DownloadFiles(gitignoreUrl, dataPath) 136 | if err != nil { 137 | log.Fatal(err) 138 | return err 139 | } 140 | return nil 141 | }, 142 | }, 143 | { 144 | Name: "g", 145 | Aliases: []string{"generate"}, 146 | Usage: "generate gitignore files", 147 | Action: func(c *cli.Context) error { 148 | if c.NArg() != 1 { 149 | cli.ShowAppHelp(c) 150 | } else { 151 | generate(c.Args()[0]) 152 | } 153 | return nil 154 | }, 155 | }, 156 | } 157 | app.Run(os.Args) 158 | } 159 | -------------------------------------------------------------------------------- /tool.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | function usage { 5 | local tool=$(basename $0) 6 | cat <