TMSU lets you tags your files and then access them through a nifty virtual filesystem from any other application.

Overview

TMSU

Build Status Go Report Card

Overview

TMSU is a tool for tagging your files. It provides a simple command-line utility for applying tags and a virtual filesystem to give you a tag-based view of your files from any other program.

TMSU does not alter your files in any way: they remain unchanged on disk, or on the network, wherever your put them. TMSU maintains its own database and you simply gain an additional view, which you can mount where you like, based upon the tags you set up.

Usage

Before you can get tagging, you'll need to initialise a TMSU database:

$ cd ~
$ tmsu init

This database will be used automatically whenever you are under that directory. In this case we created one under the home directory.

You can tag a file by specifying the file and the list of tags to apply:

$ tmsu tag banana.jpg fruit art year=2015

Or you can apply tags to multiple files:

$ tmsu tag --tags="fruit still-life art" banana.jpg apple.png

You can query for files with or without particular tags:

$ tmsu files fruit and not still-life

Mount the virtual filesystem to an empty directory:

$ mkdir mp
$ tmsu mount mp

A subcommand overview and detail on how to use each subcommand is available via the integrated help:

$ tmsu help
$ tmsu help tags

Documentation is maintained online on the wiki:

Installing

Packages

Thanks to the efforts of contributors using these platforms, packages are available for the following GNU/Linux distributions:

These packages are not maintained by me and I cannot guarantee their content.

Binary

Binary builds for a limited number of architectures and operating system combinations are available:

You will need to ensure that both FUSE and Sqlite3 are installed for the program to function. These packages are typically available with your operating system's package management system. (If you install TMSU using one of the above packages, these should be installed automatically.)

  1. Install the binary

    Copy the program binary. The location may be different for your operating system:

     $ sudo cp bin/tmsu /usr/bin
    
  2. Optional: Zsh completion

    Copy the Zsh completion file to the Zsh site-functions directory:

     $ cp misc/zsh/_tmsu /usr/share/zsh/site-functions
    

From Source

If you would rather build from the source code then please see COMPILING.md in the root of the repository.

About

TMSU itself is written and maintained by [Paul Ruane](mailto:Paul Ruane [email protected]).

The creation of TMSU is motivation in itself, but if you should feel inclinded to make a small gift via Pledgie or Bitcoin then it shall be gratefully received:

TMSU is written in Go: http://www.golang.org/

Much of the functionality the program provides is made possible by the FUSE and Sqlite3 libraries, their Go bindings and the Go language standard library.

Release Notes

v0.8.0 (in development)

  • VFS now uses relative paths -- thanks to foxcpp
  • Support for Blake2b-256 fingerprints -- thanks to foxcpp
  • Hidden files are no longer tagged by default when tagging recursively. To include hidden files use the --include-hidden option -- thanks to foxcpp
  • Fixes to Zsh completion -- thanks to taiyu-len and Shadoukan

v0.7.5

  • Fixed issue with broken stderr pipe if VFS produces an error
  • '--name' option on 'tags' subcommand now takes argument to control when file/value names are printed

v0.7.4

  • Fixed further regressions with the set of files returned by files command.

v0.7.3

  • VFS directories were showing incorrect files and tags

v0.7.2

  • VFS directories were not showing for tag values

v0.7.1

  • Fixed a bug where wrong files would be returned when an tag=value implied another tag -- thanks to Fornost461
  • Specifying empty FUSE options would cause Fusermount to fail -- thanks to metafex
  • Manual repair would drop the file fingerprint -- thanks to c7nh7r

v0.7.0

