Merge with stable
authorPatrick Mezard <patrick@mezard.eu>
Wed, 15 Aug 2012 23:03:40 +0200
changeset 17372 ff3c89cf1477
parent 17361 5e276d1d504a (current diff)
parent 17371 1310489eb5d6 (diff)
child 17375 499e284f3f32
Merge with stable
--- a/mercurial/commands.py	Wed Aug 15 12:12:21 2012 +0200
+++ b/mercurial/commands.py	Wed Aug 15 23:03:40 2012 +0200
@@ -1847,14 +1847,17 @@
         localrevs = opts.get('local_head')
         doit(localrevs, remoterevs)
 
-@command('debugfileset', [], ('REVSPEC'))
-def debugfileset(ui, repo, expr):
+@command('debugfileset',
+    [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
+    _('[-r REV] FILESPEC'))
+def debugfileset(ui, repo, expr, **opts):
     '''parse and apply a fileset specification'''
+    ctx = scmutil.revsingle(repo, opts.get('rev'), None)
     if ui.verbose:
         tree = fileset.parse(expr)[0]
         ui.note(tree, "\n")
 
-    for f in fileset.getfileset(repo[None], expr):
+    for f in fileset.getfileset(ctx, expr):
         ui.write("%s\n" % f)
 
 @command('debugfsinfo', [], _('[PATH]'))
--- a/mercurial/fileset.py	Wed Aug 15 12:12:21 2012 +0200
+++ b/mercurial/fileset.py	Wed Aug 15 23:03:40 2012 +0200
@@ -107,6 +107,11 @@
     s = set(getset(mctx, x))
     return [r for r in mctx.subset if r not in s]
 
+def minusset(mctx, x, y):
+    xl = getset(mctx, x)
+    yl = set(getset(mctx, y))
+    return [f for f in xl if f not in yl]
+
 def listset(mctx, a, b):
     raise error.ParseError(_("can't use a list in this context"))
 
@@ -251,8 +256,11 @@
     """``grep(regex)``
     File contains the given regular expression.
     """
-    pat = getstring(x, _("grep requires a pattern"))
-    r = re.compile(pat)
+    try:
+        # i18n: "grep" is a keyword
+        r = re.compile(getstring(x, _("grep requires a pattern")))
+    except re.error, e:
+        raise error.ParseError(_('invalid match pattern: %s') % e)
     return [f for f in mctx.existing() if r.search(mctx.ctx[f].data())]
 
 _units = dict(k=2**10, K=2**10, kB=2**10, KB=2**10,
@@ -406,6 +414,7 @@
     'symbol': stringset,
     'and': andset,
     'or': orset,
+    'minus': minusset,
     'list': listset,
     'group': getset,
     'not': notset,
@@ -424,7 +433,14 @@
     def filter(self, files):
         return [f for f in files if f in self.subset]
     def existing(self):
-        return (f for f in self.subset if f in self.ctx)
+        if self._status is not None:
+            removed = set(self._status[3])
+            unknown = set(self._status[4] + self._status[5])
+        else:
+            removed = set()
+            unknown = set()
+        return (f for f in self.subset
+                if (f in self.ctx and f not in removed) or f in unknown)
     def narrow(self, files):
         return matchctx(self.ctx, self.filter(files), self._status)
 
@@ -438,14 +454,26 @@
                 return True
     return False
 
+# filesets using matchctx.existing()
+_existingcallers = [
+    'binary',
+    'exec',
+    'grep',
+    'size',
+    'symlink',
+]
+
 def getfileset(ctx, expr):
     tree, pos = parse(expr)
     if (pos != len(expr)):
         raise error.ParseError(_("invalid token"), pos)
 
     # do we need status info?
-    if _intree(['modified', 'added', 'removed', 'deleted',
-                'unknown', 'ignored', 'clean'], tree):
+    if (_intree(['modified', 'added', 'removed', 'deleted',
+                 'unknown', 'ignored', 'clean'], tree) or
+        # Using matchctx.existing() on a workingctx requires us to check
+        # for deleted files.
+        (ctx.rev() is None and _intree(_existingcallers, tree))):
         unknown = _intree(['unknown'], tree)
         ignored = _intree(['ignored'], tree)
 
@@ -457,7 +485,7 @@
             subset.extend(c)
     else:
         status = None
-        subset = ctx.walk(ctx.match([]))
+        subset = list(ctx.walk(ctx.match([])))
 
     return getset(matchctx(ctx, subset, status), tree)
 
--- a/tests/test-cat.t	Wed Aug 15 12:12:21 2012 +0200
+++ b/tests/test-cat.t	Wed Aug 15 23:03:40 2012 +0200
@@ -21,3 +21,14 @@
   [1]
   $ hg cat -r 1 b
   1
+
+Test fileset
+
+  $ echo 3 > c
+  $ hg ci -Am addmore c
+  $ hg cat 'set:not(b) or a'
+  3
+  $ hg cat 'set:c or b'
+  1
+  3
+
--- a/tests/test-debugcomplete.t	Wed Aug 15 12:12:21 2012 +0200
+++ b/tests/test-debugcomplete.t	Wed Aug 15 23:03:40 2012 +0200
@@ -229,7 +229,7 @@
   debugdata: changelog, manifest
   debugdate: extended
   debugdiscovery: old, nonheads, ssh, remotecmd, insecure
-  debugfileset: 
+  debugfileset: rev
   debugfsinfo: 
   debuggetbundle: head, common, type
   debugignore: 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-fileset.t	Wed Aug 15 23:03:40 2012 +0200
@@ -0,0 +1,228 @@
+  $ fileset() {
+  >   hg debugfileset "$@"
+  > }
+
+  $ hg init repo
+  $ cd repo
+  $ echo a > a1
+  $ echo a > a2
+  $ echo b > b1
+  $ echo b > b2
+  $ hg ci -Am addfiles
+  adding a1
+  adding a2
+  adding b1
+  adding b2
+
+Test operators and basic patterns
+
+  $ fileset a1
+  a1
+  $ fileset 'a*'
+  a1
+  a2
+  $ fileset '"re:a\d"'
+  a1
+  a2
+  $ fileset 'a1 or a2'
+  a1
+  a2
+  $ fileset 'a1 | a2'
+  a1
+  a2
+  $ fileset 'a* and "*1"'
+  a1
+  $ fileset 'a* & "*1"'
+  a1
+  $ fileset 'not (r"a*")'
+  b1
+  b2
+  $ fileset '! ("a*")'
+  b1
+  b2
+  $ fileset 'a* - a1'
+  a2
+
+Test files status
+
+  $ rm a1
+  $ hg rm a2
+  $ echo b >> b2
+  $ hg cp b1 c1
+  $ echo c > c2
+  $ echo c > c3
+  $ cat > .hgignore <<EOF
+  > \.hgignore
+  > 2$
+  > EOF
+  $ fileset 'modified()'
+  b2
+  $ fileset 'added()'
+  c1
+  $ fileset 'removed()'
+  a2
+  $ fileset 'deleted()'
+  a1
+  $ fileset 'unknown()'
+  c3
+  $ fileset 'ignored()'
+  .hgignore
+  c2
+  $ fileset 'hgignore()'
+  a2
+  b2
+  $ fileset 'clean()'
+  b1
+  $ fileset 'copied()'
+  c1
+
+Test files properties
+
+  >>> file('bin', 'wb').write('\0a')
+  $ fileset 'binary()'
+  $ fileset 'binary() and unknown()'
+  bin
+  $ echo '^bin$' >> .hgignore
+  $ fileset 'binary() and ignored()'
+  bin
+  $ hg add bin
+  $ fileset 'binary()'
+  bin
+
+  $ fileset 'grep("b{1}")'
+  b2
+  c1
+  b1
+  $ fileset 'grep("missingparens(")'
+  hg: parse error: invalid match pattern: unbalanced parenthesis
+  [255]
+
+#if execbit
+  $ chmod +x b2
+  $ fileset 'exec()'
+  b2
+#endif
+
+#if symlink
+  $ ln -s b2 b2link
+  $ fileset 'symlink() and unknown()'
+  b2link
+  $ hg add b2link
+#endif
+
+  >>> file('1k', 'wb').write(' '*1024)
+  >>> file('2k', 'wb').write(' '*2048)
+  $ hg add 1k 2k
+  $ fileset 'size("bar")'
+  hg: parse error: couldn't parse size: bar
+  [255]
+  $ fileset 'size(1k)'
+  1k
+  $ fileset '(1k or 2k) and size("< 2k")'
+  1k
+  $ fileset '(1k or 2k) and size("<=2k")'
+  1k
+  2k
+  $ fileset '(1k or 2k) and size("> 1k")'
+  2k
+  $ fileset '(1k or 2k) and size(">=1K")'
+  1k
+  2k
+  $ fileset '(1k or 2k) and size(".5KB - 1.5kB")'
+  1k
+
+Test merge states
+
+  $ hg ci -m manychanges
+  $ hg up -C 0
+  * files updated, 0 files merged, * files removed, 0 files unresolved (glob)
+  $ echo c >> b2
+  $ hg ci -m diverging b2
+  created new head
+  $ fileset 'resolved()'
+  $ fileset 'unresolved()'
+  $ hg merge
+  merging b2
+  warning: conflicts during merge.
+  merging b2 incomplete! (edit conflicts, then use 'hg resolve --mark')
+  * files updated, 0 files merged, * files removed, 1 files unresolved (glob)
+  use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+  [1]
+  $ fileset 'resolved()'
+  $ fileset 'unresolved()'
+  b2
+  $ echo e > b2
+  $ hg resolve -m b2
+  $ fileset 'resolved()'
+  b2
+  $ fileset 'unresolved()'
+  $ hg ci -m merge
+
+Test subrepo predicate
+
+  $ hg init sub
+  $ echo a > sub/suba
+  $ hg -R sub add sub/suba
+  $ hg -R sub ci -m sub
+  $ echo 'sub = sub' > .hgsub
+  $ fileset 'subrepo()'
+  $ hg add .hgsub
+  $ fileset 'subrepo()'
+  sub
+  $ fileset 'subrepo("sub")'
+  sub
+  $ fileset 'subrepo("glob:*")'
+  sub
+  $ hg ci -m subrepo
+
+Test with a revision
+
+  $ hg log -G --template '{rev} {desc}\n'
+  @  4 subrepo
+  |
+  o    3 merge
+  |\
+  | o  2 diverging
+  | |
+  o |  1 manychanges
+  |/
+  o  0 addfiles
+  
+  $ echo unknown > unknown
+  $ fileset -r1 'modified()'
+  b2
+  $ fileset -r1 'added() and c1'
+  c1
+  $ fileset -r1 'removed()'
+  a2
+  $ fileset -r1 'deleted()'
+  $ fileset -r1 'unknown()'
+  $ fileset -r1 'ignored()'
+  $ fileset -r1 'hgignore()'
+  b2
+  bin
+  $ fileset -r1 'binary()'
+  bin
+  $ fileset -r1 'size(1k)'
+  1k
+  $ fileset -r3 'resolved()'
+  $ fileset -r3 'unresolved()'
+
+#if execbit
+  $ fileset -r1 'exec()'
+  b2
+#endif
+
+#if symlink
+  $ fileset -r1 'symlink()'
+  b2link
+#endif
+
+  $ fileset -r4 'subrepo("re:su.*")'
+  sub
+  $ fileset -r4 'subrepo("sub")'
+  sub
+  $ fileset -r4 'b2 or c1'
+  b2
+  c1
+