github.com/AndrewDeryabin/doublestar/v4@v4.0.0-20230123132908-d9476b7d41be/globoptions.go (about)

     1  package doublestar
     2  
     3  import "strings"
     4  
     5  // glob is an internal type to store options during globbing.
     6  type glob struct {
     7  	failOnIOErrors        bool
     8  	failOnPatternNotExist bool
     9  	filesOnly             bool
    10  	noFollow              bool
    11  }
    12  
    13  // GlobOption represents a setting that can be passed to Glob, GlobWalk, and
    14  // FilepathGlob.
    15  type GlobOption func(*glob)
    16  
    17  // Construct a new glob object with the given options
    18  func newGlob(opts ...GlobOption) *glob {
    19  	g := &glob{}
    20  	for _, opt := range opts {
    21  		opt(g)
    22  	}
    23  	return g
    24  }
    25  
    26  // WithFailOnIOErrors is an option that can be passed to Glob, GlobWalk, or
    27  // FilepathGlob. If passed, doublestar will abort and return IO errors when
    28  // encountered. Note that if the glob pattern references a path that does not
    29  // exist (such as `nonexistent/path/*`), this is _not_ considered an IO error:
    30  // it is considered a pattern with no matches.
    31  //
    32  func WithFailOnIOErrors() GlobOption {
    33  	return func(g *glob) {
    34  		g.failOnIOErrors = true
    35  	}
    36  }
    37  
    38  // WithFailOnPatternNotExist is an option that can be passed to Glob, GlobWalk,
    39  // or FilepathGlob. If passed, doublestar will abort and return
    40  // ErrPatternNotExist if the pattern references a path that does not exist
    41  // before any meta charcters such as `nonexistent/path/*`. Note that alts (ie,
    42  // `{...}`) are expanded before this check. In other words, a pattern such as
    43  // `{a,b}/*` may fail if either `a` or `b` do not exist but `*/{a,b}` will
    44  // never fail because the star may match nothing.
    45  //
    46  func WithFailOnPatternNotExist() GlobOption {
    47  	return func(g *glob) {
    48  		g.failOnPatternNotExist = true
    49  	}
    50  }
    51  
    52  // WithFilesOnly is an option that can be passed to Glob, GlobWalk, or
    53  // FilepathGlob. If passed, doublestar will only return files that match the
    54  // pattern, not directories.
    55  //
    56  // Note: if combined with the WithNoFollow option, symlinks to directories
    57  // _will_ be included in the result since no attempt is made to follow the
    58  // symlink.
    59  //
    60  func WithFilesOnly() GlobOption {
    61  	return func(g *glob) {
    62  		g.filesOnly = true
    63  	}
    64  }
    65  
    66  // WithNoFollow is an option that can be passed to Glob, GlobWalk, or
    67  // FilepathGlob. If passed, doublestar will not follow symlinks while
    68  // traversing the filesystem. However, due to io/fs's _very_ poor support for
    69  // querying the filesystem about symlinks, there's a caveat here: if part of
    70  // the pattern before any meta characters contains a reference to a symlink, it
    71  // will be followed. For example, a pattern such as `path/to/symlink/*` will be
    72  // followed assuming it is a valid symlink to a directory. However, from this
    73  // same example, a pattern such as `path/to/**` will not traverse the
    74  // `symlink`, nor would `path/*/symlink/*`
    75  //
    76  // Note: if combined with the WithFilesOnly option, symlinks to directories
    77  // _will_ be included in the result since no attempt is made to follow the
    78  // symlink.
    79  //
    80  func WithNoFollow() GlobOption {
    81  	return func(g *glob) {
    82  		g.noFollow = true
    83  	}
    84  }
    85  
    86  // forwardErrIfFailOnIOErrors is used to wrap the return values of I/O
    87  // functions. When failOnIOErrors is enabled, it will return err; otherwise, it
    88  // always returns nil.
    89  //
    90  func (g *glob) forwardErrIfFailOnIOErrors(err error) error {
    91  	if g.failOnIOErrors {
    92  		return err
    93  	}
    94  	return nil
    95  }
    96  
    97  // handleErrNotExist handles fs.ErrNotExist errors. If
    98  // WithFailOnPatternNotExist has been enabled and canFail is true, this will
    99  // return ErrPatternNotExist. Otherwise, it will return nil.
   100  //
   101  func (g *glob) handlePatternNotExist(canFail bool) error {
   102  	if canFail && g.failOnPatternNotExist {
   103  		return ErrPatternNotExist
   104  	}
   105  	return nil
   106  }
   107  
   108  // Format options for debugging/testing purposes
   109  func (g *glob) GoString() string {
   110  	var b strings.Builder
   111  	b.WriteString("opts: ")
   112  
   113  	hasOpts := false
   114  	if g.failOnIOErrors {
   115  		b.WriteString("WithFailOnIOErrors")
   116  		hasOpts = true
   117  	}
   118  	if g.failOnPatternNotExist {
   119  		if hasOpts {
   120  			b.WriteString(", ")
   121  		}
   122  		b.WriteString("WithFailOnPatternNotExist")
   123  		hasOpts = true
   124  	}
   125  	if g.filesOnly {
   126  		if hasOpts {
   127  			b.WriteString(", ")
   128  		}
   129  		b.WriteString("WithFilesOnly")
   130  		hasOpts = true
   131  	}
   132  	if g.noFollow {
   133  		if hasOpts {
   134  			b.WriteString(", ")
   135  		}
   136  		b.WriteString("WithNoFollow")
   137  		hasOpts = true
   138  	}
   139  
   140  	if !hasOpts {
   141  		b.WriteString("nil")
   142  	}
   143  	return b.String()
   144  }