comparison mercurial/hg.py @ 276:10e325db7347

add tracking of execute permissions -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 add tracking of execute permissions Changes to executable permissions are now tracked. We only track one bit here as the others tends to be problematic. "hg manifest" now shows file permissions. manifest hash: b76b85d12a9550fdc9fbc4f9446a812f3a2bbe88 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.0 (GNU/Linux) iD8DBQFCpzYBywK+sNU5EO8RAgkMAJ48l2ac12E20EFS24/i8ScwOtG4HwCgkbaE ue6l1RJroqzNA7vNeqwCwK4= =sEmJ -----END PGP SIGNATURE-----
author mpm@selenic.com
date Wed, 08 Jun 2005 10:16:33 -0800
parents 61d45b0ba8fb
children 79279550c8ff
comparison
equal deleted inserted replaced
275:61d45b0ba8fb 276:10e325db7347
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
451 linkrev = self.changelog.count() 470 linkrev = self.changelog.count()
452 commit.sort() 471 commit.sort()
453 for f in commit: 472 for f in commit:
454 self.ui.note(f + "\n") 473 self.ui.note(f + "\n")
455 try: 474 try:
456 t = file(self.wjoin(f)).read() 475 fp = self.wjoin(f)
476 mf1[f] = is_exec(fp)
477 t = file(fp).read()
457 except IOError: 478 except IOError:
458 self.warn("trouble committing %s!\n" % f) 479 self.warn("trouble committing %s!\n" % f)
459 raise 480 raise
460 481
461 r = self.file(f) 482 r = self.file(f)
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
523 changed.append(fn) 544 changed.append(fn)
524 elif c[0] == 'a': 545 elif c[0] == 'a':
525 added.append(fn) 546 added.append(fn)
526 elif c[0] == 'r': 547 elif c[0] == 'r':
527 unknown.append(fn) 548 unknown.append(fn)
528 elif c[2] != s.st_size: 549 elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100:
529 changed.append(fn) 550 changed.append(fn)
530 elif c[1] != s.st_mode or c[3] != s.st_mtime: 551 elif c[1] != s.st_mode or c[3] != s.st_mtime:
531 if fcmp(fn): 552 if fcmp(fn):
532 changed.append(fn) 553 changed.append(fn)
533 else: 554 else:
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)