mercurial/hg.py
changeset 276 10e325db7347
parent 275 61d45b0ba8fb
child 277 79279550c8ff
--- a/mercurial/hg.py	Tue Jun 07 20:06:05 2005 -0800
+++ b/mercurial/hg.py	Wed Jun 08 10:16:33 2005 -0800
@@ -11,6 +11,15 @@
 demandload(globals(), "re lock urllib urllib2 transaction time socket")
 demandload(globals(), "tempfile byterange difflib")
 
+def is_exec(f):
+    return (os.stat(f).st_mode & 0100 != 0)
+
+def set_exec(f, mode):
+    s = os.stat(f).st_mode
+    if (s & 0100 != 0) == mode:
+        return
+    os.chmod(f, s & 0666 | (mode * 0111))
+
 class filelog(revlog):
     def __init__(self, opener, path):
         revlog.__init__(self, opener,
@@ -85,13 +94,20 @@
             return self.mapcache[1].copy()
         text = self.revision(node)
         map = {}
+        flag = {}
         self.listcache = (text, text.splitlines(1))
         for l in self.listcache[1]:
             (f, n) = l.split('\0')
             map[f] = bin(n[:40])
-        self.mapcache = (node, map)
+            flag[f] = (n[40:-1] == "x")
+        self.mapcache = (node, map, flag)
         return map
 
+    def readflags(self, node):
+        if self.mapcache or self.mapcache[0] != node:
+            self.read(node)
+        return self.mapcache[2]
+
     def diff(self, a, b):
         # this is sneaky, as we're not actually using a and b
         if self.listcache and self.addlist and self.listcache[0] == a:
@@ -103,11 +119,13 @@
         else:
             return mdiff.textdiff(a, b)
 
-    def add(self, map, transaction, link, p1=None, p2=None):
+    def add(self, map, flags, transaction, link, p1=None, p2=None):
         files = map.keys()
         files.sort()
 
-        self.addlist = ["%s\000%s\n" % (f, hex(map[f])) for f in files]
+        self.addlist = ["%s\000%s%s\n" %
+                        (f, hex(map[f]), flags[f] and "x" or '')
+                        for f in files]
         text = "".join(self.addlist)
 
         n = self.addrevision(text, transaction, link, p1, p2)
@@ -442,6 +460,7 @@
         c1 = self.changelog.read(p1)
         c2 = self.changelog.read(p2)
         m1 = self.manifest.read(c1[0])
+        mf1 = self.manifest.readflags(c1[0])
         m2 = self.manifest.read(c2[0])
         lock = self.lock()
         tr = self.transaction()
@@ -453,7 +472,9 @@
         for f in commit:
             self.ui.note(f + "\n")
             try:
-                t = file(self.wjoin(f)).read()
+                fp = self.wjoin(f)
+                mf1[f] = is_exec(fp)
+                t = file(fp).read()
             except IOError:
                 self.warn("trouble committing %s!\n" % f)
                 raise
@@ -466,7 +487,7 @@
         # update manifest
         m1.update(new)
         for f in remove: del m1[f]
-        mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0])
+        mn = self.manifest.add(m1, mf1, tr, linkrev, c1[0], c2[0])
 
         # add changeset
         new = new.keys()
@@ -525,7 +546,7 @@
                         added.append(fn)
                     elif c[0] == 'r':
                         unknown.append(fn)
-                    elif c[2] != s.st_size:
+                    elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100:
                         changed.append(fn)
                     elif c[1] != s.st_mode or c[3] != s.st_mtime:
                         if fcmp(fn):
@@ -846,8 +867,11 @@
         m2n = self.changelog.read(p2)[0]
         man = self.manifest.ancestor(m1n, m2n)
         m1 = self.manifest.read(m1n)
+        mf1 = self.manifest.readflags(m1n)
         m2 = self.manifest.read(m2n)
+        mf2 = self.manifest.readflags(m2n)
         ma = self.manifest.read(man)
+        mfa = self.manifest.readflags(m2n)
 
         (c, a, d, u) = self.diffdir(self.root)
 
@@ -863,8 +887,10 @@
 
         # construct a working dir manifest
         mw = m1.copy()
+        mfw = mf1.copy()
         for f in a + c + u:
             mw[f] = ""
+            mfw[f] = is_exec(self.wjoin(f))
         for f in d:
             if f in mw: del mw[f]
 
@@ -875,6 +901,11 @@
                     if n != a and m2[f] != a:
                         self.ui.debug(" %s versions differ, resolve\n" % f)
                         merge[f] = (m1.get(f, nullid), m2[f])
+                        # merge executable bits
+                        # "if we changed or they changed, change in merge"
+                        a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
+                        mode = ((a^b) | (a^c)) ^ a
+                        merge[f] = (m1.get(f, nullid), m2[f], mode)
                     elif m2[f] != a:
                         self.ui.debug(" remote %s is newer, get\n" % f)
                         get[f] = m2[f]
@@ -939,12 +970,14 @@
         for f in files:
             if f[0] == "/": continue
             self.ui.note("getting %s\n" % f)
-            t = self.file(f).revision(get[f])
+            t = self.file(f).read(get[f])
+            wp = self.wjoin(f)
             try:
-                file(self.wjoin(f), "w").write(t)
+                file(wp, "w").write(t)
             except IOError:
-                os.makedirs(os.path.dirname(f))
-                file(self.wjoin(f), "w").write(t)
+                os.makedirs(os.path.dirname(wp))
+                file(wp, "w").write(t)
+            set_exec(wp, mf2[f])
             self.dirstate.update([f], mode)
 
         # merge the tricky bits
@@ -952,8 +985,9 @@
         files.sort()
         for f in files:
             self.ui.status("merging %s\n" % f)
-            m, o = merge[f]
+            m, o, flag = merge[f]
             self.merge3(f, m, o)
+            set_exec(wp, flag)
             self.dirstate.update([f], 'm')
 
         for f in remove: