diff --git a/contrib/chg/Makefile b/contrib/chg/Makefile --- a/contrib/chg/Makefile +++ b/contrib/chg/Makefile @@ -8,6 +8,9 @@ override CFLAGS += -std=gnu99 ifdef HGPATH override CPPFLAGS += -DHGPATH=\"$(HGPATH)\" endif +ifdef HGPATHREL +override CPPFLAGS += -DHGPATHREL=\"$(HGPATHREL)\" +endif DESTDIR = PREFIX = /usr/local diff --git a/contrib/chg/README b/contrib/chg/README --- a/contrib/chg/README +++ b/contrib/chg/README @@ -30,3 +30,11 @@ The following variables are available fo * CHGSOCKNAME specifies the socket path of the background cmdserver. * CHGTIMEOUT specifies how many seconds chg will wait before giving up connecting to a cmdserver. If it is 0, chg will wait forever. Default: 60 + +Build environment variables: + + * HGPATH: the path to the hg executable to call when CHGHG and HG are not set, + instead of "hg" + * HGPATHREL=1: when CHGHG and HG are not set, the hg executable will be ./hg + relative to the chg executable. Only works on linux, falls back to "hg" + otherwise. diff --git a/contrib/chg/chg.c b/contrib/chg/chg.c --- a/contrib/chg/chg.c +++ b/contrib/chg/chg.c @@ -184,13 +184,46 @@ static void setcmdserveropts(struct cmds abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r); } +/* If the current program is, say, /a/b/c/chg, returns /a/b/c/hg. */ +static char *getrelhgcmd(void) +{ + ssize_t n; + char *res, *slash; + int maxsize = 4096; + res = malloc(maxsize); + if (res == NULL) + goto cleanup; + n = readlink("/proc/self/exe", res, maxsize); + if (n < 0 || n >= maxsize) + goto cleanup; + res[n] = '\0'; + slash = strrchr(res, '/'); + if (slash == NULL) + goto cleanup; + /* 4 is strlen("/hg") + nul byte */ + if (slash + 4 >= res + maxsize) + goto cleanup; + memcpy(slash, "/hg", 4); + return res; + cleanup: + free(res); + return NULL; +} + static const char *gethgcmd(void) { static const char *hgcmd = NULL; +#ifdef HGPATHREL + int tryrelhgcmd = 1; +#else + int tryrelhgcmd = 0; +#endif if (!hgcmd) { hgcmd = getenv("CHGHG"); if (!hgcmd || hgcmd[0] == '\0') hgcmd = getenv("HG"); + if (tryrelhgcmd && (!hgcmd || hgcmd[0] == '\0')) + hgcmd = getrelhgcmd(); if (!hgcmd || hgcmd[0] == '\0') #ifdef HGPATH hgcmd = (HGPATH);