| 1 | #!/usr/bin/env bash |
| 2 | |
| 3 | set -e |
| 4 | |
| 5 | # List ignored files of current directory by constructing a "find" |
| 6 | # expression that matches names of ignored files. |
| 7 | # |
| 8 | # This script supports a reasonable subset of "gitignore(5)" |
| 9 | # semantics. Notably, it does support: |
| 10 | # * Patterns read from .gitignore files in current and parent directories |
| 11 | # * Blank line separators |
| 12 | # * Leading "#" comments |
| 13 | # * Trailing "/" directory patterns |
| 14 | # * Leading "/" this-directory patterns |
| 15 | # and it does not support: |
| 16 | # * Patterns read from $GIT_DIR/info/exclude |
| 17 | # (b/c inappropriate for a source release) |
| 18 | # * Patterns read from file specified by configuration variable core.excludesfile |
| 19 | # (b/c inappropriate for a source release) |
| 20 | # * Leading "!" negation patterns |
| 21 | # (b/c complex semantics) |
| 22 | # * Internal "/" FNM_PATHNAME patterns |
| 23 | # (b/c complex semantics incompatible with '-path' primary) |
| 24 | |
| 25 | name=$(basename "$0") |
| 26 | dir=$(dirname "$0") |
| 27 | root=$(cd "$dir/.." && pwd) |
| 28 | |
| 29 | ignore='.gitignore' |
| 30 | |
| 31 | declare -a fargs |
| 32 | fargs+=("(") |
| 33 | fargs+=("-exec") |
| 34 | fargs+=("false") |
| 35 | fargs+=(";") |
| 36 | idir="." |
| 37 | while true; do |
| 38 | if [ -r "$idir/$ignore" ]; then |
| 39 | while IFS= read -r opat; do |
| 40 | pat="$opat" |
| 41 | ## Blank line: Separator -- supported |
| 42 | if [ -z "$pat" ]; then |
| 43 | continue |
| 44 | fi |
| 45 | ## Leading "#": Comment -- supported |
| 46 | if [ "${pat:0:1}" = "#" ]; then |
| 47 | continue |
| 48 | fi |
| 49 | ## Leading "\#": Pattern beginning with "#" -- supported |
| 50 | if [ "${pat:0:2}" = "\#" ]; then |
| 51 | pat="#${pat:2}" |
| 52 | fi |
| 53 | ## Leading "!": Negated pattern -- unsupported |
| 54 | if [ "${pat:0:1}" = "!" ]; then |
| 55 | echo "$name:: unsupported pattern: $opat" |
| 56 | exit 1 |
| 57 | fi |
| 58 | ## Leading "\!": Pattern beginning with "!" -- supported |
| 59 | if [ "${pat:0:2}" = "\!" ]; then |
| 60 | pat="!${pat:2}" |
| 61 | fi |
| 62 | ## Trailing "/": Directory pattern -- supported |
| 63 | if [ "${pat:$((${#pat}-1)):1}" = "/" ]; then |
| 64 | dirPat="yes" |
| 65 | pat="${pat:0:$((${#pat}-1))}" |
| 66 | else |
| 67 | dirPat="no" |
| 68 | fi |
| 69 | ## Leading "/": This-directory pattern -- supported |
| 70 | if [ "${pat:0:1}" = "/" ]; then |
| 71 | if [ "$idir" = "." ]; then |
| 72 | pat="${pat:1}" |
| 73 | else |
| 74 | continue |
| 75 | fi |
| 76 | fi |
| 77 | ## Internal "/": FNM_PATHNAME pattern -- unsupported |
| 78 | if [ -z "${pat##*/*}" ]; then |
| 79 | echo "$name:: unsupported pattern: $opat" |
| 80 | exit 1 |
| 81 | fi |
| 82 | fargs+=("-o") |
| 83 | fargs+=("(") |
| 84 | if [ "$dirPat" = "yes" ]; then |
| 85 | fargs+=("-type") |
| 86 | fargs+=("d") |
| 87 | fi |
| 88 | fargs+=("-name") |
| 89 | fargs+=("$pat") |
| 90 | fargs+=(")") |
| 91 | done < "$idir/$ignore" |
| 92 | fi |
| 93 | if [ "$(cd "$idir" && pwd)" != "$root" ]; then |
| 94 | idir="../$idir" |
| 95 | else |
| 96 | break |
| 97 | fi |
| 98 | done |
| 99 | fargs+=(")") |
| 100 | |
| 101 | find . -mindepth 1 -maxdepth 1 "${fargs[@]}" -print |