// 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, ",") + "}") } }
// 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 }
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 }
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)) }
// 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 }
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)) }
// 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 }
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)) }
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)) }
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 }
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 }
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 }