func tagFrom(store *storage.Storage, tx *storage.Tx, fromPath string, paths []string, explicit, recursive, force, followSymlinks bool) (error, warnings) { log.Infof(2, "loading settings") settings, err := store.Settings(tx) if err != nil { return fmt.Errorf("could not retrieve settings: %v", err), nil } stat, err := os.Lstat(fromPath) if err != nil { return err, nil } if stat.Mode()&os.ModeSymlink != 0 && followSymlinks { fromPath, err = _path.Dereference(fromPath) if err != nil { return err, nil } } file, err := store.FileByPath(tx, fromPath) if err != nil { return fmt.Errorf("%v: could not retrieve file: %v", fromPath, err), nil } if file == nil { return fmt.Errorf("%v: path is not tagged", fromPath), nil } fileTags, err := store.FileTagsByFileId(tx, file.Id, true) if err != nil { return fmt.Errorf("%v: could not retrieve filetags: %v", fromPath, err), nil } pairs := make([]entities.TagIdValueIdPair, len(fileTags)) for index, fileTag := range fileTags { pairs[index] = entities.TagIdValueIdPair{fileTag.TagId, fileTag.ValueId} } warnings := make(warnings, 0, 10) for _, path := range paths { if err := tagPath(store, tx, path, pairs, explicit, recursive, force, followSymlinks, settings.FileFingerprintAlgorithm(), settings.DirectoryFingerprintAlgorithm(), settings.SymlinkFingerprintAlgorithm(), settings.ReportDuplicates()); err != nil { switch { case os.IsPermission(err): warnings = append(warnings, fmt.Sprintf("%v: permisison denied", path)) case os.IsNotExist(err): warnings = append(warnings, fmt.Sprintf("%v: no such file", path)) default: return fmt.Errorf("%v: could not stat file: %v", path, err), warnings } } } return nil, warnings }
func tagNamesForFile(store *storage.Storage, tx *storage.Tx, fileId entities.FileId, explicitOnly, colour bool) ([]string, error) { fileTags, err := store.FileTagsByFileId(tx, fileId, explicitOnly) if err != nil { return nil, fmt.Errorf("could not retrieve file-tags for file '%v': %v", fileId, err) } taggings := make([]string, len(fileTags)) for index, fileTag := range fileTags { tag, err := store.Tag(tx, fileTag.TagId) if err != nil { return nil, fmt.Errorf("could not lookup tag: %v", err) } if tag == nil { return nil, fmt.Errorf("tag '%v' does not exist", fileTag.TagId) } var tagging string if fileTag.ValueId == 0 { tagging = formatTagValueName(tag.Name, "", colour, fileTag.Implicit, fileTag.Explicit) } else { value, err := store.Value(tx, fileTag.ValueId) if err != nil { return nil, fmt.Errorf("could not lookup value: %v", err) } if value == nil { return nil, fmt.Errorf("value '%v' does not exist", fileTag.ValueId) } tagging = formatTagValueName(tag.Name, value.Name, colour, fileTag.Implicit, fileTag.Explicit) } taggings[index] = tagging } ansi.Sort(taggings) return taggings, nil }
func rationalizeFileTags(store *storage.Storage, tx *storage.Tx, files entities.Files) error { log.Infof(2, "rationalizing file tags") for _, file := range files { fileTags, err := store.FileTagsByFileId(tx, file.Id, false) if err != nil { return fmt.Errorf("could not determine tags for file '%v': %v", file.Path(), err) } for _, fileTag := range fileTags { if fileTag.Implicit && fileTag.Explicit { log.Infof(2, "%v: removing explicit tagging %v as implicit tagging exists", file.Path(), fileTag.TagId) if err := store.DeleteFileTag(tx, fileTag.FileId, fileTag.TagId, fileTag.ValueId); err != nil { return fmt.Errorf("could not delete file tag for file %v, tag %v and value %v", fileTag.FileId, fileTag.TagId, fileTag.ValueId) } } } } return nil }
func removeAlreadyAppliedTagValuePairs(store *storage.Storage, tx *storage.Tx, pairs []entities.TagIdValueIdPair, file *entities.File) ([]entities.TagIdValueIdPair, error) { log.Infof(2, "%v: determining existing file-tags", file.Path()) existingFileTags, err := store.FileTagsByFileId(tx, file.Id, false) if err != nil { return nil, fmt.Errorf("%v: could not determine file's tags: %v", file.Path(), err) } log.Infof(2, "%v: determining implied tags", file.Path()) newImplications, err := store.ImplicationsFor(tx, pairs...) if err != nil { return nil, fmt.Errorf("%v: could not determine implied tags: %v", file.Path(), err) } log.Infof(2, "%v: revising set of tags to apply", file.Path()) revisedPairs := make([]entities.TagIdValueIdPair, 0, len(pairs)) for _, pair := range pairs { predicate := func(ft entities.FileTag) bool { return ft.TagId == pair.TagId && ft.ValueId == pair.ValueId } if existingFileTags.Any(predicate) { continue } if newImplications.Implies(pair) { continue } revisedPairs = append(revisedPairs, pair) } return revisedPairs, nil }