github.com/tilt-dev/wat@v0.0.2-0.20180626175338-9349b638e250/cli/wat/recent.go (about) 1 package wat 2 3 import ( 4 "fmt" 5 "regexp" 6 "time" 7 8 "sort" 9 10 "os" 11 "path/filepath" 12 13 "github.com/spf13/cobra" 14 "github.com/windmilleng/wat/os/ospath" 15 ) 16 17 var kNumMostRecent = 1 18 19 var recentCmd = &cobra.Command{ 20 Use: "recent", 21 Short: "Print the N most recently edited files", 22 Run: recent, 23 } 24 25 type fileInfo struct { 26 name string 27 modTime time.Time 28 } 29 30 func (f fileInfo) String() string { 31 return fmt.Sprintf("%s (%s)", f.name, f.modTime.String()) 32 } 33 34 type fileInfos []fileInfo 35 36 func (infos fileInfos) Len() int { 37 return len(infos) 38 } 39 40 func (infos fileInfos) Less(i, j int) bool { 41 return infos[i].modTime.Before(infos[j].modTime) 42 } 43 44 func (infos fileInfos) Swap(i, j int) { 45 infos[i], infos[j] = infos[j], infos[i] 46 } 47 48 var _ sort.Interface = fileInfos{} 49 50 func recent(cmd *cobra.Command, args []string) { 51 ws, err := GetOrInitWatWorkspace() 52 if err != nil { 53 ws.Fatal("GetWatWorkspace", err) 54 } 55 56 files, err := RecentFileNames(ws) 57 if err != nil { 58 ws.Fatal("RecentFileNames", err) 59 } 60 for _, f := range files { 61 fmt.Println(f) 62 } 63 } 64 65 func RecentFileInfos(ws WatWorkspace) ([]fileInfo, error) { 66 files, err := ws.WalkRoot() 67 if err != nil { 68 return nil, err 69 } 70 71 sort.Sort(fileInfos(files)) 72 // Might want to make this accept an arg for # of files to return... 73 return files[len(files)-kNumMostRecent:], nil 74 } 75 76 func RecentFileNames(ws WatWorkspace) ([]string, error) { 77 files, err := RecentFileInfos(ws) 78 if err != nil { 79 return nil, err 80 } 81 strs := []string{} 82 for _, f := range files { 83 strs = append(strs, f.name) 84 } 85 return strs, nil 86 } 87 88 func (w WatWorkspace) WalkRoot() ([]fileInfo, error) { 89 return w.WalkDir(w.root) 90 } 91 92 func (w WatWorkspace) WalkDir(dir string) ([]fileInfo, error) { 93 return walkDir(dir) 94 } 95 96 func walkDir(dir string) ([]fileInfo, error) { 97 // Assume watIgnore lives in this directory 98 ignore := watIgnoreOrDummy(filepath.Join(dir, fnameWatIgnore)) 99 100 dir, err := ospath.RealAbs(dir) 101 if err != nil { 102 return nil, err 103 } 104 105 files := []fileInfo{} 106 err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { 107 if err != nil { 108 return err 109 } 110 111 shouldIgnore := ignore.Match(path, info.IsDir()) 112 if shouldIgnore { 113 if info.IsDir() { 114 // skip whole dir 115 return filepath.SkipDir 116 } 117 // ignored file, don't add to result 118 return nil 119 } 120 if info.Mode().IsRegular() { 121 name, _, err := ospath.RealChild(dir, path) 122 if err != nil { 123 return err 124 } 125 files = append(files, fileInfo{name: name, modTime: info.ModTime()}) 126 } 127 return nil 128 }) 129 130 return files, err 131 } 132 133 // filterFilesMatchAny takes an array of files and returns those files with names 134 // matching 1 or more of the given regexes 135 func filterFilesMatchAny(files []fileInfo, res []*regexp.Regexp) []fileInfo { 136 matched := []fileInfo{} 137 for _, f := range files { 138 if matchAny(f.name, res) { 139 matched = append(matched, f) 140 } 141 } 142 return matched 143 } 144 145 func matchAny(s string, res []*regexp.Regexp) bool { 146 for _, re := range res { 147 if re.Match([]byte(s)) { 148 return true 149 } 150 } 151 return false 152 }