Mercurial > public > mercurial-scm > hg
comparison mercurial/merge.py @ 37107:71543b942eea
merge: return an attrs class from update() and applyupdates()
Previously, we returned a tuple containing counts. The result of an
update is kind of complex and the use of tuples with nameless fields
made the code a bit harder to read and constrained future expansion
of the return value.
Let's invent an attrs-defined class for representing the result of
an update operation.
We provide __getitem__ and __len__ implementations for backwards
compatibility as a container type to minimize code churn.
In (at least) Python 2, the % operator seems to insist on using
tuples. So we had to update a consumer using the % operator.
.. api::
merge.update() and merge.applyupdates() now return a class
with named attributes instead of a tuple. Switch consumers
to access elements by name instead of by offset.
Differential Revision: https://phab.mercurial-scm.org/D2692
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Mon, 05 Mar 2018 00:02:13 -0500 |
parents | e4640ec346ac |
children | a532b2f54f95 |
comparison
equal
deleted
inserted
replaced
37106:3d3cff1f6bde | 37107:71543b942eea |
---|---|
19 hex, | 19 hex, |
20 modifiednodeid, | 20 modifiednodeid, |
21 nullhex, | 21 nullhex, |
22 nullid, | 22 nullid, |
23 nullrev, | 23 nullrev, |
24 ) | |
25 from .thirdparty import ( | |
26 attr, | |
24 ) | 27 ) |
25 from . import ( | 28 from . import ( |
26 copies, | 29 copies, |
27 error, | 30 error, |
28 filemerge, | 31 filemerge, |
1396 # changed/deleted never resolves to something from the remote side. | 1399 # changed/deleted never resolves to something from the remote side. |
1397 oplist = [actions[a] for a in 'g dc dg m'.split()] | 1400 oplist = [actions[a] for a in 'g dc dg m'.split()] |
1398 prefetch = scmutil.fileprefetchhooks | 1401 prefetch = scmutil.fileprefetchhooks |
1399 prefetch(repo, ctx, [f for sublist in oplist for f, args, msg in sublist]) | 1402 prefetch(repo, ctx, [f for sublist in oplist for f, args, msg in sublist]) |
1400 | 1403 |
1404 @attr.s(frozen=True) | |
1405 class updateresult(object): | |
1406 updatedcount = attr.ib() | |
1407 mergedcount = attr.ib() | |
1408 removedcount = attr.ib() | |
1409 unresolvedcount = attr.ib() | |
1410 | |
1411 # TODO remove container emulation once consumers switch to new API. | |
1412 | |
1413 def __getitem__(self, x): | |
1414 if x == 0: | |
1415 return self.updatedcount | |
1416 elif x == 1: | |
1417 return self.mergedcount | |
1418 elif x == 2: | |
1419 return self.removedcount | |
1420 elif x == 3: | |
1421 return self.unresolvedcount | |
1422 else: | |
1423 raise IndexError('can only access items 0-3') | |
1424 | |
1425 def __len__(self): | |
1426 return 4 | |
1427 | |
1401 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None): | 1428 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None): |
1402 """apply the merge action list to the working directory | 1429 """apply the merge action list to the working directory |
1403 | 1430 |
1404 wctx is the working copy context | 1431 wctx is the working copy context |
1405 mctx is the context to be merged into the working copy | 1432 mctx is the context to be merged into the working copy |
1579 # the driver might leave some files unresolved | 1606 # the driver might leave some files unresolved |
1580 unresolvedf = set(ms.unresolved()) | 1607 unresolvedf = set(ms.unresolved()) |
1581 if not proceed: | 1608 if not proceed: |
1582 # XXX setting unresolved to at least 1 is a hack to make sure we | 1609 # XXX setting unresolved to at least 1 is a hack to make sure we |
1583 # error out | 1610 # error out |
1584 return updated, merged, removed, max(len(unresolvedf), 1) | 1611 return updateresult(updated, merged, removed, |
1612 max(len(unresolvedf), 1)) | |
1585 newactions = [] | 1613 newactions = [] |
1586 for f, args, msg in mergeactions: | 1614 for f, args, msg in mergeactions: |
1587 if f in unresolvedf: | 1615 if f in unresolvedf: |
1588 newactions.append((f, args, msg)) | 1616 newactions.append((f, args, msg)) |
1589 mergeactions = newactions | 1617 mergeactions = newactions |
1654 mfiles.difference_update(a[0] for a in acts) | 1682 mfiles.difference_update(a[0] for a in acts) |
1655 | 1683 |
1656 actions['m'] = [a for a in actions['m'] if a[0] in mfiles] | 1684 actions['m'] = [a for a in actions['m'] if a[0] in mfiles] |
1657 | 1685 |
1658 progress(_updating, None, total=numupdates, unit=_files) | 1686 progress(_updating, None, total=numupdates, unit=_files) |
1659 | 1687 return updateresult(updated, merged, removed, unresolved) |
1660 return updated, merged, removed, unresolved | |
1661 | 1688 |
1662 def recordupdates(repo, actions, branchmerge): | 1689 def recordupdates(repo, actions, branchmerge): |
1663 "record merge actions to the dirstate" | 1690 "record merge actions to the dirstate" |
1664 # remove (must come first) | 1691 # remove (must come first) |
1665 for f, args, msg in actions.get('r', []): | 1692 for f, args, msg in actions.get('r', []): |
1876 elif not overwrite: | 1903 elif not overwrite: |
1877 if p1 == p2: # no-op update | 1904 if p1 == p2: # no-op update |
1878 # call the hooks and exit early | 1905 # call the hooks and exit early |
1879 repo.hook('preupdate', throw=True, parent1=xp2, parent2='') | 1906 repo.hook('preupdate', throw=True, parent1=xp2, parent2='') |
1880 repo.hook('update', parent1=xp2, parent2='', error=0) | 1907 repo.hook('update', parent1=xp2, parent2='', error=0) |
1881 return 0, 0, 0, 0 | 1908 return updateresult(0, 0, 0, 0) |
1882 | 1909 |
1883 if (updatecheck == 'linear' and | 1910 if (updatecheck == 'linear' and |
1884 pas not in ([p1], [p2])): # nonlinear | 1911 pas not in ([p1], [p2])): # nonlinear |
1885 dirty = wc.dirty(missing=True) | 1912 dirty = wc.dirty(missing=True) |
1886 if dirty: | 1913 if dirty: |