##// END OF EJS Templates
patchbomb: fix parsing of multiple addresses, allow multiple addrs in --to/cc/bcc...
patchbomb: fix parsing of multiple addresses, allow multiple addrs in --to/cc/bcc Instead of using custom code to split apart addresses, we now use mail.parseaddrlist() which always does the Right Thing as it relies on Python's email.Utils.getaddresses(). Previously, 'hg email --to=foo,bar' only respected foo and discarded bar. Also, commas in names were not allowed in hgrc or the interactive prompt; specifying '"Lastname, Firstname" <foo>' would confuse patchbomb. The testcase uses '-m tmp.mbox' because -n (like in other tests) would disable address mangling.

File last commit:

r9693:c40a1ee2 default
r9947:4600e622 default
Show More
transaction.py
167 lines | 4.6 KiB | text/x-python | PythonLexer
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 # 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.
#
Vadim Gelfer
update copyrights.
r2859 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 #
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
# GNU General Public License version 2, incorporated herein by reference.
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
Matt Mackall
Simplify i18n imports
r3891 from i18n import _
Benoit Boissinot
add missing import from 618140c75d8d
r7335 import os, errno
Henrik Stuart
transaction: ensure finished transactions are not reused...
r8289 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
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
Henrik Stuart
transaction: refactor transaction.abort and rollback to use the same code...
r8294 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)
Benoit Boissinot
transaction: more specific exceptions, os.unlink can raise OSError
r9686 except IOError:
Henrik Stuart
transaction: refactor transaction.abort and rollback to use the same code...
r8294 report(_("failed to truncate %s\n") % f)
raise
else:
try:
fn = opener(f).name
os.unlink(fn)
Benoit Boissinot
transaction: more specific exceptions, os.unlink can raise OSError
r9686 except (IOError, OSError), inst:
Henrik Stuart
transaction: refactor transaction.abort and rollback to use the same code...
r8294 if inst.errno != errno.ENOENT:
raise
os.unlink(journal)
Eric Hopper
Convert all classes to new-style classes by deriving them from object.
r1559 class transaction(object):
Alexis S. L. Carvalho
make the journal/undo files from transactions inherit the mode from .hg/store
r6065 def __init__(self, report, opener, journal, after=None, createmode=None):
mpm@selenic.com
Implement recover and undo commands...
r162 self.journal = None
mason@suse.com
Automatic nesting into running transactions in the same repository....
r1806 self.count = 1
mpm@selenic.com
Remove all remaining print statements...
r582 self.report = report
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 self.opener = opener
mpm@selenic.com
Beginnings of transaction undo support
r95 self.after = after
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 self.entries = []
mpm@selenic.com
Fix multiple changes to file per transaction
r42 self.map = {}
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 self.journal = journal
Henrik Stuart
transaction: add atomic groups to transaction logic...
r8363 self._queue = []
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
self.file = open(self.journal, "w")
Alexis S. L. Carvalho
make the journal/undo files from transactions inherit the mode from .hg/store
r6065 if createmode is not None:
os.chmod(self.journal, createmode & 0666)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
def __del__(self):
mpm@selenic.com
transaction: __del__ should do nothing if the journal already exists...
r558 if self.journal:
Sune Foldager
transaction: always remove empty journal on abort...
r9693 self._abort()
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
Henrik Stuart
transaction: ensure finished transactions are not reused...
r8289 @active
Henrik Stuart
transaction: add atomic groups to transaction logic...
r8363 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
Chris Mason
...
r2084 def add(self, file, offset, data=None):
mpm@selenic.com
Fix multiple changes to file per transaction
r42 if file in self.map: return
Henrik Stuart
transaction: add atomic groups to transaction logic...
r8363
if self._queue:
self._queue[-1].append((file, offset, data))
return
Chris Mason
...
r2084 self.entries.append((file, offset, data))
self.map[file] = len(self.entries) - 1
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 # add enough data to the journal to do the truncate
self.file.write("%s\0%d\n" % (file, offset))
self.file.flush()
Henrik Stuart
transaction: ensure finished transactions are not reused...
r8289 @active
Chris Mason
...
r2084 def find(self, file):
if file in self.map:
return self.entries[self.map[file]]
return None
Henrik Stuart
transaction: ensure finished transactions are not reused...
r8289 @active
Chris Mason
...
r2084 def replace(self, file, offset, data=None):
Henrik Stuart
transaction: add atomic groups to transaction logic...
r8363 '''
replace can only replace already committed entries
that are not pending in the queue
'''
Chris Mason
...
r2084 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()
Henrik Stuart
transaction: ensure finished transactions are not reused...
r8289 @active
mason@suse.com
Automatic nesting into running transactions in the same repository....
r1806 def nest(self):
self.count += 1
return self
def running(self):
return self.count > 0
Henrik Stuart
transaction: ensure finished transactions are not reused...
r8289 @active
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 def close(self):
Greg Ward
transaction: document close(), abort() methods
r9220 '''commit the transaction'''
mason@suse.com
Automatic nesting into running transactions in the same repository....
r1806 self.count -= 1
if self.count != 0:
return
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 self.file.close()
self.entries = []
mpm@selenic.com
Beginnings of transaction undo support
r95 if self.after:
mpm@selenic.com
Fix undo after aborted commit bug...
r785 self.after()
Sune Foldager
transaction: always remove empty journal on abort...
r9693 if os.path.isfile(self.journal):
mpm@selenic.com
Beginnings of transaction undo support
r95 os.unlink(self.journal)
mpm@selenic.com
transaction: nullify journal after close()...
r573 self.journal = None
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
Henrik Stuart
transaction: ensure finished transactions are not reused...
r8289 @active
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 def abort(self):
Greg Ward
transaction: document close(), abort() methods
r9220 '''abort the transaction (generally called on error, or when the
transaction is not explicitly committed before going out of
scope)'''
Henrik Stuart
transaction: ensure finished transactions are not reused...
r8289 self._abort()
def _abort(self):
Henrik Stuart
transaction: reset transaction on abort...
r8290 self.count = 0
self.file.close()
Sune Foldager
transaction: always remove empty journal on abort...
r9693 if not self.entries:
if self.journal:
os.unlink(self.journal)
return
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 self.report(_("transaction abort!\n"))
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
Henrik Stuart
transaction: refactor transaction.abort and rollback to use the same code...
r8294 try:
mpm@selenic.com
Warn if we fail to truncate something
r108 try:
Henrik Stuart
transaction: refactor transaction.abort and rollback to use the same code...
r8294 _playback(self.journal, self.report, self.opener, self.entries, False)
self.report(_("rollback completed\n"))
mpm@selenic.com
Warn if we fail to truncate something
r108 except:
Henrik Stuart
transaction: refactor transaction.abort and rollback to use the same code...
r8294 self.report(_("rollback failed - please run hg recover\n"))
finally:
self.journal = None
Henrik Stuart
transaction: reset transaction on abort...
r8290
Henrik Stuart
transaction: refactor transaction.abort and rollback to use the same code...
r8294 def rollback(opener, file, report):
entries = []
mpm@selenic.com
Implement recover and undo commands...
r162 for l in open(file).readlines():
f, o = l.split('\0')
Henrik Stuart
transaction: refactor transaction.abort and rollback to use the same code...
r8294 entries.append((f, int(o), None))
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
Henrik Stuart
transaction: refactor transaction.abort and rollback to use the same code...
r8294 _playback(file, report, opener, entries)