[PATCH 1 of 2 STABLE] context: add 'changectx.dirs()' to recognize directory matching pattern

Matt Mackall mpm at selenic.com
Sat Feb 18 13:58:47 CST 2012


On Sun, 2012-02-19 at 00:15 +0900, FUJIWARA Katsunori wrote:
> # HG changeset patch
> # User FUJIWARA Katsunori <foozy at lares.dti.ne.jp>
> # Date 1329577967 -32400
> # Branch stable
> # Node ID 0df295bc57a9dbf897fde6be438711dd56797591
> # Parent  0e0060bf2f440d5cc33e5f36d99868a5380debd4
> context: add 'changectx.dirs()' to recognize directory matching pattern
> 
> when patterns which does not match any files in working context is
> specified, current implementation of 'localrepository.status()' decide
> whether warning message about it should be shown or not
> by 'f not in targetcontext'

> this works correctly for 'file pattern', but not for 'directory
> pattern', because 'f not in targetcontext' always returns True for
> directories.
> 
> this patch add 'changectx.dirs()', which returns map of all
> directories deduced from manifest, to examine whether specified
> directory is related to context or not quickly.

Interesting. There's probably a bit too much refactoring happening in
this patch.

Note that the code in dirstate is specialized for reference counting so
that add/remove does the right thing. For non-workingctx contexts, it's
a lot slower than it need be. And for working contexts, well, we might
as well be looking at the directory tree that dirstate has already
built, right?

So for normal contexts, we want something like:

dirs = set()
add = dirs.add
for path in self:
    pos = path.rfind('/')
    while pos != -1:
	if path[:pos] in dirs:
	    break # seen this directory and above
	add(path[:pos])
        pos = path.rfind('/', 0, pos)

But note that this is still pretty expensive, as it means unpacking a
manifest: we don't want to call this function if we can avoid it.

> diff -r 0e0060bf2f44 -r 0df295bc57a9 mercurial/context.py
> --- a/mercurial/context.py	Mon Feb 13 17:22:35 2012 +0100
> +++ b/mercurial/context.py	Sun Feb 19 00:12:47 2012 +0900
> @@ -236,6 +236,16 @@
>          return patch.diff(self._repo, ctx2.node(), self.node(),
>                            match=match, opts=diffopts)
>  
> +    @propertycache
> +    def _dirs(self):
> +        dirs = {}
> +        for f in self._manifest:
> +            util.incdirs(dirs, f)
> +        return dirs
> +
> +    def dirs(self):
> +        return self._dirs
> +
>  class filectx(object):
>      """A filecontext object makes access to data related to a particular
>         filerevision convenient."""
> diff -r 0e0060bf2f44 -r 0df295bc57a9 mercurial/dirstate.py
> --- a/mercurial/dirstate.py	Mon Feb 13 17:22:35 2012 +0100
> +++ b/mercurial/dirstate.py	Sun Feb 19 00:12:47 2012 +0900
> @@ -15,25 +15,9 @@
>  _format = ">cllll"
>  propertycache = util.propertycache
>  
> -def _finddirs(path):
> -    pos = path.rfind('/')
> -    while pos != -1:
> -        yield path[:pos]
> -        pos = path.rfind('/', 0, pos)
> -
> -def _incdirs(dirs, path):
> -    for base in _finddirs(path):
> -        if base in dirs:
> -            dirs[base] += 1
> -            return
> -        dirs[base] = 1
> -
> -def _decdirs(dirs, path):
> -    for base in _finddirs(path):
> -        if dirs[base] > 1:
> -            dirs[base] -= 1
> -            return
> -        del dirs[base]
> +_finddirs = util.finddirs
> +_incdirs = util.incdirs
> +_decdirs = util.decdirs
>  
>  class dirstate(object):
>  
> diff -r 0e0060bf2f44 -r 0df295bc57a9 mercurial/localrepo.py
> --- a/mercurial/localrepo.py	Mon Feb 13 17:22:35 2012 +0100
> +++ b/mercurial/localrepo.py	Sun Feb 19 00:12:47 2012 +0900
> @@ -1351,7 +1351,9 @@
>  
>          if not parentworking:
>              def bad(f, msg):
> -                if f not in ctx1:
> +                # 'f' may be a directory pattern from 'match.files()',
> +                # so 'f not in ctx1' is not enough
> +                if (f not in ctx1) and (f not in ctx1.dirs()):
>                      self.ui.warn('%s: %s\n' % (self.dirstate.pathto(f), msg))
>              match.bad = bad
>  
> diff -r 0e0060bf2f44 -r 0df295bc57a9 mercurial/util.py
> --- a/mercurial/util.py	Mon Feb 13 17:22:35 2012 +0100
> +++ b/mercurial/util.py	Sun Feb 19 00:12:47 2012 +0900
> @@ -1747,3 +1747,24 @@
>          return fd.isatty()
>      except AttributeError:
>          return False
> +
> +def finddirs(path):
> +    pos = path.rfind('/')
> +    while pos != -1:
> +        yield path[:pos]
> +        pos = path.rfind('/', 0, pos)
> +
> +def incdirs(dirs, path):
> +    for base in finddirs(path):
> +        if base in dirs:
> +            dirs[base] += 1
> +            return
> +        dirs[base] = 1
> +
> +def decdirs(dirs, path):
> +    for base in finddirs(path):
> +        if dirs[base] > 1:
> +            dirs[base] -= 1
> +            return
> +        del dirs[base]
> +
> diff -r 0e0060bf2f44 -r 0df295bc57a9 tests/test-status.t
> --- a/tests/test-status.t	Mon Feb 13 17:22:35 2012 +0100
> +++ b/tests/test-status.t	Sun Feb 19 00:12:47 2012 +0900
> @@ -295,3 +295,33 @@
>    $ hg ci -q -A -m 'add another file'
>    $ hg status -A --rev 1:2 010a
>    C 010a
> +
> +  $ cd ..
> +
> +test "hg status" with "directory pattern" which matches against files
> +only known on target revision.
> +
> +  $ hg init repo6
> +  $ cd repo6
> +
> +  $ echo a > a.txt
> +  $ hg add a.txt
> +  $ hg commit -m '#0'
> +  $ mkdir sub
> +  $ echo b > sub/b.txt
> +  $ hg add sub/b.txt
> +  $ hg commit -m '#1'
> +
> +  $ hg update -C 0 > /dev/null
> +  $ hg status -A
> +  C a.txt
> +
> +the directory matching against specified pattern should be removed,
> +because directory existence prevents 'dirstate.walk()' from showing
> +warning message about such pattern.
> +
> +  $ test ! -d sub
> +  $ hg status -A --rev 1 sub
> +  R sub/b.txt
> +
> +  $ cd ..
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel


-- 
Mathematics is the supreme nostalgia of our time.




More information about the Mercurial-devel mailing list