##// END OF EJS Templates
repair: do not compress partial bundle if we do not keep it on disk...
Nicolas Dumazet -
r11791:00cde9bd default
parent child Browse files
Show More
@@ -1,160 +1,167
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 or any later version.
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 def _bundle(repo, bases, heads, node, suffix, extranodes=None):
14 def _bundle(repo, bases, heads, node, suffix, extranodes=None, compress=True):
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.hg" % (short(node), suffix))
21 return changegroup.writebundle(cg, name, "HG10BZ")
21 if compress:
22 bundletype = "HG10BZ"
23 else:
24 bundletype = "HG10UN"
25 return changegroup.writebundle(cg, name, bundletype)
22 26
23 27 def _collectfiles(repo, striprev):
24 28 """find out the filelogs affected by the strip"""
25 29 files = set()
26 30
27 31 for x in xrange(striprev, len(repo)):
28 32 files.update(repo[x].files())
29 33
30 34 return sorted(files)
31 35
32 36 def _collectextranodes(repo, files, link):
33 37 """return the nodes that have to be saved before the strip"""
34 38 def collectone(revlog):
35 39 extra = []
36 40 startrev = count = len(revlog)
37 41 # find the truncation point of the revlog
38 42 for i in xrange(count):
39 43 lrev = revlog.linkrev(i)
40 44 if lrev >= link:
41 45 startrev = i + 1
42 46 break
43 47
44 48 # see if any revision after that point has a linkrev less than link
45 49 # (we have to manually save these guys)
46 50 for i in xrange(startrev, count):
47 51 node = revlog.node(i)
48 52 lrev = revlog.linkrev(i)
49 53 if lrev < link:
50 54 extra.append((node, cl.node(lrev)))
51 55
52 56 return extra
53 57
54 58 extranodes = {}
55 59 cl = repo.changelog
56 60 extra = collectone(repo.manifest)
57 61 if extra:
58 62 extranodes[1] = extra
59 63 for fname in files:
60 64 f = repo.file(fname)
61 65 extra = collectone(f)
62 66 if extra:
63 67 extranodes[fname] = extra
64 68
65 69 return extranodes
66 70
67 71 def strip(ui, repo, node, backup="all"):
68 72 cl = repo.changelog
69 73 # TODO delete the undo files, and handle undo of merge sets
70 74 striprev = cl.rev(node)
71 75
76 keeppartialbundle = backup == 'strip'
77
72 78 # Some revisions with rev > striprev may not be descendants of striprev.
73 79 # We have to find these revisions and put them in a bundle, so that
74 80 # we can restore them after the truncations.
75 81 # To create the bundle we use repo.changegroupsubset which requires
76 82 # the list of heads and bases of the set of interesting revisions.
77 83 # (head = revision in the set that has no descendant in the set;
78 84 # base = revision in the set that has no ancestor in the set)
79 85 tostrip = set((striprev,))
80 86 saveheads = set()
81 87 savebases = []
82 88 for r in xrange(striprev + 1, len(cl)):
83 89 parents = cl.parentrevs(r)
84 90 if parents[0] in tostrip or parents[1] in tostrip:
85 91 # r is a descendant of striprev
86 92 tostrip.add(r)
87 93 # if this is a merge and one of the parents does not descend
88 94 # from striprev, mark that parent as a savehead.
89 95 if parents[1] != nullrev:
90 96 for p in parents:
91 97 if p not in tostrip and p > striprev:
92 98 saveheads.add(p)
93 99 else:
94 100 # if no parents of this revision will be stripped, mark it as
95 101 # a savebase
96 102 if parents[0] < striprev and parents[1] < striprev:
97 103 savebases.append(cl.node(r))
98 104
99 105 saveheads.difference_update(parents)
100 106 saveheads.add(r)
101 107
102 108 saveheads = [cl.node(r) for r in saveheads]
103 109 files = _collectfiles(repo, striprev)
104 110
105 111 extranodes = _collectextranodes(repo, files, striprev)
106 112
107 113 # create a changegroup for all the branches we need to keep
108 114 backupfile = None
109 115 if backup == "all":
110 116 backupfile = _bundle(repo, [node], cl.heads(), node, 'backup')
111 117 repo.ui.status(_("saved backup bundle to %s\n") % backupfile)
112 118 if saveheads or extranodes:
119 # do not compress partial bundle if we remove it from disk later
113 120 chgrpfile = _bundle(repo, savebases, saveheads, node, 'temp',
114 extranodes)
121 extranodes=extranodes, compress=keeppartialbundle)
115 122
116 123 mfst = repo.manifest
117 124
118 125 tr = repo.transaction("strip")
119 126 offset = len(tr.entries)
120 127
121 128 try:
122 129 tr.startgroup()
123 130 cl.strip(striprev, tr)
124 131 mfst.strip(striprev, tr)
125 132 for fn in files:
126 133 repo.file(fn).strip(striprev, tr)
127 134 tr.endgroup()
128 135
129 136 try:
130 137 for i in xrange(offset, len(tr.entries)):
131 138 file, troffset, ignore = tr.entries[i]
132 139 repo.sopener(file, 'a').truncate(troffset)
133 140 tr.close()
134 141 except:
135 142 tr.abort()
136 143 raise
137 144
138 145 if saveheads or extranodes:
139 146 ui.note(_("adding branch\n"))
140 147 f = open(chgrpfile, "rb")
141 148 gen = changegroup.readbundle(f, chgrpfile)
142 149 if not repo.ui.verbose:
143 150 # silence internal shuffling chatter
144 151 repo.ui.pushbuffer()
145 152 repo.addchangegroup(gen, 'strip', 'bundle:' + chgrpfile, True)
146 153 if not repo.ui.verbose:
147 154 repo.ui.popbuffer()
148 155 f.close()
149 if backup != "strip":
156 if not keeppartialbundle:
150 157 os.unlink(chgrpfile)
151 158 except:
152 159 if backupfile:
153 160 ui.warn(_("strip failed, full bundle stored in '%s'\n")
154 161 % backupfile)
155 162 elif saveheads:
156 163 ui.warn(_("strip failed, partial bundle stored in '%s'\n")
157 164 % chgrpfile)
158 165 raise
159 166
160 167 repo.destroyed()
General Comments 0
You need to be logged in to leave comments. Login now