// Upload sends the paths contents to the service compressed. func (watcher *Watcher) Upload() error { var ( err error file *os.File ) path := watcher.uploadPath() i := 0 ignores, err := db.GetIgnores(watcher.Path) if err != nil { return watcher.wrapErr(err) } if watcher.Path != "" { upload, err := tar.Tar(watcher.Path, ignores) if err != nil { return watcher.wrapErr(err) } // Write the tgz file to read from. file, err = os.Create(path) if err != nil { return watcher.wrapErr(err) } defer os.RemoveAll(path) defer file.Close() // Copy the contents to the file. _, err = io.Copy(file, upload) if err != nil { return watcher.wrapErr(err) } } for i < 1000 { // If we've failed once, wait a bit. if err != nil { <-time.After(time.Millisecond * 50) } // Make sure we're at the beginning of the file. if watcher.Path != "" { _, err = file.Seek(0, os.SEEK_SET) if err != nil { return watcher.wrapErr(err) } } // Attempt to upload the file to the services satellite. err = delancey.Upload(watcher.Service.SatelliteAddr, watcher.Service.Name, file) if err == nil { return nil } i++ } return watcher.wrapErr(err) }
// Start handles file events and uploads the changes. func (watcher *Watcher) Start(evChan chan *Event, errChan chan error) { if watcher.Path == "" { return } stats := make(map[string]os.FileInfo) found := make([]string, 0) ignores, err := db.GetIgnores(watcher.Path) if err != nil { errChan <- watcher.wrapErr(err) return } // Get initial stats. err = filepath.Walk(watcher.Path, func(path string, info os.FileInfo, err error) error { if err != nil { return err } // Check if ignoring. for _, ignore := range ignores { if ignore == path { if info.IsDir() { return filepath.SkipDir } return nil } } stats[path] = info return nil }) if err != nil { errChan <- watcher.wrapErr(err) return } // Manager updates/creates. walker := func(path string, info os.FileInfo, err error) error { if err != nil { return err } rel, err := filepath.Rel(watcher.Path, path) if err != nil { return err } // Check if ignoring. for _, ignore := range ignores { if ignore == path { for p := range stats { if p == path || strings.Contains(p, path+string(filepath.Separator)) { delete(stats, p) } } if info.IsDir() { return filepath.SkipDir } return nil } } pstat, ok := stats[path] status := "" // Check if created/updated. if ok && (info.ModTime().After(pstat.ModTime()) || info.Mode() != pstat.Mode()) { status = "update" } else if !ok { status = "create" } // Ignore directory changes, and no event status. if info.IsDir() || status == "" { stats[path] = info found = append(found, path) return nil } err = watcher.Update(rel, status) if err != nil { if os.IsNotExist(err) { log.Debug("Ignoring temp file", status, "event", rel) return nil } return err } evChan <- &Event{watcher.Service.Name, status, rel} stats[path] = info found = append(found, path) return nil } for { // Check if we're done. select { case <-watcher.done: return default: } ignores, err = db.GetIgnores(watcher.Path) if err != nil { errChan <- watcher.wrapErr(err) return } err = filepath.Walk(watcher.Path, walker) if err != nil { errChan <- watcher.wrapErr(err) return } // Check for deletes. for path := range stats { skip := false rel, err := filepath.Rel(watcher.Path, path) if err != nil { errChan <- watcher.wrapErr(err) return } for _, f := range found { if f == path { skip = true break } } if skip { continue } delete(stats, path) err = watcher.Update(rel, "delete") if err != nil { errChan <- watcher.wrapErr(err) return } evChan <- &Event{watcher.Service.Name, "delete", rel} } found = make([]string, 0) <-time.After(500 * time.Millisecond) } }