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