comparison mercurial/hg.py @ 740:d2422f10c136

Merge from BOS manifest hash: 2276dbd96bb4221e579c871a1de2403c92c85659
author mpm@selenic.com
date Wed, 20 Jul 2005 20:00:29 -0500
parents fed842bb84b2 8db4d406b3d3
children 156dc2f3be7f
comparison
equal deleted inserted replaced
722:e5b39ce2c3c9 740:d2422f10c136
275 self.dirty = 0 275 self.dirty = 0
276 self.ui = ui 276 self.ui = ui
277 self.map = None 277 self.map = None
278 self.pl = None 278 self.pl = None
279 self.copies = {} 279 self.copies = {}
280 self.ignorefunc = None
281
282 def wjoin(self, f):
283 return os.path.join(self.root, f)
284
285 def ignore(self, f):
286 if not self.ignorefunc:
287 bigpat = []
288 try:
289 l = file(self.wjoin(".hgignore"))
290 for pat in l:
291 if pat != "\n":
292 p = util.pconvert(pat[:-1])
293 try:
294 r = re.compile(p)
295 except:
296 self.ui.warn("ignoring invalid ignore"
297 + " regular expression '%s'\n" % p)
298 else:
299 bigpat.append(util.pconvert(pat[:-1]))
300 except IOError: pass
301
302 if bigpat:
303 s = "(?:%s)" % (")|(?:".join(bigpat))
304 r = re.compile(s)
305 self.ignorefunc = r.search
306 else:
307 self.ignorefunc = util.never
308
309 return self.ignorefunc(f)
280 310
281 def __del__(self): 311 def __del__(self):
282 if self.dirty: 312 if self.dirty:
283 self.write() 313 self.write()
284 314
296 def parents(self): 326 def parents(self):
297 if not self.pl: 327 if not self.pl:
298 self.read() 328 self.read()
299 return self.pl 329 return self.pl
300 330
331 def markdirty(self):
332 if not self.dirty:
333 self.dirty = 1
334
301 def setparents(self, p1, p2 = nullid): 335 def setparents(self, p1, p2 = nullid):
302 self.dirty = 1 336 self.markdirty()
303 self.pl = p1, p2 337 self.pl = p1, p2
304 338
305 def state(self, key): 339 def state(self, key):
306 try: 340 try:
307 return self[key][0] 341 return self[key][0]
332 self.map[f] = e[:4] 366 self.map[f] = e[:4]
333 pos += l 367 pos += l
334 368
335 def copy(self, source, dest): 369 def copy(self, source, dest):
336 self.read() 370 self.read()
337 self.dirty = 1 371 self.markdirty()
338 self.copies[dest] = source 372 self.copies[dest] = source
339 373
340 def copied(self, file): 374 def copied(self, file):
341 return self.copies.get(file, None) 375 return self.copies.get(file, None)
342 376
347 r marked for removal 381 r marked for removal
348 a marked for addition''' 382 a marked for addition'''
349 383
350 if not files: return 384 if not files: return
351 self.read() 385 self.read()
352 self.dirty = 1 386 self.markdirty()
353 for f in files: 387 for f in files:
354 if state == "r": 388 if state == "r":
355 self.map[f] = ('r', 0, 0, 0) 389 self.map[f] = ('r', 0, 0, 0)
356 else: 390 else:
357 s = os.stat(os.path.join(self.root, f)) 391 s = os.stat(os.path.join(self.root, f))
358 self.map[f] = (state, s.st_mode, s.st_size, s.st_mtime) 392 self.map[f] = (state, s.st_mode, s.st_size, s.st_mtime)
359 393
360 def forget(self, files): 394 def forget(self, files):
361 if not files: return 395 if not files: return
362 self.read() 396 self.read()
363 self.dirty = 1 397 self.markdirty()
364 for f in files: 398 for f in files:
365 try: 399 try:
366 del self.map[f] 400 del self.map[f]
367 except KeyError: 401 except KeyError:
368 self.ui.warn("not in dirstate: %s!\n" % f) 402 self.ui.warn("not in dirstate: %s!\n" % f)
369 pass 403 pass
370 404
371 def clear(self): 405 def clear(self):
372 self.map = {} 406 self.map = {}
373 self.dirty = 1 407 self.markdirty()
374 408
375 def write(self): 409 def write(self):
376 st = self.opener("dirstate", "w") 410 st = self.opener("dirstate", "w")
377 st.write("".join(self.pl)) 411 st.write("".join(self.pl))
378 for f, e in self.map.items(): 412 for f, e in self.map.items():
381 f = f + "\0" + c 415 f = f + "\0" + c
382 e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f)) 416 e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f))
383 st.write(e + f) 417 st.write(e + f)
384 self.dirty = 0 418 self.dirty = 0
385 419
386 def changes(self, files, ignore): 420 def walk(self, files = None, match = util.always):
387 self.read() 421 self.read()
388 dc = self.map.copy() 422 dc = self.map.copy()
389 lookup, changed, added, unknown = [], [], [], [] 423 # walk all files by default
390
391 # compare all files by default
392 if not files: files = [self.root] 424 if not files: files = [self.root]
393 425 def traverse():
394 # recursive generator of all files listed
395 def walk(files):
396 for f in util.unique(files): 426 for f in util.unique(files):
397 f = os.path.join(self.root, f) 427 f = os.path.join(self.root, f)
398 if os.path.isdir(f): 428 if os.path.isdir(f):
399 for dir, subdirs, fl in os.walk(f): 429 for dir, subdirs, fl in os.walk(f):
400 d = dir[len(self.root) + 1:] 430 d = dir[len(self.root) + 1:]
431 if d == '.hg':
432 subdirs[:] = []
433 continue
401 for sd in subdirs: 434 for sd in subdirs:
402 if ignore(os.path.join(d, sd +'/')): 435 ds = os.path.join(d, sd +'/')
436 if self.ignore(ds) or not match(ds):
403 subdirs.remove(sd) 437 subdirs.remove(sd)
404 for fn in fl: 438 for fn in fl:
405 fn = util.pconvert(os.path.join(d, fn)) 439 fn = util.pconvert(os.path.join(d, fn))
406 yield fn 440 yield 'f', fn
407 else: 441 else:
408 yield f[len(self.root) + 1:] 442 yield 'f', f[len(self.root) + 1:]
409 443
410 for k in dc.keys(): 444 for k in dc.keys():
411 yield k 445 yield 'm', k
412 446
413 for fn in util.unique(walk(files)): 447 # yield only files that match: all in dirstate, others only if
448 # not in .hgignore
449
450 for src, fn in util.unique(traverse()):
451 if fn in dc:
452 del dc[fn]
453 elif self.ignore(fn):
454 continue
455 if match(fn):
456 yield src, fn
457
458 def changes(self, files = None, match = util.always):
459 self.read()
460 dc = self.map.copy()
461 lookup, changed, added, unknown = [], [], [], []
462
463 for src, fn in self.walk(files, match):
414 try: s = os.stat(os.path.join(self.root, fn)) 464 try: s = os.stat(os.path.join(self.root, fn))
415 except: continue 465 except: continue
416 466
417 if fn in dc: 467 if fn in dc:
418 c = dc[fn] 468 c = dc[fn]
427 elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100: 477 elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100:
428 changed.append(fn) 478 changed.append(fn)
429 elif c[1] != s.st_mode or c[3] != s.st_mtime: 479 elif c[1] != s.st_mode or c[3] != s.st_mtime:
430 lookup.append(fn) 480 lookup.append(fn)
431 else: 481 else:
432 if not ignore(fn): unknown.append(fn) 482 if match(fn): unknown.append(fn)
433 483
434 return (lookup, changed, added, dc.keys(), unknown) 484 return (lookup, changed, added, filter(match, dc.keys()), unknown)
435 485
436 # used to avoid circular references so destructors work 486 # used to avoid circular references so destructors work
437 def opener(base): 487 def opener(base):
438 p = base 488 p = base
439 def o(path, mode="r"): 489 def o(path, mode="r"):
491 541
492 self.opener = opener(self.path) 542 self.opener = opener(self.path)
493 self.wopener = opener(self.root) 543 self.wopener = opener(self.root)
494 self.manifest = manifest(self.opener) 544 self.manifest = manifest(self.opener)
495 self.changelog = changelog(self.opener) 545 self.changelog = changelog(self.opener)
496 self.ignorefunc = None
497 self.tagscache = None 546 self.tagscache = None
498 self.nodetagscache = None 547 self.nodetagscache = None
499 548
500 if not self.remote: 549 if not self.remote:
501 self.dirstate = dirstate(self.opener, ui, self.root) 550 self.dirstate = dirstate(self.opener, ui, self.root)
502 try: 551 try:
503 self.ui.readconfig(self.opener("hgrc")) 552 self.ui.readconfig(self.opener("hgrc"))
504 except IOError: pass 553 except IOError: pass
505
506 def ignore(self, f):
507 if not self.ignorefunc:
508 bigpat = ["^.hg/$"]
509 try:
510 l = file(self.wjoin(".hgignore"))
511 for pat in l:
512 if pat != "\n":
513 p = util.pconvert(pat[:-1])
514 try:
515 r = re.compile(p)
516 except:
517 self.ui.warn("ignoring invalid ignore"
518 + " regular expression '%s'\n" % p)
519 else:
520 bigpat.append(util.pconvert(pat[:-1]))
521 except IOError: pass
522
523 s = "(?:%s)" % (")|(?:".join(bigpat))
524 r = re.compile(s)
525 self.ignorefunc = r.search
526
527 return self.ignorefunc(f)
528 554
529 def hook(self, name, **args): 555 def hook(self, name, **args):
530 s = self.ui.config("hooks", name) 556 s = self.ui.config("hooks", name)
531 if s: 557 if s:
532 self.ui.note("running hook %s: %s\n" % (name, s)) 558 self.ui.note("running hook %s: %s\n" % (name, s))
736 elif s == 'r': 762 elif s == 'r':
737 remove.append(f) 763 remove.append(f)
738 else: 764 else:
739 self.ui.warn("%s not tracked!\n" % f) 765 self.ui.warn("%s not tracked!\n" % f)
740 else: 766 else:
741 (c, a, d, u) = self.changes(None, None) 767 (c, a, d, u) = self.changes()
742 commit = c + a 768 commit = c + a
743 remove = d 769 remove = d
744 770
745 if not commit and not remove: 771 if not commit and not remove:
746 self.ui.status("nothing changed\n") 772 self.ui.status("nothing changed\n")
813 self.dirstate.forget(remove) 839 self.dirstate.forget(remove)
814 840
815 if not self.hook("commit", node=hex(n)): 841 if not self.hook("commit", node=hex(n)):
816 return 1 842 return 1
817 843
818 def changes(self, node1, node2, files=None): 844 def walk(self, node = None, files = [], match = util.always):
845 if node:
846 for fn in self.manifest.read(self.changelog.read(node)[0]):
847 yield 'm', fn
848 else:
849 for src, fn in self.dirstate.walk(files, match):
850 yield src, fn
851
852 def changes(self, node1 = None, node2 = None, files = [],
853 match = util.always):
819 mf2, u = None, [] 854 mf2, u = None, []
820 855
821 def fcmp(fn, mf): 856 def fcmp(fn, mf):
822 t1 = self.wfile(fn).read() 857 t1 = self.wfile(fn).read()
823 t2 = self.file(fn).revision(mf[fn]) 858 t2 = self.file(fn).revision(mf[fn])
824 return cmp(t1, t2) 859 return cmp(t1, t2)
825 860
861 def mfmatches(node):
862 mf = dict(self.manifest.read(node))
863 for fn in mf.keys():
864 if not match(fn):
865 del mf[fn]
866 return mf
867
826 # are we comparing the working directory? 868 # are we comparing the working directory?
827 if not node2: 869 if not node2:
828 l, c, a, d, u = self.dirstate.changes(files, self.ignore) 870 l, c, a, d, u = self.dirstate.changes(files, match)
829 871
830 # are we comparing working dir against its parent? 872 # are we comparing working dir against its parent?
831 if not node1: 873 if not node1:
832 if l: 874 if l:
833 # do a full compare of any files that might have changed 875 # do a full compare of any files that might have changed
834 change = self.changelog.read(self.dirstate.parents()[0]) 876 change = self.changelog.read(self.dirstate.parents()[0])
835 mf2 = self.manifest.read(change[0]) 877 mf2 = mfmatches(change[0])
836 for f in l: 878 for f in l:
837 if fcmp(f, mf2): 879 if fcmp(f, mf2):
838 c.append(f) 880 c.append(f)
839 881
840 for l in c, a, d, u: 882 for l in c, a, d, u:
845 # are we comparing working dir against non-tip? 887 # are we comparing working dir against non-tip?
846 # generate a pseudo-manifest for the working dir 888 # generate a pseudo-manifest for the working dir
847 if not node2: 889 if not node2:
848 if not mf2: 890 if not mf2:
849 change = self.changelog.read(self.dirstate.parents()[0]) 891 change = self.changelog.read(self.dirstate.parents()[0])
850 mf2 = self.manifest.read(change[0]).copy() 892 mf2 = mfmatches(change[0])
851 for f in a + c + l: 893 for f in a + c + l:
852 mf2[f] = "" 894 mf2[f] = ""
853 for f in d: 895 for f in d:
854 if f in mf2: del mf2[f] 896 if f in mf2: del mf2[f]
855 else: 897 else:
856 change = self.changelog.read(node2) 898 change = self.changelog.read(node2)
857 mf2 = self.manifest.read(change[0]) 899 mf2 = mfmatches(change[0])
858 900
859 # flush lists from dirstate before comparing manifests 901 # flush lists from dirstate before comparing manifests
860 c, a = [], [] 902 c, a = [], []
861 903
862 change = self.changelog.read(node1) 904 change = self.changelog.read(node1)
863 mf1 = self.manifest.read(change[0]).copy() 905 mf1 = mfmatches(change[0])
864 906
865 for fn in mf2: 907 for fn in mf2:
866 if mf1.has_key(fn): 908 if mf1.has_key(fn):
867 if mf1[fn] != mf2[fn]: 909 if mf1[fn] != mf2[fn]:
868 if mf2[fn] != "" or fcmp(fn, mf1): 910 if mf2[fn] != "" or fcmp(fn, mf1):
883 p = self.wjoin(f) 925 p = self.wjoin(f)
884 if not os.path.exists(p): 926 if not os.path.exists(p):
885 self.ui.warn("%s does not exist!\n" % f) 927 self.ui.warn("%s does not exist!\n" % f)
886 elif not os.path.isfile(p): 928 elif not os.path.isfile(p):
887 self.ui.warn("%s not added: mercurial only supports files currently\n" % f) 929 self.ui.warn("%s not added: mercurial only supports files currently\n" % f)
888 elif self.dirstate.state(f) == 'n': 930 elif self.dirstate.state(f) in 'an':
889 self.ui.warn("%s already tracked!\n" % f) 931 self.ui.warn("%s already tracked!\n" % f)
890 else: 932 else:
891 self.dirstate.update([f], "a") 933 self.dirstate.update([f], "a")
892 934
893 def forget(self, list): 935 def forget(self, list):
1266 m2 = self.manifest.read(m2n) 1308 m2 = self.manifest.read(m2n)
1267 mf2 = self.manifest.readflags(m2n) 1309 mf2 = self.manifest.readflags(m2n)
1268 ma = self.manifest.read(man) 1310 ma = self.manifest.read(man)
1269 mfa = self.manifest.readflags(man) 1311 mfa = self.manifest.readflags(man)
1270 1312
1271 (c, a, d, u) = self.changes(None, None) 1313 (c, a, d, u) = self.changes()
1272 1314
1273 # is this a jump, or a merge? i.e. is there a linear path 1315 # is this a jump, or a merge? i.e. is there a linear path
1274 # from p1 to p2? 1316 # from p1 to p2?
1275 linear_path = (pa == p1 or pa == p2) 1317 linear_path = (pa == p1 or pa == p2)
1276 1318