103 class appendopener(object): |
103 class appendopener(object): |
104 '''special opener for files that only read or append.''' |
104 '''special opener for files that only read or append.''' |
105 |
105 |
106 def __init__(self, opener): |
106 def __init__(self, opener): |
107 self.realopener = opener |
107 self.realopener = opener |
108 # key: file name, value: appendfile name |
108 self.tmpname = None |
109 self.tmpnames = {} |
|
110 |
109 |
111 def __call__(self, name, mode='r'): |
110 def __call__(self, name, mode='r'): |
112 '''open file.''' |
111 '''open file.''' |
113 |
112 # only handle .i file |
|
113 if not name.endswith("."): |
|
114 return self.realopener(name, mode) |
114 assert mode in 'ra+' |
115 assert mode in 'ra+' |
115 try: |
116 try: |
116 realfp = self.realopener(name, 'r') |
117 realfp = self.realopener(name, 'r') |
117 except IOError, err: |
118 except IOError, err: |
118 if err.errno != errno.ENOENT: raise |
119 if err.errno != errno.ENOENT: raise |
119 realfp = self.realopener(name, 'w+') |
120 self.realfp = self.realopener(name, 'w+') |
120 tmpname = self.tmpnames.get(name) |
121 fp = appendfile(realfp, self.tmpname) |
121 fp = appendfile(realfp, tmpname) |
|
122 if tmpname is None: |
122 if tmpname is None: |
123 self.tmpnames[name] = fp.tmpname |
123 self.tmpname = fp.tmpname |
|
124 self.name = name |
124 return fp |
125 return fp |
125 |
126 |
126 def writedata(self): |
127 def writedata(self): |
127 '''copy data from temp files to real files.''' |
128 '''copy data from temp files to real files.''' |
128 # write .d file before .i file. |
129 if not self.tmpname: |
129 tmpnames = self.tmpnames.items() |
130 return |
130 tmpnames.sort() |
131 ifp = open(self.tmpname, 'rb') |
131 for name, tmpname in tmpnames: |
132 ofp = self.realopener(self.name, 'a') |
132 ifp = open(tmpname, 'rb') |
133 for chunk in util.filechunkiter(ifp): |
133 ofp = self.realopener(name, 'a') |
134 ofp.write(chunk) |
134 for chunk in util.filechunkiter(ifp): |
135 ifp.close() |
135 ofp.write(chunk) |
136 os.unlink(self.tmpname) |
136 ifp.close() |
137 ofp.close() |
137 os.unlink(tmpname) |
|
138 del self.tmpnames[name] |
|
139 ofp.close() |
|
140 |
138 |
141 def cleanup(self): |
139 def cleanup(self): |
142 '''delete temp files (this discards unwritten data!)''' |
140 '''delete temp files (this discards unwritten data!)''' |
143 for tmpname in self.tmpnames.values(): |
141 if self.tmpname: |
144 os.unlink(tmpname) |
142 os.unlink(self.tmpname) |
145 |
143 |
146 # files for changelog and manifest are in different appendopeners, so |
144 # files for changelog and manifest are in different appendopeners, so |
147 # not mixed up together. |
145 # not mixed up together. |
148 |
146 |
149 class appendchangelog(changelog.changelog, appendopener): |
147 class appendchangelog(changelog.changelog, appendopener): |