changeset 50089:5fb2546d0df1 stable

dirstate: handle missing backup file on restoration This is the stable counter part to e358f6e0e50e. Since 6.4 will stop writing undo.dirstate in some case (actually… at all), a transaction created with 6.4 and recover/rolledback with 6.3 need to work to a certain degreee. This changeset add the necessary bits so that we don't get a traceback from 6..3 in this cases.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Fri, 17 Feb 2023 14:00:39 +0100
parents 4fc6b423fa97
children 010a1e73f69e
files mercurial/dirstate.py
diffstat 1 files changed, 23 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/dirstate.py	Tue Feb 14 11:56:02 2023 -0500
+++ b/mercurial/dirstate.py	Fri Feb 17 14:00:39 2023 +0100
@@ -1444,6 +1444,9 @@
         """return a filename to backup a data-file or None"""
         if not self._use_dirstate_v2:
             return None
+        if self._map.docket.uuid is None:
+            # not created yet, nothing to backup
+            return None
         data_filename = self._map.docket.data_filename()
         return data_filename, self.data_backup_filename(backupname)
 
@@ -1514,10 +1517,23 @@
         # this "invalidate()" prevents "wlock.release()" from writing
         # changes of dirstate out after restoring from backup file
         self.invalidate()
+        o = self._opener
+        if not o.exists(backupname):
+            # there was no file backup, delete existing files
+            filename = self._actualfilename(tr)
+            data_file = None
+            if self._use_dirstate_v2 and self._map.docket.uuid is not None:
+                data_file = self._map.docket.data_filename()
+            if o.exists(filename):
+                o.unlink(filename)
+            if data_file is not None and o.exists(data_file):
+                o.unlink(data_file)
+            return
         filename = self._actualfilename(tr)
-        o = self._opener
         data_pair = self.backup_data_file(backupname)
-        if util.samefile(o.join(backupname), o.join(filename)):
+        if o.exists(filename) and util.samefile(
+            o.join(backupname), o.join(filename)
+        ):
             o.unlink(backupname)
         else:
             o.rename(backupname, filename, checkambig=True)
@@ -1534,11 +1550,11 @@
     def clearbackup(self, tr, backupname):
         '''Clear backup file'''
         o = self._opener
-        data_backup = self.backup_data_file(backupname)
-        o.unlink(backupname)
-
-        if data_backup is not None:
-            o.unlink(data_backup[0])
+        if o.exists(backupname):
+            data_backup = self.backup_data_file(backupname)
+            o.unlink(backupname)
+            if data_backup is not None:
+                o.unlink(data_backup[0])
 
     def verify(self, m1, m2):
         """check the dirstate content again the parent manifest and yield errors"""