comparison hgext3rd/topic/discovery.py @ 6364:e8d85d51c7b2 stable

topic: monkey-patch ctx.branch() correctly in override_context_branch There's a `for p in ctx.parents()` loop in this block of code, and it's used to monkey-patch .branch() method for both parents of ctx. It assigns each parent of ctx to variable `p` (implicitly) and p.branch method to variable `pbranch` (explicitly). This worked fine when there's only one p1, but when there were 2 parents, this code was broken, and our tests didn't catch this because the use of override_context_branch context manager is quite limited. The problem is that the newly created function uses `p` and `pbranch`, and the closures for the new p1.branch() and p2.branch() didn't get created until the for-loop finished, and the values `p` and `pbranch` could change before that. In other words, the new .branch method of p1 was effectively identical to p2's because the values that were available to it were from the second cycle of the for-loop, when it the loop was at p2. Now we pass the values to a function that creates the new .branch methods, and since these values are provided to overridebranch() as arguments, they get enclosed when the function returns. This was seen (and tested) during topic namespaces-related work, when override_context_branch usage was expanded to include some local operations.
author Anton Shestakov <av6@dwimlabs.net>
date Thu, 15 Dec 2022 17:07:25 +0400
parents 885a972d5069
children 3271ec128328
comparison
equal deleted inserted replaced
6363:f168c0fdbde9 6364:e8d85d51c7b2
23 23
24 @contextlib.contextmanager 24 @contextlib.contextmanager
25 def override_context_branch(repo, publishedset=()): 25 def override_context_branch(repo, publishedset=()):
26 unfi = repo.unfiltered() 26 unfi = repo.unfiltered()
27 27
28 def overridebranch(p, origbranch):
29 def branch():
30 b = origbranch()
31 if p.rev() in publishedset:
32 return b
33 t = p.topic()
34 if t:
35 b = b"%s:%s" % (b, t)
36 return b
37 return branch
38
28 class repocls(unfi.__class__): 39 class repocls(unfi.__class__):
29 # awful hack to see branch as "branch:topic" 40 # awful hack to see branch as "branch:topic"
30 def __getitem__(self, key): 41 def __getitem__(self, key):
31 ctx = super(repocls, self).__getitem__(key) 42 ctx = super(repocls, self).__getitem__(key)
32 oldbranch = ctx.branch 43 oldbranch = ctx.branch
45 def parents(): 56 def parents():
46 parents = oldparents() 57 parents = oldparents()
47 for p in parents: 58 for p in parents:
48 if getattr(p, '_topic_ext_branch_hack', False): 59 if getattr(p, '_topic_ext_branch_hack', False):
49 continue 60 continue
50 pbranch = p.branch 61
51 62 p.branch = overridebranch(p, p.branch)
52 def branch():
53 branch = pbranch()
54 if p.rev() in publishedset:
55 return branch
56 topic = p.topic()
57 if topic:
58 branch = b"%s:%s" % (branch, topic)
59 return branch
60 p.branch = branch
61 p._topic_ext_branch_hack = True 63 p._topic_ext_branch_hack = True
62 return parents 64 return parents
63 65
64 ctx.branch = branch 66 ctx.branch = branch
65 ctx.parents = parents 67 ctx.parents = parents