##// END OF EJS Templates
manifestcache: use `wcache` directory for manifest cache...
marmoute -
r42131:e4ac7e63 default
parent child Browse files
Show More
@@ -1,2055 +1,2055 b''
1 1 # manifest.py - manifest revision class for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
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 from __future__ import absolute_import
9 9
10 10 import heapq
11 11 import itertools
12 12 import struct
13 13 import weakref
14 14
15 15 from .i18n import _
16 16 from .node import (
17 17 bin,
18 18 hex,
19 19 nullid,
20 20 nullrev,
21 21 )
22 22 from . import (
23 23 error,
24 24 mdiff,
25 25 policy,
26 26 pycompat,
27 27 repository,
28 28 revlog,
29 29 util,
30 30 )
31 31 from .utils import (
32 32 interfaceutil,
33 33 )
34 34
35 35 parsers = policy.importmod(r'parsers')
36 36 propertycache = util.propertycache
37 37
38 38 def _parse(data):
39 39 # This method does a little bit of excessive-looking
40 40 # precondition checking. This is so that the behavior of this
41 41 # class exactly matches its C counterpart to try and help
42 42 # prevent surprise breakage for anyone that develops against
43 43 # the pure version.
44 44 if data and data[-1:] != '\n':
45 45 raise ValueError('Manifest did not end in a newline.')
46 46 prev = None
47 47 for l in data.splitlines():
48 48 if prev is not None and prev > l:
49 49 raise ValueError('Manifest lines not in sorted order.')
50 50 prev = l
51 51 f, n = l.split('\0')
52 52 if len(n) > 40:
53 53 yield f, bin(n[:40]), n[40:]
54 54 else:
55 55 yield f, bin(n), ''
56 56
57 57 def _text(it):
58 58 files = []
59 59 lines = []
60 60 for f, n, fl in it:
61 61 files.append(f)
62 62 # if this is changed to support newlines in filenames,
63 63 # be sure to check the templates/ dir again (especially *-raw.tmpl)
64 64 lines.append("%s\0%s%s\n" % (f, hex(n), fl))
65 65
66 66 _checkforbidden(files)
67 67 return ''.join(lines)
68 68
69 69 class lazymanifestiter(object):
70 70 def __init__(self, lm):
71 71 self.pos = 0
72 72 self.lm = lm
73 73
74 74 def __iter__(self):
75 75 return self
76 76
77 77 def next(self):
78 78 try:
79 79 data, pos = self.lm._get(self.pos)
80 80 except IndexError:
81 81 raise StopIteration
82 82 if pos == -1:
83 83 self.pos += 1
84 84 return data[0]
85 85 self.pos += 1
86 86 zeropos = data.find('\x00', pos)
87 87 return data[pos:zeropos]
88 88
89 89 __next__ = next
90 90
91 91 class lazymanifestiterentries(object):
92 92 def __init__(self, lm):
93 93 self.lm = lm
94 94 self.pos = 0
95 95
96 96 def __iter__(self):
97 97 return self
98 98
99 99 def next(self):
100 100 try:
101 101 data, pos = self.lm._get(self.pos)
102 102 except IndexError:
103 103 raise StopIteration
104 104 if pos == -1:
105 105 self.pos += 1
106 106 return data
107 107 zeropos = data.find('\x00', pos)
108 108 hashval = unhexlify(data, self.lm.extrainfo[self.pos],
109 109 zeropos + 1, 40)
110 110 flags = self.lm._getflags(data, self.pos, zeropos)
111 111 self.pos += 1
112 112 return (data[pos:zeropos], hashval, flags)
113 113
114 114 __next__ = next
115 115
116 116 def unhexlify(data, extra, pos, length):
117 117 s = bin(data[pos:pos + length])
118 118 if extra:
119 119 s += chr(extra & 0xff)
120 120 return s
121 121
122 122 def _cmp(a, b):
123 123 return (a > b) - (a < b)
124 124
125 125 class _lazymanifest(object):
126 126 def __init__(self, data, positions=None, extrainfo=None, extradata=None):
127 127 if positions is None:
128 128 self.positions = self.findlines(data)
129 129 self.extrainfo = [0] * len(self.positions)
130 130 self.data = data
131 131 self.extradata = []
132 132 else:
133 133 self.positions = positions[:]
134 134 self.extrainfo = extrainfo[:]
135 135 self.extradata = extradata[:]
136 136 self.data = data
137 137
138 138 def findlines(self, data):
139 139 if not data:
140 140 return []
141 141 pos = data.find("\n")
142 142 if pos == -1 or data[-1:] != '\n':
143 143 raise ValueError("Manifest did not end in a newline.")
144 144 positions = [0]
145 145 prev = data[:data.find('\x00')]
146 146 while pos < len(data) - 1 and pos != -1:
147 147 positions.append(pos + 1)
148 148 nexts = data[pos + 1:data.find('\x00', pos + 1)]
149 149 if nexts < prev:
150 150 raise ValueError("Manifest lines not in sorted order.")
151 151 prev = nexts
152 152 pos = data.find("\n", pos + 1)
153 153 return positions
154 154
155 155 def _get(self, index):
156 156 # get the position encoded in pos:
157 157 # positive number is an index in 'data'
158 158 # negative number is in extrapieces
159 159 pos = self.positions[index]
160 160 if pos >= 0:
161 161 return self.data, pos
162 162 return self.extradata[-pos - 1], -1
163 163
164 164 def _getkey(self, pos):
165 165 if pos >= 0:
166 166 return self.data[pos:self.data.find('\x00', pos + 1)]
167 167 return self.extradata[-pos - 1][0]
168 168
169 169 def bsearch(self, key):
170 170 first = 0
171 171 last = len(self.positions) - 1
172 172
173 173 while first <= last:
174 174 midpoint = (first + last)//2
175 175 nextpos = self.positions[midpoint]
176 176 candidate = self._getkey(nextpos)
177 177 r = _cmp(key, candidate)
178 178 if r == 0:
179 179 return midpoint
180 180 else:
181 181 if r < 0:
182 182 last = midpoint - 1
183 183 else:
184 184 first = midpoint + 1
185 185 return -1
186 186
187 187 def bsearch2(self, key):
188 188 # same as the above, but will always return the position
189 189 # done for performance reasons
190 190 first = 0
191 191 last = len(self.positions) - 1
192 192
193 193 while first <= last:
194 194 midpoint = (first + last)//2
195 195 nextpos = self.positions[midpoint]
196 196 candidate = self._getkey(nextpos)
197 197 r = _cmp(key, candidate)
198 198 if r == 0:
199 199 return (midpoint, True)
200 200 else:
201 201 if r < 0:
202 202 last = midpoint - 1
203 203 else:
204 204 first = midpoint + 1
205 205 return (first, False)
206 206
207 207 def __contains__(self, key):
208 208 return self.bsearch(key) != -1
209 209
210 210 def _getflags(self, data, needle, pos):
211 211 start = pos + 41
212 212 end = data.find("\n", start)
213 213 if end == -1:
214 214 end = len(data) - 1
215 215 if start == end:
216 216 return ''
217 217 return self.data[start:end]
218 218
219 219 def __getitem__(self, key):
220 220 if not isinstance(key, bytes):
221 221 raise TypeError("getitem: manifest keys must be a bytes.")
222 222 needle = self.bsearch(key)
223 223 if needle == -1:
224 224 raise KeyError
225 225 data, pos = self._get(needle)
226 226 if pos == -1:
227 227 return (data[1], data[2])
228 228 zeropos = data.find('\x00', pos)
229 229 assert 0 <= needle <= len(self.positions)
230 230 assert len(self.extrainfo) == len(self.positions)
231 231 hashval = unhexlify(data, self.extrainfo[needle], zeropos + 1, 40)
232 232 flags = self._getflags(data, needle, zeropos)
233 233 return (hashval, flags)
234 234
235 235 def __delitem__(self, key):
236 236 needle, found = self.bsearch2(key)
237 237 if not found:
238 238 raise KeyError
239 239 cur = self.positions[needle]
240 240 self.positions = self.positions[:needle] + self.positions[needle + 1:]
241 241 self.extrainfo = self.extrainfo[:needle] + self.extrainfo[needle + 1:]
242 242 if cur >= 0:
243 243 self.data = self.data[:cur] + '\x00' + self.data[cur + 1:]
244 244
245 245 def __setitem__(self, key, value):
246 246 if not isinstance(key, bytes):
247 247 raise TypeError("setitem: manifest keys must be a byte string.")
248 248 if not isinstance(value, tuple) or len(value) != 2:
249 249 raise TypeError("Manifest values must be a tuple of (node, flags).")
250 250 hashval = value[0]
251 251 if not isinstance(hashval, bytes) or not 20 <= len(hashval) <= 22:
252 252 raise TypeError("node must be a 20-byte byte string")
253 253 flags = value[1]
254 254 if len(hashval) == 22:
255 255 hashval = hashval[:-1]
256 256 if not isinstance(flags, bytes) or len(flags) > 1:
257 257 raise TypeError("flags must a 0 or 1 byte string, got %r", flags)
258 258 needle, found = self.bsearch2(key)
259 259 if found:
260 260 # put the item
261 261 pos = self.positions[needle]
262 262 if pos < 0:
263 263 self.extradata[-pos - 1] = (key, hashval, value[1])
264 264 else:
265 265 # just don't bother
266 266 self.extradata.append((key, hashval, value[1]))
267 267 self.positions[needle] = -len(self.extradata)
268 268 else:
269 269 # not found, put it in with extra positions
270 270 self.extradata.append((key, hashval, value[1]))
271 271 self.positions = (self.positions[:needle] + [-len(self.extradata)]
272 272 + self.positions[needle:])
273 273 self.extrainfo = (self.extrainfo[:needle] + [0] +
274 274 self.extrainfo[needle:])
275 275
276 276 def copy(self):
277 277 # XXX call _compact like in C?
278 278 return _lazymanifest(self.data, self.positions, self.extrainfo,
279 279 self.extradata)
280 280
281 281 def _compact(self):
282 282 # hopefully not called TOO often
283 283 if len(self.extradata) == 0:
284 284 return
285 285 l = []
286 286 i = 0
287 287 offset = 0
288 288 self.extrainfo = [0] * len(self.positions)
289 289 while i < len(self.positions):
290 290 if self.positions[i] >= 0:
291 291 cur = self.positions[i]
292 292 last_cut = cur
293 293 while True:
294 294 self.positions[i] = offset
295 295 i += 1
296 296 if i == len(self.positions) or self.positions[i] < 0:
297 297 break
298 298 offset += self.positions[i] - cur
299 299 cur = self.positions[i]
300 300 end_cut = self.data.find('\n', cur)
301 301 if end_cut != -1:
302 302 end_cut += 1
303 303 offset += end_cut - cur
304 304 l.append(self.data[last_cut:end_cut])
305 305 else:
306 306 while i < len(self.positions) and self.positions[i] < 0:
307 307 cur = self.positions[i]
308 308 t = self.extradata[-cur - 1]
309 309 l.append(self._pack(t))
310 310 self.positions[i] = offset
311 311 if len(t[1]) > 20:
312 312 self.extrainfo[i] = ord(t[1][21])
313 313 offset += len(l[-1])
314 314 i += 1
315 315 self.data = ''.join(l)
316 316 self.extradata = []
317 317
318 318 def _pack(self, d):
319 319 return d[0] + '\x00' + hex(d[1][:20]) + d[2] + '\n'
320 320
321 321 def text(self):
322 322 self._compact()
323 323 return self.data
324 324
325 325 def diff(self, m2, clean=False):
326 326 '''Finds changes between the current manifest and m2.'''
327 327 # XXX think whether efficiency matters here
328 328 diff = {}
329 329
330 330 for fn, e1, flags in self.iterentries():
331 331 if fn not in m2:
332 332 diff[fn] = (e1, flags), (None, '')
333 333 else:
334 334 e2 = m2[fn]
335 335 if (e1, flags) != e2:
336 336 diff[fn] = (e1, flags), e2
337 337 elif clean:
338 338 diff[fn] = None
339 339
340 340 for fn, e2, flags in m2.iterentries():
341 341 if fn not in self:
342 342 diff[fn] = (None, ''), (e2, flags)
343 343
344 344 return diff
345 345
346 346 def iterentries(self):
347 347 return lazymanifestiterentries(self)
348 348
349 349 def iterkeys(self):
350 350 return lazymanifestiter(self)
351 351
352 352 def __iter__(self):
353 353 return lazymanifestiter(self)
354 354
355 355 def __len__(self):
356 356 return len(self.positions)
357 357
358 358 def filtercopy(self, filterfn):
359 359 # XXX should be optimized
360 360 c = _lazymanifest('')
361 361 for f, n, fl in self.iterentries():
362 362 if filterfn(f):
363 363 c[f] = n, fl
364 364 return c
365 365
366 366 try:
367 367 _lazymanifest = parsers.lazymanifest
368 368 except AttributeError:
369 369 pass
370 370
371 371 @interfaceutil.implementer(repository.imanifestdict)
372 372 class manifestdict(object):
373 373 def __init__(self, data=''):
374 374 self._lm = _lazymanifest(data)
375 375
376 376 def __getitem__(self, key):
377 377 return self._lm[key][0]
378 378
379 379 def find(self, key):
380 380 return self._lm[key]
381 381
382 382 def __len__(self):
383 383 return len(self._lm)
384 384
385 385 def __nonzero__(self):
386 386 # nonzero is covered by the __len__ function, but implementing it here
387 387 # makes it easier for extensions to override.
388 388 return len(self._lm) != 0
389 389
390 390 __bool__ = __nonzero__
391 391
392 392 def __setitem__(self, key, node):
393 393 self._lm[key] = node, self.flags(key, '')
394 394
395 395 def __contains__(self, key):
396 396 if key is None:
397 397 return False
398 398 return key in self._lm
399 399
400 400 def __delitem__(self, key):
401 401 del self._lm[key]
402 402
403 403 def __iter__(self):
404 404 return self._lm.__iter__()
405 405
406 406 def iterkeys(self):
407 407 return self._lm.iterkeys()
408 408
409 409 def keys(self):
410 410 return list(self.iterkeys())
411 411
412 412 def filesnotin(self, m2, match=None):
413 413 '''Set of files in this manifest that are not in the other'''
414 414 if match:
415 415 m1 = self.matches(match)
416 416 m2 = m2.matches(match)
417 417 return m1.filesnotin(m2)
418 418 diff = self.diff(m2)
419 419 files = set(filepath
420 420 for filepath, hashflags in diff.iteritems()
421 421 if hashflags[1][0] is None)
422 422 return files
423 423
424 424 @propertycache
425 425 def _dirs(self):
426 426 return util.dirs(self)
427 427
428 428 def dirs(self):
429 429 return self._dirs
430 430
431 431 def hasdir(self, dir):
432 432 return dir in self._dirs
433 433
434 434 def _filesfastpath(self, match):
435 435 '''Checks whether we can correctly and quickly iterate over matcher
436 436 files instead of over manifest files.'''
437 437 files = match.files()
438 438 return (len(files) < 100 and (match.isexact() or
439 439 (match.prefix() and all(fn in self for fn in files))))
440 440
441 441 def walk(self, match):
442 442 '''Generates matching file names.
443 443
444 444 Equivalent to manifest.matches(match).iterkeys(), but without creating
445 445 an entirely new manifest.
446 446
447 447 It also reports nonexistent files by marking them bad with match.bad().
448 448 '''
449 449 if match.always():
450 450 for f in iter(self):
451 451 yield f
452 452 return
453 453
454 454 fset = set(match.files())
455 455
456 456 # avoid the entire walk if we're only looking for specific files
457 457 if self._filesfastpath(match):
458 458 for fn in sorted(fset):
459 459 yield fn
460 460 return
461 461
462 462 for fn in self:
463 463 if fn in fset:
464 464 # specified pattern is the exact name
465 465 fset.remove(fn)
466 466 if match(fn):
467 467 yield fn
468 468
469 469 # for dirstate.walk, files=['.'] means "walk the whole tree".
470 470 # follow that here, too
471 471 fset.discard('.')
472 472
473 473 for fn in sorted(fset):
474 474 if not self.hasdir(fn):
475 475 match.bad(fn, None)
476 476
477 477 def matches(self, match):
478 478 '''generate a new manifest filtered by the match argument'''
479 479 if match.always():
480 480 return self.copy()
481 481
482 482 if self._filesfastpath(match):
483 483 m = manifestdict()
484 484 lm = self._lm
485 485 for fn in match.files():
486 486 if fn in lm:
487 487 m._lm[fn] = lm[fn]
488 488 return m
489 489
490 490 m = manifestdict()
491 491 m._lm = self._lm.filtercopy(match)
492 492 return m
493 493
494 494 def diff(self, m2, match=None, clean=False):
495 495 '''Finds changes between the current manifest and m2.
496 496
497 497 Args:
498 498 m2: the manifest to which this manifest should be compared.
499 499 clean: if true, include files unchanged between these manifests
500 500 with a None value in the returned dictionary.
501 501
502 502 The result is returned as a dict with filename as key and
503 503 values of the form ((n1,fl1),(n2,fl2)), where n1/n2 is the
504 504 nodeid in the current/other manifest and fl1/fl2 is the flag
505 505 in the current/other manifest. Where the file does not exist,
506 506 the nodeid will be None and the flags will be the empty
507 507 string.
508 508 '''
509 509 if match:
510 510 m1 = self.matches(match)
511 511 m2 = m2.matches(match)
512 512 return m1.diff(m2, clean=clean)
513 513 return self._lm.diff(m2._lm, clean)
514 514
515 515 def setflag(self, key, flag):
516 516 self._lm[key] = self[key], flag
517 517
518 518 def get(self, key, default=None):
519 519 try:
520 520 return self._lm[key][0]
521 521 except KeyError:
522 522 return default
523 523
524 524 def flags(self, key, default=''):
525 525 try:
526 526 return self._lm[key][1]
527 527 except KeyError:
528 528 return default
529 529
530 530 def copy(self):
531 531 c = manifestdict()
532 532 c._lm = self._lm.copy()
533 533 return c
534 534
535 535 def items(self):
536 536 return (x[:2] for x in self._lm.iterentries())
537 537
538 538 def iteritems(self):
539 539 return (x[:2] for x in self._lm.iterentries())
540 540
541 541 def iterentries(self):
542 542 return self._lm.iterentries()
543 543
544 544 def text(self):
545 545 # most likely uses native version
546 546 return self._lm.text()
547 547
548 548 def fastdelta(self, base, changes):
549 549 """Given a base manifest text as a bytearray and a list of changes
550 550 relative to that text, compute a delta that can be used by revlog.
551 551 """
552 552 delta = []
553 553 dstart = None
554 554 dend = None
555 555 dline = [""]
556 556 start = 0
557 557 # zero copy representation of base as a buffer
558 558 addbuf = util.buffer(base)
559 559
560 560 changes = list(changes)
561 561 if len(changes) < 1000:
562 562 # start with a readonly loop that finds the offset of
563 563 # each line and creates the deltas
564 564 for f, todelete in changes:
565 565 # bs will either be the index of the item or the insert point
566 566 start, end = _msearch(addbuf, f, start)
567 567 if not todelete:
568 568 h, fl = self._lm[f]
569 569 l = "%s\0%s%s\n" % (f, hex(h), fl)
570 570 else:
571 571 if start == end:
572 572 # item we want to delete was not found, error out
573 573 raise AssertionError(
574 574 _("failed to remove %s from manifest") % f)
575 575 l = ""
576 576 if dstart is not None and dstart <= start and dend >= start:
577 577 if dend < end:
578 578 dend = end
579 579 if l:
580 580 dline.append(l)
581 581 else:
582 582 if dstart is not None:
583 583 delta.append([dstart, dend, "".join(dline)])
584 584 dstart = start
585 585 dend = end
586 586 dline = [l]
587 587
588 588 if dstart is not None:
589 589 delta.append([dstart, dend, "".join(dline)])
590 590 # apply the delta to the base, and get a delta for addrevision
591 591 deltatext, arraytext = _addlistdelta(base, delta)
592 592 else:
593 593 # For large changes, it's much cheaper to just build the text and
594 594 # diff it.
595 595 arraytext = bytearray(self.text())
596 596 deltatext = mdiff.textdiff(
597 597 util.buffer(base), util.buffer(arraytext))
598 598
599 599 return arraytext, deltatext
600 600
601 601 def _msearch(m, s, lo=0, hi=None):
602 602 '''return a tuple (start, end) that says where to find s within m.
603 603
604 604 If the string is found m[start:end] are the line containing
605 605 that string. If start == end the string was not found and
606 606 they indicate the proper sorted insertion point.
607 607
608 608 m should be a buffer, a memoryview or a byte string.
609 609 s is a byte string'''
610 610 def advance(i, c):
611 611 while i < lenm and m[i:i + 1] != c:
612 612 i += 1
613 613 return i
614 614 if not s:
615 615 return (lo, lo)
616 616 lenm = len(m)
617 617 if not hi:
618 618 hi = lenm
619 619 while lo < hi:
620 620 mid = (lo + hi) // 2
621 621 start = mid
622 622 while start > 0 and m[start - 1:start] != '\n':
623 623 start -= 1
624 624 end = advance(start, '\0')
625 625 if bytes(m[start:end]) < s:
626 626 # we know that after the null there are 40 bytes of sha1
627 627 # this translates to the bisect lo = mid + 1
628 628 lo = advance(end + 40, '\n') + 1
629 629 else:
630 630 # this translates to the bisect hi = mid
631 631 hi = start
632 632 end = advance(lo, '\0')
633 633 found = m[lo:end]
634 634 if s == found:
635 635 # we know that after the null there are 40 bytes of sha1
636 636 end = advance(end + 40, '\n')
637 637 return (lo, end + 1)
638 638 else:
639 639 return (lo, lo)
640 640
641 641 def _checkforbidden(l):
642 642 """Check filenames for illegal characters."""
643 643 for f in l:
644 644 if '\n' in f or '\r' in f:
645 645 raise error.StorageError(
646 646 _("'\\n' and '\\r' disallowed in filenames: %r")
647 647 % pycompat.bytestr(f))
648 648
649 649
650 650 # apply the changes collected during the bisect loop to our addlist
651 651 # return a delta suitable for addrevision
652 652 def _addlistdelta(addlist, x):
653 653 # for large addlist arrays, building a new array is cheaper
654 654 # than repeatedly modifying the existing one
655 655 currentposition = 0
656 656 newaddlist = bytearray()
657 657
658 658 for start, end, content in x:
659 659 newaddlist += addlist[currentposition:start]
660 660 if content:
661 661 newaddlist += bytearray(content)
662 662
663 663 currentposition = end
664 664
665 665 newaddlist += addlist[currentposition:]
666 666
667 667 deltatext = "".join(struct.pack(">lll", start, end, len(content))
668 668 + content for start, end, content in x)
669 669 return deltatext, newaddlist
670 670
671 671 def _splittopdir(f):
672 672 if '/' in f:
673 673 dir, subpath = f.split('/', 1)
674 674 return dir + '/', subpath
675 675 else:
676 676 return '', f
677 677
678 678 _noop = lambda s: None
679 679
680 680 class treemanifest(object):
681 681 def __init__(self, dir='', text=''):
682 682 self._dir = dir
683 683 self._node = nullid
684 684 self._loadfunc = _noop
685 685 self._copyfunc = _noop
686 686 self._dirty = False
687 687 self._dirs = {}
688 688 self._lazydirs = {}
689 689 # Using _lazymanifest here is a little slower than plain old dicts
690 690 self._files = {}
691 691 self._flags = {}
692 692 if text:
693 693 def readsubtree(subdir, subm):
694 694 raise AssertionError('treemanifest constructor only accepts '
695 695 'flat manifests')
696 696 self.parse(text, readsubtree)
697 697 self._dirty = True # Mark flat manifest dirty after parsing
698 698
699 699 def _subpath(self, path):
700 700 return self._dir + path
701 701
702 702 def _loadalllazy(self):
703 703 selfdirs = self._dirs
704 704 for d, (path, node, readsubtree, docopy) in self._lazydirs.iteritems():
705 705 if docopy:
706 706 selfdirs[d] = readsubtree(path, node).copy()
707 707 else:
708 708 selfdirs[d] = readsubtree(path, node)
709 709 self._lazydirs = {}
710 710
711 711 def _loadlazy(self, d):
712 712 v = self._lazydirs.get(d)
713 713 if v:
714 714 path, node, readsubtree, docopy = v
715 715 if docopy:
716 716 self._dirs[d] = readsubtree(path, node).copy()
717 717 else:
718 718 self._dirs[d] = readsubtree(path, node)
719 719 del self._lazydirs[d]
720 720
721 721 def _loadchildrensetlazy(self, visit):
722 722 if not visit:
723 723 return None
724 724 if visit == 'all' or visit == 'this':
725 725 self._loadalllazy()
726 726 return None
727 727
728 728 loadlazy = self._loadlazy
729 729 for k in visit:
730 730 loadlazy(k + '/')
731 731 return visit
732 732
733 733 def _loaddifflazy(self, t1, t2):
734 734 """load items in t1 and t2 if they're needed for diffing.
735 735
736 736 The criteria currently is:
737 737 - if it's not present in _lazydirs in either t1 or t2, load it in the
738 738 other (it may already be loaded or it may not exist, doesn't matter)
739 739 - if it's present in _lazydirs in both, compare the nodeid; if it
740 740 differs, load it in both
741 741 """
742 742 toloadlazy = []
743 743 for d, v1 in t1._lazydirs.iteritems():
744 744 v2 = t2._lazydirs.get(d)
745 745 if not v2 or v2[1] != v1[1]:
746 746 toloadlazy.append(d)
747 747 for d, v1 in t2._lazydirs.iteritems():
748 748 if d not in t1._lazydirs:
749 749 toloadlazy.append(d)
750 750
751 751 for d in toloadlazy:
752 752 t1._loadlazy(d)
753 753 t2._loadlazy(d)
754 754
755 755 def __len__(self):
756 756 self._load()
757 757 size = len(self._files)
758 758 self._loadalllazy()
759 759 for m in self._dirs.values():
760 760 size += m.__len__()
761 761 return size
762 762
763 763 def __nonzero__(self):
764 764 # Faster than "__len() != 0" since it avoids loading sub-manifests
765 765 return not self._isempty()
766 766
767 767 __bool__ = __nonzero__
768 768
769 769 def _isempty(self):
770 770 self._load() # for consistency; already loaded by all callers
771 771 # See if we can skip loading everything.
772 772 if self._files or (self._dirs and
773 773 any(not m._isempty() for m in self._dirs.values())):
774 774 return False
775 775 self._loadalllazy()
776 776 return (not self._dirs or
777 777 all(m._isempty() for m in self._dirs.values()))
778 778
779 779 def __repr__(self):
780 780 return ('<treemanifest dir=%s, node=%s, loaded=%s, dirty=%s at 0x%x>' %
781 781 (self._dir, hex(self._node),
782 782 bool(self._loadfunc is _noop),
783 783 self._dirty, id(self)))
784 784
785 785 def dir(self):
786 786 '''The directory that this tree manifest represents, including a
787 787 trailing '/'. Empty string for the repo root directory.'''
788 788 return self._dir
789 789
790 790 def node(self):
791 791 '''This node of this instance. nullid for unsaved instances. Should
792 792 be updated when the instance is read or written from a revlog.
793 793 '''
794 794 assert not self._dirty
795 795 return self._node
796 796
797 797 def setnode(self, node):
798 798 self._node = node
799 799 self._dirty = False
800 800
801 801 def iterentries(self):
802 802 self._load()
803 803 self._loadalllazy()
804 804 for p, n in sorted(itertools.chain(self._dirs.items(),
805 805 self._files.items())):
806 806 if p in self._files:
807 807 yield self._subpath(p), n, self._flags.get(p, '')
808 808 else:
809 809 for x in n.iterentries():
810 810 yield x
811 811
812 812 def items(self):
813 813 self._load()
814 814 self._loadalllazy()
815 815 for p, n in sorted(itertools.chain(self._dirs.items(),
816 816 self._files.items())):
817 817 if p in self._files:
818 818 yield self._subpath(p), n
819 819 else:
820 820 for f, sn in n.iteritems():
821 821 yield f, sn
822 822
823 823 iteritems = items
824 824
825 825 def iterkeys(self):
826 826 self._load()
827 827 self._loadalllazy()
828 828 for p in sorted(itertools.chain(self._dirs, self._files)):
829 829 if p in self._files:
830 830 yield self._subpath(p)
831 831 else:
832 832 for f in self._dirs[p]:
833 833 yield f
834 834
835 835 def keys(self):
836 836 return list(self.iterkeys())
837 837
838 838 def __iter__(self):
839 839 return self.iterkeys()
840 840
841 841 def __contains__(self, f):
842 842 if f is None:
843 843 return False
844 844 self._load()
845 845 dir, subpath = _splittopdir(f)
846 846 if dir:
847 847 self._loadlazy(dir)
848 848
849 849 if dir not in self._dirs:
850 850 return False
851 851
852 852 return self._dirs[dir].__contains__(subpath)
853 853 else:
854 854 return f in self._files
855 855
856 856 def get(self, f, default=None):
857 857 self._load()
858 858 dir, subpath = _splittopdir(f)
859 859 if dir:
860 860 self._loadlazy(dir)
861 861
862 862 if dir not in self._dirs:
863 863 return default
864 864 return self._dirs[dir].get(subpath, default)
865 865 else:
866 866 return self._files.get(f, default)
867 867
868 868 def __getitem__(self, f):
869 869 self._load()
870 870 dir, subpath = _splittopdir(f)
871 871 if dir:
872 872 self._loadlazy(dir)
873 873
874 874 return self._dirs[dir].__getitem__(subpath)
875 875 else:
876 876 return self._files[f]
877 877
878 878 def flags(self, f):
879 879 self._load()
880 880 dir, subpath = _splittopdir(f)
881 881 if dir:
882 882 self._loadlazy(dir)
883 883
884 884 if dir not in self._dirs:
885 885 return ''
886 886 return self._dirs[dir].flags(subpath)
887 887 else:
888 888 if f in self._lazydirs or f in self._dirs:
889 889 return ''
890 890 return self._flags.get(f, '')
891 891
892 892 def find(self, f):
893 893 self._load()
894 894 dir, subpath = _splittopdir(f)
895 895 if dir:
896 896 self._loadlazy(dir)
897 897
898 898 return self._dirs[dir].find(subpath)
899 899 else:
900 900 return self._files[f], self._flags.get(f, '')
901 901
902 902 def __delitem__(self, f):
903 903 self._load()
904 904 dir, subpath = _splittopdir(f)
905 905 if dir:
906 906 self._loadlazy(dir)
907 907
908 908 self._dirs[dir].__delitem__(subpath)
909 909 # If the directory is now empty, remove it
910 910 if self._dirs[dir]._isempty():
911 911 del self._dirs[dir]
912 912 else:
913 913 del self._files[f]
914 914 if f in self._flags:
915 915 del self._flags[f]
916 916 self._dirty = True
917 917
918 918 def __setitem__(self, f, n):
919 919 assert n is not None
920 920 self._load()
921 921 dir, subpath = _splittopdir(f)
922 922 if dir:
923 923 self._loadlazy(dir)
924 924 if dir not in self._dirs:
925 925 self._dirs[dir] = treemanifest(self._subpath(dir))
926 926 self._dirs[dir].__setitem__(subpath, n)
927 927 else:
928 928 self._files[f] = n[:21] # to match manifestdict's behavior
929 929 self._dirty = True
930 930
931 931 def _load(self):
932 932 if self._loadfunc is not _noop:
933 933 lf, self._loadfunc = self._loadfunc, _noop
934 934 lf(self)
935 935 elif self._copyfunc is not _noop:
936 936 cf, self._copyfunc = self._copyfunc, _noop
937 937 cf(self)
938 938
939 939 def setflag(self, f, flags):
940 940 """Set the flags (symlink, executable) for path f."""
941 941 self._load()
942 942 dir, subpath = _splittopdir(f)
943 943 if dir:
944 944 self._loadlazy(dir)
945 945 if dir not in self._dirs:
946 946 self._dirs[dir] = treemanifest(self._subpath(dir))
947 947 self._dirs[dir].setflag(subpath, flags)
948 948 else:
949 949 self._flags[f] = flags
950 950 self._dirty = True
951 951
952 952 def copy(self):
953 953 copy = treemanifest(self._dir)
954 954 copy._node = self._node
955 955 copy._dirty = self._dirty
956 956 if self._copyfunc is _noop:
957 957 def _copyfunc(s):
958 958 self._load()
959 959 s._lazydirs = {d: (p, n, r, True) for
960 960 d, (p, n, r, c) in self._lazydirs.iteritems()}
961 961 sdirs = s._dirs
962 962 for d, v in self._dirs.iteritems():
963 963 sdirs[d] = v.copy()
964 964 s._files = dict.copy(self._files)
965 965 s._flags = dict.copy(self._flags)
966 966 if self._loadfunc is _noop:
967 967 _copyfunc(copy)
968 968 else:
969 969 copy._copyfunc = _copyfunc
970 970 else:
971 971 copy._copyfunc = self._copyfunc
972 972 return copy
973 973
974 974 def filesnotin(self, m2, match=None):
975 975 '''Set of files in this manifest that are not in the other'''
976 976 if match and not match.always():
977 977 m1 = self.matches(match)
978 978 m2 = m2.matches(match)
979 979 return m1.filesnotin(m2)
980 980
981 981 files = set()
982 982 def _filesnotin(t1, t2):
983 983 if t1._node == t2._node and not t1._dirty and not t2._dirty:
984 984 return
985 985 t1._load()
986 986 t2._load()
987 987 self._loaddifflazy(t1, t2)
988 988 for d, m1 in t1._dirs.iteritems():
989 989 if d in t2._dirs:
990 990 m2 = t2._dirs[d]
991 991 _filesnotin(m1, m2)
992 992 else:
993 993 files.update(m1.iterkeys())
994 994
995 995 for fn in t1._files:
996 996 if fn not in t2._files:
997 997 files.add(t1._subpath(fn))
998 998
999 999 _filesnotin(self, m2)
1000 1000 return files
1001 1001
1002 1002 @propertycache
1003 1003 def _alldirs(self):
1004 1004 return util.dirs(self)
1005 1005
1006 1006 def dirs(self):
1007 1007 return self._alldirs
1008 1008
1009 1009 def hasdir(self, dir):
1010 1010 self._load()
1011 1011 topdir, subdir = _splittopdir(dir)
1012 1012 if topdir:
1013 1013 self._loadlazy(topdir)
1014 1014 if topdir in self._dirs:
1015 1015 return self._dirs[topdir].hasdir(subdir)
1016 1016 return False
1017 1017 dirslash = dir + '/'
1018 1018 return dirslash in self._dirs or dirslash in self._lazydirs
1019 1019
1020 1020 def walk(self, match):
1021 1021 '''Generates matching file names.
1022 1022
1023 1023 Equivalent to manifest.matches(match).iterkeys(), but without creating
1024 1024 an entirely new manifest.
1025 1025
1026 1026 It also reports nonexistent files by marking them bad with match.bad().
1027 1027 '''
1028 1028 if match.always():
1029 1029 for f in iter(self):
1030 1030 yield f
1031 1031 return
1032 1032
1033 1033 fset = set(match.files())
1034 1034
1035 1035 for fn in self._walk(match):
1036 1036 if fn in fset:
1037 1037 # specified pattern is the exact name
1038 1038 fset.remove(fn)
1039 1039 yield fn
1040 1040
1041 1041 # for dirstate.walk, files=['.'] means "walk the whole tree".
1042 1042 # follow that here, too
1043 1043 fset.discard('.')
1044 1044
1045 1045 for fn in sorted(fset):
1046 1046 if not self.hasdir(fn):
1047 1047 match.bad(fn, None)
1048 1048
1049 1049 def _walk(self, match):
1050 1050 '''Recursively generates matching file names for walk().'''
1051 1051 visit = match.visitchildrenset(self._dir[:-1] or '.')
1052 1052 if not visit:
1053 1053 return
1054 1054
1055 1055 # yield this dir's files and walk its submanifests
1056 1056 self._load()
1057 1057 visit = self._loadchildrensetlazy(visit)
1058 1058 for p in sorted(list(self._dirs) + list(self._files)):
1059 1059 if p in self._files:
1060 1060 fullp = self._subpath(p)
1061 1061 if match(fullp):
1062 1062 yield fullp
1063 1063 else:
1064 1064 if not visit or p[:-1] in visit:
1065 1065 for f in self._dirs[p]._walk(match):
1066 1066 yield f
1067 1067
1068 1068 def matches(self, match):
1069 1069 '''generate a new manifest filtered by the match argument'''
1070 1070 if match.always():
1071 1071 return self.copy()
1072 1072
1073 1073 return self._matches(match)
1074 1074
1075 1075 def _matches(self, match):
1076 1076 '''recursively generate a new manifest filtered by the match argument.
1077 1077 '''
1078 1078
1079 1079 visit = match.visitchildrenset(self._dir[:-1] or '.')
1080 1080 if visit == 'all':
1081 1081 return self.copy()
1082 1082 ret = treemanifest(self._dir)
1083 1083 if not visit:
1084 1084 return ret
1085 1085
1086 1086 self._load()
1087 1087 for fn in self._files:
1088 1088 # While visitchildrenset *usually* lists only subdirs, this is
1089 1089 # actually up to the matcher and may have some files in the set().
1090 1090 # If visit == 'this', we should obviously look at the files in this
1091 1091 # directory; if visit is a set, and fn is in it, we should inspect
1092 1092 # fn (but no need to inspect things not in the set).
1093 1093 if visit != 'this' and fn not in visit:
1094 1094 continue
1095 1095 fullp = self._subpath(fn)
1096 1096 # visitchildrenset isn't perfect, we still need to call the regular
1097 1097 # matcher code to further filter results.
1098 1098 if not match(fullp):
1099 1099 continue
1100 1100 ret._files[fn] = self._files[fn]
1101 1101 if fn in self._flags:
1102 1102 ret._flags[fn] = self._flags[fn]
1103 1103
1104 1104 visit = self._loadchildrensetlazy(visit)
1105 1105 for dir, subm in self._dirs.iteritems():
1106 1106 if visit and dir[:-1] not in visit:
1107 1107 continue
1108 1108 m = subm._matches(match)
1109 1109 if not m._isempty():
1110 1110 ret._dirs[dir] = m
1111 1111
1112 1112 if not ret._isempty():
1113 1113 ret._dirty = True
1114 1114 return ret
1115 1115
1116 1116 def diff(self, m2, match=None, clean=False):
1117 1117 '''Finds changes between the current manifest and m2.
1118 1118
1119 1119 Args:
1120 1120 m2: the manifest to which this manifest should be compared.
1121 1121 clean: if true, include files unchanged between these manifests
1122 1122 with a None value in the returned dictionary.
1123 1123
1124 1124 The result is returned as a dict with filename as key and
1125 1125 values of the form ((n1,fl1),(n2,fl2)), where n1/n2 is the
1126 1126 nodeid in the current/other manifest and fl1/fl2 is the flag
1127 1127 in the current/other manifest. Where the file does not exist,
1128 1128 the nodeid will be None and the flags will be the empty
1129 1129 string.
1130 1130 '''
1131 1131 if match and not match.always():
1132 1132 m1 = self.matches(match)
1133 1133 m2 = m2.matches(match)
1134 1134 return m1.diff(m2, clean=clean)
1135 1135 result = {}
1136 1136 emptytree = treemanifest()
1137 1137
1138 1138 def _iterativediff(t1, t2, stack):
1139 1139 """compares two tree manifests and append new tree-manifests which
1140 1140 needs to be compared to stack"""
1141 1141 if t1._node == t2._node and not t1._dirty and not t2._dirty:
1142 1142 return
1143 1143 t1._load()
1144 1144 t2._load()
1145 1145 self._loaddifflazy(t1, t2)
1146 1146
1147 1147 for d, m1 in t1._dirs.iteritems():
1148 1148 m2 = t2._dirs.get(d, emptytree)
1149 1149 stack.append((m1, m2))
1150 1150
1151 1151 for d, m2 in t2._dirs.iteritems():
1152 1152 if d not in t1._dirs:
1153 1153 stack.append((emptytree, m2))
1154 1154
1155 1155 for fn, n1 in t1._files.iteritems():
1156 1156 fl1 = t1._flags.get(fn, '')
1157 1157 n2 = t2._files.get(fn, None)
1158 1158 fl2 = t2._flags.get(fn, '')
1159 1159 if n1 != n2 or fl1 != fl2:
1160 1160 result[t1._subpath(fn)] = ((n1, fl1), (n2, fl2))
1161 1161 elif clean:
1162 1162 result[t1._subpath(fn)] = None
1163 1163
1164 1164 for fn, n2 in t2._files.iteritems():
1165 1165 if fn not in t1._files:
1166 1166 fl2 = t2._flags.get(fn, '')
1167 1167 result[t2._subpath(fn)] = ((None, ''), (n2, fl2))
1168 1168
1169 1169 stackls = []
1170 1170 _iterativediff(self, m2, stackls)
1171 1171 while stackls:
1172 1172 t1, t2 = stackls.pop()
1173 1173 # stackls is populated in the function call
1174 1174 _iterativediff(t1, t2, stackls)
1175 1175 return result
1176 1176
1177 1177 def unmodifiedsince(self, m2):
1178 1178 return not self._dirty and not m2._dirty and self._node == m2._node
1179 1179
1180 1180 def parse(self, text, readsubtree):
1181 1181 selflazy = self._lazydirs
1182 1182 subpath = self._subpath
1183 1183 for f, n, fl in _parse(text):
1184 1184 if fl == 't':
1185 1185 f = f + '/'
1186 1186 # False below means "doesn't need to be copied" and can use the
1187 1187 # cached value from readsubtree directly.
1188 1188 selflazy[f] = (subpath(f), n, readsubtree, False)
1189 1189 elif '/' in f:
1190 1190 # This is a flat manifest, so use __setitem__ and setflag rather
1191 1191 # than assigning directly to _files and _flags, so we can
1192 1192 # assign a path in a subdirectory, and to mark dirty (compared
1193 1193 # to nullid).
1194 1194 self[f] = n
1195 1195 if fl:
1196 1196 self.setflag(f, fl)
1197 1197 else:
1198 1198 # Assigning to _files and _flags avoids marking as dirty,
1199 1199 # and should be a little faster.
1200 1200 self._files[f] = n
1201 1201 if fl:
1202 1202 self._flags[f] = fl
1203 1203
1204 1204 def text(self):
1205 1205 """Get the full data of this manifest as a bytestring."""
1206 1206 self._load()
1207 1207 return _text(self.iterentries())
1208 1208
1209 1209 def dirtext(self):
1210 1210 """Get the full data of this directory as a bytestring. Make sure that
1211 1211 any submanifests have been written first, so their nodeids are correct.
1212 1212 """
1213 1213 self._load()
1214 1214 flags = self.flags
1215 1215 lazydirs = [(d[:-1], v[1], 't') for d, v in self._lazydirs.iteritems()]
1216 1216 dirs = [(d[:-1], self._dirs[d]._node, 't') for d in self._dirs]
1217 1217 files = [(f, self._files[f], flags(f)) for f in self._files]
1218 1218 return _text(sorted(dirs + files + lazydirs))
1219 1219
1220 1220 def read(self, gettext, readsubtree):
1221 1221 def _load_for_read(s):
1222 1222 s.parse(gettext(), readsubtree)
1223 1223 s._dirty = False
1224 1224 self._loadfunc = _load_for_read
1225 1225
1226 1226 def writesubtrees(self, m1, m2, writesubtree, match):
1227 1227 self._load() # for consistency; should never have any effect here
1228 1228 m1._load()
1229 1229 m2._load()
1230 1230 emptytree = treemanifest()
1231 1231 def getnode(m, d):
1232 1232 ld = m._lazydirs.get(d)
1233 1233 if ld:
1234 1234 return ld[1]
1235 1235 return m._dirs.get(d, emptytree)._node
1236 1236
1237 1237 # let's skip investigating things that `match` says we do not need.
1238 1238 visit = match.visitchildrenset(self._dir[:-1] or '.')
1239 1239 visit = self._loadchildrensetlazy(visit)
1240 1240 if visit == 'this' or visit == 'all':
1241 1241 visit = None
1242 1242 for d, subm in self._dirs.iteritems():
1243 1243 if visit and d[:-1] not in visit:
1244 1244 continue
1245 1245 subp1 = getnode(m1, d)
1246 1246 subp2 = getnode(m2, d)
1247 1247 if subp1 == nullid:
1248 1248 subp1, subp2 = subp2, subp1
1249 1249 writesubtree(subm, subp1, subp2, match)
1250 1250
1251 1251 def walksubtrees(self, matcher=None):
1252 1252 """Returns an iterator of the subtrees of this manifest, including this
1253 1253 manifest itself.
1254 1254
1255 1255 If `matcher` is provided, it only returns subtrees that match.
1256 1256 """
1257 1257 if matcher and not matcher.visitdir(self._dir[:-1] or '.'):
1258 1258 return
1259 1259 if not matcher or matcher(self._dir[:-1]):
1260 1260 yield self
1261 1261
1262 1262 self._load()
1263 1263 # OPT: use visitchildrenset to avoid loading everything.
1264 1264 self._loadalllazy()
1265 1265 for d, subm in self._dirs.iteritems():
1266 1266 for subtree in subm.walksubtrees(matcher=matcher):
1267 1267 yield subtree
1268 1268
1269 1269 class manifestfulltextcache(util.lrucachedict):
1270 1270 """File-backed LRU cache for the manifest cache
1271 1271
1272 1272 File consists of entries, up to EOF:
1273 1273
1274 1274 - 20 bytes node, 4 bytes length, <length> manifest data
1275 1275
1276 1276 These are written in reverse cache order (oldest to newest).
1277 1277
1278 1278 """
1279 1279
1280 1280 _file = 'manifestfulltextcache'
1281 1281
1282 1282 def __init__(self, max):
1283 1283 super(manifestfulltextcache, self).__init__(max)
1284 1284 self._dirty = False
1285 1285 self._read = False
1286 1286 self._opener = None
1287 1287
1288 1288 def read(self):
1289 1289 if self._read or self._opener is None:
1290 1290 return
1291 1291
1292 1292 try:
1293 1293 with self._opener(self._file) as fp:
1294 1294 set = super(manifestfulltextcache, self).__setitem__
1295 1295 # ignore trailing data, this is a cache, corruption is skipped
1296 1296 while True:
1297 1297 node = fp.read(20)
1298 1298 if len(node) < 20:
1299 1299 break
1300 1300 try:
1301 1301 size = struct.unpack('>L', fp.read(4))[0]
1302 1302 except struct.error:
1303 1303 break
1304 1304 value = bytearray(fp.read(size))
1305 1305 if len(value) != size:
1306 1306 break
1307 1307 set(node, value)
1308 1308 except IOError:
1309 1309 # the file is allowed to be missing
1310 1310 pass
1311 1311
1312 1312 self._read = True
1313 1313 self._dirty = False
1314 1314
1315 1315 def write(self):
1316 1316 if not self._dirty or self._opener is None:
1317 1317 return
1318 1318 # rotate backwards to the first used node
1319 1319 with self._opener(self._file, 'w', atomictemp=True, checkambig=True
1320 1320 ) as fp:
1321 1321 node = self._head.prev
1322 1322 while True:
1323 1323 if node.key in self._cache:
1324 1324 fp.write(node.key)
1325 1325 fp.write(struct.pack('>L', len(node.value)))
1326 1326 fp.write(node.value)
1327 1327 if node is self._head:
1328 1328 break
1329 1329 node = node.prev
1330 1330
1331 1331 def __len__(self):
1332 1332 if not self._read:
1333 1333 self.read()
1334 1334 return super(manifestfulltextcache, self).__len__()
1335 1335
1336 1336 def __contains__(self, k):
1337 1337 if not self._read:
1338 1338 self.read()
1339 1339 return super(manifestfulltextcache, self).__contains__(k)
1340 1340
1341 1341 def __iter__(self):
1342 1342 if not self._read:
1343 1343 self.read()
1344 1344 return super(manifestfulltextcache, self).__iter__()
1345 1345
1346 1346 def __getitem__(self, k):
1347 1347 if not self._read:
1348 1348 self.read()
1349 1349 # the cache lru order can change on read
1350 1350 setdirty = self._cache.get(k) is not self._head
1351 1351 value = super(manifestfulltextcache, self).__getitem__(k)
1352 1352 if setdirty:
1353 1353 self._dirty = True
1354 1354 return value
1355 1355
1356 1356 def __setitem__(self, k, v):
1357 1357 if not self._read:
1358 1358 self.read()
1359 1359 super(manifestfulltextcache, self).__setitem__(k, v)
1360 1360 self._dirty = True
1361 1361
1362 1362 def __delitem__(self, k):
1363 1363 if not self._read:
1364 1364 self.read()
1365 1365 super(manifestfulltextcache, self).__delitem__(k)
1366 1366 self._dirty = True
1367 1367
1368 1368 def get(self, k, default=None):
1369 1369 if not self._read:
1370 1370 self.read()
1371 1371 return super(manifestfulltextcache, self).get(k, default=default)
1372 1372
1373 1373 def clear(self, clear_persisted_data=False):
1374 1374 super(manifestfulltextcache, self).clear()
1375 1375 if clear_persisted_data:
1376 1376 self._dirty = True
1377 1377 self.write()
1378 1378 self._read = False
1379 1379
1380 1380 @interfaceutil.implementer(repository.imanifeststorage)
1381 1381 class manifestrevlog(object):
1382 1382 '''A revlog that stores manifest texts. This is responsible for caching the
1383 1383 full-text manifest contents.
1384 1384 '''
1385 1385 def __init__(self, opener, tree='', dirlogcache=None, indexfile=None,
1386 1386 treemanifest=False):
1387 1387 """Constructs a new manifest revlog
1388 1388
1389 1389 `indexfile` - used by extensions to have two manifests at once, like
1390 1390 when transitioning between flatmanifeset and treemanifests.
1391 1391
1392 1392 `treemanifest` - used to indicate this is a tree manifest revlog. Opener
1393 1393 options can also be used to make this a tree manifest revlog. The opener
1394 1394 option takes precedence, so if it is set to True, we ignore whatever
1395 1395 value is passed in to the constructor.
1396 1396 """
1397 1397 # During normal operations, we expect to deal with not more than four
1398 1398 # revs at a time (such as during commit --amend). When rebasing large
1399 1399 # stacks of commits, the number can go up, hence the config knob below.
1400 1400 cachesize = 4
1401 1401 optiontreemanifest = False
1402 1402 opts = getattr(opener, 'options', None)
1403 1403 if opts is not None:
1404 1404 cachesize = opts.get('manifestcachesize', cachesize)
1405 1405 optiontreemanifest = opts.get('treemanifest', False)
1406 1406
1407 1407 self._treeondisk = optiontreemanifest or treemanifest
1408 1408
1409 1409 self._fulltextcache = manifestfulltextcache(cachesize)
1410 1410
1411 1411 if tree:
1412 1412 assert self._treeondisk, 'opts is %r' % opts
1413 1413
1414 1414 if indexfile is None:
1415 1415 indexfile = '00manifest.i'
1416 1416 if tree:
1417 1417 indexfile = "meta/" + tree + indexfile
1418 1418
1419 1419 self.tree = tree
1420 1420
1421 1421 # The dirlogcache is kept on the root manifest log
1422 1422 if tree:
1423 1423 self._dirlogcache = dirlogcache
1424 1424 else:
1425 1425 self._dirlogcache = {'': self}
1426 1426
1427 1427 self._revlog = revlog.revlog(opener, indexfile,
1428 1428 # only root indexfile is cached
1429 1429 checkambig=not bool(tree),
1430 1430 mmaplargeindex=True)
1431 1431
1432 1432 self.index = self._revlog.index
1433 1433 self.version = self._revlog.version
1434 1434 self._generaldelta = self._revlog._generaldelta
1435 1435
1436 1436 def _setupmanifestcachehooks(self, repo):
1437 1437 """Persist the manifestfulltextcache on lock release"""
1438 1438 if not util.safehasattr(repo, '_wlockref'):
1439 1439 return
1440 1440
1441 self._fulltextcache._opener = repo.cachevfs
1441 self._fulltextcache._opener = repo.wcachevfs
1442 1442 if repo._currentlock(repo._wlockref) is None:
1443 1443 return
1444 1444
1445 1445 reporef = weakref.ref(repo)
1446 1446 manifestrevlogref = weakref.ref(self)
1447 1447
1448 1448 def persistmanifestcache():
1449 1449 repo = reporef()
1450 1450 self = manifestrevlogref()
1451 1451 if repo is None or self is None:
1452 1452 return
1453 1453 if repo.manifestlog.getstorage(b'') is not self:
1454 1454 # there's a different manifest in play now, abort
1455 1455 return
1456 1456 self._fulltextcache.write()
1457 1457
1458 1458 repo._afterlock(persistmanifestcache)
1459 1459
1460 1460 @property
1461 1461 def fulltextcache(self):
1462 1462 return self._fulltextcache
1463 1463
1464 1464 def clearcaches(self, clear_persisted_data=False):
1465 1465 self._revlog.clearcaches()
1466 1466 self._fulltextcache.clear(clear_persisted_data=clear_persisted_data)
1467 1467 self._dirlogcache = {self.tree: self}
1468 1468
1469 1469 def dirlog(self, d):
1470 1470 if d:
1471 1471 assert self._treeondisk
1472 1472 if d not in self._dirlogcache:
1473 1473 mfrevlog = manifestrevlog(self.opener, d,
1474 1474 self._dirlogcache,
1475 1475 treemanifest=self._treeondisk)
1476 1476 self._dirlogcache[d] = mfrevlog
1477 1477 return self._dirlogcache[d]
1478 1478
1479 1479 def add(self, m, transaction, link, p1, p2, added, removed, readtree=None,
1480 1480 match=None):
1481 1481 if p1 in self.fulltextcache and util.safehasattr(m, 'fastdelta'):
1482 1482 # If our first parent is in the manifest cache, we can
1483 1483 # compute a delta here using properties we know about the
1484 1484 # manifest up-front, which may save time later for the
1485 1485 # revlog layer.
1486 1486
1487 1487 _checkforbidden(added)
1488 1488 # combine the changed lists into one sorted iterator
1489 1489 work = heapq.merge([(x, False) for x in added],
1490 1490 [(x, True) for x in removed])
1491 1491
1492 1492 arraytext, deltatext = m.fastdelta(self.fulltextcache[p1], work)
1493 1493 cachedelta = self._revlog.rev(p1), deltatext
1494 1494 text = util.buffer(arraytext)
1495 1495 n = self._revlog.addrevision(text, transaction, link, p1, p2,
1496 1496 cachedelta)
1497 1497 else:
1498 1498 # The first parent manifest isn't already loaded, so we'll
1499 1499 # just encode a fulltext of the manifest and pass that
1500 1500 # through to the revlog layer, and let it handle the delta
1501 1501 # process.
1502 1502 if self._treeondisk:
1503 1503 assert readtree, "readtree must be set for treemanifest writes"
1504 1504 assert match, "match must be specified for treemanifest writes"
1505 1505 m1 = readtree(self.tree, p1)
1506 1506 m2 = readtree(self.tree, p2)
1507 1507 n = self._addtree(m, transaction, link, m1, m2, readtree,
1508 1508 match=match)
1509 1509 arraytext = None
1510 1510 else:
1511 1511 text = m.text()
1512 1512 n = self._revlog.addrevision(text, transaction, link, p1, p2)
1513 1513 arraytext = bytearray(text)
1514 1514
1515 1515 if arraytext is not None:
1516 1516 self.fulltextcache[n] = arraytext
1517 1517
1518 1518 return n
1519 1519
1520 1520 def _addtree(self, m, transaction, link, m1, m2, readtree, match):
1521 1521 # If the manifest is unchanged compared to one parent,
1522 1522 # don't write a new revision
1523 1523 if self.tree != '' and (m.unmodifiedsince(m1) or m.unmodifiedsince(
1524 1524 m2)):
1525 1525 return m.node()
1526 1526 def writesubtree(subm, subp1, subp2, match):
1527 1527 sublog = self.dirlog(subm.dir())
1528 1528 sublog.add(subm, transaction, link, subp1, subp2, None, None,
1529 1529 readtree=readtree, match=match)
1530 1530 m.writesubtrees(m1, m2, writesubtree, match)
1531 1531 text = m.dirtext()
1532 1532 n = None
1533 1533 if self.tree != '':
1534 1534 # Double-check whether contents are unchanged to one parent
1535 1535 if text == m1.dirtext():
1536 1536 n = m1.node()
1537 1537 elif text == m2.dirtext():
1538 1538 n = m2.node()
1539 1539
1540 1540 if not n:
1541 1541 n = self._revlog.addrevision(text, transaction, link, m1.node(),
1542 1542 m2.node())
1543 1543
1544 1544 # Save nodeid so parent manifest can calculate its nodeid
1545 1545 m.setnode(n)
1546 1546 return n
1547 1547
1548 1548 def __len__(self):
1549 1549 return len(self._revlog)
1550 1550
1551 1551 def __iter__(self):
1552 1552 return self._revlog.__iter__()
1553 1553
1554 1554 def rev(self, node):
1555 1555 return self._revlog.rev(node)
1556 1556
1557 1557 def node(self, rev):
1558 1558 return self._revlog.node(rev)
1559 1559
1560 1560 def lookup(self, value):
1561 1561 return self._revlog.lookup(value)
1562 1562
1563 1563 def parentrevs(self, rev):
1564 1564 return self._revlog.parentrevs(rev)
1565 1565
1566 1566 def parents(self, node):
1567 1567 return self._revlog.parents(node)
1568 1568
1569 1569 def linkrev(self, rev):
1570 1570 return self._revlog.linkrev(rev)
1571 1571
1572 1572 def checksize(self):
1573 1573 return self._revlog.checksize()
1574 1574
1575 1575 def revision(self, node, _df=None, raw=False):
1576 1576 return self._revlog.revision(node, _df=_df, raw=raw)
1577 1577
1578 1578 def revdiff(self, rev1, rev2):
1579 1579 return self._revlog.revdiff(rev1, rev2)
1580 1580
1581 1581 def cmp(self, node, text):
1582 1582 return self._revlog.cmp(node, text)
1583 1583
1584 1584 def deltaparent(self, rev):
1585 1585 return self._revlog.deltaparent(rev)
1586 1586
1587 1587 def emitrevisions(self, nodes, nodesorder=None,
1588 1588 revisiondata=False, assumehaveparentrevisions=False,
1589 1589 deltamode=repository.CG_DELTAMODE_STD):
1590 1590 return self._revlog.emitrevisions(
1591 1591 nodes, nodesorder=nodesorder, revisiondata=revisiondata,
1592 1592 assumehaveparentrevisions=assumehaveparentrevisions,
1593 1593 deltamode=deltamode)
1594 1594
1595 1595 def addgroup(self, deltas, linkmapper, transaction, addrevisioncb=None):
1596 1596 return self._revlog.addgroup(deltas, linkmapper, transaction,
1597 1597 addrevisioncb=addrevisioncb)
1598 1598
1599 1599 def rawsize(self, rev):
1600 1600 return self._revlog.rawsize(rev)
1601 1601
1602 1602 def getstrippoint(self, minlink):
1603 1603 return self._revlog.getstrippoint(minlink)
1604 1604
1605 1605 def strip(self, minlink, transaction):
1606 1606 return self._revlog.strip(minlink, transaction)
1607 1607
1608 1608 def files(self):
1609 1609 return self._revlog.files()
1610 1610
1611 1611 def clone(self, tr, destrevlog, **kwargs):
1612 1612 if not isinstance(destrevlog, manifestrevlog):
1613 1613 raise error.ProgrammingError('expected manifestrevlog to clone()')
1614 1614
1615 1615 return self._revlog.clone(tr, destrevlog._revlog, **kwargs)
1616 1616
1617 1617 def storageinfo(self, exclusivefiles=False, sharedfiles=False,
1618 1618 revisionscount=False, trackedsize=False,
1619 1619 storedsize=False):
1620 1620 return self._revlog.storageinfo(
1621 1621 exclusivefiles=exclusivefiles, sharedfiles=sharedfiles,
1622 1622 revisionscount=revisionscount, trackedsize=trackedsize,
1623 1623 storedsize=storedsize)
1624 1624
1625 1625 @property
1626 1626 def indexfile(self):
1627 1627 return self._revlog.indexfile
1628 1628
1629 1629 @indexfile.setter
1630 1630 def indexfile(self, value):
1631 1631 self._revlog.indexfile = value
1632 1632
1633 1633 @property
1634 1634 def opener(self):
1635 1635 return self._revlog.opener
1636 1636
1637 1637 @opener.setter
1638 1638 def opener(self, value):
1639 1639 self._revlog.opener = value
1640 1640
1641 1641 @interfaceutil.implementer(repository.imanifestlog)
1642 1642 class manifestlog(object):
1643 1643 """A collection class representing the collection of manifest snapshots
1644 1644 referenced by commits in the repository.
1645 1645
1646 1646 In this situation, 'manifest' refers to the abstract concept of a snapshot
1647 1647 of the list of files in the given commit. Consumers of the output of this
1648 1648 class do not care about the implementation details of the actual manifests
1649 1649 they receive (i.e. tree or flat or lazily loaded, etc)."""
1650 1650 def __init__(self, opener, repo, rootstore, narrowmatch):
1651 1651 usetreemanifest = False
1652 1652 cachesize = 4
1653 1653
1654 1654 opts = getattr(opener, 'options', None)
1655 1655 if opts is not None:
1656 1656 usetreemanifest = opts.get('treemanifest', usetreemanifest)
1657 1657 cachesize = opts.get('manifestcachesize', cachesize)
1658 1658
1659 1659 self._treemanifests = usetreemanifest
1660 1660
1661 1661 self._rootstore = rootstore
1662 1662 self._rootstore._setupmanifestcachehooks(repo)
1663 1663 self._narrowmatch = narrowmatch
1664 1664
1665 1665 # A cache of the manifestctx or treemanifestctx for each directory
1666 1666 self._dirmancache = {}
1667 1667 self._dirmancache[''] = util.lrucachedict(cachesize)
1668 1668
1669 1669 self._cachesize = cachesize
1670 1670
1671 1671 def __getitem__(self, node):
1672 1672 """Retrieves the manifest instance for the given node. Throws a
1673 1673 LookupError if not found.
1674 1674 """
1675 1675 return self.get('', node)
1676 1676
1677 1677 def get(self, tree, node, verify=True):
1678 1678 """Retrieves the manifest instance for the given node. Throws a
1679 1679 LookupError if not found.
1680 1680
1681 1681 `verify` - if True an exception will be thrown if the node is not in
1682 1682 the revlog
1683 1683 """
1684 1684 if node in self._dirmancache.get(tree, ()):
1685 1685 return self._dirmancache[tree][node]
1686 1686
1687 1687 if not self._narrowmatch.always():
1688 1688 if not self._narrowmatch.visitdir(tree[:-1] or '.'):
1689 1689 return excludeddirmanifestctx(tree, node)
1690 1690 if tree:
1691 1691 if self._rootstore._treeondisk:
1692 1692 if verify:
1693 1693 # Side-effect is LookupError is raised if node doesn't
1694 1694 # exist.
1695 1695 self.getstorage(tree).rev(node)
1696 1696
1697 1697 m = treemanifestctx(self, tree, node)
1698 1698 else:
1699 1699 raise error.Abort(
1700 1700 _("cannot ask for manifest directory '%s' in a flat "
1701 1701 "manifest") % tree)
1702 1702 else:
1703 1703 if verify:
1704 1704 # Side-effect is LookupError is raised if node doesn't exist.
1705 1705 self._rootstore.rev(node)
1706 1706
1707 1707 if self._treemanifests:
1708 1708 m = treemanifestctx(self, '', node)
1709 1709 else:
1710 1710 m = manifestctx(self, node)
1711 1711
1712 1712 if node != nullid:
1713 1713 mancache = self._dirmancache.get(tree)
1714 1714 if not mancache:
1715 1715 mancache = util.lrucachedict(self._cachesize)
1716 1716 self._dirmancache[tree] = mancache
1717 1717 mancache[node] = m
1718 1718 return m
1719 1719
1720 1720 def getstorage(self, tree):
1721 1721 return self._rootstore.dirlog(tree)
1722 1722
1723 1723 def clearcaches(self, clear_persisted_data=False):
1724 1724 self._dirmancache.clear()
1725 1725 self._rootstore.clearcaches(clear_persisted_data=clear_persisted_data)
1726 1726
1727 1727 def rev(self, node):
1728 1728 return self._rootstore.rev(node)
1729 1729
1730 1730 @interfaceutil.implementer(repository.imanifestrevisionwritable)
1731 1731 class memmanifestctx(object):
1732 1732 def __init__(self, manifestlog):
1733 1733 self._manifestlog = manifestlog
1734 1734 self._manifestdict = manifestdict()
1735 1735
1736 1736 def _storage(self):
1737 1737 return self._manifestlog.getstorage(b'')
1738 1738
1739 1739 def new(self):
1740 1740 return memmanifestctx(self._manifestlog)
1741 1741
1742 1742 def copy(self):
1743 1743 memmf = memmanifestctx(self._manifestlog)
1744 1744 memmf._manifestdict = self.read().copy()
1745 1745 return memmf
1746 1746
1747 1747 def read(self):
1748 1748 return self._manifestdict
1749 1749
1750 1750 def write(self, transaction, link, p1, p2, added, removed, match=None):
1751 1751 return self._storage().add(self._manifestdict, transaction, link,
1752 1752 p1, p2, added, removed, match=match)
1753 1753
1754 1754 @interfaceutil.implementer(repository.imanifestrevisionstored)
1755 1755 class manifestctx(object):
1756 1756 """A class representing a single revision of a manifest, including its
1757 1757 contents, its parent revs, and its linkrev.
1758 1758 """
1759 1759 def __init__(self, manifestlog, node):
1760 1760 self._manifestlog = manifestlog
1761 1761 self._data = None
1762 1762
1763 1763 self._node = node
1764 1764
1765 1765 # TODO: We eventually want p1, p2, and linkrev exposed on this class,
1766 1766 # but let's add it later when something needs it and we can load it
1767 1767 # lazily.
1768 1768 #self.p1, self.p2 = store.parents(node)
1769 1769 #rev = store.rev(node)
1770 1770 #self.linkrev = store.linkrev(rev)
1771 1771
1772 1772 def _storage(self):
1773 1773 return self._manifestlog.getstorage(b'')
1774 1774
1775 1775 def node(self):
1776 1776 return self._node
1777 1777
1778 1778 def new(self):
1779 1779 return memmanifestctx(self._manifestlog)
1780 1780
1781 1781 def copy(self):
1782 1782 memmf = memmanifestctx(self._manifestlog)
1783 1783 memmf._manifestdict = self.read().copy()
1784 1784 return memmf
1785 1785
1786 1786 @propertycache
1787 1787 def parents(self):
1788 1788 return self._storage().parents(self._node)
1789 1789
1790 1790 def read(self):
1791 1791 if self._data is None:
1792 1792 if self._node == nullid:
1793 1793 self._data = manifestdict()
1794 1794 else:
1795 1795 store = self._storage()
1796 1796 if self._node in store.fulltextcache:
1797 1797 text = pycompat.bytestr(store.fulltextcache[self._node])
1798 1798 else:
1799 1799 text = store.revision(self._node)
1800 1800 arraytext = bytearray(text)
1801 1801 store.fulltextcache[self._node] = arraytext
1802 1802 self._data = manifestdict(text)
1803 1803 return self._data
1804 1804
1805 1805 def readfast(self, shallow=False):
1806 1806 '''Calls either readdelta or read, based on which would be less work.
1807 1807 readdelta is called if the delta is against the p1, and therefore can be
1808 1808 read quickly.
1809 1809
1810 1810 If `shallow` is True, nothing changes since this is a flat manifest.
1811 1811 '''
1812 1812 store = self._storage()
1813 1813 r = store.rev(self._node)
1814 1814 deltaparent = store.deltaparent(r)
1815 1815 if deltaparent != nullrev and deltaparent in store.parentrevs(r):
1816 1816 return self.readdelta()
1817 1817 return self.read()
1818 1818
1819 1819 def readdelta(self, shallow=False):
1820 1820 '''Returns a manifest containing just the entries that are present
1821 1821 in this manifest, but not in its p1 manifest. This is efficient to read
1822 1822 if the revlog delta is already p1.
1823 1823
1824 1824 Changing the value of `shallow` has no effect on flat manifests.
1825 1825 '''
1826 1826 store = self._storage()
1827 1827 r = store.rev(self._node)
1828 1828 d = mdiff.patchtext(store.revdiff(store.deltaparent(r), r))
1829 1829 return manifestdict(d)
1830 1830
1831 1831 def find(self, key):
1832 1832 return self.read().find(key)
1833 1833
1834 1834 @interfaceutil.implementer(repository.imanifestrevisionwritable)
1835 1835 class memtreemanifestctx(object):
1836 1836 def __init__(self, manifestlog, dir=''):
1837 1837 self._manifestlog = manifestlog
1838 1838 self._dir = dir
1839 1839 self._treemanifest = treemanifest()
1840 1840
1841 1841 def _storage(self):
1842 1842 return self._manifestlog.getstorage(b'')
1843 1843
1844 1844 def new(self, dir=''):
1845 1845 return memtreemanifestctx(self._manifestlog, dir=dir)
1846 1846
1847 1847 def copy(self):
1848 1848 memmf = memtreemanifestctx(self._manifestlog, dir=self._dir)
1849 1849 memmf._treemanifest = self._treemanifest.copy()
1850 1850 return memmf
1851 1851
1852 1852 def read(self):
1853 1853 return self._treemanifest
1854 1854
1855 1855 def write(self, transaction, link, p1, p2, added, removed, match=None):
1856 1856 def readtree(dir, node):
1857 1857 return self._manifestlog.get(dir, node).read()
1858 1858 return self._storage().add(self._treemanifest, transaction, link,
1859 1859 p1, p2, added, removed, readtree=readtree,
1860 1860 match=match)
1861 1861
1862 1862 @interfaceutil.implementer(repository.imanifestrevisionstored)
1863 1863 class treemanifestctx(object):
1864 1864 def __init__(self, manifestlog, dir, node):
1865 1865 self._manifestlog = manifestlog
1866 1866 self._dir = dir
1867 1867 self._data = None
1868 1868
1869 1869 self._node = node
1870 1870
1871 1871 # TODO: Load p1/p2/linkrev lazily. They need to be lazily loaded so that
1872 1872 # we can instantiate treemanifestctx objects for directories we don't
1873 1873 # have on disk.
1874 1874 #self.p1, self.p2 = store.parents(node)
1875 1875 #rev = store.rev(node)
1876 1876 #self.linkrev = store.linkrev(rev)
1877 1877
1878 1878 def _storage(self):
1879 1879 narrowmatch = self._manifestlog._narrowmatch
1880 1880 if not narrowmatch.always():
1881 1881 if not narrowmatch.visitdir(self._dir[:-1] or '.'):
1882 1882 return excludedmanifestrevlog(self._dir)
1883 1883 return self._manifestlog.getstorage(self._dir)
1884 1884
1885 1885 def read(self):
1886 1886 if self._data is None:
1887 1887 store = self._storage()
1888 1888 if self._node == nullid:
1889 1889 self._data = treemanifest()
1890 1890 # TODO accessing non-public API
1891 1891 elif store._treeondisk:
1892 1892 m = treemanifest(dir=self._dir)
1893 1893 def gettext():
1894 1894 return store.revision(self._node)
1895 1895 def readsubtree(dir, subm):
1896 1896 # Set verify to False since we need to be able to create
1897 1897 # subtrees for trees that don't exist on disk.
1898 1898 return self._manifestlog.get(dir, subm, verify=False).read()
1899 1899 m.read(gettext, readsubtree)
1900 1900 m.setnode(self._node)
1901 1901 self._data = m
1902 1902 else:
1903 1903 if self._node in store.fulltextcache:
1904 1904 text = pycompat.bytestr(store.fulltextcache[self._node])
1905 1905 else:
1906 1906 text = store.revision(self._node)
1907 1907 arraytext = bytearray(text)
1908 1908 store.fulltextcache[self._node] = arraytext
1909 1909 self._data = treemanifest(dir=self._dir, text=text)
1910 1910
1911 1911 return self._data
1912 1912
1913 1913 def node(self):
1914 1914 return self._node
1915 1915
1916 1916 def new(self, dir=''):
1917 1917 return memtreemanifestctx(self._manifestlog, dir=dir)
1918 1918
1919 1919 def copy(self):
1920 1920 memmf = memtreemanifestctx(self._manifestlog, dir=self._dir)
1921 1921 memmf._treemanifest = self.read().copy()
1922 1922 return memmf
1923 1923
1924 1924 @propertycache
1925 1925 def parents(self):
1926 1926 return self._storage().parents(self._node)
1927 1927
1928 1928 def readdelta(self, shallow=False):
1929 1929 '''Returns a manifest containing just the entries that are present
1930 1930 in this manifest, but not in its p1 manifest. This is efficient to read
1931 1931 if the revlog delta is already p1.
1932 1932
1933 1933 If `shallow` is True, this will read the delta for this directory,
1934 1934 without recursively reading subdirectory manifests. Instead, any
1935 1935 subdirectory entry will be reported as it appears in the manifest, i.e.
1936 1936 the subdirectory will be reported among files and distinguished only by
1937 1937 its 't' flag.
1938 1938 '''
1939 1939 store = self._storage()
1940 1940 if shallow:
1941 1941 r = store.rev(self._node)
1942 1942 d = mdiff.patchtext(store.revdiff(store.deltaparent(r), r))
1943 1943 return manifestdict(d)
1944 1944 else:
1945 1945 # Need to perform a slow delta
1946 1946 r0 = store.deltaparent(store.rev(self._node))
1947 1947 m0 = self._manifestlog.get(self._dir, store.node(r0)).read()
1948 1948 m1 = self.read()
1949 1949 md = treemanifest(dir=self._dir)
1950 1950 for f, ((n0, fl0), (n1, fl1)) in m0.diff(m1).iteritems():
1951 1951 if n1:
1952 1952 md[f] = n1
1953 1953 if fl1:
1954 1954 md.setflag(f, fl1)
1955 1955 return md
1956 1956
1957 1957 def readfast(self, shallow=False):
1958 1958 '''Calls either readdelta or read, based on which would be less work.
1959 1959 readdelta is called if the delta is against the p1, and therefore can be
1960 1960 read quickly.
1961 1961
1962 1962 If `shallow` is True, it only returns the entries from this manifest,
1963 1963 and not any submanifests.
1964 1964 '''
1965 1965 store = self._storage()
1966 1966 r = store.rev(self._node)
1967 1967 deltaparent = store.deltaparent(r)
1968 1968 if (deltaparent != nullrev and
1969 1969 deltaparent in store.parentrevs(r)):
1970 1970 return self.readdelta(shallow=shallow)
1971 1971
1972 1972 if shallow:
1973 1973 return manifestdict(store.revision(self._node))
1974 1974 else:
1975 1975 return self.read()
1976 1976
1977 1977 def find(self, key):
1978 1978 return self.read().find(key)
1979 1979
1980 1980 class excludeddir(treemanifest):
1981 1981 """Stand-in for a directory that is excluded from the repository.
1982 1982
1983 1983 With narrowing active on a repository that uses treemanifests,
1984 1984 some of the directory revlogs will be excluded from the resulting
1985 1985 clone. This is a huge storage win for clients, but means we need
1986 1986 some sort of pseudo-manifest to surface to internals so we can
1987 1987 detect a merge conflict outside the narrowspec. That's what this
1988 1988 class is: it stands in for a directory whose node is known, but
1989 1989 whose contents are unknown.
1990 1990 """
1991 1991 def __init__(self, dir, node):
1992 1992 super(excludeddir, self).__init__(dir)
1993 1993 self._node = node
1994 1994 # Add an empty file, which will be included by iterators and such,
1995 1995 # appearing as the directory itself (i.e. something like "dir/")
1996 1996 self._files[''] = node
1997 1997 self._flags[''] = 't'
1998 1998
1999 1999 # Manifests outside the narrowspec should never be modified, so avoid
2000 2000 # copying. This makes a noticeable difference when there are very many
2001 2001 # directories outside the narrowspec. Also, it makes sense for the copy to
2002 2002 # be of the same type as the original, which would not happen with the
2003 2003 # super type's copy().
2004 2004 def copy(self):
2005 2005 return self
2006 2006
2007 2007 class excludeddirmanifestctx(treemanifestctx):
2008 2008 """context wrapper for excludeddir - see that docstring for rationale"""
2009 2009 def __init__(self, dir, node):
2010 2010 self._dir = dir
2011 2011 self._node = node
2012 2012
2013 2013 def read(self):
2014 2014 return excludeddir(self._dir, self._node)
2015 2015
2016 2016 def write(self, *args):
2017 2017 raise error.ProgrammingError(
2018 2018 'attempt to write manifest from excluded dir %s' % self._dir)
2019 2019
2020 2020 class excludedmanifestrevlog(manifestrevlog):
2021 2021 """Stand-in for excluded treemanifest revlogs.
2022 2022
2023 2023 When narrowing is active on a treemanifest repository, we'll have
2024 2024 references to directories we can't see due to the revlog being
2025 2025 skipped. This class exists to conform to the manifestrevlog
2026 2026 interface for those directories and proactively prevent writes to
2027 2027 outside the narrowspec.
2028 2028 """
2029 2029
2030 2030 def __init__(self, dir):
2031 2031 self._dir = dir
2032 2032
2033 2033 def __len__(self):
2034 2034 raise error.ProgrammingError(
2035 2035 'attempt to get length of excluded dir %s' % self._dir)
2036 2036
2037 2037 def rev(self, node):
2038 2038 raise error.ProgrammingError(
2039 2039 'attempt to get rev from excluded dir %s' % self._dir)
2040 2040
2041 2041 def linkrev(self, node):
2042 2042 raise error.ProgrammingError(
2043 2043 'attempt to get linkrev from excluded dir %s' % self._dir)
2044 2044
2045 2045 def node(self, rev):
2046 2046 raise error.ProgrammingError(
2047 2047 'attempt to get node from excluded dir %s' % self._dir)
2048 2048
2049 2049 def add(self, *args, **kwargs):
2050 2050 # We should never write entries in dirlogs outside the narrow clone.
2051 2051 # However, the method still gets called from writesubtree() in
2052 2052 # _addtree(), so we need to handle it. We should possibly make that
2053 2053 # avoid calling add() with a clean manifest (_dirty is always False
2054 2054 # in excludeddir instances).
2055 2055 pass
@@ -1,1294 +1,1292 b''
1 1 #testcases sshv1 sshv2
2 2
3 3 #if sshv2
4 4 $ cat >> $HGRCPATH << EOF
5 5 > [experimental]
6 6 > sshpeer.advertise-v2 = true
7 7 > sshserver.support-v2 = true
8 8 > EOF
9 9 #endif
10 10
11 11 Prepare repo a:
12 12
13 13 $ hg init a
14 14 $ cd a
15 15 $ echo a > a
16 16 $ hg add a
17 17 $ hg commit -m test
18 18 $ echo first line > b
19 19 $ hg add b
20 20
21 21 Create a non-inlined filelog:
22 22
23 23 $ "$PYTHON" -c 'open("data1", "wb").write(b"".join(b"%d\n" % x for x in range(10000)))'
24 24 $ for j in 0 1 2 3 4 5 6 7 8 9; do
25 25 > cat data1 >> b
26 26 > hg commit -m test
27 27 > done
28 28
29 29 List files in store/data (should show a 'b.d'):
30 30
31 31 #if reporevlogstore
32 32 $ for i in .hg/store/data/*; do
33 33 > echo $i
34 34 > done
35 35 .hg/store/data/a.i
36 36 .hg/store/data/b.d
37 37 .hg/store/data/b.i
38 38 #endif
39 39
40 40 Trigger branchcache creation:
41 41
42 42 $ hg branches
43 43 default 10:a7949464abda
44 44 $ ls .hg/cache
45 45 branch2-served
46 manifestfulltextcache (reporevlogstore !)
47 46 rbc-names-v1
48 47 rbc-revs-v1
49 48
50 49 Default operation:
51 50
52 51 $ hg clone . ../b
53 52 updating to branch default
54 53 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
55 54 $ cd ../b
56 55
57 56 Ensure branchcache got copied over:
58 57
59 58 $ ls .hg/cache
60 59 branch2-served
61 manifestfulltextcache
62 60 rbc-names-v1
63 61 rbc-revs-v1
64 62
65 63 $ cat a
66 64 a
67 65 $ hg verify
68 66 checking changesets
69 67 checking manifests
70 68 crosschecking files in changesets and manifests
71 69 checking files
72 70 checked 11 changesets with 11 changes to 2 files
73 71
74 72 Invalid dest '' must abort:
75 73
76 74 $ hg clone . ''
77 75 abort: empty destination path is not valid
78 76 [255]
79 77
80 78 No update, with debug option:
81 79
82 80 #if hardlink
83 81 $ hg --debug clone -U . ../c --config progress.debug=true
84 82 linking: 1 files
85 83 linking: 2 files
86 84 linking: 3 files
87 85 linking: 4 files
88 86 linking: 5 files
89 87 linking: 6 files
90 88 linking: 7 files
91 89 linking: 8 files
92 90 linked 8 files (reporevlogstore !)
93 91 linking: 9 files (reposimplestore !)
94 92 linking: 10 files (reposimplestore !)
95 93 linking: 11 files (reposimplestore !)
96 94 linking: 12 files (reposimplestore !)
97 95 linking: 13 files (reposimplestore !)
98 96 linking: 14 files (reposimplestore !)
99 97 linking: 15 files (reposimplestore !)
100 98 linking: 16 files (reposimplestore !)
101 99 linking: 17 files (reposimplestore !)
102 100 linking: 18 files (reposimplestore !)
103 101 linked 18 files (reposimplestore !)
104 102 #else
105 103 $ hg --debug clone -U . ../c --config progress.debug=true
106 104 linking: 1 files
107 105 copying: 2 files
108 106 copying: 3 files
109 107 copying: 4 files
110 108 copying: 5 files
111 109 copying: 6 files
112 110 copying: 7 files
113 111 copying: 8 files
114 112 copied 8 files (reporevlogstore !)
115 113 copying: 9 files (reposimplestore !)
116 114 copying: 10 files (reposimplestore !)
117 115 copying: 11 files (reposimplestore !)
118 116 copying: 12 files (reposimplestore !)
119 117 copying: 13 files (reposimplestore !)
120 118 copying: 14 files (reposimplestore !)
121 119 copying: 15 files (reposimplestore !)
122 120 copying: 16 files (reposimplestore !)
123 121 copying: 17 files (reposimplestore !)
124 122 copying: 18 files (reposimplestore !)
125 123 copied 18 files (reposimplestore !)
126 124 #endif
127 125 $ cd ../c
128 126
129 127 Ensure branchcache got copied over:
130 128
131 129 $ ls .hg/cache
132 130 branch2-served
133 131 rbc-names-v1
134 132 rbc-revs-v1
135 133
136 134 $ cat a 2>/dev/null || echo "a not present"
137 135 a not present
138 136 $ hg verify
139 137 checking changesets
140 138 checking manifests
141 139 crosschecking files in changesets and manifests
142 140 checking files
143 141 checked 11 changesets with 11 changes to 2 files
144 142
145 143 Default destination:
146 144
147 145 $ mkdir ../d
148 146 $ cd ../d
149 147 $ hg clone ../a
150 148 destination directory: a
151 149 updating to branch default
152 150 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
153 151 $ cd a
154 152 $ hg cat a
155 153 a
156 154 $ cd ../..
157 155
158 156 Check that we drop the 'file:' from the path before writing the .hgrc:
159 157
160 158 $ hg clone file:a e
161 159 updating to branch default
162 160 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
163 161 $ grep 'file:' e/.hg/hgrc
164 162 [1]
165 163
166 164 Check that path aliases are expanded:
167 165
168 166 $ hg clone -q -U --config 'paths.foobar=a#0' foobar f
169 167 $ hg -R f showconfig paths.default
170 168 $TESTTMP/a#0
171 169
172 170 Use --pull:
173 171
174 172 $ hg clone --pull a g
175 173 requesting all changes
176 174 adding changesets
177 175 adding manifests
178 176 adding file changes
179 177 added 11 changesets with 11 changes to 2 files
180 178 new changesets acb14030fe0a:a7949464abda
181 179 updating to branch default
182 180 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
183 181 $ hg -R g verify
184 182 checking changesets
185 183 checking manifests
186 184 crosschecking files in changesets and manifests
187 185 checking files
188 186 checked 11 changesets with 11 changes to 2 files
189 187
190 188 Invalid dest '' with --pull must abort (issue2528):
191 189
192 190 $ hg clone --pull a ''
193 191 abort: empty destination path is not valid
194 192 [255]
195 193
196 194 Clone to '.':
197 195
198 196 $ mkdir h
199 197 $ cd h
200 198 $ hg clone ../a .
201 199 updating to branch default
202 200 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
203 201 $ cd ..
204 202
205 203
206 204 *** Tests for option -u ***
207 205
208 206 Adding some more history to repo a:
209 207
210 208 $ cd a
211 209 $ hg tag ref1
212 210 $ echo the quick brown fox >a
213 211 $ hg ci -m "hacked default"
214 212 $ hg up ref1
215 213 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
216 214 $ hg branch stable
217 215 marked working directory as branch stable
218 216 (branches are permanent and global, did you want a bookmark?)
219 217 $ echo some text >a
220 218 $ hg ci -m "starting branch stable"
221 219 $ hg tag ref2
222 220 $ echo some more text >a
223 221 $ hg ci -m "another change for branch stable"
224 222 $ hg up ref2
225 223 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
226 224 $ hg parents
227 225 changeset: 13:e8ece76546a6
228 226 branch: stable
229 227 tag: ref2
230 228 parent: 10:a7949464abda
231 229 user: test
232 230 date: Thu Jan 01 00:00:00 1970 +0000
233 231 summary: starting branch stable
234 232
235 233
236 234 Repo a has two heads:
237 235
238 236 $ hg heads
239 237 changeset: 15:0aae7cf88f0d
240 238 branch: stable
241 239 tag: tip
242 240 user: test
243 241 date: Thu Jan 01 00:00:00 1970 +0000
244 242 summary: another change for branch stable
245 243
246 244 changeset: 12:f21241060d6a
247 245 user: test
248 246 date: Thu Jan 01 00:00:00 1970 +0000
249 247 summary: hacked default
250 248
251 249
252 250 $ cd ..
253 251
254 252
255 253 Testing --noupdate with --updaterev (must abort):
256 254
257 255 $ hg clone --noupdate --updaterev 1 a ua
258 256 abort: cannot specify both --noupdate and --updaterev
259 257 [255]
260 258
261 259
262 260 Testing clone -u:
263 261
264 262 $ hg clone -u . a ua
265 263 updating to branch stable
266 264 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
267 265
268 266 Repo ua has both heads:
269 267
270 268 $ hg -R ua heads
271 269 changeset: 15:0aae7cf88f0d
272 270 branch: stable
273 271 tag: tip
274 272 user: test
275 273 date: Thu Jan 01 00:00:00 1970 +0000
276 274 summary: another change for branch stable
277 275
278 276 changeset: 12:f21241060d6a
279 277 user: test
280 278 date: Thu Jan 01 00:00:00 1970 +0000
281 279 summary: hacked default
282 280
283 281
284 282 Same revision checked out in repo a and ua:
285 283
286 284 $ hg -R a parents --template "{node|short}\n"
287 285 e8ece76546a6
288 286 $ hg -R ua parents --template "{node|short}\n"
289 287 e8ece76546a6
290 288
291 289 $ rm -r ua
292 290
293 291
294 292 Testing clone --pull -u:
295 293
296 294 $ hg clone --pull -u . a ua
297 295 requesting all changes
298 296 adding changesets
299 297 adding manifests
300 298 adding file changes
301 299 added 16 changesets with 16 changes to 3 files (+1 heads)
302 300 new changesets acb14030fe0a:0aae7cf88f0d
303 301 updating to branch stable
304 302 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
305 303
306 304 Repo ua has both heads:
307 305
308 306 $ hg -R ua heads
309 307 changeset: 15:0aae7cf88f0d
310 308 branch: stable
311 309 tag: tip
312 310 user: test
313 311 date: Thu Jan 01 00:00:00 1970 +0000
314 312 summary: another change for branch stable
315 313
316 314 changeset: 12:f21241060d6a
317 315 user: test
318 316 date: Thu Jan 01 00:00:00 1970 +0000
319 317 summary: hacked default
320 318
321 319
322 320 Same revision checked out in repo a and ua:
323 321
324 322 $ hg -R a parents --template "{node|short}\n"
325 323 e8ece76546a6
326 324 $ hg -R ua parents --template "{node|short}\n"
327 325 e8ece76546a6
328 326
329 327 $ rm -r ua
330 328
331 329
332 330 Testing clone -u <branch>:
333 331
334 332 $ hg clone -u stable a ua
335 333 updating to branch stable
336 334 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
337 335
338 336 Repo ua has both heads:
339 337
340 338 $ hg -R ua heads
341 339 changeset: 15:0aae7cf88f0d
342 340 branch: stable
343 341 tag: tip
344 342 user: test
345 343 date: Thu Jan 01 00:00:00 1970 +0000
346 344 summary: another change for branch stable
347 345
348 346 changeset: 12:f21241060d6a
349 347 user: test
350 348 date: Thu Jan 01 00:00:00 1970 +0000
351 349 summary: hacked default
352 350
353 351
354 352 Branch 'stable' is checked out:
355 353
356 354 $ hg -R ua parents
357 355 changeset: 15:0aae7cf88f0d
358 356 branch: stable
359 357 tag: tip
360 358 user: test
361 359 date: Thu Jan 01 00:00:00 1970 +0000
362 360 summary: another change for branch stable
363 361
364 362
365 363 $ rm -r ua
366 364
367 365
368 366 Testing default checkout:
369 367
370 368 $ hg clone a ua
371 369 updating to branch default
372 370 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
373 371
374 372 Repo ua has both heads:
375 373
376 374 $ hg -R ua heads
377 375 changeset: 15:0aae7cf88f0d
378 376 branch: stable
379 377 tag: tip
380 378 user: test
381 379 date: Thu Jan 01 00:00:00 1970 +0000
382 380 summary: another change for branch stable
383 381
384 382 changeset: 12:f21241060d6a
385 383 user: test
386 384 date: Thu Jan 01 00:00:00 1970 +0000
387 385 summary: hacked default
388 386
389 387
390 388 Branch 'default' is checked out:
391 389
392 390 $ hg -R ua parents
393 391 changeset: 12:f21241060d6a
394 392 user: test
395 393 date: Thu Jan 01 00:00:00 1970 +0000
396 394 summary: hacked default
397 395
398 396 Test clone with a branch named "@" (issue3677)
399 397
400 398 $ hg -R ua branch @
401 399 marked working directory as branch @
402 400 $ hg -R ua commit -m 'created branch @'
403 401 $ hg clone ua atbranch
404 402 updating to branch default
405 403 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
406 404 $ hg -R atbranch heads
407 405 changeset: 16:798b6d97153e
408 406 branch: @
409 407 tag: tip
410 408 parent: 12:f21241060d6a
411 409 user: test
412 410 date: Thu Jan 01 00:00:00 1970 +0000
413 411 summary: created branch @
414 412
415 413 changeset: 15:0aae7cf88f0d
416 414 branch: stable
417 415 user: test
418 416 date: Thu Jan 01 00:00:00 1970 +0000
419 417 summary: another change for branch stable
420 418
421 419 changeset: 12:f21241060d6a
422 420 user: test
423 421 date: Thu Jan 01 00:00:00 1970 +0000
424 422 summary: hacked default
425 423
426 424 $ hg -R atbranch parents
427 425 changeset: 12:f21241060d6a
428 426 user: test
429 427 date: Thu Jan 01 00:00:00 1970 +0000
430 428 summary: hacked default
431 429
432 430
433 431 $ rm -r ua atbranch
434 432
435 433
436 434 Testing #<branch>:
437 435
438 436 $ hg clone -u . a#stable ua
439 437 adding changesets
440 438 adding manifests
441 439 adding file changes
442 440 added 14 changesets with 14 changes to 3 files
443 441 new changesets acb14030fe0a:0aae7cf88f0d
444 442 updating to branch stable
445 443 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
446 444
447 445 Repo ua has branch 'stable' and 'default' (was changed in fd511e9eeea6):
448 446
449 447 $ hg -R ua heads
450 448 changeset: 13:0aae7cf88f0d
451 449 branch: stable
452 450 tag: tip
453 451 user: test
454 452 date: Thu Jan 01 00:00:00 1970 +0000
455 453 summary: another change for branch stable
456 454
457 455 changeset: 10:a7949464abda
458 456 user: test
459 457 date: Thu Jan 01 00:00:00 1970 +0000
460 458 summary: test
461 459
462 460
463 461 Same revision checked out in repo a and ua:
464 462
465 463 $ hg -R a parents --template "{node|short}\n"
466 464 e8ece76546a6
467 465 $ hg -R ua parents --template "{node|short}\n"
468 466 e8ece76546a6
469 467
470 468 $ rm -r ua
471 469
472 470
473 471 Testing -u -r <branch>:
474 472
475 473 $ hg clone -u . -r stable a ua
476 474 adding changesets
477 475 adding manifests
478 476 adding file changes
479 477 added 14 changesets with 14 changes to 3 files
480 478 new changesets acb14030fe0a:0aae7cf88f0d
481 479 updating to branch stable
482 480 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
483 481
484 482 Repo ua has branch 'stable' and 'default' (was changed in fd511e9eeea6):
485 483
486 484 $ hg -R ua heads
487 485 changeset: 13:0aae7cf88f0d
488 486 branch: stable
489 487 tag: tip
490 488 user: test
491 489 date: Thu Jan 01 00:00:00 1970 +0000
492 490 summary: another change for branch stable
493 491
494 492 changeset: 10:a7949464abda
495 493 user: test
496 494 date: Thu Jan 01 00:00:00 1970 +0000
497 495 summary: test
498 496
499 497
500 498 Same revision checked out in repo a and ua:
501 499
502 500 $ hg -R a parents --template "{node|short}\n"
503 501 e8ece76546a6
504 502 $ hg -R ua parents --template "{node|short}\n"
505 503 e8ece76546a6
506 504
507 505 $ rm -r ua
508 506
509 507
510 508 Testing -r <branch>:
511 509
512 510 $ hg clone -r stable a ua
513 511 adding changesets
514 512 adding manifests
515 513 adding file changes
516 514 added 14 changesets with 14 changes to 3 files
517 515 new changesets acb14030fe0a:0aae7cf88f0d
518 516 updating to branch stable
519 517 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
520 518
521 519 Repo ua has branch 'stable' and 'default' (was changed in fd511e9eeea6):
522 520
523 521 $ hg -R ua heads
524 522 changeset: 13:0aae7cf88f0d
525 523 branch: stable
526 524 tag: tip
527 525 user: test
528 526 date: Thu Jan 01 00:00:00 1970 +0000
529 527 summary: another change for branch stable
530 528
531 529 changeset: 10:a7949464abda
532 530 user: test
533 531 date: Thu Jan 01 00:00:00 1970 +0000
534 532 summary: test
535 533
536 534
537 535 Branch 'stable' is checked out:
538 536
539 537 $ hg -R ua parents
540 538 changeset: 13:0aae7cf88f0d
541 539 branch: stable
542 540 tag: tip
543 541 user: test
544 542 date: Thu Jan 01 00:00:00 1970 +0000
545 543 summary: another change for branch stable
546 544
547 545
548 546 $ rm -r ua
549 547
550 548
551 549 Issue2267: Error in 1.6 hg.py: TypeError: 'NoneType' object is not
552 550 iterable in addbranchrevs()
553 551
554 552 $ cat <<EOF > simpleclone.py
555 553 > from mercurial import hg, ui as uimod
556 554 > myui = uimod.ui.load()
557 555 > repo = hg.repository(myui, b'a')
558 556 > hg.clone(myui, {}, repo, dest=b"ua")
559 557 > EOF
560 558
561 559 $ "$PYTHON" simpleclone.py
562 560 updating to branch default
563 561 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
564 562
565 563 $ rm -r ua
566 564
567 565 $ cat <<EOF > branchclone.py
568 566 > from mercurial import extensions, hg, ui as uimod
569 567 > myui = uimod.ui.load()
570 568 > extensions.loadall(myui)
571 569 > extensions.populateui(myui)
572 570 > repo = hg.repository(myui, b'a')
573 571 > hg.clone(myui, {}, repo, dest=b"ua", branch=[b"stable"])
574 572 > EOF
575 573
576 574 $ "$PYTHON" branchclone.py
577 575 adding changesets
578 576 adding manifests
579 577 adding file changes
580 578 added 14 changesets with 14 changes to 3 files
581 579 new changesets acb14030fe0a:0aae7cf88f0d
582 580 updating to branch stable
583 581 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
584 582 $ rm -r ua
585 583
586 584
587 585 Test clone with special '@' bookmark:
588 586 $ cd a
589 587 $ hg bookmark -r a7949464abda @ # branch point of stable from default
590 588 $ hg clone . ../i
591 589 updating to bookmark @
592 590 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
593 591 $ hg id -i ../i
594 592 a7949464abda
595 593 $ rm -r ../i
596 594
597 595 $ hg bookmark -f -r stable @
598 596 $ hg bookmarks
599 597 @ 15:0aae7cf88f0d
600 598 $ hg clone . ../i
601 599 updating to bookmark @ on branch stable
602 600 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
603 601 $ hg id -i ../i
604 602 0aae7cf88f0d
605 603 $ cd "$TESTTMP"
606 604
607 605
608 606 Testing failures:
609 607
610 608 $ mkdir fail
611 609 $ cd fail
612 610
613 611 No local source
614 612
615 613 $ hg clone a b
616 614 abort: repository a not found!
617 615 [255]
618 616
619 617 No remote source
620 618
621 619 #if windows
622 620 $ hg clone http://$LOCALIP:3121/a b
623 621 abort: error: * (glob)
624 622 [255]
625 623 #else
626 624 $ hg clone http://$LOCALIP:3121/a b
627 625 abort: error: *refused* (glob)
628 626 [255]
629 627 #endif
630 628 $ rm -rf b # work around bug with http clone
631 629
632 630
633 631 #if unix-permissions no-root
634 632
635 633 Inaccessible source
636 634
637 635 $ mkdir a
638 636 $ chmod 000 a
639 637 $ hg clone a b
640 638 abort: Permission denied: *$TESTTMP/fail/a/.hg* (glob)
641 639 [255]
642 640
643 641 Inaccessible destination
644 642
645 643 $ hg init b
646 644 $ cd b
647 645 $ hg clone . ../a
648 646 abort: Permission denied: *../a* (glob)
649 647 [255]
650 648 $ cd ..
651 649 $ chmod 700 a
652 650 $ rm -r a b
653 651
654 652 #endif
655 653
656 654
657 655 #if fifo
658 656
659 657 Source of wrong type
660 658
661 659 $ mkfifo a
662 660 $ hg clone a b
663 661 abort: $ENOTDIR$: *$TESTTMP/fail/a/.hg* (glob)
664 662 [255]
665 663 $ rm a
666 664
667 665 #endif
668 666
669 667 Default destination, same directory
670 668
671 669 $ hg init q
672 670 $ hg clone q
673 671 destination directory: q
674 672 abort: destination 'q' is not empty
675 673 [255]
676 674
677 675 destination directory not empty
678 676
679 677 $ mkdir a
680 678 $ echo stuff > a/a
681 679 $ hg clone q a
682 680 abort: destination 'a' is not empty
683 681 [255]
684 682
685 683
686 684 #if unix-permissions no-root
687 685
688 686 leave existing directory in place after clone failure
689 687
690 688 $ hg init c
691 689 $ cd c
692 690 $ echo c > c
693 691 $ hg commit -A -m test
694 692 adding c
695 693 $ chmod -rx .hg/store/data
696 694 $ cd ..
697 695 $ mkdir d
698 696 $ hg clone c d 2> err
699 697 [255]
700 698 $ test -d d
701 699 $ test -d d/.hg
702 700 [1]
703 701
704 702 re-enable perm to allow deletion
705 703
706 704 $ chmod +rx c/.hg/store/data
707 705
708 706 #endif
709 707
710 708 $ cd ..
711 709
712 710 Test clone from the repository in (emulated) revlog format 0 (issue4203):
713 711
714 712 $ mkdir issue4203
715 713 $ mkdir -p src/.hg
716 714 $ echo foo > src/foo
717 715 $ hg -R src add src/foo
718 716 $ hg -R src commit -m '#0'
719 717 $ hg -R src log -q
720 718 0:e1bab28bca43
721 719 $ hg -R src debugrevlog -c | egrep 'format|flags'
722 720 format : 0
723 721 flags : (none)
724 722 $ hg clone -U -q src dst
725 723 $ hg -R dst log -q
726 724 0:e1bab28bca43
727 725
728 726 Create repositories to test auto sharing functionality
729 727
730 728 $ cat >> $HGRCPATH << EOF
731 729 > [extensions]
732 730 > share=
733 731 > EOF
734 732
735 733 $ hg init empty
736 734 $ hg init source1a
737 735 $ cd source1a
738 736 $ echo initial1 > foo
739 737 $ hg -q commit -A -m initial
740 738 $ echo second > foo
741 739 $ hg commit -m second
742 740 $ cd ..
743 741
744 742 $ hg init filteredrev0
745 743 $ cd filteredrev0
746 744 $ cat >> .hg/hgrc << EOF
747 745 > [experimental]
748 746 > evolution.createmarkers=True
749 747 > EOF
750 748 $ echo initial1 > foo
751 749 $ hg -q commit -A -m initial0
752 750 $ hg -q up -r null
753 751 $ echo initial2 > foo
754 752 $ hg -q commit -A -m initial1
755 753 $ hg debugobsolete c05d5c47a5cf81401869999f3d05f7d699d2b29a e082c1832e09a7d1e78b7fd49a592d372de854c8
756 754 obsoleted 1 changesets
757 755 $ cd ..
758 756
759 757 $ hg -q clone --pull source1a source1b
760 758 $ cd source1a
761 759 $ hg bookmark bookA
762 760 $ echo 1a > foo
763 761 $ hg commit -m 1a
764 762 $ cd ../source1b
765 763 $ hg -q up -r 0
766 764 $ echo head1 > foo
767 765 $ hg commit -m head1
768 766 created new head
769 767 $ hg bookmark head1
770 768 $ hg -q up -r 0
771 769 $ echo head2 > foo
772 770 $ hg commit -m head2
773 771 created new head
774 772 $ hg bookmark head2
775 773 $ hg -q up -r 0
776 774 $ hg branch branch1
777 775 marked working directory as branch branch1
778 776 (branches are permanent and global, did you want a bookmark?)
779 777 $ echo branch1 > foo
780 778 $ hg commit -m branch1
781 779 $ hg -q up -r 0
782 780 $ hg branch branch2
783 781 marked working directory as branch branch2
784 782 $ echo branch2 > foo
785 783 $ hg commit -m branch2
786 784 $ cd ..
787 785 $ hg init source2
788 786 $ cd source2
789 787 $ echo initial2 > foo
790 788 $ hg -q commit -A -m initial2
791 789 $ echo second > foo
792 790 $ hg commit -m second
793 791 $ cd ..
794 792
795 793 Clone with auto share from an empty repo should not result in share
796 794
797 795 $ mkdir share
798 796 $ hg --config share.pool=share clone empty share-empty
799 797 (not using pooled storage: remote appears to be empty)
800 798 updating to branch default
801 799 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
802 800 $ ls share
803 801 $ test -d share-empty/.hg/store
804 802 $ test -f share-empty/.hg/sharedpath
805 803 [1]
806 804
807 805 Clone with auto share from a repo with filtered revision 0 should not result in share
808 806
809 807 $ hg --config share.pool=share clone filteredrev0 share-filtered
810 808 (not using pooled storage: unable to resolve identity of remote)
811 809 requesting all changes
812 810 adding changesets
813 811 adding manifests
814 812 adding file changes
815 813 added 1 changesets with 1 changes to 1 files
816 814 new changesets e082c1832e09
817 815 updating to branch default
818 816 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
819 817
820 818 Clone from repo with content should result in shared store being created
821 819
822 820 $ hg --config share.pool=share clone source1a share-dest1a
823 821 (sharing from new pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
824 822 requesting all changes
825 823 adding changesets
826 824 adding manifests
827 825 adding file changes
828 826 added 3 changesets with 3 changes to 1 files
829 827 new changesets b5f04eac9d8f:e5bfe23c0b47
830 828 searching for changes
831 829 no changes found
832 830 adding remote bookmark bookA
833 831 updating working directory
834 832 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
835 833
836 834 The shared repo should have been created
837 835
838 836 $ ls share
839 837 b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1
840 838
841 839 The destination should point to it
842 840
843 841 $ cat share-dest1a/.hg/sharedpath; echo
844 842 $TESTTMP/share/b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1/.hg
845 843
846 844 The destination should have bookmarks
847 845
848 846 $ hg -R share-dest1a bookmarks
849 847 bookA 2:e5bfe23c0b47
850 848
851 849 The default path should be the remote, not the share
852 850
853 851 $ hg -R share-dest1a config paths.default
854 852 $TESTTMP/source1a
855 853
856 854 Clone with existing share dir should result in pull + share
857 855
858 856 $ hg --config share.pool=share clone source1b share-dest1b
859 857 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
860 858 searching for changes
861 859 adding changesets
862 860 adding manifests
863 861 adding file changes
864 862 added 4 changesets with 4 changes to 1 files (+4 heads)
865 863 adding remote bookmark head1
866 864 adding remote bookmark head2
867 865 new changesets 4a8dc1ab4c13:6bacf4683960
868 866 updating working directory
869 867 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
870 868
871 869 $ ls share
872 870 b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1
873 871
874 872 $ cat share-dest1b/.hg/sharedpath; echo
875 873 $TESTTMP/share/b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1/.hg
876 874
877 875 We only get bookmarks from the remote, not everything in the share
878 876
879 877 $ hg -R share-dest1b bookmarks
880 878 head1 3:4a8dc1ab4c13
881 879 head2 4:99f71071f117
882 880
883 881 Default path should be source, not share.
884 882
885 883 $ hg -R share-dest1b config paths.default
886 884 $TESTTMP/source1b
887 885
888 886 Checked out revision should be head of default branch
889 887
890 888 $ hg -R share-dest1b log -r .
891 889 changeset: 4:99f71071f117
892 890 bookmark: head2
893 891 parent: 0:b5f04eac9d8f
894 892 user: test
895 893 date: Thu Jan 01 00:00:00 1970 +0000
896 894 summary: head2
897 895
898 896
899 897 Clone from unrelated repo should result in new share
900 898
901 899 $ hg --config share.pool=share clone source2 share-dest2
902 900 (sharing from new pooled repository 22aeff664783fd44c6d9b435618173c118c3448e)
903 901 requesting all changes
904 902 adding changesets
905 903 adding manifests
906 904 adding file changes
907 905 added 2 changesets with 2 changes to 1 files
908 906 new changesets 22aeff664783:63cf6c3dba4a
909 907 searching for changes
910 908 no changes found
911 909 updating working directory
912 910 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
913 911
914 912 $ ls share
915 913 22aeff664783fd44c6d9b435618173c118c3448e
916 914 b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1
917 915
918 916 remote naming mode works as advertised
919 917
920 918 $ hg --config share.pool=shareremote --config share.poolnaming=remote clone source1a share-remote1a
921 919 (sharing from new pooled repository 195bb1fcdb595c14a6c13e0269129ed78f6debde)
922 920 requesting all changes
923 921 adding changesets
924 922 adding manifests
925 923 adding file changes
926 924 added 3 changesets with 3 changes to 1 files
927 925 new changesets b5f04eac9d8f:e5bfe23c0b47
928 926 searching for changes
929 927 no changes found
930 928 adding remote bookmark bookA
931 929 updating working directory
932 930 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
933 931
934 932 $ ls shareremote
935 933 195bb1fcdb595c14a6c13e0269129ed78f6debde
936 934
937 935 $ hg --config share.pool=shareremote --config share.poolnaming=remote clone source1b share-remote1b
938 936 (sharing from new pooled repository c0d4f83847ca2a873741feb7048a45085fd47c46)
939 937 requesting all changes
940 938 adding changesets
941 939 adding manifests
942 940 adding file changes
943 941 added 6 changesets with 6 changes to 1 files (+4 heads)
944 942 new changesets b5f04eac9d8f:6bacf4683960
945 943 searching for changes
946 944 no changes found
947 945 adding remote bookmark head1
948 946 adding remote bookmark head2
949 947 updating working directory
950 948 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
951 949
952 950 $ ls shareremote
953 951 195bb1fcdb595c14a6c13e0269129ed78f6debde
954 952 c0d4f83847ca2a873741feb7048a45085fd47c46
955 953
956 954 request to clone a single revision is respected in sharing mode
957 955
958 956 $ hg --config share.pool=sharerevs clone -r 4a8dc1ab4c13 source1b share-1arev
959 957 (sharing from new pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
960 958 adding changesets
961 959 adding manifests
962 960 adding file changes
963 961 added 2 changesets with 2 changes to 1 files
964 962 new changesets b5f04eac9d8f:4a8dc1ab4c13
965 963 no changes found
966 964 adding remote bookmark head1
967 965 updating working directory
968 966 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
969 967
970 968 $ hg -R share-1arev log -G
971 969 @ changeset: 1:4a8dc1ab4c13
972 970 | bookmark: head1
973 971 | tag: tip
974 972 | user: test
975 973 | date: Thu Jan 01 00:00:00 1970 +0000
976 974 | summary: head1
977 975 |
978 976 o changeset: 0:b5f04eac9d8f
979 977 user: test
980 978 date: Thu Jan 01 00:00:00 1970 +0000
981 979 summary: initial
982 980
983 981
984 982 making another clone should only pull down requested rev
985 983
986 984 $ hg --config share.pool=sharerevs clone -r 99f71071f117 source1b share-1brev
987 985 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
988 986 searching for changes
989 987 adding changesets
990 988 adding manifests
991 989 adding file changes
992 990 added 1 changesets with 1 changes to 1 files (+1 heads)
993 991 adding remote bookmark head1
994 992 adding remote bookmark head2
995 993 new changesets 99f71071f117
996 994 updating working directory
997 995 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
998 996
999 997 $ hg -R share-1brev log -G
1000 998 @ changeset: 2:99f71071f117
1001 999 | bookmark: head2
1002 1000 | tag: tip
1003 1001 | parent: 0:b5f04eac9d8f
1004 1002 | user: test
1005 1003 | date: Thu Jan 01 00:00:00 1970 +0000
1006 1004 | summary: head2
1007 1005 |
1008 1006 | o changeset: 1:4a8dc1ab4c13
1009 1007 |/ bookmark: head1
1010 1008 | user: test
1011 1009 | date: Thu Jan 01 00:00:00 1970 +0000
1012 1010 | summary: head1
1013 1011 |
1014 1012 o changeset: 0:b5f04eac9d8f
1015 1013 user: test
1016 1014 date: Thu Jan 01 00:00:00 1970 +0000
1017 1015 summary: initial
1018 1016
1019 1017
1020 1018 Request to clone a single branch is respected in sharing mode
1021 1019
1022 1020 $ hg --config share.pool=sharebranch clone -b branch1 source1b share-1bbranch1
1023 1021 (sharing from new pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1024 1022 adding changesets
1025 1023 adding manifests
1026 1024 adding file changes
1027 1025 added 2 changesets with 2 changes to 1 files
1028 1026 new changesets b5f04eac9d8f:5f92a6c1a1b1
1029 1027 no changes found
1030 1028 updating working directory
1031 1029 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1032 1030
1033 1031 $ hg -R share-1bbranch1 log -G
1034 1032 o changeset: 1:5f92a6c1a1b1
1035 1033 | branch: branch1
1036 1034 | tag: tip
1037 1035 | user: test
1038 1036 | date: Thu Jan 01 00:00:00 1970 +0000
1039 1037 | summary: branch1
1040 1038 |
1041 1039 @ changeset: 0:b5f04eac9d8f
1042 1040 user: test
1043 1041 date: Thu Jan 01 00:00:00 1970 +0000
1044 1042 summary: initial
1045 1043
1046 1044
1047 1045 $ hg --config share.pool=sharebranch clone -b branch2 source1b share-1bbranch2
1048 1046 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1049 1047 searching for changes
1050 1048 adding changesets
1051 1049 adding manifests
1052 1050 adding file changes
1053 1051 added 1 changesets with 1 changes to 1 files (+1 heads)
1054 1052 new changesets 6bacf4683960
1055 1053 updating working directory
1056 1054 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1057 1055
1058 1056 $ hg -R share-1bbranch2 log -G
1059 1057 o changeset: 2:6bacf4683960
1060 1058 | branch: branch2
1061 1059 | tag: tip
1062 1060 | parent: 0:b5f04eac9d8f
1063 1061 | user: test
1064 1062 | date: Thu Jan 01 00:00:00 1970 +0000
1065 1063 | summary: branch2
1066 1064 |
1067 1065 | o changeset: 1:5f92a6c1a1b1
1068 1066 |/ branch: branch1
1069 1067 | user: test
1070 1068 | date: Thu Jan 01 00:00:00 1970 +0000
1071 1069 | summary: branch1
1072 1070 |
1073 1071 @ changeset: 0:b5f04eac9d8f
1074 1072 user: test
1075 1073 date: Thu Jan 01 00:00:00 1970 +0000
1076 1074 summary: initial
1077 1075
1078 1076
1079 1077 -U is respected in share clone mode
1080 1078
1081 1079 $ hg --config share.pool=share clone -U source1a share-1anowc
1082 1080 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1083 1081 searching for changes
1084 1082 no changes found
1085 1083 adding remote bookmark bookA
1086 1084
1087 1085 $ ls share-1anowc
1088 1086
1089 1087 Test that auto sharing doesn't cause failure of "hg clone local remote"
1090 1088
1091 1089 $ cd $TESTTMP
1092 1090 $ hg -R a id -r 0
1093 1091 acb14030fe0a
1094 1092 $ hg id -R remote -r 0
1095 1093 abort: repository remote not found!
1096 1094 [255]
1097 1095 $ hg --config share.pool=share -q clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" a ssh://user@dummy/remote
1098 1096 $ hg -R remote id -r 0
1099 1097 acb14030fe0a
1100 1098
1101 1099 Cloning into pooled storage doesn't race (issue5104)
1102 1100
1103 1101 $ HGPOSTLOCKDELAY=2.0 hg --config share.pool=racepool --config extensions.lockdelay=$TESTDIR/lockdelay.py clone source1a share-destrace1 > race1.log 2>&1 &
1104 1102 $ HGPRELOCKDELAY=1.0 hg --config share.pool=racepool --config extensions.lockdelay=$TESTDIR/lockdelay.py clone source1a share-destrace2 > race2.log 2>&1
1105 1103 $ wait
1106 1104
1107 1105 $ hg -R share-destrace1 log -r tip
1108 1106 changeset: 2:e5bfe23c0b47
1109 1107 bookmark: bookA
1110 1108 tag: tip
1111 1109 user: test
1112 1110 date: Thu Jan 01 00:00:00 1970 +0000
1113 1111 summary: 1a
1114 1112
1115 1113
1116 1114 $ hg -R share-destrace2 log -r tip
1117 1115 changeset: 2:e5bfe23c0b47
1118 1116 bookmark: bookA
1119 1117 tag: tip
1120 1118 user: test
1121 1119 date: Thu Jan 01 00:00:00 1970 +0000
1122 1120 summary: 1a
1123 1121
1124 1122 One repo should be new, the other should be shared from the pool. We
1125 1123 don't care which is which, so we just make sure we always print the
1126 1124 one containing "new pooled" first, then one one containing "existing
1127 1125 pooled".
1128 1126
1129 1127 $ (grep 'new pooled' race1.log > /dev/null && cat race1.log || cat race2.log) | grep -v lock
1130 1128 (sharing from new pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1131 1129 requesting all changes
1132 1130 adding changesets
1133 1131 adding manifests
1134 1132 adding file changes
1135 1133 added 3 changesets with 3 changes to 1 files
1136 1134 new changesets b5f04eac9d8f:e5bfe23c0b47
1137 1135 searching for changes
1138 1136 no changes found
1139 1137 adding remote bookmark bookA
1140 1138 updating working directory
1141 1139 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1142 1140
1143 1141 $ (grep 'existing pooled' race1.log > /dev/null && cat race1.log || cat race2.log) | grep -v lock
1144 1142 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1145 1143 searching for changes
1146 1144 no changes found
1147 1145 adding remote bookmark bookA
1148 1146 updating working directory
1149 1147 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1150 1148
1151 1149 SEC: check for unsafe ssh url
1152 1150
1153 1151 $ cat >> $HGRCPATH << EOF
1154 1152 > [ui]
1155 1153 > ssh = sh -c "read l; read l; read l"
1156 1154 > EOF
1157 1155
1158 1156 $ hg clone 'ssh://-oProxyCommand=touch${IFS}owned/path'
1159 1157 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path'
1160 1158 [255]
1161 1159 $ hg clone 'ssh://%2DoProxyCommand=touch${IFS}owned/path'
1162 1160 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path'
1163 1161 [255]
1164 1162 $ hg clone 'ssh://fakehost|touch%20owned/path'
1165 1163 abort: no suitable response from remote hg!
1166 1164 [255]
1167 1165 $ hg clone 'ssh://fakehost%7Ctouch%20owned/path'
1168 1166 abort: no suitable response from remote hg!
1169 1167 [255]
1170 1168
1171 1169 $ hg clone 'ssh://-oProxyCommand=touch owned%20foo@example.com/nonexistent/path'
1172 1170 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch owned foo@example.com/nonexistent/path'
1173 1171 [255]
1174 1172
1175 1173 #if windows
1176 1174 $ hg clone "ssh://%26touch%20owned%20/" --debug
1177 1175 running sh -c "read l; read l; read l" "&touch owned " "hg -R . serve --stdio"
1178 1176 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
1179 1177 sending hello command
1180 1178 sending between command
1181 1179 abort: no suitable response from remote hg!
1182 1180 [255]
1183 1181 $ hg clone "ssh://example.com:%26touch%20owned%20/" --debug
1184 1182 running sh -c "read l; read l; read l" -p "&touch owned " example.com "hg -R . serve --stdio"
1185 1183 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
1186 1184 sending hello command
1187 1185 sending between command
1188 1186 abort: no suitable response from remote hg!
1189 1187 [255]
1190 1188 #else
1191 1189 $ hg clone "ssh://%3btouch%20owned%20/" --debug
1192 1190 running sh -c "read l; read l; read l" ';touch owned ' 'hg -R . serve --stdio'
1193 1191 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
1194 1192 sending hello command
1195 1193 sending between command
1196 1194 abort: no suitable response from remote hg!
1197 1195 [255]
1198 1196 $ hg clone "ssh://example.com:%3btouch%20owned%20/" --debug
1199 1197 running sh -c "read l; read l; read l" -p ';touch owned ' example.com 'hg -R . serve --stdio'
1200 1198 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
1201 1199 sending hello command
1202 1200 sending between command
1203 1201 abort: no suitable response from remote hg!
1204 1202 [255]
1205 1203 #endif
1206 1204
1207 1205 $ hg clone "ssh://v-alid.example.com/" --debug
1208 1206 running sh -c "read l; read l; read l" v-alid\.example\.com ['"]hg -R \. serve --stdio['"] (re)
1209 1207 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
1210 1208 sending hello command
1211 1209 sending between command
1212 1210 abort: no suitable response from remote hg!
1213 1211 [255]
1214 1212
1215 1213 We should not have created a file named owned - if it exists, the
1216 1214 attack succeeded.
1217 1215 $ if test -f owned; then echo 'you got owned'; fi
1218 1216
1219 1217 Cloning without fsmonitor enabled does not print a warning for small repos
1220 1218
1221 1219 $ hg clone a fsmonitor-default
1222 1220 updating to bookmark @ on branch stable
1223 1221 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1224 1222
1225 1223 Lower the warning threshold to simulate a large repo
1226 1224
1227 1225 $ cat >> $HGRCPATH << EOF
1228 1226 > [fsmonitor]
1229 1227 > warn_update_file_count = 2
1230 1228 > EOF
1231 1229
1232 1230 We should see a warning about no fsmonitor on supported platforms
1233 1231
1234 1232 #if linuxormacos no-fsmonitor
1235 1233 $ hg clone a nofsmonitor
1236 1234 updating to bookmark @ on branch stable
1237 1235 (warning: large working directory being used without fsmonitor enabled; enable fsmonitor to improve performance; see "hg help -e fsmonitor")
1238 1236 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1239 1237 #else
1240 1238 $ hg clone a nofsmonitor
1241 1239 updating to bookmark @ on branch stable
1242 1240 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1243 1241 #endif
1244 1242
1245 1243 We should not see warning about fsmonitor when it is enabled
1246 1244
1247 1245 #if fsmonitor
1248 1246 $ hg clone a fsmonitor-enabled
1249 1247 updating to bookmark @ on branch stable
1250 1248 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1251 1249 #endif
1252 1250
1253 1251 We can disable the fsmonitor warning
1254 1252
1255 1253 $ hg --config fsmonitor.warn_when_unused=false clone a fsmonitor-disable-warning
1256 1254 updating to bookmark @ on branch stable
1257 1255 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1258 1256
1259 1257 Loaded fsmonitor but disabled in config should still print warning
1260 1258
1261 1259 #if linuxormacos fsmonitor
1262 1260 $ hg --config fsmonitor.mode=off clone a fsmonitor-mode-off
1263 1261 updating to bookmark @ on branch stable
1264 1262 (warning: large working directory being used without fsmonitor enabled; enable fsmonitor to improve performance; see "hg help -e fsmonitor") (fsmonitor !)
1265 1263 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1266 1264 #endif
1267 1265
1268 1266 Warning not printed if working directory isn't empty
1269 1267
1270 1268 $ hg -q clone a fsmonitor-update
1271 1269 (warning: large working directory being used without fsmonitor enabled; enable fsmonitor to improve performance; see "hg help -e fsmonitor") (?)
1272 1270 $ cd fsmonitor-update
1273 1271 $ hg up acb14030fe0a
1274 1272 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
1275 1273 (leaving bookmark @)
1276 1274 $ hg up cf0fe1914066
1277 1275 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1278 1276
1279 1277 `hg update` from null revision also prints
1280 1278
1281 1279 $ hg up null
1282 1280 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
1283 1281
1284 1282 #if linuxormacos no-fsmonitor
1285 1283 $ hg up cf0fe1914066
1286 1284 (warning: large working directory being used without fsmonitor enabled; enable fsmonitor to improve performance; see "hg help -e fsmonitor")
1287 1285 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1288 1286 #else
1289 1287 $ hg up cf0fe1914066
1290 1288 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1291 1289 #endif
1292 1290
1293 1291 $ cd ..
1294 1292
@@ -1,656 +1,655 b''
1 1 $ cat << EOF >> $HGRCPATH
2 2 > [ui]
3 3 > interactive=yes
4 4 > EOF
5 5
6 6 $ hg init debugrevlog
7 7 $ cd debugrevlog
8 8 $ echo a > a
9 9 $ hg ci -Am adda
10 10 adding a
11 11 $ hg rm .
12 12 removing a
13 13 $ hg ci -Am make-it-empty
14 14 $ hg revert --all -r 0
15 15 adding a
16 16 $ hg ci -Am make-it-full
17 17 #if reporevlogstore
18 18 $ hg debugrevlog -c
19 19 format : 1
20 20 flags : inline
21 21
22 22 revisions : 3
23 23 merges : 0 ( 0.00%)
24 24 normal : 3 (100.00%)
25 25 revisions : 3
26 26 empty : 0 ( 0.00%)
27 27 text : 0 (100.00%)
28 28 delta : 0 (100.00%)
29 29 snapshot : 3 (100.00%)
30 30 lvl-0 : 3 (100.00%)
31 31 deltas : 0 ( 0.00%)
32 32 revision size : 191
33 33 snapshot : 191 (100.00%)
34 34 lvl-0 : 191 (100.00%)
35 35 deltas : 0 ( 0.00%)
36 36
37 37 chunks : 3
38 38 0x75 (u) : 3 (100.00%)
39 39 chunks size : 191
40 40 0x75 (u) : 191 (100.00%)
41 41
42 42 avg chain length : 0
43 43 max chain length : 0
44 44 max chain reach : 67
45 45 compression ratio : 0
46 46
47 47 uncompressed data size (min/max/avg) : 57 / 66 / 62
48 48 full revision size (min/max/avg) : 58 / 67 / 63
49 49 inter-snapshot size (min/max/avg) : 0 / 0 / 0
50 50 delta size (min/max/avg) : 0 / 0 / 0
51 51 $ hg debugrevlog -m
52 52 format : 1
53 53 flags : inline, generaldelta
54 54
55 55 revisions : 3
56 56 merges : 0 ( 0.00%)
57 57 normal : 3 (100.00%)
58 58 revisions : 3
59 59 empty : 1 (33.33%)
60 60 text : 1 (100.00%)
61 61 delta : 0 ( 0.00%)
62 62 snapshot : 2 (66.67%)
63 63 lvl-0 : 2 (66.67%)
64 64 deltas : 0 ( 0.00%)
65 65 revision size : 88
66 66 snapshot : 88 (100.00%)
67 67 lvl-0 : 88 (100.00%)
68 68 deltas : 0 ( 0.00%)
69 69
70 70 chunks : 3
71 71 empty : 1 (33.33%)
72 72 0x75 (u) : 2 (66.67%)
73 73 chunks size : 88
74 74 empty : 0 ( 0.00%)
75 75 0x75 (u) : 88 (100.00%)
76 76
77 77 avg chain length : 0
78 78 max chain length : 0
79 79 max chain reach : 44
80 80 compression ratio : 0
81 81
82 82 uncompressed data size (min/max/avg) : 0 / 43 / 28
83 83 full revision size (min/max/avg) : 44 / 44 / 44
84 84 inter-snapshot size (min/max/avg) : 0 / 0 / 0
85 85 delta size (min/max/avg) : 0 / 0 / 0
86 86 $ hg debugrevlog a
87 87 format : 1
88 88 flags : inline, generaldelta
89 89
90 90 revisions : 1
91 91 merges : 0 ( 0.00%)
92 92 normal : 1 (100.00%)
93 93 revisions : 1
94 94 empty : 0 ( 0.00%)
95 95 text : 0 (100.00%)
96 96 delta : 0 (100.00%)
97 97 snapshot : 1 (100.00%)
98 98 lvl-0 : 1 (100.00%)
99 99 deltas : 0 ( 0.00%)
100 100 revision size : 3
101 101 snapshot : 3 (100.00%)
102 102 lvl-0 : 3 (100.00%)
103 103 deltas : 0 ( 0.00%)
104 104
105 105 chunks : 1
106 106 0x75 (u) : 1 (100.00%)
107 107 chunks size : 3
108 108 0x75 (u) : 3 (100.00%)
109 109
110 110 avg chain length : 0
111 111 max chain length : 0
112 112 max chain reach : 3
113 113 compression ratio : 0
114 114
115 115 uncompressed data size (min/max/avg) : 2 / 2 / 2
116 116 full revision size (min/max/avg) : 3 / 3 / 3
117 117 inter-snapshot size (min/max/avg) : 0 / 0 / 0
118 118 delta size (min/max/avg) : 0 / 0 / 0
119 119 #endif
120 120
121 121 Test debugindex, with and without the --verbose/--debug flag
122 122 $ hg debugrevlogindex a
123 123 rev linkrev nodeid p1 p2
124 124 0 0 b789fdd96dc2 000000000000 000000000000
125 125
126 126 #if no-reposimplestore
127 127 $ hg --verbose debugrevlogindex a
128 128 rev offset length linkrev nodeid p1 p2
129 129 0 0 3 0 b789fdd96dc2 000000000000 000000000000
130 130
131 131 $ hg --debug debugrevlogindex a
132 132 rev offset length linkrev nodeid p1 p2
133 133 0 0 3 0 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
134 134 #endif
135 135
136 136 $ hg debugrevlogindex -f 1 a
137 137 rev flag size link p1 p2 nodeid
138 138 0 0000 2 0 -1 -1 b789fdd96dc2
139 139
140 140 #if no-reposimplestore
141 141 $ hg --verbose debugrevlogindex -f 1 a
142 142 rev flag offset length size link p1 p2 nodeid
143 143 0 0000 0 3 2 0 -1 -1 b789fdd96dc2
144 144
145 145 $ hg --debug debugrevlogindex -f 1 a
146 146 rev flag offset length size link p1 p2 nodeid
147 147 0 0000 0 3 2 0 -1 -1 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
148 148 #endif
149 149
150 150 $ hg debugindex -c
151 151 rev linkrev nodeid p1 p2
152 152 0 0 07f494440405 000000000000 000000000000
153 153 1 1 8cccb4b5fec2 07f494440405 000000000000
154 154 2 2 b1e228c512c5 8cccb4b5fec2 000000000000
155 155 $ hg debugindex -c --debug
156 156 rev linkrev nodeid p1 p2
157 157 0 0 07f4944404050f47db2e5c5071e0e84e7a27bba9 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
158 158 1 1 8cccb4b5fec20cafeb99dd01c26d4dee8ea4388a 07f4944404050f47db2e5c5071e0e84e7a27bba9 0000000000000000000000000000000000000000
159 159 2 2 b1e228c512c5d7066d70562ed839c3323a62d6d2 8cccb4b5fec20cafeb99dd01c26d4dee8ea4388a 0000000000000000000000000000000000000000
160 160 $ hg debugindex -m
161 161 rev linkrev nodeid p1 p2
162 162 0 0 a0c8bcbbb45c 000000000000 000000000000
163 163 1 1 57faf8a737ae a0c8bcbbb45c 000000000000
164 164 2 2 a35b10320954 57faf8a737ae 000000000000
165 165 $ hg debugindex -m --debug
166 166 rev linkrev nodeid p1 p2
167 167 0 0 a0c8bcbbb45c63b90b70ad007bf38961f64f2af0 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
168 168 1 1 57faf8a737ae7faf490582941a82319ba6529dca a0c8bcbbb45c63b90b70ad007bf38961f64f2af0 0000000000000000000000000000000000000000
169 169 2 2 a35b103209548032201c16c7688cb2657f037a38 57faf8a737ae7faf490582941a82319ba6529dca 0000000000000000000000000000000000000000
170 170 $ hg debugindex a
171 171 rev linkrev nodeid p1 p2
172 172 0 0 b789fdd96dc2 000000000000 000000000000
173 173 $ hg debugindex --debug a
174 174 rev linkrev nodeid p1 p2
175 175 0 0 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
176 176
177 177 debugdelta chain basic output
178 178
179 179 #if reporevlogstore pure
180 180 $ hg debugindexstats
181 181 abort: debugindexstats only works with native code
182 182 [255]
183 183 #endif
184 184 #if reporevlogstore no-pure
185 185 $ hg debugindexstats
186 186 node trie capacity: 4
187 187 node trie count: 2
188 188 node trie depth: 1
189 189 node trie last rev scanned: -1
190 190 node trie lookups: 4
191 191 node trie misses: 1
192 192 node trie splits: 1
193 193 revs in memory: 3
194 194 #endif
195 195
196 196 #if reporevlogstore no-pure
197 197 $ hg debugdeltachain -m
198 198 rev chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio readsize largestblk rddensity srchunks
199 199 0 1 1 -1 base 44 43 44 1.02326 44 0 0.00000 44 44 1.00000 1
200 200 1 2 1 -1 base 0 0 0 0.00000 0 0 0.00000 0 0 1.00000 1
201 201 2 3 1 -1 base 44 43 44 1.02326 44 0 0.00000 44 44 1.00000 1
202 202
203 203 $ hg debugdeltachain -m -T '{rev} {chainid} {chainlen}\n'
204 204 0 1 1
205 205 1 2 1
206 206 2 3 1
207 207
208 208 $ hg debugdeltachain -m -Tjson
209 209 [
210 210 {
211 211 "chainid": 1,
212 212 "chainlen": 1,
213 213 "chainratio": 1.02325581395, (no-py3 !)
214 214 "chainratio": 1.0232558139534884, (py3 !)
215 215 "chainsize": 44,
216 216 "compsize": 44,
217 217 "deltatype": "base",
218 218 "extradist": 0,
219 219 "extraratio": 0.0,
220 220 "largestblock": 44,
221 221 "lindist": 44,
222 222 "prevrev": -1,
223 223 "readdensity": 1.0,
224 224 "readsize": 44,
225 225 "rev": 0,
226 226 "srchunks": 1,
227 227 "uncompsize": 43
228 228 },
229 229 {
230 230 "chainid": 2,
231 231 "chainlen": 1,
232 232 "chainratio": 0,
233 233 "chainsize": 0,
234 234 "compsize": 0,
235 235 "deltatype": "base",
236 236 "extradist": 0,
237 237 "extraratio": 0,
238 238 "largestblock": 0,
239 239 "lindist": 0,
240 240 "prevrev": -1,
241 241 "readdensity": 1,
242 242 "readsize": 0,
243 243 "rev": 1,
244 244 "srchunks": 1,
245 245 "uncompsize": 0
246 246 },
247 247 {
248 248 "chainid": 3,
249 249 "chainlen": 1,
250 250 "chainratio": 1.02325581395, (no-py3 !)
251 251 "chainratio": 1.0232558139534884, (py3 !)
252 252 "chainsize": 44,
253 253 "compsize": 44,
254 254 "deltatype": "base",
255 255 "extradist": 0,
256 256 "extraratio": 0.0,
257 257 "largestblock": 44,
258 258 "lindist": 44,
259 259 "prevrev": -1,
260 260 "readdensity": 1.0,
261 261 "readsize": 44,
262 262 "rev": 2,
263 263 "srchunks": 1,
264 264 "uncompsize": 43
265 265 }
266 266 ]
267 267
268 268 debugdelta chain with sparse read enabled
269 269
270 270 $ cat >> $HGRCPATH <<EOF
271 271 > [experimental]
272 272 > sparse-read = True
273 273 > EOF
274 274 $ hg debugdeltachain -m
275 275 rev chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio readsize largestblk rddensity srchunks
276 276 0 1 1 -1 base 44 43 44 1.02326 44 0 0.00000 44 44 1.00000 1
277 277 1 2 1 -1 base 0 0 0 0.00000 0 0 0.00000 0 0 1.00000 1
278 278 2 3 1 -1 base 44 43 44 1.02326 44 0 0.00000 44 44 1.00000 1
279 279
280 280 $ hg debugdeltachain -m -T '{rev} {chainid} {chainlen} {readsize} {largestblock} {readdensity}\n'
281 281 0 1 1 44 44 1.0
282 282 1 2 1 0 0 1
283 283 2 3 1 44 44 1.0
284 284
285 285 $ hg debugdeltachain -m -Tjson
286 286 [
287 287 {
288 288 "chainid": 1,
289 289 "chainlen": 1,
290 290 "chainratio": 1.02325581395, (no-py3 !)
291 291 "chainratio": 1.0232558139534884, (py3 !)
292 292 "chainsize": 44,
293 293 "compsize": 44,
294 294 "deltatype": "base",
295 295 "extradist": 0,
296 296 "extraratio": 0.0,
297 297 "largestblock": 44,
298 298 "lindist": 44,
299 299 "prevrev": -1,
300 300 "readdensity": 1.0,
301 301 "readsize": 44,
302 302 "rev": 0,
303 303 "srchunks": 1,
304 304 "uncompsize": 43
305 305 },
306 306 {
307 307 "chainid": 2,
308 308 "chainlen": 1,
309 309 "chainratio": 0,
310 310 "chainsize": 0,
311 311 "compsize": 0,
312 312 "deltatype": "base",
313 313 "extradist": 0,
314 314 "extraratio": 0,
315 315 "largestblock": 0,
316 316 "lindist": 0,
317 317 "prevrev": -1,
318 318 "readdensity": 1,
319 319 "readsize": 0,
320 320 "rev": 1,
321 321 "srchunks": 1,
322 322 "uncompsize": 0
323 323 },
324 324 {
325 325 "chainid": 3,
326 326 "chainlen": 1,
327 327 "chainratio": 1.02325581395, (no-py3 !)
328 328 "chainratio": 1.0232558139534884, (py3 !)
329 329 "chainsize": 44,
330 330 "compsize": 44,
331 331 "deltatype": "base",
332 332 "extradist": 0,
333 333 "extraratio": 0.0,
334 334 "largestblock": 44,
335 335 "lindist": 44,
336 336 "prevrev": -1,
337 337 "readdensity": 1.0,
338 338 "readsize": 44,
339 339 "rev": 2,
340 340 "srchunks": 1,
341 341 "uncompsize": 43
342 342 }
343 343 ]
344 344
345 345 $ printf "This test checks things.\n" >> a
346 346 $ hg ci -m a
347 347 $ hg branch other
348 348 marked working directory as branch other
349 349 (branches are permanent and global, did you want a bookmark?)
350 350 $ for i in `$TESTDIR/seq.py 5`; do
351 351 > printf "shorter ${i}" >> a
352 352 > hg ci -m "a other:$i"
353 353 > hg up -q default
354 354 > printf "for the branch default we want longer chains: ${i}" >> a
355 355 > hg ci -m "a default:$i"
356 356 > hg up -q other
357 357 > done
358 358 $ hg debugdeltachain a -T '{rev} {srchunks}\n' \
359 359 > --config experimental.sparse-read.density-threshold=0.50 \
360 360 > --config experimental.sparse-read.min-gap-size=0
361 361 0 1
362 362 1 1
363 363 2 1
364 364 3 1
365 365 4 1
366 366 5 1
367 367 6 1
368 368 7 1
369 369 8 1
370 370 9 1
371 371 10 2
372 372 11 1
373 373 $ hg --config extensions.strip= strip --no-backup -r 1
374 374 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
375 375
376 376 Test max chain len
377 377 $ cat >> $HGRCPATH << EOF
378 378 > [format]
379 379 > maxchainlen=4
380 380 > EOF
381 381
382 382 $ printf "This test checks if maxchainlen config value is respected also it can serve as basic test for debugrevlog -d <file>.\n" >> a
383 383 $ hg ci -m a
384 384 $ printf "b\n" >> a
385 385 $ hg ci -m a
386 386 $ printf "c\n" >> a
387 387 $ hg ci -m a
388 388 $ printf "d\n" >> a
389 389 $ hg ci -m a
390 390 $ printf "e\n" >> a
391 391 $ hg ci -m a
392 392 $ printf "f\n" >> a
393 393 $ hg ci -m a
394 394 $ printf 'g\n' >> a
395 395 $ hg ci -m a
396 396 $ printf 'h\n' >> a
397 397 $ hg ci -m a
398 398
399 399 $ hg debugrevlog -d a
400 400 # rev p1rev p2rev start end deltastart base p1 p2 rawsize totalsize compression heads chainlen
401 401 0 -1 -1 0 ??? 0 0 0 0 ??? ???? ? 1 0 (glob)
402 402 1 0 -1 ??? ??? 0 0 0 0 ??? ???? ? 1 1 (glob)
403 403 2 1 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 2 (glob)
404 404 3 2 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 3 (glob)
405 405 4 3 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 4 (glob)
406 406 5 4 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 0 (glob)
407 407 6 5 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 1 (glob)
408 408 7 6 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 2 (glob)
409 409 8 7 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 3 (glob)
410 410 #endif
411 411
412 412 Test debuglocks command:
413 413
414 414 $ hg debuglocks
415 415 lock: free
416 416 wlock: free
417 417
418 418 * Test setting the lock
419 419
420 420 waitlock <file> will wait for file to be created. If it isn't in a reasonable
421 421 amount of time, displays error message and returns 1
422 422 $ waitlock() {
423 423 > start=`date +%s`
424 424 > timeout=5
425 425 > while [ \( ! -f $1 \) -a \( ! -L $1 \) ]; do
426 426 > now=`date +%s`
427 427 > if [ "`expr $now - $start`" -gt $timeout ]; then
428 428 > echo "timeout: $1 was not created in $timeout seconds"
429 429 > return 1
430 430 > fi
431 431 > sleep 0.1
432 432 > done
433 433 > }
434 434 $ dolock() {
435 435 > {
436 436 > waitlock .hg/unlock
437 437 > rm -f .hg/unlock
438 438 > echo y
439 439 > } | hg debuglocks "$@" > /dev/null
440 440 > }
441 441 $ dolock -s &
442 442 $ waitlock .hg/store/lock
443 443
444 444 $ hg debuglocks
445 445 lock: user *, process * (*s) (glob)
446 446 wlock: free
447 447 [1]
448 448 $ touch .hg/unlock
449 449 $ wait
450 450 $ [ -f .hg/store/lock ] || echo "There is no lock"
451 451 There is no lock
452 452
453 453 * Test setting the wlock
454 454
455 455 $ dolock -S &
456 456 $ waitlock .hg/wlock
457 457
458 458 $ hg debuglocks
459 459 lock: free
460 460 wlock: user *, process * (*s) (glob)
461 461 [1]
462 462 $ touch .hg/unlock
463 463 $ wait
464 464 $ [ -f .hg/wlock ] || echo "There is no wlock"
465 465 There is no wlock
466 466
467 467 * Test setting both locks
468 468
469 469 $ dolock -Ss &
470 470 $ waitlock .hg/wlock && waitlock .hg/store/lock
471 471
472 472 $ hg debuglocks
473 473 lock: user *, process * (*s) (glob)
474 474 wlock: user *, process * (*s) (glob)
475 475 [2]
476 476
477 477 * Test failing to set a lock
478 478
479 479 $ hg debuglocks -s
480 480 abort: lock is already held
481 481 [255]
482 482
483 483 $ hg debuglocks -S
484 484 abort: wlock is already held
485 485 [255]
486 486
487 487 $ touch .hg/unlock
488 488 $ wait
489 489
490 490 $ hg debuglocks
491 491 lock: free
492 492 wlock: free
493 493
494 494 * Test forcing the lock
495 495
496 496 $ dolock -s &
497 497 $ waitlock .hg/store/lock
498 498
499 499 $ hg debuglocks
500 500 lock: user *, process * (*s) (glob)
501 501 wlock: free
502 502 [1]
503 503
504 504 $ hg debuglocks -L
505 505
506 506 $ hg debuglocks
507 507 lock: free
508 508 wlock: free
509 509
510 510 $ touch .hg/unlock
511 511 $ wait
512 512
513 513 * Test forcing the wlock
514 514
515 515 $ dolock -S &
516 516 $ waitlock .hg/wlock
517 517
518 518 $ hg debuglocks
519 519 lock: free
520 520 wlock: user *, process * (*s) (glob)
521 521 [1]
522 522
523 523 $ hg debuglocks -W
524 524
525 525 $ hg debuglocks
526 526 lock: free
527 527 wlock: free
528 528
529 529 $ touch .hg/unlock
530 530 $ wait
531 531
532 532 Test WdirUnsupported exception
533 533
534 534 $ hg debugdata -c ffffffffffffffffffffffffffffffffffffffff
535 535 abort: working directory revision cannot be specified
536 536 [255]
537 537
538 538 Test cache warming command
539 539
540 540 $ rm -rf .hg/cache/
541 541 $ hg debugupdatecaches --debug
542 542 updating the branch cache
543 543 $ ls -r .hg/cache/*
544 544 .hg/cache/tags2-served
545 545 .hg/cache/tags2
546 546 .hg/cache/rbc-revs-v1
547 547 .hg/cache/rbc-names-v1
548 .hg/cache/manifestfulltextcache (reporevlogstore !)
549 548 .hg/cache/branch2-served
550 549
551 550 Test debugcolor
552 551
553 552 #if no-windows
554 553 $ hg debugcolor --style --color always | egrep 'mode|style|log\.'
555 554 color mode: 'ansi'
556 555 available style:
557 556 \x1b[0;33mlog.changeset\x1b[0m: \x1b[0;33myellow\x1b[0m (esc)
558 557 #endif
559 558
560 559 $ hg debugcolor --style --color never
561 560 color mode: None
562 561 available style:
563 562
564 563 $ cd ..
565 564
566 565 Test internal debugstacktrace command
567 566
568 567 $ cat > debugstacktrace.py << EOF
569 568 > from __future__ import absolute_import
570 569 > from mercurial import (
571 570 > pycompat,
572 571 > util,
573 572 > )
574 573 > def f():
575 574 > util.debugstacktrace(f=pycompat.stdout)
576 575 > g()
577 576 > def g():
578 577 > util.dst(b'hello from g\\n', skip=1)
579 578 > h()
580 579 > def h():
581 580 > util.dst(b'hi ...\\nfrom h hidden in g', 1, depth=2)
582 581 > f()
583 582 > EOF
584 583 $ "$PYTHON" debugstacktrace.py
585 584 stacktrace at:
586 585 debugstacktrace.py:14 in * (glob)
587 586 debugstacktrace.py:7 in f
588 587 hello from g at:
589 588 debugstacktrace.py:14 in * (glob)
590 589 debugstacktrace.py:8 in f
591 590 hi ...
592 591 from h hidden in g at:
593 592 debugstacktrace.py:8 in f
594 593 debugstacktrace.py:11 in g
595 594
596 595 Test debugcapabilities command:
597 596
598 597 $ hg debugcapabilities ./debugrevlog/
599 598 Main capabilities:
600 599 branchmap
601 600 $USUAL_BUNDLE2_CAPS$
602 601 getbundle
603 602 known
604 603 lookup
605 604 pushkey
606 605 unbundle
607 606 Bundle2 capabilities:
608 607 HG20
609 608 bookmarks
610 609 changegroup
611 610 01
612 611 02
613 612 digests
614 613 md5
615 614 sha1
616 615 sha512
617 616 error
618 617 abort
619 618 unsupportedcontent
620 619 pushraced
621 620 pushkey
622 621 hgtagsfnodes
623 622 listkeys
624 623 phases
625 624 heads
626 625 pushkey
627 626 remote-changegroup
628 627 http
629 628 https
630 629 rev-branch-cache
631 630 stream
632 631 v2
633 632
634 633 Test debugpeer
635 634
636 635 $ hg --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" debugpeer ssh://user@dummy/debugrevlog
637 636 url: ssh://user@dummy/debugrevlog
638 637 local: no
639 638 pushable: yes
640 639
641 640 $ hg --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" --debug debugpeer ssh://user@dummy/debugrevlog
642 641 running "*" "*/tests/dummyssh" 'user@dummy' 'hg -R debugrevlog serve --stdio' (glob) (no-windows !)
643 642 running "*" "*\tests/dummyssh" "user@dummy" "hg -R debugrevlog serve --stdio" (glob) (windows !)
644 643 devel-peer-request: hello+between
645 644 devel-peer-request: pairs: 81 bytes
646 645 sending hello command
647 646 sending between command
648 647 remote: 440
649 648 remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
650 649 remote: 1
651 650 devel-peer-request: protocaps
652 651 devel-peer-request: caps: * bytes (glob)
653 652 sending protocaps command
654 653 url: ssh://user@dummy/debugrevlog
655 654 local: no
656 655 pushable: yes
@@ -1,518 +1,518 b''
1 1 #require repofncache
2 2
3 3 Init repo1:
4 4
5 5 $ hg init repo1
6 6 $ cd repo1
7 7 $ echo "some text" > a
8 8 $ hg add
9 9 adding a
10 10 $ hg ci -m first
11 11 $ cat .hg/store/fncache | sort
12 12 data/a.i
13 13
14 14 Testing a.i/b:
15 15
16 16 $ mkdir a.i
17 17 $ echo "some other text" > a.i/b
18 18 $ hg add
19 19 adding a.i/b
20 20 $ hg ci -m second
21 21 $ cat .hg/store/fncache | sort
22 22 data/a.i
23 23 data/a.i.hg/b.i
24 24
25 25 Testing a.i.hg/c:
26 26
27 27 $ mkdir a.i.hg
28 28 $ echo "yet another text" > a.i.hg/c
29 29 $ hg add
30 30 adding a.i.hg/c
31 31 $ hg ci -m third
32 32 $ cat .hg/store/fncache | sort
33 33 data/a.i
34 34 data/a.i.hg.hg/c.i
35 35 data/a.i.hg/b.i
36 36
37 37 Testing verify:
38 38
39 39 $ hg verify
40 40 checking changesets
41 41 checking manifests
42 42 crosschecking files in changesets and manifests
43 43 checking files
44 44 checked 3 changesets with 3 changes to 3 files
45 45
46 46 $ rm .hg/store/fncache
47 47
48 48 $ hg verify
49 49 checking changesets
50 50 checking manifests
51 51 crosschecking files in changesets and manifests
52 52 checking files
53 53 warning: revlog 'data/a.i' not in fncache!
54 54 warning: revlog 'data/a.i.hg/c.i' not in fncache!
55 55 warning: revlog 'data/a.i/b.i' not in fncache!
56 56 checked 3 changesets with 3 changes to 3 files
57 57 3 warnings encountered!
58 58 hint: run "hg debugrebuildfncache" to recover from corrupt fncache
59 59
60 60 Follow the hint to make sure it works
61 61
62 62 $ hg debugrebuildfncache
63 63 adding data/a.i
64 64 adding data/a.i.hg/c.i
65 65 adding data/a.i/b.i
66 66 3 items added, 0 removed from fncache
67 67
68 68 $ hg verify
69 69 checking changesets
70 70 checking manifests
71 71 crosschecking files in changesets and manifests
72 72 checking files
73 73 checked 3 changesets with 3 changes to 3 files
74 74
75 75 $ cd ..
76 76
77 77 Non store repo:
78 78
79 79 $ hg --config format.usestore=False init foo
80 80 $ cd foo
81 81 $ mkdir tst.d
82 82 $ echo foo > tst.d/foo
83 83 $ hg ci -Amfoo
84 84 adding tst.d/foo
85 85 $ find .hg | sort
86 86 .hg
87 87 .hg/00changelog.i
88 88 .hg/00manifest.i
89 89 .hg/cache
90 90 .hg/cache/branch2-served
91 .hg/cache/manifestfulltextcache (reporevlogstore !)
92 91 .hg/cache/rbc-names-v1
93 92 .hg/cache/rbc-revs-v1
94 93 .hg/data
95 94 .hg/data/tst.d.hg
96 95 .hg/data/tst.d.hg/foo.i
97 96 .hg/dirstate
98 97 .hg/fsmonitor.state (fsmonitor !)
99 98 .hg/last-message.txt
100 99 .hg/phaseroots
101 100 .hg/requires
102 101 .hg/undo
103 102 .hg/undo.backup.dirstate
104 103 .hg/undo.backupfiles
105 104 .hg/undo.bookmarks
106 105 .hg/undo.branch
107 106 .hg/undo.desc
108 107 .hg/undo.dirstate
109 108 .hg/undo.phaseroots
110 109 .hg/wcache
111 110 .hg/wcache/checkisexec (execbit !)
112 111 .hg/wcache/checklink (symlink !)
113 112 .hg/wcache/checklink-target (symlink !)
113 .hg/wcache/manifestfulltextcache (reporevlogstore !)
114 114 $ cd ..
115 115
116 116 Non fncache repo:
117 117
118 118 $ hg --config format.usefncache=False init bar
119 119 $ cd bar
120 120 $ mkdir tst.d
121 121 $ echo foo > tst.d/Foo
122 122 $ hg ci -Amfoo
123 123 adding tst.d/Foo
124 124 $ find .hg | sort
125 125 .hg
126 126 .hg/00changelog.i
127 127 .hg/cache
128 128 .hg/cache/branch2-served
129 .hg/cache/manifestfulltextcache (reporevlogstore !)
130 129 .hg/cache/rbc-names-v1
131 130 .hg/cache/rbc-revs-v1
132 131 .hg/dirstate
133 132 .hg/fsmonitor.state (fsmonitor !)
134 133 .hg/last-message.txt
135 134 .hg/requires
136 135 .hg/store
137 136 .hg/store/00changelog.i
138 137 .hg/store/00manifest.i
139 138 .hg/store/data
140 139 .hg/store/data/tst.d.hg
141 140 .hg/store/data/tst.d.hg/_foo.i
142 141 .hg/store/phaseroots
143 142 .hg/store/undo
144 143 .hg/store/undo.backupfiles
145 144 .hg/store/undo.phaseroots
146 145 .hg/undo.backup.dirstate
147 146 .hg/undo.bookmarks
148 147 .hg/undo.branch
149 148 .hg/undo.desc
150 149 .hg/undo.dirstate
151 150 .hg/wcache
152 151 .hg/wcache/checkisexec (execbit !)
153 152 .hg/wcache/checklink (symlink !)
154 153 .hg/wcache/checklink-target (symlink !)
154 .hg/wcache/manifestfulltextcache (reporevlogstore !)
155 155 $ cd ..
156 156
157 157 Encoding of reserved / long paths in the store
158 158
159 159 $ hg init r2
160 160 $ cd r2
161 161 $ cat <<EOF > .hg/hgrc
162 162 > [ui]
163 163 > portablefilenames = ignore
164 164 > EOF
165 165
166 166 $ hg import -q --bypass - <<EOF
167 167 > # HG changeset patch
168 168 > # User test
169 169 > # Date 0 0
170 170 > # Node ID 1c7a2f7cb77be1a0def34e4c7cabc562ad98fbd7
171 171 > # Parent 0000000000000000000000000000000000000000
172 172 > 1
173 173 >
174 174 > diff --git a/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-123456789-12.3456789-12345-ABCDEFGHIJKLMNOPRSTUVWXYZ-abcdefghjiklmnopqrstuvwxyz b/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-123456789-12.3456789-12345-ABCDEFGHIJKLMNOPRSTUVWXYZ-abcdefghjiklmnopqrstuvwxyz
175 175 > new file mode 100644
176 176 > --- /dev/null
177 177 > +++ b/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-123456789-12.3456789-12345-ABCDEFGHIJKLMNOPRSTUVWXYZ-abcdefghjiklmnopqrstuvwxyz
178 178 > @@ -0,0 +1,1 @@
179 179 > +foo
180 180 > diff --git a/AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/TENTH/ELEVENTH/LOREMIPSUM.TXT b/AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/TENTH/ELEVENTH/LOREMIPSUM.TXT
181 181 > new file mode 100644
182 182 > --- /dev/null
183 183 > +++ b/AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/TENTH/ELEVENTH/LOREMIPSUM.TXT
184 184 > @@ -0,0 +1,1 @@
185 185 > +foo
186 186 > diff --git a/Project Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt b/Project Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt
187 187 > new file mode 100644
188 188 > --- /dev/null
189 189 > +++ b/Project Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt
190 190 > @@ -0,0 +1,1 @@
191 191 > +foo
192 192 > diff --git a/bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL/normal.c b/bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL/normal.c
193 193 > new file mode 100644
194 194 > --- /dev/null
195 195 > +++ b/bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL/normal.c
196 196 > @@ -0,0 +1,1 @@
197 197 > +foo
198 198 > diff --git a/enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/wsdlExtension/src/main/java/META-INF/services/org.netbeans.modules.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider b/enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/wsdlExtension/src/main/java/META-INF/services/org.netbeans.modules.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider
199 199 > new file mode 100644
200 200 > --- /dev/null
201 201 > +++ b/enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/wsdlExtension/src/main/java/META-INF/services/org.netbeans.modules.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider
202 202 > @@ -0,0 +1,1 @@
203 203 > +foo
204 204 > EOF
205 205
206 206 $ find .hg/store -name *.i | sort
207 207 .hg/store/00changelog.i
208 208 .hg/store/00manifest.i
209 209 .hg/store/data/bla.aux/pr~6e/_p_r_n/lpt/co~6d3/nu~6c/coma/foo._n_u_l/normal.c.i
210 210 .hg/store/dh/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxx168e07b38e65eff86ab579afaaa8e30bfbe0f35f.i
211 211 .hg/store/dh/au~78/second/x.prn/fourth/fi~3afth/sixth/seventh/eighth/nineth/tenth/loremia20419e358ddff1bf8751e38288aff1d7c32ec05.i
212 212 .hg/store/dh/enterpri/openesba/contrib-/corba-bc/netbeans/wsdlexte/src/main/java/org.net7018f27961fdf338a598a40c4683429e7ffb9743.i
213 213 .hg/store/dh/project_/resource/anotherl/followed/andanoth/andthenanextremelylongfilename0d8e1f4187c650e2f1fdca9fd90f786bc0976b6b.i
214 214
215 215 $ cd ..
216 216
217 217 Aborting lock does not prevent fncache writes
218 218
219 219 $ cat > exceptionext.py <<EOF
220 220 > from __future__ import absolute_import
221 221 > import os
222 222 > from mercurial import commands, error, extensions
223 223 >
224 224 > def lockexception(orig, vfs, lockname, wait, releasefn, *args, **kwargs):
225 225 > def releasewrap():
226 226 > l.held = False # ensure __del__ is a noop
227 227 > raise error.Abort("forced lock failure")
228 228 > l = orig(vfs, lockname, wait, releasewrap, *args, **kwargs)
229 229 > return l
230 230 >
231 231 > def reposetup(ui, repo):
232 232 > extensions.wrapfunction(repo, '_lock', lockexception)
233 233 >
234 234 > cmdtable = {}
235 235 >
236 236 > # wrap "commit" command to prevent wlock from being '__del__()'-ed
237 237 > # at the end of dispatching (for intentional "forced lcok failure")
238 238 > def commitwrap(orig, ui, repo, *pats, **opts):
239 239 > repo = repo.unfiltered() # to use replaced repo._lock certainly
240 240 > wlock = repo.wlock()
241 241 > try:
242 242 > return orig(ui, repo, *pats, **opts)
243 243 > finally:
244 244 > # multiple 'relase()' is needed for complete releasing wlock,
245 245 > # because "forced" abort at last releasing store lock
246 246 > # prevents wlock from being released at same 'lockmod.release()'
247 247 > for i in range(wlock.held):
248 248 > wlock.release()
249 249 >
250 250 > def extsetup(ui):
251 251 > extensions.wrapcommand(commands.table, b"commit", commitwrap)
252 252 > EOF
253 253 $ extpath=`pwd`/exceptionext.py
254 254 $ hg init fncachetxn
255 255 $ cd fncachetxn
256 256 $ printf "[extensions]\nexceptionext=$extpath\n" >> .hg/hgrc
257 257 $ touch y
258 258 $ hg ci -qAm y
259 259 abort: forced lock failure
260 260 [255]
261 261 $ cat .hg/store/fncache
262 262 data/y.i
263 263
264 264 Aborting transaction prevents fncache change
265 265
266 266 $ cat > ../exceptionext.py <<EOF
267 267 > from __future__ import absolute_import
268 268 > import os
269 269 > from mercurial import commands, error, extensions, localrepo
270 270 >
271 271 > def wrapper(orig, self, *args, **kwargs):
272 272 > tr = orig(self, *args, **kwargs)
273 273 > def fail(tr):
274 274 > raise error.Abort(b"forced transaction failure")
275 275 > # zzz prefix to ensure it sorted after store.write
276 276 > tr.addfinalize(b'zzz-forcefails', fail)
277 277 > return tr
278 278 >
279 279 > def uisetup(ui):
280 280 > extensions.wrapfunction(
281 281 > localrepo.localrepository, b'transaction', wrapper)
282 282 >
283 283 > cmdtable = {}
284 284 >
285 285 > EOF
286 286
287 287 Clean cached version
288 288 $ rm -f "${extpath}c"
289 289 $ rm -Rf "`dirname $extpath`/__pycache__"
290 290
291 291 $ touch z
292 292 $ hg ci -qAm z
293 293 transaction abort!
294 294 rollback completed
295 295 abort: forced transaction failure
296 296 [255]
297 297 $ cat .hg/store/fncache
298 298 data/y.i
299 299
300 300 Aborted transactions can be recovered later
301 301
302 302 $ cat > ../exceptionext.py <<EOF
303 303 > from __future__ import absolute_import
304 304 > import os
305 305 > from mercurial import (
306 306 > commands,
307 307 > error,
308 308 > extensions,
309 309 > localrepo,
310 310 > transaction,
311 311 > )
312 312 >
313 313 > def trwrapper(orig, self, *args, **kwargs):
314 314 > tr = orig(self, *args, **kwargs)
315 315 > def fail(tr):
316 316 > raise error.Abort(b"forced transaction failure")
317 317 > # zzz prefix to ensure it sorted after store.write
318 318 > tr.addfinalize(b'zzz-forcefails', fail)
319 319 > return tr
320 320 >
321 321 > def abortwrapper(orig, self, *args, **kwargs):
322 322 > raise error.Abort(b"forced transaction failure")
323 323 >
324 324 > def uisetup(ui):
325 325 > extensions.wrapfunction(localrepo.localrepository, 'transaction',
326 326 > trwrapper)
327 327 > extensions.wrapfunction(transaction.transaction, '_abort',
328 328 > abortwrapper)
329 329 >
330 330 > cmdtable = {}
331 331 >
332 332 > EOF
333 333
334 334 Clean cached versions
335 335 $ rm -f "${extpath}c"
336 336 $ rm -Rf "`dirname $extpath`/__pycache__"
337 337
338 338 $ hg up -q 1
339 339 $ touch z
340 340 $ hg ci -qAm z 2>/dev/null
341 341 [255]
342 342 $ cat .hg/store/fncache | sort
343 343 data/y.i
344 344 data/z.i
345 345 $ hg recover
346 346 rolling back interrupted transaction
347 347 checking changesets
348 348 checking manifests
349 349 crosschecking files in changesets and manifests
350 350 checking files
351 351 checked 1 changesets with 1 changes to 1 files
352 352 $ cat .hg/store/fncache
353 353 data/y.i
354 354
355 355 $ cd ..
356 356
357 357 debugrebuildfncache does nothing unless repo has fncache requirement
358 358
359 359 $ hg --config format.usefncache=false init nofncache
360 360 $ cd nofncache
361 361 $ hg debugrebuildfncache
362 362 (not rebuilding fncache because repository does not support fncache)
363 363
364 364 $ cd ..
365 365
366 366 debugrebuildfncache works on empty repository
367 367
368 368 $ hg init empty
369 369 $ cd empty
370 370 $ hg debugrebuildfncache
371 371 fncache already up to date
372 372 $ cd ..
373 373
374 374 debugrebuildfncache on an up to date repository no-ops
375 375
376 376 $ hg init repo
377 377 $ cd repo
378 378 $ echo initial > foo
379 379 $ echo initial > .bar
380 380 $ hg commit -A -m initial
381 381 adding .bar
382 382 adding foo
383 383
384 384 $ cat .hg/store/fncache | sort
385 385 data/.bar.i
386 386 data/foo.i
387 387
388 388 $ hg debugrebuildfncache
389 389 fncache already up to date
390 390
391 391 debugrebuildfncache restores deleted fncache file
392 392
393 393 $ rm -f .hg/store/fncache
394 394 $ hg debugrebuildfncache
395 395 adding data/.bar.i
396 396 adding data/foo.i
397 397 2 items added, 0 removed from fncache
398 398
399 399 $ cat .hg/store/fncache | sort
400 400 data/.bar.i
401 401 data/foo.i
402 402
403 403 Rebuild after rebuild should no-op
404 404
405 405 $ hg debugrebuildfncache
406 406 fncache already up to date
407 407
408 408 A single missing file should get restored, an extra file should be removed
409 409
410 410 $ cat > .hg/store/fncache << EOF
411 411 > data/foo.i
412 412 > data/bad-entry.i
413 413 > EOF
414 414
415 415 $ hg debugrebuildfncache
416 416 removing data/bad-entry.i
417 417 adding data/.bar.i
418 418 1 items added, 1 removed from fncache
419 419
420 420 $ cat .hg/store/fncache | sort
421 421 data/.bar.i
422 422 data/foo.i
423 423
424 424 $ cd ..
425 425
426 426 Try a simple variation without dotencode to ensure fncache is ignorant of encoding
427 427
428 428 $ hg --config format.dotencode=false init nodotencode
429 429 $ cd nodotencode
430 430 $ echo initial > foo
431 431 $ echo initial > .bar
432 432 $ hg commit -A -m initial
433 433 adding .bar
434 434 adding foo
435 435
436 436 $ cat .hg/store/fncache | sort
437 437 data/.bar.i
438 438 data/foo.i
439 439
440 440 $ rm .hg/store/fncache
441 441 $ hg debugrebuildfncache
442 442 adding data/.bar.i
443 443 adding data/foo.i
444 444 2 items added, 0 removed from fncache
445 445
446 446 $ cat .hg/store/fncache | sort
447 447 data/.bar.i
448 448 data/foo.i
449 449
450 450 $ cd ..
451 451
452 452 In repositories that have accumulated a large number of files over time, the
453 453 fncache file is going to be large. If we possibly can avoid loading it, so much the better.
454 454 The cache should not loaded when committing changes to existing files, or when unbundling
455 455 changesets that only contain changes to existing files:
456 456
457 457 $ cat > fncacheloadwarn.py << EOF
458 458 > from __future__ import absolute_import
459 459 > from mercurial import extensions, localrepo
460 460 >
461 461 > def extsetup(ui):
462 462 > def wrapstore(orig, requirements, *args):
463 463 > store = orig(requirements, *args)
464 464 > if b'store' in requirements and b'fncache' in requirements:
465 465 > instrumentfncachestore(store, ui)
466 466 > return store
467 467 > extensions.wrapfunction(localrepo, 'makestore', wrapstore)
468 468 >
469 469 > def instrumentfncachestore(fncachestore, ui):
470 470 > class instrumentedfncache(type(fncachestore.fncache)):
471 471 > def _load(self):
472 472 > ui.warn(b'fncache load triggered!\n')
473 473 > super(instrumentedfncache, self)._load()
474 474 > fncachestore.fncache.__class__ = instrumentedfncache
475 475 > EOF
476 476
477 477 $ fncachextpath=`pwd`/fncacheloadwarn.py
478 478 $ hg init nofncacheload
479 479 $ cd nofncacheload
480 480 $ printf "[extensions]\nfncacheloadwarn=$fncachextpath\n" >> .hg/hgrc
481 481
482 482 A new file should trigger a load, as we'd want to update the fncache set in that case:
483 483
484 484 $ touch foo
485 485 $ hg ci -qAm foo
486 486 fncache load triggered!
487 487
488 488 But modifying that file should not:
489 489
490 490 $ echo bar >> foo
491 491 $ hg ci -qm foo
492 492
493 493 If a transaction has been aborted, the zero-size truncated index file will
494 494 not prevent the fncache from being loaded; rather than actually abort
495 495 a transaction, we simulate the situation by creating a zero-size index file:
496 496
497 497 $ touch .hg/store/data/bar.i
498 498 $ touch bar
499 499 $ hg ci -qAm bar
500 500 fncache load triggered!
501 501
502 502 Unbundling should follow the same rules; existing files should not cause a load:
503 503
504 504 $ hg clone -q . tobundle
505 505 $ echo 'new line' > tobundle/bar
506 506 $ hg -R tobundle ci -qm bar
507 507 $ hg -R tobundle bundle -q barupdated.hg
508 508 $ hg unbundle -q barupdated.hg
509 509
510 510 but adding new files should:
511 511
512 512 $ touch tobundle/newfile
513 513 $ hg -R tobundle ci -qAm newfile
514 514 $ hg -R tobundle bundle -q newfile.hg
515 515 $ hg unbundle -q newfile.hg
516 516 fncache load triggered!
517 517
518 518 $ cd ..
@@ -1,432 +1,432 b''
1 1 #require hardlink reporevlogstore
2 2
3 3 $ cat > nlinks.py <<EOF
4 4 > from __future__ import print_function
5 5 > import sys
6 6 > from mercurial import pycompat, util
7 7 > for f in sorted(sys.stdin.readlines()):
8 8 > f = f[:-1]
9 9 > print(util.nlinks(pycompat.fsencode(f)), f)
10 10 > EOF
11 11
12 12 $ nlinksdir()
13 13 > {
14 14 > find "$@" -type f | "$PYTHON" $TESTTMP/nlinks.py
15 15 > }
16 16
17 17 Some implementations of cp can't create hardlinks (replaces 'cp -al' on Linux):
18 18
19 19 $ cat > linkcp.py <<EOF
20 20 > from __future__ import absolute_import
21 21 > import sys
22 22 > from mercurial import pycompat, util
23 23 > util.copyfiles(pycompat.fsencode(sys.argv[1]),
24 24 > pycompat.fsencode(sys.argv[2]), hardlink=True)
25 25 > EOF
26 26
27 27 $ linkcp()
28 28 > {
29 29 > "$PYTHON" $TESTTMP/linkcp.py $1 $2
30 30 > }
31 31
32 32 Prepare repo r1:
33 33
34 34 $ hg init r1
35 35 $ cd r1
36 36
37 37 $ echo c1 > f1
38 38 $ hg add f1
39 39 $ hg ci -m0
40 40
41 41 $ mkdir d1
42 42 $ cd d1
43 43 $ echo c2 > f2
44 44 $ hg add f2
45 45 $ hg ci -m1
46 46 $ cd ../..
47 47
48 48 $ nlinksdir r1/.hg/store
49 49 1 r1/.hg/store/00changelog.i
50 50 1 r1/.hg/store/00manifest.i
51 51 1 r1/.hg/store/data/d1/f2.i
52 52 1 r1/.hg/store/data/f1.i
53 53 1 r1/.hg/store/fncache (repofncache !)
54 54 1 r1/.hg/store/phaseroots
55 55 1 r1/.hg/store/undo
56 56 1 r1/.hg/store/undo.backup.fncache (repofncache !)
57 57 1 r1/.hg/store/undo.backupfiles
58 58 1 r1/.hg/store/undo.phaseroots
59 59
60 60
61 61 Create hardlinked clone r2:
62 62
63 63 $ hg clone -U --debug r1 r2 --config progress.debug=true
64 64 linking: 1 files
65 65 linking: 2 files
66 66 linking: 3 files
67 67 linking: 4 files
68 68 linking: 5 files
69 69 linking: 6 files
70 70 linking: 7 files
71 71 linked 7 files
72 72
73 73 Create non-hardlinked clone r3:
74 74
75 75 $ hg clone --pull r1 r3
76 76 requesting all changes
77 77 adding changesets
78 78 adding manifests
79 79 adding file changes
80 80 added 2 changesets with 2 changes to 2 files
81 81 new changesets 40d85e9847f2:7069c422939c
82 82 updating to branch default
83 83 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
84 84
85 85
86 86 Repos r1 and r2 should now contain hardlinked files:
87 87
88 88 $ nlinksdir r1/.hg/store
89 89 2 r1/.hg/store/00changelog.i
90 90 2 r1/.hg/store/00manifest.i
91 91 2 r1/.hg/store/data/d1/f2.i
92 92 2 r1/.hg/store/data/f1.i
93 93 2 r1/.hg/store/fncache (repofncache !)
94 94 1 r1/.hg/store/phaseroots
95 95 1 r1/.hg/store/undo
96 96 1 r1/.hg/store/undo.backup.fncache (repofncache !)
97 97 1 r1/.hg/store/undo.backupfiles
98 98 1 r1/.hg/store/undo.phaseroots
99 99
100 100 $ nlinksdir r2/.hg/store
101 101 2 r2/.hg/store/00changelog.i
102 102 2 r2/.hg/store/00manifest.i
103 103 2 r2/.hg/store/data/d1/f2.i
104 104 2 r2/.hg/store/data/f1.i
105 105 2 r2/.hg/store/fncache (repofncache !)
106 106
107 107 Repo r3 should not be hardlinked:
108 108
109 109 $ nlinksdir r3/.hg/store
110 110 1 r3/.hg/store/00changelog.i
111 111 1 r3/.hg/store/00manifest.i
112 112 1 r3/.hg/store/data/d1/f2.i
113 113 1 r3/.hg/store/data/f1.i
114 114 1 r3/.hg/store/fncache (repofncache !)
115 115 1 r3/.hg/store/phaseroots
116 116 1 r3/.hg/store/undo
117 117 1 r3/.hg/store/undo.backupfiles
118 118 1 r3/.hg/store/undo.phaseroots
119 119
120 120
121 121 Create a non-inlined filelog in r3:
122 122
123 123 $ cd r3/d1
124 124 >>> f = open('data1', 'wb')
125 125 >>> for x in range(10000):
126 126 ... f.write(b"%d\n" % x) and None
127 127 >>> f.close()
128 128 $ for j in 0 1 2 3 4 5 6 7 8 9; do
129 129 > cat data1 >> f2
130 130 > hg commit -m$j
131 131 > done
132 132 $ cd ../..
133 133
134 134 $ nlinksdir r3/.hg/store
135 135 1 r3/.hg/store/00changelog.i
136 136 1 r3/.hg/store/00manifest.i
137 137 1 r3/.hg/store/data/d1/f2.d
138 138 1 r3/.hg/store/data/d1/f2.i
139 139 1 r3/.hg/store/data/f1.i
140 140 1 r3/.hg/store/fncache (repofncache !)
141 141 1 r3/.hg/store/phaseroots
142 142 1 r3/.hg/store/undo
143 143 1 r3/.hg/store/undo.backup.fncache (repofncache !)
144 144 1 r3/.hg/store/undo.backup.phaseroots
145 145 1 r3/.hg/store/undo.backupfiles
146 146 1 r3/.hg/store/undo.phaseroots
147 147
148 148 Push to repo r1 should break up most hardlinks in r2:
149 149
150 150 $ hg -R r2 verify
151 151 checking changesets
152 152 checking manifests
153 153 crosschecking files in changesets and manifests
154 154 checking files
155 155 checked 2 changesets with 2 changes to 2 files
156 156
157 157 $ cd r3
158 158 $ hg push
159 159 pushing to $TESTTMP/r1
160 160 searching for changes
161 161 adding changesets
162 162 adding manifests
163 163 adding file changes
164 164 added 10 changesets with 10 changes to 1 files
165 165
166 166 $ cd ..
167 167
168 168 $ nlinksdir r2/.hg/store
169 169 1 r2/.hg/store/00changelog.i
170 170 1 r2/.hg/store/00manifest.i
171 171 1 r2/.hg/store/data/d1/f2.i
172 172 2 r2/.hg/store/data/f1.i
173 173 [12] r2/\.hg/store/fncache (re) (repofncache !)
174 174
175 175 #if hardlink-whitelisted repofncache
176 176 $ nlinksdir r2/.hg/store/fncache
177 177 2 r2/.hg/store/fncache
178 178 #endif
179 179
180 180 $ hg -R r2 verify
181 181 checking changesets
182 182 checking manifests
183 183 crosschecking files in changesets and manifests
184 184 checking files
185 185 checked 2 changesets with 2 changes to 2 files
186 186
187 187
188 188 $ cd r1
189 189 $ hg up
190 190 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
191 191
192 192 Committing a change to f1 in r1 must break up hardlink f1.i in r2:
193 193
194 194 $ echo c1c1 >> f1
195 195 $ hg ci -m00
196 196 $ cd ..
197 197
198 198 $ nlinksdir r2/.hg/store
199 199 1 r2/.hg/store/00changelog.i
200 200 1 r2/.hg/store/00manifest.i
201 201 1 r2/.hg/store/data/d1/f2.i
202 202 1 r2/.hg/store/data/f1.i
203 203 [12] r2/\.hg/store/fncache (re) (repofncache !)
204 204
205 205 #if hardlink-whitelisted repofncache
206 206 $ nlinksdir r2/.hg/store/fncache
207 207 2 r2/.hg/store/fncache
208 208 #endif
209 209
210 210 Create a file which exec permissions we will change
211 211 $ cd r3
212 212 $ echo "echo hello world" > f3
213 213 $ hg add f3
214 214 $ hg ci -mf3
215 215 $ cd ..
216 216
217 217 $ cd r3
218 218 $ hg tip --template '{rev}:{node|short}\n'
219 219 12:d3b77733a28a
220 220 $ echo bla > f1
221 221 $ chmod +x f3
222 222 $ hg ci -m1
223 223 $ cd ..
224 224
225 225 Create hardlinked copy r4 of r3 (on Linux, we would call 'cp -al'):
226 226
227 227 $ linkcp r3 r4
228 228
229 229 'checklink' is produced by hardlinking a symlink, which is undefined whether
230 230 the symlink should be followed or not. It does behave differently on Linux and
231 231 BSD. Just remove it so the test pass on both platforms.
232 232
233 233 $ rm -f r4/.hg/wcache/checklink
234 234
235 235 r4 has hardlinks in the working dir (not just inside .hg):
236 236
237 237 $ nlinksdir r4
238 238 2 r4/.hg/00changelog.i
239 239 2 r4/.hg/branch
240 240 2 r4/.hg/cache/branch2-base
241 241 2 r4/.hg/cache/branch2-served
242 2 r4/.hg/cache/manifestfulltextcache (reporevlogstore !)
243 242 2 r4/.hg/cache/rbc-names-v1
244 243 2 r4/.hg/cache/rbc-revs-v1
245 244 2 r4/.hg/dirstate
246 245 2 r4/.hg/fsmonitor.state (fsmonitor !)
247 246 2 r4/.hg/hgrc
248 247 2 r4/.hg/last-message.txt
249 248 2 r4/.hg/requires
250 249 2 r4/.hg/store/00changelog.i
251 250 2 r4/.hg/store/00manifest.i
252 251 2 r4/.hg/store/data/d1/f2.d
253 252 2 r4/.hg/store/data/d1/f2.i
254 253 2 r4/.hg/store/data/f1.i
255 254 2 r4/.hg/store/data/f3.i
256 255 2 r4/.hg/store/fncache (repofncache !)
257 256 2 r4/.hg/store/phaseroots
258 257 2 r4/.hg/store/undo
259 258 2 r4/.hg/store/undo.backup.fncache (repofncache !)
260 259 2 r4/.hg/store/undo.backup.phaseroots
261 260 2 r4/.hg/store/undo.backupfiles
262 261 2 r4/.hg/store/undo.phaseroots
263 262 [24] r4/\.hg/undo\.backup\.dirstate (re)
264 263 2 r4/.hg/undo.bookmarks
265 264 2 r4/.hg/undo.branch
266 265 2 r4/.hg/undo.desc
267 266 [24] r4/\.hg/undo\.dirstate (re)
268 267 2 r4/.hg/wcache/checkisexec (execbit !)
269 268 2 r4/.hg/wcache/checklink-target (symlink !)
270 269 2 r4/.hg/wcache/checknoexec (execbit !)
270 2 r4/.hg/wcache/manifestfulltextcache (reporevlogstore !)
271 271 2 r4/d1/data1
272 272 2 r4/d1/f2
273 273 2 r4/f1
274 274 2 r4/f3
275 275
276 276 Update back to revision 12 in r4 should break hardlink of file f1 and f3:
277 277 #if hardlink-whitelisted
278 278 $ nlinksdir r4/.hg/undo.backup.dirstate r4/.hg/undo.dirstate
279 279 4 r4/.hg/undo.backup.dirstate
280 280 4 r4/.hg/undo.dirstate
281 281 #endif
282 282
283 283
284 284 $ hg -R r4 up 12
285 285 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (execbit !)
286 286 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-execbit !)
287 287
288 288 $ nlinksdir r4
289 289 2 r4/.hg/00changelog.i
290 290 1 r4/.hg/branch
291 291 2 r4/.hg/cache/branch2-base
292 292 2 r4/.hg/cache/branch2-served
293 1 r4/.hg/cache/manifestfulltextcache (reporevlogstore !)
294 293 2 r4/.hg/cache/rbc-names-v1
295 294 2 r4/.hg/cache/rbc-revs-v1
296 295 1 r4/.hg/dirstate
297 296 1 r4/.hg/fsmonitor.state (fsmonitor !)
298 297 2 r4/.hg/hgrc
299 298 2 r4/.hg/last-message.txt
300 299 2 r4/.hg/requires
301 300 2 r4/.hg/store/00changelog.i
302 301 2 r4/.hg/store/00manifest.i
303 302 2 r4/.hg/store/data/d1/f2.d
304 303 2 r4/.hg/store/data/d1/f2.i
305 304 2 r4/.hg/store/data/f1.i
306 305 2 r4/.hg/store/data/f3.i
307 306 2 r4/.hg/store/fncache
308 307 2 r4/.hg/store/phaseroots
309 308 2 r4/.hg/store/undo
310 309 2 r4/.hg/store/undo.backup.fncache (repofncache !)
311 310 2 r4/.hg/store/undo.backup.phaseroots
312 311 2 r4/.hg/store/undo.backupfiles
313 312 2 r4/.hg/store/undo.phaseroots
314 313 [24] r4/\.hg/undo\.backup\.dirstate (re)
315 314 2 r4/.hg/undo.bookmarks
316 315 2 r4/.hg/undo.branch
317 316 2 r4/.hg/undo.desc
318 317 [24] r4/\.hg/undo\.dirstate (re)
319 318 2 r4/.hg/wcache/checkisexec (execbit !)
320 319 2 r4/.hg/wcache/checklink-target (symlink !)
321 320 2 r4/.hg/wcache/checknoexec (execbit !)
321 1 r4/.hg/wcache/manifestfulltextcache (reporevlogstore !)
322 322 2 r4/d1/data1
323 323 2 r4/d1/f2
324 324 1 r4/f1
325 325 1 r4/f3 (execbit !)
326 326 2 r4/f3 (no-execbit !)
327 327
328 328 #if hardlink-whitelisted
329 329 $ nlinksdir r4/.hg/undo.backup.dirstate r4/.hg/undo.dirstate
330 330 4 r4/.hg/undo.backup.dirstate
331 331 4 r4/.hg/undo.dirstate
332 332 #endif
333 333
334 334 Test hardlinking outside hg:
335 335
336 336 $ mkdir x
337 337 $ echo foo > x/a
338 338
339 339 $ linkcp x y
340 340 $ echo bar >> y/a
341 341
342 342 No diff if hardlink:
343 343
344 344 $ diff x/a y/a
345 345
346 346 Test mq hardlinking:
347 347
348 348 $ echo "[extensions]" >> $HGRCPATH
349 349 $ echo "mq=" >> $HGRCPATH
350 350
351 351 $ hg init a
352 352 $ cd a
353 353
354 354 $ hg qimport -n foo - << EOF
355 355 > # HG changeset patch
356 356 > # Date 1 0
357 357 > diff -r 2588a8b53d66 a
358 358 > --- /dev/null Thu Jan 01 00:00:00 1970 +0000
359 359 > +++ b/a Wed Jul 23 15:54:29 2008 +0200
360 360 > @@ -0,0 +1,1 @@
361 361 > +a
362 362 > EOF
363 363 adding foo to series file
364 364
365 365 $ hg qpush
366 366 applying foo
367 367 now at: foo
368 368
369 369 $ cd ..
370 370 $ linkcp a b
371 371 $ cd b
372 372
373 373 $ hg qimport -n bar - << EOF
374 374 > # HG changeset patch
375 375 > # Date 2 0
376 376 > diff -r 2588a8b53d66 a
377 377 > --- /dev/null Thu Jan 01 00:00:00 1970 +0000
378 378 > +++ b/b Wed Jul 23 15:54:29 2008 +0200
379 379 > @@ -0,0 +1,1 @@
380 380 > +b
381 381 > EOF
382 382 adding bar to series file
383 383
384 384 $ hg qpush
385 385 applying bar
386 386 now at: bar
387 387
388 388 $ cat .hg/patches/status
389 389 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo
390 390 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c:bar
391 391
392 392 $ cat .hg/patches/series
393 393 foo
394 394 bar
395 395
396 396 $ cat ../a/.hg/patches/status
397 397 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo
398 398
399 399 $ cat ../a/.hg/patches/series
400 400 foo
401 401
402 402 Test tags hardlinking:
403 403
404 404 $ hg qdel -r qbase:qtip
405 405 patch foo finalized without changeset message
406 406 patch bar finalized without changeset message
407 407
408 408 $ hg tag -l lfoo
409 409 $ hg tag foo
410 410
411 411 $ cd ..
412 412 $ linkcp b c
413 413 $ cd c
414 414
415 415 $ hg tag -l -r 0 lbar
416 416 $ hg tag -r 0 bar
417 417
418 418 $ cat .hgtags
419 419 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo
420 420 430ed4828a74fa4047bc816a25500f7472ab4bfe bar
421 421
422 422 $ cat .hg/localtags
423 423 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo
424 424 430ed4828a74fa4047bc816a25500f7472ab4bfe lbar
425 425
426 426 $ cat ../b/.hgtags
427 427 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo
428 428
429 429 $ cat ../b/.hg/localtags
430 430 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo
431 431
432 432 $ cd ..
@@ -1,182 +1,182 b''
1 1 #require unix-permissions
2 2
3 3 test that new files created in .hg inherit the permissions from .hg/store
4 4
5 5 $ mkdir dir
6 6
7 7 just in case somebody has a strange $TMPDIR
8 8
9 9 $ chmod g-s dir
10 10 $ cd dir
11 11
12 12 $ cat >printmodes.py <<EOF
13 13 > from __future__ import absolute_import, print_function
14 14 > import os
15 15 > import sys
16 16 >
17 17 > allnames = []
18 18 > isdir = {}
19 19 > for root, dirs, files in os.walk(sys.argv[1]):
20 20 > for d in dirs:
21 21 > name = os.path.join(root, d)
22 22 > isdir[name] = 1
23 23 > allnames.append(name)
24 24 > for f in files:
25 25 > name = os.path.join(root, f)
26 26 > allnames.append(name)
27 27 > allnames.sort()
28 28 > for name in allnames:
29 29 > suffix = name in isdir and '/' or ''
30 30 > print('%05o %s%s' % (os.lstat(name).st_mode & 0o7777, name, suffix))
31 31 > EOF
32 32
33 33 $ cat >mode.py <<EOF
34 34 > from __future__ import absolute_import, print_function
35 35 > import os
36 36 > import sys
37 37 > print('%05o' % os.lstat(sys.argv[1]).st_mode)
38 38 > EOF
39 39
40 40 $ umask 077
41 41
42 42 $ hg init repo
43 43 $ cd repo
44 44
45 45 $ chmod 0770 .hg/store .hg/cache .hg/wcache
46 46
47 47 before commit
48 48 store can be written by the group, other files cannot
49 49 store is setgid
50 50
51 51 $ "$PYTHON" ../printmodes.py .
52 52 00700 ./.hg/
53 53 00600 ./.hg/00changelog.i
54 54 00770 ./.hg/cache/
55 55 00600 ./.hg/requires
56 56 00770 ./.hg/store/
57 57 00770 ./.hg/wcache/
58 58
59 59 $ mkdir dir
60 60 $ touch foo dir/bar
61 61 $ hg ci -qAm 'add files'
62 62
63 63 after commit
64 64 working dir files can only be written by the owner
65 65 files created in .hg can be written by the group
66 66 (in particular, store/**, dirstate, branch cache file, undo files)
67 67 new directories are setgid
68 68
69 69 $ "$PYTHON" ../printmodes.py .
70 70 00700 ./.hg/
71 71 00600 ./.hg/00changelog.i
72 72 00770 ./.hg/cache/
73 73 00660 ./.hg/cache/branch2-served
74 00660 ./.hg/cache/manifestfulltextcache (reporevlogstore !)
75 74 00660 ./.hg/cache/rbc-names-v1
76 75 00660 ./.hg/cache/rbc-revs-v1
77 76 00660 ./.hg/dirstate
78 77 00660 ./.hg/fsmonitor.state (fsmonitor !)
79 78 00660 ./.hg/last-message.txt
80 79 00600 ./.hg/requires
81 80 00770 ./.hg/store/
82 81 00660 ./.hg/store/00changelog.i
83 82 00660 ./.hg/store/00manifest.i
84 83 00770 ./.hg/store/data/
85 84 00770 ./.hg/store/data/dir/
86 85 00660 ./.hg/store/data/dir/bar.i (reporevlogstore !)
87 86 00660 ./.hg/store/data/foo.i (reporevlogstore !)
88 87 00770 ./.hg/store/data/dir/bar/ (reposimplestore !)
89 88 00660 ./.hg/store/data/dir/bar/b80de5d138758541c5f05265ad144ab9fa86d1db (reposimplestore !)
90 89 00660 ./.hg/store/data/dir/bar/index (reposimplestore !)
91 90 00770 ./.hg/store/data/foo/ (reposimplestore !)
92 91 00660 ./.hg/store/data/foo/b80de5d138758541c5f05265ad144ab9fa86d1db (reposimplestore !)
93 92 00660 ./.hg/store/data/foo/index (reposimplestore !)
94 93 00660 ./.hg/store/fncache (repofncache !)
95 94 00660 ./.hg/store/phaseroots
96 95 00660 ./.hg/store/undo
97 96 00660 ./.hg/store/undo.backupfiles
98 97 00660 ./.hg/store/undo.phaseroots
99 98 00660 ./.hg/undo.backup.dirstate
100 99 00660 ./.hg/undo.bookmarks
101 100 00660 ./.hg/undo.branch
102 101 00660 ./.hg/undo.desc
103 102 00660 ./.hg/undo.dirstate
104 103 00770 ./.hg/wcache/
105 104 00711 ./.hg/wcache/checkisexec
106 105 007.. ./.hg/wcache/checklink (re)
107 106 00600 ./.hg/wcache/checklink-target
107 00660 ./.hg/wcache/manifestfulltextcache (reporevlogstore !)
108 108 00700 ./dir/
109 109 00600 ./dir/bar
110 110 00600 ./foo
111 111
112 112 $ umask 007
113 113 $ hg init ../push
114 114
115 115 before push
116 116 group can write everything
117 117
118 118 $ "$PYTHON" ../printmodes.py ../push
119 119 00770 ../push/.hg/
120 120 00660 ../push/.hg/00changelog.i
121 121 00770 ../push/.hg/cache/
122 122 00660 ../push/.hg/requires
123 123 00770 ../push/.hg/store/
124 124 00770 ../push/.hg/wcache/
125 125
126 126 $ umask 077
127 127 $ hg -q push ../push
128 128
129 129 after push
130 130 group can still write everything
131 131
132 132 $ "$PYTHON" ../printmodes.py ../push
133 133 00770 ../push/.hg/
134 134 00660 ../push/.hg/00changelog.i
135 135 00770 ../push/.hg/cache/
136 136 00660 ../push/.hg/cache/branch2-base
137 137 00660 ../push/.hg/dirstate
138 138 00660 ../push/.hg/requires
139 139 00770 ../push/.hg/store/
140 140 00660 ../push/.hg/store/00changelog.i
141 141 00660 ../push/.hg/store/00manifest.i
142 142 00770 ../push/.hg/store/data/
143 143 00770 ../push/.hg/store/data/dir/
144 144 00660 ../push/.hg/store/data/dir/bar.i (reporevlogstore !)
145 145 00660 ../push/.hg/store/data/foo.i (reporevlogstore !)
146 146 00770 ../push/.hg/store/data/dir/bar/ (reposimplestore !)
147 147 00660 ../push/.hg/store/data/dir/bar/b80de5d138758541c5f05265ad144ab9fa86d1db (reposimplestore !)
148 148 00660 ../push/.hg/store/data/dir/bar/index (reposimplestore !)
149 149 00770 ../push/.hg/store/data/foo/ (reposimplestore !)
150 150 00660 ../push/.hg/store/data/foo/b80de5d138758541c5f05265ad144ab9fa86d1db (reposimplestore !)
151 151 00660 ../push/.hg/store/data/foo/index (reposimplestore !)
152 152 00660 ../push/.hg/store/fncache (repofncache !)
153 153 00660 ../push/.hg/store/undo
154 154 00660 ../push/.hg/store/undo.backupfiles
155 155 00660 ../push/.hg/store/undo.phaseroots
156 156 00660 ../push/.hg/undo.bookmarks
157 157 00660 ../push/.hg/undo.branch
158 158 00660 ../push/.hg/undo.desc
159 159 00660 ../push/.hg/undo.dirstate
160 160 00770 ../push/.hg/wcache/
161 161
162 162
163 163 Test that we don't lose the setgid bit when we call chmod.
164 164 Not all systems support setgid directories (e.g. HFS+), so
165 165 just check that directories have the same mode.
166 166
167 167 $ cd ..
168 168 $ hg init setgid
169 169 $ cd setgid
170 170 $ chmod g+rwx .hg/store
171 171 $ chmod g+s .hg/store 2> /dev/null || true
172 172 $ mkdir dir
173 173 $ touch dir/file
174 174 $ hg ci -qAm 'add dir/file'
175 175 $ storemode=`"$PYTHON" ../mode.py .hg/store`
176 176 $ dirmode=`"$PYTHON" ../mode.py .hg/store/data/dir`
177 177 $ if [ "$storemode" != "$dirmode" ]; then
178 178 > echo "$storemode != $dirmode"
179 179 > fi
180 180 $ cd ..
181 181
182 182 $ cd .. # g-s dir
@@ -1,481 +1,481 b''
1 1 $ echo "[extensions]" >> $HGRCPATH
2 2 $ echo "share = " >> $HGRCPATH
3 3
4 4 prepare repo1
5 5
6 6 $ hg init repo1
7 7 $ cd repo1
8 8 $ echo a > a
9 9 $ hg commit -A -m'init'
10 10 adding a
11 11
12 12 share it
13 13
14 14 $ cd ..
15 15 $ hg share repo1 repo2
16 16 updating working directory
17 17 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
18 18
19 19 share shouldn't have a store dir
20 20
21 21 $ cd repo2
22 22 $ test -d .hg/store
23 23 [1]
24 24
25 25 share shouldn't have a full cache dir, original repo should
26 26
27 27 $ hg branches
28 28 default 0:d3873e73d99e
29 29 $ hg tags
30 30 tip 0:d3873e73d99e
31 31 $ test -d .hg/cache
32 32 [1]
33 33 $ ls -1 .hg/wcache || true
34 34 checkisexec (execbit !)
35 35 checklink (symlink !)
36 36 checklink-target (symlink !)
37 manifestfulltextcache (reporevlogstore !)
37 38 $ ls -1 ../repo1/.hg/cache
38 39 branch2-served
39 manifestfulltextcache (reporevlogstore !)
40 40 rbc-names-v1
41 41 rbc-revs-v1
42 42 tags2-visible
43 43
44 44 Some sed versions appends newline, some don't, and some just fails
45 45
46 46 $ cat .hg/sharedpath; echo
47 47 $TESTTMP/repo1/.hg
48 48
49 49 trailing newline on .hg/sharedpath is ok
50 50 $ hg tip -q
51 51 0:d3873e73d99e
52 52 $ echo '' >> .hg/sharedpath
53 53 $ cat .hg/sharedpath
54 54 $TESTTMP/repo1/.hg
55 55 $ hg tip -q
56 56 0:d3873e73d99e
57 57
58 58 commit in shared clone
59 59
60 60 $ echo a >> a
61 61 $ hg commit -m'change in shared clone'
62 62
63 63 check original
64 64
65 65 $ cd ../repo1
66 66 $ hg log
67 67 changeset: 1:8af4dc49db9e
68 68 tag: tip
69 69 user: test
70 70 date: Thu Jan 01 00:00:00 1970 +0000
71 71 summary: change in shared clone
72 72
73 73 changeset: 0:d3873e73d99e
74 74 user: test
75 75 date: Thu Jan 01 00:00:00 1970 +0000
76 76 summary: init
77 77
78 78 $ hg update
79 79 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
80 80 $ cat a # should be two lines of "a"
81 81 a
82 82 a
83 83
84 84 commit in original
85 85
86 86 $ echo b > b
87 87 $ hg commit -A -m'another file'
88 88 adding b
89 89
90 90 check in shared clone
91 91
92 92 $ cd ../repo2
93 93 $ hg log
94 94 changeset: 2:c2e0ac586386
95 95 tag: tip
96 96 user: test
97 97 date: Thu Jan 01 00:00:00 1970 +0000
98 98 summary: another file
99 99
100 100 changeset: 1:8af4dc49db9e
101 101 user: test
102 102 date: Thu Jan 01 00:00:00 1970 +0000
103 103 summary: change in shared clone
104 104
105 105 changeset: 0:d3873e73d99e
106 106 user: test
107 107 date: Thu Jan 01 00:00:00 1970 +0000
108 108 summary: init
109 109
110 110 $ hg update
111 111 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
112 112 $ cat b # should exist with one "b"
113 113 b
114 114
115 115 hg serve shared clone
116 116
117 117 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid
118 118 $ cat hg.pid >> $DAEMON_PIDS
119 119 $ get-with-headers.py localhost:$HGPORT 'raw-file/'
120 120 200 Script output follows
121 121
122 122
123 123 -rw-r--r-- 4 a
124 124 -rw-r--r-- 2 b
125 125
126 126
127 127 Cloning a shared repo via bundle2 results in a non-shared clone
128 128
129 129 $ cd ..
130 130 $ hg clone -q --stream --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/`pwd`/repo2 cloned-via-bundle2
131 131 $ cat ./cloned-via-bundle2/.hg/requires | grep "shared"
132 132 [1]
133 133 $ hg id --cwd cloned-via-bundle2 -r tip
134 134 c2e0ac586386 tip
135 135 $ cd repo2
136 136
137 137 test unshare command
138 138
139 139 $ hg unshare
140 140 $ test -d .hg/store
141 141 $ test -f .hg/sharedpath
142 142 [1]
143 143 $ grep shared .hg/requires
144 144 [1]
145 145 $ hg unshare
146 146 abort: this is not a shared repo
147 147 [255]
148 148
149 149 check that a change does not propagate
150 150
151 151 $ echo b >> b
152 152 $ hg commit -m'change in unshared'
153 153 $ cd ../repo1
154 154 $ hg id -r tip
155 155 c2e0ac586386 tip
156 156
157 157 $ cd ..
158 158
159 159
160 160 test sharing bookmarks
161 161
162 162 $ hg share -B repo1 repo3
163 163 updating working directory
164 164 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
165 165 $ cd repo1
166 166 $ hg bookmark bm1
167 167 $ hg bookmarks
168 168 * bm1 2:c2e0ac586386
169 169 $ cd ../repo2
170 170 $ hg book bm2
171 171 $ hg bookmarks
172 172 * bm2 3:0e6e70d1d5f1
173 173 $ cd ../repo3
174 174 $ hg bookmarks
175 175 bm1 2:c2e0ac586386
176 176 $ hg book bm3
177 177 $ hg bookmarks
178 178 bm1 2:c2e0ac586386
179 179 * bm3 2:c2e0ac586386
180 180 $ cd ../repo1
181 181 $ hg bookmarks
182 182 * bm1 2:c2e0ac586386
183 183 bm3 2:c2e0ac586386
184 184
185 185 check whether HG_PENDING makes pending changes only in relatd
186 186 repositories visible to an external hook.
187 187
188 188 In "hg share" case, another transaction can't run in other
189 189 repositories sharing same source repository, because starting
190 190 transaction requires locking store of source repository.
191 191
192 192 Therefore, this test scenario ignores checking visibility of
193 193 .hg/bookmakrs.pending in repo2, which shares repo1 without bookmarks.
194 194
195 195 $ cat > $TESTTMP/checkbookmarks.sh <<EOF
196 196 > echo "@repo1"
197 197 > hg -R "$TESTTMP/repo1" bookmarks
198 198 > echo "@repo2"
199 199 > hg -R "$TESTTMP/repo2" bookmarks
200 200 > echo "@repo3"
201 201 > hg -R "$TESTTMP/repo3" bookmarks
202 202 > exit 1 # to avoid adding new bookmark for subsequent tests
203 203 > EOF
204 204
205 205 $ cd ../repo1
206 206 $ hg --config hooks.pretxnclose="sh $TESTTMP/checkbookmarks.sh" -q book bmX
207 207 @repo1
208 208 bm1 2:c2e0ac586386
209 209 bm3 2:c2e0ac586386
210 210 * bmX 2:c2e0ac586386
211 211 @repo2
212 212 * bm2 3:0e6e70d1d5f1
213 213 @repo3
214 214 bm1 2:c2e0ac586386
215 215 * bm3 2:c2e0ac586386
216 216 bmX 2:c2e0ac586386
217 217 transaction abort!
218 218 rollback completed
219 219 abort: pretxnclose hook exited with status 1
220 220 [255]
221 221 $ hg book bm1
222 222
223 223 FYI, in contrast to above test, bmX is invisible in repo1 (= shared
224 224 src), because (1) HG_PENDING refers only repo3 and (2)
225 225 "bookmarks.pending" is written only into repo3.
226 226
227 227 $ cd ../repo3
228 228 $ hg --config hooks.pretxnclose="sh $TESTTMP/checkbookmarks.sh" -q book bmX
229 229 @repo1
230 230 * bm1 2:c2e0ac586386
231 231 bm3 2:c2e0ac586386
232 232 @repo2
233 233 * bm2 3:0e6e70d1d5f1
234 234 @repo3
235 235 bm1 2:c2e0ac586386
236 236 bm3 2:c2e0ac586386
237 237 * bmX 2:c2e0ac586386
238 238 transaction abort!
239 239 rollback completed
240 240 abort: pretxnclose hook exited with status 1
241 241 [255]
242 242 $ hg book bm3
243 243
244 244 $ cd ../repo1
245 245
246 246 test that commits work
247 247
248 248 $ echo 'shared bookmarks' > a
249 249 $ hg commit -m 'testing shared bookmarks'
250 250 $ hg bookmarks
251 251 * bm1 3:b87954705719
252 252 bm3 2:c2e0ac586386
253 253 $ cd ../repo3
254 254 $ hg bookmarks
255 255 bm1 3:b87954705719
256 256 * bm3 2:c2e0ac586386
257 257 $ echo 'more shared bookmarks' > a
258 258 $ hg commit -m 'testing shared bookmarks'
259 259 created new head
260 260 $ hg bookmarks
261 261 bm1 3:b87954705719
262 262 * bm3 4:62f4ded848e4
263 263 $ cd ../repo1
264 264 $ hg bookmarks
265 265 * bm1 3:b87954705719
266 266 bm3 4:62f4ded848e4
267 267 $ cd ..
268 268
269 269 non largefiles repos won't enable largefiles
270 270
271 271 $ hg share --config extensions.largefiles= repo3 sharedrepo
272 272 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
273 273 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
274 274 updating working directory
275 275 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
276 276 $ [ -f sharedrepo/.hg/hgrc ]
277 277 [1]
278 278
279 279 test pushing bookmarks works
280 280
281 281 $ hg clone repo3 repo4
282 282 updating to branch default
283 283 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
284 284 $ cd repo4
285 285 $ hg boo bm4
286 286 $ echo foo > b
287 287 $ hg commit -m 'foo in b'
288 288 $ hg boo
289 289 bm1 3:b87954705719
290 290 bm3 4:62f4ded848e4
291 291 * bm4 5:92793bfc8cad
292 292 $ hg push -B bm4
293 293 pushing to $TESTTMP/repo3
294 294 searching for changes
295 295 adding changesets
296 296 adding manifests
297 297 adding file changes
298 298 added 1 changesets with 1 changes to 1 files
299 299 exporting bookmark bm4
300 300 $ cd ../repo1
301 301 $ hg bookmarks
302 302 * bm1 3:b87954705719
303 303 bm3 4:62f4ded848e4
304 304 bm4 5:92793bfc8cad
305 305 $ cd ../repo3
306 306 $ hg bookmarks
307 307 bm1 3:b87954705719
308 308 * bm3 4:62f4ded848e4
309 309 bm4 5:92793bfc8cad
310 310 $ cd ..
311 311
312 312 test behavior when sharing a shared repo
313 313
314 314 $ hg share -B repo3 missingdir/repo5
315 315 updating working directory
316 316 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
317 317 $ cd missingdir/repo5
318 318 $ hg book
319 319 bm1 3:b87954705719
320 320 bm3 4:62f4ded848e4
321 321 bm4 5:92793bfc8cad
322 322 $ cd ../..
323 323
324 324 test what happens when an active bookmark is deleted
325 325
326 326 $ cd repo1
327 327 $ hg boo -d bm3
328 328 $ hg boo
329 329 * bm1 3:b87954705719
330 330 bm4 5:92793bfc8cad
331 331 $ cd ../repo3
332 332 $ hg boo
333 333 bm1 3:b87954705719
334 334 bm4 5:92793bfc8cad
335 335 $ cd ..
336 336
337 337 verify that bookmarks are not written on failed transaction
338 338
339 339 $ cat > failpullbookmarks.py << EOF
340 340 > """A small extension that makes bookmark pulls fail, for testing"""
341 341 > from __future__ import absolute_import
342 342 > from mercurial import (
343 343 > error,
344 344 > exchange,
345 345 > extensions,
346 346 > )
347 347 > def _pullbookmarks(orig, pullop):
348 348 > orig(pullop)
349 349 > raise error.HookAbort('forced failure by extension')
350 350 > def extsetup(ui):
351 351 > extensions.wrapfunction(exchange, '_pullbookmarks', _pullbookmarks)
352 352 > EOF
353 353 $ cd repo4
354 354 $ hg boo
355 355 bm1 3:b87954705719
356 356 bm3 4:62f4ded848e4
357 357 * bm4 5:92793bfc8cad
358 358 $ cd ../repo3
359 359 $ hg boo
360 360 bm1 3:b87954705719
361 361 bm4 5:92793bfc8cad
362 362 $ hg --config "extensions.failpullbookmarks=$TESTTMP/failpullbookmarks.py" pull $TESTTMP/repo4
363 363 pulling from $TESTTMP/repo4
364 364 searching for changes
365 365 no changes found
366 366 adding remote bookmark bm3
367 367 abort: forced failure by extension
368 368 [255]
369 369 $ hg boo
370 370 bm1 3:b87954705719
371 371 bm4 5:92793bfc8cad
372 372 $ hg pull $TESTTMP/repo4
373 373 pulling from $TESTTMP/repo4
374 374 searching for changes
375 375 no changes found
376 376 adding remote bookmark bm3
377 377 1 local changesets published
378 378 $ hg boo
379 379 bm1 3:b87954705719
380 380 * bm3 4:62f4ded848e4
381 381 bm4 5:92793bfc8cad
382 382 $ cd ..
383 383
384 384 verify bookmark behavior after unshare
385 385
386 386 $ cd repo3
387 387 $ hg unshare
388 388 $ hg boo
389 389 bm1 3:b87954705719
390 390 * bm3 4:62f4ded848e4
391 391 bm4 5:92793bfc8cad
392 392 $ hg boo -d bm4
393 393 $ hg boo bm5
394 394 $ hg boo
395 395 bm1 3:b87954705719
396 396 bm3 4:62f4ded848e4
397 397 * bm5 4:62f4ded848e4
398 398 $ cd ../repo1
399 399 $ hg boo
400 400 * bm1 3:b87954705719
401 401 bm3 4:62f4ded848e4
402 402 bm4 5:92793bfc8cad
403 403 $ cd ..
404 404
405 405 test shared clones using relative paths work
406 406
407 407 $ mkdir thisdir
408 408 $ hg init thisdir/orig
409 409 $ hg share -U thisdir/orig thisdir/abs
410 410 $ hg share -U --relative thisdir/abs thisdir/rel
411 411 $ cat thisdir/rel/.hg/sharedpath
412 412 ../../orig/.hg (no-eol)
413 413 $ grep shared thisdir/*/.hg/requires
414 414 thisdir/abs/.hg/requires:shared
415 415 thisdir/rel/.hg/requires:relshared
416 416 thisdir/rel/.hg/requires:shared
417 417
418 418 test that relative shared paths aren't relative to $PWD
419 419
420 420 $ cd thisdir
421 421 $ hg -R rel root
422 422 $TESTTMP/thisdir/rel
423 423 $ cd ..
424 424
425 425 now test that relative paths really are relative, survive across
426 426 renames and changes of PWD
427 427
428 428 $ hg -R thisdir/abs root
429 429 $TESTTMP/thisdir/abs
430 430 $ hg -R thisdir/rel root
431 431 $TESTTMP/thisdir/rel
432 432 $ mv thisdir thatdir
433 433 $ hg -R thatdir/abs root
434 434 abort: .hg/sharedpath points to nonexistent directory $TESTTMP/thisdir/orig/.hg!
435 435 [255]
436 436 $ hg -R thatdir/rel root
437 437 $TESTTMP/thatdir/rel
438 438
439 439 test unshare relshared repo
440 440
441 441 $ cd thatdir/rel
442 442 $ hg unshare
443 443 $ test -d .hg/store
444 444 $ test -f .hg/sharedpath
445 445 [1]
446 446 $ grep shared .hg/requires
447 447 [1]
448 448 $ hg unshare
449 449 abort: this is not a shared repo
450 450 [255]
451 451 $ cd ../..
452 452
453 453 $ rm -r thatdir
454 454
455 455 Demonstrate buggy behavior around requirements validation
456 456 See comment in localrepo.py:makelocalrepository() for more.
457 457
458 458 $ hg init sharenewrequires
459 459 $ hg share sharenewrequires shareoldrequires
460 460 updating working directory
461 461 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
462 462
463 463 $ cat >> sharenewrequires/.hg/requires << EOF
464 464 > missing-requirement
465 465 > EOF
466 466
467 467 We cannot open the repo with the unknown requirement
468 468
469 469 $ hg -R sharenewrequires status
470 470 abort: repository requires features unknown to this Mercurial: missing-requirement!
471 471 (see https://mercurial-scm.org/wiki/MissingRequirement for more information)
472 472 [255]
473 473
474 474 BUG: we don't get the same error when opening the shared repo pointing to it
475 475
476 476 $ hg -R shareoldrequires status
477 477
478 478 Explicitly kill daemons to let the test exit on Windows
479 479
480 480 $ killdaemons.py
481 481
@@ -1,1996 +1,1997 b''
1 1 Let commit recurse into subrepos by default to match pre-2.0 behavior:
2 2
3 3 $ echo "[ui]" >> $HGRCPATH
4 4 $ echo "commitsubrepos = Yes" >> $HGRCPATH
5 5
6 6 $ hg init t
7 7 $ cd t
8 8
9 9 first revision, no sub
10 10
11 11 $ echo a > a
12 12 $ hg ci -Am0
13 13 adding a
14 14
15 15 add first sub
16 16
17 17 $ echo s = s > .hgsub
18 18 $ hg add .hgsub
19 19 $ hg init s
20 20 $ echo a > s/a
21 21
22 22 Issue2232: committing a subrepo without .hgsub
23 23
24 24 $ hg ci -mbad s
25 25 abort: can't commit subrepos without .hgsub
26 26 [255]
27 27
28 28 $ hg -R s add s/a
29 29 $ hg files -S
30 30 .hgsub
31 31 a
32 32 s/a
33 33
34 34 `hg files` respects ui.relative-paths
35 35 BROKEN: shows subrepo paths relative to the subrepo
36 36 $ hg files -S --config ui.relative-paths=no
37 37 .hgsub
38 38 a
39 39 s/a
40 40
41 41 $ hg -R s ci -Ams0
42 42 $ hg sum
43 43 parent: 0:f7b1eb17ad24 tip
44 44 0
45 45 branch: default
46 46 commit: 1 added, 1 subrepos
47 47 update: (current)
48 48 phases: 1 draft
49 49 $ hg ci -m1
50 50
51 51 test handling .hgsubstate "added" explicitly.
52 52
53 53 $ hg parents --template '{node}\n{files}\n'
54 54 7cf8cfea66e410e8e3336508dfeec07b3192de51
55 55 .hgsub .hgsubstate
56 56 $ hg rollback -q
57 57 $ hg add .hgsubstate
58 58 $ hg ci -m1
59 59 $ hg parents --template '{node}\n{files}\n'
60 60 7cf8cfea66e410e8e3336508dfeec07b3192de51
61 61 .hgsub .hgsubstate
62 62
63 63 Subrepopath which overlaps with filepath, does not change warnings in remove()
64 64
65 65 $ mkdir snot
66 66 $ touch snot/file
67 67 $ hg remove -S snot/file
68 68 not removing snot/file: file is untracked
69 69 [1]
70 70 $ hg cat snot/filenot
71 71 snot/filenot: no such file in rev 7cf8cfea66e4
72 72 [1]
73 73 $ rm -r snot
74 74
75 75 Revert subrepo and test subrepo fileset keyword:
76 76
77 77 $ echo b > s/a
78 78 $ hg revert --dry-run "set:subrepo('glob:s*')"
79 79 reverting subrepo s
80 80 reverting s/a
81 81 $ cat s/a
82 82 b
83 83 $ hg revert "set:subrepo('glob:s*')"
84 84 reverting subrepo s
85 85 reverting s/a
86 86 $ cat s/a
87 87 a
88 88 $ rm s/a.orig
89 89
90 90 Revert subrepo with no backup. The "reverting s/a" line is gone since
91 91 we're really running 'hg update' in the subrepo:
92 92
93 93 $ echo b > s/a
94 94 $ hg revert --no-backup s
95 95 reverting subrepo s
96 96
97 97 Issue2022: update -C
98 98
99 99 $ echo b > s/a
100 100 $ hg sum
101 101 parent: 1:7cf8cfea66e4 tip
102 102 1
103 103 branch: default
104 104 commit: 1 subrepos
105 105 update: (current)
106 106 phases: 2 draft
107 107 $ hg co -C 1
108 108 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
109 109 $ hg sum
110 110 parent: 1:7cf8cfea66e4 tip
111 111 1
112 112 branch: default
113 113 commit: (clean)
114 114 update: (current)
115 115 phases: 2 draft
116 116
117 117 commands that require a clean repo should respect subrepos
118 118
119 119 $ echo b >> s/a
120 120 $ hg backout tip
121 121 abort: uncommitted changes in subrepository "s"
122 122 [255]
123 123 $ hg revert -C -R s s/a
124 124
125 125 add sub sub
126 126
127 127 $ echo ss = ss > s/.hgsub
128 128 $ hg init s/ss
129 129 $ echo a > s/ss/a
130 130 $ hg -R s add s/.hgsub
131 131 $ hg -R s/ss add s/ss/a
132 132 $ hg sum
133 133 parent: 1:7cf8cfea66e4 tip
134 134 1
135 135 branch: default
136 136 commit: 1 subrepos
137 137 update: (current)
138 138 phases: 2 draft
139 139 $ hg ci -m2
140 140 committing subrepository s
141 141 committing subrepository s/ss
142 142 $ hg sum
143 143 parent: 2:df30734270ae tip
144 144 2
145 145 branch: default
146 146 commit: (clean)
147 147 update: (current)
148 148 phases: 3 draft
149 149
150 150 test handling .hgsubstate "modified" explicitly.
151 151
152 152 $ hg parents --template '{node}\n{files}\n'
153 153 df30734270ae757feb35e643b7018e818e78a9aa
154 154 .hgsubstate
155 155 $ hg rollback -q
156 156 $ hg status -A .hgsubstate
157 157 M .hgsubstate
158 158 $ hg ci -m2
159 159 $ hg parents --template '{node}\n{files}\n'
160 160 df30734270ae757feb35e643b7018e818e78a9aa
161 161 .hgsubstate
162 162
163 163 bump sub rev (and check it is ignored by ui.commitsubrepos)
164 164
165 165 $ echo b > s/a
166 166 $ hg -R s ci -ms1
167 167 $ hg --config ui.commitsubrepos=no ci -m3
168 168
169 169 leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
170 170
171 171 $ echo c > s/a
172 172 $ hg --config ui.commitsubrepos=no ci -m4
173 173 abort: uncommitted changes in subrepository "s"
174 174 (use --subrepos for recursive commit)
175 175 [255]
176 176 $ hg id
177 177 f6affe3fbfaa+ tip
178 178 $ hg -R s ci -mc
179 179 $ hg id
180 180 f6affe3fbfaa+ tip
181 181 $ echo d > s/a
182 182 $ hg ci -m4
183 183 committing subrepository s
184 184 $ hg tip -R s
185 185 changeset: 4:02dcf1d70411
186 186 tag: tip
187 187 user: test
188 188 date: Thu Jan 01 00:00:00 1970 +0000
189 189 summary: 4
190 190
191 191
192 192 check caching
193 193
194 194 $ hg co 0
195 195 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
196 196 $ hg debugsub
197 197
198 198 restore
199 199
200 200 $ hg co
201 201 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
202 202 $ hg debugsub
203 203 path s
204 204 source s
205 205 revision 02dcf1d704118aee3ee306ccfa1910850d5b05ef
206 206
207 207 new branch for merge tests
208 208
209 209 $ hg co 1
210 210 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
211 211 $ echo t = t >> .hgsub
212 212 $ hg init t
213 213 $ echo t > t/t
214 214 $ hg -R t add t
215 215 adding t/t
216 216
217 217 5
218 218
219 219 $ hg ci -m5 # add sub
220 220 committing subrepository t
221 221 created new head
222 222 $ echo t2 > t/t
223 223
224 224 6
225 225
226 226 $ hg st -R s
227 227 $ hg ci -m6 # change sub
228 228 committing subrepository t
229 229 $ hg debugsub
230 230 path s
231 231 source s
232 232 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
233 233 path t
234 234 source t
235 235 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
236 236 $ echo t3 > t/t
237 237
238 238 7
239 239
240 240 $ hg ci -m7 # change sub again for conflict test
241 241 committing subrepository t
242 242 $ hg rm .hgsub
243 243
244 244 8
245 245
246 246 $ hg ci -m8 # remove sub
247 247
248 248 test handling .hgsubstate "removed" explicitly.
249 249
250 250 $ hg parents --template '{node}\n{files}\n'
251 251 96615c1dad2dc8e3796d7332c77ce69156f7b78e
252 252 .hgsub .hgsubstate
253 253 $ hg rollback -q
254 254 $ hg remove .hgsubstate
255 255 $ hg ci -m8
256 256 $ hg parents --template '{node}\n{files}\n'
257 257 96615c1dad2dc8e3796d7332c77ce69156f7b78e
258 258 .hgsub .hgsubstate
259 259
260 260 merge tests
261 261
262 262 $ hg co -C 3
263 263 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
264 264 $ hg merge 5 # test adding
265 265 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
266 266 (branch merge, don't forget to commit)
267 267 $ hg debugsub
268 268 path s
269 269 source s
270 270 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
271 271 path t
272 272 source t
273 273 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
274 274 $ hg ci -m9
275 275 created new head
276 276 $ hg merge 6 --debug # test change
277 277 searching for copies back to rev 2
278 278 resolving manifests
279 279 branchmerge: True, force: False, partial: False
280 280 ancestor: 1f14a2e2d3ec, local: f0d2028bf86d+, remote: 1831e14459c4
281 281 starting 4 threads for background file closing (?)
282 282 .hgsubstate: versions differ -> m (premerge)
283 283 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
284 284 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
285 285 getting subrepo t
286 286 resolving manifests
287 287 branchmerge: False, force: False, partial: False
288 288 ancestor: 60ca1237c194, local: 60ca1237c194+, remote: 6747d179aa9a
289 289 t: remote is newer -> g
290 290 getting t
291 291 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
292 292 (branch merge, don't forget to commit)
293 293 $ hg debugsub
294 294 path s
295 295 source s
296 296 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
297 297 path t
298 298 source t
299 299 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
300 300 $ echo conflict > t/t
301 301 $ hg ci -m10
302 302 committing subrepository t
303 303 $ HGMERGE=internal:merge hg merge --debug 7 # test conflict
304 304 searching for copies back to rev 2
305 305 resolving manifests
306 306 branchmerge: True, force: False, partial: False
307 307 ancestor: 1831e14459c4, local: e45c8b14af55+, remote: f94576341bcf
308 308 starting 4 threads for background file closing (?)
309 309 .hgsubstate: versions differ -> m (premerge)
310 310 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
311 311 subrepo t: both sides changed
312 312 subrepository t diverged (local revision: 20a0db6fbf6c, remote revision: 7af322bc1198)
313 313 starting 4 threads for background file closing (?)
314 314 (M)erge, keep (l)ocal [working copy] or keep (r)emote [merge rev]? m
315 315 merging subrepository "t"
316 316 searching for copies back to rev 2
317 317 resolving manifests
318 318 branchmerge: True, force: False, partial: False
319 319 ancestor: 6747d179aa9a, local: 20a0db6fbf6c+, remote: 7af322bc1198
320 320 preserving t for resolve of t
321 321 starting 4 threads for background file closing (?)
322 322 t: versions differ -> m (premerge)
323 323 picked tool ':merge' for t (binary False symlink False changedelete False)
324 324 merging t
325 325 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
326 326 t: versions differ -> m (merge)
327 327 picked tool ':merge' for t (binary False symlink False changedelete False)
328 328 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
329 329 warning: conflicts while merging t! (edit, then use 'hg resolve --mark')
330 330 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
331 331 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
332 332 subrepo t: merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
333 333 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
334 334 (branch merge, don't forget to commit)
335 335
336 336 should conflict
337 337
338 338 $ cat t/t
339 339 <<<<<<< local: 20a0db6fbf6c - test: 10
340 340 conflict
341 341 =======
342 342 t3
343 343 >>>>>>> other: 7af322bc1198 - test: 7
344 344
345 345 11: remove subrepo t
346 346
347 347 $ hg co -C 5
348 348 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
349 349 $ hg revert -r 4 .hgsub # remove t
350 350 $ hg ci -m11
351 351 created new head
352 352 $ hg debugsub
353 353 path s
354 354 source s
355 355 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
356 356
357 357 local removed, remote changed, keep changed
358 358
359 359 $ hg merge 6
360 360 remote [merge rev] changed subrepository t which local [working copy] removed
361 361 use (c)hanged version or (d)elete? c
362 362 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
363 363 (branch merge, don't forget to commit)
364 364 BROKEN: should include subrepo t
365 365 $ hg debugsub
366 366 path s
367 367 source s
368 368 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
369 369 $ cat .hgsubstate
370 370 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
371 371 6747d179aa9a688023c4b0cad32e4c92bb7f34ad t
372 372 $ hg ci -m 'local removed, remote changed, keep changed'
373 373 BROKEN: should include subrepo t
374 374 $ hg debugsub
375 375 path s
376 376 source s
377 377 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
378 378 BROKEN: should include subrepo t
379 379 $ cat .hgsubstate
380 380 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
381 381 $ cat t/t
382 382 t2
383 383
384 384 local removed, remote changed, keep removed
385 385
386 386 $ hg co -C 11
387 387 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
388 388 $ hg merge --config ui.interactive=true 6 <<EOF
389 389 > d
390 390 > EOF
391 391 remote [merge rev] changed subrepository t which local [working copy] removed
392 392 use (c)hanged version or (d)elete? d
393 393 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
394 394 (branch merge, don't forget to commit)
395 395 $ hg debugsub
396 396 path s
397 397 source s
398 398 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
399 399 $ cat .hgsubstate
400 400 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
401 401 $ hg ci -m 'local removed, remote changed, keep removed'
402 402 created new head
403 403 $ hg debugsub
404 404 path s
405 405 source s
406 406 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
407 407 $ cat .hgsubstate
408 408 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
409 409
410 410 local changed, remote removed, keep changed
411 411
412 412 $ hg co -C 6
413 413 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
414 414 $ hg merge 11
415 415 local [working copy] changed subrepository t which remote [merge rev] removed
416 416 use (c)hanged version or (d)elete? c
417 417 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
418 418 (branch merge, don't forget to commit)
419 419 BROKEN: should include subrepo t
420 420 $ hg debugsub
421 421 path s
422 422 source s
423 423 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
424 424 BROKEN: should include subrepo t
425 425 $ cat .hgsubstate
426 426 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
427 427 $ hg ci -m 'local changed, remote removed, keep changed'
428 428 created new head
429 429 BROKEN: should include subrepo t
430 430 $ hg debugsub
431 431 path s
432 432 source s
433 433 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
434 434 BROKEN: should include subrepo t
435 435 $ cat .hgsubstate
436 436 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
437 437 $ cat t/t
438 438 t2
439 439
440 440 local changed, remote removed, keep removed
441 441
442 442 $ hg co -C 6
443 443 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
444 444 $ hg merge --config ui.interactive=true 11 <<EOF
445 445 > d
446 446 > EOF
447 447 local [working copy] changed subrepository t which remote [merge rev] removed
448 448 use (c)hanged version or (d)elete? d
449 449 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
450 450 (branch merge, don't forget to commit)
451 451 $ hg debugsub
452 452 path s
453 453 source s
454 454 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
455 455 $ cat .hgsubstate
456 456 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
457 457 $ hg ci -m 'local changed, remote removed, keep removed'
458 458 created new head
459 459 $ hg debugsub
460 460 path s
461 461 source s
462 462 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
463 463 $ cat .hgsubstate
464 464 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
465 465
466 466 clean up to avoid having to fix up the tests below
467 467
468 468 $ hg co -C 10
469 469 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
470 470 $ cat >> $HGRCPATH <<EOF
471 471 > [extensions]
472 472 > strip=
473 473 > EOF
474 474 $ hg strip -r 11:15
475 475 saved backup bundle to $TESTTMP/t/.hg/strip-backup/*-backup.hg (glob)
476 476
477 477 clone
478 478
479 479 $ cd ..
480 480 $ hg clone t tc
481 481 updating to branch default
482 482 cloning subrepo s from $TESTTMP/t/s
483 483 cloning subrepo s/ss from $TESTTMP/t/s/ss
484 484 cloning subrepo t from $TESTTMP/t/t
485 485 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
486 486 $ cd tc
487 487 $ hg debugsub
488 488 path s
489 489 source s
490 490 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
491 491 path t
492 492 source t
493 493 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
494 494 $ cd ..
495 495
496 496 clone with subrepo disabled (update should fail)
497 497
498 498 $ hg clone t -U tc2 --config subrepos.allowed=false
499 499 $ hg update -R tc2 --config subrepos.allowed=false
500 500 abort: subrepos not enabled
501 501 (see 'hg help config.subrepos' for details)
502 502 [255]
503 503 $ ls tc2
504 504 a
505 505
506 506 $ hg clone t tc3 --config subrepos.allowed=false
507 507 updating to branch default
508 508 abort: subrepos not enabled
509 509 (see 'hg help config.subrepos' for details)
510 510 [255]
511 511 $ ls tc3
512 512 a
513 513
514 514 And again with just the hg type disabled
515 515
516 516 $ hg clone t -U tc4 --config subrepos.hg:allowed=false
517 517 $ hg update -R tc4 --config subrepos.hg:allowed=false
518 518 abort: hg subrepos not allowed
519 519 (see 'hg help config.subrepos' for details)
520 520 [255]
521 521 $ ls tc4
522 522 a
523 523
524 524 $ hg clone t tc5 --config subrepos.hg:allowed=false
525 525 updating to branch default
526 526 abort: hg subrepos not allowed
527 527 (see 'hg help config.subrepos' for details)
528 528 [255]
529 529 $ ls tc5
530 530 a
531 531
532 532 push
533 533
534 534 $ cd tc
535 535 $ echo bah > t/t
536 536 $ hg ci -m11
537 537 committing subrepository t
538 538 $ hg push
539 539 pushing to $TESTTMP/t
540 540 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss
541 541 no changes made to subrepo s since last push to $TESTTMP/t/s
542 542 pushing subrepo t to $TESTTMP/t/t
543 543 searching for changes
544 544 adding changesets
545 545 adding manifests
546 546 adding file changes
547 547 added 1 changesets with 1 changes to 1 files
548 548 searching for changes
549 549 adding changesets
550 550 adding manifests
551 551 adding file changes
552 552 added 1 changesets with 1 changes to 1 files
553 553
554 554 push -f
555 555
556 556 $ echo bah > s/a
557 557 $ hg ci -m12
558 558 committing subrepository s
559 559 $ hg push
560 560 pushing to $TESTTMP/t
561 561 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss
562 562 pushing subrepo s to $TESTTMP/t/s
563 563 searching for changes
564 564 abort: push creates new remote head 12a213df6fa9! (in subrepository "s")
565 565 (merge or see 'hg help push' for details about pushing new heads)
566 566 [255]
567 567 $ hg push -f
568 568 pushing to $TESTTMP/t
569 569 pushing subrepo s/ss to $TESTTMP/t/s/ss
570 570 searching for changes
571 571 no changes found
572 572 pushing subrepo s to $TESTTMP/t/s
573 573 searching for changes
574 574 adding changesets
575 575 adding manifests
576 576 adding file changes
577 577 added 1 changesets with 1 changes to 1 files (+1 heads)
578 578 pushing subrepo t to $TESTTMP/t/t
579 579 searching for changes
580 580 no changes found
581 581 searching for changes
582 582 adding changesets
583 583 adding manifests
584 584 adding file changes
585 585 added 1 changesets with 1 changes to 1 files
586 586
587 587 check that unmodified subrepos are not pushed
588 588
589 589 $ hg clone . ../tcc
590 590 updating to branch default
591 591 cloning subrepo s from $TESTTMP/tc/s
592 592 cloning subrepo s/ss from $TESTTMP/tc/s/ss
593 593 cloning subrepo t from $TESTTMP/tc/t
594 594 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
595 595
596 596 the subrepos on the new clone have nothing to push to its source
597 597
598 598 $ hg push -R ../tcc .
599 599 pushing to .
600 600 no changes made to subrepo s/ss since last push to s/ss
601 601 no changes made to subrepo s since last push to s
602 602 no changes made to subrepo t since last push to t
603 603 searching for changes
604 604 no changes found
605 605 [1]
606 606
607 607 the subrepos on the source do not have a clean store versus the clone target
608 608 because they were never explicitly pushed to the source
609 609
610 610 $ hg push ../tcc
611 611 pushing to ../tcc
612 612 pushing subrepo s/ss to ../tcc/s/ss
613 613 searching for changes
614 614 no changes found
615 615 pushing subrepo s to ../tcc/s
616 616 searching for changes
617 617 no changes found
618 618 pushing subrepo t to ../tcc/t
619 619 searching for changes
620 620 no changes found
621 621 searching for changes
622 622 no changes found
623 623 [1]
624 624
625 625 after push their stores become clean
626 626
627 627 $ hg push ../tcc
628 628 pushing to ../tcc
629 629 no changes made to subrepo s/ss since last push to ../tcc/s/ss
630 630 no changes made to subrepo s since last push to ../tcc/s
631 631 no changes made to subrepo t since last push to ../tcc/t
632 632 searching for changes
633 633 no changes found
634 634 [1]
635 635
636 636 updating a subrepo to a different revision or changing
637 637 its working directory does not make its store dirty
638 638
639 639 $ hg -R s update '.^'
640 640 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
641 641 $ hg push
642 642 pushing to $TESTTMP/t
643 643 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss
644 644 no changes made to subrepo s since last push to $TESTTMP/t/s
645 645 no changes made to subrepo t since last push to $TESTTMP/t/t
646 646 searching for changes
647 647 no changes found
648 648 [1]
649 649 $ echo foo >> s/a
650 650 $ hg push
651 651 pushing to $TESTTMP/t
652 652 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss
653 653 no changes made to subrepo s since last push to $TESTTMP/t/s
654 654 no changes made to subrepo t since last push to $TESTTMP/t/t
655 655 searching for changes
656 656 no changes found
657 657 [1]
658 658 $ hg -R s update -C tip
659 659 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
660 660
661 661 committing into a subrepo makes its store (but not its parent's store) dirty
662 662
663 663 $ echo foo >> s/ss/a
664 664 $ hg -R s/ss commit -m 'test dirty store detection'
665 665
666 666 $ hg out -S -r `hg log -r tip -T "{node|short}"`
667 667 comparing with $TESTTMP/t
668 668 searching for changes
669 669 no changes found
670 670 comparing with $TESTTMP/t/s
671 671 searching for changes
672 672 no changes found
673 673 comparing with $TESTTMP/t/s/ss
674 674 searching for changes
675 675 changeset: 1:79ea5566a333
676 676 tag: tip
677 677 user: test
678 678 date: Thu Jan 01 00:00:00 1970 +0000
679 679 summary: test dirty store detection
680 680
681 681 comparing with $TESTTMP/t/t
682 682 searching for changes
683 683 no changes found
684 684
685 685 $ hg push
686 686 pushing to $TESTTMP/t
687 687 pushing subrepo s/ss to $TESTTMP/t/s/ss
688 688 searching for changes
689 689 adding changesets
690 690 adding manifests
691 691 adding file changes
692 692 added 1 changesets with 1 changes to 1 files
693 693 no changes made to subrepo s since last push to $TESTTMP/t/s
694 694 no changes made to subrepo t since last push to $TESTTMP/t/t
695 695 searching for changes
696 696 no changes found
697 697 [1]
698 698
699 699 a subrepo store may be clean versus one repo but not versus another
700 700
701 701 $ hg push
702 702 pushing to $TESTTMP/t
703 703 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss
704 704 no changes made to subrepo s since last push to $TESTTMP/t/s
705 705 no changes made to subrepo t since last push to $TESTTMP/t/t
706 706 searching for changes
707 707 no changes found
708 708 [1]
709 709 $ hg push ../tcc
710 710 pushing to ../tcc
711 711 pushing subrepo s/ss to ../tcc/s/ss
712 712 searching for changes
713 713 adding changesets
714 714 adding manifests
715 715 adding file changes
716 716 added 1 changesets with 1 changes to 1 files
717 717 no changes made to subrepo s since last push to ../tcc/s
718 718 no changes made to subrepo t since last push to ../tcc/t
719 719 searching for changes
720 720 no changes found
721 721 [1]
722 722
723 723 update
724 724
725 725 $ cd ../t
726 726 $ hg up -C # discard our earlier merge
727 727 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
728 728 updated to "c373c8102e68: 12"
729 729 2 other heads for branch "default"
730 730 $ echo blah > t/t
731 731 $ hg ci -m13
732 732 committing subrepository t
733 733
734 734 backout calls revert internally with minimal opts, which should not raise
735 735 KeyError
736 736
737 737 $ hg backout ".^" --no-commit
738 738 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
739 739 changeset c373c8102e68 backed out, don't forget to commit.
740 740
741 741 $ hg up -C # discard changes
742 742 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
743 743 updated to "925c17564ef8: 13"
744 744 2 other heads for branch "default"
745 745
746 746 pull
747 747
748 748 $ cd ../tc
749 749 $ hg pull
750 750 pulling from $TESTTMP/t
751 751 searching for changes
752 752 adding changesets
753 753 adding manifests
754 754 adding file changes
755 755 added 1 changesets with 1 changes to 1 files
756 756 new changesets 925c17564ef8
757 757 (run 'hg update' to get a working copy)
758 758
759 759 should pull t
760 760
761 761 $ hg incoming -S -r `hg log -r tip -T "{node|short}"`
762 762 comparing with $TESTTMP/t
763 763 no changes found
764 764 comparing with $TESTTMP/t/s
765 765 searching for changes
766 766 no changes found
767 767 comparing with $TESTTMP/t/s/ss
768 768 searching for changes
769 769 no changes found
770 770 comparing with $TESTTMP/t/t
771 771 searching for changes
772 772 changeset: 5:52c0adc0515a
773 773 tag: tip
774 774 user: test
775 775 date: Thu Jan 01 00:00:00 1970 +0000
776 776 summary: 13
777 777
778 778
779 779 $ hg up
780 780 pulling subrepo t from $TESTTMP/t/t
781 781 searching for changes
782 782 adding changesets
783 783 adding manifests
784 784 adding file changes
785 785 added 1 changesets with 1 changes to 1 files
786 786 new changesets 52c0adc0515a
787 787 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
788 788 updated to "925c17564ef8: 13"
789 789 2 other heads for branch "default"
790 790 $ cat t/t
791 791 blah
792 792
793 793 bogus subrepo path aborts
794 794
795 795 $ echo 'bogus=[boguspath' >> .hgsub
796 796 $ hg ci -m 'bogus subrepo path'
797 797 abort: missing ] in subrepository source
798 798 [255]
799 799
800 800 Issue1986: merge aborts when trying to merge a subrepo that
801 801 shouldn't need merging
802 802
803 803 # subrepo layout
804 804 #
805 805 # o 5 br
806 806 # /|
807 807 # o | 4 default
808 808 # | |
809 809 # | o 3 br
810 810 # |/|
811 811 # o | 2 default
812 812 # | |
813 813 # | o 1 br
814 814 # |/
815 815 # o 0 default
816 816
817 817 $ cd ..
818 818 $ rm -rf sub
819 819 $ hg init main
820 820 $ cd main
821 821 $ hg init s
822 822 $ cd s
823 823 $ echo a > a
824 824 $ hg ci -Am1
825 825 adding a
826 826 $ hg branch br
827 827 marked working directory as branch br
828 828 (branches are permanent and global, did you want a bookmark?)
829 829 $ echo a >> a
830 830 $ hg ci -m1
831 831 $ hg up default
832 832 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
833 833 $ echo b > b
834 834 $ hg ci -Am1
835 835 adding b
836 836 $ hg up br
837 837 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
838 838 $ hg merge tip
839 839 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
840 840 (branch merge, don't forget to commit)
841 841 $ hg ci -m1
842 842 $ hg up 2
843 843 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
844 844 $ echo c > c
845 845 $ hg ci -Am1
846 846 adding c
847 847 $ hg up 3
848 848 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
849 849 $ hg merge 4
850 850 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
851 851 (branch merge, don't forget to commit)
852 852 $ hg ci -m1
853 853
854 854 # main repo layout:
855 855 #
856 856 # * <-- try to merge default into br again
857 857 # .`|
858 858 # . o 5 br --> substate = 5
859 859 # . |
860 860 # o | 4 default --> substate = 4
861 861 # | |
862 862 # | o 3 br --> substate = 2
863 863 # |/|
864 864 # o | 2 default --> substate = 2
865 865 # | |
866 866 # | o 1 br --> substate = 3
867 867 # |/
868 868 # o 0 default --> substate = 2
869 869
870 870 $ cd ..
871 871 $ echo 's = s' > .hgsub
872 872 $ hg -R s up 2
873 873 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
874 874 $ hg ci -Am1
875 875 adding .hgsub
876 876 $ hg branch br
877 877 marked working directory as branch br
878 878 (branches are permanent and global, did you want a bookmark?)
879 879 $ echo b > b
880 880 $ hg -R s up 3
881 881 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
882 882 $ hg ci -Am1
883 883 adding b
884 884 $ hg up default
885 885 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
886 886 $ echo c > c
887 887 $ hg ci -Am1
888 888 adding c
889 889 $ hg up 1
890 890 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
891 891 $ hg merge 2
892 892 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
893 893 (branch merge, don't forget to commit)
894 894 $ hg ci -m1
895 895 $ hg up 2
896 896 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
897 897 $ hg -R s up 4
898 898 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
899 899 $ echo d > d
900 900 $ hg ci -Am1
901 901 adding d
902 902 $ hg up 3
903 903 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
904 904 $ hg -R s up 5
905 905 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
906 906 $ echo e > e
907 907 $ hg ci -Am1
908 908 adding e
909 909
910 910 $ hg up 5
911 911 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
912 912 $ hg merge 4 # try to merge default into br again
913 913 subrepository s diverged (local revision: f8f13b33206e, remote revision: a3f9062a4f88)
914 914 (M)erge, keep (l)ocal [working copy] or keep (r)emote [merge rev]? m
915 915 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
916 916 (branch merge, don't forget to commit)
917 917 $ cd ..
918 918
919 919 test subrepo delete from .hgsubstate
920 920
921 921 $ hg init testdelete
922 922 $ mkdir testdelete/nested testdelete/nested2
923 923 $ hg init testdelete/nested
924 924 $ hg init testdelete/nested2
925 925 $ echo test > testdelete/nested/foo
926 926 $ echo test > testdelete/nested2/foo
927 927 $ hg -R testdelete/nested add
928 928 adding testdelete/nested/foo
929 929 $ hg -R testdelete/nested2 add
930 930 adding testdelete/nested2/foo
931 931 $ hg -R testdelete/nested ci -m test
932 932 $ hg -R testdelete/nested2 ci -m test
933 933 $ echo nested = nested > testdelete/.hgsub
934 934 $ echo nested2 = nested2 >> testdelete/.hgsub
935 935 $ hg -R testdelete add
936 936 adding testdelete/.hgsub
937 937 $ hg -R testdelete ci -m "nested 1 & 2 added"
938 938 $ echo nested = nested > testdelete/.hgsub
939 939 $ hg -R testdelete ci -m "nested 2 deleted"
940 940 $ cat testdelete/.hgsubstate
941 941 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
942 942 $ hg -R testdelete remove testdelete/.hgsub
943 943 $ hg -R testdelete ci -m ".hgsub deleted"
944 944 $ cat testdelete/.hgsubstate
945 945 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
946 946
947 947 test repository cloning
948 948
949 949 $ mkdir mercurial mercurial2
950 950 $ hg init nested_absolute
951 951 $ echo test > nested_absolute/foo
952 952 $ hg -R nested_absolute add
953 953 adding nested_absolute/foo
954 954 $ hg -R nested_absolute ci -mtest
955 955 $ cd mercurial
956 956 $ hg init nested_relative
957 957 $ echo test2 > nested_relative/foo2
958 958 $ hg -R nested_relative add
959 959 adding nested_relative/foo2
960 960 $ hg -R nested_relative ci -mtest2
961 961 $ hg init main
962 962 $ echo "nested_relative = ../nested_relative" > main/.hgsub
963 963 $ echo "nested_absolute = `pwd`/nested_absolute" >> main/.hgsub
964 964 $ hg -R main add
965 965 adding main/.hgsub
966 966 $ hg -R main ci -m "add subrepos"
967 967 $ cd ..
968 968 $ hg clone mercurial/main mercurial2/main
969 969 updating to branch default
970 970 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
971 971 $ cat mercurial2/main/nested_absolute/.hg/hgrc \
972 972 > mercurial2/main/nested_relative/.hg/hgrc
973 973 [paths]
974 974 default = $TESTTMP/mercurial/nested_absolute
975 975 [paths]
976 976 default = $TESTTMP/mercurial/nested_relative
977 977 $ rm -rf mercurial mercurial2
978 978
979 979 Issue1977: multirepo push should fail if subrepo push fails
980 980
981 981 $ hg init repo
982 982 $ hg init repo/s
983 983 $ echo a > repo/s/a
984 984 $ hg -R repo/s ci -Am0
985 985 adding a
986 986 $ echo s = s > repo/.hgsub
987 987 $ hg -R repo ci -Am1
988 988 adding .hgsub
989 989 $ hg clone repo repo2
990 990 updating to branch default
991 991 cloning subrepo s from $TESTTMP/repo/s
992 992 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
993 993 $ hg -q -R repo2 pull -u
994 994 $ echo 1 > repo2/s/a
995 995 $ hg -R repo2/s ci -m2
996 996 $ hg -q -R repo2/s push
997 997 $ hg -R repo2/s up -C 0
998 998 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
999 999 $ echo 2 > repo2/s/b
1000 1000 $ hg -R repo2/s ci -m3 -A
1001 1001 adding b
1002 1002 created new head
1003 1003 $ hg -R repo2 ci -m3
1004 1004 $ hg -q -R repo2 push
1005 1005 abort: push creates new remote head cc505f09a8b2! (in subrepository "s")
1006 1006 (merge or see 'hg help push' for details about pushing new heads)
1007 1007 [255]
1008 1008 $ hg -R repo update
1009 1009 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1010 1010
1011 1011 test if untracked file is not overwritten
1012 1012
1013 1013 (this also tests that updated .hgsubstate is treated as "modified",
1014 1014 when 'merge.update()' is aborted before 'merge.recordupdates()', even
1015 1015 if none of mode, size and timestamp of it isn't changed on the
1016 1016 filesystem (see also issue4583))
1017 1017
1018 1018 $ echo issue3276_ok > repo/s/b
1019 1019 $ hg -R repo2 push -f -q
1020 1020 $ touch -t 200001010000 repo/.hgsubstate
1021 1021
1022 1022 $ cat >> repo/.hg/hgrc <<EOF
1023 1023 > [fakedirstatewritetime]
1024 1024 > # emulate invoking dirstate.write() via repo.status()
1025 1025 > # at 2000-01-01 00:00
1026 1026 > fakenow = 200001010000
1027 1027 >
1028 1028 > [extensions]
1029 1029 > fakedirstatewritetime = $TESTDIR/fakedirstatewritetime.py
1030 1030 > EOF
1031 1031 $ hg -R repo update
1032 1032 b: untracked file differs
1033 1033 abort: untracked files in working directory differ from files in requested revision (in subrepository "s")
1034 1034 [255]
1035 1035 $ cat >> repo/.hg/hgrc <<EOF
1036 1036 > [extensions]
1037 1037 > fakedirstatewritetime = !
1038 1038 > EOF
1039 1039
1040 1040 $ cat repo/s/b
1041 1041 issue3276_ok
1042 1042 $ rm repo/s/b
1043 1043 $ touch -t 200001010000 repo/.hgsubstate
1044 1044 $ hg -R repo revert --all
1045 1045 reverting repo/.hgsubstate
1046 1046 reverting subrepo s
1047 1047 $ hg -R repo update
1048 1048 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1049 1049 $ cat repo/s/b
1050 1050 2
1051 1051 $ rm -rf repo2 repo
1052 1052
1053 1053
1054 1054 Issue1852 subrepos with relative paths always push/pull relative to default
1055 1055
1056 1056 Prepare a repo with subrepo
1057 1057
1058 1058 $ hg init issue1852a
1059 1059 $ cd issue1852a
1060 1060 $ hg init sub/repo
1061 1061 $ echo test > sub/repo/foo
1062 1062 $ hg -R sub/repo add sub/repo/foo
1063 1063 $ echo sub/repo = sub/repo > .hgsub
1064 1064 $ hg add .hgsub
1065 1065 $ hg ci -mtest
1066 1066 committing subrepository sub/repo
1067 1067 $ echo test >> sub/repo/foo
1068 1068 $ hg ci -mtest
1069 1069 committing subrepository sub/repo
1070 1070 $ hg cat sub/repo/foo
1071 1071 test
1072 1072 test
1073 1073 $ hg cat sub/repo/foo -Tjson | sed 's|\\\\|/|g'
1074 1074 [
1075 1075 {
1076 1076 "data": "test\ntest\n",
1077 1077 "path": "foo"
1078 1078 }
1079 1079 ]
1080 1080
1081 1081 non-exact match:
1082 1082
1083 1083 $ hg cat -T '{path|relpath}\n' 'glob:**'
1084 1084 .hgsub
1085 1085 .hgsubstate
1086 1086 sub/repo/foo
1087 1087 $ hg cat -T '{path|relpath}\n' 're:^sub'
1088 1088 sub/repo/foo
1089 1089
1090 1090 missing subrepos in working directory:
1091 1091
1092 1092 $ mkdir -p tmp/sub/repo
1093 1093 $ hg cat -r 0 --output tmp/%p_p sub/repo/foo
1094 1094 $ cat tmp/sub/repo/foo_p
1095 1095 test
1096 1096 $ mv sub/repo sub_
1097 1097 $ hg cat sub/repo/baz
1098 1098 skipping missing subrepository: sub/repo
1099 1099 [1]
1100 1100 $ rm -rf sub/repo
1101 1101 $ mv sub_ sub/repo
1102 1102 $ cd ..
1103 1103
1104 1104 Create repo without default path, pull top repo, and see what happens on update
1105 1105
1106 1106 $ hg init issue1852b
1107 1107 $ hg -R issue1852b pull issue1852a
1108 1108 pulling from issue1852a
1109 1109 requesting all changes
1110 1110 adding changesets
1111 1111 adding manifests
1112 1112 adding file changes
1113 1113 added 2 changesets with 3 changes to 2 files
1114 1114 new changesets 19487b456929:be5eb94e7215
1115 1115 (run 'hg update' to get a working copy)
1116 1116 $ hg -R issue1852b update
1117 1117 abort: default path for subrepository not found (in subrepository "sub/repo")
1118 1118 [255]
1119 1119
1120 1120 Ensure a full traceback, not just the SubrepoAbort part
1121 1121
1122 1122 $ hg -R issue1852b update --traceback 2>&1 | grep 'raise error\.Abort'
1123 1123 raise error.Abort(_("default path for subrepository not found"))
1124 1124
1125 1125 Pull -u now doesn't help
1126 1126
1127 1127 $ hg -R issue1852b pull -u issue1852a
1128 1128 pulling from issue1852a
1129 1129 searching for changes
1130 1130 no changes found
1131 1131
1132 1132 Try the same, but with pull -u
1133 1133
1134 1134 $ hg init issue1852c
1135 1135 $ hg -R issue1852c pull -r0 -u issue1852a
1136 1136 pulling from issue1852a
1137 1137 adding changesets
1138 1138 adding manifests
1139 1139 adding file changes
1140 1140 added 1 changesets with 2 changes to 2 files
1141 1141 new changesets 19487b456929
1142 1142 cloning subrepo sub/repo from issue1852a/sub/repo
1143 1143 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1144 1144
1145 1145 Try to push from the other side
1146 1146
1147 1147 $ hg -R issue1852a push `pwd`/issue1852c
1148 1148 pushing to $TESTTMP/issue1852c
1149 1149 pushing subrepo sub/repo to $TESTTMP/issue1852c/sub/repo
1150 1150 searching for changes
1151 1151 no changes found
1152 1152 searching for changes
1153 1153 adding changesets
1154 1154 adding manifests
1155 1155 adding file changes
1156 1156 added 1 changesets with 1 changes to 1 files
1157 1157
1158 1158 Incoming and outgoing should not use the default path:
1159 1159
1160 1160 $ hg clone -q issue1852a issue1852d
1161 1161 $ hg -R issue1852d outgoing --subrepos issue1852c
1162 1162 comparing with issue1852c
1163 1163 searching for changes
1164 1164 no changes found
1165 1165 comparing with issue1852c/sub/repo
1166 1166 searching for changes
1167 1167 no changes found
1168 1168 [1]
1169 1169 $ hg -R issue1852d incoming --subrepos issue1852c
1170 1170 comparing with issue1852c
1171 1171 searching for changes
1172 1172 no changes found
1173 1173 comparing with issue1852c/sub/repo
1174 1174 searching for changes
1175 1175 no changes found
1176 1176 [1]
1177 1177
1178 1178 Check that merge of a new subrepo doesn't write the uncommitted state to
1179 1179 .hgsubstate (issue4622)
1180 1180
1181 1181 $ hg init issue1852a/addedsub
1182 1182 $ echo zzz > issue1852a/addedsub/zz.txt
1183 1183 $ hg -R issue1852a/addedsub ci -Aqm "initial ZZ"
1184 1184
1185 1185 $ hg clone issue1852a/addedsub issue1852d/addedsub
1186 1186 updating to branch default
1187 1187 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1188 1188
1189 1189 $ echo def > issue1852a/sub/repo/foo
1190 1190 $ hg -R issue1852a ci -SAm 'tweaked subrepo'
1191 1191 adding tmp/sub/repo/foo_p
1192 1192 committing subrepository sub/repo
1193 1193
1194 1194 $ echo 'addedsub = addedsub' >> issue1852d/.hgsub
1195 1195 $ echo xyz > issue1852d/sub/repo/foo
1196 1196 $ hg -R issue1852d pull -u
1197 1197 pulling from $TESTTMP/issue1852a
1198 1198 searching for changes
1199 1199 adding changesets
1200 1200 adding manifests
1201 1201 adding file changes
1202 1202 added 1 changesets with 2 changes to 2 files
1203 1203 new changesets c82b79fdcc5b
1204 1204 subrepository sub/repo diverged (local revision: f42d5c7504a8, remote revision: 46cd4aac504c)
1205 1205 (M)erge, keep (l)ocal [working copy] or keep (r)emote [destination]? m
1206 1206 pulling subrepo sub/repo from $TESTTMP/issue1852a/sub/repo
1207 1207 searching for changes
1208 1208 adding changesets
1209 1209 adding manifests
1210 1210 adding file changes
1211 1211 added 1 changesets with 1 changes to 1 files
1212 1212 new changesets 46cd4aac504c
1213 1213 subrepository sources for sub/repo differ
1214 1214 use (l)ocal source (f42d5c7504a8) or (r)emote source (46cd4aac504c)? l
1215 1215 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1216 1216 $ cat issue1852d/.hgsubstate
1217 1217 f42d5c7504a811dda50f5cf3e5e16c3330b87172 sub/repo
1218 1218
1219 1219 Check status of files when none of them belong to the first
1220 1220 subrepository:
1221 1221
1222 1222 $ hg init subrepo-status
1223 1223 $ cd subrepo-status
1224 1224 $ hg init subrepo-1
1225 1225 $ hg init subrepo-2
1226 1226 $ cd subrepo-2
1227 1227 $ touch file
1228 1228 $ hg add file
1229 1229 $ cd ..
1230 1230 $ echo subrepo-1 = subrepo-1 > .hgsub
1231 1231 $ echo subrepo-2 = subrepo-2 >> .hgsub
1232 1232 $ hg add .hgsub
1233 1233 $ hg ci -m 'Added subrepos'
1234 1234 committing subrepository subrepo-2
1235 1235 $ hg st subrepo-2/file
1236 1236
1237 1237 Check that share works with subrepo
1238 1238 $ hg --config extensions.share= share . ../shared
1239 1239 updating working directory
1240 1240 sharing subrepo subrepo-1 from $TESTTMP/subrepo-status/subrepo-1
1241 1241 sharing subrepo subrepo-2 from $TESTTMP/subrepo-status/subrepo-2
1242 1242 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1243 1243 $ find ../shared/* | sort
1244 1244 ../shared/subrepo-1
1245 1245 ../shared/subrepo-1/.hg
1246 1246 ../shared/subrepo-1/.hg/cache
1247 1247 ../shared/subrepo-1/.hg/cache/storehash
1248 1248 ../shared/subrepo-1/.hg/cache/storehash/* (glob)
1249 1249 ../shared/subrepo-1/.hg/hgrc
1250 1250 ../shared/subrepo-1/.hg/requires
1251 1251 ../shared/subrepo-1/.hg/sharedpath
1252 1252 ../shared/subrepo-1/.hg/wcache
1253 1253 ../shared/subrepo-2
1254 1254 ../shared/subrepo-2/.hg
1255 1255 ../shared/subrepo-2/.hg/branch
1256 1256 ../shared/subrepo-2/.hg/cache
1257 1257 ../shared/subrepo-2/.hg/cache/storehash
1258 1258 ../shared/subrepo-2/.hg/cache/storehash/* (glob)
1259 1259 ../shared/subrepo-2/.hg/dirstate
1260 1260 ../shared/subrepo-2/.hg/hgrc
1261 1261 ../shared/subrepo-2/.hg/requires
1262 1262 ../shared/subrepo-2/.hg/sharedpath
1263 1263 ../shared/subrepo-2/.hg/wcache
1264 1264 ../shared/subrepo-2/.hg/wcache/checkisexec (execbit !)
1265 1265 ../shared/subrepo-2/.hg/wcache/checklink (symlink !)
1266 1266 ../shared/subrepo-2/.hg/wcache/checklink-target (symlink !)
1267 ../shared/subrepo-2/.hg/wcache/manifestfulltextcache (reporevlogstore !)
1267 1268 ../shared/subrepo-2/file
1268 1269 $ hg -R ../shared in
1269 1270 abort: repository default not found!
1270 1271 [255]
1271 1272 $ hg -R ../shared/subrepo-2 showconfig paths
1272 1273 paths.default=$TESTTMP/subrepo-status/subrepo-2
1273 1274 $ hg -R ../shared/subrepo-1 sum --remote
1274 1275 parent: -1:000000000000 tip (empty repository)
1275 1276 branch: default
1276 1277 commit: (clean)
1277 1278 update: (current)
1278 1279 remote: (synced)
1279 1280
1280 1281 Check hg update --clean
1281 1282 $ cd $TESTTMP/t
1282 1283 $ rm -r t/t.orig
1283 1284 $ hg status -S --all
1284 1285 C .hgsub
1285 1286 C .hgsubstate
1286 1287 C a
1287 1288 C s/.hgsub
1288 1289 C s/.hgsubstate
1289 1290 C s/a
1290 1291 C s/ss/a
1291 1292 C t/t
1292 1293 $ echo c1 > s/a
1293 1294 $ cd s
1294 1295 $ echo c1 > b
1295 1296 $ echo c1 > c
1296 1297 $ hg add b
1297 1298 $ cd ..
1298 1299 $ hg status -S
1299 1300 M s/a
1300 1301 A s/b
1301 1302 ? s/c
1302 1303 $ hg update -C
1303 1304 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1304 1305 updated to "925c17564ef8: 13"
1305 1306 2 other heads for branch "default"
1306 1307 $ hg status -S
1307 1308 ? s/b
1308 1309 ? s/c
1309 1310
1310 1311 Sticky subrepositories, no changes
1311 1312 $ cd $TESTTMP/t
1312 1313 $ hg id
1313 1314 925c17564ef8 tip
1314 1315 $ hg -R s id
1315 1316 12a213df6fa9 tip
1316 1317 $ hg -R t id
1317 1318 52c0adc0515a tip
1318 1319 $ hg update 11
1319 1320 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1320 1321 $ hg id
1321 1322 365661e5936a
1322 1323 $ hg -R s id
1323 1324 fc627a69481f
1324 1325 $ hg -R t id
1325 1326 e95bcfa18a35
1326 1327
1327 1328 Sticky subrepositories, file changes
1328 1329 $ touch s/f1
1329 1330 $ touch t/f1
1330 1331 $ hg add -S s/f1
1331 1332 $ hg add -S t/f1
1332 1333 $ hg id
1333 1334 365661e5936a+
1334 1335 $ hg -R s id
1335 1336 fc627a69481f+
1336 1337 $ hg -R t id
1337 1338 e95bcfa18a35+
1338 1339 $ hg update tip
1339 1340 subrepository s diverged (local revision: fc627a69481f, remote revision: 12a213df6fa9)
1340 1341 (M)erge, keep (l)ocal [working copy] or keep (r)emote [destination]? m
1341 1342 subrepository sources for s differ
1342 1343 use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)? l
1343 1344 subrepository t diverged (local revision: e95bcfa18a35, remote revision: 52c0adc0515a)
1344 1345 (M)erge, keep (l)ocal [working copy] or keep (r)emote [destination]? m
1345 1346 subrepository sources for t differ
1346 1347 use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)? l
1347 1348 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1348 1349 $ hg id
1349 1350 925c17564ef8+ tip
1350 1351 $ hg -R s id
1351 1352 fc627a69481f+
1352 1353 $ hg -R t id
1353 1354 e95bcfa18a35+
1354 1355 $ hg update --clean tip
1355 1356 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1356 1357
1357 1358 Sticky subrepository, revision updates
1358 1359 $ hg id
1359 1360 925c17564ef8 tip
1360 1361 $ hg -R s id
1361 1362 12a213df6fa9 tip
1362 1363 $ hg -R t id
1363 1364 52c0adc0515a tip
1364 1365 $ cd s
1365 1366 $ hg update -r -2
1366 1367 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1367 1368 $ cd ../t
1368 1369 $ hg update -r 2
1369 1370 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1370 1371 $ cd ..
1371 1372 $ hg update 10
1372 1373 subrepository s diverged (local revision: 12a213df6fa9, remote revision: fc627a69481f)
1373 1374 (M)erge, keep (l)ocal [working copy] or keep (r)emote [destination]? m
1374 1375 subrepository t diverged (local revision: 52c0adc0515a, remote revision: 20a0db6fbf6c)
1375 1376 (M)erge, keep (l)ocal [working copy] or keep (r)emote [destination]? m
1376 1377 subrepository sources for t differ (in checked out version)
1377 1378 use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)? l
1378 1379 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1379 1380 $ hg id
1380 1381 e45c8b14af55+
1381 1382 $ hg -R s id
1382 1383 02dcf1d70411
1383 1384 $ hg -R t id
1384 1385 7af322bc1198
1385 1386
1386 1387 Sticky subrepository, file changes and revision updates
1387 1388 $ touch s/f1
1388 1389 $ touch t/f1
1389 1390 $ hg add -S s/f1
1390 1391 $ hg add -S t/f1
1391 1392 $ hg id
1392 1393 e45c8b14af55+
1393 1394 $ hg -R s id
1394 1395 02dcf1d70411+
1395 1396 $ hg -R t id
1396 1397 7af322bc1198+
1397 1398 $ hg update tip
1398 1399 subrepository s diverged (local revision: 12a213df6fa9, remote revision: 12a213df6fa9)
1399 1400 (M)erge, keep (l)ocal [working copy] or keep (r)emote [destination]? m
1400 1401 subrepository sources for s differ
1401 1402 use (l)ocal source (02dcf1d70411) or (r)emote source (12a213df6fa9)? l
1402 1403 subrepository t diverged (local revision: 52c0adc0515a, remote revision: 52c0adc0515a)
1403 1404 (M)erge, keep (l)ocal [working copy] or keep (r)emote [destination]? m
1404 1405 subrepository sources for t differ
1405 1406 use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)? l
1406 1407 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1407 1408 $ hg id
1408 1409 925c17564ef8+ tip
1409 1410 $ hg -R s id
1410 1411 02dcf1d70411+
1411 1412 $ hg -R t id
1412 1413 7af322bc1198+
1413 1414
1414 1415 Sticky repository, update --clean
1415 1416 $ hg update --clean tip
1416 1417 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1417 1418 $ hg id
1418 1419 925c17564ef8 tip
1419 1420 $ hg -R s id
1420 1421 12a213df6fa9 tip
1421 1422 $ hg -R t id
1422 1423 52c0adc0515a tip
1423 1424
1424 1425 Test subrepo already at intended revision:
1425 1426 $ cd s
1426 1427 $ hg update fc627a69481f
1427 1428 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1428 1429 $ cd ..
1429 1430 $ hg update 11
1430 1431 subrepository s diverged (local revision: 12a213df6fa9, remote revision: fc627a69481f)
1431 1432 (M)erge, keep (l)ocal [working copy] or keep (r)emote [destination]? m
1432 1433 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1433 1434 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1434 1435 $ hg id -n
1435 1436 11+
1436 1437 $ hg -R s id
1437 1438 fc627a69481f
1438 1439 $ hg -R t id
1439 1440 e95bcfa18a35
1440 1441
1441 1442 Test that removing .hgsubstate doesn't break anything:
1442 1443
1443 1444 $ hg rm -f .hgsubstate
1444 1445 $ hg ci -mrm
1445 1446 nothing changed
1446 1447 [1]
1447 1448 $ hg log -vr tip
1448 1449 changeset: 13:925c17564ef8
1449 1450 tag: tip
1450 1451 user: test
1451 1452 date: Thu Jan 01 00:00:00 1970 +0000
1452 1453 files: .hgsubstate
1453 1454 description:
1454 1455 13
1455 1456
1456 1457
1457 1458
1458 1459 Test that removing .hgsub removes .hgsubstate:
1459 1460
1460 1461 $ hg rm .hgsub
1461 1462 $ hg ci -mrm2
1462 1463 created new head
1463 1464 $ hg log -vr tip
1464 1465 changeset: 14:2400bccd50af
1465 1466 tag: tip
1466 1467 parent: 11:365661e5936a
1467 1468 user: test
1468 1469 date: Thu Jan 01 00:00:00 1970 +0000
1469 1470 files: .hgsub .hgsubstate
1470 1471 description:
1471 1472 rm2
1472 1473
1473 1474
1474 1475 Test issue3153: diff -S with deleted subrepos
1475 1476
1476 1477 $ hg diff --nodates -S -c .
1477 1478 diff -r 365661e5936a -r 2400bccd50af .hgsub
1478 1479 --- a/.hgsub
1479 1480 +++ /dev/null
1480 1481 @@ -1,2 +0,0 @@
1481 1482 -s = s
1482 1483 -t = t
1483 1484 diff -r 365661e5936a -r 2400bccd50af .hgsubstate
1484 1485 --- a/.hgsubstate
1485 1486 +++ /dev/null
1486 1487 @@ -1,2 +0,0 @@
1487 1488 -fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
1488 1489 -e95bcfa18a358dc4936da981ebf4147b4cad1362 t
1489 1490
1490 1491 Test behavior of add for explicit path in subrepo:
1491 1492 $ cd ..
1492 1493 $ hg init explicit
1493 1494 $ cd explicit
1494 1495 $ echo s = s > .hgsub
1495 1496 $ hg add .hgsub
1496 1497 $ hg init s
1497 1498 $ hg ci -m0
1498 1499 Adding with an explicit path in a subrepo adds the file
1499 1500 $ echo c1 > f1
1500 1501 $ echo c2 > s/f2
1501 1502 $ hg st -S
1502 1503 ? f1
1503 1504 ? s/f2
1504 1505 $ hg add s/f2
1505 1506 $ hg st -S
1506 1507 A s/f2
1507 1508 ? f1
1508 1509 $ hg ci -R s -m0
1509 1510 $ hg ci -Am1
1510 1511 adding f1
1511 1512 Adding with an explicit path in a subrepo with -S has the same behavior
1512 1513 $ echo c3 > f3
1513 1514 $ echo c4 > s/f4
1514 1515 $ hg st -S
1515 1516 ? f3
1516 1517 ? s/f4
1517 1518 $ hg add -S s/f4
1518 1519 $ hg st -S
1519 1520 A s/f4
1520 1521 ? f3
1521 1522 $ hg ci -R s -m1
1522 1523 $ hg ci -Ama2
1523 1524 adding f3
1524 1525 Adding without a path or pattern silently ignores subrepos
1525 1526 $ echo c5 > f5
1526 1527 $ echo c6 > s/f6
1527 1528 $ echo c7 > s/f7
1528 1529 $ hg st -S
1529 1530 ? f5
1530 1531 ? s/f6
1531 1532 ? s/f7
1532 1533 $ hg add
1533 1534 adding f5
1534 1535 $ hg st -S
1535 1536 A f5
1536 1537 ? s/f6
1537 1538 ? s/f7
1538 1539 $ hg ci -R s -Am2
1539 1540 adding f6
1540 1541 adding f7
1541 1542 $ hg ci -m3
1542 1543 Adding without a path or pattern with -S also adds files in subrepos
1543 1544 $ echo c8 > f8
1544 1545 $ echo c9 > s/f9
1545 1546 $ echo c10 > s/f10
1546 1547 $ hg st -S
1547 1548 ? f8
1548 1549 ? s/f10
1549 1550 ? s/f9
1550 1551 $ hg add -S
1551 1552 adding f8
1552 1553 adding s/f10
1553 1554 adding s/f9
1554 1555 $ hg st -S
1555 1556 A f8
1556 1557 A s/f10
1557 1558 A s/f9
1558 1559 $ hg ci -R s -m3
1559 1560 $ hg ci -m4
1560 1561 Adding with a pattern silently ignores subrepos
1561 1562 $ echo c11 > fm11
1562 1563 $ echo c12 > fn12
1563 1564 $ echo c13 > s/fm13
1564 1565 $ echo c14 > s/fn14
1565 1566 $ hg st -S
1566 1567 ? fm11
1567 1568 ? fn12
1568 1569 ? s/fm13
1569 1570 ? s/fn14
1570 1571 $ hg add 'glob:**fm*'
1571 1572 adding fm11
1572 1573 $ hg st -S
1573 1574 A fm11
1574 1575 ? fn12
1575 1576 ? s/fm13
1576 1577 ? s/fn14
1577 1578 $ hg ci -R s -Am4
1578 1579 adding fm13
1579 1580 adding fn14
1580 1581 $ hg ci -Am5
1581 1582 adding fn12
1582 1583 Adding with a pattern with -S also adds matches in subrepos
1583 1584 $ echo c15 > fm15
1584 1585 $ echo c16 > fn16
1585 1586 $ echo c17 > s/fm17
1586 1587 $ echo c18 > s/fn18
1587 1588 $ hg st -S
1588 1589 ? fm15
1589 1590 ? fn16
1590 1591 ? s/fm17
1591 1592 ? s/fn18
1592 1593 $ hg add -S 'glob:**fm*'
1593 1594 adding fm15
1594 1595 adding s/fm17
1595 1596 $ hg st -S
1596 1597 A fm15
1597 1598 A s/fm17
1598 1599 ? fn16
1599 1600 ? s/fn18
1600 1601 $ hg ci -R s -Am5
1601 1602 adding fn18
1602 1603 $ hg ci -Am6
1603 1604 adding fn16
1604 1605
1605 1606 Test behavior of forget for explicit path in subrepo:
1606 1607 Forgetting an explicit path in a subrepo untracks the file
1607 1608 $ echo c19 > s/f19
1608 1609 $ hg add s/f19
1609 1610 $ hg st -S
1610 1611 A s/f19
1611 1612 $ hg forget s/f19
1612 1613 $ hg st -S
1613 1614 ? s/f19
1614 1615 $ rm s/f19
1615 1616 $ cd ..
1616 1617
1617 1618 Courtesy phases synchronisation to publishing server does not block the push
1618 1619 (issue3781)
1619 1620
1620 1621 $ cp -R main issue3781
1621 1622 $ cp -R main issue3781-dest
1622 1623 $ cd issue3781-dest/s
1623 1624 $ hg phase tip # show we have draft changeset
1624 1625 5: draft
1625 1626 $ chmod a-w .hg/store/phaseroots # prevent phase push
1626 1627 $ cd ../../issue3781
1627 1628 $ cat >> .hg/hgrc << EOF
1628 1629 > [paths]
1629 1630 > default=../issue3781-dest/
1630 1631 > EOF
1631 1632 $ hg push --config devel.legacy.exchange=bundle1
1632 1633 pushing to $TESTTMP/issue3781-dest
1633 1634 pushing subrepo s to $TESTTMP/issue3781-dest/s
1634 1635 searching for changes
1635 1636 no changes found
1636 1637 searching for changes
1637 1638 no changes found
1638 1639 [1]
1639 1640 # clean the push cache
1640 1641 $ rm s/.hg/cache/storehash/*
1641 1642 $ hg push # bundle2+
1642 1643 pushing to $TESTTMP/issue3781-dest
1643 1644 pushing subrepo s to $TESTTMP/issue3781-dest/s
1644 1645 searching for changes
1645 1646 no changes found
1646 1647 searching for changes
1647 1648 no changes found
1648 1649 [1]
1649 1650 $ cd ..
1650 1651
1651 1652 Test phase choice for newly created commit with "phases.subrepochecks"
1652 1653 configuration
1653 1654
1654 1655 $ cd t
1655 1656 $ hg update -q -r 12
1656 1657
1657 1658 $ cat >> s/ss/.hg/hgrc <<EOF
1658 1659 > [phases]
1659 1660 > new-commit = secret
1660 1661 > EOF
1661 1662 $ cat >> s/.hg/hgrc <<EOF
1662 1663 > [phases]
1663 1664 > new-commit = draft
1664 1665 > EOF
1665 1666 $ echo phasecheck1 >> s/ss/a
1666 1667 $ hg -R s commit -S --config phases.checksubrepos=abort -m phasecheck1
1667 1668 committing subrepository ss
1668 1669 transaction abort!
1669 1670 rollback completed
1670 1671 abort: can't commit in draft phase conflicting secret from subrepository ss
1671 1672 [255]
1672 1673 $ echo phasecheck2 >> s/ss/a
1673 1674 $ hg -R s commit -S --config phases.checksubrepos=ignore -m phasecheck2
1674 1675 committing subrepository ss
1675 1676 $ hg -R s/ss phase tip
1676 1677 3: secret
1677 1678 $ hg -R s phase tip
1678 1679 6: draft
1679 1680 $ echo phasecheck3 >> s/ss/a
1680 1681 $ hg -R s commit -S -m phasecheck3
1681 1682 committing subrepository ss
1682 1683 warning: changes are committed in secret phase from subrepository ss
1683 1684 $ hg -R s/ss phase tip
1684 1685 4: secret
1685 1686 $ hg -R s phase tip
1686 1687 7: secret
1687 1688
1688 1689 $ cat >> t/.hg/hgrc <<EOF
1689 1690 > [phases]
1690 1691 > new-commit = draft
1691 1692 > EOF
1692 1693 $ cat >> .hg/hgrc <<EOF
1693 1694 > [phases]
1694 1695 > new-commit = public
1695 1696 > EOF
1696 1697 $ echo phasecheck4 >> s/ss/a
1697 1698 $ echo phasecheck4 >> t/t
1698 1699 $ hg commit -S -m phasecheck4
1699 1700 committing subrepository s
1700 1701 committing subrepository s/ss
1701 1702 warning: changes are committed in secret phase from subrepository ss
1702 1703 committing subrepository t
1703 1704 warning: changes are committed in secret phase from subrepository s
1704 1705 created new head
1705 1706 $ hg -R s/ss phase tip
1706 1707 5: secret
1707 1708 $ hg -R s phase tip
1708 1709 8: secret
1709 1710 $ hg -R t phase tip
1710 1711 6: draft
1711 1712 $ hg phase tip
1712 1713 15: secret
1713 1714
1714 1715 $ cd ..
1715 1716
1716 1717
1717 1718 Test that commit --secret works on both repo and subrepo (issue4182)
1718 1719
1719 1720 $ cd main
1720 1721 $ echo secret >> b
1721 1722 $ echo secret >> s/b
1722 1723 $ hg commit --secret --subrepo -m "secret"
1723 1724 committing subrepository s
1724 1725 $ hg phase -r .
1725 1726 6: secret
1726 1727 $ cd s
1727 1728 $ hg phase -r .
1728 1729 6: secret
1729 1730 $ cd ../../
1730 1731
1731 1732 Test "subrepos" template keyword
1732 1733
1733 1734 $ cd t
1734 1735 $ hg update -q 15
1735 1736 $ cat > .hgsub <<EOF
1736 1737 > s = s
1737 1738 > EOF
1738 1739 $ hg commit -m "16"
1739 1740 warning: changes are committed in secret phase from subrepository s
1740 1741
1741 1742 (addition of ".hgsub" itself)
1742 1743
1743 1744 $ hg diff --nodates -c 1 .hgsubstate
1744 1745 diff -r f7b1eb17ad24 -r 7cf8cfea66e4 .hgsubstate
1745 1746 --- /dev/null
1746 1747 +++ b/.hgsubstate
1747 1748 @@ -0,0 +1,1 @@
1748 1749 +e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1749 1750 $ hg log -r 1 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1750 1751 f7b1eb17ad24 000000000000
1751 1752 s
1752 1753
1753 1754 (modification of existing entry)
1754 1755
1755 1756 $ hg diff --nodates -c 2 .hgsubstate
1756 1757 diff -r 7cf8cfea66e4 -r df30734270ae .hgsubstate
1757 1758 --- a/.hgsubstate
1758 1759 +++ b/.hgsubstate
1759 1760 @@ -1,1 +1,1 @@
1760 1761 -e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1761 1762 +dc73e2e6d2675eb2e41e33c205f4bdab4ea5111d s
1762 1763 $ hg log -r 2 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1763 1764 7cf8cfea66e4 000000000000
1764 1765 s
1765 1766
1766 1767 (addition of entry)
1767 1768
1768 1769 $ hg diff --nodates -c 5 .hgsubstate
1769 1770 diff -r 7cf8cfea66e4 -r 1f14a2e2d3ec .hgsubstate
1770 1771 --- a/.hgsubstate
1771 1772 +++ b/.hgsubstate
1772 1773 @@ -1,1 +1,2 @@
1773 1774 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1774 1775 +60ca1237c19474e7a3978b0dc1ca4e6f36d51382 t
1775 1776 $ hg log -r 5 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1776 1777 7cf8cfea66e4 000000000000
1777 1778 t
1778 1779
1779 1780 (removal of existing entry)
1780 1781
1781 1782 $ hg diff --nodates -c 16 .hgsubstate
1782 1783 diff -r 8bec38d2bd0b -r f2f70bc3d3c9 .hgsubstate
1783 1784 --- a/.hgsubstate
1784 1785 +++ b/.hgsubstate
1785 1786 @@ -1,2 +1,1 @@
1786 1787 0731af8ca9423976d3743119d0865097c07bdc1b s
1787 1788 -e202dc79b04c88a636ea8913d9182a1346d9b3dc t
1788 1789 $ hg log -r 16 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1789 1790 8bec38d2bd0b 000000000000
1790 1791 t
1791 1792
1792 1793 (merging)
1793 1794
1794 1795 $ hg diff --nodates -c 9 .hgsubstate
1795 1796 diff -r f6affe3fbfaa -r f0d2028bf86d .hgsubstate
1796 1797 --- a/.hgsubstate
1797 1798 +++ b/.hgsubstate
1798 1799 @@ -1,1 +1,2 @@
1799 1800 fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
1800 1801 +60ca1237c19474e7a3978b0dc1ca4e6f36d51382 t
1801 1802 $ hg log -r 9 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1802 1803 f6affe3fbfaa 1f14a2e2d3ec
1803 1804 t
1804 1805
1805 1806 (removal of ".hgsub" itself)
1806 1807
1807 1808 $ hg diff --nodates -c 8 .hgsubstate
1808 1809 diff -r f94576341bcf -r 96615c1dad2d .hgsubstate
1809 1810 --- a/.hgsubstate
1810 1811 +++ /dev/null
1811 1812 @@ -1,2 +0,0 @@
1812 1813 -e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1813 1814 -7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4 t
1814 1815 $ hg log -r 8 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1815 1816 f94576341bcf 000000000000
1816 1817
1817 1818 Test that '[paths]' is configured correctly at subrepo creation
1818 1819
1819 1820 $ cd $TESTTMP/tc
1820 1821 $ cat > .hgsub <<EOF
1821 1822 > # to clear bogus subrepo path 'bogus=[boguspath'
1822 1823 > s = s
1823 1824 > t = t
1824 1825 > EOF
1825 1826 $ hg update -q --clean null
1826 1827 $ rm -rf s t
1827 1828 $ cat >> .hg/hgrc <<EOF
1828 1829 > [paths]
1829 1830 > default-push = /foo/bar
1830 1831 > EOF
1831 1832 $ hg update -q
1832 1833 $ cat s/.hg/hgrc
1833 1834 [paths]
1834 1835 default = $TESTTMP/t/s
1835 1836 default-push = /foo/bar/s
1836 1837 $ cat s/ss/.hg/hgrc
1837 1838 [paths]
1838 1839 default = $TESTTMP/t/s/ss
1839 1840 default-push = /foo/bar/s/ss
1840 1841 $ cat t/.hg/hgrc
1841 1842 [paths]
1842 1843 default = $TESTTMP/t/t
1843 1844 default-push = /foo/bar/t
1844 1845
1845 1846 $ cd $TESTTMP/t
1846 1847 $ hg up -qC 0
1847 1848 $ echo 'bar' > bar.txt
1848 1849 $ hg ci -Am 'branch before subrepo add'
1849 1850 adding bar.txt
1850 1851 created new head
1851 1852 $ hg merge -r "first(subrepo('s'))"
1852 1853 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1853 1854 (branch merge, don't forget to commit)
1854 1855 $ hg status -S -X '.hgsub*'
1855 1856 A s/a
1856 1857 ? s/b
1857 1858 ? s/c
1858 1859 ? s/f1
1859 1860 $ hg status -S --rev 'p2()'
1860 1861 A bar.txt
1861 1862 ? s/b
1862 1863 ? s/c
1863 1864 ? s/f1
1864 1865 $ hg diff -S -X '.hgsub*' --nodates
1865 1866 diff -r 000000000000 s/a
1866 1867 --- /dev/null
1867 1868 +++ b/s/a
1868 1869 @@ -0,0 +1,1 @@
1869 1870 +a
1870 1871 $ hg diff -S --rev 'p2()' --nodates
1871 1872 diff -r 7cf8cfea66e4 bar.txt
1872 1873 --- /dev/null
1873 1874 +++ b/bar.txt
1874 1875 @@ -0,0 +1,1 @@
1875 1876 +bar
1876 1877
1877 1878 $ cd ..
1878 1879
1879 1880 test for ssh exploit 2017-07-25
1880 1881
1881 1882 $ cat >> $HGRCPATH << EOF
1882 1883 > [ui]
1883 1884 > ssh = sh -c "read l; read l; read l"
1884 1885 > EOF
1885 1886
1886 1887 $ hg init malicious-proxycommand
1887 1888 $ cd malicious-proxycommand
1888 1889 $ echo 's = [hg]ssh://-oProxyCommand=touch${IFS}owned/path' > .hgsub
1889 1890 $ hg init s
1890 1891 $ cd s
1891 1892 $ echo init > init
1892 1893 $ hg add
1893 1894 adding init
1894 1895 $ hg commit -m init
1895 1896 $ cd ..
1896 1897 $ hg add .hgsub
1897 1898 $ hg ci -m 'add subrepo'
1898 1899 $ cd ..
1899 1900 $ hg clone malicious-proxycommand malicious-proxycommand-clone
1900 1901 updating to branch default
1901 1902 cloning subrepo s from ssh://-oProxyCommand%3Dtouch%24%7BIFS%7Downed/path
1902 1903 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path' (in subrepository "s")
1903 1904 [255]
1904 1905
1905 1906 also check that a percent encoded '-' (%2D) doesn't work
1906 1907
1907 1908 $ cd malicious-proxycommand
1908 1909 $ echo 's = [hg]ssh://%2DoProxyCommand=touch${IFS}owned/path' > .hgsub
1909 1910 $ hg ci -m 'change url to percent encoded'
1910 1911 $ cd ..
1911 1912 $ rm -r malicious-proxycommand-clone
1912 1913 $ hg clone malicious-proxycommand malicious-proxycommand-clone
1913 1914 updating to branch default
1914 1915 cloning subrepo s from ssh://-oProxyCommand%3Dtouch%24%7BIFS%7Downed/path
1915 1916 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path' (in subrepository "s")
1916 1917 [255]
1917 1918
1918 1919 also check for a pipe
1919 1920
1920 1921 $ cd malicious-proxycommand
1921 1922 $ echo 's = [hg]ssh://fakehost|touch${IFS}owned/path' > .hgsub
1922 1923 $ hg ci -m 'change url to pipe'
1923 1924 $ cd ..
1924 1925 $ rm -r malicious-proxycommand-clone
1925 1926 $ hg clone malicious-proxycommand malicious-proxycommand-clone
1926 1927 updating to branch default
1927 1928 cloning subrepo s from ssh://fakehost%7Ctouch%24%7BIFS%7Downed/path
1928 1929 abort: no suitable response from remote hg!
1929 1930 [255]
1930 1931 $ [ ! -f owned ] || echo 'you got owned'
1931 1932
1932 1933 also check that a percent encoded '|' (%7C) doesn't work
1933 1934
1934 1935 $ cd malicious-proxycommand
1935 1936 $ echo 's = [hg]ssh://fakehost%7Ctouch%20owned/path' > .hgsub
1936 1937 $ hg ci -m 'change url to percent encoded pipe'
1937 1938 $ cd ..
1938 1939 $ rm -r malicious-proxycommand-clone
1939 1940 $ hg clone malicious-proxycommand malicious-proxycommand-clone
1940 1941 updating to branch default
1941 1942 cloning subrepo s from ssh://fakehost%7Ctouch%20owned/path
1942 1943 abort: no suitable response from remote hg!
1943 1944 [255]
1944 1945 $ [ ! -f owned ] || echo 'you got owned'
1945 1946
1946 1947 and bad usernames:
1947 1948 $ cd malicious-proxycommand
1948 1949 $ echo 's = [hg]ssh://-oProxyCommand=touch owned@example.com/path' > .hgsub
1949 1950 $ hg ci -m 'owned username'
1950 1951 $ cd ..
1951 1952 $ rm -r malicious-proxycommand-clone
1952 1953 $ hg clone malicious-proxycommand malicious-proxycommand-clone
1953 1954 updating to branch default
1954 1955 cloning subrepo s from ssh://-oProxyCommand%3Dtouch%20owned@example.com/path
1955 1956 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch owned@example.com/path' (in subrepository "s")
1956 1957 [255]
1957 1958
1958 1959 Test convert subrepositories including merge (issue5526):
1959 1960
1960 1961 $ hg init tconv
1961 1962 $ hg convert --config extensions.convert= -q t/s tconv/s
1962 1963 $ hg convert --config extensions.convert= -q t/s/ss tconv/s/ss
1963 1964 $ hg convert --config extensions.convert= -q t/t tconv/t
1964 1965
1965 1966 convert shouldn't fail because of pseudo filenode:
1966 1967
1967 1968 $ hg convert --config extensions.convert= t tconv
1968 1969 scanning source...
1969 1970 sorting...
1970 1971 converting...
1971 1972 17 0
1972 1973 16 1
1973 1974 15 2
1974 1975 14 3
1975 1976 13 4
1976 1977 12 5
1977 1978 11 6
1978 1979 10 7
1979 1980 9 8
1980 1981 8 9
1981 1982 7 10
1982 1983 6 11
1983 1984 5 12
1984 1985 4 13
1985 1986 3 rm2
1986 1987 2 phasecheck4
1987 1988 1 16
1988 1989 0 branch before subrepo add
1989 1990
1990 1991 converted .hgsubstate should point to valid nodes:
1991 1992
1992 1993 $ hg up -R tconv 9
1993 1994 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1994 1995 $ cat tconv/.hgsubstate
1995 1996 fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
1996 1997 60ca1237c19474e7a3978b0dc1ca4e6f36d51382 t
General Comments 0
You need to be logged in to leave comments. Login now