Saturday, January 28, 2006

Using rsync with Eclipse

I use Eclipse, the free, open-source IDE (Integrated Development Environment) from the Eclipse Foundation, with an extensive plug-in suite from MyEclipse.com. Eclipse by itself is good for Java development, but lacks sufficient tools for JSP and XML file editing (although this is changing thanks to the Eclipse WTP (Web Tools Project)), which is where MyEclipse fills in. At my workplace, we have a corporate license for the IDEA IDE from Jetbrains, and most people use IDEA, so I am one of the few odd ones out, which also means that I have to roll my own solutions when it comes to IDEA-ish features that are not supported by Eclipse.

I will concede that IDEA's web application support for JSP, CSS and Javascript editing are pretty fantastic, and Eclipse (or MyEclipse) does not even come close, although I am told that the WTP may change this. The one major reason I use Eclipse is that I started using Eclipse before IDEA (I was a vim user when the early adopters at work were banging away at IDEA), and I am just more familiar with Eclipse's keyboard shortcuts and general layout, and switching to IDEA represents a steep learning curve for me. The other reason is that IDEA is a commercial product, and since I do some open-source work on my own computer and on my own time, switching back and forth between the two IDEs was not an appealing prospect for me.

Anyway, one thing I have always liked about IDEA was its Unison plugin. Unison is a GUI tool that allows you to sync up code from your desktop to the central minicomputer where your application server resides. Personally, I have no use for this at work, because I develop on a shared NFS mount from my local Linux workstation which is also visible from any machine on the network. For Windows users, there is a similar shared SAMBA mount, but the mount is quite slow, so that is not a true option.

I do have a use for this functionality, however, when working with Eclipse from home on my laptop, over a VPN connection. For a while, I tried opening a VNC remote desktop session on my workstation (using the RealVNC software on both ends) from my laptop, but full-screen refreshes are slow enough to make you wish you switched back to using vim for remote editing, especially for heavy-duty coding against a tight deadline.

The only real alternative I found at the time was to transfer the files over to my laptop over the VPN, work on them locally, and transfer them back up to my workstation at work. My first approach was to tar the directory on the remote machine, use scp to copy over the tarball, explode them locally, work on them, tar it back, and scp them over to the remote machine. This is quite a bit of overhead if you are downloading and uploading 400+ files to make a single change and see if your change worked.

I looked at Unison working on a co-workers Apple PowerBook which he used at work, and it seemed to me that what Unison was really using under the covers was rsync. Of course, I was only partially correct, Unison does have features that go beyond what rsync does, but that is how I got the idea of using rsync to sync up files between my laptop and my desktop at work over VPN. I am ashamed to admit that I did not even look at the Unison site at the time, thinking that it must be some closed-source freeware with very tight bindings to IDEA, and consequently of no use to me as an Eclipse user. I know now that Unison is free and open source, and released under the GNU Public License.

In any case, I was learning Python at the time, so I thought it would be cool to wrap the rsync call in a Python script which exposed only a very simple interface, shown below:

1
sync.py up|down webapp-name

The "up" would sync the files up from my local laptop to my workstation (which is conveniently located on a NFS mount, so the files would be instantly available for working with the web application). The "down" would sync files down from the my desktop at work to my laptop. The webapp-name would name the web application I would be working on at the time. This utilizes the almost similar directory structures I have set up on my desktop at work and my laptop. The exact mapping between the two locations is embedded within the script, since I dont forsee me changing it any time soon. Heres the script:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/local/bin/python2.4
# $Id: sync.py,v 1.1 2005/11/25 17:44:24 sujit Exp sujit $
# $Source: /home/sujit/bin/python/RCS/sync.py,v $
# Called from within Eclipse when trying to rsync between laptop and desktop
#
import os
import sys

# CONFIG - start of configuration
LOCAL_BASEDIR = "/home/remoteuser/src/company"
REMOTE_BASEDIR = "nfs-mount/head/"
REMOTE_HOST = "remoteuser@remotedesk.company.com"
RSYNC_COMMAND = "/usr/bin/rsync -Cavzu --stats --progress"
# CONFIG

if (len(sys.argv) != 3):
   print "sync.py up|down ${app.name}\n"
   sys.exit(-1)
  
rsync_mode = sys.argv[1]
app_name = sys.argv[2]

print "Connecting to " + REMOTE_HOST + ":" + REMOTE_BASEDIR + "..."
if (rsync_mode == "up"):
   args = [RSYNC_COMMAND, LOCAL_BASEDIR + app_name + "/*", REMOTE_HOST + ":" + REMOTE_BASEDIR + app_name]
else:
   args = [RSYNC_COMMAND, REMOTE_HOST + ":" + REMOTE_BASEDIR + app_name + "/*", LOCAL_BASEDIR + app_name]
print "Executing " + " ".join(args)
os.system(" ".join(args))

The CONFIG block within the script specifies the mapping between the location of the files in the local laptop and the remote desktop. The LOCAL_BASEDIR is where I put all my company code when I have to work on them, under src/company. The REMOTE_BASEDIR is where I mount the NFS file system on my home directory on my local workstation. Under that is all the code I am working on. The REMOTE_HOST is the remote user name, followed by an @ sign, followed by the full machine name of the desktop. Finally, the RSYNC_COMMAND is the command we will use to do the upload or download, with all the required options. See the man page (man rsync) for details about these options.

The next step is hooking up this from Eclipse. This is fairly easy, click on Run::External Tools::External Tools. This will bring up a External Tool configuration popup. You will need to configure two entries for each web application you are working on. Fill in the Location field with the full path to the sync.py file (you will need to make this executable if you are on Unix). In the arguments, put the arguments "up webapps/your-webapp-name" for the sync-up version and "down webapps/your-webapp-name" for the sync-down version. This will create two entries under the Run::External Tools menu option. You will need to sync down before you start work on making modifications, and sync up when you are done.

Does this work as well as working locally on the NFS mount? No, not really, since there is one additional step to remember to do when working over the VPN. When working locally, you would make your changes and save in your Eclipse IDE, then push the files over to your development application server using an Ant script or calling the Ant task from within Eclipse. When working remotely, you will need to have a terminal window open on the remote machine and run the Ant task from that machine. Since I rarely use Ant tasks from within Eclipse, for me the extra step is really the "remembering to rsync up" step.

5 comments (moderated to prevent spam):

Anonymous said...

Thanks - it never occurred to me to try this - this is actually much easier then trying to use the sync plugins on large projects.

Sujit Pal said...

Actually, I gave up using this after the first few times I confused "up" with "down", and have switched to Unison since then. I use it as an external tool and use F5 to sync the file system with Eclipse. It is slow if you try to sync up your entire home directory, but if you have multiple .prf (profile) files for individual projects, it works out pretty good. You will need to install unison on both the server and the client. I have been working till recently with version 2.13 and lately with version 2.27, and I can honestly say its much more convenient than what I wrote up in my blog :-).

Anonymous said...

You might want to look at eclipse Target Management Tools. They have all the functionality you described plus. It also allows you to make an entire project or just part of i on the remote system.

Sujit Pal said...

Thank you, I took a quick look at the Eclipse Target Management page and one of the things that I really liked was the ability to work on remote filesystems over ssh. Beats having to remember to synchronize. Thanks again for the tip, I will try it out.

Anonymous said...

Well, the eclipse RSE (part of TM) works
fine for a small number of files and fast
connection. It's slow and some tools
like CDT does not work well if you you
use the files as links to an RSE directory. This is my case, and I am trying unison and rsync to keep a local/remote copy in sync ...