For the future 'base' action in histedit we need a verification
constraint which will not allow using this action with changes
that are currently edited.
Before we can add a 'base' action to histedit need to change verification
so that action can specify which steps of verification should run for it.
Also it's everything we need for the exec and stop actions implementation.
I thought about baking verification into each histedit action (so each
of them is responsible for verifying its constraints) but it felt wrong
because:
- every action would need to know its context (eg. the list of all other
actions)
- a lot of duplicated work will be added - each action will iterate through
all others
- the steps of the verification would need to be extracted and named anyway
in order to be reused
The verifyrules function grows too big now. I plan to refator it in one of
the next series.
Before this patch we were using the old api bookmarks.write, this patches
replaces its usage by bookmarks.recordchange, the new api to record bookmark
changes.
Back in June we made histedit use obsolete markers to cleanup when possible.
This was rolled back as part of bb3db0db4037 (which should have only rolled back
the --abort stuff, but rolled back everything). This caused a nasty bug when
used in conjuction with the inhibit+directaccess extensions where histedit would
leave old nodes around even after they had been squashed away.
The root of the problem is that we first clean up old nodes, and then we clean
up temp nodes. In the first pass, when we obsoleted old nodes, some would become
unobsolete because they had temp nodes on top of them, thus making them stick
around even after the histedit finished.
The fix is to A) move the temp node cleanup to be before the old node cleanup
(since they are topological on top of the old nodes), and B) use obsolete
markers instead of stripping.
The home of 'Abort' is 'error' not 'util' however, a lot of code seems to be
confused about that and gives all the credit to 'util' instead of the
hardworking 'error'. In a spirit of equity, we break the cycle of injustice and
give back to 'error' the respect it deserves. And screw that 'util' poser.
For great justice.
When an user aborts a histedit, many things could go wrong. At a minimum, after
a histedit abort failure, their repository should be out of that state. We've
found situations where the user could not exit the histedit state without
manually deleting the histedit state file. This patch ensures that if any
exception happens during an abort, the histedit statefile will be deleted so
that users are out of the histedit state and can at least manually get the repo
back to a workable condition.
When the histeditstate class instance has it's clear() method called, there is
nothing to check to see if the state file exists before deleting it. It may not
exist, which would create an exception. This patch allows clear to be called at
any time.
This will be needed for the following patch.
If a histedit is progress, the 'histedit-state' file should exist. The patch
implements a convenience function to do check if a histedit is in progress.
This method will be use in next patch in the series.
This was the first ever feature request for histedit, originally filed
back on April 4, 2009. Finally fixed.
In the future we'll probably want to make it possible for other
preprocessing steps to be added to the list, but for now we're
skipping that because it's unclear what the API should look like
without a proposed consumer.
There is case where nodes are neither in tmpnodes nor leaf but still get
removed. For example, if you used the "edit" action, made a commit and run
--abort. The commit you made is not tracked by histedit, yet it will likely be
cleaned up with its parent. The commit may not tracked because no replacements
computations are done in the --abort case.
The for loop is already quite more complicated than necessary and we are about
to add some logic. Instead, we use a simple revset. Revset laziness should
provide us with similar performance.
The goal of this function is to strip content out of the repository. We do not
really care if this content is visible or cleanup node not and we should proceed
anyway. None of the internal actions are subject to this, however, a third party
extension running arbitrary commands during histedit is affected by this.
The process replacement is building a full mapping to allow moving bookmarks and
creating obsolescence marker. We do not need the full logic for abort so we
extract it. It will be useful as abort is missing some data about the
replacement and can crash when third party extensions push it a bit too far.
The faulty changeset use obsolescence marker to roll the repository back on
--abort. This is a problematic approach because --abort should be as close as an
actually transaction rollback as possible stripping all created data from the
repository (cf `hg rebase --abort` stripping all created changesets). Instead
3e883e7ec57b made all content created during the aborted histedit still
available in the repository adding obsolescence marker to make them hidden. This
will cause trouble to evolution user as a re-run of the same histedit (with
success) will likely result in the very same node to be "recreated" while
obsolescence marker would be in place for them. And canceling an obsoletion is
still a fairly complicated process.
This also rollback using obsmarkers instead of strip to clean up temporary node
on successful histedit run because the two change were not split in separated
changeset. Rolling that part back does not have significant consequence a will
have to be resubmitted independently
Before this patch, we were stripping temporary commits at the end of a histedit
whether it was successful or not. If we can create obs markers, we should
create them instead of stripping because it is faster and safer.
We use a variable to store whether or not we can create obsolescence markers.
It makes the patch series more readable as we are going to reuse this
values in other places in the function.
Python 2.6 introduced the "except type as instance" syntax, replacing
the "except type, instance" syntax that came before. Python 3 dropped
support for the latter syntax. Since we no longer support Python 2.4 or
2.5, we have no need to continue supporting the "except type, instance".
This patch mass rewrites the exception syntax to be Python 2.6+ and
Python 3 compatible.
This patch was produced by running `2to3 -f except -w -n .`.
This is suboptimal as the user still has to explicitly cancel the
histedit afterwards, but it prevents the immediate problem.
histedit should probably implicitly do 'hg histedit --abort' if a
util.Abort is raised internally.
The phrase "cannot edit immutable changeset" is kind of tautological.
Of course unchangeable things can't be changed. We instead mention
"public" and provide a hint so that we can point to the actual
problem. Even in cases where some operation other than edition cannot
be performed, "public" gives the root cause that results in the
"immutable" effect.
There is a precedent for saying "public" instead of "immutable", for
example, in `hg commit --amend`.
If histedit failed after all the rules were complete (for instance, if there was
an exception in the cleanup phase), you couldn't --continue because it was
unable to pop a rule. Let's just skip the rule execution phase of --continue if
there are no more rules.
If the histedit backupfile was None (like if evolve is enabled) it would get
serialized as 'None' into the state file. Later if the histedit was aborted and
the top most commit was unreachable (ex: if it was obsolete or stripped),
histedit would try to unbundle the backupfile and try to read .hg/None.
This fixes it to not serialize None. Since it only happens with evolve, I'm not
sure how to add test coverage here.
--edit-plan was completely broken from the command line because it used an old
api that was not updated (it would crash with a stack trace). Let's update it
and add tests to catch this.
Commit 960f8ca79ab1 broke histedit's rollup by causing it to open the editor.
Turns out I missed a spot where the rollup option was read.
This fixes that and adjusts the test to catch this case.
The existing state serialization format assumed the rule line consisted of an
action and a hash. In our external extension that adds 'exec' this is not the
case (there is no hash, just the shell command). So let's change the format to
be more generic with just an action and a remainder, and the various commands
can handle it as they wish.
Flagged for stable since we want to get this format tweak in before the new
format goes live in the release.
Previously the fold action would inspect it's class to figure out if it was a
rollup or not. This was hacky. Now that finishfold is inside the fold class,
let's modify it to check a function (which roll can override) to determine if it
should be prompting for a commit message.
This converts the fold/roll actions into a histeditclass instance, as part of an
ongoing effort to refactor histedit for maintainability and robustness.
The tests changed for two reasons:
1) We get a new 'empty changeset' warning because we now warn more consistently
between normal histedit and --continue about commits disappearing.
2) Previously we were not putting the histedit-source extra field on the
temporary fold commit during normal runs, but we were on --continue runs. By
unifying these code paths we now consistently put histedit-source on the
temporary fold commit, which changes some of the hashes in the backup bundles.