11 # This software may be used and distributed according to the terms of the |
11 # This software may be used and distributed according to the terms of the |
12 # GNU General Public License version 2, incorporated herein by reference. |
12 # GNU General Public License version 2, incorporated herein by reference. |
13 |
13 |
14 from i18n import _ |
14 from i18n import _ |
15 import os, errno |
15 import os, errno |
|
16 import error |
|
17 |
|
18 def active(func): |
|
19 def _active(self, *args, **kwds): |
|
20 if self.count == 0: |
|
21 raise error.Abort(_( |
|
22 'cannot use transaction when it is already committed/aborted')) |
|
23 return func(self, *args, **kwds) |
|
24 return _active |
16 |
25 |
17 class transaction(object): |
26 class transaction(object): |
18 def __init__(self, report, opener, journal, after=None, createmode=None): |
27 def __init__(self, report, opener, journal, after=None, createmode=None): |
19 self.journal = None |
28 self.journal = None |
20 |
29 |
30 if createmode is not None: |
39 if createmode is not None: |
31 os.chmod(self.journal, createmode & 0666) |
40 os.chmod(self.journal, createmode & 0666) |
32 |
41 |
33 def __del__(self): |
42 def __del__(self): |
34 if self.journal: |
43 if self.journal: |
35 if self.entries: self.abort() |
44 if self.entries: self._abort() |
36 self.file.close() |
45 self.file.close() |
37 |
46 |
|
47 @active |
38 def add(self, file, offset, data=None): |
48 def add(self, file, offset, data=None): |
39 if file in self.map: return |
49 if file in self.map: return |
40 self.entries.append((file, offset, data)) |
50 self.entries.append((file, offset, data)) |
41 self.map[file] = len(self.entries) - 1 |
51 self.map[file] = len(self.entries) - 1 |
42 # add enough data to the journal to do the truncate |
52 # add enough data to the journal to do the truncate |
43 self.file.write("%s\0%d\n" % (file, offset)) |
53 self.file.write("%s\0%d\n" % (file, offset)) |
44 self.file.flush() |
54 self.file.flush() |
45 |
55 |
|
56 @active |
46 def find(self, file): |
57 def find(self, file): |
47 if file in self.map: |
58 if file in self.map: |
48 return self.entries[self.map[file]] |
59 return self.entries[self.map[file]] |
49 return None |
60 return None |
50 |
61 |
|
62 @active |
51 def replace(self, file, offset, data=None): |
63 def replace(self, file, offset, data=None): |
52 if file not in self.map: |
64 if file not in self.map: |
53 raise KeyError(file) |
65 raise KeyError(file) |
54 index = self.map[file] |
66 index = self.map[file] |
55 self.entries[index] = (file, offset, data) |
67 self.entries[index] = (file, offset, data) |
56 self.file.write("%s\0%d\n" % (file, offset)) |
68 self.file.write("%s\0%d\n" % (file, offset)) |
57 self.file.flush() |
69 self.file.flush() |
58 |
70 |
|
71 @active |
59 def nest(self): |
72 def nest(self): |
60 self.count += 1 |
73 self.count += 1 |
61 return self |
74 return self |
62 |
75 |
63 def running(self): |
76 def running(self): |
64 return self.count > 0 |
77 return self.count > 0 |
65 |
78 |
|
79 @active |
66 def close(self): |
80 def close(self): |
67 self.count -= 1 |
81 self.count -= 1 |
68 if self.count != 0: |
82 if self.count != 0: |
69 return |
83 return |
70 self.file.close() |
84 self.file.close() |