Show & use any properties you want: donnatella adds custom properties!

Freshly pushed to the branch next on donnatella's github are a few commits, as usual some fixes and other improvements of course, but mainly this is about the addition of "custom properties."

As you may know, in donna everything is a node, and a node has properties. They are the name, size, dates and permissions of your files for example. But sometimes you need more than just those basic properties, and donna will let you use whatever you want...

Introducing custom properties

donnatella: Custom properties in action

It is now possible to easilly add properties to any nodes you want. The way this works is:

  1. you specify on which nodes to add the property. This will be done using donna's powerful filtering system.
  2. you specify the name (and type) of the property to add, as well as the command line that will be executed in order to get the property's value.
  3. voilà!

Well, almost. Obviously you then need to use this property; This will simply be done like with any other: create a new column for said property, and you'll be able to add this column whenever you need. You can even sort/filter via this column if you want.

How is a property's value obtained?

When donna needs to obtain/refresh a property, it will execute the specified command line for the custom property (CP), usually specifying the node (file) for which it is needed.

The process output will then be parsed, expecting to get a line with the node's location (e.g. /full/path/filename), a pipe sign as separator, the property's name, another pipe sign, and the value until the end of line (LF).

As you may have guessed, donna will try and "regroup" refresh requests, so that one process can be started to refresh a property on multiple nodes/files at once.

There's also the possibility of having multiple properties handled as a group (by one command line), for cases where the program reads the file and obtains all properties at once, hence the need for the property name as well.

Your first custom property

Custom properties can be of 2 types as of now: string, and uint (for sizes or timestamps). For a simple example, let's say we want to show the last commit message (from a git repo) associated with files/folders in a given repo. Somewhat like what you see on many git interfaces, starting with github.

