Commit graph

1372 commits

Author SHA1 Message Date
Yuya Nishihara
8a796cd98c cli: copy color output option to Criterion 2023-04-01 11:13:05 +09:00
Yuya Nishihara
9f1dc8f67c cli: remove excessive newline from "jj bench revset(s)" output 2023-04-01 11:13:05 +09:00
Martin von Zweigbergk
68ea927c66 cli: move default ui.pager config to misc.toml 2023-03-30 21:16:28 -07:00
Martin von Zweigbergk
5ae6698f81 cli: report invalid ui.pager config value
If you set e.g.`ui.pager = 5`, we currently ignore that and fall back
to the default. It seems better to let the user know that their config
is invalid, as we generally do. This commit does that. With this
change, the error message will look like this:

```
Config error: Invalid `ui.pager`: data did not match any variant of untagged enum CommandNameAndArgs
```

Maybe the key name will be redundant once the `config` crate releases
a version including https://github.com/mehcode/config-rs/pull/413
(thanks, Yuya).
2023-03-30 21:16:28 -07:00
Martin von Zweigbergk
5fe5991ca8 cli: on config error, point to documentation 2023-03-30 21:16:28 -07:00
Waleed Khan
4c629f3aa6 cli: add warrant to identity-not-configured message
The impact of not having configured one's name and email is not apparent from the warning message. Under the Toulmin model:

- Claim (implicit): You should configure your name and email.
- Grounds: Your name and email are not currently configured.
- Warrant (currently missing): Configuring your name and email will let you do...
2023-03-30 11:43:30 -07:00
Yuya Nishihara
a03e9c41a3 cli: run revset bench with fresh (but index-preloaded) repo instance
Some benchmark numbers in the following order:
- original
- fresh repo, BatchSize::SmallInput
- fresh but index-preloaded repo, BatchSize::SmallInput
- fresh but index-preloaded repo, BatchSize::LargeInput

    % cargo run --release --features bench -- bench revset ':main'
    revsets/:main           time:   [271.49 µs 271.74 µs 272.07 µs]
    revsets/:main           time:   [754.17 µs 758.22 µs 764.02 µs]
    revsets/:main           time:   [367.11 µs 372.65 µs 381.99 µs]
    revsets/:main           time:   [341.76 µs 342.98 µs 344.35 µs]

    % cargo run --release --features bench -- bench revset 'author(martinvonz)'
    revsets/author(martinvonz)
                            time:   [767.43 µs 770.52 µs 775.59 µs]
    revsets/author(martinvonz)
                            time:   [31.960 ms 31.984 ms 32.011 ms]
    revsets/author(martinvonz)
                            time:   [31.478 ms 31.538 ms 31.615 ms]
    revsets/author(martinvonz)
                            time:   [31.503 ms 31.526 ms 31.550 ms]

I think the fresh but index-preloaded repo is close to the practical
evaluation environment. With BatchSize::SmallInput, it appears to consume
~600MB (RES) memory (compared to ~50MB in LargeInput.) I don't think that's
huge, but it might affect cache usage, so I chose LargeInput.

https://docs.rs/criterion/latest/criterion/enum.BatchSize.html
2023-03-30 19:13:11 +09:00
Yuya Nishihara
db516081de cli: leverage bench_with_input() to make revset expression opaque to optimizer
I don't think this would matter since the revset evaluation is behind virtual
dispatch, but let's follow the general guideline.

https://bheisler.github.io/criterion.rs/book/user_guide/benchmarking_with_inputs.html#benchmarking-with-one-input
2023-03-30 19:13:11 +09:00
Yuya Nishihara
ce1f9ab9e5 cli: extract helper for revset benchmark
The benchmark ids slightly changed, but I think it's better to share the
target/criterion/revsets directory.
2023-03-30 19:13:11 +09:00
Martin von Zweigbergk
f7dbade07a cli: add a command for benchmarking many revsets
This command is similar to Mercurial's revset benchmarking command. It
lets you pass in a file containing revsets. I also included a file
with some revsets to test on the git.git repo. I put it in `testing/`,
which doesn't seem perfect. I'm happy to hear suggestions for better
places, or we can move it later if we find a better place.

