diff 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
line wrap: on
line diff
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -179,7 +179,7 @@ def canonpath(root, cwd, myname):
     if root == os.sep:
         rootsep = os.sep
     else:
-    	rootsep = root + os.sep
+        rootsep = root + os.sep
     name = myname
     if not name.startswith(os.sep):
         name = os.path.join(root, cwd, name)
@@ -315,15 +315,42 @@ def _matcher(canonroot, cwd, names, inc,
                          (files and filematch(fn)))),
             (inc or exc or (pats and pats != [('glob', '**')])) and True)
 
-def system(cmd, errprefix=None):
-    """execute a shell command that must succeed"""
-    rc = os.system(cmd)
-    if rc:
-        errmsg = "%s %s" % (os.path.basename(cmd.split(None, 1)[0]),
-                            explain_exit(rc)[0])
-        if errprefix:
-            errmsg = "%s: %s" % (errprefix, errmsg)
-        raise Abort(errmsg)
+def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None):
+    '''enhanced shell command execution.
+    run with environment maybe modified, maybe in different dir.
+
+    if command fails and onerr is None, return status.  if ui object,
+    print error message and return status, else raise onerr object as
+    exception.'''
+    oldenv = {}
+    for k in environ:
+        oldenv[k] = os.environ.get(k)
+    if cwd is not None:
+        oldcwd = os.getcwd()
+    try:
+        for k, v in environ.iteritems():
+            os.environ[k] = str(v)
+        if cwd is not None and oldcwd != cwd:
+            os.chdir(cwd)
+        rc = os.system(cmd)
+        if rc and onerr:
+            errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]),
+                                explain_exit(rc)[0])
+            if errprefix:
+                errmsg = '%s: %s' % (errprefix, errmsg)
+            try:
+                onerr.warn(errmsg + '\n')
+            except AttributeError:
+                raise onerr(errmsg)
+        return rc
+    finally:
+        for k, v in oldenv.iteritems():
+            if v is None:
+                del os.environ[k]
+            else:
+                os.environ[k] = v
+        if cwd is not None and oldcwd != cwd:
+            os.chdir(oldcwd)
 
 def rename(src, dst):
     """forcibly rename a file"""
@@ -363,7 +390,14 @@ def copyfiles(src, dst, hardlink=None):
         else:
             shutil.copy(src, dst)
 
-def opener(base):
+def audit_path(path):
+    """Abort if path contains dangerous components"""
+    parts = os.path.normcase(path).split(os.sep)
+    if (os.path.splitdrive(path)[0] or parts[0] in ('.hg', '')
+        or os.pardir in parts):
+        raise Abort(_("path contains illegal component: %s\n") % path)
+
+def opener(base, audit=True):
     """
     return a function that opens files relative to base
 
@@ -371,6 +405,7 @@ def opener(base):
     remote file access from higher level code.
     """
     p = base
+    audit_p = audit
 
     def mktempcopy(name):
         d, fn = os.path.split(name)
@@ -401,6 +436,8 @@ def opener(base):
             self.close()
 
     def o(path, mode="r", text=False, atomic=False):
+        if audit_p:
+            audit_path(path)
         f = os.path.join(p, path)
 
         if not text:
@@ -489,7 +526,7 @@ if os.name == 'nt':
         return pf
 
     try: # ActivePython can create hard links using win32file module
-        import win32file
+        import win32api, win32con, win32file
 
         def os_link(src, dst): # NB will only succeed on NTFS
             win32file.CreateHardLink(dst, src)
@@ -506,8 +543,18 @@ if os.name == 'nt':
             except:
                 return os.stat(pathname).st_nlink
 
+        def testpid(pid):
+            '''return False if pid is dead, True if running or not known'''
+            try:
+                win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION,
+                                     False, pid)
+            except:
+                return True
+
     except ImportError:
-        pass
+        def testpid(pid):
+            '''return False if pid dead, True if running or not known'''
+            return True
 
     def is_exec(f, last):
         return last
@@ -604,6 +651,14 @@ else:
             else:
                 raise
 
+    def testpid(pid):
+        '''return False if pid dead, True if running or not sure'''
+        try:
+            os.kill(pid, 0)
+            return True
+        except OSError, inst:
+            return inst.errno != errno.ESRCH
+
     def explain_exit(code):
         """return a 2-tuple (desc, code) describing a process's status"""
         if os.WIFEXITED(code):
@@ -700,3 +755,16 @@ def shortuser(user):
     if f >= 0:
         user = user[f+1:]
     return user
+
+def walkrepos(path):
+    '''yield every hg repository under path, recursively.'''
+    def errhandler(err):
+        if err.filename == path:
+            raise err
+
+    for root, dirs, files in os.walk(path, onerror=errhandler):
+        for d in dirs:
+            if d == '.hg':
+                yield root
+                dirs[:] = []
+                break