In order to give us the freedom to change the changegroup3 format,
let's hide it behind an experimental config. Since it is required by
treemanifests, that will override the cg3 config.
This backs out 7e679fd51132 (status: change + back out == clean (API),
2016-01-04). Although correct, it turned out that it was just too
slow. For example, 'hg status --rev .~1000 --rev .' on the Mozilla
repo went from <1s to >30s on cold disk. So we go back to reporting
reverted changes as modified instead of clean. These are rare anyway,
as suggested by the fact that it had been broken since before
Mercurial 2.0.
Before this patch rebase would create divergence when you were rebasing obsolete
changesets on a destination not containing one of its successors.
This patch introduces rebase.allowdivergence to explicitly allow
divergence creation with rebase.
This patch is a refactoring of the code skipping obsolete changesets already
present in destination. It makes the following patches more legible.
Instead of passing all the revs to be rebased to _computeobsoletenotrebased,
we only pass the obsolete revisions of the rebaseset.
The preceding #if conditional was the only modification to the file, so the
"reverting file" line in the subsequent revert command was getting dropped.
In some real-world cases it is preferable to allow overwriting ignored files
while continuing to abort on unknown files. This primarily happens when we're
replacing build artifacts (which are ignored) with checked in files, but
continuing to abort on differing files that aren't ignored.
We're redefining merge.checkunknown to only control the behavior for files
that aren't ignored. That's fine because this config was only very recently
introduced and has not made its way into any Mercurial releases yet.
Sometimes a txnclose or changegroup hook wants to iterate through all
the changesets in transaction: in that situation usually the revset
`$HG_NODE:` is used to select the revisions. Unfortunately this revset
sometimes may contain too many changesets because we don't have the
write lock while the hook runs newer changes may be added to
repository in the meantime.
That's why there is a need for extra variable carrying the information about
the last change in the transaction.
The clone bundles feature was introduced in Mercurial 3.6 behind an
experimental and disabled by default flag. The feature has been enabled
on hg.mozilla.org for a few months and has served many terabytes of
clones. Users have been encouraged to use the feature and reception
has been very positive (mainly due to faster clones as a result of
connecting to a CDN). I have heard no feedback about changing the
feature other than inquiries about when it will be enabled by default.
So, I think the feature is ready to be enabled by default.
This patch renames experimental.clonebundles to ui.clonebundles,
documents the option, and enables it by default. References to the
experimental state of clone bundles have been removed. The remaining
config option docs in clonebundles.py have been removed because they
are redudant with `hg help config`.
There are some oddities with behavior of clone bundles. Because clones
with clone bundles are effectively 2 `hg pull` operations, there may be
2 transactions. This could result in hooks running twice. If the
subsequent pull is aborted, it could result in partial rollback and an
incomplete clone. This behavior is a bit wonky and should probably
be documented. If this patch is accepted, I'll send a follow-up to
document it. I don't think this behavior should prevent the feature
being enabled by default. Reworking the clone mechanism to support
interrupted or multi-part clones feels like a major new feature and
something that when implemented can change the hook and rollback
semantics of clone bundles. Besides, partial clone is better than
full rollback and hooks running on initial clone are likely rare, so I
think the impact is minimal.
I screwed up.
When clone bundles is enabled on the server and a compatible client
without the feature enabled clones, the server sends down an
advertisement saying to enable the feature. The server creates the
message which is printed verbatim on the client as an "output" part.
There are 2 problems:
1) The message doesn't respect the client's localization
2) The message contains a reference to the "experimental.clonebundles"
option.
Since clone bundles is about to be marked as non-experimental and the
goal of the advertisement was to encourage clients to test the
experimental feature, let's just remove the broken advertisement since
it no longer serves a purpose.
By adding a mandatory 'treemanifest' parameter in the bundle2 part, we
make it possible for the recipient to set repo requirements before the
manifest revlog is accessed.
Specifically, :hg:`foo 'bar baz'` when rendered by `hg help`
results in:
'hg foo 'bar baz''
... which is hard to read.
We encourage :hg:`foo "bar baz"` instead.
Previously, we were using Python's native 'os.path.isfile' method which follows
symlinks. In this case, since we're operating on repo contents, we don't want
to follow symlinks.
There's a behaviour change here, as shown by the second part of the added test.
Consider a symlink 'f' pointing to a file containing 'abc'. If we try and
replace it with a file with contents 'abc', previously we would have let it
though. Now we don't. Although this breaks naive inspection with tools like
'cat' and 'diff', on balance I believe this is the right change.
This effectively backs out 163c899d1e46 and f44b0edaab90.
We can't handle "default-push" just like "default:pushurl" because it is a
stand-alone named path. Instead, I have two ideas to work around the issue:
a. two defaults: getpath(dest, default=('default-push', 'default'))
b. virtual path: getpath(dest, default=':default')
(a) is conservative approach and will have less trouble, but callers have
to specify they need "default-push" or "default". (b) generates hidden
":default" path from "default" and "default-push", and callers request
":default". This will require some tricks and won't work if there are
conflicting sub-options valid for both "pull" and "push".
I'll take (a) for default branch. This patch should NOT BE MERGED to default
except for tests because it would break handling of "pushurl" sub-option.
On some servers, python curses support is disabled. This patch not only fixes
that but provides a fallback on other machines (e.g. Windows) when curses is
not found.
The previous code was actually flawed logic and relied on wcurses throwing an
ImportError which demandimport wouldn't throw. So, this patch also fixes that
problem.
Instead of blindly trusting the user's experimental.crecord, we use checkcurses
to abstract that logic so that we can handle the case where python was not
built with curses.
Not only does this improve fragility with 'if os.name == ...' it will help
future patches enable the behavior to fallback to use plain record when curses
is unavailable (e.g. python compiled without curses support).
Before this patch, "hg qimport -r REV" fails, if the summary line of
description of REV doesn't contain any alpha-numeric bytes.
In this case, all bytes in the summary line 'title' are dropped from
'namebase' by the code path below.
namebase = re.sub('[\s\W_]+', '_', title.lower()).strip('_')
'makepatchname()' immediately returns this empty string as valid patch
name, because patch name conflicting against empty string never
exists.
Then, "hg qimport -r REV" is aborted at creation of patch file with
empty filename.
This situation isn't so rare. For example, ordinary texts in Japanese
often consist of non alpha-numeric bytes in UTF-8.
This patch makes 'makepatchname()' use fallback patch name if the
summary line of imported revision doesn't contain any alpha-numeric
bytes.
Revlogs were recently refactored to open file handles in "a+" and use a
persistent file handle for reading and writing. This drastically
reduced the number of file handles being opened.
Unfortunately, it appears that some versions of Solaris lose the file
offset when performing a write after the handle has been seeked.
The simplest workaround is to seek to EOF on files opened in a+ mode
before writing to them, which is what this patch does.
Ideally, this code would exist in the vfs layer. However, this would
require creating a proxy class for file objects in order to provide a
custom implementation of write(). This would add overhead. Since
revlogs are the only files we open in a+ mode, the one-off workaround
in revlog.py should be sufficient.
This patch appears to have little to no impact on performance on my
Linux machine.
Embedded passwords are masked only in plain output because we'll want raw
values in machine-readable format such as JSON. For custom template, we can
add a filter to mask passwords (e.g. "{url|hidepassword}").
path.rawloc field is called as "url" than "path" because we have "pushurl"
sub-option. Also, "name" and "url" are not allowed as sub-options as they
conflict with the field names.
Truth table (extracted from the original implementation):
search quiet name path subopt
------ ----- ---- ---- ------
f f T T T
f T T f f
T f f T f
T T f f f
This prepares for porting to the formatter API. Future patches will use a
single loop to handle both search=None|pattern cases because formatter output
should be the same. "pathitems" will be switched instead.
This aligns with the unconditional plural output for the update line contents,
as well as the incoming/outgoing bookmarks line. It also matches the message
in evolve's summary hook as of 4f83b2d2d20d. (Though I thought this was removed
recently?)
For reasons I can't explain (but likely have something to do with a
combination of __import__ inferring default values for arguments and
the demand importer mechanism further assuming defaults), the demand
importer isn't playing well with IPython. Without this patch, we get
a failure "ValueError: Attempted relative import in non-package" when
attempting to import "IPython." The stack has numerous demandimport
calls on it and adding "IPython" to the exclude list in demandimport
isn't enough to make the problem go away, which means the issue is
likely somewhere in the bowells of IPython. It's easier to just disable
the demand importer when importing the debugger.
After backing out a change, so the file contents is equal to a
previous revision of itself, we currently report the status between
the two equal revisions as modified. This is because
context._buildstatus() reports any file whose new nodeid is not equal
to _newnode as modified. That magic nodeid is given only to files
added or modified in the working directory, so any file whose nodeid
has changed between two revisions will be reported as modified.
Fix by simply comparing the file contents for all cases where the
nodeid changed, whether they are in the working copy or committed.
Marking with (API) as it subtly changes the semantics of the method.
mercurial_source.getchanges() seems to care about files whose nodeid
has changed even if their contents has not (i.e. it has been
reverted/backed out). The method uses ctx1.status(ctx2) to find
differencing files. However, that method is currently broken and
reports reverted changes as modified. In order to fix that method, we
first need to rewrite getchanges() using manifest.diff(), which does
report reverted files as modified (because it's about differences in
the manifest, so about nodeids).
The next commit will rewrite the way we find changes between two
manifests. By making the cache not care about the difference between
added and modified files, we don't require the rewritten code to care
about that difference either. Also extract the call to ctx.status() to
simplify the next commit.