Commit Graph

170 Commits

Author SHA1 Message Date
Jun Wu
caf2d3031d templatekw: implement nodechanges as a template keyword
Summary: Will be used by the next change.

Reviewed By: mitrandir77

Differential Revision: D8221077

fbshipit-source-id: c9713175dfaab0b090f81d2c9d4f4d9d63a0771c
2018-06-06 15:43:25 -07:00
Jun Wu
584656dff3 codemod: join the auto-formatter party
Summary:
Turned on the auto formatter. Ran `arc lint --apply-patches --take BLACK **/*.py`.
Then run `arc lint` again so some other autofixers like spellchecker etc. looked
at the code base. Manually accept the changes whenever they make sense, or use
a workaround (ex. changing "dict()" to "dict constructor") where autofix is false
positive. Disabled linters on files that are hard (i18n/polib.py) to fix, or less
interesting to fix (hgsubversion tests), or cannot be fixed without breaking
OSS build (FBPYTHON4).

Conflicted linters (test-check-module-imports.t, part of test-check-code.t,
test-check-pyflakes.t) are removed or disabled.

Duplicated linters (test-check-pyflakes.t, test-check-pylint.t) are removed.

An issue of the auto-formatter is lines are no longer guarnateed to be <= 80
chars. But that seems less important comparing with the benefit auto-formatter
provides.

As we're here, also remove test-check-py3-compat.t, as it is currently broken
if `PYTHON3=/bin/python3` is set.

Reviewed By: wez, phillco, simpkins, pkaush, singhsrb

Differential Revision: D8173629

fbshipit-source-id: 90e248ae0c5e6eaadbe25520a6ee42d32005621b
2018-05-25 22:17:29 -07:00
Mark Thomas
903419fa25 templatekw: add filestat template keyword
Summary:
Add the filestat template keyword, which expands to a list of file status
information for each file modified in a commit.

Reviewed By: mitrandir77

Differential Revision: D8161706

fbshipit-source-id: 1dc41acebbcb081581f6b227facc8228375a320e
2018-05-25 10:05:41 -07:00
Mark Thomas
76e9f1518b templatekw: untemplated lists of objects should render sensibly
Summary:
Make template keywords that expand to lists of things that aren't strings, and
don't have a template to render the items in the list, render as the number of
items.

Reviewed By: mitrandir77

Differential Revision: D8161705

fbshipit-source-id: 19ca1cba88c0ce75c0ba358cd7e6f27c7ac61c34
2018-05-25 10:05:41 -07:00
Jun Wu
f085bc4510 templatekw: define 'username' as current username
Summary:
This could be useful for implementing logic like "if this commit is by the
current user, show something differently".

Reviewed By: markbt

Differential Revision: D7964292

fbshipit-source-id: de1ac0b5edde838dbaae646a88ebf636b4925b22
2018-05-14 11:14:38 -07:00
Yuya Nishihara
2c811cd701 log: translate column labels at once (issue5750)
This makes sure that all columns are aligned. getlogcolumns() is hosted by
templatekw so the namespaces module can see it.

i18n/de.po is updated so test-log.t passes with no error. "obsolete:" and
"instability:" are kept untranslated.
2017-12-02 16:29:49 +09:00
Pulkit Goyal
6a9585e5d1 py3: fix args handling for obsfate template
Differential Revision: https://phab.mercurial-scm.org/D1536
2017-11-29 04:41:48 +05:30
Yuya Nishihara
dfea246882 templatekw: add verbosity keyword to select template by -q/-v/--debug flag
This can be used in conjunction with the ifeq() function.
2017-10-21 17:46:41 +09:00
Yuya Nishihara
7f232b3ac0 templatekw: move loadkeyword() to bottom
loadkeyword() isn't a template keyword function.
2017-10-21 17:31:13 +09:00
Yuya Nishihara
1a42d3581c help: hide phaseidx template keyword
I don't think it's great idea to expose the internal representation of phases.
Let's discourage use of the phaseidx keyword.
2017-10-21 17:05:04 +09:00
Boris Feld
4ed4f0d702 templatekw: introduce obsfate keyword
Introduce an obsfate printer that uses all helpers functions defined in
obsutil to get all the obsfate-related data and format a string according to
the current format in test-obsmarker-template.t.

Then, introduce an obsfate templatekw that uses the obsfateprinter to return a
list of strings.

The goal is not to replace existing obsfate template functions but to propose
a default, good-enough and easily usable obsfate definition for end-users that
don't want to customize it. Such output would ultimately get included in the
default log output.

