chg: fallback to original hg for some unsupported commands or flags
authorJun Wu <quark@fb.com>
Fri, 26 Feb 2016 14:17:59 +0000
changeset 28260 0a17cfbe5429
parent 28259 7829d0ba7459
child 28261 2ab59ac06b76
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.
contrib/chg/chg.c
--- a/contrib/chg/chg.c	Wed Feb 24 13:20:06 2016 +0000
+++ b/contrib/chg/chg.c	Fri Feb 26 14:17:59 2016 +0000
@@ -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], "--") == 0)
+			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 - 1, argv + 1))
+		execoriginalhg(argv);
+
 	struct cmdserveropts opts;
 	initcmdserveropts(&opts);
 	setcmdserveropts(&opts);