github.com/dnephin/dobi@v0.15.0/utils/fs/directory.go (about) 1 package fs 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "time" 8 9 "github.com/docker/docker/pkg/fileutils" 10 ) 11 12 // LastModifiedSearch provides the means by which to specify your search parameters when 13 // finding the last modified file. 14 type LastModifiedSearch struct { 15 // Root must be set to the absolute path of the directory to traverse. Any 16 // relative paths in Paths and Excludes will be considered relative to this 17 // root directory. 18 Root string 19 Excludes []string 20 Paths []string 21 } 22 23 // LastModified returns the latest modified time for all the files and 24 // directories. The files in each directory are checked for their last modified 25 // time. 26 // TODO: use go routines to speed this up 27 // nolint: gocyclo 28 func LastModified(search *LastModifiedSearch) (time.Time, error) { 29 var latest time.Time 30 var err error 31 32 pm, err := fileutils.NewPatternMatcher(search.Excludes) 33 if err != nil { 34 return time.Time{}, err 35 } 36 37 isExcluded := func(path string) (bool, error) { 38 relPath, err := filepath.Rel(search.Root, path) 39 if err != nil { 40 return false, err 41 } 42 if relPath == "." { 43 // Don't let them exclude everything, kind of silly. 44 return false, nil 45 } 46 return pm.Matches(relPath) 47 } 48 49 walker := func(filePath string, info os.FileInfo, err error) error { 50 if err != nil { 51 if os.IsPermission(err) { 52 return fmt.Errorf("can't stat '%s'", filePath) 53 } 54 return err 55 } 56 57 skip, err := isExcluded(filePath) 58 switch { 59 case err != nil: 60 return err 61 case skip: 62 if info.IsDir() { 63 return filepath.SkipDir 64 } 65 return nil 66 } 67 68 if info.ModTime().After(latest) { 69 latest = info.ModTime() 70 } 71 return nil 72 } 73 74 for _, path := range search.Paths { 75 if !filepath.IsAbs(path) { 76 path = filepath.Join(search.Root, path) 77 } 78 79 info, err := os.Stat(path) 80 if err != nil { 81 return latest, fmt.Errorf("internal error: %w", err) 82 } 83 switch info.IsDir() { 84 case false: 85 skip, err := isExcluded(path) 86 switch { 87 case err != nil: 88 return time.Time{}, err 89 case skip: 90 continue 91 } 92 93 if info.ModTime().After(latest) { 94 latest = info.ModTime() 95 continue 96 } 97 default: 98 if err := filepath.Walk(path, walker); err != nil { 99 return latest, err 100 } 101 } 102 } 103 return latest, nil 104 }