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 }