Mercurial > hg > mercurial-source
comparison mercurial/transaction.py @ 8294:48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
This adds a change to the way that abort is processed, as it will not continue
truncating files beyond the first failure, otherwise the respective
functionality is maintained, i.e. abort will not unlink files, but rollback
will.
Co-contributor: Sune Foldager <cryo@cyanite.org>
author | Henrik Stuart <hg@hstuart.dk> |
---|---|
date | Mon, 04 May 2009 15:31:57 +0200 |
parents | 560af1bbfd6e |
children | c8e81f557da7 |
comparison
equal
deleted
inserted
replaced
8293:f00573bc93f8 | 8294:48a382c23226 |
---|---|
20 if self.count == 0: | 20 if self.count == 0: |
21 raise error.Abort(_( | 21 raise error.Abort(_( |
22 'cannot use transaction when it is already committed/aborted')) | 22 'cannot use transaction when it is already committed/aborted')) |
23 return func(self, *args, **kwds) | 23 return func(self, *args, **kwds) |
24 return _active | 24 return _active |
25 | |
26 def _playback(journal, report, opener, entries, unlink=True): | |
27 for f, o, ignore in entries: | |
28 if o or not unlink: | |
29 try: | |
30 opener(f, 'a').truncate(o) | |
31 except: | |
32 report(_("failed to truncate %s\n") % f) | |
33 raise | |
34 else: | |
35 try: | |
36 fn = opener(f).name | |
37 os.unlink(fn) | |
38 except OSError, inst: | |
39 if inst.errno != errno.ENOENT: | |
40 raise | |
41 os.unlink(journal) | |
25 | 42 |
26 class transaction(object): | 43 class transaction(object): |
27 def __init__(self, report, opener, journal, after=None, createmode=None): | 44 def __init__(self, report, opener, journal, after=None, createmode=None): |
28 self.journal = None | 45 self.journal = None |
29 | 46 |
99 | 116 |
100 if not self.entries: return | 117 if not self.entries: return |
101 | 118 |
102 self.report(_("transaction abort!\n")) | 119 self.report(_("transaction abort!\n")) |
103 | 120 |
104 failed = False | 121 try: |
105 for f, o, ignore in self.entries: | |
106 try: | 122 try: |
107 self.opener(f, "a").truncate(o) | 123 _playback(self.journal, self.report, self.opener, self.entries, False) |
124 self.report(_("rollback completed\n")) | |
108 except: | 125 except: |
109 failed = True | 126 self.report(_("rollback failed - please run hg recover\n")) |
110 self.report(_("failed to truncate %s\n") % f) | 127 finally: |
111 | 128 self.journal = None |
112 self.entries = [] | |
113 | |
114 if not failed: | |
115 os.unlink(self.journal) | |
116 self.report(_("rollback completed\n")) | |
117 else: | |
118 self.report(_("rollback failed - please run hg recover\n")) | |
119 | |
120 self.journal = None | |
121 | 129 |
122 | 130 |
123 def rollback(opener, file): | 131 def rollback(opener, file, report): |
124 files = {} | 132 entries = [] |
133 | |
125 for l in open(file).readlines(): | 134 for l in open(file).readlines(): |
126 f, o = l.split('\0') | 135 f, o = l.split('\0') |
127 files[f] = int(o) | 136 entries.append((f, int(o), None)) |
128 for f in files: | |
129 o = files[f] | |
130 if o: | |
131 opener(f, "a").truncate(int(o)) | |
132 else: | |
133 try: | |
134 fn = opener(f).name | |
135 os.unlink(fn) | |
136 except OSError, inst: | |
137 if inst.errno != errno.ENOENT: | |
138 raise | |
139 os.unlink(file) | |
140 | 137 |
138 _playback(file, report, opener, entries) |