commands/helpers/file_archiver.go (153 lines of code) (raw):

package helpers import ( "bufio" "bytes" "errors" "fmt" "io" "os" "os/exec" "path/filepath" "sort" "strings" "time" "github.com/Sirupsen/logrus" ) type fileArchiver struct { Paths []string `long:"path" description:"Add paths to archive"` Untracked bool `long:"untracked" description:"Add git untracked files"` Verbose bool `long:"verbose" description:"Detailed information"` wd string files map[string]os.FileInfo } func (c *fileArchiver) isChanged(modTime time.Time) bool { for _, info := range c.files { if modTime.Before(info.ModTime()) { return true } } return false } func (c *fileArchiver) isFileChanged(fileName string) bool { ai, err := os.Stat(fileName) if ai != nil { if !c.isChanged(ai.ModTime()) { return false } } else if !os.IsNotExist(err) { logrus.Warningln(err) } return true } func (c *fileArchiver) sortedFiles() []string { files := make([]string, len(c.files)) i := 0 for file := range c.files { files[i] = file i++ } sort.Strings(files) return files } func (c *fileArchiver) add(path string) (err error) { // Always use slashes path = filepath.ToSlash(path) // Check if file exist info, err := os.Lstat(path) if err == nil { c.files[path] = info } return } func (c *fileArchiver) process(match string) bool { var absolute, relative string var err error absolute, err = filepath.Abs(match) if err == nil { // Let's try to find a real relative path to an absolute from working directory relative, err = filepath.Rel(c.wd, absolute) } if err == nil { // Process path only if it lives in our build directory if !strings.HasPrefix(relative, ".."+string(filepath.Separator)) { err = c.add(relative) } else { err = errors.New("not supported: outside build directory") } } if err == nil { return true } else if os.IsNotExist(err) { // We hide the error that file doesn't exist return false } logrus.Warningf("%s: %v", match, err) return false } func (c *fileArchiver) processPaths() { for _, path := range c.Paths { matches, err := filepath.Glob(path) if err != nil { logrus.Warningf("%s: %v", path, err) continue } found := 0 for _, match := range matches { err := filepath.Walk(match, func(path string, info os.FileInfo, err error) error { if c.process(path) { found++ } return nil }) if err != nil { logrus.Warningln("Walking", match, err) } } if found == 0 { logrus.Warningf("%s: no matching files", path) } else { logrus.Infof("%s: found %d matching files", path, found) } } } func (c *fileArchiver) processUntracked() { if !c.Untracked { return } found := 0 var output bytes.Buffer cmd := exec.Command("git", "ls-files", "-o") cmd.Env = os.Environ() cmd.Stdout = &output cmd.Stderr = os.Stderr logrus.Debugln("Executing command:", strings.Join(cmd.Args, " ")) err := cmd.Run() if err == nil { reader := bufio.NewReader(&output) for { line, _, err := reader.ReadLine() if err == io.EOF { break } else if err != nil { logrus.Warningln(err) break } if c.process(string(line)) { found++ } } if found == 0 { logrus.Warningf("untracked: no files") } else { logrus.Infof("untracked: found %d files", found) } } else { logrus.Warningf("untracked: %v", err) } } func (c *fileArchiver) enumerate() error { wd, err := os.Getwd() if err != nil { return fmt.Errorf("Failed to get current working directory: %v", err) } c.wd = wd c.files = make(map[string]os.FileInfo) c.processPaths() c.processUntracked() return nil }