Now that we have named attributes, let's convert the code base to use
them. We also add deprecation warnings so legacy consumers are aware
of their transgressions.
`stats.unresolvedcount is much easier to read than stats[3]`,
don't you think?
( )
| durin42 | |
| martinvonz | |
| pulkit |
| hg-reviewers |
Now that we have named attributes, let's convert the code base to use
them. We also add deprecation warnings so legacy consumers are aware
of their transgressions.
`stats.unresolvedcount is much easier to read than stats[3]`,
don't you think?
| Lint Skipped |
| Unit Tests Skipped |
This one failed to apply, probably because of my changes to rebase.py. I have to leave now, but I'll try again later tonight, whether or not you've gotten a chance to update it.
| Path | Packages | |||
|---|---|---|---|---|
| M | hgext/histedit.py (2 lines) | |||
| M | hgext/rebase.py (2 lines) | |||
| M | mercurial/commands.py (4 lines) | |||
| M | mercurial/hg.py (12 lines) | |||
| M | mercurial/merge.py (11 lines) |
| """Applies the changes from this action's rulectx onto the current | """Applies the changes from this action's rulectx onto the current | ||||
| parentctx, but does not commit them.""" | parentctx, but does not commit them.""" | ||||
| repo = self.repo | repo = self.repo | ||||
| rulectx = repo[self.node] | rulectx = repo[self.node] | ||||
| repo.ui.pushbuffer(error=True, labeled=True) | repo.ui.pushbuffer(error=True, labeled=True) | ||||
| hg.update(repo, self.state.parentctxnode, quietempty=True) | hg.update(repo, self.state.parentctxnode, quietempty=True) | ||||
| stats = applychanges(repo.ui, repo, rulectx, {}) | stats = applychanges(repo.ui, repo, rulectx, {}) | ||||
| repo.dirstate.setbranch(rulectx.branch()) | repo.dirstate.setbranch(rulectx.branch()) | ||||
| if stats and stats[3] > 0: | if stats.unresolvedcount: | ||||
| buf = repo.ui.popbuffer() | buf = repo.ui.popbuffer() | ||||
| repo.ui.write(buf) | repo.ui.write(buf) | ||||
| raise error.InterventionRequired( | raise error.InterventionRequired( | ||||
| _('Fix up the change (%s %s)') % | _('Fix up the change (%s %s)') % | ||||
| (self.verb, node.short(self.node)), | (self.verb, node.short(self.node)), | ||||
| hint=_('hg histedit --continue to resume')) | hint=_('hg histedit --continue to resume')) | ||||
| else: | else: | ||||
| repo.ui.popbuffer() | repo.ui.popbuffer() | ||||
| if len(repo[None].parents()) == 2: | if len(repo[None].parents()) == 2: | ||||
| repo.ui.debug('resuming interrupted rebase\n') | repo.ui.debug('resuming interrupted rebase\n') | ||||
| else: | else: | ||||
| try: | try: | ||||
| ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), | ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), | ||||
| 'rebase') | 'rebase') | ||||
| stats = rebasenode(repo, rev, p1, base, self.state, | stats = rebasenode(repo, rev, p1, base, self.state, | ||||
| self.collapsef, dest, wctx=self.wctx) | self.collapsef, dest, wctx=self.wctx) | ||||
| if stats[3] > 0: | if stats.unresolvedcount > 0: | ||||
| if self.wctx.isinmemory(): | if self.wctx.isinmemory(): | ||||
| raise error.InMemoryMergeConflictsError() | raise error.InMemoryMergeConflictsError() | ||||
| else: | else: | ||||
| raise error.InterventionRequired( | raise error.InterventionRequired( | ||||
| _('unresolved conflicts (see hg ' | _('unresolved conflicts (see hg ' | ||||
| 'resolve, then hg rebase --continue)')) | 'resolve, then hg rebase --continue)')) | ||||
| finally: | finally: | ||||
| ui.setconfig('ui', 'forcemerge', '', 'rebase') | ui.setconfig('ui', 'forcemerge', '', 'rebase') | ||||
| dsguard = dirstateguard.dirstateguard(repo, 'backout') | dsguard = dirstateguard.dirstateguard(repo, 'backout') | ||||
| try: | try: | ||||
| ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), | ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), | ||||
| 'backout') | 'backout') | ||||
| stats = mergemod.update(repo, parent, True, True, node, False) | stats = mergemod.update(repo, parent, True, True, node, False) | ||||
| repo.setparents(op1, op2) | repo.setparents(op1, op2) | ||||
| dsguard.close() | dsguard.close() | ||||
| hg._showstats(repo, stats) | hg._showstats(repo, stats) | ||||
| if stats[3]: | if stats.unresolvedcount: | ||||
| repo.ui.status(_("use 'hg resolve' to retry unresolved " | repo.ui.status(_("use 'hg resolve' to retry unresolved " | ||||
| "file merges\n")) | "file merges\n")) | ||||
| return 1 | return 1 | ||||
| finally: | finally: | ||||
| ui.setconfig('ui', 'forcemerge', '', '') | ui.setconfig('ui', 'forcemerge', '', '') | ||||
| lockmod.release(dsguard) | lockmod.release(dsguard) | ||||
| else: | else: | ||||
| hg.clean(repo, node, show_stats=False) | hg.clean(repo, node, show_stats=False) | ||||
| # ui.forcemerge is an internal variable, do not document | # ui.forcemerge is an internal variable, do not document | ||||
| repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), | repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), | ||||
| 'graft') | 'graft') | ||||
| stats = mergemod.graft(repo, ctx, ctx.p1(), | stats = mergemod.graft(repo, ctx, ctx.p1(), | ||||
| ['local', 'graft']) | ['local', 'graft']) | ||||
| finally: | finally: | ||||
| repo.ui.setconfig('ui', 'forcemerge', '', 'graft') | repo.ui.setconfig('ui', 'forcemerge', '', 'graft') | ||||
| # report any conflicts | # report any conflicts | ||||
| if stats[3] > 0: | if stats.unresolvedcount > 0: | ||||
| # write out state for --continue | # write out state for --continue | ||||
| nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]] | nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]] | ||||
| repo.vfs.write('graftstate', ''.join(nodelines)) | repo.vfs.write('graftstate', ''.join(nodelines)) | ||||
| extra = '' | extra = '' | ||||
| if opts.get('user'): | if opts.get('user'): | ||||
| extra += ' --user %s' % util.shellquote(opts['user']) | extra += ' --user %s' % util.shellquote(opts['user']) | ||||
| if opts.get('date'): | if opts.get('date'): | ||||
| extra += ' --date %s' % util.shellquote(opts['date']) | extra += ' --date %s' % util.shellquote(opts['date']) | ||||
| release(srclock, destlock) | release(srclock, destlock) | ||||
| if cleandir is not None: | if cleandir is not None: | ||||
| shutil.rmtree(cleandir, True) | shutil.rmtree(cleandir, True) | ||||
| if srcpeer is not None: | if srcpeer is not None: | ||||
| srcpeer.close() | srcpeer.close() | ||||
| return srcpeer, destpeer | return srcpeer, destpeer | ||||
| def _showstats(repo, stats, quietempty=False): | def _showstats(repo, stats, quietempty=False): | ||||
| if quietempty and not any(stats): | if quietempty and stats.isempty(): | ||||
| return | return | ||||
| repo.ui.status(_("%d files updated, %d files merged, " | repo.ui.status(_("%d files updated, %d files merged, " | ||||
| "%d files removed, %d files unresolved\n") % ( | "%d files removed, %d files unresolved\n") % ( | ||||
| stats.updatedcount, stats.mergedcount, | stats.updatedcount, stats.mergedcount, | ||||
| stats.removedcount, stats.unresolvedcount)) | stats.removedcount, stats.unresolvedcount)) | ||||
| def updaterepo(repo, node, overwrite, updatecheck=None): | def updaterepo(repo, node, overwrite, updatecheck=None): | ||||
| """Update the working directory to node. | """Update the working directory to node. | ||||
| When overwrite is set, changes are clobbered, merged else | When overwrite is set, changes are clobbered, merged else | ||||
| returns stats (see pydoc mercurial.merge.applyupdates)""" | returns stats (see pydoc mercurial.merge.applyupdates)""" | ||||
| return mergemod.update(repo, node, False, overwrite, | return mergemod.update(repo, node, False, overwrite, | ||||
| labels=['working copy', 'destination'], | labels=['working copy', 'destination'], | ||||
| updatecheck=updatecheck) | updatecheck=updatecheck) | ||||
| def update(repo, node, quietempty=False, updatecheck=None): | def update(repo, node, quietempty=False, updatecheck=None): | ||||
| """update the working directory to node""" | """update the working directory to node""" | ||||
| stats = updaterepo(repo, node, False, updatecheck=updatecheck) | stats = updaterepo(repo, node, False, updatecheck=updatecheck) | ||||
| _showstats(repo, stats, quietempty) | _showstats(repo, stats, quietempty) | ||||
| if stats[3]: | if stats.unresolvedcount: | ||||
| repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n")) | repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n")) | ||||
| return stats[3] > 0 | return stats.unresolvedcount > 0 | ||||
| # naming conflict in clone() | # naming conflict in clone() | ||||
| _update = update | _update = update | ||||
| def clean(repo, node, show_stats=True, quietempty=False): | def clean(repo, node, show_stats=True, quietempty=False): | ||||
| """forcibly switch the working directory to node, clobbering changes""" | """forcibly switch the working directory to node, clobbering changes""" | ||||
| stats = updaterepo(repo, node, True) | stats = updaterepo(repo, node, True) | ||||
| repo.vfs.unlinkpath('graftstate', ignoremissing=True) | repo.vfs.unlinkpath('graftstate', ignoremissing=True) | ||||
| if show_stats: | if show_stats: | ||||
| _showstats(repo, stats, quietempty) | _showstats(repo, stats, quietempty) | ||||
| return stats[3] > 0 | return stats.unresolvedcount > 0 | ||||
| # naming conflict in updatetotally() | # naming conflict in updatetotally() | ||||
| _clean = clean | _clean = clean | ||||
| def updatetotally(ui, repo, checkout, brev, clean=False, updatecheck=None): | def updatetotally(ui, repo, checkout, brev, clean=False, updatecheck=None): | ||||
| """Update the working directory with extra care for non-file components | """Update the working directory with extra care for non-file components | ||||
| This takes care of non-file components below: | This takes care of non-file components below: | ||||
| node = repo['.'].hex() | node = repo['.'].hex() | ||||
| repo.ui.status(_("aborting the merge, updating back to" | repo.ui.status(_("aborting the merge, updating back to" | ||||
| " %s\n") % node[:12]) | " %s\n") % node[:12]) | ||||
| stats = mergemod.update(repo, node, branchmerge=False, force=True, | stats = mergemod.update(repo, node, branchmerge=False, force=True, | ||||
| labels=labels) | labels=labels) | ||||
| _showstats(repo, stats) | _showstats(repo, stats) | ||||
| if stats[3]: | if stats.unresolvedcount: | ||||
| repo.ui.status(_("use 'hg resolve' to retry unresolved file merges " | repo.ui.status(_("use 'hg resolve' to retry unresolved file merges " | ||||
| "or 'hg merge --abort' to abandon\n")) | "or 'hg merge --abort' to abandon\n")) | ||||
| elif remind and not abort: | elif remind and not abort: | ||||
| repo.ui.status(_("(branch merge, don't forget to commit)\n")) | repo.ui.status(_("(branch merge, don't forget to commit)\n")) | ||||
| return stats[3] > 0 | return stats.unresolvedcount > 0 | ||||
| def _incoming(displaychlist, subreporecurse, ui, repo, source, | def _incoming(displaychlist, subreporecurse, ui, repo, source, | ||||
| opts, buffered=False): | opts, buffered=False): | ||||
| """ | """ | ||||
| Helper for incoming / gincoming. | Helper for incoming / gincoming. | ||||
| displaychlist gets called with | displaychlist gets called with | ||||
| (remoterepo, incomingchangesetlist, displayer) parameters, | (remoterepo, incomingchangesetlist, displayer) parameters, | ||||
| and is supposed to contain only code that can't be unified. | and is supposed to contain only code that can't be unified. | ||||
| @attr.s(frozen=True) | @attr.s(frozen=True) | ||||
| class updateresult(object): | class updateresult(object): | ||||
| updatedcount = attr.ib() | updatedcount = attr.ib() | ||||
| mergedcount = attr.ib() | mergedcount = attr.ib() | ||||
| removedcount = attr.ib() | removedcount = attr.ib() | ||||
| unresolvedcount = attr.ib() | unresolvedcount = attr.ib() | ||||
| def isempty(self): | |||||
| return (not self.updatedcount and not self.mergedcount | |||||
| and not self.removedcount and not self.unresolvedcount) | |||||
| # TODO remove container emulation once consumers switch to new API. | # TODO remove container emulation once consumers switch to new API. | ||||
| def __getitem__(self, x): | def __getitem__(self, x): | ||||
| util.nouideprecwarn('access merge.update() results by name instead of ' | |||||
| 'index', '4.6', 2) | |||||
| if x == 0: | if x == 0: | ||||
| return self.updatedcount | return self.updatedcount | ||||
| elif x == 1: | elif x == 1: | ||||
| return self.mergedcount | return self.mergedcount | ||||
| elif x == 2: | elif x == 2: | ||||
| return self.removedcount | return self.removedcount | ||||
| elif x == 3: | elif x == 3: | ||||
| return self.unresolvedcount | return self.unresolvedcount | ||||
| else: | else: | ||||
| raise IndexError('can only access items 0-3') | raise IndexError('can only access items 0-3') | ||||
| def __len__(self): | def __len__(self): | ||||
| util.nouideprecwarn('access merge.update() results by name instead of ' | |||||
| 'index', '4.6', 2) | |||||
| return 4 | return 4 | ||||
| def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None): | def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None): | ||||
| """apply the merge action list to the working directory | """apply the merge action list to the working directory | ||||
| wctx is the working copy context | wctx is the working copy context | ||||
| mctx is the context to be merged into the working copy | mctx is the context to be merged into the working copy | ||||
| repo.dirstate.setbranch(p2.branch()) | repo.dirstate.setbranch(p2.branch()) | ||||
| # If we're updating to a location, clean up any stale temporary includes | # If we're updating to a location, clean up any stale temporary includes | ||||
| # (ex: this happens during hg rebase --abort). | # (ex: this happens during hg rebase --abort). | ||||
| if not branchmerge: | if not branchmerge: | ||||
| sparse.prunetemporaryincludes(repo) | sparse.prunetemporaryincludes(repo) | ||||
| if not partial: | if not partial: | ||||
| repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3]) | repo.hook('update', parent1=xp1, parent2=xp2, | ||||
| error=stats.unresolvedcount) | |||||
| return stats | return stats | ||||
| def graft(repo, ctx, pctx, labels, keepparent=False): | def graft(repo, ctx, pctx, labels, keepparent=False): | ||||
| """Do a graft-like merge. | """Do a graft-like merge. | ||||
| This is a merge where the merge ancestor is chosen such that one | This is a merge where the merge ancestor is chosen such that one | ||||
| or more changesets are grafted onto the current changeset. In | or more changesets are grafted onto the current changeset. In | ||||
| addition to the merge, this fixes up the dirstate to include only | addition to the merge, this fixes up the dirstate to include only | ||||