538 else: |
538 else: |
539 match = lambda fn: incmatch(fn) and not excmatch(fn) and patmatch(fn) |
539 match = lambda fn: incmatch(fn) and not excmatch(fn) and patmatch(fn) |
540 |
540 |
541 return (roots, match, (inc or exc or anypats) and True) |
541 return (roots, match, (inc or exc or anypats) and True) |
542 |
542 |
543 _hgexecutable = None |
543 _hgexecutable = 'hg' |
544 |
544 |
545 def set_hgexecutable(path): |
545 def set_hgexecutable(path): |
546 """remember location of the 'hg' executable if easily possible |
546 """remember location of the 'hg' executable if easily possible |
547 |
547 |
548 path might be None or empty if hg was loaded as a module, |
548 path might be None or empty if hg was loaded as a module, |
549 fall back to 'hg' in this case. |
549 fall back to 'hg' in this case. |
550 """ |
550 """ |
551 global _hgexecutable |
551 global _hgexecutable |
552 _hgexecutable = path and os.path.abspath(path) or 'hg' |
552 if path: |
|
553 _hgexecutable = os.path.abspath(path) |
553 |
554 |
554 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None): |
555 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None): |
555 '''enhanced shell command execution. |
556 '''enhanced shell command execution. |
556 run with environment maybe modified, maybe in different dir. |
557 run with environment maybe modified, maybe in different dir. |
557 |
558 |
1179 def encodedopener(openerfn, fn): |
1180 def encodedopener(openerfn, fn): |
1180 def o(path, *args, **kw): |
1181 def o(path, *args, **kw): |
1181 return openerfn(fn(path), *args, **kw) |
1182 return openerfn(fn(path), *args, **kw) |
1182 return o |
1183 return o |
1183 |
1184 |
1184 def opener(base, audit=True): |
1185 def mktempcopy(name, emptyok=False): |
|
1186 """Create a temporary file with the same contents from name |
|
1187 |
|
1188 The permission bits are copied from the original file. |
|
1189 |
|
1190 If the temporary file is going to be truncated immediately, you |
|
1191 can use emptyok=True as an optimization. |
|
1192 |
|
1193 Returns the name of the temporary file. |
1185 """ |
1194 """ |
1186 return a function that opens files relative to base |
1195 d, fn = os.path.split(name) |
1187 |
1196 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d) |
1188 this function is used to hide the details of COW semantics and |
1197 os.close(fd) |
|
1198 # Temporary files are created with mode 0600, which is usually not |
|
1199 # what we want. If the original file already exists, just copy |
|
1200 # its mode. Otherwise, manually obey umask. |
|
1201 try: |
|
1202 st_mode = os.lstat(name).st_mode |
|
1203 except OSError, inst: |
|
1204 if inst.errno != errno.ENOENT: |
|
1205 raise |
|
1206 st_mode = 0666 & ~_umask |
|
1207 os.chmod(temp, st_mode) |
|
1208 if emptyok: |
|
1209 return temp |
|
1210 try: |
|
1211 try: |
|
1212 ifp = posixfile(name, "rb") |
|
1213 except IOError, inst: |
|
1214 if inst.errno == errno.ENOENT: |
|
1215 return temp |
|
1216 if not getattr(inst, 'filename', None): |
|
1217 inst.filename = name |
|
1218 raise |
|
1219 ofp = posixfile(temp, "wb") |
|
1220 for chunk in filechunkiter(ifp): |
|
1221 ofp.write(chunk) |
|
1222 ifp.close() |
|
1223 ofp.close() |
|
1224 except: |
|
1225 try: os.unlink(temp) |
|
1226 except: pass |
|
1227 raise |
|
1228 return temp |
|
1229 |
|
1230 class atomictempfile(posixfile): |
|
1231 """file-like object that atomically updates a file |
|
1232 |
|
1233 All writes will be redirected to a temporary copy of the original |
|
1234 file. When rename is called, the copy is renamed to the original |
|
1235 name, making the changes visible. |
|
1236 """ |
|
1237 def __init__(self, name, mode): |
|
1238 self.__name = name |
|
1239 self.temp = mktempcopy(name, emptyok=('w' in mode)) |
|
1240 posixfile.__init__(self, self.temp, mode) |
|
1241 |
|
1242 def rename(self): |
|
1243 if not self.closed: |
|
1244 posixfile.close(self) |
|
1245 rename(self.temp, localpath(self.__name)) |
|
1246 |
|
1247 def __del__(self): |
|
1248 if not self.closed: |
|
1249 try: |
|
1250 os.unlink(self.temp) |
|
1251 except: pass |
|
1252 posixfile.close(self) |
|
1253 |
|
1254 class opener(object): |
|
1255 """Open files relative to a base directory |
|
1256 |
|
1257 This class is used to hide the details of COW semantics and |
1189 remote file access from higher level code. |
1258 remote file access from higher level code. |
1190 """ |
1259 """ |
1191 def mktempcopy(name, emptyok=False): |
1260 def __init__(self, base, audit=True): |
1192 d, fn = os.path.split(name) |
1261 self.base = base |
1193 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d) |
1262 self.audit = audit |
1194 os.close(fd) |
1263 |
1195 # Temporary files are created with mode 0600, which is usually not |
1264 def __getattr__(self, name): |
1196 # what we want. If the original file already exists, just copy |
1265 if name == '_can_symlink': |
1197 # its mode. Otherwise, manually obey umask. |
1266 self._can_symlink = checklink(self.base) |
1198 try: |
1267 return self._can_symlink |
1199 st_mode = os.lstat(name).st_mode |
1268 raise AttributeError(name) |
1200 except OSError, inst: |
1269 |
1201 if inst.errno != errno.ENOENT: |
1270 def __call__(self, path, mode="r", text=False, atomictemp=False): |
1202 raise |
1271 if self.audit: |
1203 st_mode = 0666 & ~_umask |
|
1204 os.chmod(temp, st_mode) |
|
1205 if emptyok: |
|
1206 return temp |
|
1207 try: |
|
1208 try: |
|
1209 ifp = posixfile(name, "rb") |
|
1210 except IOError, inst: |
|
1211 if inst.errno == errno.ENOENT: |
|
1212 return temp |
|
1213 if not getattr(inst, 'filename', None): |
|
1214 inst.filename = name |
|
1215 raise |
|
1216 ofp = posixfile(temp, "wb") |
|
1217 for chunk in filechunkiter(ifp): |
|
1218 ofp.write(chunk) |
|
1219 ifp.close() |
|
1220 ofp.close() |
|
1221 except: |
|
1222 try: os.unlink(temp) |
|
1223 except: pass |
|
1224 raise |
|
1225 return temp |
|
1226 |
|
1227 class atomictempfile(posixfile): |
|
1228 """the file will only be copied when rename is called""" |
|
1229 def __init__(self, name, mode): |
|
1230 self.__name = name |
|
1231 self.temp = mktempcopy(name, emptyok=('w' in mode)) |
|
1232 posixfile.__init__(self, self.temp, mode) |
|
1233 def rename(self): |
|
1234 if not self.closed: |
|
1235 posixfile.close(self) |
|
1236 rename(self.temp, localpath(self.__name)) |
|
1237 def __del__(self): |
|
1238 if not self.closed: |
|
1239 try: |
|
1240 os.unlink(self.temp) |
|
1241 except: pass |
|
1242 posixfile.close(self) |
|
1243 |
|
1244 def o(path, mode="r", text=False, atomictemp=False): |
|
1245 if audit: |
|
1246 audit_path(path) |
1272 audit_path(path) |
1247 f = os.path.join(base, path) |
1273 f = os.path.join(self.base, path) |
1248 |
1274 |
1249 if not text and "b" not in mode: |
1275 if not text and "b" not in mode: |
1250 mode += "b" # for that other OS |
1276 mode += "b" # for that other OS |
1251 |
1277 |
1252 if mode[0] != "r": |
1278 if mode[0] != "r": |
1261 return atomictempfile(f, mode) |
1287 return atomictempfile(f, mode) |
1262 if nlink > 1: |
1288 if nlink > 1: |
1263 rename(mktempcopy(f), f) |
1289 rename(mktempcopy(f), f) |
1264 return posixfile(f, mode) |
1290 return posixfile(f, mode) |
1265 |
1291 |
1266 return o |
1292 def symlink(self, src, dst): |
|
1293 if self.audit: |
|
1294 audit_path(dst) |
|
1295 linkname = os.path.join(self.base, dst) |
|
1296 try: |
|
1297 os.unlink(linkname) |
|
1298 except OSError: |
|
1299 pass |
|
1300 |
|
1301 dirname = os.path.dirname(linkname) |
|
1302 if not os.path.exists(dirname): |
|
1303 os.makedirs(dirname) |
|
1304 |
|
1305 if self._can_symlink: |
|
1306 os.symlink(src, linkname) |
|
1307 else: |
|
1308 f = self(self, dst, "w") |
|
1309 f.write(src) |
|
1310 f.close() |
1267 |
1311 |
1268 class chunkbuffer(object): |
1312 class chunkbuffer(object): |
1269 """Allow arbitrary sized chunks of data to be efficiently read from an |
1313 """Allow arbitrary sized chunks of data to be efficiently read from an |
1270 iterator over chunks of arbitrary size.""" |
1314 iterator over chunks of arbitrary size.""" |
1271 |
1315 |