##// END OF EJS Templates
dirstateguard: use mktemp-like functionality to generate the backup filenames...
Kyle Lippincott -
r47777:222a42ac stable
parent child Browse files
Show More
@@ -1,84 +1,97 b''
1 # dirstateguard.py - class to allow restoring dirstate after failure
1 # dirstateguard.py - class to allow restoring dirstate after failure
2 #
2 #
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import os
10 from .i18n import _
11 from .i18n import _
11
12
12 from . import (
13 from . import (
13 error,
14 error,
14 narrowspec,
15 narrowspec,
16 requirements,
15 util,
17 util,
16 )
18 )
17
19
18
20
19 class dirstateguard(util.transactional):
21 class dirstateguard(util.transactional):
20 """Restore dirstate at unexpected failure.
22 """Restore dirstate at unexpected failure.
21
23
22 At the construction, this class does:
24 At the construction, this class does:
23
25
24 - write current ``repo.dirstate`` out, and
26 - write current ``repo.dirstate`` out, and
25 - save ``.hg/dirstate`` into the backup file
27 - save ``.hg/dirstate`` into the backup file
26
28
27 This restores ``.hg/dirstate`` from backup file, if ``release()``
29 This restores ``.hg/dirstate`` from backup file, if ``release()``
28 is invoked before ``close()``.
30 is invoked before ``close()``.
29
31
30 This just removes the backup file at ``close()`` before ``release()``.
32 This just removes the backup file at ``close()`` before ``release()``.
31 """
33 """
32
34
33 def __init__(self, repo, name):
35 def __init__(self, repo, name):
34 self._repo = repo
36 self._repo = repo
35 self._active = False
37 self._active = False
36 self._closed = False
38 self._closed = False
37 self._backupname = b'dirstate.backup.%s.%d' % (name, id(self))
39
38 self._narrowspecbackupname = b'narrowspec.backup.%s.%d' % (
40 def getname(prefix):
39 name,
41 fd, fname = repo.vfs.mkstemp(prefix=prefix)
40 id(self),
42 os.close(fd)
41 )
43 return fname
44
45 self._backupname = getname(b'dirstate.backup.%s.' % name)
42 repo.dirstate.savebackup(repo.currenttransaction(), self._backupname)
46 repo.dirstate.savebackup(repo.currenttransaction(), self._backupname)
43 narrowspec.savewcbackup(repo, self._narrowspecbackupname)
47 # Don't make this the empty string, things may join it with stuff and
48 # blindly try to unlink it, which could be bad.
49 self._narrowspecbackupname = None
50 if requirements.NARROW_REQUIREMENT in repo.requirements:
51 self._narrowspecbackupname = getname(
52 b'narrowspec.backup.%s.' % name
53 )
54 narrowspec.savewcbackup(repo, self._narrowspecbackupname)
44 self._active = True
55 self._active = True
45
56
46 def __del__(self):
57 def __del__(self):
47 if self._active: # still active
58 if self._active: # still active
48 # this may occur, even if this class is used correctly:
59 # this may occur, even if this class is used correctly:
49 # for example, releasing other resources like transaction
60 # for example, releasing other resources like transaction
50 # may raise exception before ``dirstateguard.release`` in
61 # may raise exception before ``dirstateguard.release`` in
51 # ``release(tr, ....)``.
62 # ``release(tr, ....)``.
52 self._abort()
63 self._abort()
53
64
54 def close(self):
65 def close(self):
55 if not self._active: # already inactivated
66 if not self._active: # already inactivated
56 msg = (
67 msg = (
57 _(b"can't close already inactivated backup: %s")
68 _(b"can't close already inactivated backup: %s")
58 % self._backupname
69 % self._backupname
59 )
70 )
60 raise error.Abort(msg)
71 raise error.Abort(msg)
61
72
62 self._repo.dirstate.clearbackup(
73 self._repo.dirstate.clearbackup(
63 self._repo.currenttransaction(), self._backupname
74 self._repo.currenttransaction(), self._backupname
64 )
75 )
65 narrowspec.clearwcbackup(self._repo, self._narrowspecbackupname)
76 if self._narrowspecbackupname:
77 narrowspec.clearwcbackup(self._repo, self._narrowspecbackupname)
66 self._active = False
78 self._active = False
67 self._closed = True
79 self._closed = True
68
80
69 def _abort(self):
81 def _abort(self):
70 narrowspec.restorewcbackup(self._repo, self._narrowspecbackupname)
82 if self._narrowspecbackupname:
83 narrowspec.restorewcbackup(self._repo, self._narrowspecbackupname)
71 self._repo.dirstate.restorebackup(
84 self._repo.dirstate.restorebackup(
72 self._repo.currenttransaction(), self._backupname
85 self._repo.currenttransaction(), self._backupname
73 )
86 )
74 self._active = False
87 self._active = False
75
88
76 def release(self):
89 def release(self):
77 if not self._closed:
90 if not self._closed:
78 if not self._active: # already inactivated
91 if not self._active: # already inactivated
79 msg = (
92 msg = (
80 _(b"can't release already inactivated backup: %s")
93 _(b"can't release already inactivated backup: %s")
81 % self._backupname
94 % self._backupname
82 )
95 )
83 raise error.Abort(msg)
96 raise error.Abort(msg)
84 self._abort()
97 self._abort()
General Comments 0
You need to be logged in to leave comments. Login now