NetBeans, Subversion, Cygwin: Pick any two of them, and everything's smooth. Use all three,
and you're in for a slightly less agreeable ride.
The NetBeans folks make no secret out of it:
"Please note that NetBeans Subversion support does not work when used with Cygwin."
First things first: I'm both a NetBeans newbie and a fanboy. This is not an attempt
to (pardon the pun) bash the IDE; just trying to iron out a few wrinkles.
NetBeans autodetects Subversion clients on your system and will use them automagically,
which is very convenient. However, NetBeans will
also happily use the
svn
version compiled for Cygwin when it finds it in your
PATH
-
and that's there trouble starts. Some related bug reports:
108577,
108536,
124537,
124343,
108069,
144021.
Fortunately, it is simple to work around the problem, as NetBeans can either download
an integrated SVN client, or you can configure it to use
plain vanilla Windows versions
of
svn
.
That, of course, was
way too simple for me. I wanted to know what really kept my
preferred IDE from having polite conversations with Cygwin executables.
As a first step, I ran tests with the "IDE Log" window open (accessible from NetBeans'
"View" menu). I also cranked up NetBeans logging levels; example:
netbeans.exe -J-Dorg.netbeans.modules.subversion.level=1
From the logging output, it looked like the Cygwin version of the
svn
client fails because
NetBeans passes file paths in Windows notation, i.e. the paths contain backslashes.
I didn't want to mess with NetBeans code, so just for laughs, I built a trivial interceptor
tool which converts paths into UNIX
notation and then calls the original Cygwin
svn.exe
. This took me a little further, but it wasn't
sufficient. For example, NetBeans often runs the svn client like this:
svn info --targets sometempfile --non-interactive....
And the temporary file
sometempfile
contains additional file specifications (in Windows notation).
I hacked those temp files in my interceptor as well - and now I'm getting results from
NetBeans! Whoopee!
Yeah, I know, this is totally a waste of time, since using an alternative Subversion client implementation
on Windows is a) trivial to accomplish and b) so much safer than this nightmarish hack of mine, but hey,
at least I learned a couple of things about NetBeans and its SVN integration while geeking out.
A safer fix would be for NetBeans to detect if the version of
svn.exe
in use is a Cygwin version,
and if so, produce UNIX paths. That fix would probably affect
SvnCommand.java, maybe also some other files.
Without further ado, here's the
code. Obligatory warnings: Makes grown
men cry. Riddled with bugs. Platform-dependent in more ways than I probably realize. And largely untested.
#include <malloc.h>
#include <process.h>
#include <stdio.h>
#include <string.h>
#include <syslimits.h>
#include <sys/cygwin.h>
#include <unistd.h>
// Experimental svn interceptor, to help debugging
// debug NetBeans vs. Cygwin svn problems. See
// http://www.clausbrod.de/Blog/DefinePrivatePublic20100424NetBeansVersusCygwin
// for details.
//
// Claus Brod, April 2010
char *convpath(const char *from) {
if (0 == strchr(from, '\\')) {
return strdup(from);
}
ssize_t len = cygwin_conv_path(CCP_WIN_A_TO_POSIX, from, NULL, 0);
char *to = (char *) malloc(len);
if (0 == cygwin_conv_path(CCP_WIN_A_TO_POSIX, from, to, len)) {
return to;
}
free(to);
return NULL;
}
char *patchfile(const char *from) {
FILE *ffrom = fopen(from, "r");
if (!ffrom)
return NULL;
#define SUFFIX "__hungo"
char *to = (char *) malloc(PATH_MAX + sizeof (SUFFIX));
strncpy(to, from, PATH_MAX);
strcat(to, SUFFIX);
FILE *fto = fopen(to, "w");
if (!fto) {
fclose(ffrom);
return NULL;
}
char buf[2048];
while (NULL != fgets(buf, sizeof (buf), ffrom)) {
char *converted = convpath(buf);
if (converted) {
fputs(converted, fto);
free(converted);
}
}
fclose(fto);
fclose(ffrom);
return to;
}
int main(int argc, char *argv[]) {
char **args = (char **) calloc(argc + 1, sizeof (char*));
// original svn client is in /bin
args[0] = "/bin/svn.exe";
for (int i = 1; i < argc; i++) {
args[i] = convpath(argv[i]);
}
// look for --targets
for (int i = 0; i < argc; i++) {
if (0 == strcmp(args[i], "--targets")) {
char *to = patchfile(args[i + 1]);
if (to) args[i + 1] = to;
}
}
int ret = spawnv(_P_WAIT, args[0], args);
// Remove temporary --targets
for (int i = 0; i < argc; i++) {
if (0 == strcmp(args[i], "--targets")) {
unlink(args[i + 1]);
}
}
return ret;
}
Usage instructions:
- Compile into
svn.exe
, using Cygwin version of gcc
- Point NetBeans to the interceptor (Tools/Options/Miscellaneous/Versioning/Subversion)
The interceptor assumes that Cygwin is installed, along with a Cygwin version of
svn
in
/bin
.
This is a
debugging tool. Using this in a production environment is a recipe for failure and data loss.
(Did I really have to mention this?
)
to top