[PATCH 1 of 3] Add a new function, filesystem_case

Patrick Mézard pmezard at gmail.com
Wed Apr 23 16:26:25 CDT 2008


Paul Moore a écrit :
> # HG changeset patch
> # User "Paul Moore <p.f.moore at gmail.com>"
> # Date 1208894004 -3600
> # Node ID 47aabfeb37f4a12d015b809afef81cb817e18972
> # Parent  90becd2b697eb345328dabb08e23262335bf9ff2
> Add a new function, filesystem_case
> 
> The function, given a filename and an (optional) root, returns the filename
> modified to use the case actually stored in the filesystem (if the file does
> not exist, return the name unchanged).
> 
> An immplementation for Windows (case insensitive) and a no-op implementation
> for Unix is given. Unix can potentially have a case insensitive filesystem,
> but this implementation doesn't consider that. We also don't consider fancy
> stuff like Mac OS X normalisation forms. Suitable implementations for these
> can be added later.
> 
> diff --git a/mercurial/util.py b/mercurial/util.py
> --- a/mercurial/util.py
> +++ b/mercurial/util.py
> @@ -1063,6 +1063,42 @@
>      def localpath(path):
>          return path.replace('/', '\\')
>  
> +    def filesystem_case(name, root=''):

We usually try to avoid long identifiers and underscores. What about "fspath()" ? It would also fit for a normalizing version on OSX.

> +        '''Get name in the case stored in the filesystem
> +
> +        The filename 'name' is relative to the path 'root' (if given).
> +        If the file does not exist, return it unchanged. Otherwise, return the
> +        version of name with case as stored in the filesystem.
> +        '''
> +        if not os.path.exists(os.path.join(root, name)):
> +            return name

Maybe we can have a fallback value instead (defaulting to None). That would shave one os.path.exists() call in the third patch.

> +        parts = []
> +        while name:
> +            dir, leaf = os.path.split(name)
> +
> +            # Scan os.listdir for a name that matches leaf except for case
> +            leaf_l = leaf.lower()
> +            for n in os.listdir(os.path.join(root, dir)):
> +                if n.lower() == leaf_l:
> +                    parts.append(n)
> +                    break
> +            else:
> +                # This should never happen, as the file exists so it should
> +                # show up in os.listdir. TODO: check if this is needed for
> +                # hidden files, but they are probably weird anyway...
> +                parts.append(leaf)
> +
> +            # Get the actual separator used in 'name', as we want to match
> +            # whichever of os.sep or os.altsep was used.
> +            if dir:
> +                sep = name[len(dir)]
> +                parts.append(sep)
> +
> +            name = dir
> +
> +        parts.reverse()
> +        return ''.join(parts)
> +

I have no numbers to backup my claims but that really looks expensive to deal with a single file. At least, we should have a much faster version in util_win32, as suggested by Alexander Belchenko.

But the approach is good IMHO, let other comment on this.

--
Patrick Mézard


More information about the Mercurial-devel mailing list