Note that these tests don't clear caches between each run (or even
between tests), so revsets that rely on filtering commit data that's
not indexed appear faster than they typically are in reality.
2023-03-28 10:21:10 -07:00
Martin von Zweigbergk
7249be33b0 cli: replace jj bench walkrevs by generic jj bench revset
I suspect the `jj bench walkrevs` command was from before we had
support for revsets. Now there doesn't seem to be any reason to have a
specific command for only range revsets (`foo..bar`), so let's replace
it by a command for benchmarking an arbitrary revset.
2023-03-28 10:21:10 -07:00
Martin von Zweigbergk
327deeb0c4 cli: move jj bench commands to new module, hide behind feature flag
The `jj bench` commands are mostly meant for developers, so lets hide
the command from help and behind a `bench` feature flag. The feature
flags avoids bloating the binary with the `criterion` dependencies,
which was the reason I removed the command in 18c0b97d9d.
2023-03-28 10:21:10 -07:00
Martin von Zweigbergk
48fbf7e1bd cli: revive jj bench command
This just backs out commit 18c0b97d9d without making any changes,
except for resolving conflicts.

I want a way to benchmark different revsets on e.g. the Git Core repo
or the Linux repo.
2023-03-28 10:21:10 -07:00
Martin von Zweigbergk
bac2de6ac6 cli: add hint about testing with ssh -F /dev/null on SSH errors 2023-03-24 22:16:50 -07:00
Martin von Zweigbergk
6c28ec1608 cli: find working copy's first parent from commit store (not index)
This avoid another use of `IndexEntry`. The working-copy commit should
be in the cache here, so it shouldn't have any impact on performance.
2023-03-24 10:09:40 -07:00
Martin von Zweigbergk
a5b79f9b0e index: make topo_order() return commit ids instead of index entries
`IndexEntry` is specific to the default index store; we don't want it
in the interface.
2023-03-24 10:09:40 -07:00
Martin von Zweigbergk
75605e36af revset: iterate over commit ids instead of index entries
There are no remaining places where we iterate over a revset and need
the `IndexEntry`s, so we can now make `Revset::iter()` yield
`CommitId`s instead.
2023-03-23 21:58:15 -07:00
Yuya Nishihara
75d68fe24c templater: add "parents" keyword in place of "parent_commit_ids"
All commit keywords are mapped to nullary methods. No matter if we'll
introduce .field syntax and/or self. keyword, this implementation can be
reused.
2023-03-24 12:17:38 +09:00
Yuya Nishihara
f4235464c2 templater: extract function that builds commit keywords over property
New code inserts one more Commit::clone(), but I don't see a measurable cost
with "jj log -Tshow -r 'all()'".
2023-03-24 12:17:38 +09:00
Yuya Nishihara
90f27555e7 templater: remove repo reference from CommitOrChangeId
A repo reference is passed around by the language struct, so it's no longer
needed to embed in CommitOrChangeId.
2023-03-24 12:17:38 +09:00
Yuya Nishihara
9065b94dc1 templater: implement list methods for unformattable property 2023-03-24 12:17:38 +09:00
Yuya Nishihara
a0be6a5a11 templater: add support for unformattable property
A property of Commit type won't have a default format.
2023-03-24 12:17:38 +09:00
Yuya Nishihara
9d661d6f69 cli: render other kind of revset error suggestion as hint 2023-03-23 23:08:17 +09:00
Yuya Nishihara
ddeb645d7f cli: provide hint for typo of revset function name
This is similar to what Mercurial does. The similarity threshold is copied
from clap, but we might want to adjust it later.
2023-03-23 23:08:17 +09:00
Martin von Zweigbergk
9ed537b3e8 cli: leverage RevsetIteratorExt::commits() in jj log
I'm trying to remove uses of `IndexEntry`.
2023-03-23 04:50:33 -07:00
Yuya Nishihara
2a87e1f95a cli: call RevsetExpression::evaluate() directly if no symbol resolution needed
There should be no problem to evaluate revset against base_repo and collect
commit objects from (mut_)repo, but it seemed a bit odd.

