fileset: add a lightweight file filtering language
This patch was inspired by one that Jun Wu authored for the fb-experimental
repo, to avoid using matcher for efficiency[1]. We want a way to specify what
files will be converted to LFS at commit time. And per discussion, we also want
to specify what files to skip, text diff, or merge in another config option.
The current `lfs.threshold` config option could not satisfy complex needs. I'm
putting it in a core package because Augie floated the idea of also using it for
narrow and sparse.
Yuya suggested farming out to fileset.parse(), which added support for more
symbols. The only fileset element not supported here is 'negate'. (List isn't
supported by filesets either.) I also changed the 'always' token to the 'all()'
predicate for consistency, and introduced 'none()' to improve readability in a
future tracked file based config. The extension operator was changed from '.'
to '**', to match how recursive path globs are specified. Finally, I changed
the path matcher from '/' to 'path:' at Yuya's suggestion, for consistency with
matcher. Unfortunately, ':' is currently reserved in filesets, so this has to
be quoted to be processed as a string instead of a symbol[2]. We should
probably revisit that, because it's seriously ugly. But it's only used by an
experimental extension, and I think using a file based config for LFS may drive
some more tweaks, so I'm settling for this for now.
I reserved all of the glob characters in fileset except '.' and '_' for the
extension test because those are likely valid extension characters.
Sample filter settings:
all() # everything
size(">20MB") # larger than 20MB
!**.txt # except for .txt files
**.zip | **.tar.gz | **.7z # some types of compressed files
"path:bin" # files under "bin" in the project root
[1] https://www.mercurial-scm.org/pipermail/mercurial-devel/2017-December/109387.html
[2] https://www.mercurial-scm.org/pipermail/mercurial-devel/2018-January/109729.html
$ unset HGUSER
$ EMAIL="My Name <myname@example.com>"
$ export EMAIL
$ hg init test
$ cd test
$ touch asdf
$ hg add asdf
$ hg commit -m commit-1
$ hg tip
changeset: 0:53f268a58230
tag: tip
user: My Name <myname@example.com>
date: Thu Jan 01 00:00:00 1970 +0000
summary: commit-1
$ unset EMAIL
$ echo 1234 > asdf
$ hg commit -u "foo@bar.com" -m commit-1
$ hg tip
changeset: 1:3871b2a9e9bf
tag: tip
user: foo@bar.com
date: Thu Jan 01 00:00:00 1970 +0000
summary: commit-1
$ echo "[ui]" >> .hg/hgrc
$ echo "username = foobar <foo@bar.com>" >> .hg/hgrc
$ echo 12 > asdf
$ hg commit -m commit-1
$ hg tip
changeset: 2:8eeac6695c1c
tag: tip
user: foobar <foo@bar.com>
date: Thu Jan 01 00:00:00 1970 +0000
summary: commit-1
$ echo 1 > asdf
$ hg commit -u "foo@bar.com" -m commit-1
$ hg tip
changeset: 3:957606a725e4
tag: tip
user: foo@bar.com
date: Thu Jan 01 00:00:00 1970 +0000
summary: commit-1
$ echo 123 > asdf
$ echo "[ui]" > .hg/hgrc
$ echo "username = " >> .hg/hgrc
$ hg commit -m commit-1
abort: no username supplied
(use 'hg config --edit' to set your username)
[255]
# test alternate config var
$ echo 1234 > asdf
$ echo "[ui]" > .hg/hgrc
$ echo "user = Foo Bar II <foo2@bar.com>" >> .hg/hgrc
$ hg commit -m commit-1
$ hg tip
changeset: 4:6f24bfb4c617
tag: tip
user: Foo Bar II <foo2@bar.com>
date: Thu Jan 01 00:00:00 1970 +0000
summary: commit-1
# test prompt username
$ cat > .hg/hgrc <<EOF
> [ui]
> askusername = True
> EOF
$ echo 12345 > asdf
$ hg commit --config ui.interactive=False -m ask
enter a commit username:
no username found, using '[^']*' instead (re)
$ hg rollback -q
$ hg commit --config ui.interactive=True -m ask <<EOF
> Asked User <ask@example.com>
> EOF
enter a commit username: Asked User <ask@example.com>
$ hg tip
changeset: 5:84c91d963b70
tag: tip
user: Asked User <ask@example.com>
date: Thu Jan 01 00:00:00 1970 +0000
summary: ask
# test no .hg/hgrc (uses generated non-interactive username)
$ echo space > asdf
$ rm .hg/hgrc
$ hg commit -m commit-1 2>&1
no username found, using '[^']*' instead (re)
$ echo space2 > asdf
$ hg commit -u ' ' -m commit-1
transaction abort!
rollback completed
abort: empty username!
[255]
# don't add tests here, previous test is unstable
$ cd ..