NetBeans vs. Cygwin vs. Subversion (24 Apr 2010)

NetBeans, Subversion, Cygwin: Pick any two of them, and you will sail smoothly. 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 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.

netbeans_idelog.jpg 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;
}

netbeans_svn.jpg 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? big grin )



When asked for a TWiki account, use your own or the default TWikiGuest account.


Revision: r1.4 - 04 May 2010 - 07:41 - ClausBrod
Blog > DefinePrivatePublic20100424NetBeansVersusCygwin
Copyright © 1999-2024 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback