People use Eclipse. People use Windows. People use these tools together to develop code. I am not (typically) one of these people. My development environment is usually either Coda on the Mac or vim on the command line. But I do work with people using Eclipse on Windows, and while the code we’re building together is not platform specific, it does help if we all have the same capabilities. So when I added some functionality to our Apache ant deploy script to synchronize files on a remote server using rsync, the next step was, of course, getting it to work on Windows.

Allow me to walk through the configuration, step-by-step. The first thing was to create a target in my build.xml file which ant can use to synchronize files to the remote machine. Something like this:

<target name="rsync_remotehost" >
   <exec executable="rsync" dir="${cfg.someDir}">
        <arg line="-aOvz --chmod=g+w,Da+rX,Fa+r,F-X --exclude .svn . \
            ${rsync.user}@${rsync.server}:${rsync.dir}" />
    </exec>
</target>

So really, all that does is define a target which runs rsync inside a specified directory. The important aspects to note are the rsync parameters. For example this: -aOvz These are pretty standard options (a for archive, v for verbose, z does compression), except for the O. I wasn’t used to using this option, but it’s important for a very subtle reason. To explain, first a little background. Typically when I want to synchronize the entire contents of a directory with rsync, I would do this:

rsync -avz path/to/somedir user@remote.host:/some/remote/dir

But this doesn’t quite work in the Eclipse+Ant environment on Windows. The reason is because the variables holding the directory locations get represented in Windows path notation. (Imagine a C: at the beginning and all the directory slashes are backwards.) Rsync can’t handle this. It’s a Unix-based tool. It’s expecting a Unix-style path. So to get around this we set a dir attribute in the exec element which causes ant to change to that directory before execution. We also use a ‘.’ in the rsync argument line to specify that the source contents are this directory. This has an odd side effect: rsync attempts to set times on the corresponding directory at the remote location, which tends to fail. So we use the -O option to tell rsync not to set times on directories.

The other arguments given to rsync are for specifying more sane permissions on the remote files since Windows wanted to kill all permissions for group and world by default (--chmod=g+w,Da+rX,Fa+r,F-X) and for excluding our local Subversion files (--exclude .svn).

So that’s the ant target. Now to the interesting parts. ;-) First we have to get rsync installed on Windows. Cygwin makes this relatively easy. Download and install. Most options are pretty much good at the defaults, except watch out for this screen:

Selecting packages for cygwin

On this screen you need to add a couple of packages, both in the Net section: Net -> rsync and Net -> openssh. Just click once on each of those packages and it will add what you need. Finish up the installation by clicking on ‘Next’ and ‘Finish’.

Once Cygwin and Rsync is installed, there’s still a few more things we need to do in order to get it all to work together correctly. First, you need to add the path to Cygwin’s binaries to the Windows path so that system calls in Eclipse will find the Cygwin binaries. To do that, right-click on ‘My Computer’ and click ‘Properties’. Then click on the ‘Advanced’ tab and then the ‘Environment Variables’ button:

Environment Variables

Next find the section on the bottom called ‘System variables’ and scroll down and double-click on the ‘Path’ line:

Path variable

Insert the following at the end of the ‘Variable value’ line:

;%SystemDrive%\cygwin\bin

Lastly, you need to set up a public key so that when ant runs, it won’t hang waiting for you to input a password (which you can’t do inside Eclipse anyway). To do that, open up Cygwin – you should have a shortcut on your desktop. When it opens run:

ssh-keygen

Accept the defaults, don’t add a passphrase, just hit enter instead. When the command is done, it will have saved a public and private key for you. We want to upload those to our remote server, like so (you’ll be asked for your password, and possibly to accept the key for the remote host – type ‘yes’ to do so):

scp ~/.ssh/id_rsa.pub user@remote.host:~/

Next we need to place it somewhere special on the remote host (you’ll be asked for your remote password again):

ssh user@remote.host
install -dv ~/.ssh
chmod 0700 ~/.ssh
cat id_rsa.pub >> ~/.ssh/authorized_keys
rm id_rsa.pub
exit

Now, test the connection to make sure that you can connect without giving a password:

ssh user@remote.host

If all is good just exit and that should be it! The next time you open up Eclipse, it should be able to call rsync and run successfully through your Ant target!

7 thoughts on “Getting Windows, Eclipse, Ant and Rsync to Play Nicely Together

  1. Hi! Thanks for the example–it helped me a lot in figuring out how to have NetBeans do an rsync from my Mac to a remote server.

    One thing I don’t understand, though, is the “dir” attribute on the “exec” node. Can you explain that to me? I thought it was going to be used as the local directory from which I was syncing, but I see you added ‘.’ after the ‘-r’ flag in the “arg” node. It seems to me that the ‘.’ is causing the rsync to sync from the basedir of my project.

    Thanks again,
    Jim

    Reply
    • Because Windows represents file paths differently than what rsync expects (Unix format) things become much easier if you avoid using a file path string as an argument to rsync, and instead use ‘.’, or the current directory.

      Without the “dir” attribute in the “exec” node you would be running the rsync command from the base directory of the project. If that’s what you want, excellent, just remove the “dir” attribute. Otherwise, “dir” causes the whole ant target to be run inside the specified directory (ant can handle the Windows paths, so you should be able to use a string value there), which means that the rsync command will be executed within the specified directory and so ‘.’ will not be pointing at your project’s base directory, but at the contents of the “dir” attribute.

      I hope that was clear. :-)

      Reply
      • That is fairly clear, I think I have it.

        1) Is the ‘dir’ attr relative to ‘basedir’ or does it override it?
        2) The command runs as if it were in ‘dir’ or, if ‘dir’ is not present, ‘basedir’–correct? So if I eliminated ‘dir’ and ‘basedir’ was set to ‘.’ I could place ‘subdir/’ after the ‘-r’ and ‘./subdir’ (relative to the directory in which the project resides) would be rsynced?

        Thanks a lot for your patience and great help thus far.

        Jim

        Reply
        • To answer your questions 100% accurately, I’d have to run some tests :-)

          But, if I recall correctly:

          1) “dir” is a full path, thus overriding ‘basedir’. At least, that is how I used it. Relative paths to ‘basedir’ may work, too, but I haven’t tested it.
          2) I believe if ‘dir’ is not specified, then yes, the command would run in your base directory. The ‘.’ is virtual notation. It simply means ‘this current directory’. So to answer the last question, yes that looks like it should work correctly.

          I’m glad you’re finding the article helpful, and no worries, questions/comments are always welcome.

          Reply
          • You’re great, thanks a lot. I just became a lot more productive! :)

            Now if only I could cause NetBeans to rsync on a per-file basis upon save of a file. That’s what I was after originally when I was told it can’t really be done for a PHP/JS project, which led me to seek a way to map a keystroke to an rsync command and thus to your blog.

            Thanks again,
            Jim

  2. Thanks for the tutorial, it worked perfectly except for one extra step I had to do. After the line:

    cat id_rsa.pub >> ~/.ssh/authorized_keys

    I had to run:

    chmod 600 ~/.ssh/authorized_keys

    Hopefully that helps if anyone else gets stuck!

    Reply
  3. Pingback: chmod - need help with options capital D and capital F..

Leave a reply

required

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>