Here are some output examples for a commit amended:

rewritten using amend as 5:a9b1f8652753 by test (at 1970-01-01 00:00 +0000)

Next patches will make the output dependent on the verbosity.

Exemple of use-cases:

For having the obsfate on a single-line between brackets:

  {if(obsfate, " [{join(obsfate, "; ")}]")}

For having the obsfate in several lines:

  {if(obsfate, "{obsfate % "  Obsfate: {fate}\n"}")}
2017-10-05 17:42:56 +02:00
Yuya Nishihara
b3bcc5233c help: hide template keywords of obsolescence as they are still experimental 2017-10-12 21:48:02 +09:00
Yuya Nishihara
c9014c6361 help: fix formatting of template keywords
Our minirst formatter can't render multi-paragraph definition lists well.
Also added periods where appropriate.
2017-10-12 21:42:42 +09:00
Yuya Nishihara
6cc1150344 templater: store revisions as ints so min/max won't compare them as strings
Because a template value has no explicit type (like ancient PHP), ifcontains()
has to coerce the type of the needle. Before, it was always converted to a
string, which meant any container type should be a list/dict of strings.
This no longer works since we've introduced min/max functions.

In order to work around the untyped nature of templater, this patch adds
a type specifier to hybrid dict/list. It isn't named as "valuetype" since
the _hybrid class can also wrap a dict.
2017-09-19 23:13:46 +09:00
Yuya Nishihara
ef440af2e7 templatekw: allow accessing to nested namespace item by its template name
Since we have the dot operator, it makes more sense to write

  {namespaces.tags % "{tag}"}

instead of

  {namespaces.tags % "{name}"}
2017-09-30 08:57:50 +01:00
Yuya Nishihara
ccb359526e templatekw: get rid of temporary dicts from shownamespaces() 2017-09-30 08:50:24 +01:00
Yuya Nishihara
296d077704 templatekw: rename peerpaths to peerurls per naming convention (BC)
Since each element is called as "url", the template keyword should be named
as "<whatever>urls".

{peerurls} is now stabilized.
2017-09-18 23:53:05 +09:00
Yuya Nishihara
db07c1fcd9 templatekw: make experimental {peerpaths} return a single-level dict (BC)
This was planned as in 2bcc691583ec, "{peerpaths.default.pushurl} will be
translated to peerpaths['default'].makemap()['pushurl'], which means
{peerpaths} should be a single-level dict and sub-options should be
makemap()-ed."
2017-09-18 23:31:01 +09:00
Yuya Nishihara
3d25496222 templatekw: fix scope of peerpath url bound to generator
I had to explicitly bind 'd' to the generator. Otherwise, the last 'd' would
be used.
2017-09-18 23:49:05 +09:00
Yuya Nishihara
6215164ca2 templater: add dot operator to easily access a sub item
This and the next patch will allow us to access a deeply-nested item
by foo.bar.baz syntax.
2017-09-09 19:32:56 +09:00
Yuya Nishihara
366ad4616f templater: wrap get/min/max result so map operation can apply to element
See the test for usage example.

wraphybridvalue() takes a key/value pair because a hybrid dict passes a key
to its makemap() function. Since makemap() of showmanifest() doesn't need
a key, it's set to None.
2017-09-09 19:13:25 +09:00
Yuya Nishihara
b12606055b formatter: fix default list/dict generator to be evaluated more than once
Before, _hybrid.gen must be a generator which could be consumed only once.
It was okay in templatekw.py since template keywords are functions which
create temporary hybrid objects, but the formatter doesn't work in that way.

To work around the issue, this patch makes _hybrid.gen optionally be a
function returning a generator.

Thanks to Pulkit for finding this issue.
2017-10-01 08:37:04 +01:00
Yuya Nishihara
7dafbbbbcf templatekw: add new-style template expansion to {manifest}
The goal is to allow us to easily access to nested data. The dot operator
will be introduced later so we can write '{p1.files}' instead of
'{revset("p1()") % "{files}"}' for example.

In the example above, 'p1' needs to carry a mapping dict along with its
string representation. If it were a list or a dict, it could be wrapped
semi-transparently with the _hybrid class, but for non-list/dict types,
it would be difficult to proxy all necessary functions to underlying value
type because several core operations may conflict with the ones of the
underlying value:

 - hash(value) should be different from hash(wrapped(value)), which means
   dict[wrapped(value)] would be invalid
 - 'value == wrapped(value)' would be false, breaks 'ifcontains'
 - len(wrapped(value)) may be either len(value) or len(iter(wrapped(value)))

So the wrapper has no proxy functions and its scope designed to be minimal.
It's unwrapped at eval*() functions so we don't have to care for a wrapped
object unless it's really needed:

  # most template functions just call evalfuncarg()
  unwrapped_value = evalfuncarg(context, mapping, args[n])
  # if wrapped value is needed, use evalrawexp()
  maybe_wrapped_value = evalrawexp(context, mapping, args[n])

Another idea was to wrap every template variable with a tagging class, but
which seemed uneasy without a static type checker.

This patch updates {manifest} to a mappable as an example.
2016-04-24 18:41:23 +09:00
Yuya Nishihara
d5b31456c5 templatekw: just pass underlying value (or key) to joinfmt() function
Before, iter(hybrid) was proxied to hybrid.gen, which generated formatted
strings. That's why we had to apply joinfmt() to the dicts generated by
hybrid.itermaps(). Since this weird API was fixed at 1906bcc0f923, we can
get rid of the makemap() calls from join().
2017-09-24 15:22:46 +09:00
Yuya Nishihara
b009eae820 scmutil: extract helper functions that returns human-readable change id
We do "'%d:%s' % (ctx...)" at several places, so let's formalize it. A low-
level function, formatrevnode(ui, rev, node), is extracted so we can pass
a manifest rev/node pair.

Note that hex() for manifest output can be replaced with hexfunc() because
it is printed only when debugflag is set.

i18n/de.po is updated so test-log.t passes with no error.
2017-09-24 12:43:57 +09:00
Boris Feld
e5f84ad7bf template: add minimal obsfate template function
The goal of this series is to have templates capable of displaying the
evolution of a changeset in a clean and human-readable way.

Add the succsandmarkers template return successors and markers so it can be
used separately like this:

> {succsandmarkers % "{get(succsandmarkers, "markers")|json};"}

The following patches will add template functions that takes successors and
markers as inputs and compute various obsfate fields from them.
2017-08-17 18:26:11 +02:00
Sean Farley
e18a90ab08 merge with stable 2017-08-21 21:35:06 -07:00
Martin von Zweigbergk
7cd70adbc1 templatekw: choose {latesttag} by len(changes), not date (issue5659)
As Augie reported in the bug, the current heuristic of choosing the
best tag of a merge commit by taking the one with newest tag (in terms
of tagging date) currently fails in the Mercurial repo itself. Copying
the example from Yuya:

  $ hg glog -T '{node|short} {latesttag}+{latesttagdistance}\n' \
    -r '4.2.3: & (merge() + parents(merge()) + tag())'
  o    cc59efae4cc0 4.2.3+5
  |\
  | o    06f60e88fc3a 4.2.3+4
  | |\
  | | o  c191a9eb0b10 4.3-rc+109
  | | |
  | | ~
  o |  49ada93fdc10 4.3.1+2
  : |
  o |  229937197835 4.3.1+0
  |/
  o    6a83ad94c0f2 4.2.3+3
  |\
  | ~
  o  8e9dcdd1de74 4.2.3+2
  :
  o  525f2b18248f 4.2.3+0
  |
  ~

It seems to me like the best choice is the tag with the smallest
number of changes since it (across all paths, not the longest single
path). So that's what this patch does, even though it's
costly. Best-of-5 timings for Yuya's command above shows a slowdown
from 1.293s to 1.610s. We can optimize it later.

Differential Revision: https://phab.mercurial-scm.org/D447
2017-08-15 23:23:55 -07:00
Danny Hooper
54e3286e1e log: add a "graphwidth" template variable
Wrapping text in templates for 'hg log --graph' can't be done very well,
because the template doesn't know how wide the graph drawing is. The edge
drawing function needs to know the number of lines in the template output, so
we need to also determine how wide that drawing would be before we call the
edgefn or evaluate the template.

This patch makes edgefn compute the graph width and pass it into the template
so that we can do something like this:

COLUMNS=10 hg log --graph --template "{fill(desc, termwidth - graphwidth)}"
@  a a a a
|  a a a a
|  a a a a
o    a a a
|\   a a a
| |  a a a
| |  a a a

Using extensions to do this would be relatively complicated due to a lack of
hooks in this area of the code.

In the future it may make sense to have a more generic "textwidth" that tells
you how many columns you can expect to fill without causing the terminal to
wrap your output. I'm not sure there are other situations to motivate this yet,
or if it is entirely feasible.

Differential Revision: https://phab.mercurial-scm.org/D360
2017-08-15 10:15:31 -07:00
Yuya Nishihara
38282452e0 templatekw: specify plural form of instability
Follows up ebfef9a04f8d.
2017-08-13 14:12:28 +09:00
Yuya Nishihara
79af97cbbf templatekw: rename termwidth() per convention 2017-08-16 13:57:19 +09:00
Boris Feld
d833c9f0c7 label: rename trouble.X into instability.X
The renaming is done according to
https://www.mercurial-scm.org/wiki/CEDVocabulary.

Differential Revision: https://phab.mercurial-scm.org/D258
2017-08-03 15:30:41 +02:00
Boris Feld
b03347ff01 context: rename troubles into instabilities
Rename troubles context method into instabilities.

Copy the old troubles method and add a deprecation warning. This way
extensions calling troubles will see the deprecation warning but will not
break due to new return values.

The renaming is done according to
https://www.mercurial-scm.org/wiki/CEDVocabulary.

Differential Revision: https://phab.mercurial-scm.org/D238
2017-08-02 18:34:39 +02:00
Boris Feld
52010996a6 template: rename troubles templatekw into instabilities
Rename troubles template keyword into instabilities and add a deprecation
warning on templatekw.

Update default mapfile and test files to use the new template keyword.

The renaming is done according to
https://www.mercurial-scm.org/wiki/CEDVocabulary.

Differential Revision: https://phab.mercurial-scm.org/D237
2017-08-02 11:32:25 +02:00
Yuya Nishihara
46a6e6a290 templatekw: hide {peerpaths} keyword for 4.3
Thinking a bit further about list/dict subscript operation (proposed by
issue 5534), I noticed the current data structure, a dict of dicts, might
not be ideal.

For example, if there were "'[' index ']'" and "'.' key" operators,
"{parents[0]}" would return "{p1rev}:{p1node}", and we would probably want to
write "{parents[0].desc}" to get the first element of "{parents % "{desc}"}".
This will basically execute parents[0].makemap()['desc'] in Python.

Given the rule above, "{peerpaths.default.pushurl}" will be translated to
peerpaths['default'].makemap()['pushurl'], which means {peerpaths} should
be a single-level dict and sub-options should be makemap()-ed.

  "{peerpaths % "{name} = {url}, {pushurl}, ..."}"

(Well, it could be peerpaths['default']['pushurl'], but in which case,
peerpaths['default'] should be a plain dict, not a hybrid object.)

So, let's mark the current implementation experimental and revisit it later.
2017-07-15 00:38:57 +09:00
Yuya Nishihara
963c78d353 templatekw: export ui.paths as {peerpaths}
It's sometimes useful to show hyperlinks in log output.

  "{get(peerpaths, "default")}/rev/{node}"

Since each path may have sub options, "{peerpaths}" is structured as a dict
of dicts, but the inner dict is rendered as if it were a string URL. The
implementation is ad-hoc, so there are some weird behaviors described in
the test. We might need to introduce a proper way of handling a hybrid
scalar object.

This patch adds _hybrid.__getitem__() so d['path']['url'] works.

The keyword is named as "peerpaths" since "paths" seemed too generic in
log context.
2017-07-13 00:35:54 +09:00
Boris Feld
37426f06b5 template: add successors template
Add a 'successorssets' template that returns the list of all closest known
sucessorssets for a changectx. The elements of the list are changesets.

The "closest successors" are the first locally known revisions encountered
while, walking successors markers. It uses successorsets previously modified
to support the closest argument.

This logic respect repository filtering. So hidden revision will be skipped by
this logic unless --hidden is specified. Since we only display the visible
predecessors, this template will not display anything in most case. It makes a
good candidate for inclusion in the default log output.

I updated the test-obsmarker-template.t test file introduced with the
predecessors template to test successorssets template.
2017-07-03 11:22:00 +02:00
Gregory Szorc
6c60659b4c namespaces: record and expose whether namespace is built-in
Currently, the templating layer tends to treat each namespace
as a one-off, with explicit usage of {bookmarks}, {tags}, {branch},
etc instead of using {namespaces}. It would be really useful if
we could iterate over namespaces and operate on them generically.
However, some consumers may wish to differentiate namespaces by
whether they are built-in to core Mercurial or provided by extensions.
Expected use cases include ignoring non-built-in namespaces or
emitting a generic label for non-built-in namespaces.

This commit introduces an attribute on namespace instances
that says whether the namespace is "built-in" and then exposes
this to the templating layer.

As part of this, we implement a reusable extension for defining
custom names on each changeset for testing. A second consumer
will be introduced in a subsequent commit.
2017-06-24 14:52:15 -07:00
Gregory Szorc
da11a0810d templatekw: expose color name in {namespaces} entries
Templates make use of a "log.<namespace>" label. The <namespace> value
here differs from the actual namespace name in that the namespace
itself is plural but the label/color value is singular.

Expose the color name to the templating layer so log.* labels
can be emitted for {namespaces}.

As part of this, we refactored the logic to eliminate a gnarly
comprehension. We store color names in their own dict because the
lookup can occur in tight loops and we shouldn't have to go to
repo.names[ns] multiple times for every changeset.
2017-06-24 13:39:20 -07:00
Pulkit Goyal
3e9e1184d1 py3: convert kwargs' keys' to str using pycompat.strkwargs()
On Python 3, we must have keys of keyword arguments as str.
2017-06-22 03:16:16 +05:30
Pulkit Goyal
dc55608174 py3: use "%d" % val for int rather than pycompat.bytestr
Earlier I used pycompat.bytestr() to convert integers to bytes, but we can do
b"%d" % val to convert that int to bytes. b'' is already added by the
transformer.

Thanks to Yuya for suggesting this.
2017-06-22 01:29:07 +05:30
Pulkit Goyal
b5c1ee7c59 py3: use pycompat.bytestr() in place of str() 2017-06-21 02:20:34 +05:30
Pulkit Goyal
42ca4394c3 py3: use r'' to access values from kwargs where keys are str
These are the cases where either args is again passed as keyword argument or 1
or 2 elements are accessed. So it's better to add an r'' to prevent it
converting to bytes rather than doing the conversion of args.
2017-06-21 02:13:34 +05:30
Pulkit Goyal
bdff49ff8e py3: convert keys of kwargs in template keywords functions to bytes
This patch converts the args argument keys' to bytes wherever necessary as there
are some places where either args is not used or using r'' is better or args is
again passed as keyword arguments.
2017-06-21 02:10:25 +05:30
Pulkit Goyal
d05173a0a0 py3: replace str with bytes in isinstance()
We were using str because on Python 2, str were bytes but now we have to use
bytes. Otherwise the if conditions fails and we have weird results from commands
on Python 3.
2017-06-20 23:46:18 +05:30
Yuya Nishihara
2db9374d13 templatekw: use common "rev:node" format as the default of predecessors
I'm not sure if this is better. If we're planning to add a template keyword
that returns obsoleted nodes unavailable in the repo (i.e. they have no valid
revision numbers), we might want to use the current "node"-only format
everywhere.
2017-06-17 13:34:18 +09:00
Yuya Nishihara
c3de10454c templatekw: populate all keywords depending on predecessor in map operation
This is what showparents() does. repo[precnode] should never fail since its
validity is tested by closestpredecessors().
2017-06-17 13:23:55 +09:00
Yuya Nishihara
5e5cff46c2 templatekw: reference predecessor node id as {node} in map operation
More predecessor-depending values will be populated by the next patch.
2017-06-17 13:18:03 +09:00
Boris Feld
6b02ddc020 template: add predecessors template
Add a 'predecessors' template that returns the list of all closest known
predecessors for a changectx. The elements of the list are row changectx node id
formatted by default as short nodes.

The "closest predecessors" are the first locally known revisions encountered
while, walking predecessors markers. For example:

  1) If a (A, (B)) markers exists and both A and B are locally known A is a
  closest predecessors of B.

  2) If a (A, (B)) and (B, (C)) markers exists and only A and C are known
  locally, A will be the closest precursors of C.

This logic respect repository filtering. So hidden revision will be skipped by
this logic unless --hidden is specified. Since we only display the visible
predecessors, this template will not display anything in most case. It makes a
good candidate for inclusion in the default log output.

I added a new test-file for testing the precursors in various scenarios. This
test file will also be used for the successors template.

A new "obsutil" module has been added to start gathering utility function
outside of the large obsolete.py module.
2017-06-15 13:02:58 +02:00
Yuya Nishihara
32b5726eef scmutil: introduce binnode(ctx) as paired function with intrev(ctx)
It seemed silly to convert ctx.hex() back to binary to use node.hex/short(),
or to use [:12] instead of node.short() because ctx.node() could be None.

Eventually I want to change wctx.rev() and wctx.node() to return wdirrev and
wdirid respectively, but that's quite big API breakage and can't be achieved
without some compatibility wrappers.
2017-06-03 19:12:01 +09:00