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  }