In rebase examples other than the "new --insert-after", we could switch to
tx.repo(). However, I think the use of tx.base_repo() makes it clear that
there's no data dependency on the previous mutation.
2023-03-23 01:15:31 +09:00
Martin von Zweigbergk
5f74dd5db3 repo: implement Repo on ReadonlyRepo instead of its Arc
I'd like to be able to pass a `self` of `type `&ReadonlyRepo` to
functions that take a `&dyn Repo`. For that, we need `ReadonlyRepo`
itself to implement `Repo` instead of having `Arc<ReadonlyRepo>`
implement it. I could have solved it in a different way, but the `Arc`
requirement seems like an unnecessary constraint.
2023-03-21 21:43:44 -07:00
Martin von Zweigbergk
58e153af19 cli: use Transaction::repo() instead of base_repo() when possible
In most cases, we just need to access the commit backend and then the
shorter `base()` works. I noticed because I wanted to implement `Repo`
on `ReadonlyRepo` instead of on `Arc<ReadonlyRepo>` and then these
uses failed.
2023-03-21 21:43:44 -07:00
Martin von Zweigbergk
01d7239732 revset: make graph iterator yield commit ids (not index entries)
We only need `CommitId`s, and `IndexEntry` is specific to the default
index implementation.
2023-03-20 01:45:54 -07:00
Martin von Zweigbergk
2f876861ae graphlog: key by commit id (not index position)
The index position is specific to the default index implementation and
we don't want to use it in outside of there. This commit removes the
use of it as a key for nodes in the graphlog.

I timed it on the git.git repo using `jj log -r 'all()' -T commit_id`
(the worst case I can think of) and it slowed down from ~2.02 s to
~2.20 s (~9%).
2023-03-20 01:45:54 -07:00
Martin von Zweigbergk
fc84c02c8e cli: add jj describe --no-edit to not open editor 2023-03-19 00:48:05 -07:00
Martin von Zweigbergk
3bacc367cd cli: add jj describe --reset-author
I think requests to reset the author came up twice in the last week,
so let's just add support for it. I copied git's behavior of resetting
the name, email, and timestamp. The flag name is also from git.
2023-03-19 00:48:05 -07:00
Martin von Zweigbergk
2495c8f27e cargo: update MSRV to 1.64
We need 1.64 to bump `clap` to `4.1`. We don't really need to upgrade
to that, but being on an older version causes minor confusions like
#1393. Rust 1.64 is very close to 6 months old at this point.
2023-03-17 22:44:29 -07:00
Martin von Zweigbergk
70d4a0f42e revset: remove context parameter from evaluate()
The `RevsetWorkspaceContext` argument is now instead used by the new
`resolve_symbol()` function.
2023-03-17 22:42:41 -07:00
Martin von Zweigbergk
94aec90bee revset: resolve symbols earlier, before passing to revset engine
For large repos, it's useful to be able to use shorter change id and
commit id prefixes by resolving the prefix in a limited subset of the
repo (typically the same subset that you'd want to see in your default
log output). For very large repos, like Google's internal one, the
shortest unique prefix evaluated within the whole repo is practically
useless because it's long enough that the user would want to copy and
paste it anyway.

