##// END OF EJS Templates
repair: bulk update sets...
Martin Geisler -
r8479:3e16c0fc default
parent child Browse files
Show More
@@ -1,149 +1,145
1 1 # repair.py - functions for repository repair for mercurial
2 2 #
3 3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
4 4 # Copyright 2007 Matt Mackall
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2, incorporated herein by reference.
8 8
9 9 import changegroup
10 10 from node import nullrev, short
11 11 from i18n import _
12 12 import os
13 13
14 14 def _bundle(repo, bases, heads, node, suffix, extranodes=None):
15 15 """create a bundle with the specified revisions as a backup"""
16 16 cg = repo.changegroupsubset(bases, heads, 'strip', extranodes)
17 17 backupdir = repo.join("strip-backup")
18 18 if not os.path.isdir(backupdir):
19 19 os.mkdir(backupdir)
20 20 name = os.path.join(backupdir, "%s-%s" % (short(node), suffix))
21 21 repo.ui.warn(_("saving bundle to %s\n") % name)
22 22 return changegroup.writebundle(cg, name, "HG10BZ")
23 23
24 24 def _collectfiles(repo, striprev):
25 25 """find out the filelogs affected by the strip"""
26 26 files = set()
27 27
28 28 for x in xrange(striprev, len(repo)):
29 for name in repo[x].files():
30 if name in files:
31 continue
32 files.add(name)
29 files.update(repo[x].files())
33 30
34 31 return sorted(files)
35 32
36 33 def _collectextranodes(repo, files, link):
37 34 """return the nodes that have to be saved before the strip"""
38 35 def collectone(revlog):
39 36 extra = []
40 37 startrev = count = len(revlog)
41 38 # find the truncation point of the revlog
42 39 for i in xrange(0, count):
43 40 lrev = revlog.linkrev(i)
44 41 if lrev >= link:
45 42 startrev = i + 1
46 43 break
47 44
48 45 # see if any revision after that point has a linkrev less than link
49 46 # (we have to manually save these guys)
50 47 for i in xrange(startrev, count):
51 48 node = revlog.node(i)
52 49 lrev = revlog.linkrev(i)
53 50 if lrev < link:
54 51 extra.append((node, cl.node(lrev)))
55 52
56 53 return extra
57 54
58 55 extranodes = {}
59 56 cl = repo.changelog
60 57 extra = collectone(repo.manifest)
61 58 if extra:
62 59 extranodes[1] = extra
63 60 for fname in files:
64 61 f = repo.file(fname)
65 62 extra = collectone(f)
66 63 if extra:
67 64 extranodes[fname] = extra
68 65
69 66 return extranodes
70 67
71 68 def strip(ui, repo, node, backup="all"):
72 69 cl = repo.changelog
73 70 # TODO delete the undo files, and handle undo of merge sets
74 71 striprev = cl.rev(node)
75 72
76 73 # Some revisions with rev > striprev may not be descendants of striprev.
77 74 # We have to find these revisions and put them in a bundle, so that
78 75 # we can restore them after the truncations.
79 76 # To create the bundle we use repo.changegroupsubset which requires
80 77 # the list of heads and bases of the set of interesting revisions.
81 78 # (head = revision in the set that has no descendant in the set;
82 79 # base = revision in the set that has no ancestor in the set)
83 80 tostrip = set((striprev,))
84 81 saveheads = set()
85 82 savebases = []
86 83 for r in xrange(striprev + 1, len(cl)):
87 84 parents = cl.parentrevs(r)
88 85 if parents[0] in tostrip or parents[1] in tostrip:
89 86 # r is a descendant of striprev
90 87 tostrip.add(r)
91 88 # if this is a merge and one of the parents does not descend
92 89 # from striprev, mark that parent as a savehead.
93 90 if parents[1] != nullrev:
94 91 for p in parents:
95 92 if p not in tostrip and p > striprev:
96 93 saveheads.add(p)
97 94 else:
98 95 # if no parents of this revision will be stripped, mark it as
99 96 # a savebase
100 97 if parents[0] < striprev and parents[1] < striprev:
101 98 savebases.append(cl.node(r))
102 99
103 for p in parents:
104 saveheads.discard(p)
100 saveheads.difference_update(parents)
105 101 saveheads.add(r)
106 102
107 103 saveheads = [cl.node(r) for r in saveheads]
108 104 files = _collectfiles(repo, striprev)
109 105
110 106 extranodes = _collectextranodes(repo, files, striprev)
111 107
112 108 # create a changegroup for all the branches we need to keep
113 109 if backup == "all":
114 110 _bundle(repo, [node], cl.heads(), node, 'backup')
115 111 if saveheads or extranodes:
116 112 chgrpfile = _bundle(repo, savebases, saveheads, node, 'temp',
117 113 extranodes)
118 114
119 115 fs = [repo.file(name) for name in files]
120 116 mfst = repo.manifest
121 117
122 118 tr = repo.transaction()
123 119 offset = len(tr.entries)
124 120
125 121 tr.startgroup()
126 122 cl.strip(striprev, tr)
127 123 mfst.strip(striprev, tr)
128 124 for f in fs:
129 125 f.strip(striprev, tr)
130 126 tr.endgroup()
131 127
132 128 try:
133 129 for i in xrange(offset, len(tr.entries)):
134 130 file, troffset, ignore = tr.entries[i]
135 131 repo.sopener(file, 'a').truncate(troffset)
136 132 tr.close()
137 133 except:
138 134 tr.abort()
139 135 raise
140 136
141 137 if saveheads or extranodes:
142 138 ui.status(_("adding branch\n"))
143 139 f = open(chgrpfile, "rb")
144 140 gen = changegroup.readbundle(f, chgrpfile)
145 141 repo.addchangegroup(gen, 'strip', 'bundle:' + chgrpfile, True)
146 142 f.close()
147 143 if backup != "strip":
148 144 os.unlink(chgrpfile)
149 145
General Comments 0
You need to be logged in to leave comments. Login now