Mercurial > public > mercurial-scm > hg
comparison mercurial/util.py @ 1920:b7cc0f323a4c
merge with crew.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Sun, 12 Mar 2006 16:21:59 -0800 |
parents | e4abeafd6eb1 c0320567931f |
children | 696230e52e4d |
comparison
equal
deleted
inserted
replaced
1919:8f565af14095 | 1920:b7cc0f323a4c |
---|---|
177 def canonpath(root, cwd, myname): | 177 def canonpath(root, cwd, myname): |
178 """return the canonical path of myname, given cwd and root""" | 178 """return the canonical path of myname, given cwd and root""" |
179 if root == os.sep: | 179 if root == os.sep: |
180 rootsep = os.sep | 180 rootsep = os.sep |
181 else: | 181 else: |
182 rootsep = root + os.sep | 182 rootsep = root + os.sep |
183 name = myname | 183 name = myname |
184 if not name.startswith(os.sep): | 184 if not name.startswith(os.sep): |
185 name = os.path.join(root, cwd, name) | 185 name = os.path.join(root, cwd, name) |
186 name = os.path.normpath(name) | 186 name = os.path.normpath(name) |
187 if name.startswith(rootsep): | 187 if name.startswith(rootsep): |
313 (not pats and not files) or | 313 (not pats and not files) or |
314 (pats and patmatch(fn)) or | 314 (pats and patmatch(fn)) or |
315 (files and filematch(fn)))), | 315 (files and filematch(fn)))), |
316 (inc or exc or (pats and pats != [('glob', '**')])) and True) | 316 (inc or exc or (pats and pats != [('glob', '**')])) and True) |
317 | 317 |
318 def system(cmd, errprefix=None): | 318 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None): |
319 """execute a shell command that must succeed""" | 319 '''enhanced shell command execution. |
320 rc = os.system(cmd) | 320 run with environment maybe modified, maybe in different dir. |
321 if rc: | 321 |
322 errmsg = "%s %s" % (os.path.basename(cmd.split(None, 1)[0]), | 322 if command fails and onerr is None, return status. if ui object, |
323 explain_exit(rc)[0]) | 323 print error message and return status, else raise onerr object as |
324 if errprefix: | 324 exception.''' |
325 errmsg = "%s: %s" % (errprefix, errmsg) | 325 oldenv = {} |
326 raise Abort(errmsg) | 326 for k in environ: |
327 oldenv[k] = os.environ.get(k) | |
328 if cwd is not None: | |
329 oldcwd = os.getcwd() | |
330 try: | |
331 for k, v in environ.iteritems(): | |
332 os.environ[k] = str(v) | |
333 if cwd is not None and oldcwd != cwd: | |
334 os.chdir(cwd) | |
335 rc = os.system(cmd) | |
336 if rc and onerr: | |
337 errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]), | |
338 explain_exit(rc)[0]) | |
339 if errprefix: | |
340 errmsg = '%s: %s' % (errprefix, errmsg) | |
341 try: | |
342 onerr.warn(errmsg + '\n') | |
343 except AttributeError: | |
344 raise onerr(errmsg) | |
345 return rc | |
346 finally: | |
347 for k, v in oldenv.iteritems(): | |
348 if v is None: | |
349 del os.environ[k] | |
350 else: | |
351 os.environ[k] = v | |
352 if cwd is not None and oldcwd != cwd: | |
353 os.chdir(oldcwd) | |
327 | 354 |
328 def rename(src, dst): | 355 def rename(src, dst): |
329 """forcibly rename a file""" | 356 """forcibly rename a file""" |
330 try: | 357 try: |
331 os.rename(src, dst) | 358 os.rename(src, dst) |
361 hardlink = False | 388 hardlink = False |
362 shutil.copy(src, dst) | 389 shutil.copy(src, dst) |
363 else: | 390 else: |
364 shutil.copy(src, dst) | 391 shutil.copy(src, dst) |
365 | 392 |
366 def opener(base): | 393 def audit_path(path): |
394 """Abort if path contains dangerous components""" | |
395 parts = os.path.normcase(path).split(os.sep) | |
396 if (os.path.splitdrive(path)[0] or parts[0] in ('.hg', '') | |
397 or os.pardir in parts): | |
398 raise Abort(_("path contains illegal component: %s\n") % path) | |
399 | |
400 def opener(base, audit=True): | |
367 """ | 401 """ |
368 return a function that opens files relative to base | 402 return a function that opens files relative to base |
369 | 403 |
370 this function is used to hide the details of COW semantics and | 404 this function is used to hide the details of COW semantics and |
371 remote file access from higher level code. | 405 remote file access from higher level code. |
372 """ | 406 """ |
373 p = base | 407 p = base |
408 audit_p = audit | |
374 | 409 |
375 def mktempcopy(name): | 410 def mktempcopy(name): |
376 d, fn = os.path.split(name) | 411 d, fn = os.path.split(name) |
377 fd, temp = tempfile.mkstemp(prefix=fn, dir=d) | 412 fd, temp = tempfile.mkstemp(prefix=fn, dir=d) |
378 fp = os.fdopen(fd, "wb") | 413 fp = os.fdopen(fd, "wb") |
399 rename(self.temp, self.__name) | 434 rename(self.temp, self.__name) |
400 def __del__(self): | 435 def __del__(self): |
401 self.close() | 436 self.close() |
402 | 437 |
403 def o(path, mode="r", text=False, atomic=False): | 438 def o(path, mode="r", text=False, atomic=False): |
439 if audit_p: | |
440 audit_path(path) | |
404 f = os.path.join(p, path) | 441 f = os.path.join(p, path) |
405 | 442 |
406 if not text: | 443 if not text: |
407 mode += "b" # for that other OS | 444 mode += "b" # for that other OS |
408 | 445 |
487 if pf[0] == '`': | 524 if pf[0] == '`': |
488 pf = pf[1:-1] # Remove the quotes | 525 pf = pf[1:-1] # Remove the quotes |
489 return pf | 526 return pf |
490 | 527 |
491 try: # ActivePython can create hard links using win32file module | 528 try: # ActivePython can create hard links using win32file module |
492 import win32file | 529 import win32api, win32con, win32file |
493 | 530 |
494 def os_link(src, dst): # NB will only succeed on NTFS | 531 def os_link(src, dst): # NB will only succeed on NTFS |
495 win32file.CreateHardLink(dst, src) | 532 win32file.CreateHardLink(dst, src) |
496 | 533 |
497 def nlinks(pathname): | 534 def nlinks(pathname): |
504 fh.Close() | 541 fh.Close() |
505 return res[7] | 542 return res[7] |
506 except: | 543 except: |
507 return os.stat(pathname).st_nlink | 544 return os.stat(pathname).st_nlink |
508 | 545 |
546 def testpid(pid): | |
547 '''return False if pid is dead, True if running or not known''' | |
548 try: | |
549 win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION, | |
550 False, pid) | |
551 except: | |
552 return True | |
553 | |
509 except ImportError: | 554 except ImportError: |
510 pass | 555 def testpid(pid): |
556 '''return False if pid dead, True if running or not known''' | |
557 return True | |
511 | 558 |
512 def is_exec(f, last): | 559 def is_exec(f, last): |
513 return last | 560 return last |
514 | 561 |
515 def set_exec(f, mode): | 562 def set_exec(f, mode): |
601 except OSError, why: | 648 except OSError, why: |
602 if why.errno == errno.EINVAL: | 649 if why.errno == errno.EINVAL: |
603 return _readlock_file(pathname) | 650 return _readlock_file(pathname) |
604 else: | 651 else: |
605 raise | 652 raise |
653 | |
654 def testpid(pid): | |
655 '''return False if pid dead, True if running or not sure''' | |
656 try: | |
657 os.kill(pid, 0) | |
658 return True | |
659 except OSError, inst: | |
660 return inst.errno != errno.ESRCH | |
606 | 661 |
607 def explain_exit(code): | 662 def explain_exit(code): |
608 """return a 2-tuple (desc, code) describing a process's status""" | 663 """return a 2-tuple (desc, code) describing a process's status""" |
609 if os.WIFEXITED(code): | 664 if os.WIFEXITED(code): |
610 val = os.WEXITSTATUS(code) | 665 val = os.WEXITSTATUS(code) |
698 user = user[:f] | 753 user = user[:f] |
699 f = user.find('<') | 754 f = user.find('<') |
700 if f >= 0: | 755 if f >= 0: |
701 user = user[f+1:] | 756 user = user[f+1:] |
702 return user | 757 return user |
758 | |
759 def walkrepos(path): | |
760 '''yield every hg repository under path, recursively.''' | |
761 def errhandler(err): | |
762 if err.filename == path: | |
763 raise err | |
764 | |
765 for root, dirs, files in os.walk(path, onerror=errhandler): | |
766 for d in dirs: | |
767 if d == '.hg': | |
768 yield root | |
769 dirs[:] = [] | |
770 break |