Use tool of your choice to perform IO operations in donnatella

A few changes have just been pushed to branch next of donnatella, introducing some changes when it comes to IO operations (i.e. copy/move/delete files).

Starting at the top: donnatella doesn't perform any such IO operations itself. This isn't a not-yet-implemented feature but a design choice: there are plenty of tools which specialized in such things, no need to re-invent the wheel, let's use the existing ones instead!

So when you copy/move/delete files in donna, it will actually run cp/mp/rm to perform the operation (parsing the output to determine what was done/ask confirmations/etc).

This is good, but quite limited. In fact, when it comes to GUI operations one might expect to have, in case e.g. a file already exists, a detailled window with information about both files, and possibilities to skip, overwrite, rename, etc.

None of that is currently possible, though - truth be told - it's on a todo list of mine (though not as part of donna, but an external tool).

IO Engines

To try to maybe help and offer more possibilities, donna now introduces the notion of IO engines, giving you the ability to choose which one to use.

New options providers/fs/engine_{copy,move,delete} have been added, and must be set to the name of the IO engine to use to perform copy, move or delete operations respectively.

By default, donna uses the basic IO engine, the one "wrapping" cp/mv/rm as needed. But another one is now avaialable as well, called exec

IO Engine "exec"

This engine simply allows you to specify a command line to be executed to perform the corresponding IO operation. Therefore, you can now use about any tool you want to perform IO operation in donna, e.g. use rsync to copy files.

As you may know, in donna an IO operation comes from command nodes_io() where the source(s), destination (if any) and type of operation (copy/move/delete) are specified.

Optionally, for copy/move operation with a single source, a new name can be specified, to rename the item as it is copied/moved.

The command-line to be used when IO engine exec is used are defined under providers/fs/ioengine-exec and are named:

  • copy_cmdline : for copy operations
  • copy_cmdline_new_name : for copy operations with a new name specified (implies a single source)
  • move_cmdline : for move operations
  • move_cmdline_new_name : for move operations with a new name specified (implies a single source)
  • delete_cmdline : for delete operations

Those command-lines support the following variables :

  • %s : the source node(s)
  • %d : the destination node
  • %n : the new name

It should be noted that because behind %s and %d are nodes, they should most likely be used with FS dereferencing, e.g. cp -irvat %:d %:s

Similarly, you'll want to use %'n to have the new name escaped in a shell-compatible way.

The options allow you to define a command line, but the way it will be processed is actually as a location in provider "exec" which means that, for instance, you can use supported prefixes to e.g. execute it inside a(n embedded) terminal.


It is important to note that nodes_io() usually returns an array of nodes, of the copied/moved files. This is obviously not possible when using IO engine "exec" since it has no awareness of what actually gets done.

As a result, using it will have the command return nothing, which could lead to errors if you tried to get/used the command's return value furthermore. For such cases, you might need to use another engine (e.g basic).

Command fs_nodes_io()

A new command has also been added, which works just like nodes_io() except that :

  • it takes an extra optional argument, the name of the IO engine to use;
  • if said argument isn't specified, different default options (fs_engine_{copy,move,delete}) are used before falling back to the main ones (engine_{copy,move,delete}).


As an example, one could decide to have e.g. copy and move operations be done via a small script wrapping cp/mv and to be run inside an embedded terminal.

To do so, one could set it up like so (note that we set the default for fs_nodes_io() back to "basic" so we can use that function to use the basic IO engine easilly) :

copy_cmdline=!!donna-io cp %:d %:s
copy_cmdline_new_name=!!donna-io cp-nn %:d %'n %:s
move_cmdline=!!donna-io mv %:d %:s
move_cmdline_new_name=!!donna-io mv-nn %:d %'n %:s

And the script in question could look something like this:

  1. #!/bin/bash
  3. ALL_OFF="\e[0m"
  4. BOLD="\e[1m"
  5. BLUE="${BOLD}\e[34m"
  6. GREEN="${BOLD}\e[32m"
  7. RED="${BOLD}\e[31m"
  8. YELLOW="${BOLD}\e[33m"
  10. msg() {
  11.     local mesg=$1; shift
  12.     printf "${GREEN}==>${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
  13. }
  15. error() {
  16.     local mesg=$1; shift
  17.     printf "${RED}==> ERROR:${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
  18. }
  20. err() {
  21.     error "$@"
  22.     exit 1
  23. }
  26. op=$1
  27. shift
  29. nn=0
  30. case $op in
  31.     "copy"|"cp")
  32.         op="cp"
  33.         action="Copying"
  34.         ;;
  36.     "copy-new-name"|"cp-nn")
  37.         op="cp-nn"
  38.         action="Copying"
  39.         nn=1
  40.         ;;
  42.     "move"|"mv")
  43.         op="mv"
  44.         action="Moving"
  45.         ;;
  47.     "move-new-name"|"mv-nn")
  48.         op="mv-nn"
  49.         action="Moving"
  50.         nn=1
  51.         ;;
  53.     "delete"|"rm")
  54.         op="rm"
  55.         action="Deleting"
  56.         ;;
  58.     *)
  59.         err "invalid operation '$op': must be 'copy', 'move' or 'delete'"
  60.         ;;
  61. esac
  63. if [[ $op = "rm" ]]; then
  64.     nb=$#
  65.     if [[ $nb -gt 1 ]]; then
  66.         msg "$action $nb files..."
  67.     elif [[ $nb -eq 1 ]]; then
  68.         msg "$action $1..."
  69.     else
  70.         err "missing source(s)"
  71.     fi
  72. else
  73.     dest=$1
  74.     shift
  75.     if [[ $nn -eq 1 ]]; then
  76.         new_name=$1
  77.         shift
  78.     fi
  80.     nb=$#
  81.     if [[ $nn -eq 1 ]]; then
  82.         msg "$action $1 as $dest/$new_name..."
  83.     elif [[ $nb -gt 1 ]]; then
  84.         msg "$action $nb files to $dest..."
  85.     elif [[ $nb -eq 1 ]]; then
  86.         msg "$action $1 to $dest..."
  87.     else
  88.         err "missing source(s)"
  89.     fi
  90. fi
  91. echo
  93. case $op in
  94.     "cp")
  95.         cp -irvat "$dest" "$@"
  96.         ;;
  98.     "cp-nn")
  99.         cp -irvaT "$@" "$d/$new_name"
  100.         ;;
  102.     "mv")
  103.         mv -ivt "$dest" "$@"
  104.         ;;
  106.     "mv-nn")
  107.         mv -ivT "$@" "$dest/$new_name"
  108.         ;;
  110.     "rm")
  111.         rm -Irv "$@"
  112.         ;;
  113. esac
  115. echo
  116. msg "done"

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.

Top of Page