test-template-functions.t
1723 lines
| 41.9 KiB
| text/troff
|
Tads3Lexer
/ tests / test-template-functions.t
|
r38453 | Test template filters and functions | ||
=================================== | ||||
$ hg init a | ||||
$ cd a | ||||
$ echo a > a | ||||
$ hg add a | ||||
$ echo line 1 > b | ||||
$ echo line 2 >> b | ||||
$ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>' | ||||
$ hg add b | ||||
$ echo other 1 > c | ||||
$ echo other 2 >> c | ||||
$ echo >> c | ||||
$ echo other 3 >> c | ||||
$ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>' | ||||
$ hg add c | ||||
$ hg commit -m 'no person' -d '1200000 0' -u 'other@place' | ||||
$ echo c >> c | ||||
$ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person' | ||||
$ echo foo > .hg/branch | ||||
$ hg commit -m 'new branch' -d '1400000 0' -u 'person' | ||||
$ hg co -q 3 | ||||
$ echo other 4 >> d | ||||
$ hg add d | ||||
$ hg commit -m 'new head' -d '1500000 0' -u 'person' | ||||
$ hg merge -q foo | ||||
$ hg commit -m 'merge' -d '1500001 0' -u 'person' | ||||
Second branch starting at nullrev: | ||||
$ hg update null | ||||
0 files updated, 0 files merged, 4 files removed, 0 files unresolved | ||||
$ echo second > second | ||||
$ hg add second | ||||
$ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>' | ||||
created new head | ||||
$ echo third > third | ||||
$ hg add third | ||||
$ hg mv second fourth | ||||
$ hg commit -m third -d "2020-01-01 10:01" | ||||
$ hg phase -r 5 --public | ||||
$ hg phase -r 7 --secret --force | ||||
Filters work: | ||||
$ hg log --template '{author|domain}\n' | ||||
hostname | ||||
place | ||||
place | ||||
hostname | ||||
$ hg log --template '{author|person}\n' | ||||
test | ||||
User Name | ||||
person | ||||
person | ||||
person | ||||
person | ||||
other | ||||
A. N. Other | ||||
User Name | ||||
$ hg log --template '{author|user}\n' | ||||
test | ||||
user | ||||
person | ||||
person | ||||
person | ||||
person | ||||
other | ||||
other | ||||
user | ||||
$ hg log --template '{date|date}\n' | ||||
Wed Jan 01 10:01:00 2020 +0000 | ||||
Mon Jan 12 13:46:40 1970 +0000 | ||||
Sun Jan 18 08:40:01 1970 +0000 | ||||
Sun Jan 18 08:40:00 1970 +0000 | ||||
Sat Jan 17 04:53:20 1970 +0000 | ||||
Fri Jan 16 01:06:40 1970 +0000 | ||||
Wed Jan 14 21:20:00 1970 +0000 | ||||
Tue Jan 13 17:33:20 1970 +0000 | ||||
Mon Jan 12 13:46:40 1970 +0000 | ||||
$ hg log --template '{date|isodate}\n' | ||||
2020-01-01 10:01 +0000 | ||||
1970-01-12 13:46 +0000 | ||||
1970-01-18 08:40 +0000 | ||||
1970-01-18 08:40 +0000 | ||||
1970-01-17 04:53 +0000 | ||||
1970-01-16 01:06 +0000 | ||||
1970-01-14 21:20 +0000 | ||||
1970-01-13 17:33 +0000 | ||||
1970-01-12 13:46 +0000 | ||||
$ hg log --template '{date|isodatesec}\n' | ||||
2020-01-01 10:01:00 +0000 | ||||
1970-01-12 13:46:40 +0000 | ||||
1970-01-18 08:40:01 +0000 | ||||
1970-01-18 08:40:00 +0000 | ||||
1970-01-17 04:53:20 +0000 | ||||
1970-01-16 01:06:40 +0000 | ||||
1970-01-14 21:20:00 +0000 | ||||
1970-01-13 17:33:20 +0000 | ||||
1970-01-12 13:46:40 +0000 | ||||
$ hg log --template '{date|rfc822date}\n' | ||||
Wed, 01 Jan 2020 10:01:00 +0000 | ||||
Mon, 12 Jan 1970 13:46:40 +0000 | ||||
Sun, 18 Jan 1970 08:40:01 +0000 | ||||
Sun, 18 Jan 1970 08:40:00 +0000 | ||||
Sat, 17 Jan 1970 04:53:20 +0000 | ||||
Fri, 16 Jan 1970 01:06:40 +0000 | ||||
Wed, 14 Jan 1970 21:20:00 +0000 | ||||
Tue, 13 Jan 1970 17:33:20 +0000 | ||||
Mon, 12 Jan 1970 13:46:40 +0000 | ||||
$ hg log --template '{desc|firstline}\n' | ||||
third | ||||
second | ||||
merge | ||||
new head | ||||
new branch | ||||
no user, no domain | ||||
no person | ||||
other 1 | ||||
line 1 | ||||
$ hg log --template '{node|short}\n' | ||||
95c24699272e | ||||
29114dbae42b | ||||
d41e714fe50d | ||||
13207e5a10d9 | ||||
bbe44766e73d | ||||
10e46f2dcbf4 | ||||
97054abb4ab8 | ||||
b608e9d1a3f0 | ||||
1e4e1b8f71e0 | ||||
$ hg log --template '<changeset author="{author|xmlescape}"/>\n' | ||||
<changeset author="test"/> | ||||
<changeset author="User Name <user@hostname>"/> | ||||
<changeset author="person"/> | ||||
<changeset author="person"/> | ||||
<changeset author="person"/> | ||||
<changeset author="person"/> | ||||
<changeset author="other@place"/> | ||||
<changeset author="A. N. Other <other@place>"/> | ||||
<changeset author="User Name <user@hostname>"/> | ||||
$ hg log --template '{rev}: {children}\n' | ||||
8: | ||||
7: 8:95c24699272e | ||||
6: | ||||
5: 6:d41e714fe50d | ||||
4: 6:d41e714fe50d | ||||
3: 4:bbe44766e73d 5:13207e5a10d9 | ||||
2: 3:10e46f2dcbf4 | ||||
1: 2:97054abb4ab8 | ||||
0: 1:b608e9d1a3f0 | ||||
Formatnode filter works: | ||||
$ hg -q log -r 0 --template '{node|formatnode}\n' | ||||
1e4e1b8f71e0 | ||||
$ hg log -r 0 --template '{node|formatnode}\n' | ||||
1e4e1b8f71e0 | ||||
$ hg -v log -r 0 --template '{node|formatnode}\n' | ||||
1e4e1b8f71e0 | ||||
$ hg --debug log -r 0 --template '{node|formatnode}\n' | ||||
1e4e1b8f71e05681d422154f5421e385fec3454f | ||||
Age filter: | ||||
$ hg init unstable-hash | ||||
$ cd unstable-hash | ||||
$ hg log --template '{date|age}\n' > /dev/null || exit 1 | ||||
>>> from __future__ import absolute_import | ||||
>>> import datetime | ||||
>>> fp = open('a', 'wb') | ||||
>>> n = datetime.datetime.now() + datetime.timedelta(366 * 7) | ||||
>>> fp.write(b'%d-%d-%d 00:00' % (n.year, n.month, n.day)) and None | ||||
>>> fp.close() | ||||
$ hg add a | ||||
$ hg commit -m future -d "`cat a`" | ||||
$ hg log -l1 --template '{date|age}\n' | ||||
7 years from now | ||||
$ cd .. | ||||
$ rm -rf unstable-hash | ||||
Filename filters: | ||||
$ hg debugtemplate '{"foo/bar"|basename}|{"foo/"|basename}|{"foo"|basename}|\n' | ||||
bar||foo| | ||||
$ hg debugtemplate '{"foo/bar"|dirname}|{"foo/"|dirname}|{"foo"|dirname}|\n' | ||||
foo|foo|| | ||||
$ hg debugtemplate '{"foo/bar"|stripdir}|{"foo/"|stripdir}|{"foo"|stripdir}|\n' | ||||
foo|foo|foo| | ||||
|
r38454 | commondir() filter: | ||
$ hg debugtemplate '{""|splitlines|commondir}\n' | ||||
$ hg debugtemplate '{"foo/bar\nfoo/baz\nfoo/foobar\n"|splitlines|commondir}\n' | ||||
foo | ||||
$ hg debugtemplate '{"foo/bar\nfoo/bar\n"|splitlines|commondir}\n' | ||||
foo | ||||
$ hg debugtemplate '{"/foo/bar\n/foo/bar\n"|splitlines|commondir}\n' | ||||
foo | ||||
$ hg debugtemplate '{"/foo\n/foo\n"|splitlines|commondir}\n' | ||||
$ hg debugtemplate '{"foo/bar\nbar/baz"|splitlines|commondir}\n' | ||||
$ hg debugtemplate '{"foo/bar\nbar/baz\nbar/foo\n"|splitlines|commondir}\n' | ||||
$ hg debugtemplate '{"foo/../bar\nfoo/bar"|splitlines|commondir}\n' | ||||
foo | ||||
$ hg debugtemplate '{"foo\n/foo"|splitlines|commondir}\n' | ||||
$ hg log -r null -T '{rev|commondir}' | ||||
hg: parse error: argument is not a list of text | ||||
(template filter 'commondir' is not compatible with keyword 'rev') | ||||
[255] | ||||
|
r38453 | Add a dummy commit to make up for the instability of the above: | ||
$ echo a > a | ||||
$ hg add a | ||||
$ hg ci -m future | ||||
Count filter: | ||||
$ hg log -l1 --template '{node|count} {node|short|count}\n' | ||||
40 12 | ||||
$ hg log -l1 --template '{revset("null^")|count} {revset(".")|count} {revset("0::3")|count}\n' | ||||
0 1 4 | ||||
$ hg log -G --template '{rev}: children: {children|count}, \ | ||||
> tags: {tags|count}, file_adds: {file_adds|count}, \ | ||||
> ancestors: {revset("ancestors(%s)", rev)|count}' | ||||
@ 9: children: 0, tags: 1, file_adds: 1, ancestors: 3 | ||||
| | ||||
o 8: children: 1, tags: 0, file_adds: 2, ancestors: 2 | ||||
| | ||||
o 7: children: 1, tags: 0, file_adds: 1, ancestors: 1 | ||||
o 6: children: 0, tags: 0, file_adds: 0, ancestors: 7 | ||||
|\ | ||||
| o 5: children: 1, tags: 0, file_adds: 1, ancestors: 5 | ||||
| | | ||||
o | 4: children: 1, tags: 0, file_adds: 0, ancestors: 5 | ||||
|/ | ||||
o 3: children: 2, tags: 0, file_adds: 0, ancestors: 4 | ||||
| | ||||
o 2: children: 1, tags: 0, file_adds: 1, ancestors: 3 | ||||
| | ||||
o 1: children: 1, tags: 0, file_adds: 1, ancestors: 2 | ||||
| | ||||
o 0: children: 1, tags: 0, file_adds: 1, ancestors: 1 | ||||
$ hg log -l1 -T '{termwidth|count}\n' | ||||
hg: parse error: not countable | ||||
(template filter 'count' is not compatible with keyword 'termwidth') | ||||
[255] | ||||
Upper/lower filters: | ||||
$ hg log -r0 --template '{branch|upper}\n' | ||||
DEFAULT | ||||
$ hg log -r0 --template '{author|lower}\n' | ||||
user name <user@hostname> | ||||
$ hg log -r0 --template '{date|upper}\n' | ||||
1000000.00 | ||||
Add a commit that does all possible modifications at once | ||||
$ echo modify >> third | ||||
$ touch b | ||||
$ hg add b | ||||
$ hg mv fourth fifth | ||||
$ hg rm a | ||||
$ hg ci -m "Modify, add, remove, rename" | ||||
Pass generator object created by template function to filter | ||||
$ hg log -l 1 --template '{if(author, author)|user}\n' | ||||
test | ||||
Test diff function: | ||||
$ hg diff -c 8 | ||||
diff -r 29114dbae42b -r 95c24699272e fourth | ||||
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 | ||||
+++ b/fourth Wed Jan 01 10:01:00 2020 +0000 | ||||
@@ -0,0 +1,1 @@ | ||||
+second | ||||
diff -r 29114dbae42b -r 95c24699272e second | ||||
--- a/second Mon Jan 12 13:46:40 1970 +0000 | ||||
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000 | ||||
@@ -1,1 +0,0 @@ | ||||
-second | ||||
diff -r 29114dbae42b -r 95c24699272e third | ||||
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 | ||||
+++ b/third Wed Jan 01 10:01:00 2020 +0000 | ||||
@@ -0,0 +1,1 @@ | ||||
+third | ||||
$ hg log -r 8 -T "{diff()}" | ||||
diff -r 29114dbae42b -r 95c24699272e fourth | ||||
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 | ||||
+++ b/fourth Wed Jan 01 10:01:00 2020 +0000 | ||||
@@ -0,0 +1,1 @@ | ||||
+second | ||||
diff -r 29114dbae42b -r 95c24699272e second | ||||
--- a/second Mon Jan 12 13:46:40 1970 +0000 | ||||
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000 | ||||
@@ -1,1 +0,0 @@ | ||||
-second | ||||
diff -r 29114dbae42b -r 95c24699272e third | ||||
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 | ||||
+++ b/third Wed Jan 01 10:01:00 2020 +0000 | ||||
@@ -0,0 +1,1 @@ | ||||
+third | ||||
$ hg log -r 8 -T "{diff('glob:f*')}" | ||||
diff -r 29114dbae42b -r 95c24699272e fourth | ||||
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 | ||||
+++ b/fourth Wed Jan 01 10:01:00 2020 +0000 | ||||
@@ -0,0 +1,1 @@ | ||||
+second | ||||
$ hg log -r 8 -T "{diff('', 'glob:f*')}" | ||||
diff -r 29114dbae42b -r 95c24699272e second | ||||
--- a/second Mon Jan 12 13:46:40 1970 +0000 | ||||
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000 | ||||
@@ -1,1 +0,0 @@ | ||||
-second | ||||
diff -r 29114dbae42b -r 95c24699272e third | ||||
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 | ||||
+++ b/third Wed Jan 01 10:01:00 2020 +0000 | ||||
@@ -0,0 +1,1 @@ | ||||
+third | ||||
$ hg log -r 8 -T "{diff('FOURTH'|lower)}" | ||||
diff -r 29114dbae42b -r 95c24699272e fourth | ||||
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 | ||||
+++ b/fourth Wed Jan 01 10:01:00 2020 +0000 | ||||
@@ -0,0 +1,1 @@ | ||||
+second | ||||
|
r43321 | $ hg --config diff.git=true log -r 8 -T "{diff()}" | ||
diff --git a/second b/fourth | ||||
rename from second | ||||
rename to fourth | ||||
diff --git a/third b/third | ||||
new file mode 100644 | ||||
--- /dev/null | ||||
+++ b/third | ||||
@@ -0,0 +1,1 @@ | ||||
+third | ||||
|
r38453 | $ cd .. | ||
latesttag() function: | ||||
$ hg init latesttag | ||||
$ cd latesttag | ||||
$ echo a > file | ||||
$ hg ci -Am a -d '0 0' | ||||
adding file | ||||
$ echo b >> file | ||||
$ hg ci -m b -d '1 0' | ||||
$ echo c >> head1 | ||||
$ hg ci -Am h1c -d '2 0' | ||||
adding head1 | ||||
$ hg update -q 1 | ||||
$ echo d >> head2 | ||||
$ hg ci -Am h2d -d '3 0' | ||||
adding head2 | ||||
created new head | ||||
$ echo e >> head2 | ||||
$ hg ci -m h2e -d '4 0' | ||||
$ hg merge -q | ||||
$ hg ci -m merge -d '5 -3600' | ||||
$ hg tag -r 1 -m t1 -d '6 0' t1 | ||||
$ hg tag -r 2 -m t2 -d '7 0' t2 | ||||
$ hg tag -r 3 -m t3 -d '8 0' t3 | ||||
$ hg tag -r 4 -m t4 -d '4 0' t4 # older than t2, but should not matter | ||||
$ hg tag -r 5 -m t5 -d '9 0' t5 | ||||
$ hg tag -r 3 -m at3 -d '10 0' at3 | ||||
$ hg log -G --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n" | ||||
@ 11: t3, C: 9, D: 8 | ||||
| | ||||
o 10: t3, C: 8, D: 7 | ||||
| | ||||
o 9: t3, C: 7, D: 6 | ||||
| | ||||
o 8: t3, C: 6, D: 5 | ||||
| | ||||
o 7: t3, C: 5, D: 4 | ||||
| | ||||
o 6: t3, C: 4, D: 3 | ||||
| | ||||
o 5: t3, C: 3, D: 2 | ||||
|\ | ||||
| o 4: t3, C: 1, D: 1 | ||||
| | | ||||
| o 3: t3, C: 0, D: 0 | ||||
| | | ||||
o | 2: t1, C: 1, D: 1 | ||||
|/ | ||||
o 1: t1, C: 0, D: 0 | ||||
| | ||||
o 0: null, C: 1, D: 1 | ||||
$ cd .. | ||||
|
r38467 | Test filter() empty values: | ||
$ hg log -R a -r 1 -T '{filter(desc|splitlines) % "{line}\n"}' | ||||
other 1 | ||||
other 2 | ||||
other 3 | ||||
$ hg log -R a -r 0 -T '{filter(dict(a=0, b=1) % "{ifeq(key, "a", "{value}\n")}")}' | ||||
0 | ||||
0 should not be falsy | ||||
$ hg log -R a -r 0 -T '{filter(revset("0:2"))}\n' | ||||
0 1 2 | ||||
|
r38468 | Test filter() by expression: | ||
$ hg log -R a -r 1 -T '{filter(desc|splitlines, ifcontains("1", line, "t"))}\n' | ||||
other 1 | ||||
$ hg log -R a -r 0 -T '{filter(dict(a=0, b=1), ifeq(key, "b", "t"))}\n' | ||||
b=1 | ||||
|
r38467 | Test filter() shouldn't crash: | ||
$ hg log -R a -r 0 -T '{filter(extras)}\n' | ||||
branch=default | ||||
$ hg log -R a -r 0 -T '{filter(files)}\n' | ||||
a | ||||
Test filter() unsupported arguments: | ||||
$ hg log -R a -r 0 -T '{filter()}\n' | ||||
|
r38468 | hg: parse error: filter expects one or two arguments | ||
|
r38467 | [255] | ||
$ hg log -R a -r 0 -T '{filter(date)}\n' | ||||
hg: parse error: date is not iterable | ||||
[255] | ||||
$ hg log -R a -r 0 -T '{filter(rev)}\n' | ||||
hg: parse error: 0 is not iterable | ||||
[255] | ||||
$ hg log -R a -r 0 -T '{filter(desc|firstline)}\n' | ||||
hg: parse error: 'line 1' is not filterable | ||||
[255] | ||||
$ hg log -R a -r 0 -T '{filter(manifest)}\n' | ||||
hg: parse error: '0:a0c8bcbbb45c' is not filterable | ||||
[255] | ||||
$ hg log -R a -r 0 -T '{filter(succsandmarkers)}\n' | ||||
hg: parse error: not filterable without template | ||||
[255] | ||||
|
r38468 | $ hg log -R a -r 0 -T '{filter(desc|splitlines % "{line}", "")}\n' | ||
hg: parse error: not filterable by expression | ||||
[255] | ||||
|
r38467 | |||
|
r38453 | Test manifest/get() can be join()-ed as string, though it's silly: | ||
$ hg log -R latesttag -r tip -T '{join(manifest, ".")}\n' | ||||
1.1.:.2.b.c.6.e.9.0.0.6.c.e.2 | ||||
$ hg log -R latesttag -r tip -T '{join(get(extras, "branch"), ".")}\n' | ||||
d.e.f.a.u.l.t | ||||
Test join() over string | ||||
$ hg log -R latesttag -r tip -T '{join(rev|stringify, ".")}\n' | ||||
1.1 | ||||
Test join() over uniterable | ||||
$ hg log -R latesttag -r tip -T '{join(rev, "")}\n' | ||||
hg: parse error: 11 is not iterable | ||||
[255] | ||||
Test min/max of integers | ||||
$ hg log -R latesttag -l1 -T '{min(revset("9:10"))}\n' | ||||
9 | ||||
$ hg log -R latesttag -l1 -T '{max(revset("9:10"))}\n' | ||||
10 | ||||
Test min/max over map operation: | ||||
$ hg log -R latesttag -r3 -T '{min(tags % "{tag}")}\n' | ||||
at3 | ||||
$ hg log -R latesttag -r3 -T '{max(tags % "{tag}")}\n' | ||||
t3 | ||||
Test min/max of strings: | ||||
$ hg log -R latesttag -l1 -T '{min(desc)}\n' | ||||
3 | ||||
$ hg log -R latesttag -l1 -T '{max(desc)}\n' | ||||
t | ||||
Test min/max of non-iterable: | ||||
$ hg debugtemplate '{min(1)}' | ||||
hg: parse error: 1 is not iterable | ||||
(min first argument should be an iterable) | ||||
[255] | ||||
$ hg debugtemplate '{max(2)}' | ||||
hg: parse error: 2 is not iterable | ||||
(max first argument should be an iterable) | ||||
[255] | ||||
$ hg log -R latesttag -l1 -T '{min(date)}' | ||||
hg: parse error: date is not iterable | ||||
(min first argument should be an iterable) | ||||
[255] | ||||
$ hg log -R latesttag -l1 -T '{max(date)}' | ||||
hg: parse error: date is not iterable | ||||
(max first argument should be an iterable) | ||||
[255] | ||||
Test min/max of empty sequence: | ||||
$ hg debugtemplate '{min("")}' | ||||
hg: parse error: empty string | ||||
(min first argument should be an iterable) | ||||
[255] | ||||
$ hg debugtemplate '{max("")}' | ||||
hg: parse error: empty string | ||||
(max first argument should be an iterable) | ||||
[255] | ||||
$ hg debugtemplate '{min(dict())}' | ||||
hg: parse error: empty sequence | ||||
(min first argument should be an iterable) | ||||
[255] | ||||
$ hg debugtemplate '{max(dict())}' | ||||
hg: parse error: empty sequence | ||||
(max first argument should be an iterable) | ||||
[255] | ||||
$ hg debugtemplate '{min(dict() % "")}' | ||||
hg: parse error: empty sequence | ||||
(min first argument should be an iterable) | ||||
[255] | ||||
$ hg debugtemplate '{max(dict() % "")}' | ||||
hg: parse error: empty sequence | ||||
(max first argument should be an iterable) | ||||
[255] | ||||
Test min/max of if() result | ||||
$ cd latesttag | ||||
$ hg log -l1 -T '{min(if(true, revset("9:10"), ""))}\n' | ||||
9 | ||||
$ hg log -l1 -T '{max(if(false, "", revset("9:10")))}\n' | ||||
10 | ||||
$ hg log -l1 -T '{min(ifcontains("a", "aa", revset("9:10"), ""))}\n' | ||||
9 | ||||
$ hg log -l1 -T '{max(ifcontains("a", "bb", "", revset("9:10")))}\n' | ||||
10 | ||||
$ hg log -l1 -T '{min(ifeq(0, 0, revset("9:10"), ""))}\n' | ||||
9 | ||||
$ hg log -l1 -T '{max(ifeq(0, 1, "", revset("9:10")))}\n' | ||||
10 | ||||
$ cd .. | ||||
Test laziness of if() then/else clause | ||||
$ hg debugtemplate '{count(0)}' | ||||
hg: parse error: not countable | ||||
(incompatible use of template filter 'count') | ||||
[255] | ||||
$ hg debugtemplate '{if(true, "", count(0))}' | ||||
$ hg debugtemplate '{if(false, count(0), "")}' | ||||
$ hg debugtemplate '{ifcontains("a", "aa", "", count(0))}' | ||||
$ hg debugtemplate '{ifcontains("a", "bb", count(0), "")}' | ||||
$ hg debugtemplate '{ifeq(0, 0, "", count(0))}' | ||||
$ hg debugtemplate '{ifeq(0, 1, count(0), "")}' | ||||
|
r40970 | Test search() function: | ||
$ hg log -R a -r2 -T '{desc}\n' | ||||
no person | ||||
$ hg log -R a -r2 -T '{search(r"p.*", desc)}\n' | ||||
person | ||||
as bool | ||||
$ hg log -R a -r2 -T '{if(search(r"p.*", desc), "", "not ")}found\n' | ||||
found | ||||
$ hg log -R a -r2 -T '{if(search(r"q", desc), "", "not ")}found\n' | ||||
not found | ||||
match as json | ||||
$ hg log -R a -r2 -T '{search(r"(no) p.*", desc)|json}\n' | ||||
{"0": "no person", "1": "no"} | ||||
$ hg log -R a -r2 -T '{search(r"q", desc)|json}\n' | ||||
null | ||||
group reference | ||||
$ hg log -R a -r2 -T '{search(r"(no) (p.*)", desc) % "{1|upper} {2|hex}"}\n' | ||||
NO 706572736f6e | ||||
$ hg log -R a -r2 -T '{search(r"(?P<foo>[a-z]*)", desc) % "{foo}"}\n' | ||||
no | ||||
$ hg log -R a -r2 -T '{search(r"(?P<foo>[a-z]*)", desc).foo}\n' | ||||
no | ||||
group reference with no match | ||||
$ hg log -R a -r2 -T '{search(r"q", desc) % "match: {0}"}\n' | ||||
|
r40971 | |||
|
r40970 | |||
bad group names | ||||
$ hg log -R a -r2 -T '{search(r"(?P<0>.)", desc) % "{0}"}\n' | ||||
hg: parse error: search got an invalid pattern: (?P<0>.) | ||||
[255] | ||||
$ hg log -R a -r2 -T '{search(r"(?P<repo>.)", desc) % "{repo}"}\n' | ||||
hg: parse error: invalid group 'repo' in search pattern: (?P<repo>.) | ||||
[255] | ||||
|
r38453 | Test the sub function of templating for expansion: | ||
$ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n' | ||||
xx | ||||
$ hg log -R latesttag -r 10 -T '{sub("[", "x", rev)}\n' | ||||
hg: parse error: sub got an invalid pattern: [ | ||||
[255] | ||||
$ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n' | ||||
hg: parse error: sub got an invalid replacement: \1 | ||||
[255] | ||||
Test the strip function with chars specified: | ||||
$ hg log -R latesttag --template '{desc}\n' | ||||
at3 | ||||
t5 | ||||
t4 | ||||
t3 | ||||
t2 | ||||
t1 | ||||
merge | ||||
h2e | ||||
h2d | ||||
h1c | ||||
b | ||||
a | ||||
$ hg log -R latesttag --template '{strip(desc, "te")}\n' | ||||
at3 | ||||
5 | ||||
4 | ||||
3 | ||||
2 | ||||
1 | ||||
merg | ||||
h2 | ||||
h2d | ||||
h1c | ||||
b | ||||
a | ||||
Test date format: | ||||
$ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n' | ||||
date: 70 01 01 10 +0000 | ||||
date: 70 01 01 09 +0000 | ||||
date: 70 01 01 04 +0000 | ||||
date: 70 01 01 08 +0000 | ||||
date: 70 01 01 07 +0000 | ||||
date: 70 01 01 06 +0000 | ||||
date: 70 01 01 05 +0100 | ||||
date: 70 01 01 04 +0000 | ||||
date: 70 01 01 03 +0000 | ||||
date: 70 01 01 02 +0000 | ||||
date: 70 01 01 01 +0000 | ||||
date: 70 01 01 00 +0000 | ||||
Test invalid date: | ||||
$ hg log -R latesttag -T '{date(rev)}\n' | ||||
hg: parse error: date expects a date information | ||||
[255] | ||||
Set up repository containing template fragments in commit metadata: | ||||
$ hg init r | ||||
$ cd r | ||||
$ echo a > a | ||||
$ hg ci -Am '{rev}' | ||||
adding a | ||||
$ hg branch -q 'text.{rev}' | ||||
$ echo aa >> aa | ||||
$ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped' | ||||
color effect can be specified without quoting: | ||||
$ hg log --color=always -l 1 --template '{label(red, "text\n")}' | ||||
\x1b[0;31mtext\x1b[0m (esc) | ||||
color effects can be nested (issue5413) | ||||
$ hg debugtemplate --color=always \ | ||||
> '{label(red, "red{label(magenta, "ma{label(cyan, "cyan")}{label(yellow, "yellow")}genta")}")}\n' | ||||
\x1b[0;31mred\x1b[0;35mma\x1b[0;36mcyan\x1b[0m\x1b[0;31m\x1b[0;35m\x1b[0;33myellow\x1b[0m\x1b[0;31m\x1b[0;35mgenta\x1b[0m (esc) | ||||
pad() should interact well with color codes (issue5416) | ||||
$ hg debugtemplate --color=always \ | ||||
> '{pad(label(red, "red"), 5, label(cyan, "-"))}\n' | ||||
\x1b[0;31mred\x1b[0m\x1b[0;36m-\x1b[0m\x1b[0;36m-\x1b[0m (esc) | ||||
|
r40225 | pad() with truncate has to strip color codes, though | ||
$ hg debugtemplate --color=always \ | ||||
> '{pad(label(red, "scarlet"), 5, truncate=true)}\n' | ||||
scarl | ||||
|
r38453 | label should be no-op if color is disabled: | ||
$ hg log --color=never -l 1 --template '{label(red, "text\n")}' | ||||
text | ||||
$ hg log --config extensions.color=! -l 1 --template '{label(red, "text\n")}' | ||||
text | ||||
Test branches inside if statement: | ||||
$ hg log -r 0 --template '{if(branches, "yes", "no")}\n' | ||||
no | ||||
Test dict constructor: | ||||
$ hg log -r 0 -T '{dict(y=node|short, x=rev)}\n' | ||||
y=f7769ec2ab97 x=0 | ||||
$ hg log -r 0 -T '{dict(x=rev, y=node|short) % "{key}={value}\n"}' | ||||
x=0 | ||||
y=f7769ec2ab97 | ||||
$ hg log -r 0 -T '{dict(x=rev, y=node|short)|json}\n' | ||||
{"x": 0, "y": "f7769ec2ab97"} | ||||
$ hg log -r 0 -T '{dict()|json}\n' | ||||
{} | ||||
$ hg log -r 0 -T '{dict(rev, node=node|short)}\n' | ||||
rev=0 node=f7769ec2ab97 | ||||
$ hg log -r 0 -T '{dict(rev, node|short)}\n' | ||||
rev=0 node=f7769ec2ab97 | ||||
$ hg log -r 0 -T '{dict(rev, rev=rev)}\n' | ||||
hg: parse error: duplicated dict key 'rev' inferred | ||||
[255] | ||||
$ hg log -r 0 -T '{dict(node, node|short)}\n' | ||||
hg: parse error: duplicated dict key 'node' inferred | ||||
[255] | ||||
$ hg log -r 0 -T '{dict(1 + 2)}' | ||||
hg: parse error: dict key cannot be inferred | ||||
[255] | ||||
$ hg log -r 0 -T '{dict(x=rev, x=node)}' | ||||
hg: parse error: dict got multiple values for keyword argument 'x' | ||||
[255] | ||||
Test get function: | ||||
$ hg log -r 0 --template '{get(extras, "branch")}\n' | ||||
default | ||||
$ hg log -r 0 --template '{get(extras, "br{"anch"}")}\n' | ||||
default | ||||
$ hg log -r 0 --template '{get(files, "should_fail")}\n' | ||||
hg: parse error: not a dictionary | ||||
(get() expects a dict as first argument) | ||||
[255] | ||||
Test json filter applied to wrapped object: | ||||
$ hg log -r0 -T '{files|json}\n' | ||||
["a"] | ||||
$ hg log -r0 -T '{extras|json}\n' | ||||
{"branch": "default"} | ||||
$ hg log -r0 -T '{date|json}\n' | ||||
[0, 0] | ||||
|
r45080 | $ hg log -r0 -T '{revset(":")|json}\n' | ||
[0, 1] | ||||
|
r38453 | |||
Test json filter applied to map result: | ||||
$ hg log -r0 -T '{json(extras % "{key}")}\n' | ||||
["branch"] | ||||
Test localdate(date, tz) function: | ||||
$ TZ=JST-09 hg log -r0 -T '{date|localdate|isodate}\n' | ||||
1970-01-01 09:00 +0900 | ||||
$ TZ=JST-09 hg log -r0 -T '{localdate(date, "UTC")|isodate}\n' | ||||
1970-01-01 00:00 +0000 | ||||
$ TZ=JST-09 hg log -r0 -T '{localdate(date, "blahUTC")|isodate}\n' | ||||
hg: parse error: localdate expects a timezone | ||||
[255] | ||||
$ TZ=JST-09 hg log -r0 -T '{localdate(date, "+0200")|isodate}\n' | ||||
1970-01-01 02:00 +0200 | ||||
$ TZ=JST-09 hg log -r0 -T '{localdate(date, "0")|isodate}\n' | ||||
1970-01-01 00:00 +0000 | ||||
$ TZ=JST-09 hg log -r0 -T '{localdate(date, 0)|isodate}\n' | ||||
1970-01-01 00:00 +0000 | ||||
$ hg log -r0 -T '{localdate(date, "invalid")|isodate}\n' | ||||
hg: parse error: localdate expects a timezone | ||||
[255] | ||||
$ hg log -r0 -T '{localdate(date, date)|isodate}\n' | ||||
hg: parse error: localdate expects a timezone | ||||
[255] | ||||
Test shortest(node) function: | ||||
$ echo b > b | ||||
$ hg ci -qAm b | ||||
$ hg log --template '{shortest(node)}\n' | ||||
e777 | ||||
bcc7 | ||||
f776 | ||||
$ hg log --template '{shortest(node, 10)}\n' | ||||
e777603221 | ||||
bcc7ff960b | ||||
f7769ec2ab | ||||
|
r40377 | $ hg log --template '{shortest(node, 1)}\n' -r null | ||
00 | ||||
|
r38453 | $ hg log --template '{node|shortest}\n' -l1 | ||
e777 | ||||
$ hg log -r 0 -T '{shortest(node, "1{"0"}")}\n' | ||||
f7769ec2ab | ||||
$ hg log -r 0 -T '{shortest(node, "not an int")}\n' | ||||
hg: parse error: shortest() expects an integer minlength | ||||
[255] | ||||
$ hg log -r 'wdir()' -T '{node|shortest}\n' | ||||
ffff | ||||
$ hg log --template '{shortest("f")}\n' -l1 | ||||
f | ||||
$ hg log --template '{shortest("0123456789012345678901234567890123456789")}\n' -l1 | ||||
0123456789012345678901234567890123456789 | ||||
$ hg log --template '{shortest("01234567890123456789012345678901234567890123456789")}\n' -l1 | ||||
01234567890123456789012345678901234567890123456789 | ||||
$ hg log --template '{shortest("not a hex string")}\n' -l1 | ||||
not a hex string | ||||
$ hg log --template '{shortest("not a hex string, but it'\''s 40 bytes long")}\n' -l1 | ||||
not a hex string, but it's 40 bytes long | ||||
$ hg log --template '{shortest("ffffffffffffffffffffffffffffffffffffffff")}\n' -l1 | ||||
ffff | ||||
$ hg log --template '{shortest("fffffff")}\n' -l1 | ||||
ffff | ||||
$ hg log --template '{shortest("ff")}\n' -l1 | ||||
ffff | ||||
$ cd .. | ||||
Test shortest(node) with the repo having short hash collision: | ||||
$ hg init hashcollision | ||||
$ cd hashcollision | ||||
$ cat <<EOF >> .hg/hgrc | ||||
> [experimental] | ||||
> evolution.createmarkers=True | ||||
> EOF | ||||
$ echo 0 > a | ||||
$ hg ci -qAm 0 | ||||
$ for i in 17 129 248 242 480 580 617 1057 2857 4025; do | ||||
> hg up -q 0 | ||||
> echo $i > a | ||||
> hg ci -qm $i | ||||
> done | ||||
$ hg up -q null | ||||
$ hg log -r0: -T '{rev}:{node}\n' | ||||
0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a | ||||
1:11424df6dc1dd4ea255eae2b58eaca7831973bbc | ||||
2:11407b3f1b9c3e76a79c1ec5373924df096f0499 | ||||
3:11dd92fe0f39dfdaacdaa5f3997edc533875cfc4 | ||||
4:10776689e627b465361ad5c296a20a487e153ca4 | ||||
5:a00be79088084cb3aff086ab799f8790e01a976b | ||||
6:a0b0acd79b4498d0052993d35a6a748dd51d13e6 | ||||
7:a0457b3450b8e1b778f1163b31a435802987fe5d | ||||
8:c56256a09cd28e5764f32e8e2810d0f01e2e357a | ||||
9:c5623987d205cd6d9d8389bfc40fff9dbb670b48 | ||||
10:c562ddd9c94164376c20b86b0b4991636a3bf84f | ||||
$ hg debugobsolete a00be79088084cb3aff086ab799f8790e01a976b | ||||
r43163 | 1 new obsolescence markers | |||
|
r38453 | obsoleted 1 changesets | ||
$ hg debugobsolete c5623987d205cd6d9d8389bfc40fff9dbb670b48 | ||||
r43163 | 1 new obsolescence markers | |||
|
r38453 | obsoleted 1 changesets | ||
$ hg debugobsolete c562ddd9c94164376c20b86b0b4991636a3bf84f | ||||
r43163 | 1 new obsolescence markers | |||
|
r38453 | obsoleted 1 changesets | ||
nodes starting with '11' (we don't have the revision number '11' though) | ||||
$ hg log -r 1:3 -T '{rev}:{shortest(node, 0)}\n' | ||||
1:1142 | ||||
2:1140 | ||||
3:11d | ||||
'5:a00' is hidden, but still we have two nodes starting with 'a0' | ||||
$ hg log -r 6:7 -T '{rev}:{shortest(node, 0)}\n' | ||||
6:a0b | ||||
7:a04 | ||||
node '10' conflicts with the revision number '10' even if it is hidden | ||||
(we could exclude hidden revision numbers, but currently we don't) | ||||
$ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n' | ||||
4:107 | ||||
$ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n' --hidden | ||||
4:107 | ||||
|
r38892 | $ hg --config experimental.revisions.prefixhexnode=yes log -r 4 -T '{rev}:{shortest(node, 0)}\n' | ||
4:x10 | ||||
$ hg --config experimental.revisions.prefixhexnode=yes log -r 4 -T '{rev}:{shortest(node, 0)}\n' --hidden | ||||
4:x10 | ||||
|
r38453 | node 'c562' should be unique if the other 'c562' nodes are hidden | ||
(but we don't try the slow path to filter out hidden nodes for now) | ||||
$ hg log -r 8 -T '{rev}:{node|shortest}\n' | ||||
8:c5625 | ||||
$ hg log -r 8:10 -T '{rev}:{node|shortest}\n' --hidden | ||||
8:c5625 | ||||
9:c5623 | ||||
10:c562d | ||||
$ cd .. | ||||
|
r40377 | Test prefixhexnode when the first character of the hash is 0. | ||
$ hg init hashcollision2 | ||||
$ cd hashcollision2 | ||||
$ cat <<EOF >> .hg/hgrc | ||||
> [experimental] | ||||
> evolution.createmarkers=True | ||||
> EOF | ||||
$ echo 0 > a | ||||
$ hg ci -qAm 0 | ||||
$ echo 21 > a | ||||
$ hg ci -qm 21 | ||||
$ hg up -q null | ||||
$ hg log -r0: -T '{rev}:{node}\n' | ||||
0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a | ||||
1:0cf177ba2b1dc3862a00fb81715fec90950201be | ||||
we need the 'x' prefix to ensure we aren't colliding with rev0. We identify | ||||
the collision with nullid if we aren't using disambiguatewithin, so we need to set | ||||
that as well. | ||||
$ hg --config experimental.revisions.disambiguatewithin='descendants(0)' \ | ||||
> --config experimental.revisions.prefixhexnode=yes \ | ||||
> log -r 1 -T '{rev}:{shortest(node, 0)}\n' | ||||
1:x0 | ||||
$ hg debugobsolete 0cf177ba2b1dc3862a00fb81715fec90950201be | ||||
r43163 | 1 new obsolescence markers | |||
|
r40377 | obsoleted 1 changesets | ||
$ hg up -q 0 | ||||
$ echo 61 > a | ||||
$ hg ci -m 61 | ||||
$ hg log -r0: -T '{rev}:{node}\n' | ||||
0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a | ||||
2:01384dde84b3a511ae0835f35ac40bd806c99bb8 | ||||
we still have the 'x' prefix because '0' is still the shortest prefix, since | ||||
rev1's '0c' is hidden. | ||||
$ hg --config experimental.revisions.disambiguatewithin=0:-1-0 \ | ||||
> --config experimental.revisions.prefixhexnode=yes \ | ||||
> log -r 0:-1-0 -T '{rev}:{shortest(node, 0)}\n' | ||||
2:x0 | ||||
we don't have the 'x' prefix on 2 because '01' is not a synonym for rev1. | ||||
$ hg --config experimental.revisions.disambiguatewithin=0:-1-0 \ | ||||
> --config experimental.revisions.prefixhexnode=yes \ | ||||
> log -r 0:-1-0 -T '{rev}:{shortest(node, 0)}\n' --hidden | ||||
1:0c | ||||
2:01 | ||||
$ cd .. | ||||
|
r38453 | Test pad function | ||
$ cd r | ||||
$ hg log --template '{pad(rev, 20)} {author|user}\n' | ||||
2 test | ||||
1 {node|short} | ||||
0 test | ||||
$ hg log --template '{pad(rev, 20, " ", True)} {author|user}\n' | ||||
2 test | ||||
1 {node|short} | ||||
0 test | ||||
$ hg log --template '{pad(rev, 20, "-", False)} {author|user}\n' | ||||
2------------------- test | ||||
1------------------- {node|short} | ||||
0------------------- test | ||||
|
r40225 | $ hg log --template '{pad(author, 5, "-", False, True)}\n' | ||
test- | ||||
{node | ||||
test- | ||||
$ hg log --template '{pad(author, 5, "-", True, True)}\n' | ||||
-test | ||||
hort} | ||||
-test | ||||
|
r38453 | Test template string in pad function | ||
$ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n' | ||||
{0} test | ||||
$ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n' | ||||
\{rev} test | ||||
Test width argument passed to pad function | ||||
$ hg log -r 0 -T '{pad(rev, "1{"0"}")} {author|user}\n' | ||||
0 test | ||||
$ hg log -r 0 -T '{pad(rev, "not an int")}\n' | ||||
hg: parse error: pad() expects an integer width | ||||
[255] | ||||
Test invalid fillchar passed to pad function | ||||
$ hg log -r 0 -T '{pad(rev, 10, "")}\n' | ||||
hg: parse error: pad() expects a single fill character | ||||
[255] | ||||
$ hg log -r 0 -T '{pad(rev, 10, "--")}\n' | ||||
hg: parse error: pad() expects a single fill character | ||||
[255] | ||||
Test boolean argument passed to pad function | ||||
no crash | ||||
$ hg log -r 0 -T '{pad(rev, 10, "-", "f{"oo"}")}\n' | ||||
---------0 | ||||
string/literal | ||||
$ hg log -r 0 -T '{pad(rev, 10, "-", "false")}\n' | ||||
---------0 | ||||
$ hg log -r 0 -T '{pad(rev, 10, "-", false)}\n' | ||||
0--------- | ||||
$ hg log -r 0 -T '{pad(rev, 10, "-", "")}\n' | ||||
0--------- | ||||
unknown keyword is evaluated to '' | ||||
$ hg log -r 0 -T '{pad(rev, 10, "-", unknownkeyword)}\n' | ||||
0--------- | ||||
Test separate function | ||||
$ hg log -r 0 -T '{separate("-", "", "a", "b", "", "", "c", "")}\n' | ||||
a-b-c | ||||
$ hg log -r 0 -T '{separate(" ", "{rev}:{node|short}", author|user, branch)}\n' | ||||
0:f7769ec2ab97 test default | ||||
$ hg log -r 0 --color=always -T '{separate(" ", "a", label(red, "b"), "c", label(red, ""), "d")}\n' | ||||
a \x1b[0;31mb\x1b[0m c d (esc) | ||||
Test boolean expression/literal passed to if function | ||||
$ hg log -r 0 -T '{if(rev, "rev 0 is True")}\n' | ||||
rev 0 is True | ||||
$ hg log -r 0 -T '{if(0, "literal 0 is True as well")}\n' | ||||
literal 0 is True as well | ||||
|
r38466 | $ hg log -r 0 -T '{if(min(revset(r"0")), "0 of hybriditem is also True")}\n' | ||
0 of hybriditem is also True | ||||
|
r38453 | $ hg log -r 0 -T '{if("", "", "empty string is False")}\n' | ||
empty string is False | ||||
$ hg log -r 0 -T '{if(revset(r"0 - 0"), "", "empty list is False")}\n' | ||||
empty list is False | ||||
$ hg log -r 0 -T '{if(revset(r"0"), "non-empty list is True")}\n' | ||||
non-empty list is True | ||||
$ hg log -r 0 -T '{if(revset(r"0") % "", "list of empty strings is True")}\n' | ||||
list of empty strings is True | ||||
$ hg log -r 0 -T '{if(true, "true is True")}\n' | ||||
true is True | ||||
$ hg log -r 0 -T '{if(false, "", "false is False")}\n' | ||||
false is False | ||||
$ hg log -r 0 -T '{if("false", "non-empty string is True")}\n' | ||||
non-empty string is True | ||||
Test ifcontains function | ||||
$ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n' | ||||
2 is in the string | ||||
1 is not | ||||
0 is in the string | ||||
$ hg log -T '{rev} {ifcontains(rev, "2 two{" 0"}", "is in the string", "is not")}\n' | ||||
2 is in the string | ||||
1 is not | ||||
0 is in the string | ||||
$ hg log --template '{rev} {ifcontains("a", file_adds, "added a", "did not add a")}\n' | ||||
2 did not add a | ||||
1 did not add a | ||||
0 added a | ||||
$ hg log --debug -T '{rev}{ifcontains(1, parents, " is parent of 1")}\n' | ||||
2 is parent of 1 | ||||
1 | ||||
0 | ||||
$ hg log -l1 -T '{ifcontains("branch", extras, "t", "f")}\n' | ||||
t | ||||
$ hg log -l1 -T '{ifcontains("branch", extras % "{key}", "t", "f")}\n' | ||||
t | ||||
$ hg log -l1 -T '{ifcontains("branc", extras % "{key}", "t", "f")}\n' | ||||
f | ||||
$ hg log -l1 -T '{ifcontains("branc", stringify(extras % "{key}"), "t", "f")}\n' | ||||
t | ||||
Test revset function | ||||
$ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n' | ||||
2 current rev | ||||
1 not current rev | ||||
0 not current rev | ||||
$ hg log --template '{rev} {ifcontains(rev, revset(". + .^"), "match rev", "not match rev")}\n' | ||||
2 match rev | ||||
1 match rev | ||||
0 not match rev | ||||
$ hg log -T '{ifcontains(desc, revset(":"), "", "type not match")}\n' -l1 | ||||
type not match | ||||
$ hg log --template '{rev} Parents: {revset("parents(%s)", rev)}\n' | ||||
2 Parents: 1 | ||||
1 Parents: 0 | ||||
0 Parents: | ||||
$ cat >> .hg/hgrc <<EOF | ||||
> [revsetalias] | ||||
> myparents(\$1) = parents(\$1) | ||||
> EOF | ||||
$ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n' | ||||
2 Parents: 1 | ||||
1 Parents: 0 | ||||
0 Parents: | ||||
$ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n' | ||||
Rev: 2 | ||||
Ancestor: 0 | ||||
Ancestor: 1 | ||||
Ancestor: 2 | ||||
Rev: 1 | ||||
Ancestor: 0 | ||||
Ancestor: 1 | ||||
Rev: 0 | ||||
Ancestor: 0 | ||||
$ hg log --template '{revset("TIP"|lower)}\n' -l1 | ||||
2 | ||||
$ hg log -T '{revset("%s", "t{"ip"}")}\n' -l1 | ||||
2 | ||||
a list template is evaluated for each item of revset/parents | ||||
$ hg log -T '{rev} p: {revset("p1(%s)", rev) % "{rev}:{node|short}"}\n' | ||||
2 p: 1:bcc7ff960b8e | ||||
1 p: 0:f7769ec2ab97 | ||||
0 p: | ||||
$ hg log --debug -T '{rev} p:{parents % " {rev}:{node|short}"}\n' | ||||
2 p: 1:bcc7ff960b8e -1:000000000000 | ||||
1 p: 0:f7769ec2ab97 -1:000000000000 | ||||
0 p: -1:000000000000 -1:000000000000 | ||||
therefore, 'revcache' should be recreated for each rev | ||||
$ hg log -T '{rev} {file_adds}\np {revset("p1(%s)", rev) % "{file_adds}"}\n' | ||||
2 aa b | ||||
p | ||||
1 | ||||
p a | ||||
0 a | ||||
p | ||||
$ hg log --debug -T '{rev} {file_adds}\np {parents % "{file_adds}"}\n' | ||||
2 aa b | ||||
p | ||||
1 | ||||
p a | ||||
0 a | ||||
p | ||||
a revset item must be evaluated as an integer revision, not an offset from tip | ||||
$ hg log -l 1 -T '{revset("null") % "{rev}:{node|short}"}\n' | ||||
-1:000000000000 | ||||
$ hg log -l 1 -T '{revset("%s", "null") % "{rev}:{node|short}"}\n' | ||||
-1:000000000000 | ||||
join() should pick '{rev}' from revset items: | ||||
$ hg log -R ../a -T '{join(revset("parents(%d)", rev), ", ")}\n' -r6 | ||||
4, 5 | ||||
on the other hand, parents are formatted as '{rev}:{node|formatnode}' by | ||||
default. join() should agree with the default formatting: | ||||
$ hg log -R ../a -T '{join(parents, ", ")}\n' -r6 | ||||
5:13207e5a10d9, 4:bbe44766e73d | ||||
$ hg log -R ../a -T '{join(parents, ",\n")}\n' -r6 --debug | ||||
5:13207e5a10d9fd28ec424934298e176197f2c67f, | ||||
4:bbe44766e73d5f11ed2177f1838de10c53ef3e74 | ||||
|
r45080 | for historical reasons, revset() supports old-style list template | ||
$ hg log -T '{revset(":")}\n' -l1 \ | ||||
> --config templates.start_revisions='"["' \ | ||||
> --config templates.end_revisions='"]"' \ | ||||
> --config templates.revision='"{revision}, "' \ | ||||
> --config templates.last_revision='"{revision}"' | ||||
[0, 1, 2] | ||||
$ hg log -T '{revset(":") % " {revision}"}\n' -l1 | ||||
0 1 2 | ||||
but a filtered one doesn't | ||||
$ hg log -T '{filter(revset(":"), ifeq(rev, 1, "", "y"))}\n' -l1 \ | ||||
> --config templates.start_revisions='"["' \ | ||||
> --config templates.end_revisions='"]"' \ | ||||
> --config templates.revision='"{revision}, "' \ | ||||
> --config templates.last_revision='"{revision}"' | ||||
0 2 | ||||
$ hg log -T '{filter(revset(":"), ifeq(rev, 1, "", "y")) % "x{revision}"}\n' -l1 | ||||
xx | ||||
|
r45073 | %d parameter handling: | ||
$ hg log -T '{revset("%d", rev)}\n' -r'wdir()' | ||||
2147483647 | ||||
$ hg log -T '{revset("%d", rev)}\n' -r'null' | ||||
-1 | ||||
|
r45074 | $ hg log -T '{revset("%d", rev + 1)}\n' -r'tip' | ||
abort: unknown revision '3'! | ||||
[255] | ||||
$ hg log -T '{revset("%d", rev - 1)}\n' -r'null' | ||||
abort: unknown revision '-2'! | ||||
[255] | ||||
|
r45073 | |||
|
r38453 | Invalid arguments passed to revset() | ||
$ hg log -T '{revset("%whatever", 0)}\n' | ||||
hg: parse error: unexpected revspec format character w | ||||
[255] | ||||
$ hg log -T '{revset("%lwhatever", files)}\n' | ||||
hg: parse error: unexpected revspec format character w | ||||
[255] | ||||
$ hg log -T '{revset("%s %s", 0)}\n' | ||||
hg: parse error: missing argument for revspec | ||||
[255] | ||||
$ hg log -T '{revset("", 0)}\n' | ||||
hg: parse error: too many revspec arguments specified | ||||
[255] | ||||
$ hg log -T '{revset("%s", 0, 1)}\n' | ||||
hg: parse error: too many revspec arguments specified | ||||
[255] | ||||
$ hg log -T '{revset("%", 0)}\n' | ||||
hg: parse error: incomplete revspec format character | ||||
[255] | ||||
$ hg log -T '{revset("%l", 0)}\n' | ||||
hg: parse error: incomplete revspec format character | ||||
[255] | ||||
$ hg log -T '{revset("%d", 'foo')}\n' | ||||
hg: parse error: invalid argument for revspec | ||||
[255] | ||||
$ hg log -T '{revset("%ld", files)}\n' | ||||
hg: parse error: invalid argument for revspec | ||||
[255] | ||||
$ hg log -T '{revset("%ls", 0)}\n' | ||||
hg: parse error: invalid argument for revspec | ||||
[255] | ||||
$ hg log -T '{revset("%b", 'foo')}\n' | ||||
hg: parse error: invalid argument for revspec | ||||
[255] | ||||
$ hg log -T '{revset("%lb", files)}\n' | ||||
hg: parse error: invalid argument for revspec | ||||
[255] | ||||
$ hg log -T '{revset("%r", 0)}\n' | ||||
hg: parse error: invalid argument for revspec | ||||
[255] | ||||
|
r45080 | Invalid operation on revset() | ||
$ hg log -T '{get(revset(":"), "foo")}\n' | ||||
hg: parse error: not a dictionary | ||||
(get() expects a dict as first argument) | ||||
[255] | ||||
|
r38453 | Test files function | ||
$ hg log -T "{rev}\n{join(files('*'), '\n')}\n" | ||||
2 | ||||
a | ||||
aa | ||||
b | ||||
1 | ||||
a | ||||
0 | ||||
a | ||||
$ hg log -T "{rev}\n{join(files('aa'), '\n')}\n" | ||||
2 | ||||
aa | ||||
1 | ||||
0 | ||||
|
r39403 | |||
$ hg log -l1 -T "{files('aa') % '{file}\n'}" | ||||
aa | ||||
$ hg log -l1 -T "{files('aa') % '{path}\n'}" | ||||
aa | ||||
|
r38453 | $ hg rm a | ||
$ hg log -r "wdir()" -T "{rev}\n{join(files('*'), '\n')}\n" | ||||
2147483647 | ||||
aa | ||||
b | ||||
$ hg revert a | ||||
Test relpath function | ||||
$ hg log -r0 -T '{files % "{file|relpath}\n"}' | ||||
a | ||||
$ cd .. | ||||
$ hg log -R r -r0 -T '{files % "{file|relpath}\n"}' | ||||
r/a | ||||
Test stringify on sub expressions | ||||
$ hg log -R a -r 8 --template '{join(files, if("1", if("1", ", ")))}\n' | ||||
fourth, second, third | ||||
$ hg log -R a -r 8 --template '{strip(if("1", if("1", "-abc-")), if("1", if("1", "-")))}\n' | ||||
abc | ||||
Test splitlines | ||||
$ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}" | ||||
@ foo Modify, add, remove, rename | ||||
| | ||||
o foo future | ||||
| | ||||
o foo third | ||||
| | ||||
o foo second | ||||
o foo merge | ||||
|\ | ||||
| o foo new head | ||||
| | | ||||
o | foo new branch | ||||
|/ | ||||
o foo no user, no domain | ||||
| | ||||
o foo no person | ||||
| | ||||
o foo other 1 | ||||
| foo other 2 | ||||
| foo | ||||
| foo other 3 | ||||
o foo line 1 | ||||
foo line 2 | ||||
$ hg log -R a -r0 -T '{desc|splitlines}\n' | ||||
line 1 line 2 | ||||
$ hg log -R a -r0 -T '{join(desc|splitlines, "|")}\n' | ||||
line 1|line 2 | ||||
Test startswith | ||||
$ hg log -Gv -R a --template "{startswith(desc)}" | ||||
hg: parse error: startswith expects two arguments | ||||
[255] | ||||
$ hg log -Gv -R a --template "{startswith('line', desc)}" | ||||
@ | ||||
| | ||||
o | ||||
| | ||||
o | ||||
| | ||||
o | ||||
o | ||||
|\ | ||||
| o | ||||
| | | ||||
o | | ||||
|/ | ||||
o | ||||
| | ||||
o | ||||
| | ||||
o | ||||
| | ||||
o line 1 | ||||
line 2 | ||||
Test word function (including index out of bounds graceful failure) | ||||
$ hg log -Gv -R a --template "{word('1', desc)}" | ||||
@ add, | ||||
| | ||||
o | ||||
| | ||||
o | ||||
| | ||||
o | ||||
o | ||||
|\ | ||||
| o head | ||||
| | | ||||
o | branch | ||||
|/ | ||||
o user, | ||||
| | ||||
o person | ||||
| | ||||
o 1 | ||||
| | ||||
o 1 | ||||
Test word third parameter used as splitter | ||||
$ hg log -Gv -R a --template "{word('0', desc, 'o')}" | ||||
@ M | ||||
| | ||||
o future | ||||
| | ||||
o third | ||||
| | ||||
o sec | ||||
o merge | ||||
|\ | ||||
| o new head | ||||
| | | ||||
o | new branch | ||||
|/ | ||||
o n | ||||
| | ||||
o n | ||||
| | ||||
o | ||||
| | ||||
o line 1 | ||||
line 2 | ||||
Test word error messages for not enough and too many arguments | ||||
$ hg log -Gv -R a --template "{word('0')}" | ||||
hg: parse error: word expects two or three arguments, got 1 | ||||
[255] | ||||
$ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}" | ||||
hg: parse error: word expects two or three arguments, got 7 | ||||
[255] | ||||
Test word for integer literal | ||||
$ hg log -R a --template "{word(2, desc)}\n" -r0 | ||||
line | ||||
Test word for invalid numbers | ||||
$ hg log -Gv -R a --template "{word('a', desc)}" | ||||
hg: parse error: word expects an integer index | ||||
[255] | ||||
Test word for out of range | ||||
$ hg log -R a --template "{word(10000, desc)}" | ||||
$ hg log -R a --template "{word(-10000, desc)}" | ||||
Test indent and not adding to empty lines | ||||
$ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a | ||||
----- | ||||
> line 1 | ||||
>> line 2 | ||||
----- | ||||
> other 1 | ||||
>> other 2 | ||||
>> other 3 | ||||
|
r44092 | Test indent with empty first line | ||
$ hg version -T "{indent('', '>> ')}\n" | ||||
|
r44093 | |||
|
r44092 | |||
$ hg version -T "{indent(' | ||||
> second', '>> ')}\n" | ||||
|
r44093 | |||
|
r44092 | >> second | ||
$ hg version -T "{indent(' | ||||
> second', '>> ', ' > ')}\n" | ||||
|
r44093 | |||
|
r44092 | >> second | ||
|
r38453 | Test with non-strings like dates | ||
$ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a | ||||
1200000.00 | ||||
1300000.00 | ||||
|
r42164 | Test cbor filter: | ||
$ cat <<'EOF' > "$TESTTMP/decodecbor.py" | ||||
> from __future__ import absolute_import | ||||
|
r42167 | > from mercurial import ( | ||
> dispatch, | ||||
> pycompat, | ||||
> ) | ||||
|
r42164 | > from mercurial.utils import ( | ||
> cborutil, | ||||
> stringutil, | ||||
> ) | ||||
|
r42167 | > dispatch.initstdio() | ||
|
r42164 | > items = cborutil.decodeall(pycompat.stdin.read()) | ||
> pycompat.stdout.write(stringutil.pprint(items, indent=1) + b'\n') | ||||
> EOF | ||||
$ hg log -T "{rev|cbor}" -R a -l2 | "$PYTHON" "$TESTTMP/decodecbor.py" | ||||
[ | ||||
10, | ||||
9 | ||||
] | ||||
$ hg log -T "{extras|cbor}" -R a -l1 | "$PYTHON" "$TESTTMP/decodecbor.py" | ||||
[ | ||||
{ | ||||
'branch': 'default' | ||||
} | ||||
] | ||||
|
r45080 | $ hg log -T "{revset(':')|cbor}" -R a -l1 | "$PYTHON" "$TESTTMP/decodecbor.py" | ||
[ | ||||
[ | ||||
0, | ||||
1, | ||||
2, | ||||
3, | ||||
4, | ||||
5, | ||||
6, | ||||
7, | ||||
8, | ||||
9, | ||||
10 | ||||
] | ||||
] | ||||
|
r45087 | $ hg log -T "{dict(foo=revset('.'))|cbor}" -R a -l1 | "$PYTHON" "$TESTTMP/decodecbor.py" | ||
[ | ||||
{ | ||||
'foo': [ | ||||
10 | ||||
] | ||||
} | ||||
] | ||||
|
r38453 | json filter should escape HTML tags so that the output can be embedded in hgweb: | ||
$ hg log -T "{'<foo@example.org>'|json}\n" -R a -l1 | ||||
"\u003cfoo@example.org\u003e" | ||||
Set up repository for non-ascii encoding tests: | ||||
$ hg init nonascii | ||||
$ cd nonascii | ||||
|
r39743 | $ "$PYTHON" <<EOF | ||
|
r38453 | > open('latin1', 'wb').write(b'\xe9') | ||
> open('utf-8', 'wb').write(b'\xc3\xa9') | ||||
> EOF | ||||
$ HGENCODING=utf-8 hg branch -q `cat utf-8` | ||||
$ HGENCODING=utf-8 hg ci -qAm "non-ascii branch: `cat utf-8`" utf-8 | ||||
json filter should try round-trip conversion to utf-8: | ||||
$ HGENCODING=ascii hg log -T "{branch|json}\n" -r0 | ||||
"\u00e9" | ||||
$ HGENCODING=ascii hg log -T "{desc|json}\n" -r0 | ||||
"non-ascii branch: \u00e9" | ||||
json filter should take input as utf-8 if it was converted from utf-8: | ||||
$ HGENCODING=latin-1 hg log -T "{branch|json}\n" -r0 | ||||
"\u00e9" | ||||
$ HGENCODING=latin-1 hg log -T "{desc|json}\n" -r0 | ||||
"non-ascii branch: \u00e9" | ||||
json filter takes input as utf-8b: | ||||
$ HGENCODING=ascii hg log -T "{'`cat utf-8`'|json}\n" -l1 | ||||
"\u00e9" | ||||
$ HGENCODING=ascii hg log -T "{'`cat latin1`'|json}\n" -l1 | ||||
"\udce9" | ||||
|
r42680 | cbor filter is bytes transparent, which should handle bytes subtypes | ||
as bytes: | ||||
$ HGENCODING=ascii hg log -T "{branch|cbor}" -r0 \ | ||||
> | "$PYTHON" "$TESTTMP/decodecbor.py" | ||||
[ | ||||
'?' | ||||
] | ||||
$ HGENCODING=latin-1 hg log -T "{branch|cbor}" -r0 \ | ||||
> | "$PYTHON" "$TESTTMP/decodecbor.py" | ||||
[ | ||||
'\xe9' | ||||
] | ||||
|
r38453 | utf8 filter: | ||
$ HGENCODING=ascii hg log -T "round-trip: {branch|utf8|hex}\n" -r0 | ||||
round-trip: c3a9 | ||||
$ HGENCODING=latin1 hg log -T "decoded: {'`cat latin1`'|utf8|hex}\n" -l1 | ||||
decoded: c3a9 | ||||
$ HGENCODING=ascii hg log -T "replaced: {'`cat latin1`'|utf8|hex}\n" -l1 | ||||
abort: decoding near * (glob) | ||||
[255] | ||||
$ hg log -T "coerced to string: {rev|utf8}\n" -r0 | ||||
coerced to string: 0 | ||||
pad width: | ||||
$ HGENCODING=utf-8 hg debugtemplate "{pad('`cat utf-8`', 2, '-')}\n" | ||||
\xc3\xa9- (esc) | ||||
|
r41869 | read config options: | ||
$ hg log -T "{config('templateconfig', 'knob', 'foo')}\n" | ||||
foo | ||||
$ hg log -T "{config('templateconfig', 'knob', 'foo')}\n" \ | ||||
> --config templateconfig.knob=bar | ||||
bar | ||||
$ hg log -T "{configbool('templateconfig', 'knob', True)}\n" | ||||
True | ||||
$ hg log -T "{configbool('templateconfig', 'knob', True)}\n" \ | ||||
> --config templateconfig.knob=0 | ||||
False | ||||
$ hg log -T "{configint('templateconfig', 'knob', 123)}\n" | ||||
123 | ||||
$ hg log -T "{configint('templateconfig', 'knob', 123)}\n" \ | ||||
> --config templateconfig.knob=456 | ||||
456 | ||||
$ hg log -T "{config('templateconfig', 'knob')}\n" | ||||
devel-warn: config item requires an explicit default value: 'templateconfig.knob' at: * (glob) | ||||
$ hg log -T "{configbool('ui', 'interactive')}\n" | ||||
False | ||||
$ hg log -T "{configbool('ui', 'interactive')}\n" --config ui.interactive=1 | ||||
True | ||||
$ hg log -T "{config('templateconfig', 'knob', if(true, 'foo', 'bar'))}\n" | ||||
foo | ||||
|
r38453 | $ cd .. | ||