Package: cs.fstags
Simple filesystem based file tagging
and the associatedfstagscommand line script.Latest release 20240211:TaggedPath: subclass Promotable, add from_str(fspath) class method.FSTags: new mv(srcpath,dstpath) method to move/link/symlink a file bringing its tags.Many basic tasks can be performed with thefstagscommand line utility,
documented under theFSTagsCommandclass below.Whyfstags?
By storing the tags in a separate file we:can store tags without modifying a filedo not need to know the file's format,
or even whether that format supports metadatacan process tags on any kind of filebecause tags are inherited from parent directories,
tags can be automatically acquired merely by arranging your file treeTags are stored in the file.fstagsin each directory;
there is a line for each entry in the directory
consisting of the directory entry name and the associated tags.Tags may be "bare", or have a value.
If there is a value it is expressed with an equals ('=')
followed by the JSON encoding of the value.The tags for a file are the union of its direct tags
and all relevant ancestor tags,
with priority given to tags closer to the file.For example, a media file for a television episode with the pathname/path/to/series-name/season-02/episode-name--s02e03--something.mp4might have the tags:series_title="Series Full Name"
season=2
sf
episode=3
episode_title="Full Episode Title"obtained from the following.fstagsentries:tag file/path/to/.fstags:series-name sf series_title="Series Full Name"tag file/path/to/series-name/.fstags:season-02 season=2tag file/path/to/series-name/season-02/.fstags:episode-name--s02e03--something.mp4 episode=3 episode_title="Full Episode Title"fstagsExamplesBacking up a media tree too big for the removable drivesWalk the media tree for files tagged for backup toarchive2:fstags find /path/to/media backup=archive2Walk the media tree for files not assigned to a backup archive:fstags find /path/to/media -backupBackup thearchive2files usingrsync:fstags find --for-rsync /path/to/media backup=archive2 \
| rsync -ia --include-from=- /path/to/media /path/to/backup_archive2ClassCascadeRuleA cascade rule of possible source tag names to provide a target tag.DEFAULT_FSTAGS = FSTags('.fstags')A class to examine filesystem tags.ClassFSTags(cs.resources.MultiOpenMixin, cs.context.ContextManagerMixin)A class to examine filesystem tags.MethodFSTags.__init__(self, tagsfile_basename=None, ontology_filepath=None, physical=None, update_mapping: Optional[Mapping] = None, update_prefix: Optional[str] = 'cs.fstags', update_uuid_tag_name: Optional[str] = 'uuid'):
Initialise theFSTagsinstance.Parameters:tagsfile_basename: optional basename forthe backing tags files,
default fromTAGSFILE_BASENAME:'.fstags'ontology_filepath: optional filesystem path for an associated ontologyphysical: optional flag for the associatedFSTagsConfigspecifying whetherTagFiles are indexed by their physical or logical
filesystem pathsupdate_mapping: optional secondary mapping to which to mirror
tags, such as anSQLTags;
the default comes from anSQLTagsspecified by the
environment variable$FSTAGS_UPDATE_MAPPINGif presentupdate_prefix: optional key prefix for use in the secondary mapping;
the default comes from the environment variable$FSTAGS_UPDATE_MAPPING_PREFIXif present,
otherwise'cs.fstags'update_uuid_tag_name: optional name for the per file UUID tag name;
default'uuid'ClassFSTagsCommand(cs.cmdutils.BaseCommand, cs.tagset.TagsCommandMixin)fstagsmain command line utility.Command line usage:Usage: fstags [-o ontology] [-P] subcommand [...]
  -o ontology   Specify the path to an ontology file.
  -P            Physical. Resolve pathnames through symlinks.
                Default ~/.fstagsrc[general]physical or False.
  Subcommands:
    autotag paths...
      Tag paths based on rules from the rc file.
    cp [-finv] srcpath dstpath, cp [-finv] srcpaths... dstdirpath
      POSIX cp(1) equivalent, but also copying tags:
      copy files and their tags into targetdir.
      -f  Force: remove destination if it exists.
      -i  Interactive: fail if the destination exists.
      -n  No remove: fail if the destination exists.
      -v  Verbose: show copied files.
    cptags srcpath dstpath
      Copy the direct tags from srcpath to dstpath.
    edit [-ad] [path]
      Edit the direct tagsets of path, default: '.'
      If path is a directory, provide the tags of its entries.
      Otherwise edit just the tags for path.
      -a    List all names in directory edit mode; normally
            names commencing with a dot are omitted.
      -d    Treat directories like files: edit just its tags.
    export [-a] [--direct] path {tag[=value]|-tag}...
      Export tags for files from paths matching all the constraints.
      -a        Export all paths, not just those with tags.
      --direct  Export the direct tags instead of the computed tags.
      The output is in the same CSV format as that from "sqltags export",
      with the following columns:
      * unixtime: the file's st_mtime from os.stat.
      * id: empty
      * name: the file path
      * tags: the file's direct or indirect tags
    find [--direct] [--for-rsync] [-o output_format] path {tag[=value]|-tag}...
      List files from path matching all the constraints.
      --direct    Use direct tags instead of all tags.
      --for-rsync Instead of listing matching paths, emit a
                  sequence of rsync(1) patterns suitable for use with
                  --include-from in order to do a selective rsync of the
                  matched paths.
      -o output_format
                  Use output_format as a Python format string to lay out
                  the listing.
                  Default: {fspath}
    help [-l] [subcommand-names...]
      Print help for subcommands.
      This outputs the full help for the named subcommands,
      or the short help for all subcommands if no names are specified.
      -l  Long help even if no subcommand-names provided.
    import {-|srcpath}...
      Import CSV data in the format emitted by "export".
      Each argument is a file path or "-", indicating standard input.
    infer pathname
      Print the base and inferred tags for pathname.
    json_import --prefix=tag_prefix {-|path} {-|tags.json}
      Apply JSON data to path.
      A path named "-" indicates that paths should be read from
      the standard input.
      The JSON tag data come from the file "tags.json"; the name
      "-" indicates that the JSON data should be read from the
      standard input.
    ln [-finv] srcpath dstpath, ln [-finv] srcpaths... dstdirpath
      POSIX ln(1) equivalent, but also copying the tags:
      link files and their tags into targetdir.
      -f  Force: remove destination if it exists.
      -i  Interactive: fail if the destination exists.
      -n  No remove: fail if the destination exists.
      -v  Verbose: show linked files.
    ls [-d] [--direct] [-o output_format] [paths...]
      List files from paths and their tags.
      -d          Treat directories like files, do not recurse.
      --direct    List direct tags instead of all tags.
      -l          Long format.
      -o output_format
                  Use output_format as a Python format string to lay out
                  the listing.
                  Default: {fspath:json} {tags}
    mv [-finv] srcpath dstpath, mv [-finv] srcpaths... dstdirpath
      POSIX mv(1) equivalent, but also copying the tags:
      move files and their tags into targetdir.
      -f  Force: remove destination if it exists.
      -i  Interactive: fail if the destination exists.
      -n  No remove: fail if the destination exists.
      -v  Verbose: show moved files.
    ns [-d] [--direct] [paths...]
      Report on the available primary namespace fields for formatting.
      Note that because the namespace used for formatting has
      inferred field names there are also unshown secondary field
      names available in format strings.
      -d          Treat directories like files, do not recurse.
      --direct    List direct tags instead of all tags.
    ont [subcommand [args...]]
      With no arguments, print the ontology.
    rename -o basename_format paths...
      Rename paths according to a format string.
      -o basename_format
          Use basename_format as a Python format string to
          compute the new basename for each path.
    scrub paths...
      Remove all tags for missing paths.
      If a path is a directory, scrub the immediate paths in the directory.
    shell
      Run a command prompt via cmd.Cmd using this command's subcommands.
    tag {-|path} {tag[=value]|-tag}...
      Tag a path with multiple tags.
      With the form "-tag", remove that tag from the direct tags.
      A path named "-" indicates that paths should be read from the
      standard input.
    tagfile tagfile_path [subcommand ...]
      Subcommands:
        tag tagset_name {tag[=value]|-tag}...
          Directly modify tag_name within the tag file tagfile_path.
    tagpaths {tag[=value]|-tag} {-|paths...}
      Tag multiple paths.
      With the form "-tag", remove the tag from the immediate tags.
      A single path named "-" indicates that paths should be read
      from the standard input.
    test [--direct] path {tag[=value]|-tag}...
      Test whether the path matches all the constraints.
      --direct    Use direct tags instead of all tags.
    xattr_export {-|paths...}
      Import tag information from extended attributes.
    xattr_import {-|paths...}
      Update extended attributes from tags.ClassFSTagsConfig(cs.fs.FSPathBasedSingleton, cs.obj.SingletonMixin, cs.fs.HasFSPath)A configuration for fstags.MethodFSTagsConfig.__init__(self, rcfilepath=None, physical=None):
