Exemplo n.º 1
0
// Compile takes a list of string filters and returns a Filter interface
// for matching a given string against the filter list. The filter list
// supports glob matching too, ie:
//
//   f, _ := Compile([]string{"cpu", "mem", "net*"})
//   f.Match("cpu")     // true
//   f.Match("network") // true
//   f.Match("memory")  // false
//
func Compile(filters []string) (Filter, error) {
	// return if there is nothing to compile
	if len(filters) == 0 {
		return nil, nil
	}

	// check if we can compile a non-glob filter
	noGlob := true
	for _, filter := range filters {
		if hasMeta(filter) {
			noGlob = false
			break
		}
	}

	switch {
	case noGlob:
		// return non-globbing filter if not needed.
		return compileFilterNoGlob(filters), nil
	case len(filters) == 1:
		return glob.Compile(filters[0])
	default:
		return glob.Compile("{" + strings.Join(filters, ",") + "}")
	}
}
Exemplo n.º 2
0
// Compile compiles a pattern for future use.
func Compile(p *Pattern) (Matcher, error) {
	ret := &pattern{}
	if p == nil {
		return ret, nil
	}
	f := func(slice []string, sep rune) (result []matcher, err error) {
		result = make([]matcher, 0, len(slice))
		for _, s := range slice {
			var (
				ok  bool
				err error
				r   *regexp.Regexp
				g   glob.Glob
			)
			if s == "" {
				result = append(result, plain(""))
				continue
			}
			if s, ok = isRegex(s); ok {
				if r, err = regexp.Compile(s); err != nil {
					return nil, err
				}
				result = append(result, (*regex)(r))
				continue
			}
			if sep != 0 {
				g, err = glob.Compile(s, sep)
			} else {
				g, err = glob.Compile(s)
			}
			if err != nil {
				return nil, err
			}
			result = append(result, g)
		}
		return result, nil
	}
	var err error
	set := func(dst *[]matcher, src []string, sep rune) bool {
		var result []matcher
		if result, err = f(src, sep); err != nil {
			return false
		}
		*dst = result
		return true
	}
	if set(&ret.Accept, p.Accept, '/') &&
		set(&ret.Reject, p.Reject, '/') &&
		set(&ret.Host, p.Host, '.') &&
		set(&ret.ExcludeHost, p.ExcludeHost, '.') &&
		set(&ret.Dir, p.Dir, '/') &&
		set(&ret.ExcludeDir, p.ExcludeDir, '/') &&
		set(&ret.File, p.File, 0) &&
		set(&ret.ExcludeFile, p.ExcludeFile, 0) {

		return ret, nil
	}
	return nil, err
}
Exemplo n.º 3
0
func compileFilter(filter []string) (glob.Glob, error) {
	if len(filter) == 0 {
		return nil, nil
	}
	var g glob.Glob
	var err error
	if len(filter) == 1 {
		g, err = glob.Compile(filter[0])
	} else {
		g, err = glob.Compile("{" + strings.Join(filter, ",") + "}")
	}
	return g, err
}
Exemplo n.º 4
0
func main() {
	pattern := flag.String("p", "", "pattern to draw")
	sep := flag.String("s", "", "comma separated list of separators")
	fixture := flag.String("f", "", "fixture")
	verbose := flag.Bool("v", false, "verbose")
	flag.Parse()

	if *pattern == "" {
		flag.Usage()
		os.Exit(1)
	}

	var separators []rune
	for _, c := range strings.Split(*sep, ",") {
		if r, w := utf8.DecodeRuneInString(c); len(c) > w {
			fmt.Println("only single charactered separators are allowed")
			os.Exit(1)
		} else {
			separators = append(separators, r)
		}
	}

	g, err := glob.Compile(*pattern, separators...)
	if err != nil {
		fmt.Println("could not compile pattern:", err)
		os.Exit(1)
	}

	if !*verbose {
		fmt.Println(g.Match(*fixture))
		return
	}

	fmt.Printf("result: %t\n", g.Match(*fixture))

	cb := testing.Benchmark(func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			glob.Compile(*pattern, separators...)
		}
	})
	fmt.Println("compile:", benchString(cb))

	mb := testing.Benchmark(func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			g.Match(*fixture)
		}
	})
	fmt.Println("match:    ", benchString(mb))
}
Exemplo n.º 5
0
// Glob takes a glob pattern and returns another files object only containing
// matched  files.
//
// This is designed to be called from a template.
//
// {{ range $name, $content := .Files.Glob("foo/**") }}
// {{ $name }}: |
// {{ .Files.Get($name) | indent 4 }}{{ end }}
func (f Files) Glob(pattern string) Files {
	g, err := glob.Compile(pattern, '/')
	if err != nil {
		g, _ = glob.Compile("**")
	}

	nf := NewFiles(nil)
	for name, contents := range f {
		if g.Match(name) {
			nf[name] = contents
		}
	}

	return nf
}
Exemplo n.º 6
0
func main() {
	pattern := flag.String("p", "", "pattern to draw")
	sep := flag.String("s", "", "comma separated list of separators characters")
	flag.Parse()

	if *pattern == "" {
		flag.Usage()
		os.Exit(1)
	}

	var separators []rune
	if len(*sep) > 0 {
		for _, c := range strings.Split(*sep, ",") {
			if r, w := utf8.DecodeRuneInString(c); len(c) > w {
				fmt.Println("only single charactered separators are allowed")
				os.Exit(1)
			} else {
				separators = append(separators, r)
			}
		}
	}

	glob, err := glob.Compile(*pattern, separators...)
	if err != nil {
		fmt.Println("could not compile pattern:", err)
		os.Exit(1)
	}

	matcher := glob.(match.Matcher)
	fmt.Fprint(os.Stdout, debug.Graphviz(*pattern, matcher))
}
Exemplo n.º 7
0
// CompileFilter takes a list of glob "filters", ie:
//   ["MAIN.*", "CPU.*", "NET"]
// and compiles them into a glob object. This glob object can
// then be used to match keys to the filter.
func CompileFilter(filters []string) (glob.Glob, error) {
	var out glob.Glob

	// return if there is nothing to compile
	if len(filters) == 0 {
		return out, nil
	}

	var err error
	if len(filters) == 1 {
		out, err = glob.Compile(filters[0])
	} else {
		out, err = glob.Compile("{" + strings.Join(filters, ",") + "}")
	}
	return out, err
}
Exemplo n.º 8
0
func main() {
	pattern := flag.String("p", "", "pattern to draw")
	sep := flag.String("s", "", "comma separated list of separators")
	fixture := flag.String("f", "", "fixture")
	verbose := flag.Bool("v", false, "verbose")
	flag.Parse()

	if *pattern == "" {
		flag.Usage()
		os.Exit(1)
	}

	separators := strings.Split(*sep, ",")
	g, err := glob.Compile(*pattern, separators...)
	if err != nil {
		fmt.Println("could not compile pattern:", err)
		os.Exit(1)
	}

	if !*verbose {
		fmt.Println(g.Match(*fixture))
		return
	}

	fmt.Printf("result: %t\n", g.Match(*fixture))

	cb := testing.Benchmark(func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			glob.Compile(*pattern, separators...)
		}
	})
	fmt.Println("compile:", benchString(cb))

	mb := testing.Benchmark(func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			g.Match(*fixture)
		}
	})
	fmt.Println("match:    ", benchString(mb))
}
Exemplo n.º 9
0
func main() {
	pattern := flag.String("p", "", "pattern to draw")
	sep := flag.String("s", "", "comma separated list of separators")
	flag.Parse()

	if *pattern == "" {
		flag.Usage()
		os.Exit(1)
	}

	glob, err := glob.Compile(*pattern, strings.Split(*sep, ",")...)
	if err != nil {
		fmt.Println("could not compile pattern:", err)
		os.Exit(1)
	}

	matcher := glob.(match.Matcher)
	fmt.Fprint(os.Stdout, draw(*pattern, matcher))
}
Exemplo n.º 10
0
func Compile(path string) (*GlobPath, error) {
	out := GlobPath{
		hasMeta: hasMeta(path),
		path:    path,
	}

	// if there are no glob meta characters in the path, don't bother compiling
	// a glob object or finding the root directory. (see short-circuit in Match)
	if !out.hasMeta {
		return &out, nil
	}

	var err error
	if out.g, err = glob.Compile(path, os.PathSeparator); err != nil {
		return nil, err
	}
	// Get the root directory for this filepath
	out.root = findRootDir(path)
	return &out, nil
}
Exemplo n.º 11
0
func parseIgnoreFile(fd io.Reader, currentFile string, modtimes map[string]time.Time) ([]Pattern, error) {
	var patterns []Pattern

	defaultResult := resultInclude
	if runtime.GOOS == "darwin" || runtime.GOOS == "windows" {
		defaultResult |= resultFoldCase
	}

	addPattern := func(line string) error {
		pattern := Pattern{
			result: defaultResult,
		}

		// Allow prefixes to be specified in any order, but only once.
		var seenPrefix [3]bool

		for {
			if strings.HasPrefix(line, "!") && !seenPrefix[0] {
				seenPrefix[0] = true
				line = line[1:]
				pattern.result ^= resultInclude
			} else if strings.HasPrefix(line, "(?i)") && !seenPrefix[1] {
				seenPrefix[1] = true
				pattern.result |= resultFoldCase
				line = line[4:]
			} else if strings.HasPrefix(line, "(?d)") && !seenPrefix[2] {
				seenPrefix[2] = true
				pattern.result |= resultDeletable
				line = line[4:]
			} else {
				break
			}
		}

		if pattern.result.IsCaseFolded() {
			line = strings.ToLower(line)
		}

		pattern.pattern = line

		var err error
		if strings.HasPrefix(line, "/") {
			// Pattern is rooted in the current dir only
			pattern.match, err = glob.Compile(line[1:], '/')
			if err != nil {
				return fmt.Errorf("invalid pattern %q in ignore file (%v)", line, err)
			}
			patterns = append(patterns, pattern)
		} else if strings.HasPrefix(line, "**/") {
			// Add the pattern as is, and without **/ so it matches in current dir
			pattern.match, err = glob.Compile(line, '/')
			if err != nil {
				return fmt.Errorf("invalid pattern %q in ignore file (%v)", line, err)
			}
			patterns = append(patterns, pattern)

			line = line[3:]
			pattern.pattern = line
			pattern.match, err = glob.Compile(line, '/')
			if err != nil {
				return fmt.Errorf("invalid pattern %q in ignore file (%v)", line, err)
			}
			patterns = append(patterns, pattern)
		} else if strings.HasPrefix(line, "#include ") {
			includeRel := line[len("#include "):]
			includeFile := filepath.Join(filepath.Dir(currentFile), includeRel)
			includes, err := loadIgnoreFile(includeFile, modtimes)
			if err != nil {
				return fmt.Errorf("include of %q: %v", includeRel, err)
			}
			patterns = append(patterns, includes...)
		} else {
			// Path name or pattern, add it so it matches files both in
			// current directory and subdirs.
			pattern.match, err = glob.Compile(line, '/')
			if err != nil {
				return fmt.Errorf("invalid pattern %q in ignore file (%v)", line, err)
			}
			patterns = append(patterns, pattern)

			line := "**/" + line
			pattern.pattern = line
			pattern.match, err = glob.Compile(line, '/')
			if err != nil {
				return fmt.Errorf("invalid pattern %q in ignore file (%v)", line, err)
			}
			patterns = append(patterns, pattern)
		}
		return nil
	}

	scanner := bufio.NewScanner(fd)
	var err error
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		switch {
		case line == "":
			continue
		case strings.HasPrefix(line, "//"):
			continue
		}

		line = filepath.ToSlash(line)
		switch {
		case strings.HasPrefix(line, "#"):
			err = addPattern(line)
		case strings.HasSuffix(line, "/**"):
			err = addPattern(line)
		case strings.HasSuffix(line, "/"):
			err = addPattern(line + "**")
		default:
			err = addPattern(line)
			if err == nil {
				err = addPattern(line + "/**")
			}
		}
		if err != nil {
			return nil, err
		}
	}

	return patterns, nil
}
Exemplo n.º 12
0
func parseIgnoreFile(fd io.Reader, currentFile string, seen map[string]bool) ([]Pattern, error) {
	var patterns []Pattern

	addPattern := func(line string) error {
		pattern := Pattern{
			pattern:  line,
			include:  true,
			foldCase: runtime.GOOS == "darwin" || runtime.GOOS == "windows",
		}

		if strings.HasPrefix(line, "!") {
			line = line[1:]
			pattern.include = false
		}

		if strings.HasPrefix(line, "(?i)") {
			pattern.foldCase = true
			line = line[4:]
		}

		if pattern.foldCase {
			line = strings.ToLower(line)
		}

		var err error
		if strings.HasPrefix(line, "/") {
			// Pattern is rooted in the current dir only
			pattern.match, err = glob.Compile(line[1:])
			if err != nil {
				return fmt.Errorf("invalid pattern %q in ignore file", line)
			}
			patterns = append(patterns, pattern)
		} else if strings.HasPrefix(line, "**/") {
			// Add the pattern as is, and without **/ so it matches in current dir
			pattern.match, err = glob.Compile(line)
			if err != nil {
				return fmt.Errorf("invalid pattern %q in ignore file", line)
			}
			patterns = append(patterns, pattern)

			line = line[3:]
			pattern.pattern = line
			pattern.match, err = glob.Compile(line)
			if err != nil {
				return fmt.Errorf("invalid pattern %q in ignore file", line)
			}
			patterns = append(patterns, pattern)
		} else if strings.HasPrefix(line, "#include ") {
			includeRel := line[len("#include "):]
			includeFile := filepath.Join(filepath.Dir(currentFile), includeRel)
			includes, err := loadIgnoreFile(includeFile, seen)
			if err != nil {
				return fmt.Errorf("include of %q: %v", includeRel, err)
			}
			patterns = append(patterns, includes...)
		} else {
			// Path name or pattern, add it so it matches files both in
			// current directory and subdirs.
			pattern.match, err = glob.Compile(line)
			if err != nil {
				return fmt.Errorf("invalid pattern %q in ignore file", line)
			}
			patterns = append(patterns, pattern)

			line := "**/" + line
			pattern.pattern = line
			pattern.match, err = glob.Compile(line)
			if err != nil {
				return fmt.Errorf("invalid pattern %q in ignore file", line)
			}
			patterns = append(patterns, pattern)
		}
		return nil
	}

	scanner := bufio.NewScanner(fd)
	var err error
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		switch {
		case line == "":
			continue
		case strings.HasPrefix(line, "//"):
			continue
		}

		line = filepath.ToSlash(line)
		switch {
		case strings.HasPrefix(line, "#"):
			err = addPattern(line)
		case strings.HasSuffix(line, "/**"):
			err = addPattern(line)
		case strings.HasSuffix(line, "/"):
			err = addPattern(line)
		default:
			err = addPattern(line)
			if err == nil {
				err = addPattern(line + "/**")
			}
		}
		if err != nil {
			return nil, err
		}
	}

	return patterns, nil
}