yos/list.go
package yos import ( "os" "path/filepath" "regexp" "strings") // A FilePathInfo describes path and stat of a file or directory.type FilePathInfo struct { Path string Info os.FileInfo} // ListAll returns a list of all entries in the given directory in lexical order. The given directory is not included in the list.//// It searches recursively, but symbolic links other than the given path will be not be followed.func ListAll(root string) (entries []*FilePathInfo, err error) { return listCondEntries(root, func(info os.FileInfo) (bool, error) { return true, nil })} // ListFile returns a list of file entries in the given directory in lexical order. The given directory is not included in the list.//// It searches recursively, but symbolic links other than the given path will be not be followed.func ListFile(root string) (entries []*FilePathInfo, err error) { return listCondEntries(root, func(info os.FileInfo) (bool, error) { return isFileFi(&info), nil })} // ListSymlink returns a list of symbolic link entries in the given directory in lexical order. The given directory is not included in the list.//// It searches recursively, but symbolic links other than the given path will be not be followed.func ListSymlink(root string) (entries []*FilePathInfo, err error) { return listCondEntries(root, func(info os.FileInfo) (bool, error) { return isSymlinkFi(&info), nil })} // ListDir returns a list of nested directory entries in the given directory in lexical order. The given directory is not included in the list.//// It searches recursively, but symbolic links other than the given path will be not be followed.func ListDir(root string) (entries []*FilePathInfo, err error) { return listCondEntries(root, func(info os.FileInfo) (bool, error) { return isDirFi(&info), nil })} // The flags are used by the ListMatch method.const ( // ListRecursive indicates ListMatch to recursively list directory entries encountered. ListRecursive int = 1 << iota // ListToLower indicates ListMatch to convert file name to lower case before the pattern matching. ListToLower // ListUseRegExp indicates ListMatch to use regular expression for the pattern matching. ListUseRegExp // ListIncludeDir indicates ListMatch to include matched directories in the returned list. ListIncludeDir // ListIncludeFile indicates ListMatch to include matched files in the returned list. ListIncludeFile // ListIncludeSymlink indicates ListMatch to include matched symbolic link in the returned list. ListIncludeSymlink) const ( // ListIncludeAll indicates ListMatch to include all the matched in the returned list. ListIncludeAll = ListIncludeDir | ListIncludeFile | ListIncludeSymlink) // ListMatch returns a list of directory entries that matches any given pattern in the directory in lexical order.//// Symbolic links other than the given path will be not be followed. The given directory is not included in the list.//// ListMatch requires the pattern to match the full file name, not just a substring. Errors are returned if any pattern is malformed.//// There are two types of patterns are supported:// 1) wildcard described in filepath.Match(), this is default;// 2) regular expression accepted by google/RE2, use the ListUseRegExp flag to enable;Function `ListMatch` has a Cognitive Complexity of 33 (exceeds 20 allowed). Consider refactoring.func ListMatch(root string, flag int, patterns ...string) (entries []*FilePathInfo, err error) { var ( rePatterns []*regexp.Regexp typeFlag = flag & ListIncludeAll useRegExp = flag&ListUseRegExp != 0 useLowerName = flag&ListToLower != 0 ) if useRegExp { if rePatterns, err = compileRegexpList(patterns); err != nil { return } } return listCondEntries(root, func(info os.FileInfo) (ok bool, err error) { fileName := info.Name() if useLowerName { fileName = strings.ToLower(fileName) } if isFileTypeMatched(&info, typeFlag) { if useRegExp { for _, pat := range rePatterns { if ok = pat.MatchString(fileName); ok { break } } } else { for _, pat := range patterns { if ok, err = filepath.Match(pat, fileName); ok || err != nil { break } } } } if err == nil && (flag&ListRecursive == 0) && isDirFi(&info) { err = filepath.SkipDir } return })} // listCondEntries returns a list of conditional directory entries.func listCondEntries(root string, cond func(os.FileInfo) (bool, error)) (entries []*FilePathInfo, err error) { var ( rootFi os.FileInfo rootPath string ) if rootPath, rootFi, err = resolveDirInfo(root); err != nil { err = opError(opnList, root, err) return } err = filepath.Walk(rootPath, func(itemPath string, itemFi os.FileInfo, errIn error) (errOut error) { errOut = errIn if os.SameFile(rootFi, itemFi) || errOut != nil { return } var ok bool if ok, errOut = cond(itemFi); ok { entries = append(entries, &FilePathInfo{ Path: itemPath, Info: itemFi, }) } return }) return} // isFileTypeMatched checks whether the file type is matched with the flag.func isFileTypeMatched(info *os.FileInfo, flag int) (match bool) { switch { case flag == ListIncludeAll: match = true case flag&ListIncludeDir != 0 && isDirFi(info): match = true case flag&ListIncludeFile != 0 && isFileFi(info): match = true case flag&ListIncludeSymlink != 0 && isSymlinkFi(info): match = true } return}