[PATCH 1 of 3 V2] chg: fallback to original hg for some unsupported commands or flags

Jun Wu quark at fb.com
Fri Feb 26 14:20:25 UTC 2016


# HG changeset patch
# User Jun Wu <quark at fb.com>
# Date 1456496279 0
#      Fri Feb 26 14:17:59 2016 +0000
# Node ID ecefdf920cc8b8b983e06da8e82b8db0f67b85de
# Parent  824ccfaf08a238b50f179b39ceebf303c798031a
chg: fallback to original hg for some unsupported commands or flags

There are some known unsupported commands or flags for chg, such as hg serve -d
and hg foo --time. This patch detects these situations and transparently fall
back to the original hg. So the users won't bother remembering what chg can and
cannot do by themselves.

The current detection is not 100% accurate since we do not have an equivalent
command line parser in C. But it tries not to cause false positives that
prevents people from using chg for legit cases. In the future we may want to
implement a more accurate "unsupported" check server-side.

diff --git a/contrib/chg/chg.c b/contrib/chg/chg.c
--- a/contrib/chg/chg.c
+++ b/contrib/chg/chg.c
@@ -448,11 +448,51 @@
 	abortmsg("failed to prepare pager (errno = %d)", errno);
 }
 
+/*
+ * Test whether the command is unsupported or not. This is not designed to
+ * cover all cases. But it's fast, does not depend on the server and does
+ * not return false positives.
+ */
+static int isunsupported(int argc, const char *argv[])
+{
+	enum {
+		SERVE = 1,
+		DAEMON = 2,
+		SERVEDAEMON = SERVE | DAEMON,
+		TIME = 4,
+	};
+	unsigned int state = 0;
+	int i;
+	for (i = 0; i < argc; ++i) {
+		if (!strcmp(argv[i], "--"))
+			break;
+		if (i == 0 && strcmp("serve", argv[i]) == 0)
+			state |= SERVE;
+		else if (strcmp("-d", argv[i]) == 0 ||
+			 strcmp("--daemon", argv[i]) == 0)
+			state |= DAEMON;
+		else if (strcmp("--time", argv[i]) == 0)
+			state |= TIME;
+	}
+	return (state & TIME) == TIME ||
+	       (state & SERVEDAEMON) == SERVEDAEMON;
+}
+
+static void execoriginalhg(const char *argv[])
+{
+	debugmsg("execute original hg");
+	if (execvp(gethgcmd(), (char **)argv) < 0)
+		abortmsg("failed to exec original hg (errno = %d)", errno);
+}
+
 int main(int argc, const char *argv[], const char *envp[])
 {
 	if (getenv("CHGDEBUG"))
 		enabledebugmsg();
 
+	if (isunsupported(argc, argv))
+		execoriginalhg(argv);
+
 	struct cmdserveropts opts;
 	initcmdserveropts(&opts);
 	setcmdserveropts(&opts);


More information about the Mercurial-devel mailing list