##// END OF EJS Templates
merge with stable
Martin von Zweigbergk -
r44838:a69c08cd merge default
parent child Browse files
Show More
@@ -1,714 +1,715 b''
1 1 # chgserver.py - command server extension for cHg
2 2 #
3 3 # Copyright 2011 Yuya Nishihara <yuya@tcha.org>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 """command server extension for cHg
9 9
10 10 'S' channel (read/write)
11 11 propagate ui.system() request to client
12 12
13 13 'attachio' command
14 14 attach client's stdio passed by sendmsg()
15 15
16 16 'chdir' command
17 17 change current directory
18 18
19 19 'setenv' command
20 20 replace os.environ completely
21 21
22 22 'setumask' command (DEPRECATED)
23 23 'setumask2' command
24 24 set umask
25 25
26 26 'validate' command
27 27 reload the config and check if the server is up to date
28 28
29 29 Config
30 30 ------
31 31
32 32 ::
33 33
34 34 [chgserver]
35 35 # how long (in seconds) should an idle chg server exit
36 36 idletimeout = 3600
37 37
38 38 # whether to skip config or env change checks
39 39 skiphash = False
40 40 """
41 41
42 42 from __future__ import absolute_import
43 43
44 44 import inspect
45 45 import os
46 46 import re
47 47 import socket
48 48 import stat
49 49 import struct
50 50 import time
51 51
52 52 from .i18n import _
53 53 from .pycompat import (
54 54 getattr,
55 55 setattr,
56 56 )
57 57
58 58 from . import (
59 59 commandserver,
60 60 encoding,
61 61 error,
62 62 extensions,
63 63 node,
64 64 pycompat,
65 65 util,
66 66 )
67 67
68 68 from .utils import (
69 69 hashutil,
70 70 procutil,
71 71 stringutil,
72 72 )
73 73
74 74
75 75 def _hashlist(items):
76 76 """return sha1 hexdigest for a list"""
77 77 return node.hex(hashutil.sha1(stringutil.pprint(items)).digest())
78 78
79 79
80 80 # sensitive config sections affecting confighash
81 81 _configsections = [
82 82 b'alias', # affects global state commands.table
83 83 b'eol', # uses setconfig('eol', ...)
84 84 b'extdiff', # uisetup will register new commands
85 85 b'extensions',
86 b'schemes', # extsetup will update global hg.schemes
86 87 ]
87 88
88 89 _configsectionitems = [
89 90 (b'commands', b'show.aliasprefix'), # show.py reads it in extsetup
90 91 ]
91 92
92 93 # sensitive environment variables affecting confighash
93 94 _envre = re.compile(
94 95 br'''\A(?:
95 96 CHGHG
96 97 |HG(?:DEMANDIMPORT|EMITWARNINGS|MODULEPOLICY|PROF|RCPATH)?
97 98 |HG(?:ENCODING|PLAIN).*
98 99 |LANG(?:UAGE)?
99 100 |LC_.*
100 101 |LD_.*
101 102 |PATH
102 103 |PYTHON.*
103 104 |TERM(?:INFO)?
104 105 |TZ
105 106 )\Z''',
106 107 re.X,
107 108 )
108 109
109 110
110 111 def _confighash(ui):
111 112 """return a quick hash for detecting config/env changes
112 113
113 114 confighash is the hash of sensitive config items and environment variables.
114 115
115 116 for chgserver, it is designed that once confighash changes, the server is
116 117 not qualified to serve its client and should redirect the client to a new
117 118 server. different from mtimehash, confighash change will not mark the
118 119 server outdated and exit since the user can have different configs at the
119 120 same time.
120 121 """
121 122 sectionitems = []
122 123 for section in _configsections:
123 124 sectionitems.append(ui.configitems(section))
124 125 for section, item in _configsectionitems:
125 126 sectionitems.append(ui.config(section, item))
126 127 sectionhash = _hashlist(sectionitems)
127 128 # If $CHGHG is set, the change to $HG should not trigger a new chg server
128 129 if b'CHGHG' in encoding.environ:
129 130 ignored = {b'HG'}
130 131 else:
131 132 ignored = set()
132 133 envitems = [
133 134 (k, v)
134 135 for k, v in pycompat.iteritems(encoding.environ)
135 136 if _envre.match(k) and k not in ignored
136 137 ]
137 138 envhash = _hashlist(sorted(envitems))
138 139 return sectionhash[:6] + envhash[:6]
139 140
140 141
141 142 def _getmtimepaths(ui):
142 143 """get a list of paths that should be checked to detect change
143 144
144 145 The list will include:
145 146 - extensions (will not cover all files for complex extensions)
146 147 - mercurial/__version__.py
147 148 - python binary
148 149 """
149 150 modules = [m for n, m in extensions.extensions(ui)]
150 151 try:
151 152 from . import __version__
152 153
153 154 modules.append(__version__)
154 155 except ImportError:
155 156 pass
156 157 files = []
157 158 if pycompat.sysexecutable:
158 159 files.append(pycompat.sysexecutable)
159 160 for m in modules:
160 161 try:
161 162 files.append(pycompat.fsencode(inspect.getabsfile(m)))
162 163 except TypeError:
163 164 pass
164 165 return sorted(set(files))
165 166
166 167
167 168 def _mtimehash(paths):
168 169 """return a quick hash for detecting file changes
169 170
170 171 mtimehash calls stat on given paths and calculate a hash based on size and
171 172 mtime of each file. mtimehash does not read file content because reading is
172 173 expensive. therefore it's not 100% reliable for detecting content changes.
173 174 it's possible to return different hashes for same file contents.
174 175 it's also possible to return a same hash for different file contents for
175 176 some carefully crafted situation.
176 177
177 178 for chgserver, it is designed that once mtimehash changes, the server is
178 179 considered outdated immediately and should no longer provide service.
179 180
180 181 mtimehash is not included in confighash because we only know the paths of
181 182 extensions after importing them (there is imp.find_module but that faces
182 183 race conditions). We need to calculate confighash without importing.
183 184 """
184 185
185 186 def trystat(path):
186 187 try:
187 188 st = os.stat(path)
188 189 return (st[stat.ST_MTIME], st.st_size)
189 190 except OSError:
190 191 # could be ENOENT, EPERM etc. not fatal in any case
191 192 pass
192 193
193 194 return _hashlist(pycompat.maplist(trystat, paths))[:12]
194 195
195 196
196 197 class hashstate(object):
197 198 """a structure storing confighash, mtimehash, paths used for mtimehash"""
198 199
199 200 def __init__(self, confighash, mtimehash, mtimepaths):
200 201 self.confighash = confighash
201 202 self.mtimehash = mtimehash
202 203 self.mtimepaths = mtimepaths
203 204
204 205 @staticmethod
205 206 def fromui(ui, mtimepaths=None):
206 207 if mtimepaths is None:
207 208 mtimepaths = _getmtimepaths(ui)
208 209 confighash = _confighash(ui)
209 210 mtimehash = _mtimehash(mtimepaths)
210 211 ui.log(
211 212 b'cmdserver',
212 213 b'confighash = %s mtimehash = %s\n',
213 214 confighash,
214 215 mtimehash,
215 216 )
216 217 return hashstate(confighash, mtimehash, mtimepaths)
217 218
218 219
219 220 def _newchgui(srcui, csystem, attachio):
220 221 class chgui(srcui.__class__):
221 222 def __init__(self, src=None):
222 223 super(chgui, self).__init__(src)
223 224 if src:
224 225 self._csystem = getattr(src, '_csystem', csystem)
225 226 else:
226 227 self._csystem = csystem
227 228
228 229 def _runsystem(self, cmd, environ, cwd, out):
229 230 # fallback to the original system method if
230 231 # a. the output stream is not stdout (e.g. stderr, cStringIO),
231 232 # b. or stdout is redirected by protectfinout(),
232 233 # because the chg client is not aware of these situations and
233 234 # will behave differently (i.e. write to stdout).
234 235 if (
235 236 out is not self.fout
236 237 or not util.safehasattr(self.fout, b'fileno')
237 238 or self.fout.fileno() != procutil.stdout.fileno()
238 239 or self._finoutredirected
239 240 ):
240 241 return procutil.system(cmd, environ=environ, cwd=cwd, out=out)
241 242 self.flush()
242 243 return self._csystem(cmd, procutil.shellenviron(environ), cwd)
243 244
244 245 def _runpager(self, cmd, env=None):
245 246 self._csystem(
246 247 cmd,
247 248 procutil.shellenviron(env),
248 249 type=b'pager',
249 250 cmdtable={b'attachio': attachio},
250 251 )
251 252 return True
252 253
253 254 return chgui(srcui)
254 255
255 256
256 257 def _loadnewui(srcui, args, cdebug):
257 258 from . import dispatch # avoid cycle
258 259
259 260 newui = srcui.__class__.load()
260 261 for a in [b'fin', b'fout', b'ferr', b'environ']:
261 262 setattr(newui, a, getattr(srcui, a))
262 263 if util.safehasattr(srcui, b'_csystem'):
263 264 newui._csystem = srcui._csystem
264 265
265 266 # command line args
266 267 options = dispatch._earlyparseopts(newui, args)
267 268 dispatch._parseconfig(newui, options[b'config'])
268 269
269 270 # stolen from tortoisehg.util.copydynamicconfig()
270 271 for section, name, value in srcui.walkconfig():
271 272 source = srcui.configsource(section, name)
272 273 if b':' in source or source == b'--config' or source.startswith(b'$'):
273 274 # path:line or command line, or environ
274 275 continue
275 276 newui.setconfig(section, name, value, source)
276 277
277 278 # load wd and repo config, copied from dispatch.py
278 279 cwd = options[b'cwd']
279 280 cwd = cwd and os.path.realpath(cwd) or None
280 281 rpath = options[b'repository']
281 282 path, newlui = dispatch._getlocal(newui, rpath, wd=cwd)
282 283
283 284 extensions.populateui(newui)
284 285 commandserver.setuplogging(newui, fp=cdebug)
285 286 if newui is not newlui:
286 287 extensions.populateui(newlui)
287 288 commandserver.setuplogging(newlui, fp=cdebug)
288 289
289 290 return (newui, newlui)
290 291
291 292
292 293 class channeledsystem(object):
293 294 """Propagate ui.system() request in the following format:
294 295
295 296 payload length (unsigned int),
296 297 type, '\0',
297 298 cmd, '\0',
298 299 cwd, '\0',
299 300 envkey, '=', val, '\0',
300 301 ...
301 302 envkey, '=', val
302 303
303 304 if type == 'system', waits for:
304 305
305 306 exitcode length (unsigned int),
306 307 exitcode (int)
307 308
308 309 if type == 'pager', repetitively waits for a command name ending with '\n'
309 310 and executes it defined by cmdtable, or exits the loop if the command name
310 311 is empty.
311 312 """
312 313
313 314 def __init__(self, in_, out, channel):
314 315 self.in_ = in_
315 316 self.out = out
316 317 self.channel = channel
317 318
318 319 def __call__(self, cmd, environ, cwd=None, type=b'system', cmdtable=None):
319 320 args = [type, procutil.quotecommand(cmd), os.path.abspath(cwd or b'.')]
320 321 args.extend(b'%s=%s' % (k, v) for k, v in pycompat.iteritems(environ))
321 322 data = b'\0'.join(args)
322 323 self.out.write(struct.pack(b'>cI', self.channel, len(data)))
323 324 self.out.write(data)
324 325 self.out.flush()
325 326
326 327 if type == b'system':
327 328 length = self.in_.read(4)
328 329 (length,) = struct.unpack(b'>I', length)
329 330 if length != 4:
330 331 raise error.Abort(_(b'invalid response'))
331 332 (rc,) = struct.unpack(b'>i', self.in_.read(4))
332 333 return rc
333 334 elif type == b'pager':
334 335 while True:
335 336 cmd = self.in_.readline()[:-1]
336 337 if not cmd:
337 338 break
338 339 if cmdtable and cmd in cmdtable:
339 340 cmdtable[cmd]()
340 341 else:
341 342 raise error.Abort(_(b'unexpected command: %s') % cmd)
342 343 else:
343 344 raise error.ProgrammingError(b'invalid S channel type: %s' % type)
344 345
345 346
346 347 _iochannels = [
347 348 # server.ch, ui.fp, mode
348 349 (b'cin', b'fin', 'rb'),
349 350 (b'cout', b'fout', 'wb'),
350 351 (b'cerr', b'ferr', 'wb'),
351 352 ]
352 353
353 354
354 355 class chgcmdserver(commandserver.server):
355 356 def __init__(
356 357 self, ui, repo, fin, fout, sock, prereposetups, hashstate, baseaddress
357 358 ):
358 359 super(chgcmdserver, self).__init__(
359 360 _newchgui(ui, channeledsystem(fin, fout, b'S'), self.attachio),
360 361 repo,
361 362 fin,
362 363 fout,
363 364 prereposetups,
364 365 )
365 366 self.clientsock = sock
366 367 self._ioattached = False
367 368 self._oldios = [] # original (self.ch, ui.fp, fd) before "attachio"
368 369 self.hashstate = hashstate
369 370 self.baseaddress = baseaddress
370 371 if hashstate is not None:
371 372 self.capabilities = self.capabilities.copy()
372 373 self.capabilities[b'validate'] = chgcmdserver.validate
373 374
374 375 def cleanup(self):
375 376 super(chgcmdserver, self).cleanup()
376 377 # dispatch._runcatch() does not flush outputs if exception is not
377 378 # handled by dispatch._dispatch()
378 379 self.ui.flush()
379 380 self._restoreio()
380 381 self._ioattached = False
381 382
382 383 def attachio(self):
383 384 """Attach to client's stdio passed via unix domain socket; all
384 385 channels except cresult will no longer be used
385 386 """
386 387 # tell client to sendmsg() with 1-byte payload, which makes it
387 388 # distinctive from "attachio\n" command consumed by client.read()
388 389 self.clientsock.sendall(struct.pack(b'>cI', b'I', 1))
389 390 clientfds = util.recvfds(self.clientsock.fileno())
390 391 self.ui.log(b'chgserver', b'received fds: %r\n', clientfds)
391 392
392 393 ui = self.ui
393 394 ui.flush()
394 395 self._saveio()
395 396 for fd, (cn, fn, mode) in zip(clientfds, _iochannels):
396 397 assert fd > 0
397 398 fp = getattr(ui, fn)
398 399 os.dup2(fd, fp.fileno())
399 400 os.close(fd)
400 401 if self._ioattached:
401 402 continue
402 403 # reset buffering mode when client is first attached. as we want
403 404 # to see output immediately on pager, the mode stays unchanged
404 405 # when client re-attached. ferr is unchanged because it should
405 406 # be unbuffered no matter if it is a tty or not.
406 407 if fn == b'ferr':
407 408 newfp = fp
408 409 else:
409 410 # make it line buffered explicitly because the default is
410 411 # decided on first write(), where fout could be a pager.
411 412 if fp.isatty():
412 413 bufsize = 1 # line buffered
413 414 else:
414 415 bufsize = -1 # system default
415 416 newfp = os.fdopen(fp.fileno(), mode, bufsize)
416 417 setattr(ui, fn, newfp)
417 418 setattr(self, cn, newfp)
418 419
419 420 self._ioattached = True
420 421 self.cresult.write(struct.pack(b'>i', len(clientfds)))
421 422
422 423 def _saveio(self):
423 424 if self._oldios:
424 425 return
425 426 ui = self.ui
426 427 for cn, fn, _mode in _iochannels:
427 428 ch = getattr(self, cn)
428 429 fp = getattr(ui, fn)
429 430 fd = os.dup(fp.fileno())
430 431 self._oldios.append((ch, fp, fd))
431 432
432 433 def _restoreio(self):
433 434 ui = self.ui
434 435 for (ch, fp, fd), (cn, fn, _mode) in zip(self._oldios, _iochannels):
435 436 newfp = getattr(ui, fn)
436 437 # close newfp while it's associated with client; otherwise it
437 438 # would be closed when newfp is deleted
438 439 if newfp is not fp:
439 440 newfp.close()
440 441 # restore original fd: fp is open again
441 442 os.dup2(fd, fp.fileno())
442 443 os.close(fd)
443 444 setattr(self, cn, ch)
444 445 setattr(ui, fn, fp)
445 446 del self._oldios[:]
446 447
447 448 def validate(self):
448 449 """Reload the config and check if the server is up to date
449 450
450 451 Read a list of '\0' separated arguments.
451 452 Write a non-empty list of '\0' separated instruction strings or '\0'
452 453 if the list is empty.
453 454 An instruction string could be either:
454 455 - "unlink $path", the client should unlink the path to stop the
455 456 outdated server.
456 457 - "redirect $path", the client should attempt to connect to $path
457 458 first. If it does not work, start a new server. It implies
458 459 "reconnect".
459 460 - "exit $n", the client should exit directly with code n.
460 461 This may happen if we cannot parse the config.
461 462 - "reconnect", the client should close the connection and
462 463 reconnect.
463 464 If neither "reconnect" nor "redirect" is included in the instruction
464 465 list, the client can continue with this server after completing all
465 466 the instructions.
466 467 """
467 468 from . import dispatch # avoid cycle
468 469
469 470 args = self._readlist()
470 471 try:
471 472 self.ui, lui = _loadnewui(self.ui, args, self.cdebug)
472 473 except error.ParseError as inst:
473 474 dispatch._formatparse(self.ui.warn, inst)
474 475 self.ui.flush()
475 476 self.cresult.write(b'exit 255')
476 477 return
477 478 except error.Abort as inst:
478 479 self.ui.error(_(b"abort: %s\n") % inst)
479 480 if inst.hint:
480 481 self.ui.error(_(b"(%s)\n") % inst.hint)
481 482 self.ui.flush()
482 483 self.cresult.write(b'exit 255')
483 484 return
484 485 newhash = hashstate.fromui(lui, self.hashstate.mtimepaths)
485 486 insts = []
486 487 if newhash.mtimehash != self.hashstate.mtimehash:
487 488 addr = _hashaddress(self.baseaddress, self.hashstate.confighash)
488 489 insts.append(b'unlink %s' % addr)
489 490 # mtimehash is empty if one or more extensions fail to load.
490 491 # to be compatible with hg, still serve the client this time.
491 492 if self.hashstate.mtimehash:
492 493 insts.append(b'reconnect')
493 494 if newhash.confighash != self.hashstate.confighash:
494 495 addr = _hashaddress(self.baseaddress, newhash.confighash)
495 496 insts.append(b'redirect %s' % addr)
496 497 self.ui.log(b'chgserver', b'validate: %s\n', stringutil.pprint(insts))
497 498 self.cresult.write(b'\0'.join(insts) or b'\0')
498 499
499 500 def chdir(self):
500 501 """Change current directory
501 502
502 503 Note that the behavior of --cwd option is bit different from this.
503 504 It does not affect --config parameter.
504 505 """
505 506 path = self._readstr()
506 507 if not path:
507 508 return
508 509 self.ui.log(b'chgserver', b"chdir to '%s'\n", path)
509 510 os.chdir(path)
510 511
511 512 def setumask(self):
512 513 """Change umask (DEPRECATED)"""
513 514 # BUG: this does not follow the message frame structure, but kept for
514 515 # backward compatibility with old chg clients for some time
515 516 self._setumask(self._read(4))
516 517
517 518 def setumask2(self):
518 519 """Change umask"""
519 520 data = self._readstr()
520 521 if len(data) != 4:
521 522 raise ValueError(b'invalid mask length in setumask2 request')
522 523 self._setumask(data)
523 524
524 525 def _setumask(self, data):
525 526 mask = struct.unpack(b'>I', data)[0]
526 527 self.ui.log(b'chgserver', b'setumask %r\n', mask)
527 528 os.umask(mask)
528 529
529 530 def runcommand(self):
530 531 # pager may be attached within the runcommand session, which should
531 532 # be detached at the end of the session. otherwise the pager wouldn't
532 533 # receive EOF.
533 534 globaloldios = self._oldios
534 535 self._oldios = []
535 536 try:
536 537 return super(chgcmdserver, self).runcommand()
537 538 finally:
538 539 self._restoreio()
539 540 self._oldios = globaloldios
540 541
541 542 def setenv(self):
542 543 """Clear and update os.environ
543 544
544 545 Note that not all variables can make an effect on the running process.
545 546 """
546 547 l = self._readlist()
547 548 try:
548 549 newenv = dict(s.split(b'=', 1) for s in l)
549 550 except ValueError:
550 551 raise ValueError(b'unexpected value in setenv request')
551 552 self.ui.log(b'chgserver', b'setenv: %r\n', sorted(newenv.keys()))
552 553
553 554 encoding.environ.clear()
554 555 encoding.environ.update(newenv)
555 556
556 557 capabilities = commandserver.server.capabilities.copy()
557 558 capabilities.update(
558 559 {
559 560 b'attachio': attachio,
560 561 b'chdir': chdir,
561 562 b'runcommand': runcommand,
562 563 b'setenv': setenv,
563 564 b'setumask': setumask,
564 565 b'setumask2': setumask2,
565 566 }
566 567 )
567 568
568 569 if util.safehasattr(procutil, b'setprocname'):
569 570
570 571 def setprocname(self):
571 572 """Change process title"""
572 573 name = self._readstr()
573 574 self.ui.log(b'chgserver', b'setprocname: %r\n', name)
574 575 procutil.setprocname(name)
575 576
576 577 capabilities[b'setprocname'] = setprocname
577 578
578 579
579 580 def _tempaddress(address):
580 581 return b'%s.%d.tmp' % (address, os.getpid())
581 582
582 583
583 584 def _hashaddress(address, hashstr):
584 585 # if the basename of address contains '.', use only the left part. this
585 586 # makes it possible for the client to pass 'server.tmp$PID' and follow by
586 587 # an atomic rename to avoid locking when spawning new servers.
587 588 dirname, basename = os.path.split(address)
588 589 basename = basename.split(b'.', 1)[0]
589 590 return b'%s-%s' % (os.path.join(dirname, basename), hashstr)
590 591
591 592
592 593 class chgunixservicehandler(object):
593 594 """Set of operations for chg services"""
594 595
595 596 pollinterval = 1 # [sec]
596 597
597 598 def __init__(self, ui):
598 599 self.ui = ui
599 600 self._idletimeout = ui.configint(b'chgserver', b'idletimeout')
600 601 self._lastactive = time.time()
601 602
602 603 def bindsocket(self, sock, address):
603 604 self._inithashstate(address)
604 605 self._checkextensions()
605 606 self._bind(sock)
606 607 self._createsymlink()
607 608 # no "listening at" message should be printed to simulate hg behavior
608 609
609 610 def _inithashstate(self, address):
610 611 self._baseaddress = address
611 612 if self.ui.configbool(b'chgserver', b'skiphash'):
612 613 self._hashstate = None
613 614 self._realaddress = address
614 615 return
615 616 self._hashstate = hashstate.fromui(self.ui)
616 617 self._realaddress = _hashaddress(address, self._hashstate.confighash)
617 618
618 619 def _checkextensions(self):
619 620 if not self._hashstate:
620 621 return
621 622 if extensions.notloaded():
622 623 # one or more extensions failed to load. mtimehash becomes
623 624 # meaningless because we do not know the paths of those extensions.
624 625 # set mtimehash to an illegal hash value to invalidate the server.
625 626 self._hashstate.mtimehash = b''
626 627
627 628 def _bind(self, sock):
628 629 # use a unique temp address so we can stat the file and do ownership
629 630 # check later
630 631 tempaddress = _tempaddress(self._realaddress)
631 632 util.bindunixsocket(sock, tempaddress)
632 633 self._socketstat = os.stat(tempaddress)
633 634 sock.listen(socket.SOMAXCONN)
634 635 # rename will replace the old socket file if exists atomically. the
635 636 # old server will detect ownership change and exit.
636 637 util.rename(tempaddress, self._realaddress)
637 638
638 639 def _createsymlink(self):
639 640 if self._baseaddress == self._realaddress:
640 641 return
641 642 tempaddress = _tempaddress(self._baseaddress)
642 643 os.symlink(os.path.basename(self._realaddress), tempaddress)
643 644 util.rename(tempaddress, self._baseaddress)
644 645
645 646 def _issocketowner(self):
646 647 try:
647 648 st = os.stat(self._realaddress)
648 649 return (
649 650 st.st_ino == self._socketstat.st_ino
650 651 and st[stat.ST_MTIME] == self._socketstat[stat.ST_MTIME]
651 652 )
652 653 except OSError:
653 654 return False
654 655
655 656 def unlinksocket(self, address):
656 657 if not self._issocketowner():
657 658 return
658 659 # it is possible to have a race condition here that we may
659 660 # remove another server's socket file. but that's okay
660 661 # since that server will detect and exit automatically and
661 662 # the client will start a new server on demand.
662 663 util.tryunlink(self._realaddress)
663 664
664 665 def shouldexit(self):
665 666 if not self._issocketowner():
666 667 self.ui.log(
667 668 b'chgserver', b'%s is not owned, exiting.\n', self._realaddress
668 669 )
669 670 return True
670 671 if time.time() - self._lastactive > self._idletimeout:
671 672 self.ui.log(b'chgserver', b'being idle too long. exiting.\n')
672 673 return True
673 674 return False
674 675
675 676 def newconnection(self):
676 677 self._lastactive = time.time()
677 678
678 679 def createcmdserver(self, repo, conn, fin, fout, prereposetups):
679 680 return chgcmdserver(
680 681 self.ui,
681 682 repo,
682 683 fin,
683 684 fout,
684 685 conn,
685 686 prereposetups,
686 687 self._hashstate,
687 688 self._baseaddress,
688 689 )
689 690
690 691
691 692 def chgunixservice(ui, repo, opts):
692 693 # CHGINTERNALMARK is set by chg client. It is an indication of things are
693 694 # started by chg so other code can do things accordingly, like disabling
694 695 # demandimport or detecting chg client started by chg client. When executed
695 696 # here, CHGINTERNALMARK is no longer useful and hence dropped to make
696 697 # environ cleaner.
697 698 if b'CHGINTERNALMARK' in encoding.environ:
698 699 del encoding.environ[b'CHGINTERNALMARK']
699 700 # Python3.7+ "coerces" the LC_CTYPE environment variable to a UTF-8 one if
700 701 # it thinks the current value is "C". This breaks the hash computation and
701 702 # causes chg to restart loop.
702 703 if b'CHGORIG_LC_CTYPE' in encoding.environ:
703 704 encoding.environ[b'LC_CTYPE'] = encoding.environ[b'CHGORIG_LC_CTYPE']
704 705 del encoding.environ[b'CHGORIG_LC_CTYPE']
705 706 elif b'CHG_CLEAR_LC_CTYPE' in encoding.environ:
706 707 if b'LC_CTYPE' in encoding.environ:
707 708 del encoding.environ[b'LC_CTYPE']
708 709 del encoding.environ[b'CHG_CLEAR_LC_CTYPE']
709 710
710 711 if repo:
711 712 # one chgserver can serve multiple repos. drop repo information
712 713 ui.setconfig(b'bundle', b'mainreporoot', b'', b'repo')
713 714 h = chgunixservicehandler(ui)
714 715 return commandserver.unixforkingservice(ui, repo=None, opts=opts, handler=h)
@@ -1,368 +1,418 b''
1 1 #require chg
2 2
3 3 $ mkdir log
4 4 $ cp $HGRCPATH $HGRCPATH.unconfigured
5 5 $ cat <<'EOF' >> $HGRCPATH
6 6 > [cmdserver]
7 7 > log = $TESTTMP/log/server.log
8 8 > max-log-files = 1
9 9 > max-log-size = 10 kB
10 10 > EOF
11 11 $ cp $HGRCPATH $HGRCPATH.orig
12 12
13 13 $ filterlog () {
14 14 > sed -e 's!^[0-9/]* [0-9:]* ([0-9]*)>!YYYY/MM/DD HH:MM:SS (PID)>!' \
15 15 > -e 's!\(setprocname\|received fds\|setenv\): .*!\1: ...!' \
16 16 > -e 's!\(confighash\|mtimehash\) = [0-9a-f]*!\1 = ...!g' \
17 17 > -e 's!\(in \)[0-9.]*s\b!\1 ...s!g' \
18 18 > -e 's!\(pid\)=[0-9]*!\1=...!g' \
19 19 > -e 's!\(/server-\)[0-9a-f]*!\1...!g'
20 20 > }
21 21
22 22 init repo
23 23
24 24 $ chg init foo
25 25 $ cd foo
26 26
27 27 ill-formed config
28 28
29 29 $ chg status
30 30 $ echo '=brokenconfig' >> $HGRCPATH
31 31 $ chg status
32 32 hg: parse error at * (glob)
33 33 [255]
34 34
35 35 $ cp $HGRCPATH.orig $HGRCPATH
36 36
37 37 long socket path
38 38
39 39 $ sockpath=$TESTTMP/this/path/should/be/longer/than/one-hundred-and-seven/characters/where/107/is/the/typical/size/limit/of/unix-domain-socket
40 40 $ mkdir -p $sockpath
41 41 $ bakchgsockname=$CHGSOCKNAME
42 42 $ CHGSOCKNAME=$sockpath/server
43 43 $ export CHGSOCKNAME
44 44 $ chg root
45 45 $TESTTMP/foo
46 46 $ rm -rf $sockpath
47 47 $ CHGSOCKNAME=$bakchgsockname
48 48 $ export CHGSOCKNAME
49 49
50 50 $ cd ..
51 51
52 52 editor
53 53 ------
54 54
55 55 $ cat >> pushbuffer.py <<EOF
56 56 > def reposetup(ui, repo):
57 57 > repo.ui.pushbuffer(subproc=True)
58 58 > EOF
59 59
60 60 $ chg init editor
61 61 $ cd editor
62 62
63 63 by default, system() should be redirected to the client:
64 64
65 65 $ touch foo
66 66 $ CHGDEBUG= HGEDITOR=cat chg ci -Am channeled --edit 2>&1 \
67 67 > | egrep "HG:|run 'cat"
68 68 chg: debug: * run 'cat "*"' at '$TESTTMP/editor' (glob)
69 69 HG: Enter commit message. Lines beginning with 'HG:' are removed.
70 70 HG: Leave message empty to abort commit.
71 71 HG: --
72 72 HG: user: test
73 73 HG: branch 'default'
74 74 HG: added foo
75 75
76 76 but no redirection should be made if output is captured:
77 77
78 78 $ touch bar
79 79 $ CHGDEBUG= HGEDITOR=cat chg ci -Am bufferred --edit \
80 80 > --config extensions.pushbuffer="$TESTTMP/pushbuffer.py" 2>&1 \
81 81 > | egrep "HG:|run 'cat"
82 82 [1]
83 83
84 84 check that commit commands succeeded:
85 85
86 86 $ hg log -T '{rev}:{desc}\n'
87 87 1:bufferred
88 88 0:channeled
89 89
90 90 $ cd ..
91 91
92 92 pager
93 93 -----
94 94
95 95 $ cat >> fakepager.py <<EOF
96 96 > import sys
97 97 > for line in sys.stdin:
98 98 > sys.stdout.write('paged! %r\n' % line)
99 99 > EOF
100 100
101 101 enable pager extension globally, but spawns the master server with no tty:
102 102
103 103 $ chg init pager
104 104 $ cd pager
105 105 $ cat >> $HGRCPATH <<EOF
106 106 > [extensions]
107 107 > pager =
108 108 > [pager]
109 109 > pager = "$PYTHON" $TESTTMP/fakepager.py
110 110 > EOF
111 111 $ chg version > /dev/null
112 112 $ touch foo
113 113 $ chg ci -qAm foo
114 114
115 115 pager should be enabled if the attached client has a tty:
116 116
117 117 $ chg log -l1 -q --config ui.formatted=True
118 118 paged! '0:1f7b0de80e11\n'
119 119 $ chg log -l1 -q --config ui.formatted=False
120 120 0:1f7b0de80e11
121 121
122 122 chg waits for pager if runcommand raises
123 123
124 124 $ cat > $TESTTMP/crash.py <<EOF
125 125 > from mercurial import registrar
126 126 > cmdtable = {}
127 127 > command = registrar.command(cmdtable)
128 128 > @command(b'crash')
129 129 > def pagercrash(ui, repo, *pats, **opts):
130 130 > ui.write(b'going to crash\n')
131 131 > raise Exception('.')
132 132 > EOF
133 133
134 134 $ cat > $TESTTMP/fakepager.py <<EOF
135 135 > from __future__ import absolute_import
136 136 > import sys
137 137 > import time
138 138 > for line in iter(sys.stdin.readline, ''):
139 139 > if 'crash' in line: # only interested in lines containing 'crash'
140 140 > # if chg exits when pager is sleeping (incorrectly), the output
141 141 > # will be captured by the next test case
142 142 > time.sleep(1)
143 143 > sys.stdout.write('crash-pager: %s' % line)
144 144 > EOF
145 145
146 146 $ cat >> .hg/hgrc <<EOF
147 147 > [extensions]
148 148 > crash = $TESTTMP/crash.py
149 149 > EOF
150 150
151 151 $ chg crash --pager=on --config ui.formatted=True 2>/dev/null
152 152 crash-pager: going to crash
153 153 [255]
154 154
155 155 $ cd ..
156 156
157 157 server lifecycle
158 158 ----------------
159 159
160 160 chg server should be restarted on code change, and old server will shut down
161 161 automatically. In this test, we use the following time parameters:
162 162
163 163 - "sleep 1" to make mtime different
164 164 - "sleep 2" to notice mtime change (polling interval is 1 sec)
165 165
166 166 set up repository with an extension:
167 167
168 168 $ chg init extreload
169 169 $ cd extreload
170 170 $ touch dummyext.py
171 171 $ cat <<EOF >> .hg/hgrc
172 172 > [extensions]
173 173 > dummyext = dummyext.py
174 174 > EOF
175 175
176 176 isolate socket directory for stable result:
177 177
178 178 $ OLDCHGSOCKNAME=$CHGSOCKNAME
179 179 $ mkdir chgsock
180 180 $ CHGSOCKNAME=`pwd`/chgsock/server
181 181
182 182 warm up server:
183 183
184 184 $ CHGDEBUG= chg log 2>&1 | egrep 'instruction|start'
185 185 chg: debug: * start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
186 186
187 187 new server should be started if extension modified:
188 188
189 189 $ sleep 1
190 190 $ touch dummyext.py
191 191 $ CHGDEBUG= chg log 2>&1 | egrep 'instruction|start'
192 192 chg: debug: * instruction: unlink $TESTTMP/extreload/chgsock/server-* (glob)
193 193 chg: debug: * instruction: reconnect (glob)
194 194 chg: debug: * start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
195 195
196 196 old server will shut down, while new server should still be reachable:
197 197
198 198 $ sleep 2
199 199 $ CHGDEBUG= chg log 2>&1 | (egrep 'instruction|start' || true)
200 200
201 201 socket file should never be unlinked by old server:
202 202 (simulates unowned socket by updating mtime, which makes sure server exits
203 203 at polling cycle)
204 204
205 205 $ ls chgsock/server-*
206 206 chgsock/server-* (glob)
207 207 $ touch chgsock/server-*
208 208 $ sleep 2
209 209 $ ls chgsock/server-*
210 210 chgsock/server-* (glob)
211 211
212 212 since no server is reachable from socket file, new server should be started:
213 213 (this test makes sure that old server shut down automatically)
214 214
215 215 $ CHGDEBUG= chg log 2>&1 | egrep 'instruction|start'
216 216 chg: debug: * start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
217 217
218 218 shut down servers and restore environment:
219 219
220 220 $ rm -R chgsock
221 221 $ sleep 2
222 222 $ CHGSOCKNAME=$OLDCHGSOCKNAME
223 223 $ cd ..
224 224
225 225 check that server events are recorded:
226 226
227 227 $ ls log
228 228 server.log
229 229 server.log.1
230 230
231 231 print only the last 10 lines, since we aren't sure how many records are
232 232 preserved (since setprocname isn't available on py3, the 10th-most-recent line
233 233 is different when using py3):
234 234
235 235 $ cat log/server.log.1 log/server.log | tail -10 | filterlog
236 236 YYYY/MM/DD HH:MM:SS (PID)> confighash = ... mtimehash = ... (py3 !)
237 237 YYYY/MM/DD HH:MM:SS (PID)> forked worker process (pid=...)
238 238 YYYY/MM/DD HH:MM:SS (PID)> setprocname: ... (no-py3 !)
239 239 YYYY/MM/DD HH:MM:SS (PID)> received fds: ...
240 240 YYYY/MM/DD HH:MM:SS (PID)> chdir to '$TESTTMP/extreload'
241 241 YYYY/MM/DD HH:MM:SS (PID)> setumask 18
242 242 YYYY/MM/DD HH:MM:SS (PID)> setenv: ...
243 243 YYYY/MM/DD HH:MM:SS (PID)> confighash = ... mtimehash = ...
244 244 YYYY/MM/DD HH:MM:SS (PID)> validate: []
245 245 YYYY/MM/DD HH:MM:SS (PID)> worker process exited (pid=...)
246 246 YYYY/MM/DD HH:MM:SS (PID)> $TESTTMP/extreload/chgsock/server-... is not owned, exiting.
247 247
248 global data mutated by schems
249 -----------------------------
250
251 $ hg init schemes
252 $ cd schemes
253
254 initial state
255
256 $ cat > .hg/hgrc <<'EOF'
257 > [extensions]
258 > schemes =
259 > [schemes]
260 > foo = https://foo.example.org/
261 > EOF
262 $ hg debugexpandscheme foo://expanded
263 https://foo.example.org/expanded
264 $ hg debugexpandscheme bar://unexpanded
265 bar://unexpanded
266
267 add bar
268
269 $ cat > .hg/hgrc <<'EOF'
270 > [extensions]
271 > schemes =
272 > [schemes]
273 > foo = https://foo.example.org/
274 > bar = https://bar.example.org/
275 > EOF
276 $ hg debugexpandscheme foo://expanded
277 https://foo.example.org/expanded
278 $ hg debugexpandscheme bar://expanded
279 https://bar.example.org/expanded
280
281 remove foo
282
283 $ cat > .hg/hgrc <<'EOF'
284 > [extensions]
285 > schemes =
286 > [schemes]
287 > bar = https://bar.example.org/
288 > EOF
289 $ hg debugexpandscheme foo://unexpanded
290 foo://unexpanded
291 $ hg debugexpandscheme bar://expanded
292 https://bar.example.org/expanded
293
294 $ cd ..
295
248 296 repository cache
249 297 ----------------
250 298
251 299 $ rm log/server.log*
252 300 $ cp $HGRCPATH.unconfigured $HGRCPATH
253 301 $ cat <<'EOF' >> $HGRCPATH
254 302 > [cmdserver]
255 303 > log = $TESTTMP/log/server.log
256 304 > max-repo-cache = 1
257 305 > track-log = command, repocache
258 306 > EOF
259 307
260 308 isolate socket directory for stable result:
261 309
262 310 $ OLDCHGSOCKNAME=$CHGSOCKNAME
263 311 $ mkdir chgsock
264 312 $ CHGSOCKNAME=`pwd`/chgsock/server
265 313
266 314 create empty repo and cache it:
267 315
268 316 $ hg init cached
269 317 $ hg id -R cached
270 318 000000000000 tip
271 319 $ sleep 1
272 320
273 321 modify repo (and cache will be invalidated):
274 322
275 323 $ touch cached/a
276 324 $ hg ci -R cached -Am 'add a'
277 325 adding a
278 326 $ sleep 1
279 327
280 328 read cached repo:
281 329
282 330 $ hg log -R cached
283 331 changeset: 0:ac82d8b1f7c4
284 332 tag: tip
285 333 user: test
286 334 date: Thu Jan 01 00:00:00 1970 +0000
287 335 summary: add a
288 336
289 337 $ sleep 1
290 338
291 339 discard cached from LRU cache:
292 340
293 341 $ hg clone cached cached2
294 342 updating to branch default
295 343 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
296 344 $ hg id -R cached2
297 345 ac82d8b1f7c4 tip
298 346 $ sleep 1
299 347
300 348 read uncached repo:
301 349
302 350 $ hg log -R cached
303 351 changeset: 0:ac82d8b1f7c4
304 352 tag: tip
305 353 user: test
306 354 date: Thu Jan 01 00:00:00 1970 +0000
307 355 summary: add a
308 356
309 357 $ sleep 1
310 358
311 359 shut down servers and restore environment:
312 360
313 361 $ rm -R chgsock
314 362 $ sleep 2
315 363 $ CHGSOCKNAME=$OLDCHGSOCKNAME
316 364
317 365 check server log:
318 366
319 367 $ cat log/server.log | filterlog
368 YYYY/MM/DD HH:MM:SS (PID)> worker process exited (pid=...)
369 YYYY/MM/DD HH:MM:SS (PID)> worker process exited (pid=...)
320 370 YYYY/MM/DD HH:MM:SS (PID)> init cached
321 371 YYYY/MM/DD HH:MM:SS (PID)> id -R cached
322 372 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
323 373 YYYY/MM/DD HH:MM:SS (PID)> repo from cache: $TESTTMP/cached
324 374 YYYY/MM/DD HH:MM:SS (PID)> ci -R cached -Am 'add a'
325 375 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
326 376 YYYY/MM/DD HH:MM:SS (PID)> repo from cache: $TESTTMP/cached
327 377 YYYY/MM/DD HH:MM:SS (PID)> log -R cached
328 378 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
329 379 YYYY/MM/DD HH:MM:SS (PID)> clone cached cached2
330 380 YYYY/MM/DD HH:MM:SS (PID)> id -R cached2
331 381 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached2 (in ...s)
332 382 YYYY/MM/DD HH:MM:SS (PID)> log -R cached
333 383 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
334 384
335 385 Test that chg works (sets to the user's actual LC_CTYPE) even when python
336 386 "coerces" the locale (py3.7+)
337 387
338 388 $ cat > $TESTTMP/debugenv.py <<EOF
339 389 > from mercurial import encoding
340 390 > from mercurial import registrar
341 391 > cmdtable = {}
342 392 > command = registrar.command(cmdtable)
343 393 > @command(b'debugenv', [], b'', norepo=True)
344 394 > def debugenv(ui):
345 395 > for k in [b'LC_ALL', b'LC_CTYPE', b'LANG']:
346 396 > v = encoding.environ.get(k)
347 397 > if v is not None:
348 398 > ui.write(b'%s=%s\n' % (k, encoding.environ[k]))
349 399 > EOF
350 400 (hg keeps python's modified LC_CTYPE, chg doesn't)
351 401 $ (unset LC_ALL; unset LANG; LC_CTYPE= "$CHGHG" \
352 402 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
353 403 LC_CTYPE=C.UTF-8 (py37 !)
354 404 LC_CTYPE= (no-py37 !)
355 405 $ (unset LC_ALL; unset LANG; LC_CTYPE= chg \
356 406 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
357 407 LC_CTYPE=
358 408 $ (unset LC_ALL; unset LANG; LC_CTYPE=unsupported_value chg \
359 409 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
360 410 LC_CTYPE=unsupported_value
361 411 $ (unset LC_ALL; unset LANG; LC_CTYPE= chg \
362 412 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
363 413 LC_CTYPE=
364 414 $ LANG= LC_ALL= LC_CTYPE= chg \
365 415 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv
366 416 LC_ALL=
367 417 LC_CTYPE=
368 418 LANG=
@@ -1,194 +1,197 b''
1 1 #require bzr
2 2
3 3 $ . "$TESTDIR/bzr-definitions"
4 4
5 Work around https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=944379
6 $ mkdir -p "${HOME}/.config/breezy"
7
5 8 empty directory
6 9
7 10 $ mkdir test-empty
8 11 $ cd test-empty
9 12 $ bzr init -q source
10 13 $ cd source
11 14 $ echo content > a
12 15 $ bzr add -q a
13 16 $ bzr commit -q -m 'Initial add'
14 17 $ mkdir empty
15 18 $ bzr add -q empty
16 19 $ bzr commit -q -m 'Empty directory added'
17 20 $ echo content > empty/something
18 21 $ bzr add -q empty/something
19 22 $ bzr commit -q -m 'Added file into directory'
20 23 $ cd ..
21 24 $ hg convert source source-hg
22 25 initializing destination source-hg repository
23 26 scanning source...
24 27 sorting...
25 28 converting...
26 29 2 Initial add
27 30 1 Empty directory added
28 31 0 Added file into directory
29 32 $ manifest source-hg 1
30 33 % manifest of 1
31 34 644 a
32 35 $ manifest source-hg tip
33 36 % manifest of tip
34 37 644 a
35 38 644 empty/something
36 39 $ cd ..
37 40
38 41 directory renames
39 42
40 43 $ mkdir test-dir-rename
41 44 $ cd test-dir-rename
42 45 $ bzr init -q source
43 46 $ cd source
44 47 $ mkdir tpyo
45 48 $ echo content > tpyo/something
46 49 $ bzr add -q tpyo
47 50 $ bzr commit -q -m 'Added directory'
48 51 $ bzr mv tpyo typo
49 52 tpyo => typo
50 53 $ bzr commit -q -m 'Oops, typo'
51 54 $ cd ..
52 55 $ hg convert source source-hg
53 56 initializing destination source-hg repository
54 57 scanning source...
55 58 sorting...
56 59 converting...
57 60 1 Added directory
58 61 0 Oops, typo
59 62 $ manifest source-hg 0
60 63 % manifest of 0
61 64 644 tpyo/something
62 65 $ manifest source-hg tip
63 66 % manifest of tip
64 67 644 typo/something
65 68 $ cd ..
66 69
67 70 nested directory renames
68 71
69 72 $ mkdir test-nested-dir-rename
70 73 $ cd test-nested-dir-rename
71 74 $ bzr init -q source
72 75 $ cd source
73 76 $ mkdir -p firstlevel/secondlevel/thirdlevel
74 77 $ echo content > firstlevel/secondlevel/file
75 78 $ echo this_needs_to_be_there_too > firstlevel/secondlevel/thirdlevel/stuff
76 79 $ bzr add -q firstlevel
77 80 $ bzr commit -q -m 'Added nested directories'
78 81 $ bzr mv firstlevel/secondlevel secondlevel
79 82 firstlevel/secondlevel => secondlevel
80 83 $ bzr commit -q -m 'Moved secondlevel one level up'
81 84 $ cd ..
82 85 $ hg convert source source-hg
83 86 initializing destination source-hg repository
84 87 scanning source...
85 88 sorting...
86 89 converting...
87 90 1 Added nested directories
88 91 0 Moved secondlevel one level up
89 92 $ manifest source-hg tip
90 93 % manifest of tip
91 94 644 secondlevel/file
92 95 644 secondlevel/thirdlevel/stuff
93 96 $ cd ..
94 97
95 98 directory remove
96 99
97 100 $ mkdir test-dir-remove
98 101 $ cd test-dir-remove
99 102 $ bzr init -q source
100 103 $ cd source
101 104 $ mkdir src
102 105 $ echo content > src/sourcecode
103 106 $ bzr add -q src
104 107 $ bzr commit -q -m 'Added directory'
105 108 $ bzr rm -q src
106 109 $ bzr commit -q -m 'Removed directory'
107 110 $ cd ..
108 111 $ hg convert source source-hg
109 112 initializing destination source-hg repository
110 113 scanning source...
111 114 sorting...
112 115 converting...
113 116 1 Added directory
114 117 0 Removed directory
115 118 $ manifest source-hg 0
116 119 % manifest of 0
117 120 644 src/sourcecode
118 121 $ manifest source-hg tip
119 122 % manifest of tip
120 123 $ cd ..
121 124
122 125 directory replace
123 126
124 127 $ mkdir test-dir-replace
125 128 $ cd test-dir-replace
126 129 $ bzr init -q source
127 130 $ cd source
128 131 $ mkdir first second
129 132 $ echo content > first/file
130 133 $ echo morecontent > first/dummy
131 134 $ echo othercontent > second/something
132 135 $ bzr add -q first second
133 136 $ bzr commit -q -m 'Initial layout'
134 137 $ bzr mv first/file second/file
135 138 first/file => second/file
136 139 $ bzr mv first third
137 140 first => third
138 141 $ bzr commit -q -m 'Some conflicting moves'
139 142 $ cd ..
140 143 $ hg convert source source-hg
141 144 initializing destination source-hg repository
142 145 scanning source...
143 146 sorting...
144 147 converting...
145 148 1 Initial layout
146 149 0 Some conflicting moves
147 150 $ manifest source-hg tip
148 151 % manifest of tip
149 152 644 second/file
150 153 644 second/something
151 154 644 third/dummy
152 155 $ cd ..
153 156
154 157 divergent nested renames (issue3089)
155 158
156 159 $ mkdir test-divergent-renames
157 160 $ cd test-divergent-renames
158 161 $ bzr init -q source
159 162 $ cd source
160 163 $ mkdir -p a/c
161 164 $ echo a > a/fa
162 165 $ echo c > a/c/fc
163 166 $ bzr add -q a
164 167 $ bzr commit -q -m 'Initial layout'
165 168 $ bzr mv a b
166 169 a => b
167 170 $ mkdir a
168 171 $ bzr add a
169 172 add(ed|ing) a (re)
170 173 $ bzr mv b/c a/c
171 174 b/c => a/c
172 175 $ bzr status
173 176 added:
174 177 a/
175 178 renamed:
176 179 a/? => b/? (re)
177 180 a/c/? => a/c/? (re)
178 181 $ bzr commit -q -m 'Divergent renames'
179 182 $ cd ..
180 183 $ hg convert source source-hg
181 184 initializing destination source-hg repository
182 185 scanning source...
183 186 sorting...
184 187 converting...
185 188 1 Initial layout
186 189 0 Divergent renames
187 190 $ hg -R source-hg st -C --change 1
188 191 A b/fa
189 192 a/fa
190 193 R a/fa
191 194 $ hg -R source-hg manifest -r 1
192 195 a/c/fc
193 196 b/fa
194 197 $ cd ..
@@ -1,288 +1,288 b''
1 1 #require bzr
2 2
3 3 $ . "$TESTDIR/bzr-definitions"
4 4
5 5 create and rename on the same file in the same step
6 6
7 7 $ mkdir test-createandrename
8 8 $ cd test-createandrename
9 9 $ bzr init -q source
10 10
11 11 test empty repo conversion (issue3233)
12 12
13 13 $ hg convert source source-hg
14 14 initializing destination source-hg repository
15 15 scanning source...
16 16 sorting...
17 17 converting...
18 18
19 19 back to the rename stuff
20 20
21 21 $ cd source
22 22 $ echo a > a
23 23 $ echo c > c
24 24 $ echo e > e
25 25 $ bzr add -q a c e
26 26 $ bzr commit -q -m 'Initial add: a, c, e'
27 27 $ bzr mv a b
28 28 a => b
29 29 $ bzr mv c d
30 30 c => d
31 31 $ bzr mv e f
32 32 e => f
33 33 $ echo a2 >> a
34 34 $ mkdir e
35 35 $ bzr add -q a e
36 36 $ bzr commit -q -m 'rename a into b, create a, rename c into d'
37 37 $ cd ..
38 38 $ hg convert source source-hg
39 39 scanning source...
40 40 sorting...
41 41 converting...
42 42 1 Initial add: a, c, e
43 43 0 rename a into b, create a, rename c into d
44 44 $ glog -R source-hg
45 45 o 1@source "rename a into b, create a, rename c into d" files+: [b d f], files-: [c e], files: [a]
46 46 |
47 47 o 0@source "Initial add: a, c, e" files+: [a c e], files-: [], files: []
48 48
49 49
50 50 manifest
51 51
52 52 $ hg manifest -R source-hg -r tip
53 53 a
54 54 b
55 55 d
56 56 f
57 57
58 58 test --rev option
59 59
60 60 $ hg convert -r 1 source source-1-hg
61 61 initializing destination source-1-hg repository
62 62 scanning source...
63 63 sorting...
64 64 converting...
65 65 0 Initial add: a, c, e
66 66 $ glog -R source-1-hg
67 67 o 0@source "Initial add: a, c, e" files+: [a c e], files-: [], files: []
68 68
69 69
70 70 test with filemap
71 71
72 72 $ cat > filemap <<EOF
73 73 > exclude a
74 74 > EOF
75 75 $ hg convert --filemap filemap source source-filemap-hg
76 76 initializing destination source-filemap-hg repository
77 77 scanning source...
78 78 sorting...
79 79 converting...
80 80 1 Initial add: a, c, e
81 81 0 rename a into b, create a, rename c into d
82 82 $ hg -R source-filemap-hg manifest -r tip
83 83 b
84 84 d
85 85 f
86 86
87 87 convert from lightweight checkout
88 88
89 89 $ bzr checkout --lightweight source source-light
90 90 $ hg convert -s bzr source-light source-light-hg
91 91 initializing destination source-light-hg repository
92 92 warning: lightweight checkouts may cause conversion failures, try with a regular branch instead.
93 93 $TESTTMP/test-createandrename/source-light does not look like a Bazaar repository
94 94 abort: source-light: missing or unsupported repository
95 95 [255]
96 96
97 97 extract timestamps that look just like hg's {date|isodate}:
98 98 yyyy-mm-dd HH:MM zzzz (no seconds!)
99 99 compare timestamps
100 100
101 101 $ cd source
102 102 $ bzr log | \
103 103 > sed '/timestamp/!d;s/.\{15\}\([0-9: -]\{16\}\):.. \(.[0-9]\{4\}\)/\1 \2/' \
104 104 > > ../bzr-timestamps
105 105 $ cd ..
106 106 $ hg -R source-hg log --template "{date|isodate}\n" > hg-timestamps
107 107 $ cmp bzr-timestamps hg-timestamps || diff -u bzr-timestamps hg-timestamps
108 108 $ cd ..
109 109
110 110 merge
111 111
112 112 $ mkdir test-merge
113 113 $ cd test-merge
114 114 $ cat > helper.py <<EOF
115 115 > import sys
116 116 > from bzrlib import workingtree
117 117 > wt = workingtree.WorkingTree.open('.')
118 118 >
119 119 > message, stamp = sys.argv[1:]
120 120 > wt.commit(message, timestamp=int(stamp))
121 121 > EOF
122 122 $ bzr init -q source
123 123 $ cd source
124 124 $ echo content > a
125 125 $ echo content2 > b
126 126 $ bzr add -q a b
127 127 $ bzr commit -q -m 'Initial add'
128 128 $ cd ..
129 129 $ bzr branch -q source source-improve
130 130 $ cd source
131 131 $ echo more >> a
132 132 $ "$PYTHON" ../helper.py 'Editing a' 100
133 133 $ cd ../source-improve
134 134 $ echo content3 >> b
135 135 $ "$PYTHON" ../helper.py 'Editing b' 200
136 136 $ cd ../source
137 137 $ bzr merge -q ../source-improve
138 138 $ bzr commit -q -m 'Merged improve branch'
139 139 $ cd ..
140 140 $ hg convert --datesort source source-hg
141 141 initializing destination source-hg repository
142 142 scanning source...
143 143 sorting...
144 144 converting...
145 145 3 Initial add
146 146 2 Editing a
147 147 1 Editing b
148 148 0 Merged improve branch
149 149 $ glog -R source-hg
150 150 o 3@source "Merged improve branch" files+: [], files-: [], files: []
151 151 |\
152 152 | o 2@source-improve "Editing b" files+: [], files-: [], files: [b]
153 153 | |
154 154 o | 1@source "Editing a" files+: [], files-: [], files: [a]
155 155 |/
156 156 o 0@source "Initial add" files+: [a b], files-: [], files: []
157 157
158 158 $ cd ..
159 159
160 160 #if symlink execbit
161 161
162 162 symlinks and executable files
163 163
164 164 $ mkdir test-symlinks
165 165 $ cd test-symlinks
166 166 $ bzr init -q source
167 167 $ cd source
168 168 $ touch program
169 169 $ chmod +x program
170 170 $ ln -s program altname
171 171 $ mkdir d
172 172 $ echo a > d/a
173 173 $ ln -s a syma
174 174 $ bzr add -q altname program syma d/a
175 175 $ bzr commit -q -m 'Initial setup'
176 176 $ touch newprog
177 177 $ chmod +x newprog
178 178 $ rm altname
179 179 $ ln -s newprog altname
180 180 $ chmod -x program
181 181 $ bzr add -q newprog
182 182 $ bzr commit -q -m 'Symlink changed, x bits changed'
183 183 $ cd ..
184 184 $ hg convert source source-hg
185 185 initializing destination source-hg repository
186 186 scanning source...
187 187 sorting...
188 188 converting...
189 189 1 Initial setup
190 190 0 Symlink changed, x bits changed
191 191 $ manifest source-hg 0
192 192 % manifest of 0
193 193 644 @ altname
194 194 644 d/a
195 195 755 * program
196 196 644 @ syma
197 197 $ manifest source-hg tip
198 198 % manifest of tip
199 199 644 @ altname
200 200 644 d/a
201 201 755 * newprog
202 202 644 program
203 203 644 @ syma
204 204
205 205 test the symlinks can be recreated
206 206
207 207 $ cd source-hg
208 208 $ hg up
209 209 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
210 210 $ hg cat syma; echo
211 211 a
212 212 $ cd ../..
213 213
214 214 #endif
215 215
216 216 Multiple branches
217 217
218 218 $ bzr init-repo -q --no-trees repo
219 219 $ bzr init -q repo/trunk
220 220 $ bzr co repo/trunk repo-trunk
221 221 $ cd repo-trunk
222 222 $ echo a > a
223 223 $ bzr add -q a
224 224 $ bzr ci -qm adda
225 225 $ bzr tag trunk-tag
226 226 Created tag trunk-tag.
227 227 $ bzr switch -b branch
228 228 Tree is up to date at revision 1.
229 Switched to branch: *repo/branch/ (glob)
229 Switched to branch*repo/branch/ (glob)
230 230 $ sleep 1
231 231 $ echo b > b
232 232 $ bzr add -q b
233 233 $ bzr ci -qm addb
234 234 $ bzr tag branch-tag
235 235 Created tag branch-tag.
236 236 $ bzr switch --force ../repo/trunk
237 237 Updated to revision 1.
238 Switched to branch: */repo/trunk/ (glob)
238 Switched to branch*/repo/trunk/ (glob)
239 239 $ sleep 1
240 240 $ echo a >> a
241 241 $ bzr ci -qm changea
242 242 $ cd ..
243 243 $ hg convert --datesort repo repo-bzr
244 244 initializing destination repo-bzr repository
245 245 scanning source...
246 246 sorting...
247 247 converting...
248 248 2 adda
249 249 1 addb
250 250 0 changea
251 251 updating tags
252 252 $ (cd repo-bzr; glog)
253 253 o 3@default "update tags" files+: [.hgtags], files-: [], files: []
254 254 |
255 255 o 2@default "changea" files+: [], files-: [], files: [a]
256 256 |
257 257 | o 1@branch "addb" files+: [b], files-: [], files: []
258 258 |/
259 259 o 0@default "adda" files+: [a], files-: [], files: []
260 260
261 261
262 262 Test tags (converted identifiers are not stable because bzr ones are
263 263 not and get incorporated in extra fields).
264 264
265 265 $ hg -R repo-bzr tags
266 266 tip 3:* (glob)
267 267 branch-tag 1:* (glob)
268 268 trunk-tag 0:* (glob)
269 269
270 270 Nested repositories (issue3254)
271 271
272 272 $ bzr init-repo -q --no-trees repo/inner
273 273 $ bzr init -q repo/inner/trunk
274 274 $ bzr co repo/inner/trunk inner-trunk
275 275 $ cd inner-trunk
276 276 $ echo b > b
277 277 $ bzr add -q b
278 278 $ bzr ci -qm addb
279 279 $ cd ..
280 280 $ hg convert --datesort repo noinner-bzr
281 281 initializing destination noinner-bzr repository
282 282 scanning source...
283 283 sorting...
284 284 converting...
285 285 2 adda
286 286 1 addb
287 287 0 changea
288 288 updating tags
@@ -1,29 +1,29 b''
1 1 #require no-pure
2 2
3 3 A script to generate nasty diff worst-case scenarios:
4 4
5 5 $ cat > s.py <<EOF
6 6 > import random
7 7 > for x in range(100000):
8 8 > print
9 9 > if random.randint(0, 100) >= 50:
10 10 > x += 1
11 11 > print(hex(x))
12 12 > EOF
13 13
14 14 $ hg init a
15 15 $ cd a
16 16
17 17 Check in a big file:
18 18
19 19 $ "$PYTHON" ../s.py > a
20 20 $ hg ci -qAm0
21 21
22 22 Modify it:
23 23
24 24 $ "$PYTHON" ../s.py > a
25 25
26 26 Time a check-in, should never take more than 10 seconds user time:
27 27
28 $ hg ci --time -m1
28 $ hg ci --time -m1 --config worker.enabled=no
29 29 time: real .* secs .user [0-9][.].* sys .* (re)
@@ -1,345 +1,357 b''
1 1 #require no-windows
2 2
3 3 $ . "$TESTDIR/remotefilelog-library.sh"
4 4 $ cat >> $HGRCPATH <<EOF
5 5 > [devel]
6 6 > remotefilelog.bg-wait=True
7 7 > EOF
8 8
9 9 $ hg init master
10 10 $ cd master
11 11 $ cat >> .hg/hgrc <<EOF
12 12 > [remotefilelog]
13 13 > server=True
14 14 > EOF
15 15 $ echo x > x
16 16 $ echo z > z
17 17 $ hg commit -qAm x
18 18 $ echo x2 > x
19 19 $ echo y > y
20 20 $ hg commit -qAm y
21 21 $ echo w > w
22 22 $ rm z
23 23 $ hg commit -qAm w
24 24 $ hg bookmark foo
25 25
26 26 $ cd ..
27 27
28 28 # clone the repo
29 29
30 30 $ hgcloneshallow ssh://user@dummy/master shallow --noupdate
31 31 streaming all changes
32 32 2 files to transfer, 776 bytes of data
33 33 transferred 776 bytes in * seconds (*/sec) (glob)
34 34 searching for changes
35 35 no changes found
36 36
37 37 # Set the prefetchdays config to zero so that all commits are prefetched
38 38 # no matter what their creation date is. Also set prefetchdelay config
39 39 # to zero so that there is no delay between prefetches.
40 40 $ cd shallow
41 41 $ cat >> .hg/hgrc <<EOF
42 42 > [remotefilelog]
43 43 > prefetchdays=0
44 44 > prefetchdelay=0
45 45 > EOF
46 46 $ cd ..
47 47
48 48 # prefetch a revision
49 49 $ cd shallow
50 50
51 51 $ hg prefetch -r 0
52 52 2 files fetched over 1 fetches - (2 misses, 0.00% hit ratio) over *s (glob)
53 53
54 54 $ hg cat -r 0 x
55 55 x
56 56
57 57 # background prefetch on pull when configured
58 58
59 59 $ cat >> .hg/hgrc <<EOF
60 60 > [remotefilelog]
61 61 > pullprefetch=bookmark()
62 62 > backgroundprefetch=True
63 63 > EOF
64 64 $ hg strip tip
65 65 saved backup bundle to $TESTTMP/shallow/.hg/strip-backup/6b4b6f66ef8c-b4b8bdaf-backup.hg (glob)
66 66
67 67 $ clearcache
68 68 $ hg pull
69 69 pulling from ssh://user@dummy/master
70 70 searching for changes
71 71 adding changesets
72 72 adding manifests
73 73 adding file changes
74 74 updating bookmark foo
75 75 added 1 changesets with 0 changes to 0 files
76 76 new changesets 6b4b6f66ef8c
77 77 (run 'hg update' to get a working copy)
78 78 prefetching file contents
79 79 $ find $CACHEDIR -type f | sort
80 80 $TESTTMP/hgcache/master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/ef95c5376f34698742fe34f315fd82136f8f68c0
81 81 $TESTTMP/hgcache/master/95/cb0bfd2977c761298d9624e4b4d4c72a39974a/076f5e2225b3ff0400b98c92aa6cdf403ee24cca
82 82 $TESTTMP/hgcache/master/af/f024fe4ab0fece4091de044c58c9ae4233383a/bb6ccd5dceaa5e9dc220e0dad65e051b94f69a2c
83 83 $TESTTMP/hgcache/repos
84 84
85 85 # background prefetch with repack on pull when configured
86 86
87 87 $ cat >> .hg/hgrc <<EOF
88 88 > [remotefilelog]
89 89 > backgroundrepack=True
90 90 > EOF
91 91 $ hg strip tip
92 92 saved backup bundle to $TESTTMP/shallow/.hg/strip-backup/6b4b6f66ef8c-b4b8bdaf-backup.hg (glob)
93 93
94 94 $ clearcache
95 95 $ hg pull
96 96 pulling from ssh://user@dummy/master
97 97 searching for changes
98 98 adding changesets
99 99 adding manifests
100 100 adding file changes
101 101 updating bookmark foo
102 102 added 1 changesets with 0 changes to 0 files
103 103 new changesets 6b4b6f66ef8c
104 104 (run 'hg update' to get a working copy)
105 105 prefetching file contents
106 106 $ find $CACHEDIR -type f | sort
107 107 $TESTTMP/hgcache/master/packs/6e8633deba6e544e5f8edbd7b996d6e31a2c42ae.histidx
108 108 $TESTTMP/hgcache/master/packs/6e8633deba6e544e5f8edbd7b996d6e31a2c42ae.histpack
109 109 $TESTTMP/hgcache/master/packs/8ce5ab3745465ab83bba30a7b9c295e0c8404652.dataidx
110 110 $TESTTMP/hgcache/master/packs/8ce5ab3745465ab83bba30a7b9c295e0c8404652.datapack
111 111 $TESTTMP/hgcache/repos
112 112
113 113 # background prefetch with repack on update when wcprevset configured
114 114
115 115 $ clearcache
116 116 $ hg up -r 0
117 117 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
118 118 2 files fetched over 1 fetches - (2 misses, 0.00% hit ratio) over *s (glob)
119 119 $ find $CACHEDIR -type f | sort
120 120 $TESTTMP/hgcache/master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/1406e74118627694268417491f018a4a883152f0
121 121 $TESTTMP/hgcache/master/39/5df8f7c51f007019cb30201c49e884b46b92fa/69a1b67522704ec122181c0890bd16e9d3e7516a
122 122 $TESTTMP/hgcache/repos
123 123
124 124 $ hg up -r 1
125 125 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
126 126 2 files fetched over 2 fetches - (2 misses, 0.00% hit ratio) over *s (glob)
127 127
128 128 $ cat >> .hg/hgrc <<EOF
129 129 > [remotefilelog]
130 130 > bgprefetchrevs=.::
131 131 > EOF
132 132
133 133 $ clearcache
134 134 $ hg up -r 0
135 135 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
136 136 * files fetched over * fetches - (* misses, 0.00% hit ratio) over *s (glob)
137 137 $ find $CACHEDIR -type f | sort
138 138 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histidx
139 139 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histpack
140 140 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.dataidx
141 141 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.datapack
142 142 $TESTTMP/hgcache/repos
143 143
144 144 # Ensure that file 'w' was prefetched - it was not part of the update operation and therefore
145 145 # could only be downloaded by the background prefetch
146 146
147 147 $ hg debugdatapack `ls -ct $TESTTMP/hgcache/master/packs/*.datapack | head -n 1`
148 148 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407:
149 149 w:
150 150 Node Delta Base Delta Length Blob Size
151 151 bb6ccd5dceaa 000000000000 2 2
152 152
153 153 Total: 2 2 (0.0% bigger)
154 154 x:
155 155 Node Delta Base Delta Length Blob Size
156 156 ef95c5376f34 000000000000 3 3
157 157 1406e7411862 ef95c5376f34 14 2
158 158
159 159 Total: 17 5 (240.0% bigger)
160 160 y:
161 161 Node Delta Base Delta Length Blob Size
162 162 076f5e2225b3 000000000000 2 2
163 163
164 164 Total: 2 2 (0.0% bigger)
165 165 z:
166 166 Node Delta Base Delta Length Blob Size
167 167 69a1b6752270 000000000000 2 2
168 168
169 169 Total: 2 2 (0.0% bigger)
170 170
171 171 # background prefetch with repack on commit when wcprevset configured
172 172
173 173 $ cat >> .hg/hgrc <<EOF
174 174 > [remotefilelog]
175 175 > bgprefetchrevs=0::
176 176 > EOF
177 177
178 178 $ clearcache
179 179 $ find $CACHEDIR -type f | sort
180 180 $ echo b > b
181 .. The following output line about files fetches is globed because it is
182 .. flaky, the core the test is checked when checking the cache dir, so
183 .. hopefully this flakyness is not hiding any actual bug.
181 184 $ hg commit -qAm b
182 * files fetched over 1 fetches - (* misses, 0.00% hit ratio) over *s (glob)
185 * files fetched over 1 fetches - (* misses, 0.00% hit ratio) over *s (glob) (?)
183 186 $ hg bookmark temporary
184 187 $ find $CACHEDIR -type f | sort
185 188 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histidx
186 189 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histpack
187 190 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.dataidx
188 191 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.datapack
189 192 $TESTTMP/hgcache/repos
190 193
191 194 # Ensure that file 'w' was prefetched - it was not part of the commit operation and therefore
192 195 # could only be downloaded by the background prefetch
193 196
194 197 $ hg debugdatapack `ls -ct $TESTTMP/hgcache/master/packs/*.datapack | head -n 1`
195 198 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407:
196 199 w:
197 200 Node Delta Base Delta Length Blob Size
198 201 bb6ccd5dceaa 000000000000 2 2
199 202
200 203 Total: 2 2 (0.0% bigger)
201 204 x:
202 205 Node Delta Base Delta Length Blob Size
203 206 ef95c5376f34 000000000000 3 3
204 207 1406e7411862 ef95c5376f34 14 2
205 208
206 209 Total: 17 5 (240.0% bigger)
207 210 y:
208 211 Node Delta Base Delta Length Blob Size
209 212 076f5e2225b3 000000000000 2 2
210 213
211 214 Total: 2 2 (0.0% bigger)
212 215 z:
213 216 Node Delta Base Delta Length Blob Size
214 217 69a1b6752270 000000000000 2 2
215 218
216 219 Total: 2 2 (0.0% bigger)
217 220
218 221 # background prefetch with repack on rebase when wcprevset configured
219 222
220 223 $ hg up -r 2
221 224 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
222 225 (leaving bookmark temporary)
223 226 $ clearcache
224 227 $ find $CACHEDIR -type f | sort
228 .. The following output line about files fetches is globed because it is
229 .. flaky, the core the test is checked when checking the cache dir, so
230 .. hopefully this flakyness is not hiding any actual bug.
225 231 $ hg rebase -s temporary -d foo
226 232 rebasing 3:d9cf06e3b5b6 "b" (temporary tip)
227 233 saved backup bundle to $TESTTMP/shallow/.hg/strip-backup/d9cf06e3b5b6-e5c3dc63-rebase.hg
228 3 files fetched over 1 fetches - (3 misses, 0.00% hit ratio) over *s (glob)
234 ? files fetched over ? fetches - (? misses, 0.00% hit ratio) over *s (glob)
235 $ find $CACHEDIR -type f | sort
236 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histidx
237 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histpack
238 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.dataidx
239 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.datapack
240 $TESTTMP/hgcache/repos
229 241
230 242 # Ensure that file 'y' was prefetched - it was not part of the rebase operation and therefore
231 243 # could only be downloaded by the background prefetch
232 244
233 245 $ hg debugdatapack `ls -ct $TESTTMP/hgcache/master/packs/*.datapack | head -n 1`
234 246 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407:
235 247 w:
236 248 Node Delta Base Delta Length Blob Size
237 249 bb6ccd5dceaa 000000000000 2 2
238 250
239 251 Total: 2 2 (0.0% bigger)
240 252 x:
241 253 Node Delta Base Delta Length Blob Size
242 254 ef95c5376f34 000000000000 3 3
243 255 1406e7411862 ef95c5376f34 14 2
244 256
245 257 Total: 17 5 (240.0% bigger)
246 258 y:
247 259 Node Delta Base Delta Length Blob Size
248 260 076f5e2225b3 000000000000 2 2
249 261
250 262 Total: 2 2 (0.0% bigger)
251 263 z:
252 264 Node Delta Base Delta Length Blob Size
253 265 69a1b6752270 000000000000 2 2
254 266
255 267 Total: 2 2 (0.0% bigger)
256 268
257 269 # Check that foregound prefetch with no arguments blocks until background prefetches finish
258 270
259 271 $ hg up -r 3
260 272 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
261 273 $ clearcache
262 274 $ hg prefetch --repack
263 275 waiting for lock on prefetching in $TESTTMP/shallow held by process * on host * (glob) (?)
264 276 got lock after * seconds (glob) (?)
265 277 (running background incremental repack)
266 278 * files fetched over 1 fetches - (* misses, 0.00% hit ratio) over *s (glob) (?)
267 279
268 280 $ find $CACHEDIR -type f | sort
269 281 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histidx
270 282 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histpack
271 283 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.dataidx
272 284 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.datapack
273 285 $TESTTMP/hgcache/repos
274 286
275 287 # Ensure that files were prefetched
276 288 $ hg debugdatapack `ls -ct $TESTTMP/hgcache/master/packs/*.datapack | head -n 1`
277 289 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407:
278 290 w:
279 291 Node Delta Base Delta Length Blob Size
280 292 bb6ccd5dceaa 000000000000 2 2
281 293
282 294 Total: 2 2 (0.0% bigger)
283 295 x:
284 296 Node Delta Base Delta Length Blob Size
285 297 ef95c5376f34 000000000000 3 3
286 298 1406e7411862 ef95c5376f34 14 2
287 299
288 300 Total: 17 5 (240.0% bigger)
289 301 y:
290 302 Node Delta Base Delta Length Blob Size
291 303 076f5e2225b3 000000000000 2 2
292 304
293 305 Total: 2 2 (0.0% bigger)
294 306 z:
295 307 Node Delta Base Delta Length Blob Size
296 308 69a1b6752270 000000000000 2 2
297 309
298 310 Total: 2 2 (0.0% bigger)
299 311
300 312 # Check that foreground prefetch fetches revs specified by '. + draft() + bgprefetchrevs + pullprefetch'
301 313
302 314 $ clearcache
303 315 $ hg prefetch --repack
304 316 waiting for lock on prefetching in $TESTTMP/shallow held by process * on host * (glob) (?)
305 317 got lock after * seconds (glob) (?)
306 318 (running background incremental repack)
307 319 * files fetched over 1 fetches - (* misses, 0.00% hit ratio) over *s (glob) (?)
308 320
309 321 $ find $CACHEDIR -type f | sort
310 322 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histidx
311 323 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histpack
312 324 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.dataidx
313 325 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.datapack
314 326 $TESTTMP/hgcache/repos
315 327
316 328 # Ensure that files were prefetched
317 329 $ hg debugdatapack `ls -ct $TESTTMP/hgcache/master/packs/*.datapack | head -n 1`
318 330 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407:
319 331 w:
320 332 Node Delta Base Delta Length Blob Size
321 333 bb6ccd5dceaa 000000000000 2 2
322 334
323 335 Total: 2 2 (0.0% bigger)
324 336 x:
325 337 Node Delta Base Delta Length Blob Size
326 338 ef95c5376f34 000000000000 3 3
327 339 1406e7411862 ef95c5376f34 14 2
328 340
329 341 Total: 17 5 (240.0% bigger)
330 342 y:
331 343 Node Delta Base Delta Length Blob Size
332 344 076f5e2225b3 000000000000 2 2
333 345
334 346 Total: 2 2 (0.0% bigger)
335 347 z:
336 348 Node Delta Base Delta Length Blob Size
337 349 69a1b6752270 000000000000 2 2
338 350
339 351 Total: 2 2 (0.0% bigger)
340 352
341 353 # Test that if data was prefetched and repacked we dont need to prefetch it again
342 354 # It ensures that Mercurial looks not only in loose files but in packs as well
343 355
344 356 $ hg prefetch --repack
345 357 (running background incremental repack)
General Comments 0
You need to be logged in to leave comments. Login now