Background

For years and years now, I keep all of my work, including my checked-out source code, in some form of file synchronization system.

The advantages of having all of your files always up to date on all of the comptuters you work on are considerable.

More practically, I often get up from my work computer, and then continue on my laptop, or on my home computer, without having to think about it, and especially without having to abuse git commits purely to be able to transfer to another machine.

There are easily dozens of us who do this!

Anyways…

Although my cloud syncing system of choice has been Dropbox for the longest time, and dropbox does have an official and 100% working Linux client which these days I run on my WSL instances (in addition to the Windows dropbox on the host system) to sync the subset of my files I need to have on the native Linux filesystem, I have been wondering whether I would in theory be able to migrate to another cloud syncing service that does not have a first-class Linux app.

In short, how would I achieve light-weight, bi-directional syncing with automatic filesystem change detection between a Windows host and its WSL instances?

The answer is of course “unison”, but unison with a neat new trick!

Idea: Unison sync directly via the WSL bridge

Although I have used unison quite extensively in the past (see for example my 2015 comparison of personal sync systems), it has always been via SSH, or between local filesystems.

Neither of these are ideal for WSL: In the former case, you have to keep an SSH connection up and running which is challenging over WSL network interfaces, whilst the latter is going lack filesystem change detection on the foreign mounted fs (WSL on Windows, or Windows on WSL).

However, thanks to the WSL bridge, we can execute Windows EXE files directly from WSL, or we can execute Linux binaries from Windows using the wsl.exe command.

Although unison does not support such a thing out of the box, a dummy script to replace ssh-command would do the trick nicely!

Implementation

Below is the script which I create as ~/.local/bin/sshdummy, but you could put it anywhere on your Linux path.

See the comments in the script to understand how it works.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash

# for this URL:
# ssh://bleh@bleh.com//home/cpbotha/Dropbox/notes/mobile
# unison passes the following to ssh:
# -l bleh bleh.com -e none unison -server __new-rpc-mode
# if we leave out the username, it's only:
# bleh.com -e none unison -server __new-rpc-mode

# full WSL path to the unison binary on windows
# mine is from the github unison-v2.52.1+ocaml-4.14.0+x86_64.windows.zip
UNISON_WIN="/mnt/c/Users/cpbot/AppData/Local/unison/bin/unison.exe"

# we could skip "bleh.com -e none unison" by just shifting:
#shift 4
# but it's more robust to just pass everything from -server onwards.
# match on -server up to end of line, then grep -o prints only the match.
UNISON_ARGS=`echo $@ | grep -o "\-server.*$"`
# prepend windows unison.exe, then continue with unison args
$UNISON_WIN $UNISON_ARGS

You can invoke a synchronization with something like the following:

1
2
3
# - "bleh.com" can be anything that looks like a hostname. bleh.com is fine.
#   it is required, but will be ignored.
unison -auto -batch -repeat watch -sshcmd sshdummy ssh://bleh.com/C:/Users/cpbot/Dropbox/web ~/sync/web

Linux Unison will start Windows unison.exe directly via the WSL bridge and talk to it via standard input/output. Neat, robust and fast!

Demo

The screenshot shows how unison automatically picks up an edit I made to index.md on WSL (this blog post!) and syncs it back to Windows via the bridge:

Right after this, I saved the screenshot on the Windows side, and it was automatically picked up and pushed to WSL.

No SSH connections were harmed in the creation of this blog post!