add hg and python
This commit is contained in:
parent
3a742c699f
commit
458120dd40
3709 changed files with 1244309 additions and 1 deletions
165
sys/lib/python/mercurial/transaction.py
Normal file
165
sys/lib/python/mercurial/transaction.py
Normal file
|
@ -0,0 +1,165 @@
|
|||
# transaction.py - simple journalling scheme for mercurial
|
||||
#
|
||||
# This transaction scheme is intended to gracefully handle program
|
||||
# errors and interruptions. More serious failures like system crashes
|
||||
# can be recovered with an fsck-like tool. As the whole repository is
|
||||
# effectively log-structured, this should amount to simply truncating
|
||||
# anything that isn't referenced in the changelog.
|
||||
#
|
||||
# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
|
||||
#
|
||||
# This software may be used and distributed according to the terms of the
|
||||
# GNU General Public License version 2, incorporated herein by reference.
|
||||
|
||||
from i18n import _
|
||||
import os, errno
|
||||
import error
|
||||
|
||||
def active(func):
|
||||
def _active(self, *args, **kwds):
|
||||
if self.count == 0:
|
||||
raise error.Abort(_(
|
||||
'cannot use transaction when it is already committed/aborted'))
|
||||
return func(self, *args, **kwds)
|
||||
return _active
|
||||
|
||||
def _playback(journal, report, opener, entries, unlink=True):
|
||||
for f, o, ignore in entries:
|
||||
if o or not unlink:
|
||||
try:
|
||||
opener(f, 'a').truncate(o)
|
||||
except:
|
||||
report(_("failed to truncate %s\n") % f)
|
||||
raise
|
||||
else:
|
||||
try:
|
||||
fn = opener(f).name
|
||||
os.unlink(fn)
|
||||
except IOError, inst:
|
||||
if inst.errno != errno.ENOENT:
|
||||
raise
|
||||
os.unlink(journal)
|
||||
|
||||
class transaction(object):
|
||||
def __init__(self, report, opener, journal, after=None, createmode=None):
|
||||
self.journal = None
|
||||
|
||||
self.count = 1
|
||||
self.report = report
|
||||
self.opener = opener
|
||||
self.after = after
|
||||
self.entries = []
|
||||
self.map = {}
|
||||
self.journal = journal
|
||||
self._queue = []
|
||||
|
||||
self.file = open(self.journal, "w")
|
||||
if createmode is not None:
|
||||
os.chmod(self.journal, createmode & 0666)
|
||||
|
||||
def __del__(self):
|
||||
if self.journal:
|
||||
if self.entries: self._abort()
|
||||
self.file.close()
|
||||
|
||||
@active
|
||||
def startgroup(self):
|
||||
self._queue.append([])
|
||||
|
||||
@active
|
||||
def endgroup(self):
|
||||
q = self._queue.pop()
|
||||
d = ''.join(['%s\0%d\n' % (x[0], x[1]) for x in q])
|
||||
self.entries.extend(q)
|
||||
self.file.write(d)
|
||||
self.file.flush()
|
||||
|
||||
@active
|
||||
def add(self, file, offset, data=None):
|
||||
if file in self.map: return
|
||||
|
||||
if self._queue:
|
||||
self._queue[-1].append((file, offset, data))
|
||||
return
|
||||
|
||||
self.entries.append((file, offset, data))
|
||||
self.map[file] = len(self.entries) - 1
|
||||
# add enough data to the journal to do the truncate
|
||||
self.file.write("%s\0%d\n" % (file, offset))
|
||||
self.file.flush()
|
||||
|
||||
@active
|
||||
def find(self, file):
|
||||
if file in self.map:
|
||||
return self.entries[self.map[file]]
|
||||
return None
|
||||
|
||||
@active
|
||||
def replace(self, file, offset, data=None):
|
||||
'''
|
||||
replace can only replace already committed entries
|
||||
that are not pending in the queue
|
||||
'''
|
||||
|
||||
if file not in self.map:
|
||||
raise KeyError(file)
|
||||
index = self.map[file]
|
||||
self.entries[index] = (file, offset, data)
|
||||
self.file.write("%s\0%d\n" % (file, offset))
|
||||
self.file.flush()
|
||||
|
||||
@active
|
||||
def nest(self):
|
||||
self.count += 1
|
||||
return self
|
||||
|
||||
def running(self):
|
||||
return self.count > 0
|
||||
|
||||
@active
|
||||
def close(self):
|
||||
'''commit the transaction'''
|
||||
self.count -= 1
|
||||
if self.count != 0:
|
||||
return
|
||||
self.file.close()
|
||||
self.entries = []
|
||||
if self.after:
|
||||
self.after()
|
||||
else:
|
||||
os.unlink(self.journal)
|
||||
self.journal = None
|
||||
|
||||
@active
|
||||
def abort(self):
|
||||
'''abort the transaction (generally called on error, or when the
|
||||
transaction is not explicitly committed before going out of
|
||||
scope)'''
|
||||
self._abort()
|
||||
|
||||
def _abort(self):
|
||||
self.count = 0
|
||||
self.file.close()
|
||||
|
||||
if not self.entries: return
|
||||
|
||||
self.report(_("transaction abort!\n"))
|
||||
|
||||
try:
|
||||
try:
|
||||
_playback(self.journal, self.report, self.opener, self.entries, False)
|
||||
self.report(_("rollback completed\n"))
|
||||
except:
|
||||
self.report(_("rollback failed - please run hg recover\n"))
|
||||
finally:
|
||||
self.journal = None
|
||||
|
||||
|
||||
def rollback(opener, file, report):
|
||||
entries = []
|
||||
|
||||
for l in open(file).readlines():
|
||||
f, o = l.split('\0')
|
||||
entries.append((f, int(o), None))
|
||||
|
||||
_playback(file, report, opener, entries)
|
Loading…
Add table
Add a link
Reference in a new issue