// visit is called for each file found in a directory walk. If the file is a // directory then it is pruned if empty. Otherwise the file is spooled. func visit(filePath string, f os.FileInfo, err error) error { log.Println("Visiting", filePath) // If we visit a directory check to see if it's empty and prune if so. if f.IsDir() { return pruneDir(filePath) } matched, err := regexp.MatchString(spooler.ImagePattern, filePath) if err != nil { log.Fatalf("Error compiling regular expression '%s'. %v", spooler.ImagePattern, err) } if !matched { log.Printf("Found unhandled file type [%s]. Moving the file to %s.\n", filePath, spool.ErrorPath) if noop { log.Println("DRY RUN Skipping move file.") } else { file.MoveTo(spool.ErrorPath, filePath) } return nil } spoolError := spool.Spool(filePath) if spoolError != nil { log.Println(spoolError) } return pruneDir(filepath.Dir(filePath)) }
// Spool copies the photo given by filename to the correct directory with the correct name. func (sp *Spooler) Spool(filename string) error { if sp.closed { return fmt.Errorf("This Spooler is already closed.") } // calculate an md5 sum for the file hash := getHash(filename) // get the Time from the DateTimeOriginal exif tag dateTime, err := getDateTime(filename) if err != nil { log.Printf("Could not read the DateTimeOriginal tag. %v", err) log.Printf("Moving %s to %s.\n", filename, sp.ErrorPath) if sp.noop { log.Println("DRY RUN Skipping move file.") } else if mverr := file.MoveTo(sp.ErrorPath, filename); mverr != nil { log.Fatal(mverr) } return err } // check if the hash already exists in the db if sp.database.ContainsKey(hash) { msg := "A db entry already exists for " + filename + "." errorName := filepath.Join(sp.ErrorPath, strings.Join([]string{filepath.Base(filename), "DUPLICATE"}, ".")) log.Printf("Mv(%s, %s)\n", errorName, filename) if sp.noop { log.Println("DRY RUN Skipping move file.") } else { err := file.Mv(errorName, filename) if err != nil { return err } } return errors.New(msg) } // calculate the path to copy the file to, including a new file name newPath := sp.getDestination(filename, sp.Destination, dateTime) // ensure the new path doesn't already exist for file.Exists(newPath) { dateTime = dateTime.Add(1 * time.Second) newPath = sp.getDestination(filename, sp.Destination, dateTime) } log.Printf("Mv(%s, %s)\n", newPath, filename) if file.Exists(newPath) { fields := strings.Split(filepath.Base(filename), ".") errorName := filepath.Join(sp.ErrorPath, strings.Join([]string{fields[0], filepath.Base(newPath)}, "::")) if sp.noop { log.Println("DRY RUN Skipping move file.") } else { err := file.Mv(errorName, filename) if err != nil { log.Println(err) return err } } msg := "A file with that named " + newPath + " already exists at the destination. Moving to " + errorName log.Println(msg) // TODO This logging sucks. // TODO send an e-mail. return errors.New(msg) } // move the file to its new home if sp.noop { log.Println("DRY RUN Skipping move file.") } else if err := file.Mv(newPath, filename); err != nil { log.Println(err) return err } // add an entry to the hashmap db if err := sp.database.Insert(newPath, hash); err != nil { return err // TODO plain errors suck... } return nil }