1 from __future__ import absolute_import |
1 from __future__ import absolute_import |
2 |
2 |
3 from mercurial.i18n import _ |
3 from mercurial.i18n import _ |
4 |
4 |
|
5 from mercurial.node import ( |
|
6 bin, |
|
7 hex, |
|
8 nullhex, |
|
9 nullid, |
|
10 nullrev, |
|
11 wdirhex, |
|
12 ) |
5 from mercurial import ( |
13 from mercurial import ( |
6 ancestor, |
14 ancestor, |
7 changelog as hgchangelog, |
15 changelog as hgchangelog, |
8 dagop, |
16 dagop, |
9 encoding, |
17 encoding, |
10 error, |
18 error, |
11 manifest, |
19 manifest, |
12 node as nodemod, |
|
13 pycompat, |
20 pycompat, |
14 ) |
21 ) |
15 from mercurial.interfaces import ( |
22 from mercurial.interfaces import ( |
16 repository, |
23 repository, |
17 util as interfaceutil, |
24 util as interfaceutil, |
37 return int( |
44 return int( |
38 self._db.execute('SELECT COUNT(*) FROM changelog').fetchone()[0] |
45 self._db.execute('SELECT COUNT(*) FROM changelog').fetchone()[0] |
39 ) |
46 ) |
40 |
47 |
41 def rev(self, n): |
48 def rev(self, n): |
42 if n == nodemod.nullid: |
49 if n == nullid: |
43 return -1 |
50 return -1 |
44 t = self._db.execute( |
51 t = self._db.execute( |
45 'SELECT rev FROM changelog WHERE node = ?', (gitutil.togitnode(n),) |
52 'SELECT rev FROM changelog WHERE node = ?', (gitutil.togitnode(n),) |
46 ).fetchone() |
53 ).fetchone() |
47 if t is None: |
54 if t is None: |
48 raise error.LookupError(n, b'00changelog.i', _(b'no node %d')) |
55 raise error.LookupError(n, b'00changelog.i', _(b'no node %d')) |
49 return t[0] |
56 return t[0] |
50 |
57 |
51 def node(self, r): |
58 def node(self, r): |
52 if r == nodemod.nullrev: |
59 if r == nullrev: |
53 return nodemod.nullid |
60 return nullid |
54 t = self._db.execute( |
61 t = self._db.execute( |
55 'SELECT node FROM changelog WHERE rev = ?', (r,) |
62 'SELECT node FROM changelog WHERE rev = ?', (r,) |
56 ).fetchone() |
63 ).fetchone() |
57 if t is None: |
64 if t is None: |
58 raise error.LookupError(r, b'00changelog.i', _(b'no node')) |
65 raise error.LookupError(r, b'00changelog.i', _(b'no node')) |
59 return nodemod.bin(t[0]) |
66 return bin(t[0]) |
60 |
67 |
61 def hasnode(self, n): |
68 def hasnode(self, n): |
62 t = self._db.execute( |
69 t = self._db.execute( |
63 'SELECT node FROM changelog WHERE node = ?', (n,) |
70 'SELECT node FROM changelog WHERE node = ?', (n,) |
64 ).fetchone() |
71 ).fetchone() |
121 return baselogindex(self) |
128 return baselogindex(self) |
122 |
129 |
123 @property |
130 @property |
124 def nodemap(self): |
131 def nodemap(self): |
125 r = { |
132 r = { |
126 nodemod.bin(v[0]): v[1] |
133 bin(v[0]): v[1] |
127 for v in self._db.execute('SELECT node, rev FROM changelog') |
134 for v in self._db.execute('SELECT node, rev FROM changelog') |
128 } |
135 } |
129 r[nodemod.nullid] = nodemod.nullrev |
136 r[nullid] = nullrev |
130 return r |
137 return r |
131 |
138 |
132 def tip(self): |
139 def tip(self): |
133 t = self._db.execute( |
140 t = self._db.execute( |
134 'SELECT node FROM changelog ORDER BY rev DESC LIMIT 1' |
141 'SELECT node FROM changelog ORDER BY rev DESC LIMIT 1' |
135 ).fetchone() |
142 ).fetchone() |
136 if t: |
143 if t: |
137 return nodemod.bin(t[0]) |
144 return bin(t[0]) |
138 return nodemod.nullid |
145 return nullid |
139 |
146 |
140 def revs(self, start=0, stop=None): |
147 def revs(self, start=0, stop=None): |
141 if stop is None: |
148 if stop is None: |
142 stop = self.tip() |
149 stop = self.tip() |
143 t = self._db.execute( |
150 t = self._db.execute( |
153 'SELECT rev FROM changelog ' 'ORDER BY REV DESC ' 'LIMIT 1' |
160 'SELECT rev FROM changelog ' 'ORDER BY REV DESC ' 'LIMIT 1' |
154 ) |
161 ) |
155 return next(t) |
162 return next(t) |
156 |
163 |
157 def _partialmatch(self, id): |
164 def _partialmatch(self, id): |
158 if nodemod.wdirhex.startswith(id): |
165 if wdirhex.startswith(id): |
159 raise error.WdirUnsupported |
166 raise error.WdirUnsupported |
160 candidates = [ |
167 candidates = [ |
161 nodemod.bin(x[0]) |
168 bin(x[0]) |
162 for x in self._db.execute( |
169 for x in self._db.execute( |
163 'SELECT node FROM changelog WHERE node LIKE ?', (id + b'%',) |
170 'SELECT node FROM changelog WHERE node LIKE ?', (id + b'%',) |
164 ) |
171 ) |
165 ] |
172 ] |
166 if nodemod.nullhex.startswith(id): |
173 if nullhex.startswith(id): |
167 candidates.append(nodemod.nullid) |
174 candidates.append(nullid) |
168 if len(candidates) > 1: |
175 if len(candidates) > 1: |
169 raise error.AmbiguousPrefixLookupError( |
176 raise error.AmbiguousPrefixLookupError( |
170 id, b'00changelog.i', _(b'ambiguous identifier') |
177 id, b'00changelog.i', _(b'ambiguous identifier') |
171 ) |
178 ) |
172 if candidates: |
179 if candidates: |
175 |
182 |
176 def flags(self, rev): |
183 def flags(self, rev): |
177 return 0 |
184 return 0 |
178 |
185 |
179 def shortest(self, node, minlength=1): |
186 def shortest(self, node, minlength=1): |
180 nodehex = nodemod.hex(node) |
187 nodehex = hex(node) |
181 for attempt in pycompat.xrange(minlength, len(nodehex) + 1): |
188 for attempt in pycompat.xrange(minlength, len(nodehex) + 1): |
182 candidate = nodehex[:attempt] |
189 candidate = nodehex[:attempt] |
183 matches = int( |
190 matches = int( |
184 self._db.execute( |
191 self._db.execute( |
185 'SELECT COUNT(*) FROM changelog WHERE node LIKE ?', |
192 'SELECT COUNT(*) FROM changelog WHERE node LIKE ?', |
207 if isinstance(nodeorrev, int): |
214 if isinstance(nodeorrev, int): |
208 n = self.node(nodeorrev) |
215 n = self.node(nodeorrev) |
209 else: |
216 else: |
210 n = nodeorrev |
217 n = nodeorrev |
211 # handle looking up nullid |
218 # handle looking up nullid |
212 if n == nodemod.nullid: |
219 if n == nullid: |
213 return hgchangelog._changelogrevision(extra={}) |
220 return hgchangelog._changelogrevision(extra={}) |
214 hn = gitutil.togitnode(n) |
221 hn = gitutil.togitnode(n) |
215 # We've got a real commit! |
222 # We've got a real commit! |
216 files = [ |
223 files = [ |
217 r[0] |
224 r[0] |
224 filesremoved = [ |
231 filesremoved = [ |
225 r[0] |
232 r[0] |
226 for r in self._db.execute( |
233 for r in self._db.execute( |
227 'SELECT filename FROM changedfiles ' |
234 'SELECT filename FROM changedfiles ' |
228 'WHERE node = ? and filenode = ?', |
235 'WHERE node = ? and filenode = ?', |
229 (hn, nodemod.nullhex), |
236 (hn, nullhex), |
230 ) |
237 ) |
231 ] |
238 ] |
232 c = self.gitrepo[hn] |
239 c = self.gitrepo[hn] |
233 return hgchangelog._changelogrevision( |
240 return hgchangelog._changelogrevision( |
234 manifest=n, # pretend manifest the same as the commit node |
241 manifest=n, # pretend manifest the same as the commit node |
265 |
272 |
266 'common' is a list of revision numbers. If common is not supplied, uses |
273 'common' is a list of revision numbers. If common is not supplied, uses |
267 nullrev. |
274 nullrev. |
268 """ |
275 """ |
269 if common is None: |
276 if common is None: |
270 common = [nodemod.nullrev] |
277 common = [nullrev] |
271 |
278 |
272 return ancestor.incrementalmissingancestors(self.parentrevs, common) |
279 return ancestor.incrementalmissingancestors(self.parentrevs, common) |
273 |
280 |
274 def findmissing(self, common=None, heads=None): |
281 def findmissing(self, common=None, heads=None): |
275 """Return the ancestors of heads that are not ancestors of common. |
282 """Return the ancestors of heads that are not ancestors of common. |
285 |
292 |
286 'heads' and 'common' are both lists of node IDs. If heads is |
293 'heads' and 'common' are both lists of node IDs. If heads is |
287 not supplied, uses all of the revlog's heads. If common is not |
294 not supplied, uses all of the revlog's heads. If common is not |
288 supplied, uses nullid.""" |
295 supplied, uses nullid.""" |
289 if common is None: |
296 if common is None: |
290 common = [nodemod.nullid] |
297 common = [nullid] |
291 if heads is None: |
298 if heads is None: |
292 heads = self.heads() |
299 heads = self.heads() |
293 |
300 |
294 common = [self.rev(n) for n in common] |
301 common = [self.rev(n) for n in common] |
295 heads = [self.rev(n) for n in heads] |
302 heads = [self.rev(n) for n in heads] |
300 def children(self, node): |
307 def children(self, node): |
301 """find the children of a given node""" |
308 """find the children of a given node""" |
302 c = [] |
309 c = [] |
303 p = self.rev(node) |
310 p = self.rev(node) |
304 for r in self.revs(start=p + 1): |
311 for r in self.revs(start=p + 1): |
305 prevs = [pr for pr in self.parentrevs(r) if pr != nodemod.nullrev] |
312 prevs = [pr for pr in self.parentrevs(r) if pr != nullrev] |
306 if prevs: |
313 if prevs: |
307 for pr in prevs: |
314 for pr in prevs: |
308 if pr == p: |
315 if pr == p: |
309 c.append(self.node(r)) |
316 c.append(self.node(r)) |
310 elif p == nodemod.nullrev: |
317 elif p == nullrev: |
311 c.append(self.node(r)) |
318 c.append(self.node(r)) |
312 return c |
319 return c |
313 |
320 |
314 def reachableroots(self, minroot, heads, roots, includepath=False): |
321 def reachableroots(self, minroot, heads, roots, includepath=False): |
315 return dagop._reachablerootspure( |
322 return dagop._reachablerootspure( |
321 a, b = self.rev(a), self.rev(b) |
328 a, b = self.rev(a), self.rev(b) |
322 return self.isancestorrev(a, b) |
329 return self.isancestorrev(a, b) |
323 |
330 |
324 # Cleanup opportunity: this is *identical* to the revlog.py version |
331 # Cleanup opportunity: this is *identical* to the revlog.py version |
325 def isancestorrev(self, a, b): |
332 def isancestorrev(self, a, b): |
326 if a == nodemod.nullrev: |
333 if a == nullrev: |
327 return True |
334 return True |
328 elif a == b: |
335 elif a == b: |
329 return True |
336 return True |
330 elif a > b: |
337 elif a > b: |
331 return False |
338 return False |
335 n = self.node(rev) |
342 n = self.node(rev) |
336 hn = gitutil.togitnode(n) |
343 hn = gitutil.togitnode(n) |
337 if hn != gitutil.nullgit: |
344 if hn != gitutil.nullgit: |
338 c = self.gitrepo[hn] |
345 c = self.gitrepo[hn] |
339 else: |
346 else: |
340 return nodemod.nullrev, nodemod.nullrev |
347 return nullrev, nullrev |
341 p1 = p2 = nodemod.nullrev |
348 p1 = p2 = nullrev |
342 if c.parents: |
349 if c.parents: |
343 p1 = self.rev(c.parents[0].id.raw) |
350 p1 = self.rev(c.parents[0].id.raw) |
344 if len(c.parents) > 2: |
351 if len(c.parents) > 2: |
345 raise error.Abort(b'TODO octopus merge handling') |
352 raise error.Abort(b'TODO octopus merge handling') |
346 if len(c.parents) == 2: |
353 if len(c.parents) == 2: |
384 filesadded=None, |
391 filesadded=None, |
385 filesremoved=None, |
392 filesremoved=None, |
386 ): |
393 ): |
387 parents = [] |
394 parents = [] |
388 hp1, hp2 = gitutil.togitnode(p1), gitutil.togitnode(p2) |
395 hp1, hp2 = gitutil.togitnode(p1), gitutil.togitnode(p2) |
389 if p1 != nodemod.nullid: |
396 if p1 != nullid: |
390 parents.append(hp1) |
397 parents.append(hp1) |
391 if p2 and p2 != nodemod.nullid: |
398 if p2 and p2 != nullid: |
392 parents.append(hp2) |
399 parents.append(hp2) |
393 assert date is not None |
400 assert date is not None |
394 timestamp, tz = date |
401 timestamp, tz = date |
395 sig = pygit2.Signature( |
402 sig = pygit2.Signature( |
396 encoding.unifromlocal(stringutil.person(user)), |
403 encoding.unifromlocal(stringutil.person(user)), |
417 class manifestlog(baselog): |
424 class manifestlog(baselog): |
418 def __getitem__(self, node): |
425 def __getitem__(self, node): |
419 return self.get(b'', node) |
426 return self.get(b'', node) |
420 |
427 |
421 def get(self, relpath, node): |
428 def get(self, relpath, node): |
422 if node == nodemod.nullid: |
429 if node == nullid: |
423 # TODO: this should almost certainly be a memgittreemanifestctx |
430 # TODO: this should almost certainly be a memgittreemanifestctx |
424 return manifest.memtreemanifestctx(self, relpath) |
431 return manifest.memtreemanifestctx(self, relpath) |
425 commit = self.gitrepo[gitutil.togitnode(node)] |
432 commit = self.gitrepo[gitutil.togitnode(node)] |
426 t = commit.tree |
433 t = commit.tree |
427 if relpath: |
434 if relpath: |
438 super(filelog, self).__init__(gr, db) |
445 super(filelog, self).__init__(gr, db) |
439 assert isinstance(path, bytes) |
446 assert isinstance(path, bytes) |
440 self.path = path |
447 self.path = path |
441 |
448 |
442 def read(self, node): |
449 def read(self, node): |
443 if node == nodemod.nullid: |
450 if node == nullid: |
444 return b'' |
451 return b'' |
445 return self.gitrepo[gitutil.togitnode(node)].data |
452 return self.gitrepo[gitutil.togitnode(node)].data |
446 |
453 |
447 def lookup(self, node): |
454 def lookup(self, node): |
448 if len(node) not in (20, 40): |
455 if len(node) not in (20, 40): |
449 node = int(node) |
456 node = int(node) |
450 if isinstance(node, int): |
457 if isinstance(node, int): |
451 assert False, b'todo revnums for nodes' |
458 assert False, b'todo revnums for nodes' |
452 if len(node) == 40: |
459 if len(node) == 40: |
453 node = nodemod.bin(node) |
460 node = bin(node) |
454 hnode = gitutil.togitnode(node) |
461 hnode = gitutil.togitnode(node) |
455 if hnode in self.gitrepo: |
462 if hnode in self.gitrepo: |
456 return node |
463 return node |
457 raise error.LookupError(self.path, node, _(b'no match found')) |
464 raise error.LookupError(self.path, node, _(b'no match found')) |
458 |
465 |
498 ''', |
505 ''', |
499 (rev, pycompat.fsdecode(self.path)), |
506 (rev, pycompat.fsdecode(self.path)), |
500 ).fetchone() |
507 ).fetchone() |
501 if maybe is None: |
508 if maybe is None: |
502 raise IndexError('gitlog %r out of range %d' % (self.path, rev)) |
509 raise IndexError('gitlog %r out of range %d' % (self.path, rev)) |
503 return nodemod.bin(maybe[0]) |
510 return bin(maybe[0]) |
504 |
511 |
505 def parents(self, node): |
512 def parents(self, node): |
506 gn = gitutil.togitnode(node) |
513 gn = gitutil.togitnode(node) |
507 gp = pycompat.fsdecode(self.path) |
514 gp = pycompat.fsdecode(self.path) |
508 ps = [] |
515 ps = [] |
523 if pycompat.ispy3: |
530 if pycompat.ispy3: |
524 commit = commit.decode('ascii') |
531 commit = commit.decode('ascii') |
525 index.fill_in_filelog(self.gitrepo, self._db, commit, gp, gn) |
532 index.fill_in_filelog(self.gitrepo, self._db, commit, gp, gn) |
526 return self.parents(node) |
533 return self.parents(node) |
527 else: |
534 else: |
528 ps.append(nodemod.bin(p)) |
535 ps.append(bin(p)) |
529 return ps |
536 return ps |
530 |
537 |
531 def renamed(self, node): |
538 def renamed(self, node): |
532 # TODO: renames/copies |
539 # TODO: renames/copies |
533 return False |
540 return False |