dimecres, 23 de febrer del 2011

How to use mercurial in cygwin from Netbeans

I recently wanted to download and use a project from Kenai and import it in my Netbeans IDE. I like to use cygwin to run Linux-like command line applications, and mercurial falls in this category for me.

So I installed mercurial in my cygwin environment following the steps explained in
http://www.saltycrane.com/blog/2008/04/how-to-install-mercurial-10-on-cygwin/

Then I went to my Netbeans to instruct him to use the hg application which can be found in /bin after installation. The bad news is that hg is a python script which netbeans is not able to run. It looks like it expects some executable.

So I decided to satisfy him with a very simple wrapping executable which I initially called hg_wrapper.c

The task was not so straightforward. First (looking at the code below) I realized that netbeans waits for a file called hg, so my created executable should be renamed as hg.exe.


public Boolean isExecPathValid(String name) {
if (name.length() == 0) return true;
File file = new File(name, "hg"); // NOI18N
// I would like to call canExecute but that requires Java SE 6.
return file.exists() && file.isFile();
}

From http://www.koders.com/java/fid7AA93D1A65E57A25677056ED70F7C575E173CE38.aspx?s=PostTask

Then I realized that my netbeans is passing Windows style paths as arguments to the hg application, and this causes the cygwin script to crash. So I did include some simple Windows path detection and conversion into the cygwin path format.

The final code is below.

hg_wrapper.c

// Copyright 2011 David Castells i Rufas (david.castells@uab.es)
#include
#include
#include

char* windowsToCygwinPath(char* path)
{
int len;
int i, j;

if (strchr(path, '\\') == NULL)
// no windows path, so ignore
return path;

len = strlen(path);

// ignore deallocation, this creates a mem leak, but since this is
// a short lived application it will be freed at exit soon, so
// why bother ?
char* ret = malloc(10+len*2);

ret[0] = 0;

strcpy(ret, "/cygdrive/");
j = strlen(ret);

for (i=0; i < len; i++)
{
if (path[i] == ':')
continue;

if (path[i] == '\\')
ret[j++] = '/';
else
ret[j++] = path[i];
}

ret[j] = 0;

return ret;
}

int main(int argc, char* args[])
{
char* newArgs[50];
int i;

newArgs[0] = "c:\\cygwin\\bin\\python.exe";
// for testing purposes
// newArgs[0] = "c:\\cygwin\\bin\\echo.exe";
newArgs[1] = "/bin/hg";

for (i=0; i < argc-1; i++)
{
newArgs[2+i] = windowsToCygwinPath(args[i+1]);
}

newArgs[2+i] = 0;

execv(newArgs[0], newArgs);
}


I compiled it in a bash console with
>gcc-3 -mno-cygwin hg_wrapper.c -o hg.exe

And then I copied it in /bin directory
>cp hg.exe /bin/hg.exe

Finally I configured Netbeans as follows to use it.



Voila ! It works.