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)