Mercurial > public > mercurial-scm > hg
comparison mercurial/hg.py @ 536:c15b4bc0a11c
Refactor diffrevs/diffdir into changes
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Refactor diffrevs/diffdir into changes
Add dirstate.changes to replace most of diffdir
Add localrepository.changes to replace diffrevs/diffdir
This code can now efficiently check for changes in single files, and
often without consulting the manifest. This should eventually make 'hg
diff Makefile' in a large project much faster.
This also fixes a bug where 'hg diff -r tip' failed to account for
files that had been added but not committed yet.
manifest hash: 20fde5d4b4cee49a76bcfe50f2dacf58b1f2258b
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.0 (GNU/Linux)
iD8DBQFCxMxpywK+sNU5EO8RAhzOAJ9VLQJoC+hiRYQtTSPbDhXBEJfQZwCgpDx9
GAwQ9jZHNsgXckBfXNCkJV8=
=hMuc
-----END PGP SIGNATURE-----
author | mpm@selenic.com |
---|---|
date | Thu, 30 Jun 2005 20:54:01 -0800 |
parents | aace5b681fe9 |
children | 411e05b04ffa |
comparison
equal
deleted
inserted
replaced
535:fba26990604a | 536:c15b4bc0a11c |
---|---|
286 f = f + "\0" + c | 286 f = f + "\0" + c |
287 e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f)) | 287 e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f)) |
288 st.write(e + f) | 288 st.write(e + f) |
289 self.dirty = 0 | 289 self.dirty = 0 |
290 | 290 |
291 def dup(self): | 291 def changes(self, files, ignore): |
292 self.read() | 292 self.read() |
293 return self.map.copy() | 293 dc = self.map.copy() |
294 lookup, changed, added, unknown = [], [], [], [] | |
295 | |
296 # compare all files by default | |
297 if not files: files = [self.root] | |
298 | |
299 def uniq(g): | |
300 seen = {} | |
301 for f in g: | |
302 if f not in seen: | |
303 seen[f] = 1 | |
304 yield f | |
305 | |
306 # recursive generator of all files listed | |
307 def walk(files): | |
308 for f in uniq(files): | |
309 if os.path.isdir(f): | |
310 for dir, subdirs, fl in os.walk(f): | |
311 d = dir[len(self.root) + 1:] | |
312 if ".hg" in subdirs: subdirs.remove(".hg") | |
313 for fn in fl: | |
314 fn = util.pconvert(os.path.join(d, fn)) | |
315 yield fn | |
316 else: | |
317 yield f[len(self.root) + 1:] | |
318 | |
319 for fn in uniq(walk(files)): | |
320 try: s = os.stat(os.path.join(self.root, fn)) | |
321 except: continue | |
322 | |
323 if fn in dc: | |
324 c = dc[fn] | |
325 del dc[fn] | |
326 | |
327 if c[0] == 'm': | |
328 changed.append(fn) | |
329 elif c[0] == 'a': | |
330 added.append(fn) | |
331 elif c[0] == 'r': | |
332 unknown.append(fn) | |
333 elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100: | |
334 changed.append(fn) | |
335 elif c[1] != s.st_mode or c[3] != s.st_mtime: | |
336 lookup.append(fn) | |
337 else: | |
338 if not ignore(fn): unknown.append(fn) | |
339 | |
340 return (lookup, changed, added, dc.keys(), unknown) | |
294 | 341 |
295 # used to avoid circular references so destructors work | 342 # used to avoid circular references so destructors work |
296 def opener(base): | 343 def opener(base): |
297 p = base | 344 p = base |
298 def o(path, mode="r"): | 345 def o(path, mode="r"): |
566 elif s == 'r': | 613 elif s == 'r': |
567 remove.append(f) | 614 remove.append(f) |
568 else: | 615 else: |
569 self.ui.warn("%s not tracked!\n" % f) | 616 self.ui.warn("%s not tracked!\n" % f) |
570 else: | 617 else: |
571 (c, a, d, u) = self.diffdir(self.root) | 618 (c, a, d, u) = self.changes(None, None) |
572 commit = c + a | 619 commit = c + a |
573 remove = d | 620 remove = d |
574 | 621 |
575 if not commit and not remove: | 622 if not commit and not remove: |
576 self.ui.status("nothing changed\n") | 623 self.ui.status("nothing changed\n") |
642 | 689 |
643 self.dirstate.setparents(n) | 690 self.dirstate.setparents(n) |
644 self.dirstate.update(new, "n") | 691 self.dirstate.update(new, "n") |
645 self.dirstate.forget(remove) | 692 self.dirstate.forget(remove) |
646 | 693 |
647 def diffdir(self, path, changeset = None): | 694 def changes(self, node1, node2, *files): |
648 changed = [] | 695 # changed, added, deleted, unknown |
649 added = [] | 696 c, a, d, u, mf1 = [], [], [], [], None |
650 unknown = [] | 697 |
651 mf = {} | 698 def fcmp(fn, mf): |
652 | |
653 if changeset: | |
654 change = self.changelog.read(changeset) | |
655 mf = self.manifest.read(change[0]) | |
656 dc = dict.fromkeys(mf) | |
657 else: | |
658 changeset = self.dirstate.parents()[0] | |
659 change = self.changelog.read(changeset) | |
660 mf = self.manifest.read(change[0]) | |
661 dc = self.dirstate.dup() | |
662 | |
663 def fcmp(fn): | |
664 t1 = self.wfile(fn).read() | 699 t1 = self.wfile(fn).read() |
665 t2 = self.file(fn).revision(mf[fn]) | 700 t2 = self.file(fn).revision(mf[fn]) |
666 return cmp(t1, t2) | 701 return cmp(t1, t2) |
667 | 702 |
668 for dir, subdirs, files in os.walk(path): | 703 # are we comparing the working directory? |
669 d = dir[len(self.root)+1:] | 704 if not node1: |
670 if ".hg" in subdirs: subdirs.remove(".hg") | 705 l, c, a, d, u = self.dirstate.changes(files, self.ignore) |
671 | 706 |
672 for f in files: | 707 # are we comparing working dir against its parent? |
673 fn = util.pconvert(os.path.join(d, f)) | 708 if not node2: |
674 try: s = os.stat(os.path.join(self.root, fn)) | 709 if l: |
675 except: continue | 710 # do a full compare of any files that might have changed |
676 if fn in dc: | 711 change = self.changelog.read(self.dirstate.parents()[0]) |
677 c = dc[fn] | 712 mf1 = self.manifest.read(change[0]) |
678 del dc[fn] | 713 for f in lookup: |
679 if not c: | 714 if fcmp(f, mf): |
680 if fcmp(fn): | 715 c.append(f) |
681 changed.append(fn) | 716 return (c, a, d, u) |
682 elif c[0] == 'm': | 717 |
683 changed.append(fn) | 718 # are we comparing working dir against non-tip? |
684 elif c[0] == 'a': | 719 # generate a pseudo-manifest for the working dir |
685 added.append(fn) | 720 if not node1: |
686 elif c[0] == 'r': | 721 if not mf1: |
687 unknown.append(fn) | 722 change = self.changelog.read(self.dirstate.parents()[0]) |
688 elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100: | 723 mf1 = self.manifest.read(change[0]) |
689 changed.append(fn) | 724 for f in a + c + l: |
690 elif c[1] != s.st_mode or c[3] != s.st_mtime: | 725 mf1[f] = "" |
691 if fcmp(fn): | 726 for f in d: |
692 changed.append(fn) | 727 if f in mf1: del mf1[f] |
693 else: | 728 else: |
694 if self.ignore(fn): continue | 729 change = self.changelog.read(node1) |
695 unknown.append(fn) | 730 mf1 = self.manifest.read(change[0]) |
696 | 731 |
697 deleted = dc.keys() | |
698 deleted.sort() | |
699 | |
700 return (changed, added, deleted, unknown) | |
701 | |
702 def diffrevs(self, node1, node2): | |
703 changed, added = [], [] | |
704 | |
705 change = self.changelog.read(node1) | |
706 mf1 = self.manifest.read(change[0]) | |
707 change = self.changelog.read(node2) | 732 change = self.changelog.read(node2) |
708 mf2 = self.manifest.read(change[0]) | 733 mf2 = self.manifest.read(change[0]) |
709 | 734 |
710 for fn in mf2: | 735 for fn in mf2: |
711 if mf1.has_key(fn): | 736 if mf1.has_key(fn): |
712 if mf1[fn] != mf2[fn]: | 737 if mf1[fn] != mf2[fn]: |
713 changed.append(fn) | 738 if mf1[fn] != "" or fcmp(fn, mf2): |
739 c.append(fn) | |
714 del mf1[fn] | 740 del mf1[fn] |
715 else: | 741 else: |
716 added.append(fn) | 742 a.append(fn) |
717 | 743 |
718 deleted = mf1.keys() | 744 d = mf1.keys() |
719 deleted.sort() | 745 d.sort() |
720 | 746 |
721 return (changed, added, deleted) | 747 return (c, a, d, u) |
722 | 748 |
723 def add(self, list): | 749 def add(self, list): |
724 for f in list: | 750 for f in list: |
725 p = self.wjoin(f) | 751 p = self.wjoin(f) |
726 if not os.path.isfile(p): | 752 if not os.path.isfile(p): |
1042 m2 = self.manifest.read(m2n) | 1068 m2 = self.manifest.read(m2n) |
1043 mf2 = self.manifest.readflags(m2n) | 1069 mf2 = self.manifest.readflags(m2n) |
1044 ma = self.manifest.read(man) | 1070 ma = self.manifest.read(man) |
1045 mfa = self.manifest.readflags(man) | 1071 mfa = self.manifest.readflags(man) |
1046 | 1072 |
1047 (c, a, d, u) = self.diffdir(self.root) | 1073 (c, a, d, u) = self.changes(None, None) |
1048 | 1074 |
1049 # is this a jump, or a merge? i.e. is there a linear path | 1075 # is this a jump, or a merge? i.e. is there a linear path |
1050 # from p1 to p2? | 1076 # from p1 to p2? |
1051 linear_path = (pa == p1 or pa == p2) | 1077 linear_path = (pa == p1 or pa == p2) |
1052 | 1078 |