The script for such a CP (named git-commit) could be something like the following:

  1. #!/bin/bash
  2. while [[ -n $1 ]]; do
  3.     file=$1
  4.     shift
  5.     path=${file%/*}
  6.     msg=$(git -C "$path" log -1 HEAD --format="format:%s" -- "$file")
  7.     echo "$file|git-commit|$msg"
  8. done

As for definning the property in donna, a simple config will do:

[custom_properties/]
domain=fs
filter=location:"^/path/to/project folder/"
[custom_properties//git-commit]
cmdline=git-commit %:n

The filter makes sure we only add this property to files in our project, and it assumes our script above - named after the CP - is in the path. %:n will put every file path/name in between quotes, as expected.

Obviously it requires a column "location" defined as such:

[defaults/lists/columns/location]
type:ct=text
property=location

The last thing left to do is show this property in a (new) column. The default configuration actually includes a column "text" which can be used here. A simple arrangement such as the following will do the trick :

[arrangements/]
mask=^/path/to/project folder
columns=ln,name,text,size,time,own,perms
[arrangements//columns_options/name]
width=200
[arrangements//columns_options/text]
title=Last Commit
width=230
property=git-commit
refresh_properties:col-rp=preload

This arrangement redefines the columns layout, adding our column text. Since a new column is added, we reduce the size of column name to make room for the new one, specifying the needed options to show our custom property.

When are CPs refreshed?

You'll probably have noticed option refresh_properties in our arrangement above: Indeed, by default donna only creates the CP on the node, but no value is set.

The idea is that if said property is never used, the value will never be needed, or refreshed. And only when it is needed will donna trigger the command line to refresh the value. As said before, it waits a little (about 800ms) before actually triggering the refresh, so one call can be done for multiple nodes/files at once.

However, sometimes this might not give the best results. There are a couple of possibilities:

  • you can set option preload to true when defining the CP, in which case a refresh request will be emitted right after the property has been added to a node. That way the property has a value set as soon as possible, but it also means it's always loaded, even when the node is simply used e.g. in a menu, and the CP never actually used.
  • you can use a column's option refresh_properties to define when the treeview will trigger a refresh of the property: visible (default) to do so only when the row is visible; preload to also request refresh for non-yet-visible rows (as in, scrolling is needed, this does not apply to hidden rows, e.g. via a visual filter); or on_demand to have a refresh icon shown in the column, requiring a user action (click on said icon) to trigger the refresh. The last option is especially useful when refreshing the property can be a slow operation, e.g. reading the entire file to calculate its hash (MD5, SHA1, etc).

Video properties: A group of CPs

Sometimes the program you'll use to refresh a property can get more than one property at once; for example imagine using mediainfo to get the duration, video & audio codecs from video files. One call to mediainfo can be used to get all 3 properties at once, and to allow to only run it once instead of three times, you can use groups.

Creating a group of properties is very muck like a "regular" CP; Here's an example:

[custom_properties/]
domain=fs
filter=name:"+f" AND name:"|$.avi|$.mp4|$.mkv"
[custom_properties//video]
is_group=true
cmdline=mediainfo --output=file:///path/to/template %:n
[custom_properties//video/duration]
[custom_properties//video/vcodec]
[custom_properties//video/acodec]

This creates a group "video" with 3 properties - "duration", "vcodec" and "acodec" - which will be expected to all be refreshed when the command line is executed. Obviously, if refresh requests of all 3 properties are performed on the same file, only one will be processed.

And to go along those CPs, here are corresponding columns :

[defaults/lists/columns/duration]
type:ct=text
title=Duration
width=80
property=duration
refresh_properties:col-rp=on_demand

[defaults/lists/columns/vcodec]
type:ct=text
title=Video
width=55
property=vcodec
refresh_properties:col-rp=on_demand

[defaults/lists/columns/acodec]
type:ct=text
title=Audio
width=55
property=acodec
refresh_properties:col-rp=on_demand

Add those columns in the appropriate arrangement, or toggle them manually, and you'll be able to get those video properties for any video file in one simple click on a refresh icon.

Note that one can also use command tv_column_refresh_nodes() to refresh such properties on one or more rows at once. For example, you could select all the files for which you want the properties refreshed, and use tv_column_refresh_nodes (:active,:selected,,duration) to refresh them all at once (i.e. in one single command line execution. Note that there might be more than one, as if requests for at least 20 nodes/files have been emitted, donna might not wait the full 800ms and trigger a command line execution before that). Only asking for one of the properties is enough to refresh them all, since they're in the same group.

Examples

A few more notes about the examples that can be seen in the screenshot on top.

Package version

The example shows the folder with the different PKGBUILDs I maintain. In addition to the last commit message for each folder, is a pkgver. This is simply done via a small script like the following:

  1. #!/bin/bash
  2. while [[ -n $1 ]]; do
  3.     file=$1
  4.     shift
  5.     if [[ -f "$file/PKGBUILD" ]]; then
  6.         ver=$(grep ^pkgver= "$file/PKGBUILD")
  7.         echo "$file|pkgver|${ver:7}"
  8.     else
  9.         # set the property to empty string (avoid try to refreshing it
  10.         # again if it had failed/not be set)
  11.         echo "$file|pkgver|"
  12.     fi
  13. done

Mediainfo

Here's the template file used with mediainfo to refresh the properties :

General;%CompleteName%|duration|%Duration/String3%\n
Video;|vcodec|%Codec/String%\n
Audio;|acodec|%Codec%\n

As you can see, it is possible not to repeat the full filename for each properties, omitting it and simply starting the line with a pipe sign will have donna use the last file.

It it also possible to first output a line with the full filename and a pipe sign at the end, nothing else (no property name/value), and then lines with properties names & value, starting with a pipe sign but omitting the full filename.

This obviously is only useful for groups (though supported all the time), when multiple properties are refreshed for each file.

File Hashes

Last example featured on the screenshot: here's how you could create a property "md5" that, when refreshed, would contain the MD5 of the file:

[custom_properties/]
domain=fs
filter=+f
[custom_properties//md5]
cmdline=sh -c 'md5sum %:n | awk '"'"'{ v=$1;$1="";print substr($0,2)"|md5|"v }'"'"

Remember that command lines in donnatella aren't shells, so to use any shell feature (e.g. pipe redirection) you need to start a shell.

(Also make sure to set the column's option refresh_properties to on_demand as to not have MD5 of every listed/visible files be calculated automatically - unless that's what you want, of course.)

Sorting & filtering via CPs

Quick note regarding performing operations such as sorting or filtering using custom properties: Obviously, it can be done exactly as with "regular" properties, and it'll work just the same.

However, note that if the properties' values aren't yet known, refresh requests will be triggered, but it will be done via single execution and in blocking manner.

So if not all rows have had their properties refreshed, it might be a good idea to refresh them all (e.g. using tv_column_refresh_nodes()) before.

One exception is when the column option refresh_properties is set to on_demand, in which case only known values will be used. When sorting, all unset values will be listed last, when filtering they will simply not match.

Where to get it?

For Arch Linux users, you can use donnatella-git in the AUR to easilly get it. Or simply clone the git repo from github and compile things yourself.

For a a complete list of all changes/bug fixes please refer to the git log.

And in case you read all that and are wondering what donnatella is, or are looking for more information, download links, etc please refer to donnatella.

As always, bug reports, suggestions or any other form of constructive criticism is very much welcome. You can open issues on github, use the thread on Arch Linux forums, or simply email me.

Edited on 2014-05-24: A recent change switched the separator used in the output parsed for custom properties from colon to pipe sign. This post has been edited to reflect the change.

Top of Page