##// END OF EJS Templates
rhg: add resolve_file_args to path_utils.rs...
rhg: add resolve_file_args to path_utils.rs Extracted logic for resolving `FILE ...` arguments from cat.rs into a new function in path_utils.rs. I plan to use this for rhg annotate. I tried to reuse hg::utils::files::canonical_path instead, but that didn't work. For example it reports a InsideDotHg error for any path containing "..".

File last commit:

r50389:c96ed402 default
r53438:f33f37ac tip default
Show More
test-template-functions.t
1736 lines | 42.1 KiB | text/troff | Tads3Lexer
/ tests / test-template-functions.t
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.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 &lt;user@hostname&gt;"/>
<changeset author="person"/>
<changeset author="person"/>
<changeset author="person"/>
<changeset author="person"/>
<changeset author="other@place"/>
<changeset author="A. N. Other &lt;other@place&gt;"/>
<changeset author="User Name &lt;user@hostname&gt;"/>
$ 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
>>> 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|
Yuya Nishihara
tests: fold test-template-filters.t into test-template-functions.t
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')
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: fold test-template-filters.t into test-template-functions.t
r38454
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
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')
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453
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
Denis Laxalde
templatefuncs: account for user's diffopts in diff() (BC)
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
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
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 ..
Yuya Nishihara
templater: introduce filter() function to remove empty items from list...
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
Yuya Nishihara
templater: extend filter() to accept template expression for emptiness test...
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
Yuya Nishihara
templater: introduce filter() function to remove empty items from list...
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'
Yuya Nishihara
templater: extend filter() to accept template expression for emptiness test...
r38468 hg: parse error: filter expects one or two arguments
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
templater: introduce filter() function to remove empty items from list...
r38467 $ hg log -R a -r 0 -T '{filter(date)}\n'
hg: parse error: date is not iterable
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
templater: introduce filter() function to remove empty items from list...
r38467 $ hg log -R a -r 0 -T '{filter(rev)}\n'
hg: parse error: 0 is not iterable
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
templater: introduce filter() function to remove empty items from list...
r38467 $ hg log -R a -r 0 -T '{filter(desc|firstline)}\n'
hg: parse error: 'line 1' is not filterable
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
templater: introduce filter() function to remove empty items from list...
r38467 $ hg log -R a -r 0 -T '{filter(manifest)}\n'
hg: parse error: '0:a0c8bcbbb45c' is not filterable
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
templater: introduce filter() function to remove empty items from list...
r38467 $ hg log -R a -r 0 -T '{filter(succsandmarkers)}\n'
hg: parse error: not filterable without template
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
templater: extend filter() to accept template expression for emptiness test...
r38468 $ hg log -R a -r 0 -T '{filter(desc|splitlines % "{line}", "")}\n'
hg: parse error: not filterable by expression
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
templater: introduce filter() function to remove empty items from list...
r38467
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
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
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453
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)
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg debugtemplate '{max(2)}'
hg: parse error: 2 is not iterable
(max first argument should be an iterable)
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453
$ hg log -R latesttag -l1 -T '{min(date)}'
hg: parse error: date is not iterable
(min first argument should be an iterable)
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg log -R latesttag -l1 -T '{max(date)}'
hg: parse error: date is not iterable
(max first argument should be an iterable)
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453
Test min/max of empty sequence:
$ hg debugtemplate '{min("")}'
hg: parse error: empty string
(min first argument should be an iterable)
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg debugtemplate '{max("")}'
hg: parse error: empty string
(max first argument should be an iterable)
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg debugtemplate '{min(dict())}'
hg: parse error: empty sequence
(min first argument should be an iterable)
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg debugtemplate '{max(dict())}'
hg: parse error: empty sequence
(max first argument should be an iterable)
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg debugtemplate '{min(dict() % "")}'
hg: parse error: empty sequence
(min first argument should be an iterable)
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg debugtemplate '{max(dict() % "")}'
hg: parse error: empty sequence
(max first argument should be an iterable)
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453
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')
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ 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), "")}'
Yuya Nishihara
templatefuncs: add regexp search() function that extracts substring...
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'
Yuya Nishihara
templatefuncs: specialize "no match" value of search() to allow % operation...
r40971
Yuya Nishihara
templatefuncs: add regexp search() function that extracts substring...
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>.)
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
templatefuncs: add regexp search() function that extracts substring...
r40970 $ hg log -R a -r2 -T '{search(r"(?P<repo>.)", desc) % "{repo}"}\n'
hg: parse error: invalid group 'repo' in search pattern: (?P<repo>.)
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
templatefuncs: add regexp search() function that extracts substring...
r40970
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
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: [
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n'
hg: parse error: sub got an invalid replacement: \1
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453
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
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453
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)
Mark Thomas
templatefuncs: add truncate parameter to pad...
r40225 pad() with truncate has to strip color codes, though
$ hg debugtemplate --color=always \
> '{pad(label(red, "scarlet"), 5, truncate=true)}\n'
scarl
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
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
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg log -r 0 -T '{dict(node, node|short)}\n'
hg: parse error: duplicated dict key 'node' inferred
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg log -r 0 -T '{dict(1 + 2)}'
hg: parse error: dict key cannot be inferred
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453
$ hg log -r 0 -T '{dict(x=rev, x=node)}'
hg: parse error: dict got multiple values for keyword argument 'x'
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453
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)
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453
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]
Yuya Nishihara
templater: introduce wrapper for smartset (API)...
r45080 $ hg log -r0 -T '{revset(":")|json}\n'
[0, 1]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
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
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ 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
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg log -r0 -T '{localdate(date, date)|isodate}\n'
hg: parse error: localdate expects a timezone
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453
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
Kyle Lippincott
revisions: when using prefixhexnode, ensure we prefix "0"...
r40377 $ hg log --template '{shortest(node, 1)}\n' -r null
00
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
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
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453
$ 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
debugobsolete: also issue the "new obsmarkers" messsage...
r43163 1 new obsolescence markers
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 obsoleted 1 changesets
$ hg debugobsolete c5623987d205cd6d9d8389bfc40fff9dbb670b48
debugobsolete: also issue the "new obsmarkers" messsage...
r43163 1 new obsolescence markers
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 obsoleted 1 changesets
$ hg debugobsolete c562ddd9c94164376c20b86b0b4991636a3bf84f
debugobsolete: also issue the "new obsmarkers" messsage...
r43163 1 new obsolescence markers
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
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
Martin von Zweigbergk
shortest: use 'x' prefix to disambiguate from revnum if configured...
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
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
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 ..
Kyle Lippincott
revisions: when using prefixhexnode, ensure we prefix "0"...
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
debugobsolete: also issue the "new obsmarkers" messsage...
r43163 1 new obsolescence markers
Kyle Lippincott
revisions: when using prefixhexnode, ensure we prefix "0"...
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 ..
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
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
Mark Thomas
templatefuncs: add truncate parameter to pad...
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
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
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
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453
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
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg log -r 0 -T '{pad(rev, 10, "--")}\n'
hg: parse error: pad() expects a single fill character
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453
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
Yuya Nishihara
templater: fix truth testing of integer 0 taken from a list/dict...
r38466 $ hg log -r 0 -T '{if(min(revset(r"0")), "0 of hybriditem is also True")}\n'
0 of hybriditem is also True
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
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
Yuya Nishihara
templater: introduce wrapper for smartset (API)...
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
Yuya Nishihara
revset: allow repo.revs('%d', wdirrev)...
r45073 %d parameter handling:
$ hg log -T '{revset("%d", rev)}\n' -r'wdir()'
2147483647
$ hg log -T '{revset("%d", rev)}\n' -r'null'
-1
Yuya Nishihara
revset: fix crash by repo.revs('%d', tip + 1)...
r45074 $ hg log -T '{revset("%d", rev + 1)}\n' -r'tip'
Martin von Zweigbergk
errors: remove trailing "!" from some error messages for consistency...
r46518 abort: unknown revision '3'
Martin von Zweigbergk
errors: use detailed exit code for RepoLookupError...
r49191 [10]
Yuya Nishihara
revset: fix crash by repo.revs('%d', tip + 1)...
r45074 $ hg log -T '{revset("%d", rev - 1)}\n' -r'null'
Martin von Zweigbergk
errors: remove trailing "!" from some error messages for consistency...
r46518 abort: unknown revision '-2'
Martin von Zweigbergk
errors: use detailed exit code for RepoLookupError...
r49191 [10]
Yuya Nishihara
revset: allow repo.revs('%d', wdirrev)...
r45073
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 Invalid arguments passed to revset()
$ hg log -T '{revset("%whatever", 0)}\n'
hg: parse error: unexpected revspec format character w
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg log -T '{revset("%lwhatever", files)}\n'
hg: parse error: unexpected revspec format character w
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg log -T '{revset("%s %s", 0)}\n'
hg: parse error: missing argument for revspec
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg log -T '{revset("", 0)}\n'
hg: parse error: too many revspec arguments specified
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg log -T '{revset("%s", 0, 1)}\n'
hg: parse error: too many revspec arguments specified
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg log -T '{revset("%", 0)}\n'
hg: parse error: incomplete revspec format character
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg log -T '{revset("%l", 0)}\n'
hg: parse error: incomplete revspec format character
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg log -T '{revset("%d", 'foo')}\n'
hg: parse error: invalid argument for revspec
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg log -T '{revset("%ld", files)}\n'
hg: parse error: invalid argument for revspec
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg log -T '{revset("%ls", 0)}\n'
hg: parse error: invalid argument for revspec
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg log -T '{revset("%b", 'foo')}\n'
hg: parse error: invalid argument for revspec
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg log -T '{revset("%lb", files)}\n'
hg: parse error: invalid argument for revspec
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ hg log -T '{revset("%r", 0)}\n'
hg: parse error: invalid argument for revspec
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453
Yuya Nishihara
templater: introduce wrapper for smartset (API)...
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)
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
templater: introduce wrapper for smartset (API)...
r45080
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
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
Yuya Nishihara
templatekw: alias {file} of files list to {path}...
r39403
$ hg log -l1 -T "{files('aa') % '{file}\n'}"
aa
$ hg log -l1 -T "{files('aa') % '{path}\n'}"
aa
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
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
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453
$ 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
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453
$ 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
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453
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
Martin von Zweigbergk
errors: use exit code 10 for parse errors...
r46507 [10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453
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
Martin von Zweigbergk
tests: document behavior of indent() with empty first line...
r44092 Test indent with empty first line
$ hg version -T "{indent('', '>> ')}\n"
Martin von Zweigbergk
templates: make {indent("", " ")} be empty...
r44093
Martin von Zweigbergk
tests: document behavior of indent() with empty first line...
r44092
$ hg version -T "{indent('
> second', '>> ')}\n"
Martin von Zweigbergk
templates: make {indent("", " ")} be empty...
r44093
Martin von Zweigbergk
tests: document behavior of indent() with empty first line...
r44092 >> second
$ hg version -T "{indent('
> second', '>> ', ' > ')}\n"
Martin von Zweigbergk
templates: make {indent("", " ")} be empty...
r44093
Martin von Zweigbergk
tests: document behavior of indent() with empty first line...
r44092 >> second
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 Test with non-strings like dates
$ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
1200000.00
1300000.00
Yuya Nishihara
templatefilters: add {x|cbor} filter for custom CBOR output
r42164 Test cbor filter:
$ cat <<'EOF' > "$TESTTMP/decodecbor.py"
Yuya Nishihara
test-template: fix stdio mode on Windows...
r42167 > from mercurial import (
> dispatch,
> )
Yuya Nishihara
templatefilters: add {x|cbor} filter for custom CBOR output
r42164 > from mercurial.utils import (
> cborutil,
Manuel Jacob
pycompat: change users of pycompat.{stdin,stdout,stderr} to use procutil.std*...
r45598 > procutil,
Yuya Nishihara
templatefilters: add {x|cbor} filter for custom CBOR output
r42164 > stringutil,
> )
Yuya Nishihara
test-template: fix stdio mode on Windows...
r42167 > dispatch.initstdio()
Manuel Jacob
pycompat: change users of pycompat.{stdin,stdout,stderr} to use procutil.std*...
r45598 > items = cborutil.decodeall(procutil.stdin.read())
> procutil.stdout.write(stringutil.pprint(items, indent=1) + b'\n')
Yuya Nishihara
templatefilters: add {x|cbor} filter for custom CBOR output
r42164 > 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'
}
]
Yuya Nishihara
templater: introduce wrapper for smartset (API)...
r45080 $ hg log -T "{revset(':')|cbor}" -R a -l1 | "$PYTHON" "$TESTTMP/decodecbor.py"
[
[
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10
]
]
Yuya Nishihara
templater: fix cbor() filter to recursively convert smartset to list...
r45087 $ hg log -T "{dict(foo=revset('.'))|cbor}" -R a -l1 | "$PYTHON" "$TESTTMP/decodecbor.py"
[
{
'foo': [
10
]
}
]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
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
Matt Harbison
tests: quote PYTHON usage...
r39743 $ "$PYTHON" <<EOF
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
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"
Yuya Nishihara
cborutil: fix streamencode() to handle subtypes...
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'
]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
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)
rdamazio@google.com
templates: adding a config() function for template customization...
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
Manuel Jacob
templates: add filter to reverse list...
r50389 reverse filter:
$ hg log -T "{'abc\ndef\nghi'|splitlines|reverse}\n"
ghi def abc
$ hg log -T "{'abc'|reverse}\n"
hg: parse error: not reversible
(incompatible use of template filter 'reverse')
[10]
$ hg log -T "{date|reverse}\n"
hg: parse error: not reversible
(template filter 'reverse' is not compatible with keyword 'date')
[10]
Yuya Nishihara
tests: extract test-template-functions.t from test-command-template.t...
r38453 $ cd ..