##// END OF EJS Templates
serve: rename --daemon-pipefds to --daemon-postexec (BC)...
Jun Wu -
r28194:7623ba92 default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,466 +1,466 b''
1 /*
1 /*
2 * A fast client for Mercurial command server
2 * A fast client for Mercurial command server
3 *
3 *
4 * Copyright (c) 2011 Yuya Nishihara <yuya@tcha.org>
4 * Copyright (c) 2011 Yuya Nishihara <yuya@tcha.org>
5 *
5 *
6 * This software may be used and distributed according to the terms of the
6 * This software may be used and distributed according to the terms of the
7 * GNU General Public License version 2 or any later version.
7 * GNU General Public License version 2 or any later version.
8 */
8 */
9
9
10 #include <assert.h>
10 #include <assert.h>
11 #include <errno.h>
11 #include <errno.h>
12 #include <fcntl.h>
12 #include <fcntl.h>
13 #include <signal.h>
13 #include <signal.h>
14 #include <stdio.h>
14 #include <stdio.h>
15 #include <stdlib.h>
15 #include <stdlib.h>
16 #include <string.h>
16 #include <string.h>
17 #include <sys/stat.h>
17 #include <sys/stat.h>
18 #include <sys/types.h>
18 #include <sys/types.h>
19 #include <sys/un.h>
19 #include <sys/un.h>
20 #include <sys/wait.h>
20 #include <sys/wait.h>
21 #include <time.h>
21 #include <time.h>
22 #include <unistd.h>
22 #include <unistd.h>
23
23
24 #include "hgclient.h"
24 #include "hgclient.h"
25 #include "util.h"
25 #include "util.h"
26
26
27 #ifndef UNIX_PATH_MAX
27 #ifndef UNIX_PATH_MAX
28 #define UNIX_PATH_MAX (sizeof(((struct sockaddr_un *)NULL)->sun_path))
28 #define UNIX_PATH_MAX (sizeof(((struct sockaddr_un *)NULL)->sun_path))
29 #endif
29 #endif
30
30
31 struct cmdserveropts {
31 struct cmdserveropts {
32 char sockname[UNIX_PATH_MAX];
32 char sockname[UNIX_PATH_MAX];
33 char lockfile[UNIX_PATH_MAX];
33 char lockfile[UNIX_PATH_MAX];
34 char pidfile[UNIX_PATH_MAX];
34 char pidfile[UNIX_PATH_MAX];
35 size_t argsize;
35 size_t argsize;
36 const char **args;
36 const char **args;
37 };
37 };
38
38
39 static void initcmdserveropts(struct cmdserveropts *opts) {
39 static void initcmdserveropts(struct cmdserveropts *opts) {
40 memset(opts, 0, sizeof(struct cmdserveropts));
40 memset(opts, 0, sizeof(struct cmdserveropts));
41 }
41 }
42
42
43 static void freecmdserveropts(struct cmdserveropts *opts) {
43 static void freecmdserveropts(struct cmdserveropts *opts) {
44 free(opts->args);
44 free(opts->args);
45 opts->args = NULL;
45 opts->args = NULL;
46 opts->argsize = 0;
46 opts->argsize = 0;
47 }
47 }
48
48
49 /*
49 /*
50 * Test if an argument is a sensitive flag that should be passed to the server.
50 * Test if an argument is a sensitive flag that should be passed to the server.
51 * Return 0 if not, otherwise the number of arguments starting from the current
51 * Return 0 if not, otherwise the number of arguments starting from the current
52 * one that should be passed to the server.
52 * one that should be passed to the server.
53 */
53 */
54 static size_t testsensitiveflag(const char *arg)
54 static size_t testsensitiveflag(const char *arg)
55 {
55 {
56 static const struct {
56 static const struct {
57 const char *name;
57 const char *name;
58 size_t narg;
58 size_t narg;
59 } flags[] = {
59 } flags[] = {
60 {"--config", 1},
60 {"--config", 1},
61 {"--cwd", 1},
61 {"--cwd", 1},
62 {"--repo", 1},
62 {"--repo", 1},
63 {"--repository", 1},
63 {"--repository", 1},
64 {"--traceback", 0},
64 {"--traceback", 0},
65 {"-R", 1},
65 {"-R", 1},
66 };
66 };
67 size_t i;
67 size_t i;
68 for (i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i) {
68 for (i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i) {
69 size_t len = strlen(flags[i].name);
69 size_t len = strlen(flags[i].name);
70 size_t narg = flags[i].narg;
70 size_t narg = flags[i].narg;
71 if (memcmp(arg, flags[i].name, len) == 0) {
71 if (memcmp(arg, flags[i].name, len) == 0) {
72 if (arg[len] == '\0') { /* --flag (value) */
72 if (arg[len] == '\0') { /* --flag (value) */
73 return narg + 1;
73 return narg + 1;
74 } else if (arg[len] == '=' && narg > 0) { /* --flag=value */
74 } else if (arg[len] == '=' && narg > 0) { /* --flag=value */
75 return 1;
75 return 1;
76 } else if (flags[i].name[1] != '-') { /* short flag */
76 } else if (flags[i].name[1] != '-') { /* short flag */
77 return 1;
77 return 1;
78 }
78 }
79 }
79 }
80 }
80 }
81 return 0;
81 return 0;
82 }
82 }
83
83
84 /*
84 /*
85 * Parse argv[] and put sensitive flags to opts->args
85 * Parse argv[] and put sensitive flags to opts->args
86 */
86 */
87 static void setcmdserverargs(struct cmdserveropts *opts,
87 static void setcmdserverargs(struct cmdserveropts *opts,
88 int argc, const char *argv[])
88 int argc, const char *argv[])
89 {
89 {
90 size_t i, step;
90 size_t i, step;
91 opts->argsize = 0;
91 opts->argsize = 0;
92 for (i = 0, step = 1; i < (size_t)argc; i += step, step = 1) {
92 for (i = 0, step = 1; i < (size_t)argc; i += step, step = 1) {
93 if (!argv[i])
93 if (!argv[i])
94 continue; /* pass clang-analyse */
94 continue; /* pass clang-analyse */
95 if (strcmp(argv[i], "--") == 0)
95 if (strcmp(argv[i], "--") == 0)
96 break;
96 break;
97 size_t n = testsensitiveflag(argv[i]);
97 size_t n = testsensitiveflag(argv[i]);
98 if (n == 0 || i + n > (size_t)argc)
98 if (n == 0 || i + n > (size_t)argc)
99 continue;
99 continue;
100 opts->args = reallocx(opts->args,
100 opts->args = reallocx(opts->args,
101 (n + opts->argsize) * sizeof(char *));
101 (n + opts->argsize) * sizeof(char *));
102 memcpy(opts->args + opts->argsize, argv + i,
102 memcpy(opts->args + opts->argsize, argv + i,
103 sizeof(char *) * n);
103 sizeof(char *) * n);
104 opts->argsize += n;
104 opts->argsize += n;
105 step = n;
105 step = n;
106 }
106 }
107 }
107 }
108
108
109 static void preparesockdir(const char *sockdir)
109 static void preparesockdir(const char *sockdir)
110 {
110 {
111 int r;
111 int r;
112 r = mkdir(sockdir, 0700);
112 r = mkdir(sockdir, 0700);
113 if (r < 0 && errno != EEXIST)
113 if (r < 0 && errno != EEXIST)
114 abortmsg("cannot create sockdir %s (errno = %d)",
114 abortmsg("cannot create sockdir %s (errno = %d)",
115 sockdir, errno);
115 sockdir, errno);
116
116
117 struct stat st;
117 struct stat st;
118 r = lstat(sockdir, &st);
118 r = lstat(sockdir, &st);
119 if (r < 0)
119 if (r < 0)
120 abortmsg("cannot stat %s (errno = %d)", sockdir, errno);
120 abortmsg("cannot stat %s (errno = %d)", sockdir, errno);
121 if (!S_ISDIR(st.st_mode))
121 if (!S_ISDIR(st.st_mode))
122 abortmsg("cannot create sockdir %s (file exists)", sockdir);
122 abortmsg("cannot create sockdir %s (file exists)", sockdir);
123 if (st.st_uid != geteuid() || st.st_mode & 0077)
123 if (st.st_uid != geteuid() || st.st_mode & 0077)
124 abortmsg("insecure sockdir %s", sockdir);
124 abortmsg("insecure sockdir %s", sockdir);
125 }
125 }
126
126
127 static void setcmdserveropts(struct cmdserveropts *opts)
127 static void setcmdserveropts(struct cmdserveropts *opts)
128 {
128 {
129 int r;
129 int r;
130 char sockdir[UNIX_PATH_MAX];
130 char sockdir[UNIX_PATH_MAX];
131 const char *envsockname = getenv("CHGSOCKNAME");
131 const char *envsockname = getenv("CHGSOCKNAME");
132 if (!envsockname) {
132 if (!envsockname) {
133 /* by default, put socket file in secure directory
133 /* by default, put socket file in secure directory
134 * (permission of socket file may be ignored on some Unices) */
134 * (permission of socket file may be ignored on some Unices) */
135 const char *tmpdir = getenv("TMPDIR");
135 const char *tmpdir = getenv("TMPDIR");
136 if (!tmpdir)
136 if (!tmpdir)
137 tmpdir = "/tmp";
137 tmpdir = "/tmp";
138 r = snprintf(sockdir, sizeof(sockdir), "%s/chg%d",
138 r = snprintf(sockdir, sizeof(sockdir), "%s/chg%d",
139 tmpdir, geteuid());
139 tmpdir, geteuid());
140 if (r < 0 || (size_t)r >= sizeof(sockdir))
140 if (r < 0 || (size_t)r >= sizeof(sockdir))
141 abortmsg("too long TMPDIR (r = %d)", r);
141 abortmsg("too long TMPDIR (r = %d)", r);
142 preparesockdir(sockdir);
142 preparesockdir(sockdir);
143 }
143 }
144
144
145 const char *basename = (envsockname) ? envsockname : sockdir;
145 const char *basename = (envsockname) ? envsockname : sockdir;
146 const char *sockfmt = (envsockname) ? "%s" : "%s/server";
146 const char *sockfmt = (envsockname) ? "%s" : "%s/server";
147 const char *lockfmt = (envsockname) ? "%s.lock" : "%s/lock";
147 const char *lockfmt = (envsockname) ? "%s.lock" : "%s/lock";
148 const char *pidfmt = (envsockname) ? "%s.pid" : "%s/pid";
148 const char *pidfmt = (envsockname) ? "%s.pid" : "%s/pid";
149 r = snprintf(opts->sockname, sizeof(opts->sockname), sockfmt, basename);
149 r = snprintf(opts->sockname, sizeof(opts->sockname), sockfmt, basename);
150 if (r < 0 || (size_t)r >= sizeof(opts->sockname))
150 if (r < 0 || (size_t)r >= sizeof(opts->sockname))
151 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r);
151 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r);
152 r = snprintf(opts->lockfile, sizeof(opts->lockfile), lockfmt, basename);
152 r = snprintf(opts->lockfile, sizeof(opts->lockfile), lockfmt, basename);
153 if (r < 0 || (size_t)r >= sizeof(opts->lockfile))
153 if (r < 0 || (size_t)r >= sizeof(opts->lockfile))
154 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r);
154 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r);
155 r = snprintf(opts->pidfile, sizeof(opts->pidfile), pidfmt, basename);
155 r = snprintf(opts->pidfile, sizeof(opts->pidfile), pidfmt, basename);
156 if (r < 0 || (size_t)r >= sizeof(opts->pidfile))
156 if (r < 0 || (size_t)r >= sizeof(opts->pidfile))
157 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r);
157 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r);
158 }
158 }
159
159
160 /*
160 /*
161 * Make lock file that indicates cmdserver process is about to start. Created
161 * Make lock file that indicates cmdserver process is about to start. Created
162 * lock file will be deleted by server. (0: success, -1: lock exists)
162 * lock file will be deleted by server. (0: success, -1: lock exists)
163 */
163 */
164 static int lockcmdserver(const struct cmdserveropts *opts)
164 static int lockcmdserver(const struct cmdserveropts *opts)
165 {
165 {
166 int r;
166 int r;
167 char info[32];
167 char info[32];
168 r = snprintf(info, sizeof(info), "%d", getpid());
168 r = snprintf(info, sizeof(info), "%d", getpid());
169 if (r < 0 || (size_t)r >= sizeof(info))
169 if (r < 0 || (size_t)r >= sizeof(info))
170 abortmsg("failed to format lock info");
170 abortmsg("failed to format lock info");
171 r = symlink(info, opts->lockfile);
171 r = symlink(info, opts->lockfile);
172 if (r < 0 && errno != EEXIST)
172 if (r < 0 && errno != EEXIST)
173 abortmsg("failed to make lock %s (errno = %d)",
173 abortmsg("failed to make lock %s (errno = %d)",
174 opts->lockfile, errno);
174 opts->lockfile, errno);
175 return r;
175 return r;
176 }
176 }
177
177
178 static void execcmdserver(const struct cmdserveropts *opts)
178 static void execcmdserver(const struct cmdserveropts *opts)
179 {
179 {
180 const char *hgcmd = getenv("CHGHG");
180 const char *hgcmd = getenv("CHGHG");
181 if (!hgcmd || hgcmd[0] == '\0')
181 if (!hgcmd || hgcmd[0] == '\0')
182 hgcmd = getenv("HG");
182 hgcmd = getenv("HG");
183 if (!hgcmd || hgcmd[0] == '\0')
183 if (!hgcmd || hgcmd[0] == '\0')
184 hgcmd = "hg";
184 hgcmd = "hg";
185
185
186 const char *baseargv[] = {
186 const char *baseargv[] = {
187 hgcmd,
187 hgcmd,
188 "serve",
188 "serve",
189 "--cwd", "/",
189 "--cwd", "/",
190 "--cmdserver", "chgunix",
190 "--cmdserver", "chgunix",
191 "--address", opts->sockname,
191 "--address", opts->sockname,
192 "--daemon-pipefds", opts->lockfile,
192 "--daemon-postexec", opts->lockfile,
193 "--pid-file", opts->pidfile,
193 "--pid-file", opts->pidfile,
194 "--config", "extensions.chgserver=",
194 "--config", "extensions.chgserver=",
195 /* wrap root ui so that it can be disabled/enabled by config */
195 /* wrap root ui so that it can be disabled/enabled by config */
196 "--config", "progress.assume-tty=1",
196 "--config", "progress.assume-tty=1",
197 };
197 };
198 size_t baseargvsize = sizeof(baseargv) / sizeof(baseargv[0]);
198 size_t baseargvsize = sizeof(baseargv) / sizeof(baseargv[0]);
199 size_t argsize = baseargvsize + opts->argsize + 1;
199 size_t argsize = baseargvsize + opts->argsize + 1;
200
200
201 const char **argv = mallocx(sizeof(char *) * argsize);
201 const char **argv = mallocx(sizeof(char *) * argsize);
202 memcpy(argv, baseargv, sizeof(baseargv));
202 memcpy(argv, baseargv, sizeof(baseargv));
203 memcpy(argv + baseargvsize, opts->args, sizeof(char *) * opts->argsize);
203 memcpy(argv + baseargvsize, opts->args, sizeof(char *) * opts->argsize);
204 argv[argsize - 1] = NULL;
204 argv[argsize - 1] = NULL;
205
205
206 if (execvp(hgcmd, (char **)argv) < 0)
206 if (execvp(hgcmd, (char **)argv) < 0)
207 abortmsg("failed to exec cmdserver (errno = %d)", errno);
207 abortmsg("failed to exec cmdserver (errno = %d)", errno);
208 free(argv);
208 free(argv);
209 }
209 }
210
210
211 /*
211 /*
212 * Sleep until lock file is deleted, i.e. cmdserver process starts listening.
212 * Sleep until lock file is deleted, i.e. cmdserver process starts listening.
213 * If pid is given, it also checks if the child process fails to start.
213 * If pid is given, it also checks if the child process fails to start.
214 */
214 */
215 static void waitcmdserver(const struct cmdserveropts *opts, pid_t pid)
215 static void waitcmdserver(const struct cmdserveropts *opts, pid_t pid)
216 {
216 {
217 static const struct timespec sleepreq = {0, 10 * 1000000};
217 static const struct timespec sleepreq = {0, 10 * 1000000};
218 int pst = 0;
218 int pst = 0;
219
219
220 for (unsigned int i = 0; i < 10 * 100; i++) {
220 for (unsigned int i = 0; i < 10 * 100; i++) {
221 int r;
221 int r;
222 struct stat lst;
222 struct stat lst;
223
223
224 r = lstat(opts->lockfile, &lst);
224 r = lstat(opts->lockfile, &lst);
225 if (r < 0 && errno == ENOENT)
225 if (r < 0 && errno == ENOENT)
226 return; /* lock file deleted by server */
226 return; /* lock file deleted by server */
227 if (r < 0)
227 if (r < 0)
228 goto cleanup;
228 goto cleanup;
229
229
230 if (pid > 0) {
230 if (pid > 0) {
231 /* collect zombie if child process fails to start */
231 /* collect zombie if child process fails to start */
232 r = waitpid(pid, &pst, WNOHANG);
232 r = waitpid(pid, &pst, WNOHANG);
233 if (r != 0)
233 if (r != 0)
234 goto cleanup;
234 goto cleanup;
235 }
235 }
236
236
237 nanosleep(&sleepreq, NULL);
237 nanosleep(&sleepreq, NULL);
238 }
238 }
239
239
240 abortmsg("timed out waiting for cmdserver %s", opts->lockfile);
240 abortmsg("timed out waiting for cmdserver %s", opts->lockfile);
241 return;
241 return;
242
242
243 cleanup:
243 cleanup:
244 if (pid > 0)
244 if (pid > 0)
245 /* lockfile should be made by this process */
245 /* lockfile should be made by this process */
246 unlink(opts->lockfile);
246 unlink(opts->lockfile);
247 if (WIFEXITED(pst)) {
247 if (WIFEXITED(pst)) {
248 abortmsg("cmdserver exited with status %d", WEXITSTATUS(pst));
248 abortmsg("cmdserver exited with status %d", WEXITSTATUS(pst));
249 } else if (WIFSIGNALED(pst)) {
249 } else if (WIFSIGNALED(pst)) {
250 abortmsg("cmdserver killed by signal %d", WTERMSIG(pst));
250 abortmsg("cmdserver killed by signal %d", WTERMSIG(pst));
251 } else {
251 } else {
252 abortmsg("error white waiting cmdserver");
252 abortmsg("error white waiting cmdserver");
253 }
253 }
254 }
254 }
255
255
256 /* Spawn new background cmdserver */
256 /* Spawn new background cmdserver */
257 static void startcmdserver(const struct cmdserveropts *opts)
257 static void startcmdserver(const struct cmdserveropts *opts)
258 {
258 {
259 debugmsg("start cmdserver at %s", opts->sockname);
259 debugmsg("start cmdserver at %s", opts->sockname);
260
260
261 if (lockcmdserver(opts) < 0) {
261 if (lockcmdserver(opts) < 0) {
262 debugmsg("lock file exists, waiting...");
262 debugmsg("lock file exists, waiting...");
263 waitcmdserver(opts, 0);
263 waitcmdserver(opts, 0);
264 return;
264 return;
265 }
265 }
266
266
267 /* remove dead cmdserver socket if any */
267 /* remove dead cmdserver socket if any */
268 unlink(opts->sockname);
268 unlink(opts->sockname);
269
269
270 pid_t pid = fork();
270 pid_t pid = fork();
271 if (pid < 0)
271 if (pid < 0)
272 abortmsg("failed to fork cmdserver process");
272 abortmsg("failed to fork cmdserver process");
273 if (pid == 0) {
273 if (pid == 0) {
274 /* bypass uisetup() of pager extension */
274 /* bypass uisetup() of pager extension */
275 int nullfd = open("/dev/null", O_WRONLY);
275 int nullfd = open("/dev/null", O_WRONLY);
276 if (nullfd >= 0) {
276 if (nullfd >= 0) {
277 dup2(nullfd, fileno(stdout));
277 dup2(nullfd, fileno(stdout));
278 close(nullfd);
278 close(nullfd);
279 }
279 }
280 execcmdserver(opts);
280 execcmdserver(opts);
281 } else {
281 } else {
282 waitcmdserver(opts, pid);
282 waitcmdserver(opts, pid);
283 }
283 }
284 }
284 }
285
285
286 static void killcmdserver(const struct cmdserveropts *opts, int sig)
286 static void killcmdserver(const struct cmdserveropts *opts, int sig)
287 {
287 {
288 FILE *fp = fopen(opts->pidfile, "r");
288 FILE *fp = fopen(opts->pidfile, "r");
289 if (!fp)
289 if (!fp)
290 abortmsg("cannot open %s (errno = %d)", opts->pidfile, errno);
290 abortmsg("cannot open %s (errno = %d)", opts->pidfile, errno);
291 int pid = 0;
291 int pid = 0;
292 int n = fscanf(fp, "%d", &pid);
292 int n = fscanf(fp, "%d", &pid);
293 fclose(fp);
293 fclose(fp);
294 if (n != 1 || pid <= 0)
294 if (n != 1 || pid <= 0)
295 abortmsg("cannot read pid from %s", opts->pidfile);
295 abortmsg("cannot read pid from %s", opts->pidfile);
296
296
297 if (kill((pid_t)pid, sig) < 0) {
297 if (kill((pid_t)pid, sig) < 0) {
298 if (errno == ESRCH)
298 if (errno == ESRCH)
299 return;
299 return;
300 abortmsg("cannot kill %d (errno = %d)", pid, errno);
300 abortmsg("cannot kill %d (errno = %d)", pid, errno);
301 }
301 }
302 }
302 }
303
303
304 static pid_t peerpid = 0;
304 static pid_t peerpid = 0;
305
305
306 static void forwardsignal(int sig)
306 static void forwardsignal(int sig)
307 {
307 {
308 assert(peerpid > 0);
308 assert(peerpid > 0);
309 if (kill(peerpid, sig) < 0)
309 if (kill(peerpid, sig) < 0)
310 abortmsg("cannot kill %d (errno = %d)", peerpid, errno);
310 abortmsg("cannot kill %d (errno = %d)", peerpid, errno);
311 debugmsg("forward signal %d", sig);
311 debugmsg("forward signal %d", sig);
312 }
312 }
313
313
314 static void handlestopsignal(int sig)
314 static void handlestopsignal(int sig)
315 {
315 {
316 sigset_t unblockset, oldset;
316 sigset_t unblockset, oldset;
317 struct sigaction sa, oldsa;
317 struct sigaction sa, oldsa;
318 if (sigemptyset(&unblockset) < 0)
318 if (sigemptyset(&unblockset) < 0)
319 goto error;
319 goto error;
320 if (sigaddset(&unblockset, sig) < 0)
320 if (sigaddset(&unblockset, sig) < 0)
321 goto error;
321 goto error;
322 memset(&sa, 0, sizeof(sa));
322 memset(&sa, 0, sizeof(sa));
323 sa.sa_handler = SIG_DFL;
323 sa.sa_handler = SIG_DFL;
324 sa.sa_flags = SA_RESTART;
324 sa.sa_flags = SA_RESTART;
325 if (sigemptyset(&sa.sa_mask) < 0)
325 if (sigemptyset(&sa.sa_mask) < 0)
326 goto error;
326 goto error;
327
327
328 forwardsignal(sig);
328 forwardsignal(sig);
329 if (raise(sig) < 0) /* resend to self */
329 if (raise(sig) < 0) /* resend to self */
330 goto error;
330 goto error;
331 if (sigaction(sig, &sa, &oldsa) < 0)
331 if (sigaction(sig, &sa, &oldsa) < 0)
332 goto error;
332 goto error;
333 if (sigprocmask(SIG_UNBLOCK, &unblockset, &oldset) < 0)
333 if (sigprocmask(SIG_UNBLOCK, &unblockset, &oldset) < 0)
334 goto error;
334 goto error;
335 /* resent signal will be handled before sigprocmask() returns */
335 /* resent signal will be handled before sigprocmask() returns */
336 if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0)
336 if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0)
337 goto error;
337 goto error;
338 if (sigaction(sig, &oldsa, NULL) < 0)
338 if (sigaction(sig, &oldsa, NULL) < 0)
339 goto error;
339 goto error;
340 return;
340 return;
341
341
342 error:
342 error:
343 abortmsg("failed to handle stop signal (errno = %d)", errno);
343 abortmsg("failed to handle stop signal (errno = %d)", errno);
344 }
344 }
345
345
346 static void setupsignalhandler(pid_t pid)
346 static void setupsignalhandler(pid_t pid)
347 {
347 {
348 if (pid <= 0)
348 if (pid <= 0)
349 return;
349 return;
350 peerpid = pid;
350 peerpid = pid;
351
351
352 struct sigaction sa;
352 struct sigaction sa;
353 memset(&sa, 0, sizeof(sa));
353 memset(&sa, 0, sizeof(sa));
354 sa.sa_handler = forwardsignal;
354 sa.sa_handler = forwardsignal;
355 sa.sa_flags = SA_RESTART;
355 sa.sa_flags = SA_RESTART;
356 if (sigemptyset(&sa.sa_mask) < 0)
356 if (sigemptyset(&sa.sa_mask) < 0)
357 goto error;
357 goto error;
358
358
359 if (sigaction(SIGHUP, &sa, NULL) < 0)
359 if (sigaction(SIGHUP, &sa, NULL) < 0)
360 goto error;
360 goto error;
361 if (sigaction(SIGINT, &sa, NULL) < 0)
361 if (sigaction(SIGINT, &sa, NULL) < 0)
362 goto error;
362 goto error;
363
363
364 /* terminate frontend by double SIGTERM in case of server freeze */
364 /* terminate frontend by double SIGTERM in case of server freeze */
365 sa.sa_flags |= SA_RESETHAND;
365 sa.sa_flags |= SA_RESETHAND;
366 if (sigaction(SIGTERM, &sa, NULL) < 0)
366 if (sigaction(SIGTERM, &sa, NULL) < 0)
367 goto error;
367 goto error;
368
368
369 /* propagate job control requests to worker */
369 /* propagate job control requests to worker */
370 sa.sa_handler = forwardsignal;
370 sa.sa_handler = forwardsignal;
371 sa.sa_flags = SA_RESTART;
371 sa.sa_flags = SA_RESTART;
372 if (sigaction(SIGCONT, &sa, NULL) < 0)
372 if (sigaction(SIGCONT, &sa, NULL) < 0)
373 goto error;
373 goto error;
374 sa.sa_handler = handlestopsignal;
374 sa.sa_handler = handlestopsignal;
375 sa.sa_flags = SA_RESTART;
375 sa.sa_flags = SA_RESTART;
376 if (sigaction(SIGTSTP, &sa, NULL) < 0)
376 if (sigaction(SIGTSTP, &sa, NULL) < 0)
377 goto error;
377 goto error;
378
378
379 return;
379 return;
380
380
381 error:
381 error:
382 abortmsg("failed to set up signal handlers (errno = %d)", errno);
382 abortmsg("failed to set up signal handlers (errno = %d)", errno);
383 }
383 }
384
384
385 /* This implementation is based on hgext/pager.py (pre 369741ef7253) */
385 /* This implementation is based on hgext/pager.py (pre 369741ef7253) */
386 static void setuppager(hgclient_t *hgc, const char *const args[],
386 static void setuppager(hgclient_t *hgc, const char *const args[],
387 size_t argsize)
387 size_t argsize)
388 {
388 {
389 const char *pagercmd = hgc_getpager(hgc, args, argsize);
389 const char *pagercmd = hgc_getpager(hgc, args, argsize);
390 if (!pagercmd)
390 if (!pagercmd)
391 return;
391 return;
392
392
393 int pipefds[2];
393 int pipefds[2];
394 if (pipe(pipefds) < 0)
394 if (pipe(pipefds) < 0)
395 return;
395 return;
396 pid_t pid = fork();
396 pid_t pid = fork();
397 if (pid < 0)
397 if (pid < 0)
398 goto error;
398 goto error;
399 if (pid == 0) {
399 if (pid == 0) {
400 close(pipefds[0]);
400 close(pipefds[0]);
401 if (dup2(pipefds[1], fileno(stdout)) < 0)
401 if (dup2(pipefds[1], fileno(stdout)) < 0)
402 goto error;
402 goto error;
403 if (isatty(fileno(stderr))) {
403 if (isatty(fileno(stderr))) {
404 if (dup2(pipefds[1], fileno(stderr)) < 0)
404 if (dup2(pipefds[1], fileno(stderr)) < 0)
405 goto error;
405 goto error;
406 }
406 }
407 close(pipefds[1]);
407 close(pipefds[1]);
408 hgc_attachio(hgc); /* reattach to pager */
408 hgc_attachio(hgc); /* reattach to pager */
409 return;
409 return;
410 } else {
410 } else {
411 dup2(pipefds[0], fileno(stdin));
411 dup2(pipefds[0], fileno(stdin));
412 close(pipefds[0]);
412 close(pipefds[0]);
413 close(pipefds[1]);
413 close(pipefds[1]);
414
414
415 int r = execlp("/bin/sh", "/bin/sh", "-c", pagercmd, NULL);
415 int r = execlp("/bin/sh", "/bin/sh", "-c", pagercmd, NULL);
416 if (r < 0) {
416 if (r < 0) {
417 abortmsg("cannot start pager '%s' (errno = %d)",
417 abortmsg("cannot start pager '%s' (errno = %d)",
418 pagercmd, errno);
418 pagercmd, errno);
419 }
419 }
420 return;
420 return;
421 }
421 }
422
422
423 error:
423 error:
424 close(pipefds[0]);
424 close(pipefds[0]);
425 close(pipefds[1]);
425 close(pipefds[1]);
426 abortmsg("failed to prepare pager (errno = %d)", errno);
426 abortmsg("failed to prepare pager (errno = %d)", errno);
427 }
427 }
428
428
429 int main(int argc, const char *argv[], const char *envp[])
429 int main(int argc, const char *argv[], const char *envp[])
430 {
430 {
431 if (getenv("CHGDEBUG"))
431 if (getenv("CHGDEBUG"))
432 enabledebugmsg();
432 enabledebugmsg();
433
433
434 struct cmdserveropts opts;
434 struct cmdserveropts opts;
435 initcmdserveropts(&opts);
435 initcmdserveropts(&opts);
436 setcmdserveropts(&opts);
436 setcmdserveropts(&opts);
437 setcmdserverargs(&opts, argc, argv);
437 setcmdserverargs(&opts, argc, argv);
438
438
439 if (argc == 2) {
439 if (argc == 2) {
440 int sig = 0;
440 int sig = 0;
441 if (strcmp(argv[1], "--kill-chg-daemon") == 0)
441 if (strcmp(argv[1], "--kill-chg-daemon") == 0)
442 sig = SIGTERM;
442 sig = SIGTERM;
443 if (strcmp(argv[1], "--reload-chg-daemon") == 0)
443 if (strcmp(argv[1], "--reload-chg-daemon") == 0)
444 sig = SIGHUP;
444 sig = SIGHUP;
445 if (sig > 0) {
445 if (sig > 0) {
446 killcmdserver(&opts, sig);
446 killcmdserver(&opts, sig);
447 return 0;
447 return 0;
448 }
448 }
449 }
449 }
450
450
451 hgclient_t *hgc = hgc_open(opts.sockname);
451 hgclient_t *hgc = hgc_open(opts.sockname);
452 if (!hgc) {
452 if (!hgc) {
453 startcmdserver(&opts);
453 startcmdserver(&opts);
454 hgc = hgc_open(opts.sockname);
454 hgc = hgc_open(opts.sockname);
455 }
455 }
456 if (!hgc)
456 if (!hgc)
457 abortmsg("cannot open hg client");
457 abortmsg("cannot open hg client");
458
458
459 setupsignalhandler(hgc_peerpid(hgc));
459 setupsignalhandler(hgc_peerpid(hgc));
460 hgc_setenv(hgc, envp);
460 hgc_setenv(hgc, envp);
461 setuppager(hgc, argv + 1, argc - 1);
461 setuppager(hgc, argv + 1, argc - 1);
462 int exitcode = hgc_runcommand(hgc, argv + 1, argc - 1);
462 int exitcode = hgc_runcommand(hgc, argv + 1, argc - 1);
463 hgc_close(hgc);
463 hgc_close(hgc);
464 freecmdserveropts(&opts);
464 freecmdserveropts(&opts);
465 return exitcode;
465 return exitcode;
466 }
466 }
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,55 +1,55 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2
2
3 from __future__ import absolute_import
3 from __future__ import absolute_import
4
4
5 """
5 """
6 Small and dumb HTTP server for use in tests.
6 Small and dumb HTTP server for use in tests.
7 """
7 """
8
8
9 import optparse
9 import optparse
10 import BaseHTTPServer
10 import BaseHTTPServer
11 import signal
11 import signal
12 import SimpleHTTPServer
12 import SimpleHTTPServer
13 import sys
13 import sys
14
14
15 from mercurial import (
15 from mercurial import (
16 cmdutil,
16 cmdutil,
17 )
17 )
18
18
19 OptionParser = optparse.OptionParser
19 OptionParser = optparse.OptionParser
20
20
21 class simplehttpservice(object):
21 class simplehttpservice(object):
22 def __init__(self, host, port):
22 def __init__(self, host, port):
23 self.address = (host, port)
23 self.address = (host, port)
24 def init(self):
24 def init(self):
25 self.httpd = BaseHTTPServer.HTTPServer(
25 self.httpd = BaseHTTPServer.HTTPServer(
26 self.address, SimpleHTTPServer.SimpleHTTPRequestHandler)
26 self.address, SimpleHTTPServer.SimpleHTTPRequestHandler)
27 def run(self):
27 def run(self):
28 self.httpd.serve_forever()
28 self.httpd.serve_forever()
29
29
30 if __name__ == '__main__':
30 if __name__ == '__main__':
31 parser = OptionParser()
31 parser = OptionParser()
32 parser.add_option('-p', '--port', dest='port', type='int', default=8000,
32 parser.add_option('-p', '--port', dest='port', type='int', default=8000,
33 help='TCP port to listen on', metavar='PORT')
33 help='TCP port to listen on', metavar='PORT')
34 parser.add_option('-H', '--host', dest='host', default='localhost',
34 parser.add_option('-H', '--host', dest='host', default='localhost',
35 help='hostname or IP to listen on', metavar='HOST')
35 help='hostname or IP to listen on', metavar='HOST')
36 parser.add_option('--pid', dest='pid',
36 parser.add_option('--pid', dest='pid',
37 help='file name where the PID of the server is stored')
37 help='file name where the PID of the server is stored')
38 parser.add_option('-f', '--foreground', dest='foreground',
38 parser.add_option('-f', '--foreground', dest='foreground',
39 action='store_true',
39 action='store_true',
40 help='do not start the HTTP server in the background')
40 help='do not start the HTTP server in the background')
41 parser.add_option('--daemon-pipefds')
41 parser.add_option('--daemon-postexec')
42
42
43 (options, args) = parser.parse_args()
43 (options, args) = parser.parse_args()
44
44
45 signal.signal(signal.SIGTERM, lambda x, y: sys.exit(0))
45 signal.signal(signal.SIGTERM, lambda x, y: sys.exit(0))
46
46
47 if options.foreground and options.pid:
47 if options.foreground and options.pid:
48 parser.error("options --pid and --foreground are mutually exclusive")
48 parser.error("options --pid and --foreground are mutually exclusive")
49
49
50 opts = {'pid_file': options.pid,
50 opts = {'pid_file': options.pid,
51 'daemon': not options.foreground,
51 'daemon': not options.foreground,
52 'daemon_pipefds': options.daemon_pipefds}
52 'daemon_postexec': options.daemon_postexec}
53 service = simplehttpservice(options.host, options.port)
53 service = simplehttpservice(options.host, options.port)
54 cmdutil.service(opts, initfn=service.init, runfn=service.run,
54 cmdutil.service(opts, initfn=service.init, runfn=service.run,
55 runargs=[sys.executable, __file__] + sys.argv[1:])
55 runargs=[sys.executable, __file__] + sys.argv[1:])
@@ -1,350 +1,350 b''
1 Show all commands except debug commands
1 Show all commands except debug commands
2 $ hg debugcomplete
2 $ hg debugcomplete
3 add
3 add
4 addremove
4 addremove
5 annotate
5 annotate
6 archive
6 archive
7 backout
7 backout
8 bisect
8 bisect
9 bookmarks
9 bookmarks
10 branch
10 branch
11 branches
11 branches
12 bundle
12 bundle
13 cat
13 cat
14 clone
14 clone
15 commit
15 commit
16 config
16 config
17 copy
17 copy
18 diff
18 diff
19 export
19 export
20 files
20 files
21 forget
21 forget
22 graft
22 graft
23 grep
23 grep
24 heads
24 heads
25 help
25 help
26 identify
26 identify
27 import
27 import
28 incoming
28 incoming
29 init
29 init
30 locate
30 locate
31 log
31 log
32 manifest
32 manifest
33 merge
33 merge
34 outgoing
34 outgoing
35 parents
35 parents
36 paths
36 paths
37 phase
37 phase
38 pull
38 pull
39 push
39 push
40 recover
40 recover
41 remove
41 remove
42 rename
42 rename
43 resolve
43 resolve
44 revert
44 revert
45 rollback
45 rollback
46 root
46 root
47 serve
47 serve
48 status
48 status
49 summary
49 summary
50 tag
50 tag
51 tags
51 tags
52 tip
52 tip
53 unbundle
53 unbundle
54 update
54 update
55 verify
55 verify
56 version
56 version
57
57
58 Show all commands that start with "a"
58 Show all commands that start with "a"
59 $ hg debugcomplete a
59 $ hg debugcomplete a
60 add
60 add
61 addremove
61 addremove
62 annotate
62 annotate
63 archive
63 archive
64
64
65 Do not show debug commands if there are other candidates
65 Do not show debug commands if there are other candidates
66 $ hg debugcomplete d
66 $ hg debugcomplete d
67 diff
67 diff
68
68
69 Show debug commands if there are no other candidates
69 Show debug commands if there are no other candidates
70 $ hg debugcomplete debug
70 $ hg debugcomplete debug
71 debugancestor
71 debugancestor
72 debugapplystreamclonebundle
72 debugapplystreamclonebundle
73 debugbuilddag
73 debugbuilddag
74 debugbundle
74 debugbundle
75 debugcheckstate
75 debugcheckstate
76 debugcommands
76 debugcommands
77 debugcomplete
77 debugcomplete
78 debugconfig
78 debugconfig
79 debugcreatestreamclonebundle
79 debugcreatestreamclonebundle
80 debugdag
80 debugdag
81 debugdata
81 debugdata
82 debugdate
82 debugdate
83 debugdeltachain
83 debugdeltachain
84 debugdirstate
84 debugdirstate
85 debugdiscovery
85 debugdiscovery
86 debugextensions
86 debugextensions
87 debugfileset
87 debugfileset
88 debugfsinfo
88 debugfsinfo
89 debuggetbundle
89 debuggetbundle
90 debugignore
90 debugignore
91 debugindex
91 debugindex
92 debugindexdot
92 debugindexdot
93 debuginstall
93 debuginstall
94 debugknown
94 debugknown
95 debuglabelcomplete
95 debuglabelcomplete
96 debuglocks
96 debuglocks
97 debugmergestate
97 debugmergestate
98 debugnamecomplete
98 debugnamecomplete
99 debugobsolete
99 debugobsolete
100 debugpathcomplete
100 debugpathcomplete
101 debugpushkey
101 debugpushkey
102 debugpvec
102 debugpvec
103 debugrebuilddirstate
103 debugrebuilddirstate
104 debugrebuildfncache
104 debugrebuildfncache
105 debugrename
105 debugrename
106 debugrevlog
106 debugrevlog
107 debugrevspec
107 debugrevspec
108 debugsetparents
108 debugsetparents
109 debugsub
109 debugsub
110 debugsuccessorssets
110 debugsuccessorssets
111 debugwalk
111 debugwalk
112 debugwireargs
112 debugwireargs
113
113
114 Do not show the alias of a debug command if there are other candidates
114 Do not show the alias of a debug command if there are other candidates
115 (this should hide rawcommit)
115 (this should hide rawcommit)
116 $ hg debugcomplete r
116 $ hg debugcomplete r
117 recover
117 recover
118 remove
118 remove
119 rename
119 rename
120 resolve
120 resolve
121 revert
121 revert
122 rollback
122 rollback
123 root
123 root
124 Show the alias of a debug command if there are no other candidates
124 Show the alias of a debug command if there are no other candidates
125 $ hg debugcomplete rawc
125 $ hg debugcomplete rawc
126
126
127
127
128 Show the global options
128 Show the global options
129 $ hg debugcomplete --options | sort
129 $ hg debugcomplete --options | sort
130 --config
130 --config
131 --cwd
131 --cwd
132 --debug
132 --debug
133 --debugger
133 --debugger
134 --encoding
134 --encoding
135 --encodingmode
135 --encodingmode
136 --help
136 --help
137 --hidden
137 --hidden
138 --noninteractive
138 --noninteractive
139 --profile
139 --profile
140 --quiet
140 --quiet
141 --repository
141 --repository
142 --time
142 --time
143 --traceback
143 --traceback
144 --verbose
144 --verbose
145 --version
145 --version
146 -R
146 -R
147 -h
147 -h
148 -q
148 -q
149 -v
149 -v
150 -y
150 -y
151
151
152 Show the options for the "serve" command
152 Show the options for the "serve" command
153 $ hg debugcomplete --options serve | sort
153 $ hg debugcomplete --options serve | sort
154 --accesslog
154 --accesslog
155 --address
155 --address
156 --certificate
156 --certificate
157 --cmdserver
157 --cmdserver
158 --config
158 --config
159 --cwd
159 --cwd
160 --daemon
160 --daemon
161 --daemon-pipefds
161 --daemon-postexec
162 --debug
162 --debug
163 --debugger
163 --debugger
164 --encoding
164 --encoding
165 --encodingmode
165 --encodingmode
166 --errorlog
166 --errorlog
167 --help
167 --help
168 --hidden
168 --hidden
169 --ipv6
169 --ipv6
170 --name
170 --name
171 --noninteractive
171 --noninteractive
172 --pid-file
172 --pid-file
173 --port
173 --port
174 --prefix
174 --prefix
175 --profile
175 --profile
176 --quiet
176 --quiet
177 --repository
177 --repository
178 --stdio
178 --stdio
179 --style
179 --style
180 --templates
180 --templates
181 --time
181 --time
182 --traceback
182 --traceback
183 --verbose
183 --verbose
184 --version
184 --version
185 --web-conf
185 --web-conf
186 -6
186 -6
187 -A
187 -A
188 -E
188 -E
189 -R
189 -R
190 -a
190 -a
191 -d
191 -d
192 -h
192 -h
193 -n
193 -n
194 -p
194 -p
195 -q
195 -q
196 -t
196 -t
197 -v
197 -v
198 -y
198 -y
199
199
200 Show an error if we use --options with an ambiguous abbreviation
200 Show an error if we use --options with an ambiguous abbreviation
201 $ hg debugcomplete --options s
201 $ hg debugcomplete --options s
202 hg: command 's' is ambiguous:
202 hg: command 's' is ambiguous:
203 serve showconfig status summary
203 serve showconfig status summary
204 [255]
204 [255]
205
205
206 Show all commands + options
206 Show all commands + options
207 $ hg debugcommands
207 $ hg debugcommands
208 add: include, exclude, subrepos, dry-run
208 add: include, exclude, subrepos, dry-run
209 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, ignore-all-space, ignore-space-change, ignore-blank-lines, include, exclude, template
209 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, ignore-all-space, ignore-space-change, ignore-blank-lines, include, exclude, template
210 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
210 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
211 commit: addremove, close-branch, amend, secret, edit, interactive, include, exclude, message, logfile, date, user, subrepos
211 commit: addremove, close-branch, amend, secret, edit, interactive, include, exclude, message, logfile, date, user, subrepos
212 diff: rev, change, text, git, nodates, noprefix, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, root, include, exclude, subrepos
212 diff: rev, change, text, git, nodates, noprefix, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, root, include, exclude, subrepos
213 export: output, switch-parent, rev, text, git, nodates
213 export: output, switch-parent, rev, text, git, nodates
214 forget: include, exclude
214 forget: include, exclude
215 init: ssh, remotecmd, insecure
215 init: ssh, remotecmd, insecure
216 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
216 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
217 merge: force, rev, preview, tool
217 merge: force, rev, preview, tool
218 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
218 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
219 push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
219 push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
220 remove: after, force, subrepos, include, exclude
220 remove: after, force, subrepos, include, exclude
221 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate
221 serve: accesslog, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate
222 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos, template
222 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos, template
223 summary: remote
223 summary: remote
224 update: clean, check, date, rev, tool
224 update: clean, check, date, rev, tool
225 addremove: similarity, subrepos, include, exclude, dry-run
225 addremove: similarity, subrepos, include, exclude, dry-run
226 archive: no-decode, prefix, rev, type, subrepos, include, exclude
226 archive: no-decode, prefix, rev, type, subrepos, include, exclude
227 backout: merge, commit, no-commit, parent, rev, edit, tool, include, exclude, message, logfile, date, user
227 backout: merge, commit, no-commit, parent, rev, edit, tool, include, exclude, message, logfile, date, user
228 bisect: reset, good, bad, skip, extend, command, noupdate
228 bisect: reset, good, bad, skip, extend, command, noupdate
229 bookmarks: force, rev, delete, rename, inactive, template
229 bookmarks: force, rev, delete, rename, inactive, template
230 branch: force, clean
230 branch: force, clean
231 branches: active, closed, template
231 branches: active, closed, template
232 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
232 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
233 cat: output, rev, decode, include, exclude
233 cat: output, rev, decode, include, exclude
234 config: untrusted, edit, local, global
234 config: untrusted, edit, local, global
235 copy: after, force, include, exclude, dry-run
235 copy: after, force, include, exclude, dry-run
236 debugancestor:
236 debugancestor:
237 debugapplystreamclonebundle:
237 debugapplystreamclonebundle:
238 debugbuilddag: mergeable-file, overwritten-file, new-file
238 debugbuilddag: mergeable-file, overwritten-file, new-file
239 debugbundle: all, spec
239 debugbundle: all, spec
240 debugcheckstate:
240 debugcheckstate:
241 debugcommands:
241 debugcommands:
242 debugcomplete: options
242 debugcomplete: options
243 debugcreatestreamclonebundle:
243 debugcreatestreamclonebundle:
244 debugdag: tags, branches, dots, spaces
244 debugdag: tags, branches, dots, spaces
245 debugdata: changelog, manifest, dir
245 debugdata: changelog, manifest, dir
246 debugdate: extended
246 debugdate: extended
247 debugdeltachain: changelog, manifest, dir, template
247 debugdeltachain: changelog, manifest, dir, template
248 debugdirstate: nodates, datesort
248 debugdirstate: nodates, datesort
249 debugdiscovery: old, nonheads, ssh, remotecmd, insecure
249 debugdiscovery: old, nonheads, ssh, remotecmd, insecure
250 debugextensions: template
250 debugextensions: template
251 debugfileset: rev
251 debugfileset: rev
252 debugfsinfo:
252 debugfsinfo:
253 debuggetbundle: head, common, type
253 debuggetbundle: head, common, type
254 debugignore:
254 debugignore:
255 debugindex: changelog, manifest, dir, format
255 debugindex: changelog, manifest, dir, format
256 debugindexdot: changelog, manifest, dir
256 debugindexdot: changelog, manifest, dir
257 debuginstall:
257 debuginstall:
258 debugknown:
258 debugknown:
259 debuglabelcomplete:
259 debuglabelcomplete:
260 debuglocks: force-lock, force-wlock
260 debuglocks: force-lock, force-wlock
261 debugmergestate:
261 debugmergestate:
262 debugnamecomplete:
262 debugnamecomplete:
263 debugobsolete: flags, record-parents, rev, date, user
263 debugobsolete: flags, record-parents, rev, date, user
264 debugpathcomplete: full, normal, added, removed
264 debugpathcomplete: full, normal, added, removed
265 debugpushkey:
265 debugpushkey:
266 debugpvec:
266 debugpvec:
267 debugrebuilddirstate: rev, minimal
267 debugrebuilddirstate: rev, minimal
268 debugrebuildfncache:
268 debugrebuildfncache:
269 debugrename: rev
269 debugrename: rev
270 debugrevlog: changelog, manifest, dir, dump
270 debugrevlog: changelog, manifest, dir, dump
271 debugrevspec: optimize
271 debugrevspec: optimize
272 debugsetparents:
272 debugsetparents:
273 debugsub: rev
273 debugsub: rev
274 debugsuccessorssets:
274 debugsuccessorssets:
275 debugwalk: include, exclude
275 debugwalk: include, exclude
276 debugwireargs: three, four, five, ssh, remotecmd, insecure
276 debugwireargs: three, four, five, ssh, remotecmd, insecure
277 files: rev, print0, include, exclude, template, subrepos
277 files: rev, print0, include, exclude, template, subrepos
278 graft: rev, continue, edit, log, force, currentdate, currentuser, date, user, tool, dry-run
278 graft: rev, continue, edit, log, force, currentdate, currentuser, date, user, tool, dry-run
279 grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
279 grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
280 heads: rev, topo, active, closed, style, template
280 heads: rev, topo, active, closed, style, template
281 help: extension, command, keyword, system
281 help: extension, command, keyword, system
282 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure
282 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure
283 import: strip, base, edit, force, no-commit, bypass, partial, exact, prefix, import-branch, message, logfile, date, user, similarity
283 import: strip, base, edit, force, no-commit, bypass, partial, exact, prefix, import-branch, message, logfile, date, user, similarity
284 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
284 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
285 locate: rev, print0, fullpath, include, exclude
285 locate: rev, print0, fullpath, include, exclude
286 manifest: rev, all, template
286 manifest: rev, all, template
287 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
287 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
288 parents: rev, style, template
288 parents: rev, style, template
289 paths: template
289 paths: template
290 phase: public, draft, secret, force, rev
290 phase: public, draft, secret, force, rev
291 recover:
291 recover:
292 rename: after, force, include, exclude, dry-run
292 rename: after, force, include, exclude, dry-run
293 resolve: all, list, mark, unmark, no-status, tool, include, exclude, template
293 resolve: all, list, mark, unmark, no-status, tool, include, exclude, template
294 revert: all, date, rev, no-backup, interactive, include, exclude, dry-run
294 revert: all, date, rev, no-backup, interactive, include, exclude, dry-run
295 rollback: dry-run, force
295 rollback: dry-run, force
296 root:
296 root:
297 tag: force, local, rev, remove, edit, message, date, user
297 tag: force, local, rev, remove, edit, message, date, user
298 tags: template
298 tags: template
299 tip: patch, git, style, template
299 tip: patch, git, style, template
300 unbundle: update
300 unbundle: update
301 verify:
301 verify:
302 version:
302 version:
303
303
304 $ hg init a
304 $ hg init a
305 $ cd a
305 $ cd a
306 $ echo fee > fee
306 $ echo fee > fee
307 $ hg ci -q -Amfee
307 $ hg ci -q -Amfee
308 $ hg tag fee
308 $ hg tag fee
309 $ mkdir fie
309 $ mkdir fie
310 $ echo dead > fie/dead
310 $ echo dead > fie/dead
311 $ echo live > fie/live
311 $ echo live > fie/live
312 $ hg bookmark fo
312 $ hg bookmark fo
313 $ hg branch -q fie
313 $ hg branch -q fie
314 $ hg ci -q -Amfie
314 $ hg ci -q -Amfie
315 $ echo fo > fo
315 $ echo fo > fo
316 $ hg branch -qf default
316 $ hg branch -qf default
317 $ hg ci -q -Amfo
317 $ hg ci -q -Amfo
318 $ echo Fum > Fum
318 $ echo Fum > Fum
319 $ hg ci -q -AmFum
319 $ hg ci -q -AmFum
320 $ hg bookmark Fum
320 $ hg bookmark Fum
321
321
322 Test debugpathcomplete
322 Test debugpathcomplete
323
323
324 $ hg debugpathcomplete f
324 $ hg debugpathcomplete f
325 fee
325 fee
326 fie
326 fie
327 fo
327 fo
328 $ hg debugpathcomplete -f f
328 $ hg debugpathcomplete -f f
329 fee
329 fee
330 fie/dead
330 fie/dead
331 fie/live
331 fie/live
332 fo
332 fo
333
333
334 $ hg rm Fum
334 $ hg rm Fum
335 $ hg debugpathcomplete -r F
335 $ hg debugpathcomplete -r F
336 Fum
336 Fum
337
337
338 Test debugnamecomplete
338 Test debugnamecomplete
339
339
340 $ hg debugnamecomplete
340 $ hg debugnamecomplete
341 Fum
341 Fum
342 default
342 default
343 fee
343 fee
344 fie
344 fie
345 fo
345 fo
346 tip
346 tip
347 $ hg debugnamecomplete f
347 $ hg debugnamecomplete f
348 fee
348 fee
349 fie
349 fie
350 fo
350 fo
General Comments 0
You need to be logged in to leave comments. Login now