8 import sys, struct, os |
8 import sys, struct, os |
9 from revlog import * |
9 from revlog import * |
10 from demandload import * |
10 from demandload import * |
11 demandload(globals(), "re lock urllib urllib2 transaction time socket") |
11 demandload(globals(), "re lock urllib urllib2 transaction time socket") |
12 demandload(globals(), "tempfile byterange difflib") |
12 demandload(globals(), "tempfile byterange difflib") |
|
13 |
|
14 def is_exec(f): |
|
15 return (os.stat(f).st_mode & 0100 != 0) |
|
16 |
|
17 def set_exec(f, mode): |
|
18 s = os.stat(f).st_mode |
|
19 if (s & 0100 != 0) == mode: |
|
20 return |
|
21 os.chmod(f, s & 0666 | (mode * 0111)) |
13 |
22 |
14 class filelog(revlog): |
23 class filelog(revlog): |
15 def __init__(self, opener, path): |
24 def __init__(self, opener, path): |
16 revlog.__init__(self, opener, |
25 revlog.__init__(self, opener, |
17 os.path.join("data", path + ".i"), |
26 os.path.join("data", path + ".i"), |
83 def read(self, node): |
92 def read(self, node): |
84 if self.mapcache and self.mapcache[0] == node: |
93 if self.mapcache and self.mapcache[0] == node: |
85 return self.mapcache[1].copy() |
94 return self.mapcache[1].copy() |
86 text = self.revision(node) |
95 text = self.revision(node) |
87 map = {} |
96 map = {} |
|
97 flag = {} |
88 self.listcache = (text, text.splitlines(1)) |
98 self.listcache = (text, text.splitlines(1)) |
89 for l in self.listcache[1]: |
99 for l in self.listcache[1]: |
90 (f, n) = l.split('\0') |
100 (f, n) = l.split('\0') |
91 map[f] = bin(n[:40]) |
101 map[f] = bin(n[:40]) |
92 self.mapcache = (node, map) |
102 flag[f] = (n[40:-1] == "x") |
|
103 self.mapcache = (node, map, flag) |
93 return map |
104 return map |
|
105 |
|
106 def readflags(self, node): |
|
107 if self.mapcache or self.mapcache[0] != node: |
|
108 self.read(node) |
|
109 return self.mapcache[2] |
94 |
110 |
95 def diff(self, a, b): |
111 def diff(self, a, b): |
96 # this is sneaky, as we're not actually using a and b |
112 # this is sneaky, as we're not actually using a and b |
97 if self.listcache and self.addlist and self.listcache[0] == a: |
113 if self.listcache and self.addlist and self.listcache[0] == a: |
98 d = mdiff.diff(self.listcache[1], self.addlist, 1) |
114 d = mdiff.diff(self.listcache[1], self.addlist, 1) |
101 return mdiff.textdiff(a, b) |
117 return mdiff.textdiff(a, b) |
102 return d |
118 return d |
103 else: |
119 else: |
104 return mdiff.textdiff(a, b) |
120 return mdiff.textdiff(a, b) |
105 |
121 |
106 def add(self, map, transaction, link, p1=None, p2=None): |
122 def add(self, map, flags, transaction, link, p1=None, p2=None): |
107 files = map.keys() |
123 files = map.keys() |
108 files.sort() |
124 files.sort() |
109 |
125 |
110 self.addlist = ["%s\000%s\n" % (f, hex(map[f])) for f in files] |
126 self.addlist = ["%s\000%s%s\n" % |
|
127 (f, hex(map[f]), flags[f] and "x" or '') |
|
128 for f in files] |
111 text = "".join(self.addlist) |
129 text = "".join(self.addlist) |
112 |
130 |
113 n = self.addrevision(text, transaction, link, p1, p2) |
131 n = self.addrevision(text, transaction, link, p1, p2) |
114 self.mapcache = (n, map) |
132 self.mapcache = (n, map) |
115 self.listcache = (text, self.addlist) |
133 self.listcache = (text, self.addlist) |
440 |
458 |
441 p1, p2 = self.dirstate.parents() |
459 p1, p2 = self.dirstate.parents() |
442 c1 = self.changelog.read(p1) |
460 c1 = self.changelog.read(p1) |
443 c2 = self.changelog.read(p2) |
461 c2 = self.changelog.read(p2) |
444 m1 = self.manifest.read(c1[0]) |
462 m1 = self.manifest.read(c1[0]) |
|
463 mf1 = self.manifest.readflags(c1[0]) |
445 m2 = self.manifest.read(c2[0]) |
464 m2 = self.manifest.read(c2[0]) |
446 lock = self.lock() |
465 lock = self.lock() |
447 tr = self.transaction() |
466 tr = self.transaction() |
448 |
467 |
449 # check in files |
468 # check in files |
464 new[f] = r.add(t, tr, linkrev, fp1, fp2) |
485 new[f] = r.add(t, tr, linkrev, fp1, fp2) |
465 |
486 |
466 # update manifest |
487 # update manifest |
467 m1.update(new) |
488 m1.update(new) |
468 for f in remove: del m1[f] |
489 for f in remove: del m1[f] |
469 mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0]) |
490 mn = self.manifest.add(m1, mf1, tr, linkrev, c1[0], c2[0]) |
470 |
491 |
471 # add changeset |
492 # add changeset |
472 new = new.keys() |
493 new = new.keys() |
473 new.sort() |
494 new.sort() |
474 |
495 |
844 p1, p2 = pl[0], node |
865 p1, p2 = pl[0], node |
845 m1n = self.changelog.read(p1)[0] |
866 m1n = self.changelog.read(p1)[0] |
846 m2n = self.changelog.read(p2)[0] |
867 m2n = self.changelog.read(p2)[0] |
847 man = self.manifest.ancestor(m1n, m2n) |
868 man = self.manifest.ancestor(m1n, m2n) |
848 m1 = self.manifest.read(m1n) |
869 m1 = self.manifest.read(m1n) |
|
870 mf1 = self.manifest.readflags(m1n) |
849 m2 = self.manifest.read(m2n) |
871 m2 = self.manifest.read(m2n) |
|
872 mf2 = self.manifest.readflags(m2n) |
850 ma = self.manifest.read(man) |
873 ma = self.manifest.read(man) |
|
874 mfa = self.manifest.readflags(m2n) |
851 |
875 |
852 (c, a, d, u) = self.diffdir(self.root) |
876 (c, a, d, u) = self.diffdir(self.root) |
853 |
877 |
854 # resolve the manifest to determine which files |
878 # resolve the manifest to determine which files |
855 # we care about merging |
879 # we care about merging |
861 get = {} |
885 get = {} |
862 remove = [] |
886 remove = [] |
863 |
887 |
864 # construct a working dir manifest |
888 # construct a working dir manifest |
865 mw = m1.copy() |
889 mw = m1.copy() |
|
890 mfw = mf1.copy() |
866 for f in a + c + u: |
891 for f in a + c + u: |
867 mw[f] = "" |
892 mw[f] = "" |
|
893 mfw[f] = is_exec(self.wjoin(f)) |
868 for f in d: |
894 for f in d: |
869 if f in mw: del mw[f] |
895 if f in mw: del mw[f] |
870 |
896 |
871 for f, n in mw.iteritems(): |
897 for f, n in mw.iteritems(): |
872 if f in m2: |
898 if f in m2: |
873 if n != m2[f]: |
899 if n != m2[f]: |
874 a = ma.get(f, nullid) |
900 a = ma.get(f, nullid) |
875 if n != a and m2[f] != a: |
901 if n != a and m2[f] != a: |
876 self.ui.debug(" %s versions differ, resolve\n" % f) |
902 self.ui.debug(" %s versions differ, resolve\n" % f) |
877 merge[f] = (m1.get(f, nullid), m2[f]) |
903 merge[f] = (m1.get(f, nullid), m2[f]) |
|
904 # merge executable bits |
|
905 # "if we changed or they changed, change in merge" |
|
906 a, b, c = mfa.get(f, 0), mfw[f], mf2[f] |
|
907 mode = ((a^b) | (a^c)) ^ a |
|
908 merge[f] = (m1.get(f, nullid), m2[f], mode) |
878 elif m2[f] != a: |
909 elif m2[f] != a: |
879 self.ui.debug(" remote %s is newer, get\n" % f) |
910 self.ui.debug(" remote %s is newer, get\n" % f) |
880 get[f] = m2[f] |
911 get[f] = m2[f] |
881 del m2[f] |
912 del m2[f] |
882 elif f in ma: |
913 elif f in ma: |
937 files = get.keys() |
968 files = get.keys() |
938 files.sort() |
969 files.sort() |
939 for f in files: |
970 for f in files: |
940 if f[0] == "/": continue |
971 if f[0] == "/": continue |
941 self.ui.note("getting %s\n" % f) |
972 self.ui.note("getting %s\n" % f) |
942 t = self.file(f).revision(get[f]) |
973 t = self.file(f).read(get[f]) |
|
974 wp = self.wjoin(f) |
943 try: |
975 try: |
944 file(self.wjoin(f), "w").write(t) |
976 file(wp, "w").write(t) |
945 except IOError: |
977 except IOError: |
946 os.makedirs(os.path.dirname(f)) |
978 os.makedirs(os.path.dirname(wp)) |
947 file(self.wjoin(f), "w").write(t) |
979 file(wp, "w").write(t) |
|
980 set_exec(wp, mf2[f]) |
948 self.dirstate.update([f], mode) |
981 self.dirstate.update([f], mode) |
949 |
982 |
950 # merge the tricky bits |
983 # merge the tricky bits |
951 files = merge.keys() |
984 files = merge.keys() |
952 files.sort() |
985 files.sort() |
953 for f in files: |
986 for f in files: |
954 self.ui.status("merging %s\n" % f) |
987 self.ui.status("merging %s\n" % f) |
955 m, o = merge[f] |
988 m, o, flag = merge[f] |
956 self.merge3(f, m, o) |
989 self.merge3(f, m, o) |
|
990 set_exec(wp, flag) |
957 self.dirstate.update([f], 'm') |
991 self.dirstate.update([f], 'm') |
958 |
992 |
959 for f in remove: |
993 for f in remove: |
960 self.ui.note("removing %s\n" % f) |
994 self.ui.note("removing %s\n" % f) |
961 os.unlink(f) |
995 os.unlink(f) |