mercurial/util.py
changeset 7890 e710f0f592b2
parent 7879 5c4026a289a4
child 7913 1b1b3dd630a5
--- a/mercurial/util.py	Sat Mar 14 10:46:48 2009 -0400
+++ b/mercurial/util.py	Thu Mar 26 13:54:44 2009 -0500
@@ -13,7 +13,7 @@
 """
 
 from i18n import _
-import cStringIO, errno, getpass, re, shutil, sys, tempfile, traceback, error
+import cStringIO, errno, re, shutil, sys, tempfile, traceback, error
 import os, stat, threading, time, calendar, ConfigParser, locale, glob, osutil
 import imp, unicodedata
 
@@ -339,22 +339,6 @@
 def always(fn): return True
 def never(fn): return False
 
-def expand_glob(pats):
-    '''On Windows, expand the implicit globs in a list of patterns'''
-    if os.name != 'nt':
-        return list(pats)
-    ret = []
-    for p in pats:
-        kind, name = patkind(p, None)
-        if kind is None:
-            globbed = glob.glob(name)
-            if globbed:
-                ret.extend(globbed)
-                continue
-            # if we couldn't expand the glob, just keep it around
-        ret.append(p)
-    return ret
-
 def patkind(name, default):
     """Split a string into an optional pattern kind prefix and the
     actual pattern."""
@@ -858,12 +842,32 @@
         # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
         self.auditeddir.update(prefixes)
 
-def _makelock_file(info, pathname):
+if os.name == 'nt':
+    from windows import *
+else:
+    from posix import *
+
+def makelock(info, pathname):
+    try:
+        return os.symlink(info, pathname)
+    except OSError, why:
+        if why.errno == errno.EEXIST:
+            raise
+    except AttributeError: # no symlink in os
+        pass
+
     ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
     os.write(ld, info)
     os.close(ld)
 
-def _readlock_file(pathname):
+def readlock(pathname):
+    try:
+        return os.readlink(pathname)
+    except OSError, why:
+        if why.errno not in (errno.EINVAL, errno.ENOSYS):
+            raise
+    except AttributeError: # no symlink in os
+        pass
     return posixfile(pathname).read()
 
 def nlinks(pathname):
@@ -883,103 +887,6 @@
     except AttributeError:
         return os.stat(fp.name)
 
-posixfile = file
-
-def openhardlinks():
-    '''return true if it is safe to hold open file handles to hardlinks'''
-    return True
-
-def _statfiles(files):
-    'Stat each file in files and yield stat or None if file does not exist.'
-    lstat = os.lstat
-    for nf in files:
-        try:
-            st = lstat(nf)
-        except OSError, err:
-            if err.errno not in (errno.ENOENT, errno.ENOTDIR):
-                raise
-            st = None
-        yield st
-
-def _statfiles_clustered(files):
-    '''Stat each file in files and yield stat or None if file does not exist.
-    Cluster and cache stat per directory to minimize number of OS stat calls.'''
-    ncase = os.path.normcase
-    sep   = os.sep
-    dircache = {} # dirname -> filename -> status | None if file does not exist
-    for nf in files:
-        nf  = ncase(nf)
-        pos = nf.rfind(sep)
-        if pos == -1:
-            dir, base = '.', nf
-        else:
-            dir, base = nf[:pos+1], nf[pos+1:]
-        cache = dircache.get(dir, None)
-        if cache is None:
-            try:
-                dmap = dict([(ncase(n), s)
-                    for n, k, s in osutil.listdir(dir, True)])
-            except OSError, err:
-                # handle directory not found in Python version prior to 2.5
-                # Python <= 2.4 returns native Windows code 3 in errno
-                # Python >= 2.5 returns ENOENT and adds winerror field
-                # EINVAL is raised if dir is not a directory.
-                if err.errno not in (3, errno.ENOENT, errno.EINVAL,
-                                     errno.ENOTDIR):
-                    raise
-                dmap = {}
-            cache = dircache.setdefault(dir, dmap)
-        yield cache.get(base, None)
-
-if sys.platform == 'win32':
-    statfiles = _statfiles_clustered
-else:
-    statfiles = _statfiles
-
-getuser_fallback = None
-
-def getuser():
-    '''return name of current user'''
-    try:
-        return getpass.getuser()
-    except ImportError:
-        # import of pwd will fail on windows - try fallback
-        if getuser_fallback:
-            return getuser_fallback()
-    # raised if win32api not available
-    raise Abort(_('user name not available - set USERNAME '
-                  'environment variable'))
-
-def username(uid=None):
-    """Return the name of the user with the given uid.
-
-    If uid is None, return the name of the current user."""
-    try:
-        import pwd
-        if uid is None:
-            uid = os.getuid()
-        try:
-            return pwd.getpwuid(uid)[0]
-        except KeyError:
-            return str(uid)
-    except ImportError:
-        return None
-
-def groupname(gid=None):
-    """Return the name of the group with the given gid.
-
-    If gid is None, return the name of the current group."""
-    try:
-        import grp
-        if gid is None:
-            gid = os.getgid()
-        try:
-            return grp.getgrgid(gid)[0]
-        except KeyError:
-            return str(gid)
-    except ImportError:
-        return None
-
 # File system features
 
 def checkcase(path):
@@ -1088,9 +995,6 @@
     except (OSError, AttributeError):
         return False
 
-_umask = os.umask(0)
-os.umask(_umask)
-
 def needbinarypatch():
     """return True if patches should be applied in binary mode by default."""
     return os.name == 'nt'
@@ -1114,379 +1018,6 @@
 def lookup_reg(key, name=None, scope=None):
     return None
 
-# Platform specific variants
-if os.name == 'nt':
-    import msvcrt
-    nulldev = 'NUL:'
-
-    class winstdout:
-        '''stdout on windows misbehaves if sent through a pipe'''
-
-        def __init__(self, fp):
-            self.fp = fp
-
-        def __getattr__(self, key):
-            return getattr(self.fp, key)
-
-        def close(self):
-            try:
-                self.fp.close()
-            except: pass
-
-        def write(self, s):
-            try:
-                # This is workaround for "Not enough space" error on
-                # writing large size of data to console.
-                limit = 16000
-                l = len(s)
-                start = 0
-                while start < l:
-                    end = start + limit
-                    self.fp.write(s[start:end])
-                    start = end
-            except IOError, inst:
-                if inst.errno != 0: raise
-                self.close()
-                raise IOError(errno.EPIPE, 'Broken pipe')
-
-        def flush(self):
-            try:
-                return self.fp.flush()
-            except IOError, inst:
-                if inst.errno != errno.EINVAL: raise
-                self.close()
-                raise IOError(errno.EPIPE, 'Broken pipe')
-
-    sys.stdout = winstdout(sys.stdout)
-
-    def _is_win_9x():
-        '''return true if run on windows 95, 98 or me.'''
-        try:
-            return sys.getwindowsversion()[3] == 1
-        except AttributeError:
-            return 'command' in os.environ.get('comspec', '')
-
-    def openhardlinks():
-        return not _is_win_9x and "win32api" in locals()
-
-    def system_rcpath():
-        try:
-            return system_rcpath_win32()
-        except:
-            return [r'c:\mercurial\mercurial.ini']
-
-    def user_rcpath():
-        '''return os-specific hgrc search path to the user dir'''
-        try:
-            path = user_rcpath_win32()
-        except:
-            home = os.path.expanduser('~')
-            path = [os.path.join(home, 'mercurial.ini'),
-                    os.path.join(home, '.hgrc')]
-        userprofile = os.environ.get('USERPROFILE')
-        if userprofile:
-            path.append(os.path.join(userprofile, 'mercurial.ini'))
-            path.append(os.path.join(userprofile, '.hgrc'))
-        return path
-
-    def parse_patch_output(output_line):
-        """parses the output produced by patch and returns the file name"""
-        pf = output_line[14:]
-        if pf[0] == '`':
-            pf = pf[1:-1] # Remove the quotes
-        return pf
-
-    def sshargs(sshcmd, host, user, port):
-        '''Build argument list for ssh or Plink'''
-        pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
-        args = user and ("%s@%s" % (user, host)) or host
-        return port and ("%s %s %s" % (args, pflag, port)) or args
-
-    def testpid(pid):
-        '''return False if pid dead, True if running or not known'''
-        return True
-
-    def set_flags(f, l, x):
-        pass
-
-    def set_binary(fd):
-        # When run without console, pipes may expose invalid
-        # fileno(), usually set to -1.
-        if hasattr(fd, 'fileno') and fd.fileno() >= 0:
-            msvcrt.setmode(fd.fileno(), os.O_BINARY)
-
-    def pconvert(path):
-        return '/'.join(splitpath(path))
-
-    def localpath(path):
-        return path.replace('/', '\\')
-
-    def normpath(path):
-        return pconvert(os.path.normpath(path))
-
-    makelock = _makelock_file
-    readlock = _readlock_file
-
-    def samestat(s1, s2):
-        return False
-
-    # A sequence of backslashes is special iff it precedes a double quote:
-    # - if there's an even number of backslashes, the double quote is not
-    #   quoted (i.e. it ends the quoted region)
-    # - if there's an odd number of backslashes, the double quote is quoted
-    # - in both cases, every pair of backslashes is unquoted into a single
-    #   backslash
-    # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
-    # So, to quote a string, we must surround it in double quotes, double
-    # the number of backslashes that preceed double quotes and add another
-    # backslash before every double quote (being careful with the double
-    # quote we've appended to the end)
-    _quotere = None
-    def shellquote(s):
-        global _quotere
-        if _quotere is None:
-            _quotere = re.compile(r'(\\*)("|\\$)')
-        return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
-
-    def quotecommand(cmd):
-        """Build a command string suitable for os.popen* calls."""
-        # The extra quotes are needed because popen* runs the command
-        # through the current COMSPEC. cmd.exe suppress enclosing quotes.
-        return '"' + cmd + '"'
-
-    def popen(command, mode='r'):
-        # Work around "popen spawned process may not write to stdout
-        # under windows"
-        # http://bugs.python.org/issue1366
-        command += " 2> %s" % nulldev
-        return os.popen(quotecommand(command), mode)
-
-    def explain_exit(code):
-        return _("exited with status %d") % code, code
-
-    # if you change this stub into a real check, please try to implement the
-    # username and groupname functions above, too.
-    def isowner(fp, st=None):
-        return True
-
-    def find_exe(command):
-        '''Find executable for command searching like cmd.exe does.
-        If command is a basename then PATH is searched for command.
-        PATH isn't searched if command is an absolute or relative path.
-        An extension from PATHEXT is found and added if not present.
-        If command isn't found None is returned.'''
-        pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
-        pathexts = [ext for ext in pathext.lower().split(os.pathsep)]
-        if os.path.splitext(command)[1].lower() in pathexts:
-            pathexts = ['']
-
-        def findexisting(pathcommand):
-            'Will append extension (if needed) and return existing file'
-            for ext in pathexts:
-                executable = pathcommand + ext
-                if os.path.exists(executable):
-                    return executable
-            return None
-
-        if os.sep in command:
-            return findexisting(command)
-
-        for path in os.environ.get('PATH', '').split(os.pathsep):
-            executable = findexisting(os.path.join(path, command))
-            if executable is not None:
-                return executable
-        return None
-
-    def set_signal_handler():
-        try:
-            set_signal_handler_win32()
-        except NameError:
-            pass
-
-    try:
-        # override functions with win32 versions if possible
-        from util_win32 import *
-        if not _is_win_9x():
-            posixfile = posixfile_nt
-    except ImportError:
-        pass
-
-else:
-    nulldev = '/dev/null'
-
-    def rcfiles(path):
-        rcs = [os.path.join(path, 'hgrc')]
-        rcdir = os.path.join(path, 'hgrc.d')
-        try:
-            rcs.extend([os.path.join(rcdir, f)
-                        for f, kind in osutil.listdir(rcdir)
-                        if f.endswith(".rc")])
-        except OSError:
-            pass
-        return rcs
-
-    def system_rcpath():
-        path = []
-        # old mod_python does not set sys.argv
-        if len(getattr(sys, 'argv', [])) > 0:
-            path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
-                                  '/../etc/mercurial'))
-        path.extend(rcfiles('/etc/mercurial'))
-        return path
-
-    def user_rcpath():
-        return [os.path.expanduser('~/.hgrc')]
-
-    def parse_patch_output(output_line):
-        """parses the output produced by patch and returns the file name"""
-        pf = output_line[14:]
-        if os.sys.platform == 'OpenVMS':
-            if pf[0] == '`':
-                pf = pf[1:-1] # Remove the quotes
-        else:
-           if pf.startswith("'") and pf.endswith("'") and " " in pf:
-                pf = pf[1:-1] # Remove the quotes
-        return pf
-
-    def sshargs(sshcmd, host, user, port):
-        '''Build argument list for ssh'''
-        args = user and ("%s@%s" % (user, host)) or host
-        return port and ("%s -p %s" % (args, port)) or args
-
-    def is_exec(f):
-        """check whether a file is executable"""
-        return (os.lstat(f).st_mode & 0100 != 0)
-
-    def set_flags(f, l, x):
-        s = os.lstat(f).st_mode
-        if l:
-            if not stat.S_ISLNK(s):
-                # switch file to link
-                data = file(f).read()
-                os.unlink(f)
-                try:
-                    os.symlink(data, f)
-                except:
-                    # failed to make a link, rewrite file
-                    file(f, "w").write(data)
-            # no chmod needed at this point
-            return
-        if stat.S_ISLNK(s):
-            # switch link to file
-            data = os.readlink(f)
-            os.unlink(f)
-            file(f, "w").write(data)
-            s = 0666 & ~_umask # avoid restatting for chmod
-
-        sx = s & 0100
-        if x and not sx:
-            # Turn on +x for every +r bit when making a file executable
-            # and obey umask.
-            os.chmod(f, s | (s & 0444) >> 2 & ~_umask)
-        elif not x and sx:
-            # Turn off all +x bits
-            os.chmod(f, s & 0666)
-
-    def set_binary(fd):
-        pass
-
-    def pconvert(path):
-        return path
-
-    def localpath(path):
-        return path
-
-    normpath = os.path.normpath
-    samestat = os.path.samestat
-
-    def makelock(info, pathname):
-        try:
-            os.symlink(info, pathname)
-        except OSError, why:
-            if why.errno == errno.EEXIST:
-                raise
-            else:
-                _makelock_file(info, pathname)
-
-    def readlock(pathname):
-        try:
-            return os.readlink(pathname)
-        except OSError, why:
-            if why.errno in (errno.EINVAL, errno.ENOSYS):
-                return _readlock_file(pathname)
-            else:
-                raise
-
-    def shellquote(s):
-        if os.sys.platform == 'OpenVMS':
-            return '"%s"' % s
-        else:
-            return "'%s'" % s.replace("'", "'\\''")
-
-    def quotecommand(cmd):
-        return cmd
-
-    def popen(command, mode='r'):
-        return os.popen(command, mode)
-
-    def testpid(pid):
-        '''return False if pid dead, True if running or not sure'''
-        if os.sys.platform == 'OpenVMS':
-            return True
-        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):
-            val = os.WEXITSTATUS(code)
-            return _("exited with status %d") % val, val
-        elif os.WIFSIGNALED(code):
-            val = os.WTERMSIG(code)
-            return _("killed by signal %d") % val, val
-        elif os.WIFSTOPPED(code):
-            val = os.WSTOPSIG(code)
-            return _("stopped by signal %d") % val, val
-        raise ValueError(_("invalid exit code"))
-
-    def isowner(fp, st=None):
-        """Return True if the file object f belongs to the current user.
-
-        The return value of a util.fstat(f) may be passed as the st argument.
-        """
-        if st is None:
-            st = fstat(fp)
-        return st.st_uid == os.getuid()
-
-    def find_exe(command):
-        '''Find executable for command searching like which does.
-        If command is a basename then PATH is searched for command.
-        PATH isn't searched if command is an absolute or relative path.
-        If command isn't found None is returned.'''
-        if sys.platform == 'OpenVMS':
-            return command
-
-        def findexisting(executable):
-            'Will return executable if existing file'
-            if os.path.exists(executable):
-                return executable
-            return None
-
-        if os.sep in command:
-            return findexisting(command)
-
-        for path in os.environ.get('PATH', '').split(os.pathsep):
-            executable = findexisting(os.path.join(path, command))
-            if executable is not None:
-                return executable
-        return None
-
-    def set_signal_handler():
-        pass
-
 def mktempcopy(name, emptyok=False, createmode=None):
     """Create a temporary file with the same contents from name
 
@@ -1510,7 +1041,7 @@
             raise
         st_mode = createmode
         if st_mode is None:
-            st_mode = ~_umask
+            st_mode = ~umask
         st_mode &= 0666
     os.chmod(temp, st_mode)
     if emptyok: