Really productive day today, now that I'm out of the threaded runtime tarpit!
First, brought back --debug
logging, better than before! As part of that, I
wrote some 250 lines of code to provide a IMHO more pleasant interface to
System.Process
(itself only 650 lines of code) that avoids all the
low-level setup, cleanup, and tuple unpacking. Now I can do things like
write to a pipe to a process, and ensure it exits nonzero, this easily:
withHandle StdinHandle createProcessSuccess (proc "git" ["hash-object", "--stdin"]) $ \h ->
hHutStr h objectdata
My interface also makes it easy to run nasty background processes, reading their output lazily.
lazystring <- withHandle StdoutHandle createBackgroundProcess (proc "find" ["/"]) hGetContents
Any true Haskellers are shuddering here, I really should be using conduits or pipes, or something. One day..
The assistant needs to detect when removable drives are attached, and sync with them. This is a reasonable thing to be working on at this point, because it'll make the currently incomplete data transfer code fully usable for the sneakernet use case, and firming that up will probably be a good step toward handing other use cases involving data transfer over the network, including cases where network remotes are transientely available.
So I've been playing with using dbus to detect mount events. There's a very nice Haskell library to use dbus.
This simple program will detect removable drives being mounted, and works on Xfce (as long as you have automounting enabled in its configuration), and should also work on Gnome, and, probably, KDE:
{-# LANGUAGE OverloadedStrings #-}
import Data.List (sort)
import DBus
import DBus.Client
import Control.Monad
main = do
client <- connectSession
listen client mountadded $ \s ->
putStrLn (show s)
forever $ getLine -- let listener thread run forever
where
mountadded = matchAny
{ matchInterface = Just "org.gtk.Private.RemoteVolumeMonitor"
, matchMember = Just "MountAdded"
}
(Yeah... "org.gtk.Private.RemoteVolumeMonitor". There are so
many things wrong with that string. What does gtk have to do with
mounting a drive? Why is it Private? Bleagh. Should I only match
the "MountAdded" member and not the interface? Seems everyone who does
this relies on google to find other people who have cargo-culted it,
or just runs dbus-monitor
and picks out things.
There seems to be no canonical list of events. Bleagh.)
Spent a while shaving a yak of needing a getmntent
interface in Haskell.
Found one in a hsshellscript library; since that library is not packaged
in Debian, and I don't really want to depend on it, I extracted just
the mtab and fstab parts of it into a little library in git-annex.
I've started putting together a MountWatcher thread. On systems without
dbus (do OSX or the BSDs have dbus?), or if dbus is not running, it polls
/etc/mtab
every 10 seconds for new mounts. When dbus is available,
it doesn't need the polling, and should notice mounts more quickly.
Open question: Should it still poll even when dbus is available? Some of us
like to mount our own drives, by hand and may have automounting disabled. It'd
be good if the assistant supported that. This might need a
annex.no-dbus
setting, but I'd rather avoid needing such manual
configuration.
One idea is to do polling in addition to dbus, if /etc/fstab
contains
mount points that seem to be removable drives, on which git remotes lives.
Or it could always do polling in addition to dbus, which is just some extra
work. Or, it could try to introspect dbus to see if mount events will
be generated.
The MountWatcher so far only detects new mounts and prints out what happened. Next up: Do something in response to them.
This will involve manipulating the Annex state to belatedly add the Remote on the mount point.. tricky. And then, for Git Remotes, it should pull/push the Remote to sync git data. Finally, for all remotes, it will need to queue Transfers of file contents from/to the newly available Remote.
I am running KDE, dbus, and I like to mount drives by hand; all that without bothering to set up /etc/fstab... Often from CLI so I don't even see the notifications for new drives.
Especially while on the road, I will use no KDE, but just a tty or three. Still, dbus will be running.
Long story short, I would need polling for the assistant to work flawlessly in all use cases.
I, too, am running a dbus but like to hand mount my filesystems. However, I'd imagine that I am both a minority and that my minority could like the extra control, so perhaps even a "re-read the mtab /now/" command that can be manually run after something is manually mounted would suffice
Is it not possible to use inotify on the mtab?
How did I not think about using my favorite hammer on this problem too? But, no, /proc/mounts cannot be watched with inotify it seems, and of course the BSDs don't seem to have a file at all.
I think the dbus stuff is sorted out for manual users, see later blog entries.
It's
org.gtk
because gvfs, GLib and Gtk are all products of gtk.org (there is no separate glib.org).It's
Private
because the gvfs developers don't consider its D-Bus interface to be stable API, I believe. The official API for it is the C API in GIO, part of GLib.To poll for changes to /proc/mounts on Linux, you open it for reading and poll() for POLLERR (not sure why it gets to be different, but it is). See gio/gunixmounts.c in recent GLib.