Initialise the config.Parameters:rcfilepath: the path to the confguration file
IfNone, default to'~/.fstagsrc'(fromRCFILE).ClassFSTagsTagFile(cs.tagset.TagFile, cs.fs.FSPathBasedSingleton, cs.obj.SingletonMixin, cs.fs.HasFSPath, cs.tagset.BaseTagSets, cs.resources.MultiOpenMixin, cs.context.ContextManagerMixin, collections.abc.MutableMapping, collections.abc.Mapping, collections.abc.Collection, collections.abc.Sized, collections.abc.Iterable, collections.abc.Container, HasFSTagsMixin)AFSTagsTagFileindexingTagSets for file paths
which lives in the file path's directory.Functionget_xattr_value(fspath, xattr_name)Read the extended attributexattr_nameoffspath.
Return the extended attribute value as a string,
orNoneif the attribute does not exist.Parameters:fspath: the filesystem path to updatexattr_name: the extended attribute to obtain
if this is astr, the attribute is the UTF-8 encoding of that name.ClassHasFSTagsMixinMixin providing an automatic.fstagsproperty.Functionis_valid_basename(name: str)Test whethernameis a valid basefile for something in a directory.Functionmain(argv=None)Command line mode.Functionrfilepaths(path, name_selector=None)Generator yielding pathnames of files found underpath.Functionrpaths(path, *, yield_dirs=False, name_selector=None)Generator to recurse overpath, yielding(is_dir,subpath)for all selected subpaths.Functionrsync_patterns(paths, top_path)Return a list of rsync include lines
suitable for use with the--include-fromoption.ClassTaggedPath(cs.tagset.TagSet, builtins.dict, cs.dateutils.UNIXTimeMixin, cs.lex.FormatableMixin, cs.lex.FormatableFormatter, string.Formatter, cs.mappings.AttrableMappingMixin, HasFSTagsMixin, cs.fs.HasFSPath, cs.deco.Promotable)Class to manipulate the tags for a specific path.Functionupdate_xattr_value(fspath, xattr_name, new_xattr_value)Update the extended attributes offspathwithnew_xattr_valueforxattr_name.
Return the previous value, orNoneif the attribute was missing.We avoid callingos.setxattrif the value will not change.Parameters:fspath: the filesystem path to updatexattr_name: the extended attribute to update;
if this is astr, the attribute is the UTF-8 encoding of that name.new_xattr_value: the new extended attribute value, astrwhich should be the transcription ofTagSeti.e.str(tagset)Functionverbose(msg, *a)Emit message if in verbose mode.Release LogRelease 20240211:TaggedPath: subclass Promotable, add from_str(fspath) class method.FSTags: new mv(srcpath,dstpath) method to move/link/symlink a file bringing its tags.Release 20240201.1:
Release with "fstags" script.Release 20240201:
FSTags.attach_path: do not save the tagfile if the FSTags is open - the final close will do it.Release 20231129:
FSTags.startup_shutdown: run self.sync() in a finally clause.Release 20230407:FSTags: support open/close of self.update_mapping, update startup/shutdown to startup_shutdown.Move the (optional) ORM open/close from FSTags.startup_shutdown to TagFile.save, greatly shortens the ORM lock.Release 20230217:
FSTagsCommand.cmd_rename: use -o for the format string as for other commands, -n is for "no action".Release 20230212:FSTags.keypath(fspath) and TaggedPath.keypath with the singleton filesystem path for a TaggedPath.TaggedPath.parent property.TaggedPath.findup(check) method.FSTagsCommand: cmd_find,cmd_ls: abort if runstate.cancelled thus honouring SIGINT/^C.Release 20230211:
FSTags.init: treat empty $FSTAGS_UPDATE_MAPPING as missing i.e. None.Release 20230210:
New optional update_mapping for mirroring tags eg to an SQLTags; activated automatically by an $FSTAGS_UPDATE_MAPPING environment variable.Release 20221228:
TaggedPath.save: new options prune=True parameter to drop empty top level dict/lists.Release 20220918:FSTagsConfig: add empty .provided dict for config overrides.FSTagsConfig: set FSPATH_DEFAULT=RCFILE for use by FSPathBasedSingleton._singleton_key.FSTagsConfig: accept optionalphysicalparameter to chooserealpathoverabspathand new.physicalproperty.FSTags.getitem: useabspathorrealpathdepending onself.config.physical.FSTagsCommand: new -P option for "physical" mode, plumb though to the config and self.options.Provide a DEFAULT_FSTAGS instance and an @uses_fstags decorator.Release 20220606:
FSTagsCommand.edit: mention the filename in the header comments in tagset edit mode.Release 20220430:
Minor bugfixes.Release 20220311:New TaggedPath.infer_tags() method to compute and return the inferred TagSet.New "fstags infer pathname" command.Release 20211212:Rename edit_many to edit_tagsets for clarity.FSTags.edit_dirpath: include realpath(dirpath) at the top of the edit list.Release 20210906:TaggedPath: new auto_infer method overriding the inherited TagSet.auto_infer which consults the cascade_rules from the .fstagsrc.fstags ls: new -l option to print a multiline tag listing.fstags cptags: copy the tags from one path to another.Assorted other changes.Release 20210404:FSTags.edit_dirpath: new all_names parameter to include dot-names.FSTagsCommand.cmd_edit: new -a option to turn on the all_names parameter.Release 20210306:FSTags: new tagfile_for(filepath) to obtain the TagFile for filepath.FSTagsCommand: new -o ontology option to supply an ontology file for the FSTags.FSTagsCommand.cmd_ont: drop -o/--ontology, superceded by global -o option.Move BaseTagFile from cs.fstags to TagFile in cs.tagset.FSTags.edit_dirpath: we now get (old_name,new_name,TaggedPath) back from edit_many, obviating the te_id_map.TaggedPath: .name property returning basename(self.filepath), .set and .discard methods rejecting use of the 'name' tag.FSTagsCommand: port to new cs.cmdutils API.Many small refactors and bugfixes.Release 20200717.1:
Add the manual page MarkDown source files. Note: well out of date, need updating.Release 20200717:
DISTINFO: require cs.obj>=20200716 for SingletonMixin API change.Release 20200716:Update for changed cs.obj.SingletonMixin API.fstags: new "export" and "import" subcommands roughly paralleling those from "sqltags", providing CSV formatted export/import.fstags export: ew -a (all paths) option - the default is not to not export paths with no tags.Release 20200521.1:
fix DISTINFO.install_requiresRelease 20200521:Add -i option to cp,ln,mv for command line compatibility, just disables -f.New "rename" subcommand to rename files according to a format string.Ontology support (optional).Various classes are now singletons to avoid dissonance.Fold "edittags" subcommand into "edit" via the "-d" (directories like files) option.New "ns" subcommand reporting on the primary names available for formatting.Accept [clausename]entryname as a format string to obtain the string from that entry of the config file.Many bugfixes and improvements.Release 20200229:New TaggedPath.modified property aliasing the TagSet.modified attribute.ls: new -d option to treat directories like files (do not recurse), aiding reporting of tags for a directory.find,ls subcommands: work off the realpath of the supplied top level path.Tag: now subclasses namedtuple.Rewrite rpaths() to use scandir and to also yield (is_dir,path) tuples.TagSet, Tag, TagChoice moved into new cs.tagset module for reuse.json_import: make --prefix mandatory, is "." as separator if not empty.Move filename regexp rules to [filename_rules] config section.New CascadeRule for representing a "target_tag_name = tag_name1 tag_name2..." config rules.autotag: include the cascade rules in the autotagging after the filename rules.Release 20200210:New "json_import" subcommand to import a JSON dict as tags, initial use case to load the metadata from youtube-dl.New "scrub" command line operation, to purge tags of paths which do not exist.New "cp", "ln" and "mv" subcommands to copy/link/move paths and take their tags with them.New "test" subcommand to test paths against tag criteria, useful for find and scripts.Small bugfixes.Release 20200130:New FSTagsConfig class which parses the .fstagsrc as a .ini file; related adjustments.New HasFSTagsMixin presenting a settable .fstags property with a shared default.New xattr_import and xattr_export subcommands, remove implicit xattr access/update from other operations.New TagSet.lenreturning the number of tags.Add "-" support for stdin to "tag" and "tagpaths" subcommands.Release 20200113.2:
FSTagsCommand docstring tweak.Release 20200113.1:
Small docstring updates.Release 20200113:
Mirror tags to user.cs.fstags xattr to honour Linux namespace requirements. Add "filesize" to available tag string format (-o option). Small bugfixes.Release 20191230:Command line: new "find" command to search a file tree based on tags.Command line: new "mv" command to move a file and its tags.Command line: Python string formats for "find" and "ls" output.TaggedPath.autotag: new optionalno_saveparameter, default False, to suppress update of the associated .fstags file.Inital and untested "mirror tags to xattrs" support.Release 20191201:
New "edit" subcommand to rename files and edit tags.Release 20191130.1:
Initial release: fstags, filesystem based tagging utility.