dirstateguard.py
96 lines
| 3.0 KiB
| text/x-python
|
PythonLexer
/ mercurial / dirstateguard.py
Augie Fackler
|
r30488 | # dirstateguard.py - class to allow restoring dirstate after failure | ||
# | ||||
Raphaël Gomès
|
r47575 | # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com> | ||
Augie Fackler
|
r30488 | # | ||
# This software may be used and distributed according to the terms of the | ||||
# GNU General Public License version 2 or any later version. | ||||
Kyle Lippincott
|
r47777 | import os | ||
Augie Fackler
|
r30488 | from .i18n import _ | ||
from . import ( | ||||
error, | ||||
Martin von Zweigbergk
|
r38905 | narrowspec, | ||
Kyle Lippincott
|
r47777 | requirements, | ||
Martin von Zweigbergk
|
r33790 | util, | ||
Augie Fackler
|
r30488 | ) | ||
Augie Fackler
|
r43345 | |||
Martin von Zweigbergk
|
r33790 | class dirstateguard(util.transactional): | ||
Augie Fackler
|
r46554 | """Restore dirstate at unexpected failure. | ||
Augie Fackler
|
r30488 | |||
At the construction, this class does: | ||||
- write current ``repo.dirstate`` out, and | ||||
- save ``.hg/dirstate`` into the backup file | ||||
This restores ``.hg/dirstate`` from backup file, if ``release()`` | ||||
is invoked before ``close()``. | ||||
This just removes the backup file at ``close()`` before ``release()``. | ||||
Augie Fackler
|
r46554 | """ | ||
Augie Fackler
|
r30488 | |||
def __init__(self, repo, name): | ||||
self._repo = repo | ||||
self._active = False | ||||
self._closed = False | ||||
Kyle Lippincott
|
r47777 | |||
def getname(prefix): | ||||
fd, fname = repo.vfs.mkstemp(prefix=prefix) | ||||
os.close(fd) | ||||
return fname | ||||
self._backupname = getname(b'dirstate.backup.%s.' % name) | ||||
Adam Simpkins
|
r33440 | repo.dirstate.savebackup(repo.currenttransaction(), self._backupname) | ||
Kyle Lippincott
|
r47777 | # Don't make this the empty string, things may join it with stuff and | ||
# blindly try to unlink it, which could be bad. | ||||
self._narrowspecbackupname = None | ||||
if requirements.NARROW_REQUIREMENT in repo.requirements: | ||||
self._narrowspecbackupname = getname( | ||||
b'narrowspec.backup.%s.' % name | ||||
) | ||||
narrowspec.savewcbackup(repo, self._narrowspecbackupname) | ||||
Augie Fackler
|
r30488 | self._active = True | ||
def __del__(self): | ||||
Augie Fackler
|
r43345 | if self._active: # still active | ||
Augie Fackler
|
r30488 | # this may occur, even if this class is used correctly: | ||
# for example, releasing other resources like transaction | ||||
# may raise exception before ``dirstateguard.release`` in | ||||
# ``release(tr, ....)``. | ||||
self._abort() | ||||
def close(self): | ||||
Augie Fackler
|
r43345 | if not self._active: # already inactivated | ||
msg = ( | ||||
Augie Fackler
|
r43347 | _(b"can't close already inactivated backup: %s") | ||
Augie Fackler
|
r43345 | % self._backupname | ||
) | ||||
Augie Fackler
|
r30488 | raise error.Abort(msg) | ||
Augie Fackler
|
r43345 | self._repo.dirstate.clearbackup( | ||
self._repo.currenttransaction(), self._backupname | ||||
) | ||||
Kyle Lippincott
|
r47777 | if self._narrowspecbackupname: | ||
narrowspec.clearwcbackup(self._repo, self._narrowspecbackupname) | ||||
Augie Fackler
|
r30488 | self._active = False | ||
self._closed = True | ||||
def _abort(self): | ||||
Kyle Lippincott
|
r47777 | if self._narrowspecbackupname: | ||
narrowspec.restorewcbackup(self._repo, self._narrowspecbackupname) | ||||
Augie Fackler
|
r43345 | self._repo.dirstate.restorebackup( | ||
self._repo.currenttransaction(), self._backupname | ||||
) | ||||
Augie Fackler
|
r30488 | self._active = False | ||
def release(self): | ||||
if not self._closed: | ||||
Augie Fackler
|
r43345 | if not self._active: # already inactivated | ||
msg = ( | ||||
Augie Fackler
|
r43347 | _(b"can't release already inactivated backup: %s") | ||
Augie Fackler
|
r43345 | % self._backupname | ||
) | ||||
Augie Fackler
|
r30488 | raise error.Abort(msg) | ||
self._abort() | ||||