Note: this release changes how symbolic links are handled. See below.

  • TMSU now compiles for Mac O/S. (Thanks to https://github.com/pguth.)
  • The VFS no longer lists files alongside the tag directories under tags. Instead there are results directories at each level, within which you can find the set of symbolic links to the tagged files.
  • Symbolic links are now followed by default. This means that if you tag a symbolic link, the target file is tagged instead. To instruct TMSU to not follow symbolic links (previous behaviour) use the new --no-dereference option on the relevant subcommands.
  • Added new setting symlinkFingerprintAlgorithm to allow the fingerprint algorithm for symbolic links to be configured separately to regular files.
  • By default duplicate files will now be reported when tagging. A new setting reportDuplicates can be used to turn this off.
  • Slashes are now permitted within tags and values, useful for recording URLs. In the virtual filesystem, similar looking Unicode characters are used in their place.
  • Added --where option to tag subcommand to allow tags to be applied to the set of files matching a query.
  • The VFS tags directory will now relist tags that have values so that multiple values can be specified, e.g. tags/color/=red/color/=blue.
  • It is now possible to list tags that use a particular value with the new --value option on the 'tags' subcommand.
  • Made it possible to upgrade the database schema between releases.
  • Added --count option to untagged.
  • Bug fixes.

v0.6.1

  • Fixed crash when opening an empty tag directory in the VFS.

v0.6.0

Note: this release changes the database schema by adding additional columns to the 'implication' table. TMSU will automatically upgrade your database upon first use but you may wish to take a backup beforehand.

  • Relaxed restrictions on tag and value names, allowing punctuation and whitespace characters. Problematic characters can be escaped with backslash.
  • Values are no longer automatically deleted when no longer used: it is now up to you to manage them.
  • Added --force option to 'tag' subcommand to allow tagging of missing or permission denied paths and broken symlinks.
  • 'imply' now creates tags if necessary (and 'autoCreateTags' is set).
  • Performance improvements to the virtual filesystem.
  • Fixed 'too many SQL variables' when merging tags applied to lots of files.
  • Added --name option to 'tags' to force printing of name even if there is only a single file argument, which is useful when using xargs.
  • Replaced 'stats' subcommand with 'info' subcommand (with --stats and --usage options for tag statics and usage counts respectively).
  • Included a set of scripts for performing filesystem operations whilst keeping the TMSU database up to date. If you wish to use these scripts I recommend you alias them to simpler names, e.g. 'trm'.
    • tmsu-fs-rm Removes files from the filesystem and TMSU
    • tmsu-fs-mv Moves a file in the filesystem and updates TMSU
    • tmsu-fs-merge Merges files (deleting all but the last)
  • Tag values can now be renamed, deleted and merged using the new --value option on the corresponding subcommands.
  • Tag values can now be used in implications.
  • Tag values can be explicitly created: tmsu tag --create =2015. (It may be necessary to enclose the argument in quotes depending upon your shell.)
  • It is no longer possible to add a circular tag implication. (These were not correctly applied anyway. An alias facility will be provided in a later version.)
  • The output of 'files' can now be sorted in various ways using --sort.
  • Case insensitive queries can now be performed with the --ignore-case option on the 'files' subcommand.
  • Added integration tests covering CLI.
  • Bug fixes.

v0.5.2

  • Fixed bug where concurrent access to the virtual filesystem would cause a runtime panic.

v0.5.1

  • Fixed bug with database initialization when .tmsu directory does not already exist.

v0.5.0

Note: This release has some important changes, including the renaming of some options, the introduction of local databases and a switch from absolute to relative paths in the database. Please read the following release notes carefully.

  • The --untagged option on the 'files' and 'status' subcommands has been replaced by a new 'untagged' subcommand, which should be more intuitive.

  • The --all option on the 'files', 'tags' and 'values' subcommands has been removed. These commands now list the full set of files/tags/values when run without arguments. For the 'tags' subcommand this replaces the previous behaviour of listing tags for the files in the working directory: use 'tmsu tags *' for approximately the previous behaviour.

  • The 'repair' subcommand --pretend short option has changed from -p to -P (so that -p can be recycled for --path).

  • The 'repair' subcommand's argument now specify paths to search for moved files and no longer limit how much of the database is repaired. A new --path argument is provided for reducing the repair to a portion of the database.

  • A new --manual option on the 'repair' subcommand allows targetted repair of moved files or directories.

  • The exclamation mark character (!) is no longer permitted within a tag or value name. Please rename tags using the 'rename' command. (Value names will need to be updated manually using the Sqlite3 tooling.)

  • Added --colour option to the 'tags' subcommand to highlight implied tags.

  • 'tag' subcommand will, by default, no longer explicitly apply tags that are already implied (unless the new --explicit option is specified).

  • Added subcommand aliases, e.g. 'query' for 'files'.

  • It is now possible to tag a broken symbolic link: instead of an error this will now be reported as a warning.

  • It is now possible to remove tags with values via the VFS.

  • 'tag' subcommand can tag multiple files with different tags by reading from standard input by passing an argument of '-'.

  • TMSU will now automatically use a local database in .tmsu/db in working directory or any parent. The new 'init' subcommand allows a new local database to be initialized. See Switching Databases.

  • Paths are now stored relative to the .tmsu directory's parent rather than as absolute paths. This allows a branch of the filesystem to be moved around, shared or archived whilst preserving the tagging information. Existing absolute paths can be converted by running a manual repair:

    tmsu repair --manual / /
    
  • Added 'config' subcommand to view and amend settings.

  • The 'help' subcommand now wraps textual output to fit the terminal.

  • Rudimentary Microsoft Windows support (no virtual filesystem yet).

  • TMSU can now be built without the Makefile.

  • Bug fixes.

v0.4.3

  • Fixed unit-test problems.

v0.4.2

  • Fixed bug where 'dynamic:MD5' and 'dynamic:SHA1' fingerprint algorithms were actually using SHA256.

v0.4.1

  • Tag values are now shown as directories in the virtual filesystem.

v0.4.0

Note: This release changes the database schema to facilitate tag values. To upgrade your existing v0.3.0 database please run the following:

$ cp ~/.tmsu/default.db ~/.tmsu/default.db.backup
$ sqlite3 -init misc/db-upgrade/0.3_to_0.4.0.sql ~/.tmsu/default.db .q
  • Added support for tag values, e.g. 'tmsu tag song.mp3 country=uk' and the querying of files based upon these values, e.g. 'year > 2000'.
  • 'tags' and 'values' subcommands now tabulate output, by default, when run from terminal.
  • Added ability to configure which fingerprint algorithm to use.
  • Implied tags now calculated on-the-fly when the database is queried. This results in a (potentially) smaller database and ability to have updates to the implied tags affect previously tagged files.
  • Added --explicit option to 'files' and 'tags' subcommands to show only explicit tags (omitting any implied tags).
  • Added --path option to 'files' subcommand to retrieve just those files matching or under the path specified.
  • Added --untagged option to 'files' subcommand which, when combined with --path, will also include untagged files from the filesystem at the specified path.
  • Removed the --recursive option from the 'files' subcommand which was flawed: use 'tmsu files query | xargs find' instead.
  • Added ability to configure whether new tags and values are automatically created or not or a per-database basis.
  • Added --unmodified option to 'repair' subcommand to force the recalculation of fingerprints of unmodified files.
  • Renamed --force option of 'repair' subcommand to --remove.
  • Added support for textual comparison operators: 'eq', 'ne', 'lt', 'gt', 'le' and 'ge', which do not need escaping unlike '<', '>', &c.
  • Improved Zsh completion with respect to tag values.
  • Significant performance improvements.
  • Removed support for '-' operator: use 'not' instead.
  • Bug fixes.

v0.3.0

Note: This release changes what tag names are allowed. To ensure the tag names in your existing databases are still valid, please run the following script:

$ cp ~/.tmsu/default.db ~/.tmsu/default.db.backup
$ sqlite3 -init misc/db-upgrade/clean_tag_names.sql ~/.tmsu/default.db
  • Added support for file queries, e.g. 'fish and chips and (mushy-peas or ketchup)'.
  • Added support for file query directories in the virtual filesystem.
  • Added global option --database for specifying database location.
  • Added ability to rename and delete tags via the virtual filesystem.
  • 'tag' subcommand now allows tags to be created up front.
  • 'copy' and 'imply' subcommands now support multiple destination tags.
  • Improved 'stats' subcommand.
  • Added man page.
  • Added script to allow the virtual filesystem to be mounted via the system 'mount' command or on startup via the fstab.
  • Bug fixes.

Copyright 2011-2018 Paul Ruane

Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without any warranty.

Issues
  • Is there a way to record the URL of a file?

    Is there a way to record the URL of a file?

    Is that a way to record the URL of a file?

    I wanted to record the original download site of a file. But the value of a tag cannot contain \ and maybe other chars in a url. So is it possible to set up a special tag (e.g. url=xxx) which allows these chars?

    enhancement 
    opened by flynxea 25
  • Relax restrictions on permitted characters in tag/value names

    Relax restrictions on permitted characters in tag/value names

    Currently there are a number of restrictions on which characters are allowed to be used in tag and value names. These are present for several reasons:

    1. To make parsing file queries easier.
    2. To avoid invalid names when mounting the virtual filesystem.

    Category 2 consists only of the slash characters, the backslash being illegal on Windows and the forwardslash on most other platforms.

    Items that fall into category 1 should be relaxed where possible.

    • Changes to the scanner should make it possible to use backslash escaping for problematic characters thus allowing their use within tag and value names.
    • More difficult to remove would be restrictions on keywords that are used as operators in the query language, e.g. 'and', 'or', 'not', 'lt', &c..

    TODOs

    • ~~subcommand files to render = delimiter in colour (when colour turned on)~~
    • ~~facility for customizing the TMSU colours (à la LS_COLORS).~~
    • ~~fix bug with tag --tags not handling whitespace (and presumably literal =).~~
    • ~~test coverage for all problematic characters.~~
    • ~~Zsh completion to correctly escape characters that are used by the shell.~~
    • ~~update wiki on names and explain how to handle both shell and TMSU escapes for problematic characters.~~
    enhancement 
    opened by oniony 21
  • Make available on Ubuntu

    Make available on Ubuntu

    I'm currently working on making this available on Ubuntu, and think I am most of the way there with the packaging. This issue is more to let you (and anyone else who may be interested) know than anything.

    My work so far is at zaz/tmsu-debian (1000th commit BTW, whoot whoot!), and I hope to have a working PPA by tomorrow. If I'm tragically crushed by a falling piano before then, I hope someone will continue in my footsteps.

    In the meantime, there were a few Lintian errors that you may want to address, but I don't think they're essential: Use of /usr/sbin (I believe this is deprecated in favor of /usr/bin), and missing manpages for binaries tmsu-fs-merge, tmsu-fs-mv, and tmsu-fs-rm.

    Does TMSU have any dependencies?

    Is there anything else I should know?

    Thanks for your time!

    packages 
    opened by zaz 20
  • Interface for Rapidly Tagging Many Small Files

    Interface for Rapidly Tagging Many Small Files

    I'm looking to tag a large collection of images (though I assume the same issue would apply to small music or video files), and it would speed things up considerably if I could view and tag in a more seamless fashion. I would be looking for something like:

    tmsu view-and-tag --viewer=eog *.{png,jpg,PNG,JPG}
    

    which spawns e.g. the EOG viewer for the first file in the list, prints the file name to the terminal, and waits for me to input a list of tags (maybe with autocompletion) and then hit return - then kills the image viewer and proceeds to the next file.

    I'm wondering whether:

    • Something like this already exists
    • You would be interested in shipping such a sub-command
    • There exists some sort of precursor to this, on top of which I could create some shell script to provide the aforementioned functionality.
    • There is any alternative approach to solving the issue at hand
    opened by TheChymera 14
  • Unable to compile from source for OSX 10.10.1

    Unable to compile from source for OSX 10.10.1

    The only choice was to build from source for my platform, since a binary distribution is not available (yet?).

    I'm stuck at the following point after issuing make:

    go clean tmsu
    rm -Rf bin
    rm -Rf tmsu-x86_64-0.5.0
    rm -f tmsu-x86_64-0.5.0.tgz
    go build -o bin/tmsu tmsu
    # tmsu/common/terminal
    src/tmsu/common/terminal/print.go:29: undefined: Width
    src/tmsu/common/terminal/print.go:108: undefined: Width
    make: *** [compile] Error 2
    

    The offending lines are:

    line #29: PrintColumnsWidth(items, Width())
    
    line #108: PrintWrappedWidth(text, Width())
    

    So, what should be the definition of Width() then?

    Thanks

    bug 
    opened by evandrix 14
  • Mac compatible binaries

    Mac compatible binaries

    ... would be nice. Currently I get exec format error: tmsu on 2,7 GHz Intel Core i5, ~~Crap~~MacOS 10.11.4.

    enhancement 
    opened by perguth 13
  • Store paths relative to the database location when using -D

    Store paths relative to the database location when using -D

    When I specify custom database path using -D, paths stored in the DB are absolute. Would it be possible to allow using relative paths? Having absolute paths in a DB stored stored on a portable storage device sort of defeats the purpose of using -D.

    enhancement 
    opened by tsudoko 11
  • 'tmsu untagged' returns potentially unwanted hidden files

    'tmsu untagged' returns potentially unwanted hidden files

    I'm running v. 0.7.4 on macOS (compiled from source); when I run tmsu untagged, I get among other things, .DS_Store, .fseventsd, .Trashes, .tmsu, etc.

    Rather than running tmsu untagged | grep -v "&^\.\/\." to get rid of hidden files, which can be problematic when copying/moving/removing files among other things, it'd be nice to add in a flag to tmsu untagged; maybe -h (--skip-hidden-files), to avoid the problem altogether.

    opened by ashleyharvey 10
  • Root paths relative to database path rather than root directory (/)

    Root paths relative to database path rather than root directory (/)

    @shabbyrobe mentioned in issue #8 that they would like to have relative rather than absolute paths stored in the database:

    TMSU stores the full path to the file in the database, but this limits my ability to either share the database with others or to move it around on my own machine. It makes more sense with my desired workflow to store paths relative to the .tmsu folder, but I understand this limits the existing ability of TMSU to tag files outside a user's home directory.

    One of the main use cases I have for portable, database relative tagging is for the various bands I play or have played in. We share huge collections of snippets and ideas and each band has a distinct set of members so I need one .tmsu folder per band. Being able to tag our snippets in a portable manner using TMSU is the killer workflow upgrade we've been desperate for. I would also like to use it for some photo collections, one private, one to share with my family.

    Currently TMSU makes every path absolute before storing them in the database. This has some benefits (e.g. the '..' path element is resolved) but has some limitations:

    • External storage mounted under different mount points will break the paths in the database
    • The TMSU database is not portable between machines unless identically set up

    To solve this problem I think TMSU should not make the paths absolute but should instead resolve paths against a fixed filesystem point. For now, it would make sense to use the parent directory of the .tmsu directory of the active database as that fixed point (In the future there TMSU could offer configuration so that this can be changed).

    The following operation:

    /home/fred/food $ tmsu tag italian/pizza yum
    

    Would currently store the pizza file as /home/fred/food/italian/pizza. With this proposed change, using the default database (/home/fred/.tmsu/default.db) would store the file as food/italian/pizza, (i.e. paths would be relative to the user's home directory by default by virtue of the fact that that's where the .tmsu directory is).

    If we created a local database at /home/fred/food/.tmsu/db (see issue #8), then the path stored would be italian/pizza. This would allow the food directory to be moved, shared or archived whilst preserving the TMSU database.

    But what if the database has been specified with --database or TMSU_DB? We cannot assume that the specified database is in a .tmsu directory. We could either store the paths relative to the database file's directory or we could preserve the existing behaviour of using absolute paths when the database is specified explicitly.

    Finally, existing databases will have absolute paths stored so repair will need to be upgraded to fix these.

    enhancement 
    opened by oniony 10
  • Cannot build TMSU

    Cannot build TMSU

    When attempting to build from source on Arch Linux, it looks like the test script tries to use the program before installing it:

    make
    
    
    
    
    RUNNING INTEGRATION TESTS
    
    CLEANING
    COMPILING
    
    RUNNING UNIT TESTS
    go clean github.com/oniony/TMSU
    
    
    go test github.com/oniony/TMSU/...
    go build -o bin/tmsu github.com/oniony/TMSU
    1,2d0
    < ././config/change_one_config: line 5: tmsu: command not found
    < ././config/change_one_config: line 6: tmsu: command not found
    ./config/change_one_config [FAIL]
    1,2d0
    < ././config/change_two_configs: line 5: tmsu: command not found
    < ././config/change_two_configs: line 6: tmsu: command not found
    ./config/change_two_configs [FAIL]
    1d0
    < ././config/list_all_config: line 5: tmsu: command not found
    ./config/list_all_config [FAIL]
    1d0
    < ././config/list_one_named_config: line 5: tmsu: command not found
    ./config/list_one_named_config [FAIL]
    1d0
    < ././config/list_two_named_configs: line 5: tmsu: command not found
    ./config/list_two_named_configs [FAIL]
    src/github.com/oniony/TMSU/vfs/fusevfs.go:22:2: cannot find package "github.com/hanwen/go-fuse/fuse" in any of:
    	/usr/lib/go/src/github.com/hanwen/go-fuse/fuse (from $GOROOT)
    	/home/rena/projects/TMSU/src/github.com/hanwen/go-fuse/fuse (from $GOPATH)
    	/usr/share/gocode/src/github.com/hanwen/go-fuse/fuse
    src/github.com/oniony/TMSU/vfs/fusevfs.go:23:2: cannot find package "github.com/hanwen/go-fuse/fuse/nodefs" in any of:
    	/usr/lib/go/src/github.com/hanwen/go-fuse/fuse/nodefs (from $GOROOT)
    	/home/rena/projects/TMSU/src/github.com/hanwen/go-fuse/fuse/nodefs (from $GOPATH)
    	/usr/share/gocode/src/github.com/hanwen/go-fuse/fuse/nodefs
    src/github.com/oniony/TMSU/vfs/fusevfs.go:24:2: cannot find package "github.com/hanwen/go-fuse/fuse/pathfs" in any of:
    	/usr/lib/go/src/github.com/hanwen/go-fuse/fuse/pathfs (from $GOROOT)
    	/home/rena/projects/TMSU/src/github.com/hanwen/go-fuse/fuse/pathfs (from $GOPATH)
    	/usr/share/gocode/src/github.com/hanwen/go-fuse/fuse/pathfs
    src/github.com/oniony/TMSU/storage/database/database.go:21:2: cannot find package "github.com/mattn/go-sqlite3" in any of:
    	/usr/lib/go/src/github.com/mattn/go-sqlite3 (from $GOROOT)
    	/home/rena/projects/TMSU/src/github.com/mattn/go-sqlite3 (from $GOPATH)
    	/usr/share/gocode/src/github.com/mattn/go-sqlite3
    make: *** [Makefile:34: compile] Error 1
    make: *** Waiting for unfinished jobs....
    1,4c1
    < ././copy/copy_one_tag: line 6: tmsu: command not found
    < ././copy/copy_one_tag: line 10: tmsu: command not found
    < ././copy/copy_one_tag: line 14: tmsu: command not found
    < ././copy/copy_one_tag: line 15: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    ./copy/copy_one_tag [FAIL]
    rm -Rf bin
    rm -Rf tmsu-x86_64-0.7.0
    rm -f tmsu-x86_64-0.7.0.tgz
    1,2c1,2
    < ././copy/copy_tag_invalid_dest: line 6: tmsu: command not found
    < ././copy/copy_tag_invalid_dest: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: could not copy tag 'aubergine' to 'eggplant': tag names cannot contain U+0002
    ./copy/copy_tag_invalid_dest [FAIL]
    src/github.com/oniony/TMSU/vfs/fusevfs.go:22:2: cannot find package "github.com/hanwen/go-fuse/fuse" in any of:
    	/usr/lib/go/src/github.com/hanwen/go-fuse/fuse (from $GOROOT)
    	/home/rena/projects/TMSU/src/github.com/hanwen/go-fuse/fuse (from $GOPATH)
    	/usr/share/gocode/src/github.com/hanwen/go-fuse/fuse
    src/github.com/oniony/TMSU/vfs/fusevfs.go:23:2: cannot find package "github.com/hanwen/go-fuse/fuse/nodefs" in any of:
    	/usr/lib/go/src/github.com/hanwen/go-fuse/fuse/nodefs (from $GOROOT)
    	/home/rena/projects/TMSU/src/github.com/hanwen/go-fuse/fuse/nodefs (from $GOPATH)
    	/usr/share/gocode/src/github.com/hanwen/go-fuse/fuse/nodefs
    src/github.com/oniony/TMSU/vfs/fusevfs.go:24:2: cannot find package "github.com/hanwen/go-fuse/fuse/pathfs" in any of:
    	/usr/lib/go/src/github.com/hanwen/go-fuse/fuse/pathfs (from $GOROOT)
    	/home/rena/projects/TMSU/src/github.com/hanwen/go-fuse/fuse/pathfs (from $GOPATH)
    	/usr/share/gocode/src/github.com/hanwen/go-fuse/fuse/pathfs
    src/github.com/oniony/TMSU/storage/database/database.go:21:2: cannot find package "github.com/mattn/go-sqlite3" in any of:
    	/usr/lib/go/src/github.com/mattn/go-sqlite3 (from $GOROOT)
    	/home/rena/projects/TMSU/src/github.com/mattn/go-sqlite3 (from $GOPATH)
    	/usr/share/gocode/src/github.com/mattn/go-sqlite3
    make: *** [Makefile:42: unit-test] Error 1
    1c1
    < ././copy/copy_tag_nonexistant_source: line 6: tmsu: command not found
    ---
    > tmsu: no such tag 'aubergine'
    ./copy/copy_tag_nonexistant_source [FAIL]
    1,3c1,3
    < ././copy/copy_tag_preexisting_dest: line 6: tmsu: command not found
    < ././copy/copy_tag_preexisting_dest: line 10: tmsu: command not found
    < ././copy/copy_tag_preexisting_dest: line 14: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'eggplant'
    > tmsu: a tag with name 'eggplant' already exists
    ./copy/copy_tag_preexisting_dest [FAIL]
    1,3c1,2
    < ././copy/copy_tag_to_itself: line 8: tmsu: command not found
    < ././copy/copy_tag_to_itself: line 12: tmsu: command not found
    < ././copy/copy_tag_to_itself: line 16: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: a tag with name 'aubergine' already exists
    ./copy/copy_tag_to_itself [FAIL]
    1,5c1
    < ././copy/copy_two_tags: line 6: tmsu: command not found
    < ././copy/copy_two_tags: line 10: tmsu: command not found
    < ././copy/copy_two_tags: line 14: tmsu: command not found
    < ././copy/copy_two_tags: line 15: tmsu: command not found
    < ././copy/copy_two_tags: line 16: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    ./copy/copy_two_tags [FAIL]
    1c1
    < ././delete/delete_nonexistant_tag: line 5: tmsu: command not found
    ---
    > tmsu: no such tag 'aubergine'
    ./delete/delete_nonexistant_tag [FAIL]
    1c1
    < ././delete/delete_nonexistant_value: line 5: tmsu: command not found
    ---
    > tmsu: no such value '2015'
    ./delete/delete_nonexistant_value [FAIL]
    1,2c1
    < ././delete/delete_one_applied_tag: line 10: tmsu: command not found
    < ././delete/delete_one_applied_tag: line 14: tmsu: command not found
    ---
    > tmsu: no such tag 'aubergine'
    ./delete/delete_one_applied_tag [FAIL]
    1,2c1
    < ././delete/delete_one_unapplied_tag: line 9: tmsu: command not found
    < ././delete/delete_one_unapplied_tag: line 13: tmsu: command not found
    ---
    > tmsu: no such tag 'aubergine'
    ./delete/delete_one_unapplied_tag [FAIL]
    1,2d0
    < ././delete/delete_one_value: line 10: tmsu: command not found
    < ././delete/delete_one_value: line 14: tmsu: command not found
    ./delete/delete_one_value [FAIL]
    1,3c1,2
    < ././delete/delete_two_applied_tags: line 10: tmsu: command not found
    < ././delete/delete_two_applied_tags: line 14: tmsu: command not found
    < ././delete/delete_two_applied_tags: line 15: tmsu: command not found
    ---
    > tmsu: no such tag 'aubergine'
    > tmsu: no such tag 'eggplant'
    ./delete/delete_two_applied_tags [FAIL]
    1,3c1,2
    < ././delete/delete_two_unapplied_tags: line 9: tmsu: command not found
    < ././delete/delete_two_unapplied_tags: line 13: tmsu: command not found
    < ././delete/delete_two_unapplied_tags: line 14: tmsu: command not found
    ---
    > tmsu: no such tag 'aubergine'
    > tmsu: no such tag 'eggplant'
    ./delete/delete_two_unapplied_tags [FAIL]
    1,2d0
    < ././delete/delete_two_values: line 10: tmsu: command not found
    < ././delete/delete_two_values: line 14: tmsu: command not found
    ./delete/delete_two_values [FAIL]
    1,3c1,3
    < ././dupes/list_dupes_in_database: line 9: tmsu: command not found
    < ././dupes/list_dupes_in_database: line 10: tmsu: command not found
    < ././dupes/list_dupes_in_database: line 14: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: '/tmp/tmsu/file2' is a duplicate
    > tmsu: '/tmp/tmsu/dir/file3' is a duplicate
    ./dupes/list_dupes_in_database [FAIL]
    1,2c1
    < ././dupes/list_dupes_of_file: line 7: tmsu: command not found
    < ././dupes/list_dupes_of_file: line 11: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    ./dupes/list_dupes_of_file [FAIL]
    1,2c1
    < ././dupes/list_dupes_of_file_recursively: line 8: tmsu: command not found
    < ././dupes/list_dupes_of_file_recursively: line 12: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    ./dupes/list_dupes_of_file_recursively [FAIL]
    1d0
    < ././files/count_with_tag: line 11: tmsu: command not found
    ./files/count_with_tag [FAIL]
    1d0
    < ././files/directories_with_tag: line 11: tmsu: command not found
    ./files/directories_with_tag [FAIL]
    1,2d0
    < ././files/files_for_escaped_query: line 10: tmsu: command not found
    < ././files/files_for_escaped_query: line 11: tmsu: command not found
    ./files/files_for_escaped_query [FAIL]
    1,2d0
    < ././files/files_for_query: line 11: tmsu: command not found
    < ././files/files_for_query: line 12: tmsu: command not found
    ./files/files_for_query [FAIL]
    1d0
    < ././files/files_for_value_equals_query: line 11: tmsu: command not found
    ./files/files_for_value_equals_query [FAIL]
    1d0
    < ././files/files_for_value_greater_or_equals_query: line 11: tmsu: command not found
    ./files/files_for_value_greater_or_equals_query [FAIL]
    1d0
    < ././files/files_for_value_greater_query: line 11: tmsu: command not found
    ./files/files_for_value_greater_query [FAIL]
    1d0
    < ././files/files_for_value_less_or_equals_query: line 11: tmsu: command not found
    ./files/files_for_value_less_or_equals_query [FAIL]
    1d0
    < ././files/files_for_value_less_query: line 11: tmsu: command not found
    ./files/files_for_value_less_query [FAIL]
    1d0
    < ././files/files_for_value_not_equals_query: line 13: tmsu: command not found
    ./files/files_for_value_not_equals_query [FAIL]
    1,2d0
    < ././files/files_sorted: line 10: tmsu: command not found
    < ././files/files_sorted: line 11: tmsu: command not found
    ./files/files_sorted [FAIL]
    1d0
    < ././files/files_with_tag: line 11: tmsu: command not found
    ./files/files_with_tag [FAIL]
    1,18d0
    < ././files/implications: line 20: tmsu: command not found
    < ././files/implications: line 21: tmsu: command not found
    < ././files/implications: line 22: tmsu: command not found
    < ././files/implications: line 23: tmsu: command not found
    < ././files/implications: line 25: tmsu: command not found
    < ././files/implications: line 26: tmsu: command not found
    < ././files/implications: line 27: tmsu: command not found
    < ././files/implications: line 28: tmsu: command not found
    < ././files/implications: line 30: tmsu: command not found
    < ././files/implications: line 31: tmsu: command not found
    < ././files/implications: line 32: tmsu: command not found
    < ././files/implications: line 33: tmsu: command not found
    < ././files/implications: line 35: tmsu: command not found
    < ././files/implications: line 36: tmsu: command not found
    < ././files/implications: line 37: tmsu: command not found
    < ././files/implications: line 38: tmsu: command not found
    < ././files/implications: line 39: tmsu: command not found
    < ././files/implications: line 40: tmsu: command not found
    ./files/implications [FAIL]
    1d0
    < ././files/items_with_tag: line 11: tmsu: command not found
    ./files/items_with_tag [FAIL]
    1d0
    < ././files/items_with_tag_under_path: line 12: tmsu: command not found
    ./files/items_with_tag_under_path [FAIL]
    1d0
    < ././files/items_with_two_tags: line 11: tmsu: command not found
    ./files/items_with_two_tags [FAIL]
    1,3c1,3
    < ././imply/create_cascading_tag_to_tag_implication: line 5: tmsu: command not found
    < ././imply/create_cascading_tag_to_tag_implication: line 6: tmsu: command not found
    < ././imply/create_cascading_tag_to_tag_implication: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'vegetable'
    > tmsu: new tag 'food'
    ./imply/create_cascading_tag_to_tag_implication [FAIL]
    1,3c1,5
    < ././imply/create_cascading_tag_to_value_implication: line 5: tmsu: command not found
    < ././imply/create_cascading_tag_to_value_implication: line 6: tmsu: command not found
    < ././imply/create_cascading_tag_to_value_implication: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'food'
    > tmsu: new value 'vegetable'
    > tmsu: new tag 'song'
    > tmsu: new value 'plantlife'
    ./imply/create_cascading_tag_to_value_implication [FAIL]
    1,2c1,5
    < ././imply/create_circular_tag=value_to_tag=value_implication: line 5: tmsu: command not found
    < ././imply/create_circular_tag=value_to_tag=value_implication: line 6: tmsu: command not found
    ---
    > tmsu: new tag 'year'
    > tmsu: new value '2015'
    > tmsu: new tag 'roman'
    > tmsu: new value 'MMXV'
    > tmsu: cannot add implication of 'roman=MMXV' to 'year=2015': implication would create a cycle
    ./imply/create_circular_tag=value_to_tag=value_implication [FAIL]
    1,2c1,4
    < ././imply/create_circular_tag=value_to_tag_implication: line 5: tmsu: command not found
    < ././imply/create_circular_tag=value_to_tag_implication: line 6: tmsu: command not found
    ---
    > tmsu: new tag 'year'
    > tmsu: new value '2015'
    > tmsu: new tag 'MMXV'
    > tmsu: cannot add implication of 'MMXV' to 'year=2015': implication would create a cycle
    ./imply/create_circular_tag=value_to_tag_implication [FAIL]
    1,2c1,4
    < ././imply/create_circular_tag_to_tag=value_implication: line 5: tmsu: command not found
    < ././imply/create_circular_tag_to_tag=value_implication: line 6: tmsu: command not found
    ---
    > tmsu: new tag 'MMXV'
    > tmsu: new tag 'year'
    > tmsu: new value '2015'
    > tmsu: cannot add implication of 'year' to 'MMXV': implication would create a cycle
    ./imply/create_circular_tag_to_tag=value_implication [FAIL]
    1,2c1,3
    < ././imply/create_circular_tag_to_tag_implication: line 5: tmsu: command not found
    < ././imply/create_circular_tag_to_tag_implication: line 6: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'vegetable'
    > tmsu: cannot add implication of 'vegetable' to 'aubergine': implication would create a cycle
    ./imply/create_circular_tag_to_tag_implication [FAIL]
    1,3c1,4
    < ././imply/create_noncircular_value_to_value_implications: line 5: tmsu: command not found
    < ././imply/create_noncircular_value_to_value_implications: line 6: tmsu: command not found
    < ././imply/create_noncircular_value_to_value_implications: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'name'
    > tmsu: new value 'courgette'
    > tmsu: new value 'zucchini'
    > tmsu: new value 'marrow'
    ./imply/create_noncircular_value_to_value_implications [FAIL]
    1,2c1,2
    < ././imply/create_tag_to_tag_implication: line 5: tmsu: command not found
    < ././imply/create_tag_to_tag_implication: line 9: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'vegetable'
    ./imply/create_tag_to_tag_implication [FAIL]
    1,2c1,3
    < ././imply/create_tag_to_value_implication: line 5: tmsu: command not found
    < ././imply/create_tag_to_value_implication: line 9: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'food'
    > tmsu: new value 'vegetable'
    ./imply/create_tag_to_value_implication [FAIL]
    1,2c1,3
    < ././imply/create_value_to_tag_implication: line 5: tmsu: command not found
    < ././imply/create_value_to_tag_implication: line 9: tmsu: command not found
    ---
    > tmsu: new tag 'food'
    > tmsu: new value 'aubergine'
    > tmsu: new tag 'vegetable'
    ./imply/create_value_to_tag_implication [FAIL]
    1,2c1,4
    < ././imply/create_value_to_value_implication: line 5: tmsu: command not found
    < ././imply/create_value_to_value_implication: line 9: tmsu: command not found
    ---
    > tmsu: new tag 'food'
    > tmsu: new value 'aubergine'
    > tmsu: new tag 'class'
    > tmsu: new value 'vegetable'
    ./imply/create_value_to_value_implication [FAIL]
    1,4c1,2
    < ././imply/delete_tag_to_tag_implication: line 5: tmsu: command not found
    < ././imply/delete_tag_to_tag_implication: line 6: tmsu: command not found
    < ././imply/delete_tag_to_tag_implication: line 10: tmsu: command not found
    < ././imply/delete_tag_to_tag_implication: line 14: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'vegetable'
    ./imply/delete_tag_to_tag_implication [FAIL]
    1,4c1,3
    < ././imply/delete_tag_to_value_implication: line 5: tmsu: command not found
    < ././imply/delete_tag_to_value_implication: line 6: tmsu: command not found
    < ././imply/delete_tag_to_value_implication: line 10: tmsu: command not found
    < ././imply/delete_tag_to_value_implication: line 14: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'food'
    > tmsu: new value 'vegetable'
    ./imply/delete_tag_to_value_implication [FAIL]
    1,4c1,3
    < ././imply/delete_value_to_tag_implication: line 5: tmsu: command not found
    < ././imply/delete_value_to_tag_implication: line 6: tmsu: command not found
    < ././imply/delete_value_to_tag_implication: line 10: tmsu: command not found
    < ././imply/delete_value_to_tag_implication: line 14: tmsu: command not found
    ---
    > tmsu: new tag 'food'
    > tmsu: new value 'aubergine'
    > tmsu: new tag 'vegetable'
    ./imply/delete_value_to_tag_implication [FAIL]
    1,4c1,4
    < ././imply/delete_value_to_value_implication: line 5: tmsu: command not found
    < ././imply/delete_value_to_value_implication: line 6: tmsu: command not found
    < ././imply/delete_value_to_value_implication: line 10: tmsu: command not found
    < ././imply/delete_value_to_value_implication: line 14: tmsu: command not found
    ---
    > tmsu: new tag 'food'
    > tmsu: new value 'aubergine'
    > tmsu: new tag 'class'
    > tmsu: new value 'vegetable'
    ./imply/delete_value_to_value_implication [FAIL]
    1d0
    < ././info/basic: line 5: tmsu: command not found
    ./info/basic [FAIL]
    1d0
    < ././info/stats: line 10: tmsu: command not found
    ./info/stats [FAIL]
    1d0
    < ././info/usage: line 10: tmsu: command not found
    ./info/usage [FAIL]
    database was not created
    ./init/initialise_at_path [FAIL]
    1,2c1
    < ././merge/merge_tag_into_itself: line 10: tmsu: command not found
    < ././merge/merge_tag_into_itself: line 14: tmsu: command not found
    ---
    > tmsu: cannot merge tag 'aubergine' into itself
    ./merge/merge_tag_into_itself [FAIL]
    1,3d0
    < ././merge/merge_three_tags: line 14: tmsu: command not found
    < ././merge/merge_three_tags: line 18: tmsu: command not found
    < ././merge/merge_three_tags: line 19: tmsu: command not found
    ./merge/merge_three_tags [FAIL]
    1,2c1
    < ././merge/merge_three_tags_where_one_nonexistant: line 11: tmsu: command not found
    < ././merge/merge_three_tags_where_one_nonexistant: line 15: tmsu: command not found
    ---
    > tmsu: no such tag 'brocolli'
    ./merge/merge_three_tags_where_one_nonexistant [FAIL]
    1,3d0
    < ././merge/merge_three_values: line 14: tmsu: command not found
    < ././merge/merge_three_values: line 18: tmsu: command not found
    < ././merge/merge_three_values: line 19: tmsu: command not found
    ./merge/merge_three_values [FAIL]
    1,2c1
    < ././merge/merge_three_values_where_one_nonexistant: line 11: tmsu: command not found
    < ././merge/merge_three_values_where_one_nonexistant: line 15: tmsu: command not found
    ---
    > tmsu: no such value 'brocolli'
    ./merge/merge_three_values_where_one_nonexistant [FAIL]
    1,3d0
    < ././merge/merge_two_tags: line 11: tmsu: command not found
    < ././merge/merge_two_tags: line 15: tmsu: command not found
    < ././merge/merge_two_tags: line 16: tmsu: command not found
    ./merge/merge_two_tags [FAIL]
    1c1
    < ././merge/merge_two_tags_nonexistant_dest_tag: line 10: tmsu: command not found
    ---
    > tmsu: no such tag 'potato'
    ./merge/merge_two_tags_nonexistant_dest_tag [FAIL]
    1c1
    < ././merge/merge_two_tags_nonexistant_source_tag: line 10: tmsu: command not found
    ---
    > tmsu: no such tag 'potato'
    ./merge/merge_two_tags_nonexistant_source_tag [FAIL]
    1,3d0
    < ././merge/merge_two_values: line 11: tmsu: command not found
    < ././merge/merge_two_values: line 15: tmsu: command not found
    < ././merge/merge_two_values: line 16: tmsu: command not found
    ./merge/merge_two_values [FAIL]
    1c1
    < ././merge/merge_two_values_nonexistant_dest_value: line 10: tmsu: command not found
    ---
    > tmsu: no such value 'potato'
    ./merge/merge_two_values_nonexistant_dest_value [FAIL]
    1c1
    < ././merge/merge_two_values_nonexistant_source_value: line 10: tmsu: command not found
    ---
    > tmsu: no such value 'potato'
    ./merge/merge_two_values_nonexistant_source_value [FAIL]
    1,2c1
    < ././merge/merge_value_into_itself: line 10: tmsu: command not found
    < ././merge/merge_value_into_itself: line 14: tmsu: command not found
    ---
    > tmsu: cannot merge value 'aubergine' into itself
    ./merge/merge_value_into_itself [FAIL]
    1,4c1,2
    < ././rename/rename_tag: line 6: tmsu: command not found
    < ././rename/rename_tag: line 10: tmsu: command not found
    < ././rename/rename_tag: line 14: tmsu: command not found
    < ././rename/rename_tag: line 15: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: no such tag 'aubergine'
    ./rename/rename_tag [FAIL]
    1,2c1,2
    < ././rename/rename_tag_invalid_dest: line 6: tmsu: command not found
    < ././rename/rename_tag_invalid_dest: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: could not rename tag 'aubergine' to 'eggplant': tag names cannot contain U+0002
    ./rename/rename_tag_invalid_dest [FAIL]
    1c1
    < ././rename/rename_tag_nonexistant_source: line 5: tmsu: command not found
    ---
    > tmsu: no such tag 'aubergine'
    ./rename/rename_tag_nonexistant_source [FAIL]
    1,2c1,3
    < ././rename/rename_tag_preexisting_dest: line 6: tmsu: command not found
    < ././rename/rename_tag_preexisting_dest: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'eggplant'
    > tmsu: tag 'eggplant' already exists
    ./rename/rename_tag_preexisting_dest [FAIL]
    1,3c1,2
    < ././rename/rename_value: line 6: tmsu: command not found
    < ././rename/rename_value: line 10: tmsu: command not found
    < ././rename/rename_value: line 14: tmsu: command not found
    ---
    > tmsu: new tag 'year'
    > tmsu: new value '2015'
    ./rename/rename_value [FAIL]
    1,2c1,3
    < ././rename/rename_value_invalid_dest: line 6: tmsu: command not found
    < ././rename/rename_value_invalid_dest: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'year'
    > tmsu: new value '2015'
    > tmsu: could not rename value '2015' to '2016': tag value cannot contain U+0002
    ./rename/rename_value_invalid_dest [FAIL]
    1c1
    < ././rename/rename_value_nonexistant_source: line 5: tmsu: command not found
    ---
    > tmsu: no such value '2015'
    ./rename/rename_value_nonexistant_source [FAIL]
    1,2c1,4
    < ././rename/rename_value_preexisting_dest: line 6: tmsu: command not found
    < ././rename/rename_value_preexisting_dest: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'year'
    > tmsu: new value '2015'
    > tmsu: new value '2016'
    > tmsu: value '2016' already exists
    ./rename/rename_value_preexisting_dest [FAIL]
    1,2d0
    < ././repair/detect_missing: line 11: tmsu: command not found
    < ././repair/detect_missing: line 15: tmsu: command not found
    ./repair/detect_missing [FAIL]
    1,2d0
    < ././repair/detect_missing_under_path: line 12: tmsu: command not found
    < ././repair/detect_missing_under_path: line 16: tmsu: command not found
    ./repair/detect_missing_under_path [FAIL]
    1,2c1
    < ././repair/manual_move: line 11: tmsu: command not found
    < ././repair/manual_move: line 15: tmsu: command not found
    ---
    > tmsu: /tmp/tmsu/file1: no such file
    ./repair/manual_move [FAIL]
    1,2d0
    < ././repair/pretend_repair_modified: line 11: tmsu: command not found
    < ././repair/pretend_repair_modified: line 15: tmsu: command not found
    ./repair/pretend_repair_modified [FAIL]
    1,3d0
    < ././repair/rationalize: line 11: tmsu: command not found
    < ././repair/rationalize: line 15: tmsu: command not found
    < ././repair/rationalize: line 16: tmsu: command not found
    ./repair/rationalize [FAIL]
    1d0
    < ././repair/recalculate_fingerprints: line 10: tmsu: command not found
    ./repair/recalculate_fingerprints [FAIL]
    1,2c1
    < ././repair/remove_missing: line 11: tmsu: command not found
    < ././repair/remove_missing: line 15: tmsu: command not found
    ---
    > tmsu: /tmp/tmsu/file4: no such file
    ./repair/remove_missing [FAIL]
    1,2c1
    < ././repair/remove_missing_under_path: line 12: tmsu: command not found
    < ././repair/remove_missing_under_path: line 16: tmsu: command not found
    ---
    > tmsu: /tmp/tmsu/dir1/file1: no such file
    ./repair/remove_missing_under_path [FAIL]
    1d0
    < ././repair/repair_modified: line 11: tmsu: command not found
    ./repair/repair_modified [FAIL]
    1,2c1
    < ././repair/repair_moved: line 11: tmsu: command not found
    < ././repair/repair_moved: line 15: tmsu: command not found
    ---
    > tmsu: /tmp/tmsu/file4: no such file
    ./repair/repair_moved [FAIL]
    1,5c1
    < ././status/show_status_of_database: line 11: tmsu: command not found
    < ././status/show_status_of_database: line 12: tmsu: command not found
    < ././status/show_status_of_database: line 13: tmsu: command not found
    < ././status/show_status_of_database: line 14: tmsu: command not found
    < ././status/show_status_of_database: line 20: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    ./status/show_status_of_database [FAIL]
    1,5c1
    < ././status/show_status_of_database_nonrecursively: line 10: tmsu: command not found
    < ././status/show_status_of_database_nonrecursively: line 11: tmsu: command not found
    < ././status/show_status_of_database_nonrecursively: line 12: tmsu: command not found
    < ././status/show_status_of_database_nonrecursively: line 13: tmsu: command not found
    < ././status/show_status_of_database_nonrecursively: line 19: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    ./status/show_status_of_database_nonrecursively [FAIL]
    1,5c1
    < ././status/show_status_of_path: line 10: tmsu: command not found
    < ././status/show_status_of_path: line 11: tmsu: command not found
    < ././status/show_status_of_path: line 12: tmsu: command not found
    < ././status/show_status_of_path: line 13: tmsu: command not found
    < ././status/show_status_of_path: line 19: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    ./status/show_status_of_path [FAIL]
    1,3c1,2
    < ././tag/apply_escaped_tag: line 9: tmsu: command not found
    < ././tag/apply_escaped_tag: line 10: tmsu: command not found
    < ././tag/apply_escaped_tag: line 11: tmsu: command not found
    ---
    > tmsu: new tag 'one=two'
    > tmsu: new tag 'two=three'
    ./tag/apply_escaped_tag [FAIL]
    1,21c1,20
    < ././tag/apply_invalid_tag: line 9: tmsu: command not found
    < ././tag/apply_invalid_tag: line 10: tmsu: command not found
    < ././tag/apply_invalid_tag: line 11: tmsu: command not found
    < ././tag/apply_invalid_tag: line 12: tmsu: command not found
    < ././tag/apply_invalid_tag: line 13: tmsu: command not found
    < ././tag/apply_invalid_tag: line 14: tmsu: command not found
    < ././tag/apply_invalid_tag: line 15: tmsu: command not found
    < ././tag/apply_invalid_tag: line 16: tmsu: command not found
    < ././tag/apply_invalid_tag: line 17: tmsu: command not found
    < ././tag/apply_invalid_tag: line 18: tmsu: command not found
    < ././tag/apply_invalid_tag: line 19: tmsu: command not found
    < ././tag/apply_invalid_tag: line 20: tmsu: command not found
    < ././tag/apply_invalid_tag: line 21: tmsu: command not found
    < ././tag/apply_invalid_tag: line 22: tmsu: command not found
    < ././tag/apply_invalid_tag: line 23: tmsu: command not found
    < ././tag/apply_invalid_tag: line 24: tmsu: command not found
    < ././tag/apply_invalid_tag: line 25: tmsu: command not found
    < ././tag/apply_invalid_tag: line 26: tmsu: command not found
    < ././tag/apply_invalid_tag: line 27: tmsu: command not found
    < ././tag/apply_invalid_tag: line 28: tmsu: command not found
    < ././tag/apply_invalid_tag: line 29: tmsu: command not found
    ---
    > tmsu: tag name cannot be '.' or '..'
    > tmsu: tag name cannot be '.' or '..'
    > tmsu: tag name cannot be a logical operator: 'and', 'or' or 'not'
    > tmsu: tag name cannot be a logical operator: 'and', 'or' or 'not'
    > tmsu: tag name cannot be a logical operator: 'and', 'or' or 'not'
    > tmsu: tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: tag name cannot be a logical operator: 'and', 'or' or 'not'
    > tmsu: tag name cannot be a logical operator: 'and', 'or' or 'not'
    > tmsu: tag name cannot be a logical operator: 'and', 'or' or 'not'
    > tmsu: tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    ./tag/apply_invalid_tag [FAIL]
    1,2c1
    < ././tag/apply_one_tag: line 9: tmsu: command not found
    < ././tag/apply_one_tag: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    ./tag/apply_one_tag [FAIL]
    1,3c1
    < ././tag/apply_one_tag_to_directory_nonrecursively: line 10: tmsu: command not found
    < ././tag/apply_one_tag_to_directory_nonrecursively: line 11: tmsu: command not found
    < ././tag/apply_one_tag_to_directory_nonrecursively: line 12: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    ./tag/apply_one_tag_to_directory_nonrecursively [FAIL]
    1,3c1
    < ././tag/apply_one_tag_to_directory_recursively: line 10: tmsu: command not found
    < ././tag/apply_one_tag_to_directory_recursively: line 11: tmsu: command not found
    < ././tag/apply_one_tag_to_directory_recursively: line 12: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    ./tag/apply_one_tag_to_directory_recursively [FAIL]
    1,2c1
    < ././tag/apply_one_tag_to_mulitple_files: line 10: tmsu: command not found
    < ././tag/apply_one_tag_to_mulitple_files: line 11: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    ./tag/apply_one_tag_to_mulitple_files [FAIL]
    1,5c1,2
    < ././tag/apply_tag_already_implied_by_previous_tags: line 9: tmsu: command not found
    < ././tag/apply_tag_already_implied_by_previous_tags: line 10: tmsu: command not found
    < ././tag/apply_tag_already_implied_by_previous_tags: line 11: tmsu: command not found
    < ././tag/apply_tag_already_implied_by_previous_tags: line 12: tmsu: command not found
    < ././tag/apply_tag_already_implied_by_previous_tags: line 13: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'vegetable'
    ./tag/apply_tag_already_implied_by_previous_tags [FAIL]
    1c1,2
    < ././tag/apply_tag_to_nonexistant_file: line 5: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: /tmp/tmsu/noexist: no such file
    ./tag/apply_tag_to_nonexistant_file [FAIL]
    1,3c1,2
    < ././tag/apply_tags_from_other_file: line 8: tmsu: command not found
    < ././tag/apply_tags_from_other_file: line 9: tmsu: command not found
    < ././tag/apply_tags_from_other_file: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'potato'
    ./tag/apply_tags_from_other_file [FAIL]
    1c1
    < ././tag/apply_tags_from_untagged_file: line 9: tmsu: command not found
    ---
    > tmsu: /tmp/tmsu/file1: path is not tagged
    ./tag/apply_tags_from_untagged_file [FAIL]
    1,5c1,4
    < ././tag/apply_tags_where_query: line 9: tmsu: command not found
    < ././tag/apply_tags_where_query: line 10: tmsu: command not found
    < ././tag/apply_tags_where_query: line 11: tmsu: command not found
    < ././tag/apply_tags_where_query: line 12: tmsu: command not found
    < ././tag/apply_tags_where_query: line 13: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'potato'
    > tmsu: new tag 'shiny-purple-veg'
    > tmsu: new tag 'eggplant'
    ./tag/apply_tags_where_query [FAIL]
    1,2c1,2
    < ././tag/apply_two_tags: line 9: tmsu: command not found
    < ././tag/apply_two_tags: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'potato'
    ./tag/apply_two_tags [FAIL]
    1,2c1,2
    < ././tag/apply_two_tags_to_multiple_files: line 10: tmsu: command not found
    < ././tag/apply_two_tags_to_multiple_files: line 11: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'potato'
    ./tag/apply_two_tags_to_multiple_files [FAIL]
    1,4c1,2
    < ././tag/apply_two_tags_where_one_implies_the_other: line 9: tmsu: command not found
    < ././tag/apply_two_tags_where_one_implies_the_other: line 10: tmsu: command not found
    < ././tag/apply_two_tags_where_one_implies_the_other: line 11: tmsu: command not found
    < ././tag/apply_two_tags_where_one_implies_the_other: line 12: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'vegetable'
    ./tag/apply_two_tags_where_one_implies_the_other [FAIL]
    1,3d0
    < ././tag/create_escaped_tag: line 5: tmsu: command not found
    < ././tag/create_escaped_tag: line 6: tmsu: command not found
    < ././tag/create_escaped_tag: line 7: tmsu: command not found
    ./tag/create_escaped_tag [FAIL]
    1,21c1,20
    < ././tag/create_invalid_tag: line 5: tmsu: command not found
    < ././tag/create_invalid_tag: line 6: tmsu: command not found
    < ././tag/create_invalid_tag: line 7: tmsu: command not found
    < ././tag/create_invalid_tag: line 8: tmsu: command not found
    < ././tag/create_invalid_tag: line 9: tmsu: command not found
    < ././tag/create_invalid_tag: line 10: tmsu: command not found
    < ././tag/create_invalid_tag: line 11: tmsu: command not found
    < ././tag/create_invalid_tag: line 12: tmsu: command not found
    < ././tag/create_invalid_tag: line 13: tmsu: command not found
    < ././tag/create_invalid_tag: line 14: tmsu: command not found
    < ././tag/create_invalid_tag: line 15: tmsu: command not found
    < ././tag/create_invalid_tag: line 16: tmsu: command not found
    < ././tag/create_invalid_tag: line 17: tmsu: command not found
    < ././tag/create_invalid_tag: line 18: tmsu: command not found
    < ././tag/create_invalid_tag: line 19: tmsu: command not found
    < ././tag/create_invalid_tag: line 20: tmsu: command not found
    < ././tag/create_invalid_tag: line 21: tmsu: command not found
    < ././tag/create_invalid_tag: line 22: tmsu: command not found
    < ././tag/create_invalid_tag: line 23: tmsu: command not found
    < ././tag/create_invalid_tag: line 24: tmsu: command not found
    < ././tag/create_invalid_tag: line 25: tmsu: command not found
    ---
    > tmsu: could not create tag '.': tag name cannot be '.' or '..'
    > tmsu: could not create tag '..': tag name cannot be '.' or '..'
    > tmsu: could not create tag 'and': tag name cannot be a logical operator: 'and', 'or' or 'not'
    > tmsu: could not create tag 'or': tag name cannot be a logical operator: 'and', 'or' or 'not'
    > tmsu: could not create tag 'not': tag name cannot be a logical operator: 'and', 'or' or 'not'
    > tmsu: could not create tag 'eq': tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: could not create tag 'ne': tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: could not create tag 'lt': tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: could not create tag 'gt': tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: could not create tag 'le': tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: could not create tag 'ge': tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: could not create tag 'AND': tag name cannot be a logical operator: 'and', 'or' or 'not'
    > tmsu: could not create tag 'OR': tag name cannot be a logical operator: 'and', 'or' or 'not'
    > tmsu: could not create tag 'NOT': tag name cannot be a logical operator: 'and', 'or' or 'not'
    > tmsu: could not create tag 'EQ': tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: could not create tag 'NE': tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: could not create tag 'LT': tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: could not create tag 'GT': tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: could not create tag 'LE': tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    > tmsu: could not create tag 'GE': tag name cannot be a comparison operator: 'eq', 'ne', 'gt', 'lt', 'ge' or 'le'
    ./tag/create_invalid_tag [FAIL]
    1,2d0
    < ././tag/create_one_tag: line 5: tmsu: command not found
    < ././tag/create_one_tag: line 6: tmsu: command not found
    ./tag/create_one_tag [FAIL]
    1,2d0
    < ././tag/create_one_value: line 5: tmsu: command not found
    < ././tag/create_one_value: line 6: tmsu: command not found
    ./tag/create_one_value [FAIL]
    1,3d0
    < ././tag/create_tags_and_values: line 5: tmsu: command not found
    < ././tag/create_tags_and_values: line 6: tmsu: command not found
    < ././tag/create_tags_and_values: line 7: tmsu: command not found
    ./tag/create_tags_and_values [FAIL]
    1,2d0
    < ././tag/create_two_tags: line 5: tmsu: command not found
    < ././tag/create_two_tags: line 6: tmsu: command not found
    ./tag/create_two_tags [FAIL]
    1,2d0
    < ././tag/create_two_values: line 5: tmsu: command not found
    < ././tag/create_two_values: line 6: tmsu: command not found
    ./tag/create_two_values [FAIL]
    1,5c1,2
    < ././tag/explicitly_apply_tag_already_implied_by_previous_tags: line 9: tmsu: command not found
    < ././tag/explicitly_apply_tag_already_implied_by_previous_tags: line 10: tmsu: command not found
    < ././tag/explicitly_apply_tag_already_implied_by_previous_tags: line 11: tmsu: command not found
    < ././tag/explicitly_apply_tag_already_implied_by_previous_tags: line 12: tmsu: command not found
    < ././tag/explicitly_apply_tag_already_implied_by_previous_tags: line 13: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'vegetable'
    ./tag/explicitly_apply_tag_already_implied_by_previous_tags [FAIL]
    1,4c1,2
    < ././tag/explicitly_apply_two_tags_where_one_implies_the_other: line 9: tmsu: command not found
    < ././tag/explicitly_apply_two_tags_where_one_implies_the_other: line 10: tmsu: command not found
    < ././tag/explicitly_apply_two_tags_where_one_implies_the_other: line 11: tmsu: command not found
    < ././tag/explicitly_apply_two_tags_where_one_implies_the_other: line 12: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'vegetable'
    ./tag/explicitly_apply_two_tags_where_one_implies_the_other [FAIL]
    1,2c1
    < ././tag/force_apply_tag_to_nonexistant_file: line 5: tmsu: command not found
    < ././tag/force_apply_tag_to_nonexistant_file: line 6: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    ./tag/force_apply_tag_to_nonexistant_file [FAIL]
    1,2c1
    < ././tags/escaped_characters: line 5: tmsu: command not found
    < ././tags/escaped_characters: line 9: tmsu: command not found
    ---
    > tmsu: new tag 'crocodile'
    ./tags/escaped_characters [FAIL]
    1,3c1,2
    < ././tags/explicit_only: line 6: tmsu: command not found
    < ././tags/explicit_only: line 7: tmsu: command not found
    < ././tags/explicit_only: line 11: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'vegetable'
    ./tags/explicit_only [FAIL]
    1,2c1
    < ././tags/one_file_one_tag: line 6: tmsu: command not found
    < ././tags/one_file_one_tag: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    ./tags/one_file_one_tag [FAIL]
    1,2c1
    < ././tags/one_file_one_tag_count: line 6: tmsu: command not found
    < ././tags/one_file_one_tag_count: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    ./tags/one_file_one_tag_count [FAIL]
    1,2c1,2
    < ././tags/one_file_two_tags: line 6: tmsu: command not found
    < ././tags/one_file_two_tags: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'potato'
    ./tags/one_file_two_tags [FAIL]
    1,2c1,2
    < ././tags/one_file_two_tags_count: line 6: tmsu: command not found
    < ././tags/one_file_two_tags_count: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'potato'
    ./tags/one_file_two_tags_count [FAIL]
    1,2c1,2
    < ././tags/one_file_two_tags_list: line 6: tmsu: command not found
    < ././tags/one_file_two_tags_list: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'potato'
    ./tags/one_file_two_tags_list [FAIL]
    1,3c1,4
    < ././tags/tags_for_values: line 6: tmsu: command not found
    < ././tags/tags_for_values: line 7: tmsu: command not found
    < ././tags/tags_for_values: line 11: tmsu: command not found
    ---
    > tmsu: new tag 'color'
    > tmsu: new value 'orange'
    > tmsu: new tag 'fruit'
    > tmsu: '/tmp/tmsu/file2' is a duplicate
    ./tags/tags_for_values [FAIL]
    1,2c1
    < ././tags/two_files_one_tag: line 7: tmsu: command not found
    < ././tags/two_files_one_tag: line 11: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    ./tags/two_files_one_tag [FAIL]
    1,2c1
    < ././tags/two_files_one_tag_count: line 7: tmsu: command not found
    < ././tags/two_files_one_tag_count: line 11: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    ./tags/two_files_one_tag_count [FAIL]
    1,2c1,2
    < ././tags/two_files_two_tags: line 7: tmsu: command not found
    < ././tags/two_files_two_tags: line 11: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'potato'
    ./tags/two_files_two_tags [FAIL]
    1,2c1,2
    < ././tags/two_files_two_tags_count: line 7: tmsu: command not found
    < ././tags/two_files_two_tags_count: line 11: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'potato'
    ./tags/two_files_two_tags_count [FAIL]
    1,2c1,2
    < ././tags/two_files_two_tags_list: line 7: tmsu: command not found
    < ././tags/two_files_two_tags_list: line 11: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'potato'
    ./tags/two_files_two_tags_list [FAIL]
    1,5c1,2
    < ././untag/unapply_all_tags: line 6: tmsu: command not found
    < ././untag/unapply_all_tags: line 7: tmsu: command not found
    < ././untag/unapply_all_tags: line 8: tmsu: command not found
    < ././untag/unapply_all_tags: line 9: tmsu: command not found
    < ././untag/unapply_all_tags: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'potato'
    ./untag/unapply_all_tags [FAIL]
    1,5c1,2
    < ././untag/unapply_all_tags_from_multiple_files: line 7: tmsu: command not found
    < ././untag/unapply_all_tags_from_multiple_files: line 8: tmsu: command not found
    < ././untag/unapply_all_tags_from_multiple_files: line 9: tmsu: command not found
    < ././untag/unapply_all_tags_from_multiple_files: line 10: tmsu: command not found
    < ././untag/unapply_all_tags_from_multiple_files: line 11: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'potato'
    ./untag/unapply_all_tags_from_multiple_files [FAIL]
    1,5c1
    < ././untag/unapply_one_of_one_tags: line 6: tmsu: command not found
    < ././untag/unapply_one_of_one_tags: line 7: tmsu: command not found
    < ././untag/unapply_one_of_one_tags: line 8: tmsu: command not found
    < ././untag/unapply_one_of_one_tags: line 9: tmsu: command not found
    < ././untag/unapply_one_of_one_tags: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    ./untag/unapply_one_of_one_tags [FAIL]
    1,5c1
    < ././untag/unapply_one_of_one_tags_from_directory_nonrecursively: line 7: tmsu: command not found
    < ././untag/unapply_one_of_one_tags_from_directory_nonrecursively: line 8: tmsu: command not found
    < ././untag/unapply_one_of_one_tags_from_directory_nonrecursively: line 9: tmsu: command not found
    < ././untag/unapply_one_of_one_tags_from_directory_nonrecursively: line 10: tmsu: command not found
    < ././untag/unapply_one_of_one_tags_from_directory_nonrecursively: line 11: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    ./untag/unapply_one_of_one_tags_from_directory_nonrecursively [FAIL]
    ././untag/unapply_one_of_one_tags_from_directory_recursively: line 14: tmsu: command not found
    1,4c1
    < ././untag/unapply_one_of_one_tags_from_directory_recursively: line 10: tmsu: command not found
    < ././untag/unapply_one_of_one_tags_from_directory_recursively: line 11: tmsu: command not found
    < ././untag/unapply_one_of_one_tags_from_directory_recursively: line 12: tmsu: command not found
    < ././untag/unapply_one_of_one_tags_from_directory_recursively: line 13: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    ./untag/unapply_one_of_one_tags_from_directory_recursively [FAIL]
    1,5c1
    < ././untag/unapply_one_of_one_tags_from_mulitple_files: line 7: tmsu: command not found
    < ././untag/unapply_one_of_one_tags_from_mulitple_files: line 8: tmsu: command not found
    < ././untag/unapply_one_of_one_tags_from_mulitple_files: line 9: tmsu: command not found
    < ././untag/unapply_one_of_one_tags_from_mulitple_files: line 10: tmsu: command not found
    < ././untag/unapply_one_of_one_tags_from_mulitple_files: line 11: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    ./untag/unapply_one_of_one_tags_from_mulitple_files [FAIL]
    1,5c1,2
    < ././untag/unapply_one_of_two_tags: line 6: tmsu: command not found
    < ././untag/unapply_one_of_two_tags: line 7: tmsu: command not found
    < ././untag/unapply_one_of_two_tags: line 8: tmsu: command not found
    < ././untag/unapply_one_of_two_tags: line 9: tmsu: command not found
    < ././untag/unapply_one_of_two_tags: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'potato'
    ./untag/unapply_one_of_two_tags [FAIL]
    1,5c1,2
    < ././untag/unapply_one_of_two_tags_from_multiple_files: line 7: tmsu: command not found
    < ././untag/unapply_one_of_two_tags_from_multiple_files: line 8: tmsu: command not found
    < ././untag/unapply_one_of_two_tags_from_multiple_files: line 9: tmsu: command not found
    < ././untag/unapply_one_of_two_tags_from_multiple_files: line 10: tmsu: command not found
    < ././untag/unapply_one_of_two_tags_from_multiple_files: line 11: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'potato'
    ./untag/unapply_one_of_two_tags_from_multiple_files [FAIL]
    1,5c1,2
    < ././untag/unapply_two_of_two_tags: line 6: tmsu: command not found
    < ././untag/unapply_two_of_two_tags: line 7: tmsu: command not found
    < ././untag/unapply_two_of_two_tags: line 8: tmsu: command not found
    < ././untag/unapply_two_of_two_tags: line 9: tmsu: command not found
    < ././untag/unapply_two_of_two_tags: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'potato'
    ./untag/unapply_two_of_two_tags [FAIL]
    1,5c1,2
    < ././untag/unapply_two_of_two_tags_from_multiple_files: line 7: tmsu: command not found
    < ././untag/unapply_two_of_two_tags_from_multiple_files: line 8: tmsu: command not found
    < ././untag/unapply_two_of_two_tags_from_multiple_files: line 9: tmsu: command not found
    < ././untag/unapply_two_of_two_tags_from_multiple_files: line 10: tmsu: command not found
    < ././untag/unapply_two_of_two_tags_from_multiple_files: line 11: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    > tmsu: new tag 'potato'
    ./untag/unapply_two_of_two_tags_from_multiple_files [FAIL]
    1,3c1,2
    < ././untag/unapply_value: line 6: tmsu: command not found
    < ././untag/unapply_value: line 10: tmsu: command not found
    < ././untag/unapply_value: line 14: tmsu: command not found
    ---
    > tmsu: new tag 'year'
    > tmsu: new value '2015'
    ./untag/unapply_value [FAIL]
    1d0
    < ././untagged/count_untagged: line 12: tmsu: command not found
    ./untagged/count_untagged [FAIL]
    1d0
    < ././untagged/count_untagged_nonrecursively: line 11: tmsu: command not found
    ./untagged/count_untagged_nonrecursively [FAIL]
    ././untagged/list_untagged: line 13: tmsu: command not found
    1c1
    < ././untagged/list_untagged: line 9: tmsu: command not found
    ---
    > tmsu: new tag 'aubergine'
    ./untagged/list_untagged [FAIL]
    1d0
    < ././untagged/list_untagged_nonrecursively: line 11: tmsu: command not found
    ./untagged/list_untagged_nonrecursively [FAIL]
    1,2c1,3
    < ././values/list_value_count: line 6: tmsu: command not found
    < ././values/list_value_count: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'year'
    > tmsu: new value '2015'
    > tmsu: new value '2016'
    ./values/list_value_count [FAIL]
    1,2c1,5
    < ././values/list_value_count_for_tag: line 6: tmsu: command not found
    < ././values/list_value_count_for_tag: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'vegetable'
    > tmsu: new value 'brocolli'
    > tmsu: new tag 'year'
    > tmsu: new value '2015'
    > tmsu: new value '2016'
    ./values/list_value_count_for_tag [FAIL]
    1,2c1,3
    < ././values/list_values: line 6: tmsu: command not found
    < ././values/list_values: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'year'
    > tmsu: new value '2015'
    > tmsu: new value '2016'
    ./values/list_values [FAIL]
    1,2c1,5
    < ././values/list_values_for_tag: line 6: tmsu: command not found
    < ././values/list_values_for_tag: line 10: tmsu: command not found
    ---
    > tmsu: new tag 'vegetable'
    > tmsu: new value 'brocolli'
    > tmsu: new tag 'year'
    > tmsu: new value '2015'
    > tmsu: new value '2016'
    ./values/list_values_for_tag [FAIL]
    make: *** [Makefile:48: integration-test] Error 146
    
    opened by RenaKunisaki 9
  • [Feature Request] Libraries

    [Feature Request] Libraries

    Libraries would be a great way to organise tagged files via a special kind of tag If we were to view it as a file structure, libraries would be at the root. For example:

    ├── Camera Roll
    │   ├── queries
    │   └── tags
    ├── Cute Animals
    │   ├── queries
    │   └── tags
    ├── Memes
    │   ├── queries
    │   └── tags
    └── Movies
        ├── queries
        └── tags
    

    Viewing all files with the tag dog in Camera Roll won't show any files with the same tag in Cute Animals, and movies tagged star wars won't show up when searching for star wars in Memes In addition to this, some libraries should be hidden like .files

    For backwards compatibility, perhaps an "All" library should be added, which just contains everything across libraries (unless it's a hidden library?)

    EDIT: Others have pointed out that this might be good as an extension of the query function

    opened by Qwerty-Space 3
  • Remove tag with value just with the key

    Remove tag with value just with the key

    Hi!

    I noticed that, when a tag with value of type color=blue is attributed to a file, one can remove this tag only by specifying both tag and value, for example with tmsu untag file -t color=blue. I would find it nice to be able to do this just by giving the tag name, like tmsu untag file -t color. Is it planned to implement this?

    Best regards

    opened by maxclac 0
  • Implement BASH completion

    Implement BASH completion

    Known limitations:

    1. Does not work correctly if there is 2 (or more) tags with spaces in them and the parts before the spaces match (e.g. "space tag1" and "space tag2");
    2. Subcommand 'tag' is not completed correctly if options '-f/--from/-t/--tags/-w/--where' are not last;
    3. Subcommand 'untag' is not completed correctly if option '-t/--tags' is not last;
    4. Completion of subcommands 'files' and 'tag' (which can use queries) does not show operators in queries because some of them are not completed correctly (or at all) so they should be entered by hand.
    opened by oratosquilla-oratoria 0
  • Updated for Go (1.16) modules

    Updated for Go (1.16) modules

    opened by xxxserxxx 0
  • A tag may imply itself

    A tag may imply itself

    Reproduction:

    1. cd /tmp; tmsu init
    2. touch b; tmsu tag b tag
    3. tmsu imply tag tag
    4. tmsu files tag (hangs forever at 100% CPU)

    All queries involving the circular tag are affected. And yes, I actually did do the equivalent of this, with a little fzf selection that made it less obvious that what I was doing was absurd.

    opened by 0ion9 1
  • Change project structure to fix isse #224

    Change project structure to fix isse #224

    Using make to build this project does not work currently, at least not with go version 1.16.2. This pull request fixes this by moving the code to the root of the repo, turning it into a go module and adjusting the Makefile. Also, this will allow users to install TMSU with go install github.com/oniony/TMSU if they have their GOPATH set up. This will fix issue #224

    opened by ekkkkkknoes 0
  • Add Nix/NixOS packages

    Add Nix/NixOS packages

    Just adding Nix/NixOS packages, not maintained by me (but I use it).

    opened by alexandregv 0
  • Look for DB relative to file location?

    Look for DB relative to file location?

    I have a database file in a subdirectory for example ~/movies/.tmsu/db. If I try to list the tags for a file in movies/sub/path/ while I'm in my home directory, I get an error:

    tmsu: no database found: use 'tmsu init' to create one
    

    but if I move to ~/movies/ or a subdirectory ~/movies/ then it finds the DB.

    I feel like it is more intuitive if the directory of the file and its parent directories are part of the search paths for the DB. This should only be done after parents are searched and ~/.tmsu/defaultdb is not found.

    For example, if the current directory is ~ and the db is ~/movies/.tmsu/db then running tmsu tags ~/movies/sub/path/1.mp4 should check in this order (I assume it keeps looking at parents until it gets to the root):

    1. ~/.tmsu/db
    2. /home/.tmsu/db
    3. /.tmsu/db
    4. ~/.tmsu/defaultdb
    5. ~/movies/sub/path/.tmsu/db
    6. ~/movies/sub/.tmsu/db
    7. ~/movies/.tmsu/db
    8. ~/.tmsu/db
    9. /home/.tmsu/db
    10. /.tmsu/db

    (Yes, it can end up checking for the same files twice, but I don't think that's a big deal, and avoiding that would increase complexity and would be a premature optimization)

    Let me know if you are ok with this change and I will open a PR.

    opened by joehillen 0
  • Can't build TMSU

    Can't build TMSU

    Hello. I can't build TMSU, I installed dependencies and inside TMSU folder when call make it says this:

    CLEANING
    
    go clean github.com/oniony/TMSU
    no required module provides package github.com/oniony/TMSU: working directory is not part of a module
    make: *** [Makefile:24: clean] Error 1
    
    opened by NaurizAitbai 3
  • Dereference directory symlinks rather than only file symlinks

    Dereference directory symlinks rather than only file symlinks

    This issue was brought up as a comment in issue #154: tagging a file in a symlinked directory gives a different result depending on whether the given path is relative or absolute.

    opened by lefth 0
Releases(v0.7.5)
  • v0.7.5(Dec 2, 2019)

  • v0.7.4(Nov 7, 2018)

  • v0.7.3(Oct 13, 2018)

  • v0.7.2(Oct 5, 2018)

  • v0.7.1(Sep 3, 2018)

    DO NOT USE

    Bug fix release:

    • Wrong files would be returned when an tag=value implied another tag
    • Specifying empty FUSE options would cause Fusermount to fail
    • Manual repair would drop the file fingerprint

    This version has a bug with the VFS that means value directories are not show. Also note that the version number is wrong (0.7.0 rather than 0.7.1)

    Source code(tar.gz)
    Source code(zip)
    tmsu-x86_64-0.7.0.tgz(3.54 MB)
  • v0.7.0(Nov 8, 2017)

    Note: this release changes how symbolic links are handled. See below.

    • TMSU now compiles for Mac O/S. (Thanks to https://github.com/pguth.)
    • The VFS no longer lists files alongside the tag directories under tags. Instead there are results directories at each level, within which you can find the set of symbolic links to the tagged files.
    • Symbolic links are now followed by default. This means that if you tag a symbolic link, the target file is tagged instead. To instruct TMSU to not follow symbolic links (previous behaviour) use the new --no-dereference option on the relevant subcommands.
    • Added new setting symlinkFingerprintAlgorithm to allow the fingerprint algorithm for symbolic links to be configured separately to regular files.
    • By default duplicate files will now be reported when tagging. A new setting reportDuplicates can be used to turn this off.
    • Slashes are now permitted within tags and values, useful for recording URLs. In the virtual filesystem, similar looking Unicode characters are used in their place.
    • Added --where option to tag subcommand to allow tags to be applied to the set of files matching a query.
    • The VFS tags directory will now relist tags that have values so that multiple values can be specified, e.g. tags/color/=red/color/=blue.
    • It is now possible to list tags that use a particular value with the new --value option on the 'tags' subcommand.
    • Made it possible to upgrade the database schema between releases.
    • Added --count option to untagged.
    • Bug fixes.
    Source code(tar.gz)
    Source code(zip)
    tmsu-x86_64-0.7.0.tgz(3.19 MB)
  • v0.6.1(Mar 4, 2016)

  • v0.6.0(Nov 23, 2015)

    • Relaxed restrictions on tag and value names: in particular whitespace is now supported.
    • Tag values are no longer automatically deleted when last usage is removed: they must now be managed manually. (Removing these checks improve performance of untagging operations.)
    • Tag values can now be renamed, deleted and merged using the new --value option on the corresponding subcommands.
    • Tag values can now be used in implications.
    • Fixed "too many SQL variables" bug.
    • Output of files can now be sorted using the --sort option.
    • stats subcommand has been replaced by a --stats option on the new info subcommand.
    • Included some scripts for making destructive changes to the filesystem. (By having these operations in separate scripts rather than as core functionality TMSU remains non-destructive.)
      • tmsu-fs-rm removes a file from the filesystem and TMSU database
      • tmsu-fs-mv moves a file elsewhere on the filesystem and updates the TMSU database
      • tmsu-fs-merge deletes all but that last argument and merges their tags in the TMSU database

    And other bug fixes and performance improvements.

    Source code(tar.gz)
    Source code(zip)
    tmsu-i686-0.6.0.tgz(2.61 MB)
    tmsu-Win64-0.6.0.zip(2.47 MB)
    tmsu-x86_64-0.6.0.tgz(2.60 MB)
  • v0.5.2(Mar 13, 2015)

  • v0.5.1(Feb 9, 2015)

  • v0.5.0(Feb 7, 2015)

    Warning: there is a bug in this version that means the database will not be created if the .tmsu directory does not exist. Please create the directory by hand (e.g. mkdir ~/.tmsu) until this is fixed.

    Note: This release has some important changes, including the renaming of some options, the introduction of local databases and a switch from absolute to relative paths in the database. Please read the following release notes carefully.

    • The --untagged option on the 'files' and 'status' subcommands has been replaced by a new 'untagged' subcommand, which should be more intuitive.
    • The --all option on the 'files', 'tags' and 'values' subcommands has been removed. These commands now list the full set of files/tags/values when run without arguments. For the 'tags' subcommand this replaces the previous behaviour of listing tags for the files in the working directory: use 'tmsu tags *' for approximately the previous behaviour.
    • The 'repair' subcommand --pretend short option has changed from -p to -P (so that -p can be recycled for --path).
    • The 'repair' subcommand's argument now specify paths to search for moved files and no longer limit how much of the database is repaired. A new --path argument is provided for reducing the repair to a portion of the database.
    • A new --manual option on the 'repair' subcommand allows targetted repair of moved files or directories.
    • The exclamation mark character (!) is no longer permitted within a tag or value name. Please rename tags using the 'rename' command. (Value names will need to be updated manually using the Sqlite3 tooling.)
    • Added --colour option to the 'tags' subcommand to highlight implied tags.
    • 'tag' subcommand will, by default, no longer explicitly apply tags that are already implied (unless the new --explicit option is specified).
    • Added subcommand aliases, e.g. 'query' for 'files'.
    • It is now possible to tag a broken symbolic link: instead of an error this will now be reported as a warning.
    • It is now possible to remove tags with values via the VFS.
    • 'tag' subcommand can tag multiple files with different tags by reading from standard input by passing an argument of '-'.
    • TMSU will now automatically use a local database in .tmsu/db in working directory or any parent. The new 'init' subcommand allows a new local database to be initialized. See Switching Databases for detail.
    • Paths are now stored relative to the .tmsu directory's parent rather than as absolute paths. This allows a branch of the filesystem to be moved around, shared or archived whilst preserving the tagging information. Existing absolute paths can be converted by running a manual repair: tmsu repair --manual / /
    • Added 'config' subcommand to view and amend settings.
    • The 'help' subcommand now wraps textual output to fit the terminal.
    • Rudimentary Microsoft Windows support (no virtual filesystem yet).
    • TMSU can now be built without the Makefile.
    • Bug fixes.
    Source code(tar.gz)
    Source code(zip)
    tmsu-i686-0.5.0.tgz(2.25 MB)
    tmsu-x86_64-0.5.0.tgz(2.51 MB)
    tmsu-x86_64-0.5.0.zip(1.42 MB)
  • v0.2.0(Dec 5, 2014)

    • Added support for tag implications, e.g. tag 'a' implies 'b'. New 'imply' subcommand for managing these.
    • Added --force option to 'repair' subcommand to remove missing files (and associated taggings) from the database.
    • Added --from option to 'tag' subcommand to allow tags to copied from one file to another. e.g. 'tmsu tag -f a b' will apply file b's tags to file a. ('tag -r -f a a' will recursively retag a directory's contents.)
    • Added --directory option to 'status' subcommand to stop it recursively processing directory contents.
    • Added --print0 option to 'files' subcommand to allow use with xargs.
    • Added --count option to 'tags' and 'files' subcommand to list tag/file count rather than names.
    • Bug fixes and unit-test improvements.
    Source code(tar.gz)
    Source code(zip)
    tmsu-i686-0.2.0.tgz(1.07 MB)
  • v0.3.0(Dec 5, 2014)

    Note: This release changes what tag names are allowed. To ensure the tag names in your existing databases are still valid, please run the following script:

    $ cp ~/.tmsu/default.db ~/.tmsu/default.db.backup
    $ sqlite3 -init misc/db-upgrade/clean_tag_names.sql ~/.tmsu/default.db
    
    • Added support for file queries, e.g. 'fish and chips and (mushy-peas or ketchup)'.
    • Added support for file query directories in the virtual filesystem.
    • Added global option --database for specifying database location.
    • Added ability to rename and delete tags via the virtual filesystem.
    • 'tag' subcommand now allows tags to be created up front.
    • 'copy' and 'imply' subcommands now support multiple destination tags.
    • Improved 'stats' subcommand.
    • Added man page.
    • Added script to allow the virtual filesystem to be mounted via the system 'mount' command or on startup via the fstab.
    • Bug fixes.
    Source code(tar.gz)
    Source code(zip)
    tmsu-i686-0.3.0.tgz(1.94 MB)
  • v0.4.0(Dec 5, 2014)

    Note: This release changes the database schema to facilitate tag values. To upgrade your existing v0.3.0 database please run the following:

    $ cp ~/.tmsu/default.db ~/.tmsu/default.db.backup
    $ sqlite3 -init misc/db-upgrade/0.3_to_0.4.0.sql ~/.tmsu/default.db .q
    
    • Added support for tag values, e.g. 'tmsu tag song.mp3 country=uk' and the querying of files based upon these values, e.g. 'year > 2000'.
    • 'tags' and 'values' subcommands now tabulate output, by default, when run from terminal.
    • Added ability to configure which fingerprint algorithm to use.
    • Implied tags now calculated on-the-fly when the database is queried. This results in a (potentially) smaller database and ability to have updates to the implied tags affect previously tagged files.
    • Added --explicit option to 'files' and 'tags' subcommands to show only explicit tags (omitting any implied tags).
    • Added --path option to 'files' subcommand to retrieve just those files matching or under the path specified.
    • Added --untagged option to 'files' subcommand which, when combined with --path, will also include untagged files from the filesystem at the specified path.
    • Removed the --recursive option from the 'files' subcommand which was flawed: use 'tmsu files query | xargs find' instead.
    • Added ability to configure whether new tags and values are automatically created or not or a per-database basis.
    • Added --unmodified option to 'repair' subcommand to force the recalculation of fingerprints of unmodified files.
    • Renamed --force option of 'repair' subcommand to --remove.
    • Added support for textual comparison operators: 'eq', 'ne', 'lt', 'gt', 'le' and 'ge', which do not need escaping unlike '<', '>', &c.
    • Improved Zsh completion with respect to tag values.
    • Significant performance improvements.
    • Removed support for '-' operator: use 'not' instead.
    • Bug fixes.
    Source code(tar.gz)
    Source code(zip)
    tmsu-i686-0.4.0.tgz(1.98 MB)
  • v0.4.1(Dec 5, 2014)

  • v0.4.2(Dec 5, 2014)

Owner
Paul Ruane
Programming since I was 8, I started career in Java in 1999 and then switched over to C#. But, for my own projects, I favour Go or, more recently Rust.
Paul Ruane
Squash’s front-end and API host.

Squash: A squarish bug spray An open-source project from Square Squash is a collection of tools that help engineers find and kill bugs in their code b

null 968 Sep 9, 2021
Open source back-end server for web, mobile and IoT. The backend for busy developers. (self-hosted or hosted)

A scalable, multitenant backend for the cloud. Para is a scalable, multitenant backend server/framework for object persistence and retrieval. It helps

Erudika 408 Sep 20, 2021
Virtual Mailbox Administration

ViMbAdmin Virtual Mailbox Administration The ViMbAdmin project (vim-be-admin) provides a web based virtual mailbox administration system to allow mail

Open Solutions 451 Aug 10, 2021
Open source API management platform

About Fusio is an open source API management platform which helps to build and manage REST APIs. Fusio provides all tools to quickly build an API from

Apioo 997 Sep 15, 2021
AlertHub is a simple tool written with NodeJS to get alerted from new GitHub and GitLab repository events.

AlertHub _ _ _ _ /_\ | | ___ _ __| |_ /\ /\_ _| |__ //_\\| |/ _ \ '__| __|/ /_/ / | | | '_ \ / _ \ | __/ | |

Arda Kılıçdağı 101 Aug 31, 2021
Extremely fast tool to remove duplicates and other lint from your filesystem

rmlint finds space waste and other broken things on your filesystem and offers to remove it. Features: Finds… …Duplicate Files and duplicate directori

Chris Pahl 1.1k Sep 17, 2021
Online genealogy

webtrees - online collaborative genealogy Contents License Coding styles and standards Introduction System requirements Internet browser compatibility

Greg Roach 582 Sep 15, 2021
Personal CRM. Remember everything about your friends, family and business relationships.

Personal Relationship Manager Monica is a great open source personal relationship management system. Introduction Purpose Features Who is it for? What

Monica 13.3k Sep 24, 2021
Type emoji easily! Virtual keyboard-like emoji palette for Linux with lots of features.

Emoji keyboard Virtual keyboard-like emoji palette for Linux. If you find this software useful, please Emoji support on Linux is shaky at best. Modern

Tomas Ravinskas 243 Aug 31, 2021
Multi-platform app that allows your devices to communicate

KDE Connect - desktop app KDE Connect is a multi-platform app that allows your devices to communicate (eg: your phone and your computer). (Some) Featu

KDE GitHub Mirror 1.2k Sep 15, 2021
Display and control your Android device

scrcpy (v1.17) Read in another language This application provides display and control of Android devices connected on USB (or over TCP/IP). It does no

Genymobile 54.9k Sep 23, 2021
📻 Webserver for downloading youtube videos. Ready for docker.

?? ytdl-webserver Webserver for downloading youtube videos. Ready for docker. Demo If you have questions, read the blog post. Installation As a server

null 1.3k Sep 15, 2021
Sharetribe Go is a source available marketplace software, also available as a hosted, no-code SaaS product. For a headless, API-first marketplace solution, check out Sharetribe Flex: https://www.sharetribe.com/flex.

Sharetribe Sharetribe develops advanced marketplace software for every business life cycle stage. Sharetribe Go gives you the complete feature set to

Sharetribe 2.2k Sep 24, 2021
The Cyber Swiss Army Knife - a web app for encryption, encoding, compression and data analysis

CyberChef The Cyber Swiss Army Knife CyberChef is a simple, intuitive web app for carrying out all manner of "cyber" operations within a web browser.

GCHQ 12.9k Sep 17, 2021
Graphical program used to map keyboard buttons and mouse controls to a gamepad. Useful for playing games with no gamepad support

antimicro ?? Important update ?? This repo is currently unmaintained. The code hasn't been updated for a while. But not all is lost, antimicro has a f

null 1.5k Sep 24, 2021
Read-only mirror of https://gitlab.gnome.org/GNOME/brasero

Brasero is a CD/DVD mastering tool for the GNOME Desktop. It is designed to be simple and easy to use. Features: Data CD/DVD: - supports edition of

GNOME Github Mirror 42 Sep 13, 2021
Create agents that monitor and act on your behalf. Your agents are standing by!

What is Huginn? Huginn is a system for building agents that perform automated tasks for you online. They can read the web, watch for events, and take

Huginn 32.2k Sep 15, 2021
A black hole for Internet advertisements

Network-wide ad blocking via your own Linux hardware The Pi-hole® is a DNS sinkhole that protects your devices from unwanted content, without installi

Pi-hole 32.5k Sep 17, 2021