Show More
@@ -0,0 +1,94 b'' | |||
|
1 | """revset to select sample of repository | |
|
2 | ||
|
3 | Hopefully this is useful to create interesting discovery cases. | |
|
4 | """ | |
|
5 | ||
|
6 | import collections | |
|
7 | import random | |
|
8 | ||
|
9 | from mercurial.i18n import _ | |
|
10 | ||
|
11 | from mercurial import ( | |
|
12 | registrar, | |
|
13 | revset, | |
|
14 | revsetlang, | |
|
15 | smartset, | |
|
16 | ) | |
|
17 | ||
|
18 | revsetpredicate = registrar.revsetpredicate() | |
|
19 | ||
|
20 | ||
|
21 | @revsetpredicate(b'scratch(REVS, <count>, [seed])') | |
|
22 | def scratch(repo, subset, x): | |
|
23 | """randomly remove <count> revision from the repository top | |
|
24 | ||
|
25 | This subset is created by recursively picking changeset starting from the | |
|
26 | heads. It can be summarized using the following algorithm:: | |
|
27 | ||
|
28 | selected = set() | |
|
29 | for i in range(<count>): | |
|
30 | unselected = repo.revs("not <selected>") | |
|
31 | candidates = repo.revs("heads(<unselected>)") | |
|
32 | pick = random.choice(candidates) | |
|
33 | selected.add(pick) | |
|
34 | """ | |
|
35 | m = _(b"scratch expects revisions, count argument and an optional seed") | |
|
36 | args = revsetlang.getargs(x, 2, 3, m) | |
|
37 | if len(args) == 2: | |
|
38 | x, n = args | |
|
39 | rand = random | |
|
40 | elif len(args) == 3: | |
|
41 | x, n, seed = args | |
|
42 | seed = revsetlang.getinteger(seed, _(b"seed should be a number")) | |
|
43 | rand = random.Random(seed) | |
|
44 | else: | |
|
45 | assert False | |
|
46 | ||
|
47 | n = revsetlang.getinteger(n, _(b"scratch expects a number")) | |
|
48 | ||
|
49 | selected = set() | |
|
50 | heads = set() | |
|
51 | children_count = collections.defaultdict(lambda: 0) | |
|
52 | parents = repo.changelog._uncheckedparentrevs | |
|
53 | ||
|
54 | baseset = revset.getset(repo, smartset.fullreposet(repo), x) | |
|
55 | baseset.sort() | |
|
56 | for r in baseset: | |
|
57 | heads.add(r) | |
|
58 | ||
|
59 | p1, p2 = parents(r) | |
|
60 | if p1 >= 0: | |
|
61 | heads.discard(p1) | |
|
62 | children_count[p1] += 1 | |
|
63 | if p2 >= 0: | |
|
64 | heads.discard(p2) | |
|
65 | children_count[p2] += 1 | |
|
66 | ||
|
67 | for h in heads: | |
|
68 | assert children_count[h] == 0 | |
|
69 | ||
|
70 | selected = set() | |
|
71 | for x in range(n): | |
|
72 | if not heads: | |
|
73 | break | |
|
74 | pick = rand.choice(list(heads)) | |
|
75 | heads.remove(pick) | |
|
76 | assert pick not in selected | |
|
77 | selected.add(pick) | |
|
78 | p1, p2 = parents(pick) | |
|
79 | if p1 in children_count: | |
|
80 | assert p1 in children_count | |
|
81 | children_count[p1] -= 1 | |
|
82 | assert children_count[p1] >= 0 | |
|
83 | if children_count[p1] == 0: | |
|
84 | assert p1 not in selected, (r, p1) | |
|
85 | heads.add(p1) | |
|
86 | if p2 in children_count: | |
|
87 | assert p2 in children_count | |
|
88 | children_count[p2] -= 1 | |
|
89 | assert children_count[p2] >= 0 | |
|
90 | if children_count[p2] == 0: | |
|
91 | assert p2 not in selected, (r, p2) | |
|
92 | heads.add(p2) | |
|
93 | ||
|
94 | return smartset.baseset(selected) & subset |
General Comments 0
You need to be logged in to leave comments.
Login now