diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -310,11 +310,12 @@ def manifest(ui, repo, rev = []): if rev: n = repo.manifest.lookup(rev) m = repo.manifest.read(n) + mf = repo.manifest.readflags(n) files = m.keys() files.sort() for f in files: - print hg.hex(m[f]), f + ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f)) def parents(ui, repo, node = None): '''show the parents of the current working dir''' diff --git a/mercurial/hg.py b/mercurial/hg.py --- a/mercurial/hg.py +++ b/mercurial/hg.py @@ -11,6 +11,15 @@ from demandload import * 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 @@ class manifest(revlog): 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 @@ class manifest(revlog): 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 @@ class localrepository: 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 @@ class localrepository: 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 @@ class localrepository: # 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 @@ class localrepository: 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 @@ class localrepository: 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 @@ class localrepository: # 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 @@ class localrepository: 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 @@ class localrepository: 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 @@ class localrepository: 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: