##// END OF EJS Templates
tests: tweak chg test to make it fail less often...
Arseniy Alekseyev -
r52282:db5d7aee stable
parent child Browse files
Show More
@@ -1,572 +1,572 b''
1 1 #require chg
2 2
3 3 Scale the timeout for the chg-server to the test timeout scaling.
4 4 This is done to reduce the flakiness of this test on heavy load.
5 5
6 6 $ CHGTIMEOUT=`expr $HGTEST_TIMEOUT / 6`
7 7 $ export CHGTIMEOUT
8 8
9 9 $ mkdir log
10 10 $ cp $HGRCPATH $HGRCPATH.unconfigured
11 11 $ cat <<'EOF' >> $HGRCPATH
12 12 > [cmdserver]
13 13 > log = $TESTTMP/log/server.log
14 14 > max-log-files = 1
15 15 > max-log-size = 10 kB
16 16 > EOF
17 17 $ cp $HGRCPATH $HGRCPATH.orig
18 18
19 19 $ filterlog () {
20 20 > sed -e 's!^[0-9/]* [0-9:]* ([0-9]*)>!YYYY/MM/DD HH:MM:SS (PID)>!' \
21 21 > -e 's!\(setprocname\|received fds\|setenv\): .*!\1: ...!' \
22 22 > -e 's!\(confighash\|mtimehash\) = [0-9a-f]*!\1 = ...!g' \
23 23 > -e 's!\(in \)[0-9.]*s\b!\1 ...s!g' \
24 24 > -e 's!\(pid\)=[0-9]*!\1=...!g' \
25 25 > -e 's!\(/server-\)[0-9a-f]*!\1...!g'
26 26 > }
27 27
28 28 init repo
29 29
30 30 $ chg init foo
31 31 $ cd foo
32 32
33 33 ill-formed config
34 34
35 35 $ chg status
36 36 $ echo '=brokenconfig' >> $HGRCPATH
37 37 $ chg status
38 38 config error at * =brokenconfig (glob)
39 39 [30]
40 40
41 41 $ cp $HGRCPATH.orig $HGRCPATH
42 42
43 43 long socket path
44 44
45 45 $ sockpath=$TESTTMP/this/path/should/be/longer/than/one-hundred-and-seven/characters/where/107/is/the/typical/size/limit/of/unix-domain-socket
46 46 $ mkdir -p $sockpath
47 47 $ bakchgsockname=$CHGSOCKNAME
48 48 $ CHGSOCKNAME=$sockpath/server
49 49 $ export CHGSOCKNAME
50 50 $ chg root
51 51 $TESTTMP/foo
52 52 $ rm -rf $sockpath
53 53 $ CHGSOCKNAME=$bakchgsockname
54 54 $ export CHGSOCKNAME
55 55
56 56 $ cd ..
57 57
58 58 editor
59 59 ------
60 60
61 61 $ cat >> pushbuffer.py <<EOF
62 62 > def reposetup(ui, repo):
63 63 > repo.ui.pushbuffer(subproc=True)
64 64 > EOF
65 65
66 66 $ chg init editor
67 67 $ cd editor
68 68
69 69 by default, system() should be redirected to the client:
70 70
71 71 $ touch foo
72 72 $ CHGDEBUG= HGEDITOR=cat chg ci -Am channeled --edit 2>&1 \
73 73 > | grep -E "HG:|run 'cat"
74 74 chg: debug: * run 'cat "*"' at '$TESTTMP/editor' (glob)
75 75 HG: Enter commit message. Lines beginning with 'HG:' are removed.
76 76 HG: Leave message empty to abort commit.
77 77 HG: --
78 78 HG: user: test
79 79 HG: branch 'default'
80 80 HG: added foo
81 81
82 82 but no redirection should be made if output is captured:
83 83
84 84 $ touch bar
85 85 $ CHGDEBUG= HGEDITOR=cat chg ci -Am bufferred --edit \
86 86 > --config extensions.pushbuffer="$TESTTMP/pushbuffer.py" 2>&1 \
87 87 > | grep -E "HG:|run 'cat"
88 88 [1]
89 89
90 90 check that commit commands succeeded:
91 91
92 92 $ hg log -T '{rev}:{desc}\n'
93 93 1:bufferred
94 94 0:channeled
95 95
96 96 $ cd ..
97 97
98 98 pager
99 99 -----
100 100
101 101 $ cat >> fakepager.py <<EOF
102 102 > import sys
103 103 > for line in sys.stdin:
104 104 > sys.stdout.write('paged! %r\n' % line)
105 105 > EOF
106 106
107 107 enable pager extension globally, but spawns the master server with no tty:
108 108
109 109 $ chg init pager
110 110 $ cd pager
111 111 $ cat >> $HGRCPATH <<EOF
112 112 > [extensions]
113 113 > pager =
114 114 > [pager]
115 115 > pager = "$PYTHON" $TESTTMP/fakepager.py
116 116 > EOF
117 117 $ chg version > /dev/null
118 118 $ touch foo
119 119 $ chg ci -qAm foo
120 120
121 121 pager should be enabled if the attached client has a tty:
122 122
123 123 $ chg log -l1 -q --config ui.formatted=True
124 124 paged! '0:1f7b0de80e11\n'
125 125 $ chg log -l1 -q --config ui.formatted=False
126 126 0:1f7b0de80e11
127 127
128 128 chg waits for pager if runcommand raises
129 129
130 130 $ cat > $TESTTMP/crash.py <<EOF
131 131 > from mercurial import registrar
132 132 > cmdtable = {}
133 133 > command = registrar.command(cmdtable)
134 134 > @command(b'crash')
135 135 > def pagercrash(ui, repo, *pats, **opts):
136 136 > ui.write(b'going to crash\n')
137 137 > raise Exception('.')
138 138 > EOF
139 139
140 140 $ cat > $TESTTMP/fakepager.py <<EOF
141 141 > import sys
142 142 > import time
143 143 > for line in iter(sys.stdin.readline, ''):
144 144 > if 'crash' in line: # only interested in lines containing 'crash'
145 145 > # if chg exits when pager is sleeping (incorrectly), the output
146 146 > # will be captured by the next test case
147 147 > time.sleep(1)
148 148 > sys.stdout.write('crash-pager: %s' % line)
149 149 > EOF
150 150
151 151 $ cat >> .hg/hgrc <<EOF
152 152 > [extensions]
153 153 > crash = $TESTTMP/crash.py
154 154 > EOF
155 155
156 156 $ chg crash --pager=on --config ui.formatted=True 2>/dev/null
157 157 crash-pager: going to crash
158 158 [255]
159 159
160 160 no stdout data should be printed after pager quits, and the buffered data
161 161 should never persist (issue6207)
162 162
163 163 "killed!" may be printed if terminated by SIGPIPE, which isn't important
164 164 in this test.
165 165
166 166 $ cat > $TESTTMP/bulkwrite.py <<'EOF'
167 167 > import time
168 168 > from mercurial import error, registrar
169 169 > cmdtable = {}
170 170 > command = registrar.command(cmdtable)
171 171 > @command(b'bulkwrite')
172 172 > def bulkwrite(ui, repo, *pats, **opts):
173 173 > ui.write(b'going to write massive data\n')
174 174 > ui.flush()
175 175 > t = time.time()
176 176 > while time.time() - t < 2:
177 177 > ui.write(b'x' * 1023 + b'\n') # will be interrupted by SIGPIPE
178 178 > raise error.Abort(b"write() doesn't block")
179 179 > EOF
180 180
181 181 $ cat > $TESTTMP/fakepager.py <<'EOF'
182 182 > import sys
183 183 > import time
184 184 > sys.stdout.write('paged! %r\n' % sys.stdin.readline())
185 185 > time.sleep(1) # new data will be written
186 186 > EOF
187 187
188 188 $ cat >> .hg/hgrc <<EOF
189 189 > [extensions]
190 190 > bulkwrite = $TESTTMP/bulkwrite.py
191 191 > EOF
192 192
193 193 $ chg bulkwrite --pager=on --color no --config ui.formatted=True
194 194 paged! 'going to write massive data\n'
195 195 killed! (?)
196 196 [255]
197 197
198 198 $ chg bulkwrite --pager=on --color no --config ui.formatted=True
199 199 paged! 'going to write massive data\n'
200 200 killed! (?)
201 201 [255]
202 202
203 203 $ cd ..
204 204
205 205 missing stdio
206 206 -------------
207 207
208 208 $ CHGDEBUG=1 chg version -q 0<&-
209 209 chg: debug: * stdio fds are missing (glob)
210 210 chg: debug: * execute original hg (glob)
211 211 Mercurial Distributed SCM * (glob)
212 212
213 213 server lifecycle
214 214 ----------------
215 215
216 216 chg server should be restarted on code change, and old server will shut down
217 217 automatically. In this test, we use the following time parameters:
218 218
219 219 - "sleep 1" to make mtime different
220 220 - "sleep 2" to notice mtime change (polling interval is 1 sec)
221 221
222 222 set up repository with an extension:
223 223
224 224 $ chg init extreload
225 225 $ cd extreload
226 226 $ touch dummyext.py
227 227 $ cat <<EOF >> .hg/hgrc
228 228 > [extensions]
229 229 > dummyext = dummyext.py
230 230 > EOF
231 231
232 232 isolate socket directory for stable result:
233 233
234 234 $ OLDCHGSOCKNAME=$CHGSOCKNAME
235 235 $ mkdir chgsock
236 236 $ CHGSOCKNAME=`pwd`/chgsock/server
237 237
238 238 warm up server:
239 239
240 240 $ CHGDEBUG= chg log 2>&1 | grep -E 'instruction|start'
241 241 chg: debug: * start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
242 242
243 243 new server should be started if extension modified:
244 244
245 245 $ sleep 1
246 246 $ touch dummyext.py
247 247 $ CHGDEBUG= chg log 2>&1 | grep -E 'instruction|start'
248 248 chg: debug: * instruction: unlink $TESTTMP/extreload/chgsock/server-* (glob)
249 249 chg: debug: * instruction: reconnect (glob)
250 250 chg: debug: * start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
251 251
252 252 old server will shut down, while new server should still be reachable:
253 253
254 254 $ sleep 2
255 255 $ CHGDEBUG= chg log 2>&1 | (grep -E 'instruction|start' || true)
256 256
257 257 socket file should never be unlinked by old server:
258 258 (simulates unowned socket by updating mtime, which makes sure server exits
259 259 at polling cycle)
260 260
261 261 $ ls chgsock/server-*
262 262 chgsock/server-* (glob)
263 263 $ touch chgsock/server-*
264 264 $ sleep 2
265 265 $ ls chgsock/server-*
266 266 chgsock/server-* (glob)
267 267
268 268 since no server is reachable from socket file, new server should be started:
269 269 (this test makes sure that old server shut down automatically)
270 270
271 271 $ CHGDEBUG= chg log 2>&1 | grep -E 'instruction|start'
272 272 chg: debug: * start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
273 273
274 274 shut down servers and restore environment:
275 275
276 276 $ rm -R chgsock
277 277 $ sleep 2
278 278 $ CHGSOCKNAME=$OLDCHGSOCKNAME
279 279 $ cd ..
280 280
281 281 check that server events are recorded:
282 282
283 283 $ ls log
284 284 server.log
285 285 server.log.1
286 286
287 287 print only the last 10 lines, since we aren't sure how many records are
288 288 preserved (since setprocname isn't available on py3 and pure version,
289 289 the 10th-most-recent line is different when using py3):
290 290
291 291 $ cat log/server.log.1 log/server.log | tail -10 | filterlog
292 292 YYYY/MM/DD HH:MM:SS (PID)> confighash = ... mtimehash = ... (no-setprocname !)
293 293 YYYY/MM/DD HH:MM:SS (PID)> forked worker process (pid=...)
294 294 YYYY/MM/DD HH:MM:SS (PID)> setprocname: ... (setprocname !)
295 295 YYYY/MM/DD HH:MM:SS (PID)> received fds: ...
296 296 YYYY/MM/DD HH:MM:SS (PID)> chdir to '$TESTTMP/extreload'
297 297 YYYY/MM/DD HH:MM:SS (PID)> setumask 18
298 298 YYYY/MM/DD HH:MM:SS (PID)> setenv: ...
299 299 YYYY/MM/DD HH:MM:SS (PID)> confighash = ... mtimehash = ...
300 300 YYYY/MM/DD HH:MM:SS (PID)> validate: []
301 301 YYYY/MM/DD HH:MM:SS (PID)> worker process exited (pid=...)
302 302 YYYY/MM/DD HH:MM:SS (PID)> $TESTTMP/extreload/chgsock/server-... is not owned, exiting.
303 303
304 304 global data mutated by schems
305 305 -----------------------------
306 306
307 307 $ hg init schemes
308 308 $ cd schemes
309 309
310 310 initial state
311 311
312 312 $ cat > .hg/hgrc <<'EOF'
313 313 > [extensions]
314 314 > schemes =
315 315 > [schemes]
316 316 > foo = https://foo.example.org/
317 317 > EOF
318 318 $ hg debugexpandscheme foo://expanded
319 319 https://foo.example.org/expanded
320 320 $ hg debugexpandscheme bar://unexpanded
321 321 bar://unexpanded
322 322
323 323 add bar
324 324
325 325 $ cat > .hg/hgrc <<'EOF'
326 326 > [extensions]
327 327 > schemes =
328 328 > [schemes]
329 329 > foo = https://foo.example.org/
330 330 > bar = https://bar.example.org/
331 331 > EOF
332 332 $ hg debugexpandscheme foo://expanded
333 333 https://foo.example.org/expanded
334 334 $ hg debugexpandscheme bar://expanded
335 335 https://bar.example.org/expanded
336 336
337 337 remove foo
338 338
339 339 $ cat > .hg/hgrc <<'EOF'
340 340 > [extensions]
341 341 > schemes =
342 342 > [schemes]
343 343 > bar = https://bar.example.org/
344 344 > EOF
345 345 $ hg debugexpandscheme foo://unexpanded
346 346 foo://unexpanded
347 347 $ hg debugexpandscheme bar://expanded
348 348 https://bar.example.org/expanded
349 349
350 350 $ cd ..
351 351
352 352 repository cache
353 353 ----------------
354 354
355 355 $ cp $HGRCPATH.unconfigured $HGRCPATH
356 356 $ cat <<'EOF' >> $HGRCPATH
357 357 > [cmdserver]
358 358 > log = $TESTTMP/log/server-cached.log
359 359 > max-repo-cache = 1
360 360 > track-log = command, repocache
361 361 > EOF
362 362
363 363 isolate socket directory for stable result:
364 364
365 365 $ OLDCHGSOCKNAME=$CHGSOCKNAME
366 366 $ mkdir chgsock
367 367 $ CHGSOCKNAME=`pwd`/chgsock/server
368 368
369 369 create empty repo and cache it:
370 370
371 371 $ hg init cached
372 372 $ hg id -R cached
373 373 000000000000 tip
374 374 $ sleep 1
375 375
376 376 modify repo (and cache will be invalidated):
377 377
378 378 $ touch cached/a
379 379 $ hg ci -R cached -Am 'add a'
380 380 adding a
381 381 $ sleep 1
382 382
383 383 read cached repo:
384 384
385 385 $ hg log -R cached
386 386 changeset: 0:ac82d8b1f7c4
387 387 tag: tip
388 388 user: test
389 389 date: Thu Jan 01 00:00:00 1970 +0000
390 390 summary: add a
391 391
392 392 $ sleep 1
393 393
394 394 discard cached from LRU cache:
395 395
396 396 $ hg clone cached cached2
397 397 updating to branch default
398 398 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
399 399 $ hg id -R cached2
400 400 ac82d8b1f7c4 tip
401 401 $ sleep 1
402 402
403 403 read uncached repo:
404 404
405 405 $ hg log -R cached
406 406 changeset: 0:ac82d8b1f7c4
407 407 tag: tip
408 408 user: test
409 409 date: Thu Jan 01 00:00:00 1970 +0000
410 410 summary: add a
411 411
412 412 $ sleep 1
413 413
414 414 shut down servers and restore environment:
415 415
416 416 $ rm -R chgsock
417 417 $ sleep 2
418 418 $ CHGSOCKNAME=$OLDCHGSOCKNAME
419 419
420 420 check server log:
421 421
422 422 $ cat log/server-cached.log | filterlog
423 423 YYYY/MM/DD HH:MM:SS (PID)> init cached
424 424 YYYY/MM/DD HH:MM:SS (PID)> id -R cached
425 425 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
426 426 YYYY/MM/DD HH:MM:SS (PID)> repo from cache: $TESTTMP/cached
427 427 YYYY/MM/DD HH:MM:SS (PID)> ci -R cached -Am 'add a'
428 428 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
429 429 YYYY/MM/DD HH:MM:SS (PID)> repo from cache: $TESTTMP/cached
430 430 YYYY/MM/DD HH:MM:SS (PID)> log -R cached
431 431 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
432 432 YYYY/MM/DD HH:MM:SS (PID)> clone cached cached2
433 433 YYYY/MM/DD HH:MM:SS (PID)> id -R cached2
434 434 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached2 (in ...s)
435 435 YYYY/MM/DD HH:MM:SS (PID)> log -R cached
436 436 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
437 437
438 438 Test that -R is interpreted relative to --cwd.
439 439
440 440 $ hg init repo1
441 441 $ mkdir -p a/b
442 442 $ hg init a/b/repo2
443 443 $ printf "[alias]\ntest=repo1\n" >> repo1/.hg/hgrc
444 444 $ printf "[alias]\ntest=repo2\n" >> a/b/repo2/.hg/hgrc
445 445 $ cd a
446 446 $ chg --cwd .. -R repo1 show alias.test
447 447 repo1
448 448 $ chg --cwd . -R b/repo2 show alias.test
449 449 repo2
450 450 $ cd ..
451 451
452 452 Test that chg works (sets to the user's actual LC_CTYPE) even when python
453 453 "coerces" the locale (py3.7+)
454 454
455 455 $ cat > $TESTTMP/debugenv.py <<EOF
456 456 > from mercurial import encoding
457 457 > from mercurial import registrar
458 458 > cmdtable = {}
459 459 > command = registrar.command(cmdtable)
460 460 > @command(b'debugenv', [], b'', norepo=True)
461 461 > def debugenv(ui):
462 462 > for k in [b'LC_ALL', b'LC_CTYPE', b'LANG']:
463 463 > v = encoding.environ.get(k)
464 464 > if v is not None:
465 465 > ui.write(b'%s=%s\n' % (k, encoding.environ[k]))
466 466 > EOF
467 467 (hg keeps python's modified LC_CTYPE, chg doesn't)
468 468 $ (unset LC_ALL; unset LANG; LC_CTYPE= "$CHGHG" \
469 469 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
470 470 LC_CTYPE=C.UTF-8 (py37 !)
471 471 LC_CTYPE= (no-py37 !)
472 472 $ (unset LC_ALL; unset LANG; LC_CTYPE= chg \
473 473 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
474 474 LC_CTYPE=
475 475 $ (unset LC_ALL; unset LANG; LC_CTYPE=unsupported_value chg \
476 476 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
477 477 *cannot change locale* (glob) (?)
478 478 LC_CTYPE=unsupported_value
479 479 $ (unset LC_ALL; unset LANG; LC_CTYPE= chg \
480 480 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
481 481 LC_CTYPE=
482 482 $ LANG= LC_ALL= LC_CTYPE= chg \
483 483 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv
484 484 LC_ALL=
485 485 LC_CTYPE=
486 486 LANG=
487 487
488 488 Profiling isn't permanently enabled or carried over between chg invocations that
489 489 share the same server
490 490 $ cp $HGRCPATH.orig $HGRCPATH
491 491 $ hg init $TESTTMP/profiling
492 492 $ cd $TESTTMP/profiling
493 493 $ filteredchg() {
494 494 > CHGDEBUG=1 chg "$@" 2>&1 | sed -rn 's_^No samples recorded.*$_Sample count: 0_; /Sample count/p; /start cmdserver/p'
495 495 > }
496 496 $ newchg() {
497 497 > chg --kill-chg-daemon
498 498 > filteredchg "$@" | grep -E -v 'start cmdserver' || true
499 499 > }
500 500 (--profile isn't permanently on just because it was specified when chg was
501 501 started)
502 502 $ newchg log -r . --profile
503 503 Sample count: * (glob)
504 504 $ filteredchg log -r .
505 505 (enabling profiling via config works, even on the first chg command that starts
506 506 a cmdserver)
507 507 $ cat >> $HGRCPATH <<EOF
508 508 > [profiling]
509 509 > type=stat
510 510 > enabled=1
511 511 > EOF
512 512 $ newchg log -r .
513 513 Sample count: * (glob)
514 514 $ filteredchg log -r .
515 515 Sample count: * (glob)
516 516 (test that we aren't accumulating more and more samples each run)
517 517 $ cat > $TESTTMP/debugsleep.py <<EOF
518 518 > import time
519 519 > from mercurial import registrar
520 520 > cmdtable = {}
521 521 > command = registrar.command(cmdtable)
522 522 > @command(b'debugsleep', [], b'', norepo=True)
523 523 > def debugsleep(ui):
524 524 > start = time.time()
525 525 > x = 0
526 526 > while time.time() < start + 0.5:
527 527 > time.sleep(.1)
528 528 > x += 1
529 529 > ui.status(b'%d debugsleep iterations in %.03fs\n' % (x, time.time() - start))
530 530 > EOF
531 531 $ cat >> $HGRCPATH <<EOF
532 532 > [extensions]
533 533 > debugsleep = $TESTTMP/debugsleep.py
534 534 > EOF
535 535 $ newchg debugsleep > run_1
536 536 $ filteredchg debugsleep > run_2
537 537 $ filteredchg debugsleep > run_3
538 538 $ filteredchg debugsleep > run_4
539 539 FIXME: Run 4 should not be >3x Run 1's number of samples.
540 540 $ "$PYTHON" <<EOF
541 541 > r1 = int(open("run_1", "r").read().split()[-1])
542 542 > r4 = int(open("run_4", "r").read().split()[-1])
543 543 > print("Run 1: %d samples\nRun 4: %d samples\nRun 4 > 3 * Run 1: %s" %
544 544 > (r1, r4, r4 > (r1 * 3)))
545 545 > EOF
546 546 Run 1: * samples (glob)
547 547 Run 4: * samples (glob)
548 548 Run 4 > 3 * Run 1: False
549 549 (Disabling with --no-profile on the commandline still works, but isn't permanent)
550 550 $ newchg log -r . --no-profile
551 551 $ filteredchg log -r .
552 552 Sample count: * (glob)
553 553 $ filteredchg log -r . --no-profile
554 554 $ filteredchg log -r .
555 555 Sample count: * (glob)
556 556
557 557 chg setting CHGHG itself
558 558 ------------------------
559 559
560 560 If CHGHG is not set, chg will set it before spawning the command server.
561 561 $ hg --kill-chg-daemon
562 562 $ HG=$CHGHG CHGHG= CHGDEBUG= hg debugshell -c \
563 563 > 'ui.write(b"CHGHG=%s\n" % ui.environ.get(b"CHGHG"))' 2>&1 \
564 > | grep -E 'CHGHG|start'
564 > | grep -E 'CHGHG|start cmdserver'
565 565 chg: debug: * start cmdserver at * (glob)
566 566 CHGHG=/*/install/bin/hg (glob)
567 567
568 568 Running the same command a second time shouldn't spawn a new command server.
569 569 $ HG=$CHGHG CHGHG= CHGDEBUG= hg debugshell -c \
570 570 > 'ui.write(b"CHGHG=%s\n" % ui.environ.get(b"CHGHG"))' 2>&1 \
571 > | grep -E 'CHGHG|start'
571 > | grep -E 'CHGHG|start cmdserver'
572 572 CHGHG=/*/install/bin/hg (glob)
General Comments 0
You need to be logged in to leave comments. Login now