#!/usr/bin/env bash

set -e

# List ignored files of current directory by constructing a "find"
# expression that matches names of ignored files.
#
# This script supports a reasonable subset of "gitignore(5)"
# semantics.  Notably, it does support:
#  * Patterns read from .gitignore files in current and parent directories
#  * Blank line separators
#  * Leading "#" comments
#  * Trailing "/" directory patterns
#  * Leading "/" this-directory patterns
# and it does not support:
#  * Patterns read from $GIT_DIR/info/exclude
#    (b/c inappropriate for a source release)
#  * Patterns read from file specified by configuration variable core.excludesfile
#    (b/c inappropriate for a source release)
#  * Leading "!" negation patterns
#    (b/c complex semantics)
#  * Internal "/" FNM_PATHNAME patterns
#    (b/c complex semantics incompatible with '-path' primary)

name=$(basename "$0")
dir=$(dirname "$0")
root=$(cd "$dir/.." && pwd)

ignore='.gitignore'

declare -a fargs
fargs+=("(")
fargs+=("-false")
idir="."
while true; do
    if [ -r "$idir/$ignore" ]; then
        while IFS= read -r opat; do
            pat="$opat"
            ## Blank line: Separator -- supported
            if [ -z "$pat" ]; then
                continue
            fi
            ## Leading "#": Comment -- supported
            if [ "${pat:0:1}" = "#" ]; then
                continue
            fi
            ## Leading "\#": Pattern beginning with "#" -- supported
            if [ "${pat:0:2}" = "\#" ]; then
                pat="#${pat:2}"
            fi
            ## Leading "!": Negated pattern -- unsupported
            if [ "${pat:0:1}" = "!" ]; then
                echo "$name:: unsupported pattern: $opat"
                exit 1
            fi
            ## Leading "\!": Pattern beginning with "!" -- supported
            if [ "${pat:0:2}" = "\!" ]; then
                pat="!${pat:2}"
            fi
            ## Trailing "/": Directory pattern -- supported
            if [ "${pat:$((${#pat}-1)):1}" = "/" ]; then
                dirPat="yes"
                pat="${pat:0:$((${#pat}-1))}"
            else
                dirPat="no"
            fi
            ## Leading "/": This-directory pattern -- supported
            if [ "${pat:0:1}" = "/" ]; then
                if [ "$idir" = "." ]; then
                    pat="${pat:1}"
                else
                    continue
                fi
            fi
            ## Internal "/": FNM_PATHNAME pattern -- unsupported
            if [ -z "${pat##*/*}" ]; then
                echo "$name:: unsupported pattern: $opat"
                exit 1
            fi
            fargs+=("-o")
            fargs+=("(")
            if [ "$dirPat" = "yes" ]; then
                fargs+=("-type")
                fargs+=("d")
            fi
            fargs+=("-name")
            fargs+=("$pat")
            fargs+=(")")
        done < "$idir/$ignore"
    fi
    if [ "$(cd "$idir" && pwd)" != "$root" ]; then
        idir="../$idir"
    else
        break
    fi
done
fargs+=(")")

find . -mindepth 1 -maxdepth 1 "${fargs[@]}" -print
