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 where 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 of the interceptor. 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:
svn.exe
, using Cygwin version of gcc
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? )