[PATCH 2 of 2] dirstate: normalize on case insensitive filesystems on Mac (issue1663)

Matt Mackall mpm at selenic.com
Sat Jul 25 11:07:00 CDT 2009


On Fri, 2009-07-24 at 23:37 +0200, Dan Villiom Podlaski Christiansen
wrote:
> # HG changeset patch
> # User Dan Villiom Podlaski Christiansen <danchr at gmail.com>
> # Date 1248470961 -7200
> # Node ID f132b7058ffa2d3b4a544fe4ded53ac7e35a26ac
> # Parent  d98cef25b5afed5d8aa325ef87f98789367d8b6e
> util: add normalizepath() for getting the 'true' path on Mac OS X.

This looks promising. Please make it two patches: first introduce
realpath, next update dirstate.py.

Linux has something roughly equivalent to F_GETPATH: /proc/[pid]/fd/[fd]
is a symlink to the file in question. Not sure if it reflects case
folding on VFAT/NTFS/HFS+ though.

> diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
> --- a/mercurial/dirstate.py
> +++ b/mercurial/dirstate.py
> @@ -59,7 +59,7 @@ class dirstate(object):
>       def _foldmap(self):
>           f = {}
>           for name in self._map:
> -            f[os.path.normcase(name)] = name
> +            f[util.realpath(name)] = name
>           return f
> 
>       @propertycache
> @@ -340,7 +340,7 @@ class dirstate(object):
>               self._ui.warn(_("not in dirstate: %s\n") % f)
> 
>       def _normalize(self, path, knownpath):
> -        norm_path = os.path.normcase(path)
> +        norm_path = util.realpath(path)
>           fold_path = self._foldmap.get(norm_path, None)

Your patch has some whitespace damage.

>           if fold_path is None:
>               if knownpath or not  
> os.path.exists(os.path.join(self._root, path)):
> diff --git a/mercurial/posix.py b/mercurial/posix.py
> --- a/mercurial/posix.py
> +++ b/mercurial/posix.py
> @@ -7,7 +7,7 @@
> 
>   from i18n import _
>   import osutil
> -import os, sys, errno, stat, getpass, pwd, grp
> +import os, sys, errno, stat, getpass, pwd, grp, fcntl
> 
>   posixfile = open
>   nulldev = '/dev/null'
> @@ -104,6 +104,19 @@ def pconvert(path):
>   def localpath(path):
>       return path
> 
> +if sys.platform == 'darwin':
> +    def realpath(path):
> +        try:
> +            # fcntl.h: O_SYMLINK = 0x200000, F_GETPATH = 50
> +            f = os.open(path, 0x200000)
> +            r = fcntl.fcntl(f, 50, '\0' * 1024)
> +            os.close(f)
> +            return r.rstrip('\0')
> +        except IOError:
> +            return path
> +else:
> +    realpath = os.path.realpath
> +

This probably deserves a comment about the silliness we're addressing.

>   def shellquote(s):
>       if os.sys.platform == 'OpenVMS':
>           return '"%s"' % s
> diff --git a/mercurial/windows.py b/mercurial/windows.py
> --- a/mercurial/windows.py
> +++ b/mercurial/windows.py
> @@ -126,6 +126,10 @@ def localpath(path):
>   def normpath(path):
>       return pconvert(os.path.normpath(path))
> 
> +def realpath(path):
> +    '''Obtain the canonical version of a path.'''
> +    return os.path.normpath(os.path.normcase(os.path.realpath(path)))
> +
>   def samestat(s1, s2):
>       return False

-- 
http://selenic.com : development and support for Mercurial and Linux




More information about the Mercurial-devel mailing list