changeset 4334:1cc5fc1d0994

Merge with crew-stable.
author Alexis S. L. Carvalho <alexis@cecm.usp.br>
date Mon, 09 Apr 2007 04:57:25 -0300
parents aa26759c6fb3 (current diff) 4f721e96f1de (diff)
children 35ad84669ca5
files hgext/mq.py mercurial/dirstate.py mercurial/localrepo.py mercurial/util.py
diffstat 6 files changed, 91 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/mq.py
+++ b/hgext/mq.py
@@ -471,8 +471,16 @@ class queue:
             patcherr = not patcherr
 
             if merge and files:
-                # Mark as merged and update dirstate parent info
-                repo.dirstate.update(repo.dirstate.filterfiles(files.keys()), 'm')
+                # Mark as removed/merged and update dirstate parent info
+                removed = []
+                merged = []
+                for f in files:
+                    if os.path.exists(repo.dirstate.wjoin(f)):
+                        merged.append(f)
+                    else:
+                        removed.append(f)
+                repo.dirstate.update(repo.dirstate.filterfiles(removed), 'r')
+                repo.dirstate.update(repo.dirstate.filterfiles(merged), 'm')
                 p1, p2 = repo.dirstate.parents()
                 repo.dirstate.setparents(p1, merge)
             files = patch.updatedir(self.ui, repo, files, wlock=wlock)
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -314,7 +314,7 @@ class dirstate(object):
     def write(self):
         if not self.dirty:
             return
-        st = self.opener("dirstate", "w", atomic=True)
+        st = self.opener("dirstate", "w", atomictemp=True)
         st.write("".join(self.pl))
         for f, e in self.map.items():
             c = self.copied(f)
@@ -322,6 +322,7 @@ class dirstate(object):
                 f = f + "\0" + c
             e = struct.pack(self.format, e[0], e[1], e[2], e[3], len(f))
             st.write(e + f)
+        st.rename()
         self.dirty = 0
 
     def filterfiles(self, files):
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -417,10 +417,11 @@ class localrepository(repo.repository):
 
     def _writebranchcache(self, branches, tip, tiprev):
         try:
-            f = self.opener("branch.cache", "w")
+            f = self.opener("branch.cache", "w", atomictemp=True)
             f.write("%s %s\n" % (hex(tip), tiprev))
             for label, node in branches.iteritems():
                 f.write("%s %s\n" % (hex(node), label))
+            f.rename()
         except IOError:
             pass
 
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -804,6 +804,9 @@ def linkfunc(path, fallback):
         return lambda x: os.path.islink(os.path.join(path, x))
     return fallback
 
+_umask = os.umask(0)
+os.umask(_umask)
+
 # Platform specific variants
 if os.name == 'nt':
     import msvcrt
@@ -930,8 +933,6 @@ if os.name == 'nt':
 
 else:
     nulldev = '/dev/null'
-    _umask = os.umask(0)
-    os.umask(_umask)
 
     def rcfiles(path):
         rcs = [os.path.join(path, 'hgrc')]
@@ -1103,18 +1104,32 @@ def opener(base, audit=True):
     p = base
     audit_p = audit
 
-    def mktempcopy(name):
+    def mktempcopy(name, emptyok=False):
         d, fn = os.path.split(name)
         fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
         os.close(fd)
-        ofp = posixfile(temp, "wb")
+        # Temporary files are created with mode 0600, which is usually not
+        # what we want.  If the original file already exists, just copy
+        # its mode.  Otherwise, manually obey umask.
+        try:
+            st_mode = os.lstat(name).st_mode
+        except OSError, inst:
+            if inst.errno != errno.ENOENT:
+                raise
+            st_mode = 0666 & ~_umask
+        os.chmod(temp, st_mode)
+        if emptyok:
+            return temp
         try:
             try:
                 ifp = posixfile(name, "rb")
             except IOError, inst:
+                if inst.errno == errno.ENOENT:
+                    return temp
                 if not getattr(inst, 'filename', None):
                     inst.filename = name
                 raise
+            ofp = posixfile(temp, "wb")
             for chunk in filechunkiter(ifp):
                 ofp.write(chunk)
             ifp.close()
@@ -1123,15 +1138,13 @@ def opener(base, audit=True):
             try: os.unlink(temp)
             except: pass
             raise
-        st = os.lstat(name)
-        os.chmod(temp, st.st_mode)
         return temp
 
     class atomictempfile(posixfile):
         """the file will only be copied when rename is called"""
         def __init__(self, name, mode):
             self.__name = name
-            self.temp = mktempcopy(name)
+            self.temp = mktempcopy(name, emptyok=('w' in mode))
             posixfile.__init__(self, self.temp, mode)
         def rename(self):
             if not self.closed:
@@ -1165,16 +1178,16 @@ def opener(base, audit=True):
             try:
                 nlink = nlinks(f)
             except OSError:
+                nlink = 0
                 d = os.path.dirname(f)
                 if not os.path.isdir(d):
                     os.makedirs(d)
-            else:
-                if atomic:
-                    return atomicfile(f, mode)
-                elif atomictemp:
-                    return atomictempfile(f, mode)
-                if nlink > 1:
-                    rename(mktempcopy(f), f)
+            if atomic:
+                return atomicfile(f, mode)
+            elif atomictemp:
+                return atomictempfile(f, mode)
+            if nlink > 1:
+                rename(mktempcopy(f), f)
         return posixfile(f, mode)
 
     return o
new file mode 100755
--- /dev/null
+++ b/tests/test-mq-merge
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+# Test issue 529 - mq aborts when merging patch deleting files
+
+rewrite_path()
+{
+    sed -e 's:\\:/:g' -e 's:[^ ]*/t/::g'
+}
+
+echo "[extensions]" >> $HGRCPATH
+echo "hgext.mq=" >> $HGRCPATH
+
+# Commit two dummy files in "init" changeset
+hg init t
+cd t
+echo a > a
+echo b > b
+hg ci -Am init
+hg tag -l init
+
+# Create a patch removing a
+hg qnew rm_a
+hg rm a
+hg qrefresh -m "rm a"
+
+# Save the patch queue so we can merge it later
+hg qsave -c -e 2>&1 | rewrite_path
+
+# Update b and commit in an "update" changeset
+hg up -C init
+echo b >> b
+hg st
+hg ci -m update
+
+# Here, qpush used to abort with :
+# The system cannot find the file specified => a
+hg manifest
+hg qpush -a -m 2>&1 | rewrite_path
+hg manifest
new file mode 100644
--- /dev/null
+++ b/tests/test-mq-merge.out
@@ -0,0 +1,11 @@
+adding a
+adding b
+copy .hg/patches to .hg/patches.1
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+M b
+a
+b
+merging with queue at: .hg/patches.1
+applying rm_a
+Now at: rm_a
+b