42 if inst.errno != errno.ENOENT: |
42 if inst.errno != errno.ENOENT: |
43 raise |
43 raise |
44 |
44 |
45 backupfiles = [] |
45 backupfiles = [] |
46 for f, b in backupentries: |
46 for f, b in backupentries: |
47 if b: |
47 if f and b: |
48 filepath = opener.join(f) |
48 filepath = opener.join(f) |
49 backuppath = opener.join(b) |
49 backuppath = opener.join(b) |
50 try: |
50 try: |
51 util.copyfile(backuppath, filepath) |
51 util.copyfile(backuppath, filepath) |
52 backupfiles.append(b) |
52 backupfiles.append(b) |
53 except IOError: |
53 except IOError: |
54 report(_("failed to recover %s\n") % f) |
54 report(_("failed to recover %s\n") % f) |
55 raise |
55 raise |
56 else: |
56 else: |
57 try: |
57 target = f or b |
58 opener.unlink(f) |
58 try: |
|
59 opener.unlink(target) |
59 except (IOError, OSError), inst: |
60 except (IOError, OSError), inst: |
60 if inst.errno != errno.ENOENT: |
61 if inst.errno != errno.ENOENT: |
61 raise |
62 raise |
62 |
63 |
63 opener.unlink(journal) |
64 opener.unlink(journal) |
64 backuppath = "%s.backupfiles" % journal |
65 backuppath = "%s.backupfiles" % journal |
65 if opener.exists(backuppath): |
66 if opener.exists(backuppath): |
66 opener.unlink(backuppath) |
67 opener.unlink(backuppath) |
67 for f in backupfiles: |
68 for f in backupfiles: |
68 opener.unlink(f) |
69 if opener.exists(f): |
|
70 opener.unlink(f) |
69 |
71 |
70 class transaction(object): |
72 class transaction(object): |
71 def __init__(self, report, opener, journal, after=None, createmode=None, |
73 def __init__(self, report, opener, journal, after=None, createmode=None, |
72 onclose=None, onabort=None): |
74 onclose=None, onabort=None): |
73 """Begin a new transaction |
75 """Begin a new transaction |
97 self.hookargs = {} |
99 self.hookargs = {} |
98 self.file = opener.open(self.journal, "w") |
100 self.file = opener.open(self.journal, "w") |
99 |
101 |
100 # a list of ('path', 'backuppath') entries. |
102 # a list of ('path', 'backuppath') entries. |
101 # if 'backuppath' is empty, no file existed at backup time |
103 # if 'backuppath' is empty, no file existed at backup time |
|
104 # if 'path' is empty, this is a temporary transaction file |
102 self._backupentries = [] |
105 self._backupentries = [] |
103 self._backupmap = {} |
106 self._backupmap = {} |
104 self._backupjournal = "%s.backupfiles" % journal |
107 self._backupjournal = "%s.backupfiles" % journal |
105 self._backupsfile = opener.open(self._backupjournal, 'w') |
108 self._backupsfile = opener.open(self._backupjournal, 'w') |
106 self._backupsfile.write('%d\n' % version) |
109 self._backupsfile.write('%d\n' % version) |
198 self._backupmap[file] = len(self._backupentries) - 1 |
201 self._backupmap[file] = len(self._backupentries) - 1 |
199 self._backupsfile.write("%s\0%s\n" % entry) |
202 self._backupsfile.write("%s\0%s\n" % entry) |
200 self._backupsfile.flush() |
203 self._backupsfile.flush() |
201 |
204 |
202 @active |
205 @active |
|
206 def registertmp(self, tmpfile): |
|
207 """register a temporary transaction file |
|
208 |
|
209 Such file will be delete when the transaction exit (on both failure and |
|
210 success). |
|
211 """ |
|
212 self._addbackupentry(('', tmpfile)) |
|
213 |
|
214 @active |
203 def addfilegenerator(self, genid, filenames, genfunc, order=0, vfs=None): |
215 def addfilegenerator(self, genid, filenames, genfunc, order=0, vfs=None): |
204 """add a function to generates some files at transaction commit |
216 """add a function to generates some files at transaction commit |
205 |
217 |
206 The `genfunc` argument is a function capable of generating proper |
218 The `genfunc` argument is a function capable of generating proper |
207 content of each entry in the `filename` tuple. |
219 content of each entry in the `filename` tuple. |
340 self.count -= 1 |
352 self.count -= 1 |
341 if self.count != 0: |
353 if self.count != 0: |
342 return |
354 return |
343 self.file.close() |
355 self.file.close() |
344 self._backupsfile.close() |
356 self._backupsfile.close() |
|
357 # cleanup temporary files |
|
358 for f, b in self._backupentries: |
|
359 if not f and b and self.opener.exists(b): |
|
360 self.opener.unlink(b) |
345 self.entries = [] |
361 self.entries = [] |
346 if self.after: |
362 if self.after: |
347 self.after() |
363 self.after() |
348 if self.opener.isfile(self.journal): |
364 if self.opener.isfile(self.journal): |
349 self.opener.unlink(self.journal) |
365 self.opener.unlink(self.journal) |
350 if self.opener.isfile(self._backupjournal): |
366 if self.opener.isfile(self._backupjournal): |
351 self.opener.unlink(self._backupjournal) |
367 self.opener.unlink(self._backupjournal) |
352 for _f, b in self._backupentries: |
368 for _f, b in self._backupentries: |
353 if b: |
369 if b and self.opener.exists(b): |
354 self.opener.unlink(b) |
370 self.opener.unlink(b) |
355 self._backupentries = [] |
371 self._backupentries = [] |
356 self.journal = None |
372 self.journal = None |
357 # run post close action |
373 # run post close action |
358 categories = sorted(self._postclosecallback) |
374 categories = sorted(self._postclosecallback) |