mercurial/fileset.py
changeset 27460 11286ac374f3
parent 27459 2f15253e415f
child 27461 afa76585c955
equal deleted inserted replaced
27459:2f15253e415f 27460:11286ac374f3
   128     return [f for f in xl if f not in yl]
   128     return [f for f in xl if f not in yl]
   129 
   129 
   130 def listset(mctx, a, b):
   130 def listset(mctx, a, b):
   131     raise error.ParseError(_("can't use a list in this context"))
   131     raise error.ParseError(_("can't use a list in this context"))
   132 
   132 
       
   133 # symbols are callable like:
       
   134 #  fun(mctx, x)
       
   135 # with:
       
   136 #  mctx - current matchctx instance
       
   137 #  x - argument in tree form
       
   138 symbols = {}
       
   139 
       
   140 def predicate(decl):
       
   141     """Return a decorator for fileset predicate function
       
   142 
       
   143     'decl' argument is the declaration (including argument list like
       
   144     'adds(pattern)') or the name (for internal use only) of predicate.
       
   145     """
       
   146     def decorator(func):
       
   147         i = decl.find('(')
       
   148         if i > 0:
       
   149             name = decl[:i]
       
   150         else:
       
   151             name = decl
       
   152         symbols[name] = func
       
   153         if func.__doc__:
       
   154             func.__doc__ = "``%s``\n    %s" % (decl, func.__doc__.strip())
       
   155         return func
       
   156     return decorator
       
   157 
       
   158 @predicate('modified()')
   133 def modified(mctx, x):
   159 def modified(mctx, x):
   134     """``modified()``
   160     """File that is modified according to :hg:`status`.
   135     File that is modified according to :hg:`status`.
       
   136     """
   161     """
   137     # i18n: "modified" is a keyword
   162     # i18n: "modified" is a keyword
   138     getargs(x, 0, 0, _("modified takes no arguments"))
   163     getargs(x, 0, 0, _("modified takes no arguments"))
   139     s = mctx.status().modified
   164     s = mctx.status().modified
   140     return [f for f in mctx.subset if f in s]
   165     return [f for f in mctx.subset if f in s]
   141 
   166 
       
   167 @predicate('added()')
   142 def added(mctx, x):
   168 def added(mctx, x):
   143     """``added()``
   169     """File that is added according to :hg:`status`.
   144     File that is added according to :hg:`status`.
       
   145     """
   170     """
   146     # i18n: "added" is a keyword
   171     # i18n: "added" is a keyword
   147     getargs(x, 0, 0, _("added takes no arguments"))
   172     getargs(x, 0, 0, _("added takes no arguments"))
   148     s = mctx.status().added
   173     s = mctx.status().added
   149     return [f for f in mctx.subset if f in s]
   174     return [f for f in mctx.subset if f in s]
   150 
   175 
       
   176 @predicate('removed()')
   151 def removed(mctx, x):
   177 def removed(mctx, x):
   152     """``removed()``
   178     """File that is removed according to :hg:`status`.
   153     File that is removed according to :hg:`status`.
       
   154     """
   179     """
   155     # i18n: "removed" is a keyword
   180     # i18n: "removed" is a keyword
   156     getargs(x, 0, 0, _("removed takes no arguments"))
   181     getargs(x, 0, 0, _("removed takes no arguments"))
   157     s = mctx.status().removed
   182     s = mctx.status().removed
   158     return [f for f in mctx.subset if f in s]
   183     return [f for f in mctx.subset if f in s]
   159 
   184 
       
   185 @predicate('deleted()')
   160 def deleted(mctx, x):
   186 def deleted(mctx, x):
   161     """``deleted()``
   187     """Alias for ``missing()``.
   162     Alias for ``missing()``.
       
   163     """
   188     """
   164     # i18n: "deleted" is a keyword
   189     # i18n: "deleted" is a keyword
   165     getargs(x, 0, 0, _("deleted takes no arguments"))
   190     getargs(x, 0, 0, _("deleted takes no arguments"))
   166     s = mctx.status().deleted
   191     s = mctx.status().deleted
   167     return [f for f in mctx.subset if f in s]
   192     return [f for f in mctx.subset if f in s]
   168 
   193 
       
   194 @predicate('missing()')
   169 def missing(mctx, x):
   195 def missing(mctx, x):
   170     """``missing()``
   196     """File that is missing according to :hg:`status`.
   171     File that is missing according to :hg:`status`.
       
   172     """
   197     """
   173     # i18n: "missing" is a keyword
   198     # i18n: "missing" is a keyword
   174     getargs(x, 0, 0, _("missing takes no arguments"))
   199     getargs(x, 0, 0, _("missing takes no arguments"))
   175     s = mctx.status().deleted
   200     s = mctx.status().deleted
   176     return [f for f in mctx.subset if f in s]
   201     return [f for f in mctx.subset if f in s]
   177 
   202 
       
   203 @predicate('unknown()')
   178 def unknown(mctx, x):
   204 def unknown(mctx, x):
   179     """``unknown()``
   205     """File that is unknown according to :hg:`status`. These files will only be
   180     File that is unknown according to :hg:`status`. These files will only be
       
   181     considered if this predicate is used.
   206     considered if this predicate is used.
   182     """
   207     """
   183     # i18n: "unknown" is a keyword
   208     # i18n: "unknown" is a keyword
   184     getargs(x, 0, 0, _("unknown takes no arguments"))
   209     getargs(x, 0, 0, _("unknown takes no arguments"))
   185     s = mctx.status().unknown
   210     s = mctx.status().unknown
   186     return [f for f in mctx.subset if f in s]
   211     return [f for f in mctx.subset if f in s]
   187 
   212 
       
   213 @predicate('ignored()')
   188 def ignored(mctx, x):
   214 def ignored(mctx, x):
   189     """``ignored()``
   215     """File that is ignored according to :hg:`status`. These files will only be
   190     File that is ignored according to :hg:`status`. These files will only be
       
   191     considered if this predicate is used.
   216     considered if this predicate is used.
   192     """
   217     """
   193     # i18n: "ignored" is a keyword
   218     # i18n: "ignored" is a keyword
   194     getargs(x, 0, 0, _("ignored takes no arguments"))
   219     getargs(x, 0, 0, _("ignored takes no arguments"))
   195     s = mctx.status().ignored
   220     s = mctx.status().ignored
   196     return [f for f in mctx.subset if f in s]
   221     return [f for f in mctx.subset if f in s]
   197 
   222 
       
   223 @predicate('clean()')
   198 def clean(mctx, x):
   224 def clean(mctx, x):
   199     """``clean()``
   225     """File that is clean according to :hg:`status`.
   200     File that is clean according to :hg:`status`.
       
   201     """
   226     """
   202     # i18n: "clean" is a keyword
   227     # i18n: "clean" is a keyword
   203     getargs(x, 0, 0, _("clean takes no arguments"))
   228     getargs(x, 0, 0, _("clean takes no arguments"))
   204     s = mctx.status().clean
   229     s = mctx.status().clean
   205     return [f for f in mctx.subset if f in s]
   230     return [f for f in mctx.subset if f in s]
   224     l = getlist(x)
   249     l = getlist(x)
   225     if len(l) < min or len(l) > max:
   250     if len(l) < min or len(l) > max:
   226         raise error.ParseError(err)
   251         raise error.ParseError(err)
   227     return l
   252     return l
   228 
   253 
       
   254 @predicate('binary()')
   229 def binary(mctx, x):
   255 def binary(mctx, x):
   230     """``binary()``
   256     """File that appears to be binary (contains NUL bytes).
   231     File that appears to be binary (contains NUL bytes).
       
   232     """
   257     """
   233     # i18n: "binary" is a keyword
   258     # i18n: "binary" is a keyword
   234     getargs(x, 0, 0, _("binary takes no arguments"))
   259     getargs(x, 0, 0, _("binary takes no arguments"))
   235     return [f for f in mctx.existing() if util.binary(mctx.ctx[f].data())]
   260     return [f for f in mctx.existing() if util.binary(mctx.ctx[f].data())]
   236 
   261 
       
   262 @predicate('exec()')
   237 def exec_(mctx, x):
   263 def exec_(mctx, x):
   238     """``exec()``
   264     """File that is marked as executable.
   239     File that is marked as executable.
       
   240     """
   265     """
   241     # i18n: "exec" is a keyword
   266     # i18n: "exec" is a keyword
   242     getargs(x, 0, 0, _("exec takes no arguments"))
   267     getargs(x, 0, 0, _("exec takes no arguments"))
   243     return [f for f in mctx.existing() if mctx.ctx.flags(f) == 'x']
   268     return [f for f in mctx.existing() if mctx.ctx.flags(f) == 'x']
   244 
   269 
       
   270 @predicate('symlink()')
   245 def symlink(mctx, x):
   271 def symlink(mctx, x):
   246     """``symlink()``
   272     """File that is marked as a symlink.
   247     File that is marked as a symlink.
       
   248     """
   273     """
   249     # i18n: "symlink" is a keyword
   274     # i18n: "symlink" is a keyword
   250     getargs(x, 0, 0, _("symlink takes no arguments"))
   275     getargs(x, 0, 0, _("symlink takes no arguments"))
   251     return [f for f in mctx.existing() if mctx.ctx.flags(f) == 'l']
   276     return [f for f in mctx.existing() if mctx.ctx.flags(f) == 'l']
   252 
   277 
       
   278 @predicate('resolved()')
   253 def resolved(mctx, x):
   279 def resolved(mctx, x):
   254     """``resolved()``
   280     """File that is marked resolved according to :hg:`resolve -l`.
   255     File that is marked resolved according to :hg:`resolve -l`.
       
   256     """
   281     """
   257     # i18n: "resolved" is a keyword
   282     # i18n: "resolved" is a keyword
   258     getargs(x, 0, 0, _("resolved takes no arguments"))
   283     getargs(x, 0, 0, _("resolved takes no arguments"))
   259     if mctx.ctx.rev() is not None:
   284     if mctx.ctx.rev() is not None:
   260         return []
   285         return []
   261     ms = merge.mergestate.read(mctx.ctx.repo())
   286     ms = merge.mergestate.read(mctx.ctx.repo())
   262     return [f for f in mctx.subset if f in ms and ms[f] == 'r']
   287     return [f for f in mctx.subset if f in ms and ms[f] == 'r']
   263 
   288 
       
   289 @predicate('unresolved()')
   264 def unresolved(mctx, x):
   290 def unresolved(mctx, x):
   265     """``unresolved()``
   291     """File that is marked unresolved according to :hg:`resolve -l`.
   266     File that is marked unresolved according to :hg:`resolve -l`.
       
   267     """
   292     """
   268     # i18n: "unresolved" is a keyword
   293     # i18n: "unresolved" is a keyword
   269     getargs(x, 0, 0, _("unresolved takes no arguments"))
   294     getargs(x, 0, 0, _("unresolved takes no arguments"))
   270     if mctx.ctx.rev() is not None:
   295     if mctx.ctx.rev() is not None:
   271         return []
   296         return []
   272     ms = merge.mergestate.read(mctx.ctx.repo())
   297     ms = merge.mergestate.read(mctx.ctx.repo())
   273     return [f for f in mctx.subset if f in ms and ms[f] == 'u']
   298     return [f for f in mctx.subset if f in ms and ms[f] == 'u']
   274 
   299 
       
   300 @predicate('hgignore()')
   275 def hgignore(mctx, x):
   301 def hgignore(mctx, x):
   276     """``hgignore()``
   302     """File that matches the active .hgignore pattern.
   277     File that matches the active .hgignore pattern.
       
   278     """
   303     """
   279     # i18n: "hgignore" is a keyword
   304     # i18n: "hgignore" is a keyword
   280     getargs(x, 0, 0, _("hgignore takes no arguments"))
   305     getargs(x, 0, 0, _("hgignore takes no arguments"))
   281     ignore = mctx.ctx.repo().dirstate._ignore
   306     ignore = mctx.ctx.repo().dirstate._ignore
   282     return [f for f in mctx.subset if ignore(f)]
   307     return [f for f in mctx.subset if ignore(f)]
   283 
   308 
       
   309 @predicate('portable()')
   284 def portable(mctx, x):
   310 def portable(mctx, x):
   285     """``portable()``
   311     """File that has a portable name. (This doesn't include filenames with case
   286     File that has a portable name. (This doesn't include filenames with case
       
   287     collisions.)
   312     collisions.)
   288     """
   313     """
   289     # i18n: "portable" is a keyword
   314     # i18n: "portable" is a keyword
   290     getargs(x, 0, 0, _("portable takes no arguments"))
   315     getargs(x, 0, 0, _("portable takes no arguments"))
   291     checkwinfilename = util.checkwinfilename
   316     checkwinfilename = util.checkwinfilename
   292     return [f for f in mctx.subset if checkwinfilename(f) is None]
   317     return [f for f in mctx.subset if checkwinfilename(f) is None]
   293 
   318 
       
   319 @predicate('grep(regex)')
   294 def grep(mctx, x):
   320 def grep(mctx, x):
   295     """``grep(regex)``
   321     """File contains the given regular expression.
   296     File contains the given regular expression.
       
   297     """
   322     """
   298     try:
   323     try:
   299         # i18n: "grep" is a keyword
   324         # i18n: "grep" is a keyword
   300         r = re.compile(getstring(x, _("grep requires a pattern")))
   325         r = re.compile(getstring(x, _("grep requires a pattern")))
   301     except re.error as e:
   326     except re.error as e:
   316         # no extension, this is a precise value
   341         # no extension, this is a precise value
   317         return int(s)
   342         return int(s)
   318     except ValueError:
   343     except ValueError:
   319         raise error.ParseError(_("couldn't parse size: %s") % s)
   344         raise error.ParseError(_("couldn't parse size: %s") % s)
   320 
   345 
       
   346 @predicate('size(expression)')
   321 def size(mctx, x):
   347 def size(mctx, x):
   322     """``size(expression)``
   348     """File size matches the given expression. Examples:
   323     File size matches the given expression. Examples:
       
   324 
   349 
   325     - 1k (files from 1024 to 2047 bytes)
   350     - 1k (files from 1024 to 2047 bytes)
   326     - < 20k (files less than 20480 bytes)
   351     - < 20k (files less than 20480 bytes)
   327     - >= .5MB (files at least 524288 bytes)
   352     - >= .5MB (files at least 524288 bytes)
   328     - 4k - 1MB (files from 4096 bytes to 1048576 bytes)
   353     - 4k - 1MB (files from 4096 bytes to 1048576 bytes)
   354     else:
   379     else:
   355         raise error.ParseError(_("couldn't parse size: %s") % expr)
   380         raise error.ParseError(_("couldn't parse size: %s") % expr)
   356 
   381 
   357     return [f for f in mctx.existing() if m(mctx.ctx[f].size())]
   382     return [f for f in mctx.existing() if m(mctx.ctx[f].size())]
   358 
   383 
       
   384 @predicate('encoding(name)')
   359 def encoding(mctx, x):
   385 def encoding(mctx, x):
   360     """``encoding(name)``
   386     """File can be successfully decoded with the given character
   361     File can be successfully decoded with the given character
       
   362     encoding. May not be useful for encodings other than ASCII and
   387     encoding. May not be useful for encodings other than ASCII and
   363     UTF-8.
   388     UTF-8.
   364     """
   389     """
   365 
   390 
   366     # i18n: "encoding" is a keyword
   391     # i18n: "encoding" is a keyword
   377             continue
   402             continue
   378         s.append(f)
   403         s.append(f)
   379 
   404 
   380     return s
   405     return s
   381 
   406 
       
   407 @predicate('eol(style)')
   382 def eol(mctx, x):
   408 def eol(mctx, x):
   383     """``eol(style)``
   409     """File contains newlines of the given style (dos, unix, mac). Binary
   384     File contains newlines of the given style (dos, unix, mac). Binary
       
   385     files are excluded, files with mixed line endings match multiple
   410     files are excluded, files with mixed line endings match multiple
   386     styles.
   411     styles.
   387     """
   412     """
   388 
   413 
   389     # i18n: "encoding" is a keyword
   414     # i18n: "encoding" is a keyword
   400             s.append(f)
   425             s.append(f)
   401         elif enc == 'mac' and re.search('\r(?!\n)', d):
   426         elif enc == 'mac' and re.search('\r(?!\n)', d):
   402             s.append(f)
   427             s.append(f)
   403     return s
   428     return s
   404 
   429 
       
   430 @predicate('copied()')
   405 def copied(mctx, x):
   431 def copied(mctx, x):
   406     """``copied()``
   432     """File that is recorded as being copied.
   407     File that is recorded as being copied.
       
   408     """
   433     """
   409     # i18n: "copied" is a keyword
   434     # i18n: "copied" is a keyword
   410     getargs(x, 0, 0, _("copied takes no arguments"))
   435     getargs(x, 0, 0, _("copied takes no arguments"))
   411     s = []
   436     s = []
   412     for f in mctx.subset:
   437     for f in mctx.subset:
   413         p = mctx.ctx[f].parents()
   438         p = mctx.ctx[f].parents()
   414         if p and p[0].path() != f:
   439         if p and p[0].path() != f:
   415             s.append(f)
   440             s.append(f)
   416     return s
   441     return s
   417 
   442 
       
   443 @predicate('subrepo([pattern])')
   418 def subrepo(mctx, x):
   444 def subrepo(mctx, x):
   419     """``subrepo([pattern])``
   445     """Subrepositories whose paths match the given pattern.
   420     Subrepositories whose paths match the given pattern.
       
   421     """
   446     """
   422     # i18n: "subrepo" is a keyword
   447     # i18n: "subrepo" is a keyword
   423     getargs(x, 0, 1, _("subrepo takes at most one argument"))
   448     getargs(x, 0, 1, _("subrepo takes at most one argument"))
   424     ctx = mctx.ctx
   449     ctx = mctx.ctx
   425     sstate = sorted(ctx.substate)
   450     sstate = sorted(ctx.substate)
   435         else:
   460         else:
   436             m = matchmod.match(ctx.repo().root, '', [pat], ctx=ctx)
   461             m = matchmod.match(ctx.repo().root, '', [pat], ctx=ctx)
   437         return [sub for sub in sstate if m(sub)]
   462         return [sub for sub in sstate if m(sub)]
   438     else:
   463     else:
   439         return [sub for sub in sstate]
   464         return [sub for sub in sstate]
   440 
       
   441 symbols = {
       
   442     'added': added,
       
   443     'binary': binary,
       
   444     'clean': clean,
       
   445     'copied': copied,
       
   446     'deleted': deleted,
       
   447     'encoding': encoding,
       
   448     'eol': eol,
       
   449     'exec': exec_,
       
   450     'grep': grep,
       
   451     'ignored': ignored,
       
   452     'hgignore': hgignore,
       
   453     'missing': missing,
       
   454     'modified': modified,
       
   455     'portable': portable,
       
   456     'removed': removed,
       
   457     'resolved': resolved,
       
   458     'size': size,
       
   459     'symlink': symlink,
       
   460     'unknown': unknown,
       
   461     'unresolved': unresolved,
       
   462     'subrepo': subrepo,
       
   463 }
       
   464 
   465 
   465 methods = {
   466 methods = {
   466     'string': stringset,
   467     'string': stringset,
   467     'symbol': stringset,
   468     'symbol': stringset,
   468     'and': andset,
   469     'and': andset,