github.com/influxdata/telegraf@v1.30.3/internal/globpath/globpath.go (about)

     1  package globpath
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"strings"
     7  
     8  	"github.com/bmatcuk/doublestar/v3"
     9  	"github.com/gobwas/glob"
    10  )
    11  
    12  type GlobPath struct {
    13  	path         string
    14  	hasMeta      bool
    15  	HasSuperMeta bool
    16  	rootGlob     string
    17  	g            glob.Glob
    18  }
    19  
    20  func Compile(path string) (*GlobPath, error) {
    21  	out := GlobPath{
    22  		hasMeta:      hasMeta(path),
    23  		HasSuperMeta: hasSuperMeta(path),
    24  		path:         filepath.FromSlash(path),
    25  	}
    26  
    27  	// if there are no glob meta characters in the path, don't bother compiling
    28  	// a glob object
    29  	if !out.hasMeta || !out.HasSuperMeta {
    30  		return &out, nil
    31  	}
    32  
    33  	// find the root elements of the object path, the entry point for recursion
    34  	// when you have a super-meta in your path (which are :
    35  	// glob(/your/expression/until/first/star/of/super-meta))
    36  	out.rootGlob = path[:strings.Index(path, "**")+1]
    37  	var err error
    38  	if out.g, err = glob.Compile(path, os.PathSeparator); err != nil {
    39  		return nil, err
    40  	}
    41  	return &out, nil
    42  }
    43  
    44  // Match returns all files matching the expression.
    45  // If it's a static path, returns path.
    46  // All returned path will have the host platform separator.
    47  func (g *GlobPath) Match() []string {
    48  	// This string replacement is for backwards compatibility support
    49  	// The original implementation allowed **.txt but the double star package requires **/**.txt
    50  	g.path = strings.ReplaceAll(g.path, "**/**", "**")
    51  	g.path = strings.ReplaceAll(g.path, "**", "**/**")
    52  
    53  	files, _ := doublestar.Glob(g.path)
    54  	return files
    55  }
    56  
    57  // MatchString tests the path string against the glob.  The path should contain
    58  // the host platform separator.
    59  func (g *GlobPath) MatchString(path string) bool {
    60  	if !g.HasSuperMeta {
    61  		res, _ := filepath.Match(g.path, path)
    62  		return res
    63  	}
    64  	return g.g.Match(path)
    65  }
    66  
    67  // GetRoots returns a list of files and directories which should be optimal
    68  // prefixes of matching files when you have a super-meta in your expression :
    69  // - any directory under these roots may contain a matching file
    70  // - no file outside of these roots can match the pattern
    71  // Note that it returns both files and directories.
    72  // All returned path will have the host platform separator.
    73  func (g *GlobPath) GetRoots() []string {
    74  	if !g.hasMeta {
    75  		return []string{g.path}
    76  	}
    77  	if !g.HasSuperMeta {
    78  		matches, _ := filepath.Glob(g.path)
    79  		return matches
    80  	}
    81  	roots, _ := filepath.Glob(g.rootGlob)
    82  	return roots
    83  }
    84  
    85  // hasMeta reports whether path contains any magic glob characters.
    86  func hasMeta(path string) bool {
    87  	return strings.ContainsAny(path, "*?[")
    88  }
    89  
    90  // hasSuperMeta reports whether path contains any super magic glob characters (**).
    91  func hasSuperMeta(path string) bool {
    92  	return strings.Contains(path, "**")
    93  }