diff options
| author | Petter Rasmussen | 2016-04-17 13:11:19 +0200 | 
|---|---|---|
| committer | Petter Rasmussen | 2016-04-17 13:11:19 +0200 | 
| commit | 97981f7fd205353907135eacfc0e0ade24b88269 (patch) | |
| tree | 1fdb61a7138642a1612bb201434e8ebda141cc8a /vendor/github.com/sabhiram/go-git-ignore/ignore.go | |
| parent | 8de8e05c483c6b5f23b14742315f1860211dcef7 (diff) | |
| parent | b5eb2866cfceb69b0d4dd4948273d679a884fbb2 (diff) | |
| download | gdrive-97981f7fd205353907135eacfc0e0ade24b88269.tar.bz2 | |
Merge pull request #140 from paulz/godep
add Go dependencies by godep
Diffstat (limited to 'vendor/github.com/sabhiram/go-git-ignore/ignore.go')
| -rw-r--r-- | vendor/github.com/sabhiram/go-git-ignore/ignore.go | 200 | 
1 files changed, 200 insertions, 0 deletions
| diff --git a/vendor/github.com/sabhiram/go-git-ignore/ignore.go b/vendor/github.com/sabhiram/go-git-ignore/ignore.go new file mode 100644 index 0000000..e3241b2 --- /dev/null +++ b/vendor/github.com/sabhiram/go-git-ignore/ignore.go @@ -0,0 +1,200 @@ +/* +ignore is a library which returns a new ignorer object which can +test against various paths. This is particularly useful when trying +to filter files based on a .gitignore document + +The rules for parsing the input file are the same as the ones listed +in the Git docs here: http://git-scm.com/docs/gitignore + +The summarized version of the same has been copied here: + +    1. A blank line matches no files, so it can serve as a separator +       for readability. +    2. A line starting with # serves as a comment. Put a backslash ("\") +       in front of the first hash for patterns that begin with a hash. +    3. Trailing spaces are ignored unless they are quoted with backslash ("\"). +    4. An optional prefix "!" which negates the pattern; any matching file +       excluded by a previous pattern will become included again. It is not +       possible to re-include a file if a parent directory of that file is +       excluded. Git doesn’t list excluded directories for performance reasons, +       so any patterns on contained files have no effect, no matter where they +       are defined. Put a backslash ("\") in front of the first "!" for +       patterns that begin with a literal "!", for example, "\!important!.txt". +    5. If the pattern ends with a slash, it is removed for the purpose of the +       following description, but it would only find a match with a directory. +       In other words, foo/ will match a directory foo and paths underneath it, +       but will not match a regular file or a symbolic link foo (this is +       consistent with the way how pathspec works in general in Git). +    6. If the pattern does not contain a slash /, Git treats it as a shell glob +       pattern and checks for a match against the pathname relative to the +       location of the .gitignore file (relative to the toplevel of the work +       tree if not from a .gitignore file). +    7. Otherwise, Git treats the pattern as a shell glob suitable for +       consumption by fnmatch(3) with the FNM_PATHNAME flag: wildcards in the +       pattern will not match a / in the pathname. For example, +       "Documentation/*.html" matches "Documentation/git.html" but not +       "Documentation/ppc/ppc.html" or "tools/perf/Documentation/perf.html". +    8. A leading slash matches the beginning of the pathname. For example, +       "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c". +    9. Two consecutive asterisks ("**") in patterns matched against full +       pathname may have special meaning: +        i.   A leading "**" followed by a slash means match in all directories. +             For example, "** /foo" matches file or directory "foo" anywhere, +             the same as pattern "foo". "** /foo/bar" matches file or directory +             "bar" anywhere that is directly under directory "foo". +        ii.  A trailing "/**" matches everything inside. For example, "abc/**" +             matches all files inside directory "abc", relative to the location +             of the .gitignore file, with infinite depth. +        iii. A slash followed by two consecutive asterisks then a slash matches +             zero or more directories. For example, "a/** /b" matches "a/b", +             "a/x/b", "a/x/y/b" and so on. +        iv.  Other consecutive asterisks are considered invalid. */ +package ignore + +import ( +	"io/ioutil" +	"os" +	"regexp" +	"strings" +) + +// An IgnoreParser is an interface which exposes two methods: +//   MatchesPath() - Returns true if the path is targeted by the patterns compiled in the GitIgnore structure +type IgnoreParser interface { +	IncludesPath(f string) bool +	IgnoresPath(f string) bool +	MatchesPath(f string) bool +} + +// GitIgnore is a struct which contains a slice of regexp.Regexp +// patterns +type GitIgnore struct { +	patterns []*regexp.Regexp // List of regexp patterns which this ignore file applies +	negate   []bool           // List of booleans which determine if the pattern is negated +} + +// This function pretty much attempts to mimic the parsing rules +// listed above at the start of this file +func getPatternFromLine(line string) (*regexp.Regexp, bool) { +	// Trim OS-specific carriage returns. +	line = strings.TrimRight(line, "\r") + +	// Strip comments [Rule 2] +	if strings.HasPrefix(line, `#`) { +		return nil, false +	} + +	// Trim string [Rule 3] +	// TODO: Handle [Rule 3], when the " " is escaped with a \ +	line = strings.Trim(line, " ") + +	// Exit for no-ops and return nil which will prevent us from +	// appending a pattern against this line +	if line == "" { +		return nil, false +	} + +	// TODO: Handle [Rule 4] which negates the match for patterns leading with "!" +	negatePattern := false +	if line[0] == '!' { +		negatePattern = true +		line = line[1:] +	} + +	// Handle [Rule 2, 4], when # or ! is escaped with a \ +	// Handle [Rule 4] once we tag negatePattern, strip the leading ! char +	if regexp.MustCompile(`^(\#|\!)`).MatchString(line) { +		line = line[1:] +	} + +	// If we encounter a foo/*.blah in a folder, prepend the / char +	if regexp.MustCompile(`([^\/+])/.*\*\.`).MatchString(line) && line[0] != '/' { +		line = "/" + line +	} + +	// Handle escaping the "." char +	line = regexp.MustCompile(`\.`).ReplaceAllString(line, `\.`) + +	magicStar := "#$~" + +	// Handle "/**/" usage +	if strings.HasPrefix(line, "/**/") { +		line = line[1:] +	} +	line = regexp.MustCompile(`/\*\*/`).ReplaceAllString(line, `(/|/.+/)`) +	line = regexp.MustCompile(`\*\*/`).ReplaceAllString(line, `(|.`+magicStar+`/)`) +	line = regexp.MustCompile(`/\*\*`).ReplaceAllString(line, `(|/.`+magicStar+`)`) + +	// Handle escaping the "*" char +	line = regexp.MustCompile(`\\\*`).ReplaceAllString(line, `\`+magicStar) +	line = regexp.MustCompile(`\*`).ReplaceAllString(line, `([^/]*)`) + +	// Handle escaping the "?" char +	line = strings.Replace(line, "?", `\?`, -1) + +	line = strings.Replace(line, magicStar, "*", -1) + +	// Temporary regex +	var expr = "" +	if strings.HasSuffix(line, "/") { +		expr = line + "(|.*)$" +	} else { +		expr = line + "(|/.*)$" +	} +	if strings.HasPrefix(expr, "/") { +		expr = "^(|/)" + expr[1:] +	} else { +		expr = "^(|.*/)" + expr +	} +	pattern, _ := regexp.Compile(expr) + +	return pattern, negatePattern +} + +// Accepts a variadic set of strings, and returns a GitIgnore object which +// converts and appends the lines in the input to regexp.Regexp patterns +// held within the GitIgnore objects "patterns" field +func CompileIgnoreLines(lines ...string) (*GitIgnore, error) { +	g := new(GitIgnore) +	for _, line := range lines { +		pattern, negatePattern := getPatternFromLine(line) +		if pattern != nil { +			g.patterns = append(g.patterns, pattern) +			g.negate = append(g.negate, negatePattern) +		} +	} +	return g, nil +} + +// Accepts a ignore file as the input, parses the lines out of the file +// and invokes the CompileIgnoreLines method +func CompileIgnoreFile(fpath string) (*GitIgnore, error) { +	buffer, error := ioutil.ReadFile(fpath) +	if error == nil { +		s := strings.Split(string(buffer), "\n") +		return CompileIgnoreLines(s...) +	} +	return nil, error +} + +// MatchesPath is an interface function for the IgnoreParser interface. +// It returns true if the given GitIgnore structure would target a given +// path string "f" +func (g GitIgnore) MatchesPath(f string) bool { +	// Replace OS-specific path separator. +	f = strings.Replace(f, string(os.PathSeparator), "/", -1) + +	matchesPath := false +	for idx, pattern := range g.patterns { +		if pattern.MatchString(f) { +			// If this is a regular target (not negated with a gitignore exclude "!" etc) +			if !g.negate[idx] { +				matchesPath = true +				// Negated pattern, and matchesPath is already set +			} else if matchesPath { +				matchesPath = false +			} +		} +	} +	return matchesPath +} | 
