##// END OF EJS Templates
bundlerepo: fix inconsistency of parsed and internal name (issue #821)
Peter Arrenbrecht -
r6129:3d666e8e default
parent child Browse files
Show More
@@ -1,280 +1,282 b''
1 1 """
2 2 bundlerepo.py - repository class for viewing uncompressed bundles
3 3
4 4 This provides a read-only repository interface to bundles as if
5 5 they were part of the actual repository.
6 6
7 7 Copyright 2006, 2007 Benoit Boissinot <bboissin@gmail.com>
8 8
9 9 This software may be used and distributed according to the terms
10 10 of the GNU General Public License, incorporated herein by reference.
11 11 """
12 12
13 13 from node import *
14 14 from i18n import _
15 15 import changegroup, util, os, struct, bz2, tempfile, mdiff
16 16 import localrepo, changelog, manifest, filelog, revlog
17 17
18 18 class bundlerevlog(revlog.revlog):
19 19 def __init__(self, opener, indexfile, bundlefile,
20 20 linkmapper=None):
21 21 # How it works:
22 22 # to retrieve a revision, we need to know the offset of
23 23 # the revision in the bundlefile (an opened file).
24 24 #
25 25 # We store this offset in the index (start), to differentiate a
26 26 # rev in the bundle and from a rev in the revlog, we check
27 27 # len(index[r]). If the tuple is bigger than 7, it is a bundle
28 28 # (it is bigger since we store the node to which the delta is)
29 29 #
30 30 revlog.revlog.__init__(self, opener, indexfile)
31 31 self.bundlefile = bundlefile
32 32 self.basemap = {}
33 33 def chunkpositer():
34 34 for chunk in changegroup.chunkiter(bundlefile):
35 35 pos = bundlefile.tell()
36 36 yield chunk, pos - len(chunk)
37 37 n = self.count()
38 38 prev = None
39 39 for chunk, start in chunkpositer():
40 40 size = len(chunk)
41 41 if size < 80:
42 42 raise util.Abort("invalid changegroup")
43 43 start += 80
44 44 size -= 80
45 45 node, p1, p2, cs = struct.unpack("20s20s20s20s", chunk[:80])
46 46 if node in self.nodemap:
47 47 prev = node
48 48 continue
49 49 for p in (p1, p2):
50 50 if not p in self.nodemap:
51 51 raise revlog.LookupError(hex(p1), _("unknown parent %s") % short(p1))
52 52 if linkmapper is None:
53 53 link = n
54 54 else:
55 55 link = linkmapper(cs)
56 56
57 57 if not prev:
58 58 prev = p1
59 59 # start, size, full unc. size, base (unused), link, p1, p2, node
60 60 e = (revlog.offset_type(start, 0), size, -1, -1, link,
61 61 self.rev(p1), self.rev(p2), node)
62 62 self.basemap[n] = prev
63 63 self.index.insert(-1, e)
64 64 self.nodemap[node] = n
65 65 prev = node
66 66 n += 1
67 67
68 68 def bundle(self, rev):
69 69 """is rev from the bundle"""
70 70 if rev < 0:
71 71 return False
72 72 return rev in self.basemap
73 73 def bundlebase(self, rev): return self.basemap[rev]
74 74 def chunk(self, rev, df=None, cachelen=4096):
75 75 # Warning: in case of bundle, the diff is against bundlebase,
76 76 # not against rev - 1
77 77 # XXX: could use some caching
78 78 if not self.bundle(rev):
79 79 return revlog.revlog.chunk(self, rev, df)
80 80 self.bundlefile.seek(self.start(rev))
81 81 return self.bundlefile.read(self.length(rev))
82 82
83 83 def revdiff(self, rev1, rev2):
84 84 """return or calculate a delta between two revisions"""
85 85 if self.bundle(rev1) and self.bundle(rev2):
86 86 # hot path for bundle
87 87 revb = self.rev(self.bundlebase(rev2))
88 88 if revb == rev1:
89 89 return self.chunk(rev2)
90 90 elif not self.bundle(rev1) and not self.bundle(rev2):
91 91 return revlog.revlog.revdiff(self, rev1, rev2)
92 92
93 93 return mdiff.textdiff(self.revision(self.node(rev1)),
94 94 self.revision(self.node(rev2)))
95 95
96 96 def revision(self, node):
97 97 """return an uncompressed revision of a given"""
98 98 if node == nullid: return ""
99 99
100 100 text = None
101 101 chain = []
102 102 iter_node = node
103 103 rev = self.rev(iter_node)
104 104 # reconstruct the revision if it is from a changegroup
105 105 while self.bundle(rev):
106 106 if self._cache and self._cache[0] == iter_node:
107 107 text = self._cache[2]
108 108 break
109 109 chain.append(rev)
110 110 iter_node = self.bundlebase(rev)
111 111 rev = self.rev(iter_node)
112 112 if text is None:
113 113 text = revlog.revlog.revision(self, iter_node)
114 114
115 115 while chain:
116 116 delta = self.chunk(chain.pop())
117 117 text = mdiff.patches(text, [delta])
118 118
119 119 p1, p2 = self.parents(node)
120 120 if node != revlog.hash(text, p1, p2):
121 121 raise revlog.RevlogError(_("integrity check failed on %s:%d")
122 122 % (self.datafile, self.rev(node)))
123 123
124 124 self._cache = (node, self.rev(node), text)
125 125 return text
126 126
127 127 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
128 128 raise NotImplementedError
129 129 def addgroup(self, revs, linkmapper, transaction, unique=0):
130 130 raise NotImplementedError
131 131 def strip(self, rev, minlink):
132 132 raise NotImplementedError
133 133 def checksize(self):
134 134 raise NotImplementedError
135 135
136 136 class bundlechangelog(bundlerevlog, changelog.changelog):
137 137 def __init__(self, opener, bundlefile):
138 138 changelog.changelog.__init__(self, opener)
139 139 bundlerevlog.__init__(self, opener, self.indexfile, bundlefile)
140 140
141 141 class bundlemanifest(bundlerevlog, manifest.manifest):
142 142 def __init__(self, opener, bundlefile, linkmapper):
143 143 manifest.manifest.__init__(self, opener)
144 144 bundlerevlog.__init__(self, opener, self.indexfile, bundlefile,
145 145 linkmapper)
146 146
147 147 class bundlefilelog(bundlerevlog, filelog.filelog):
148 148 def __init__(self, opener, path, bundlefile, linkmapper):
149 149 filelog.filelog.__init__(self, opener, path)
150 150 bundlerevlog.__init__(self, opener, self.indexfile, bundlefile,
151 151 linkmapper)
152 152
153 153 class bundlerepository(localrepo.localrepository):
154 154 def __init__(self, ui, path, bundlename):
155 155 localrepo.localrepository.__init__(self, ui, path)
156 156
157 self._url = 'bundle:' + bundlename
158 if path: self._url += '+' + path
157 if path:
158 self._url = 'bundle:' + path + '+' + bundlename
159 else:
160 self._url = 'bundle:' + bundlename
159 161
160 162 self.tempfile = None
161 163 self.bundlefile = open(bundlename, "rb")
162 164 header = self.bundlefile.read(6)
163 165 if not header.startswith("HG"):
164 166 raise util.Abort(_("%s: not a Mercurial bundle file") % bundlename)
165 167 elif not header.startswith("HG10"):
166 168 raise util.Abort(_("%s: unknown bundle version") % bundlename)
167 169 elif header == "HG10BZ":
168 170 fdtemp, temp = tempfile.mkstemp(prefix="hg-bundle-",
169 171 suffix=".hg10un", dir=self.path)
170 172 self.tempfile = temp
171 173 fptemp = os.fdopen(fdtemp, 'wb')
172 174 def generator(f):
173 175 zd = bz2.BZ2Decompressor()
174 176 zd.decompress("BZ")
175 177 for chunk in f:
176 178 yield zd.decompress(chunk)
177 179 gen = generator(util.filechunkiter(self.bundlefile, 4096))
178 180
179 181 try:
180 182 fptemp.write("HG10UN")
181 183 for chunk in gen:
182 184 fptemp.write(chunk)
183 185 finally:
184 186 fptemp.close()
185 187 self.bundlefile.close()
186 188
187 189 self.bundlefile = open(self.tempfile, "rb")
188 190 # seek right after the header
189 191 self.bundlefile.seek(6)
190 192 elif header == "HG10UN":
191 193 # nothing to do
192 194 pass
193 195 else:
194 196 raise util.Abort(_("%s: unknown bundle compression type")
195 197 % bundlename)
196 198 # dict with the mapping 'filename' -> position in the bundle
197 199 self.bundlefilespos = {}
198 200
199 201 def __getattr__(self, name):
200 202 if name == 'changelog':
201 203 self.changelog = bundlechangelog(self.sopener, self.bundlefile)
202 204 self.manstart = self.bundlefile.tell()
203 205 return self.changelog
204 206 if name == 'manifest':
205 207 self.bundlefile.seek(self.manstart)
206 208 self.manifest = bundlemanifest(self.sopener, self.bundlefile,
207 209 self.changelog.rev)
208 210 self.filestart = self.bundlefile.tell()
209 211 return self.manifest
210 212 if name == 'manstart':
211 213 self.changelog
212 214 return self.manstart
213 215 if name == 'filestart':
214 216 self.manifest
215 217 return self.filestart
216 218 return localrepo.localrepository.__getattr__(self, name)
217 219
218 220 def url(self):
219 221 return self._url
220 222
221 223 def dev(self):
222 224 return -1
223 225
224 226 def file(self, f):
225 227 if not self.bundlefilespos:
226 228 self.bundlefile.seek(self.filestart)
227 229 while 1:
228 230 chunk = changegroup.getchunk(self.bundlefile)
229 231 if not chunk:
230 232 break
231 233 self.bundlefilespos[chunk] = self.bundlefile.tell()
232 234 for c in changegroup.chunkiter(self.bundlefile):
233 235 pass
234 236
235 237 if f[0] == '/':
236 238 f = f[1:]
237 239 if f in self.bundlefilespos:
238 240 self.bundlefile.seek(self.bundlefilespos[f])
239 241 return bundlefilelog(self.sopener, f, self.bundlefile,
240 242 self.changelog.rev)
241 243 else:
242 244 return filelog.filelog(self.sopener, f)
243 245
244 246 def close(self):
245 247 """Close assigned bundle file immediately."""
246 248 self.bundlefile.close()
247 249
248 250 def __del__(self):
249 251 bundlefile = getattr(self, 'bundlefile', None)
250 252 if bundlefile and not bundlefile.closed:
251 253 bundlefile.close()
252 254 tempfile = getattr(self, 'tempfile', None)
253 255 if tempfile is not None:
254 256 os.unlink(tempfile)
255 257
256 258 def instance(ui, path, create):
257 259 if create:
258 260 raise util.Abort(_('cannot create new bundle repository'))
259 261 parentpath = ui.config("bundle", "mainreporoot", "")
260 262 if parentpath:
261 263 # Try to make the full path relative so we get a nice, short URL.
262 264 # In particular, we don't want temp dir names in test outputs.
263 265 cwd = os.getcwd()
264 266 if parentpath == cwd:
265 267 parentpath = ''
266 268 else:
267 269 cwd = os.path.join(cwd,'')
268 270 if parentpath.startswith(cwd):
269 271 parentpath = parentpath[len(cwd):]
270 272 path = util.drop_scheme('file', path)
271 273 if path.startswith('bundle:'):
272 274 path = util.drop_scheme('bundle', path)
273 275 s = path.split("+", 1)
274 276 if len(s) == 1:
275 277 repopath, bundlename = parentpath, s[0]
276 278 else:
277 279 repopath, bundlename = s
278 280 else:
279 281 repopath, bundlename = parentpath, path
280 282 return bundlerepository(ui, repopath, bundlename)
@@ -1,285 +1,285 b''
1 1 ====== Setting up test
2 2 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
3 3 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
4 4 checking changesets
5 5 checking manifests
6 6 crosschecking files in changesets and manifests
7 7 checking files
8 8 4 files, 9 changesets, 7 total revisions
9 9 ====== Bundle test to full.hg
10 10 searching for changes
11 11 9 changesets found
12 12 ====== Unbundle full.hg in test
13 13 adding changesets
14 14 adding manifests
15 15 adding file changes
16 16 added 0 changesets with 0 changes to 4 files
17 17 (run 'hg update' to get a working copy)
18 18 ====== Verify empty
19 19 changeset: -1:000000000000
20 20 tag: tip
21 21 user:
22 22 date: Thu Jan 01 00:00:00 1970 +0000
23 23
24 24 checking changesets
25 25 checking manifests
26 26 crosschecking files in changesets and manifests
27 27 checking files
28 28 0 files, 0 changesets, 0 total revisions
29 29 ====== Pull full.hg into test (using --cwd)
30 30 pulling from ../full.hg
31 31 searching for changes
32 32 no changes found
33 33 ====== Pull full.hg into empty (using --cwd)
34 34 pulling from ../full.hg
35 35 requesting all changes
36 36 adding changesets
37 37 adding manifests
38 38 adding file changes
39 39 added 9 changesets with 7 changes to 4 files (+1 heads)
40 40 (run 'hg heads' to see heads, 'hg merge' to merge)
41 41 ====== Rollback empty
42 42 rolling back last transaction
43 43 ====== Pull full.hg into empty again (using --cwd)
44 44 pulling from ../full.hg
45 45 requesting all changes
46 46 adding changesets
47 47 adding manifests
48 48 adding file changes
49 49 added 9 changesets with 7 changes to 4 files (+1 heads)
50 50 (run 'hg heads' to see heads, 'hg merge' to merge)
51 51 ====== Pull full.hg into test (using -R)
52 52 pulling from full.hg
53 53 searching for changes
54 54 no changes found
55 55 ====== Pull full.hg into empty (using -R)
56 56 pulling from full.hg
57 57 searching for changes
58 58 no changes found
59 59 ====== Rollback empty
60 60 rolling back last transaction
61 61 ====== Pull full.hg into empty again (using -R)
62 62 pulling from full.hg
63 63 requesting all changes
64 64 adding changesets
65 65 adding manifests
66 66 adding file changes
67 67 added 9 changesets with 7 changes to 4 files (+1 heads)
68 68 (run 'hg heads' to see heads, 'hg merge' to merge)
69 69 ====== Log -R full.hg in fresh empty
70 70 changeset: 8:836ac62537ab
71 71 tag: tip
72 72 parent: 3:ac69c658229d
73 73 user: test
74 74 date: Mon Jan 12 13:46:40 1970 +0000
75 75 summary: 0.3m
76 76
77 77 changeset: 7:80fe151401c2
78 78 user: test
79 79 date: Mon Jan 12 13:46:40 1970 +0000
80 80 summary: 1.3m
81 81
82 82 changeset: 6:1e3f6b843bd6
83 83 user: test
84 84 date: Mon Jan 12 13:46:40 1970 +0000
85 85 summary: 1.3
86 86
87 87 changeset: 5:024e4e7df376
88 88 user: test
89 89 date: Mon Jan 12 13:46:40 1970 +0000
90 90 summary: 1.2
91 91
92 92 changeset: 4:5f4f3ceb285e
93 93 parent: 0:5649c9d34dd8
94 94 user: test
95 95 date: Mon Jan 12 13:46:40 1970 +0000
96 96 summary: 1.1
97 97
98 98 changeset: 3:ac69c658229d
99 99 user: test
100 100 date: Mon Jan 12 13:46:40 1970 +0000
101 101 summary: 0.3
102 102
103 103 changeset: 2:d62976ca1e50
104 104 user: test
105 105 date: Mon Jan 12 13:46:40 1970 +0000
106 106 summary: 0.2
107 107
108 108 changeset: 1:10b2180f755b
109 109 user: test
110 110 date: Mon Jan 12 13:46:40 1970 +0000
111 111 summary: 0.1
112 112
113 113 changeset: 0:5649c9d34dd8
114 114 user: test
115 115 date: Mon Jan 12 13:46:40 1970 +0000
116 116 summary: 0.0
117 117
118 118 ====== Pull ../full.hg into empty (with hook)
119 119 changegroup hook: HG_NODE=5649c9d34dd87d0ecb5fd39672128376e83b22e1 HG_SOURCE=pull HG_URL=bundle:../full.hg
120 120 pulling from bundle://../full.hg
121 121 requesting all changes
122 122 adding changesets
123 123 adding manifests
124 124 adding file changes
125 125 added 9 changesets with 7 changes to 4 files (+1 heads)
126 126 (run 'hg heads' to see heads, 'hg merge' to merge)
127 127 ====== Rollback empty
128 128 rolling back last transaction
129 129 ====== Log -R bundle:empty+full.hg
130 130 8 7 6 5 4 3 2 1 0
131 131 ====== Pull full.hg into empty again (using -R; with hook)
132 changegroup hook: HG_NODE=5649c9d34dd87d0ecb5fd39672128376e83b22e1 HG_SOURCE=pull HG_URL=bundle:full.hg+empty
132 changegroup hook: HG_NODE=5649c9d34dd87d0ecb5fd39672128376e83b22e1 HG_SOURCE=pull HG_URL=bundle:empty+full.hg
133 133 pulling from full.hg
134 134 requesting all changes
135 135 adding changesets
136 136 adding manifests
137 137 adding file changes
138 138 added 9 changesets with 7 changes to 4 files (+1 heads)
139 139 (run 'hg heads' to see heads, 'hg merge' to merge)
140 140 ====== Create partial clones
141 141 requesting all changes
142 142 adding changesets
143 143 adding manifests
144 144 adding file changes
145 145 added 4 changesets with 4 changes to 1 files
146 146 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
147 147 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
148 148 ====== Log -R full.hg in partial
149 149 changeset: 8:836ac62537ab
150 150 tag: tip
151 151 parent: 3:ac69c658229d
152 152 user: test
153 153 date: Mon Jan 12 13:46:40 1970 +0000
154 154 summary: 0.3m
155 155
156 156 changeset: 7:80fe151401c2
157 157 user: test
158 158 date: Mon Jan 12 13:46:40 1970 +0000
159 159 summary: 1.3m
160 160
161 161 changeset: 6:1e3f6b843bd6
162 162 user: test
163 163 date: Mon Jan 12 13:46:40 1970 +0000
164 164 summary: 1.3
165 165
166 166 changeset: 5:024e4e7df376
167 167 user: test
168 168 date: Mon Jan 12 13:46:40 1970 +0000
169 169 summary: 1.2
170 170
171 171 changeset: 4:5f4f3ceb285e
172 172 parent: 0:5649c9d34dd8
173 173 user: test
174 174 date: Mon Jan 12 13:46:40 1970 +0000
175 175 summary: 1.1
176 176
177 177 changeset: 3:ac69c658229d
178 178 user: test
179 179 date: Mon Jan 12 13:46:40 1970 +0000
180 180 summary: 0.3
181 181
182 182 changeset: 2:d62976ca1e50
183 183 user: test
184 184 date: Mon Jan 12 13:46:40 1970 +0000
185 185 summary: 0.2
186 186
187 187 changeset: 1:10b2180f755b
188 188 user: test
189 189 date: Mon Jan 12 13:46:40 1970 +0000
190 190 summary: 0.1
191 191
192 192 changeset: 0:5649c9d34dd8
193 193 user: test
194 194 date: Mon Jan 12 13:46:40 1970 +0000
195 195 summary: 0.0
196 196
197 197 ====== Incoming full.hg in partial
198 198 comparing with bundle://../full.hg
199 199 searching for changes
200 200 changeset: 4:5f4f3ceb285e
201 201 parent: 0:5649c9d34dd8
202 202 user: test
203 203 date: Mon Jan 12 13:46:40 1970 +0000
204 204 summary: 1.1
205 205
206 206 changeset: 5:024e4e7df376
207 207 user: test
208 208 date: Mon Jan 12 13:46:40 1970 +0000
209 209 summary: 1.2
210 210
211 211 changeset: 6:1e3f6b843bd6
212 212 user: test
213 213 date: Mon Jan 12 13:46:40 1970 +0000
214 214 summary: 1.3
215 215
216 216 changeset: 7:80fe151401c2
217 217 user: test
218 218 date: Mon Jan 12 13:46:40 1970 +0000
219 219 summary: 1.3m
220 220
221 221 changeset: 8:836ac62537ab
222 222 tag: tip
223 223 parent: 3:ac69c658229d
224 224 user: test
225 225 date: Mon Jan 12 13:46:40 1970 +0000
226 226 summary: 0.3m
227 227
228 228 ====== Outgoing -R full.hg vs partial2 in partial
229 229 comparing with ../partial2
230 230 searching for changes
231 231 changeset: 4:5f4f3ceb285e
232 232 parent: 0:5649c9d34dd8
233 233 user: test
234 234 date: Mon Jan 12 13:46:40 1970 +0000
235 235 summary: 1.1
236 236
237 237 changeset: 5:024e4e7df376
238 238 user: test
239 239 date: Mon Jan 12 13:46:40 1970 +0000
240 240 summary: 1.2
241 241
242 242 changeset: 6:1e3f6b843bd6
243 243 user: test
244 244 date: Mon Jan 12 13:46:40 1970 +0000
245 245 summary: 1.3
246 246
247 247 changeset: 7:80fe151401c2
248 248 user: test
249 249 date: Mon Jan 12 13:46:40 1970 +0000
250 250 summary: 1.3m
251 251
252 252 changeset: 8:836ac62537ab
253 253 tag: tip
254 254 parent: 3:ac69c658229d
255 255 user: test
256 256 date: Mon Jan 12 13:46:40 1970 +0000
257 257 summary: 0.3m
258 258
259 259 ====== Outgoing -R does-not-exist.hg vs partial2 in partial
260 260 abort: No such file or directory: ../does-not-exist.hg
261 261 ====== Unbundle incremental bundles into fresh empty in one go
262 262 1 changesets found
263 263 1 changesets found
264 264 adding changesets
265 265 adding manifests
266 266 adding file changes
267 267 added 1 changesets with 1 changes to 1 files
268 268 adding changesets
269 269 adding manifests
270 270 adding file changes
271 271 added 1 changesets with 1 changes to 1 files
272 272 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
273 273 ====== test for 540d1059c802
274 274 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
275 275 searching for changes
276 276 1 changesets found
277 277 comparing with ../bundle.hg
278 278 searching for changes
279 279 changeset: 2:ed1b79f46b9a
280 280 tag: tip
281 281 parent: 0:bbd179dfa0a7
282 282 user: test
283 283 date: Thu Jan 01 00:00:00 1970 +0000
284 284 summary: change foo
285 285
General Comments 0
You need to be logged in to leave comments. Login now