Mercurial supports this with its `revisions.disambiguatewithin` config
(added in https://www.mercurial-scm.org/repo/hg/rev/503f936489dd). I'd
like to add the same feature to jj. Mercurial's implementation works
by attempting to resolve the prefix in the whole repo and then, if the
prefix was ambiguous, it resolves it in the configured subset
instead. The advantage of doing it that way is that there's no extra
cost of resolving the revset defining the subset if the prefix was not
ambiguous within the whole repo. However, there are two important
reasons to do it differently in jj:

* We support very large repos using custom backends, and it's probably
  cheaper to resolve a prefix within the subset because it can all be
  cached on the client. Resolving the prefix within the whole repo
  requires a roundtrip to the server.

* We want to be able to resolve change id prefixes, which is always
  done in *some* revset. That revset is currently `all()`, i.e. all
  visible commits. Even on local disk, it's probably cheaper to
  resolve a small revset first and then resolve the prefix within that
  than it is to build up the index of all visible change ids.

We could achieve the goal by letting each revset engine respect the
configured subset, but since the solution proposed above makes sense
also for local-disk repos, I think it's better to do it outside of the
revset engine, so all revset engines can share the code.

This commit prepares for the new functionality by moving the symbol
resolution out of `Index::evaluate_revset()`.
2023-03-17 22:42:41 -07:00
Martin von Zweigbergk
ac23395ea1 cli: pass revset expression by value to evaluate_revset()
The callers don't need to hold on to the revset expression once it's
been evaluated, and having an owned expression (well, an expression
with shared ownership) will avoid a clone in the next commit.
2023-03-17 22:42:41 -07:00
Yuya Nishihara
998727266c templater: add join method to mapped template 2023-03-18 12:04:00 +09:00
Yuya Nishihara
2fbe581a71 templater: add trait that represents a mapped template
A mapped template is basically a combined function that takes context: &C,
extracts Vec<O>, and formats each item with Template<C>. It cannot be cleanly
turned into a function of (&C) -> Vec<Template<()>> type. So list-like methods
are implemented on Box<dyn ListTemplate<C>> instead.
2023-03-18 12:04:00 +09:00
Yuya Nishihara
ec5dd96e66 templater: convert template to Box<dyn Template> by caller
I'm going to add a trait that provides .join() -> Box<dyn Template>.
wrap_template() should handle it transparently, but the current interface
would require excessive boxing.
2023-03-18 12:04:00 +09:00
Yuya Nishihara
3124444d24 templater: add list.map(|x| ...) operation
This involves a little hack to insert a lambda parameter 'x' to be used at
keyword position. If the template language were dynamically typed (and were
interpreted), .map() implementation would be simpler. I considered that, but
interpreter version has its own warts (late error reporting, uneasy to cache
static object, etc.), and I don't think the current template engine is
complex enough to rewrite from scratch.

.map() returns template, which can't be join()-ed. This will be fixed later.
2023-03-18 12:04:00 +09:00
Yuya Nishihara
20a75947fe templater: add stub BuildContext object, pass it around build_() functions
A lambda parameter will be added there just like "locals" of expand_aliases().
2023-03-18 12:04:00 +09:00
Yuya Nishihara
369c119053 templater: generalize formattable list template for map operation 2023-03-18 12:04:00 +09:00
Yuya Nishihara
ea0cc374aa templater: extract low-level helper to format list items with separator
For map operation, we'll have to bind parameter and evaluate template for
each element, which can't be purely abstracted as a Template<()> type.
2023-03-18 12:04:00 +09:00
Yuya Nishihara
1c0bde1a2b templater: add parsing rule for lambda expression
A lambda expression will be allowed only in .map() operation. The syntax is
borrowed from Rust closure.

In Mercurial, a map operation is implemented by context substitution. For
example, 'parents % "{node}"' prints parents[i].node for each. There are two
major problems: 1. the top-level context cannot be referred from the inner map
expression. 2. context of different types inserts arbitrarily-named keywords
(e.g. a dict type inserts "{key}" and "{value}", but how we could know.)

These issues should be avoided by using explicitly named parameters.

    parents.map(|parent| parent.commit_id ++ " " ++ commit_id)
                                                    ^^^^^^^^^ global keyword

A downside is that we can't reuse template fragment in map expression. Suppose
we have -T commit_summary, -T 'parents.map(commit_summary)' doesn't work.

    # only usable as a top-level template
    'commit_summary' = 'commit_id.short() ++ " " ++ description.first_line()'

Another problem is that a lambda expression might be confused with an alias
function.

    # .map(f) doesn't work, but .map(g) does
    'f(x)' = 'x'
    'g' = '|x| x'
2023-03-18 12:04:00 +09:00
Martin von Zweigbergk
e2b4d7058d cli: move some debug commands to new (non-hidden) support group
The `jj debug` commands are hidden from help and are described as
"Low-level commands not intended for users", but e.g. `jj debug
completion` is intended for users, and should be visible in the help
output.
2023-03-17 06:50:55 -07:00
Martin von Zweigbergk
ce098a729a cli: remove jj hide as alias for jj abandon
I haven't heard of anyone using this alias, so let's remove it. It's
easy for users to add it as their own alias if they really want it.
2023-03-17 06:50:55 -07:00
Martin von Zweigbergk
fb7b680d1f cli: don't hide jj commit from help output
The command is not only useful for new users, it's also useful as a
combination of `jj describe` and `jj new`.
2023-03-17 06:50:55 -07:00
Martin von Zweigbergk
e64ca31bfd cli: show diff summary as two states instead of transition
By using one letter for the path type before and one letter for path
type after, we can encode much more information than just the current
'M'/'A'/'R'. In particular, we can indicate new and resolved
conflicts. The color still encodes the same information as before. The
output looks a bit weird after many years of using `hg status`. It's a
bit more similar to the `git status -s` format with one letter for the
index and one with the working copy. Will we get used to it and find
it useful?
2023-03-16 08:01:13 -07:00
Martin von Zweigbergk
ed1c2ea1aa cli: disallow jj diff --color-words --git 2023-03-16 08:01:13 -07:00
Martin von Zweigbergk
0899260f0c cli: try to clarify the help texts for jj op commands a little 2023-03-16 08:00:05 -07:00