##// END OF EJS Templates
Fix two bugs in verify
mpm@selenic.com -
r93:0b0efe40 default
parent child Browse files
Show More
@@ -1,514 +1,514 b''
1 1 #!/usr/bin/env python
2 2 #
3 3 # mercurial - a minimal scalable distributed SCM
4 4 # v0.4f "jane dark"
5 5 #
6 6 # Copyright 2005 Matt Mackall <mpm@selenic.com>
7 7 #
8 8 # This software may be used and distributed according to the terms
9 9 # of the GNU General Public License, incorporated herein by reference.
10 10
11 11 # the psyco compiler makes commits a bit faster
12 12 # and makes changegroup merge about 20 times slower!
13 13 # try:
14 14 # import psyco
15 15 # psyco.full()
16 16 # except:
17 17 # pass
18 18
19 19 import sys, os, time
20 20 from mercurial import hg, mdiff, fancyopts
21 21
22 22 def help():
23 23 print """\
24 24 commands:
25 25
26 26 init create a new repository in this directory
27 27 branch <path> create a branch of <path> in this directory
28 28 merge <path> merge changes from <path> into local repository
29 29 checkout [changeset] checkout the latest or given changeset
30 30 status show new, missing, and changed files in working dir
31 31 add [files...] add the given files in the next commit
32 32 remove [files...] remove the given files in the next commit
33 33 addremove add all new files, delete all missing files
34 34 commit commit all changes to the repository
35 35 history show changeset history
36 36 log <file> show revision history of a single file
37 37 dump <file> [rev] dump the latest or given revision of a file
38 38 dumpmanifest [rev] dump the latest or given revision of the manifest
39 39 diff [files...] diff working directory (or selected files)
40 40 tags show current changeset tags
41 41 annotate [files...] show changeset number per file line
42 42 blame [files...] show commit user per file line
43 43 """
44 44
45 45 def filterfiles(list, files):
46 46 l = [ x for x in list if x in files ]
47 47
48 48 for f in files:
49 49 if f[-1] != os.sep: f += os.sep
50 50 l += [ x for x in list if x.startswith(f) ]
51 51 return l
52 52
53 53 def diff(files = None, node1 = None, node2 = None):
54 54 def date(c):
55 55 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
56 56
57 57 if node2:
58 58 change = repo.changelog.read(node2)
59 59 mmap2 = repo.manifest.read(change[0])
60 60 (c, a, d) = repo.diffrevs(node1, node2)
61 61 def read(f): return repo.file(f).read(mmap2[f])
62 62 date2 = date(change)
63 63 else:
64 64 date2 = time.asctime()
65 65 if not node1:
66 66 node1 = repo.current
67 67 (c, a, d) = repo.diffdir(repo.root, node1)
68 68 def read(f): return file(os.path.join(repo.root, f)).read()
69 69
70 70 change = repo.changelog.read(node1)
71 71 mmap = repo.manifest.read(change[0])
72 72 date1 = date(change)
73 73
74 74 if files:
75 75 (c, a, d) = map(lambda x: filterfiles(x, files), (c, a, d))
76 76
77 77 for f in c:
78 78 to = repo.file(f).read(mmap[f])
79 79 tn = read(f)
80 80 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
81 81 for f in a:
82 82 to = ""
83 83 tn = read(f)
84 84 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
85 85 for f in d:
86 86 to = repo.file(f).read(mmap[f])
87 87 tn = ""
88 88 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
89 89
90 90 options = {}
91 91 opts = [('v', 'verbose', None, 'verbose'),
92 92 ('d', 'debug', None, 'debug'),
93 93 ('q', 'quiet', None, 'quiet')]
94 94
95 95 args = fancyopts.fancyopts(sys.argv[1:], opts, options,
96 96 'hg [options] <command> [command options] [files]')
97 97
98 98 try:
99 99 cmd = args[0]
100 100 args = args[1:]
101 101 except:
102 102 cmd = ""
103 103
104 104 ui = hg.ui(options["verbose"], options["debug"], options["quiet"])
105 105
106 106 if cmd == "init":
107 107 repo = hg.repository(ui, ".", create=1)
108 108 sys.exit(0)
109 109 elif cmd == "branch" or cmd == "clone":
110 110 os.system("cp -al %s/.hg .hg" % args[0])
111 111 sys.exit(0)
112 112 elif cmd == "help":
113 113 help()
114 114 sys.exit(0)
115 115 else:
116 116 try:
117 117 repo = hg.repository(ui=ui)
118 118 except IOError:
119 119 ui.warn("Unable to open repository\n")
120 120 sys.exit(0)
121 121
122 122 if cmd == "checkout" or cmd == "co":
123 123 node = repo.changelog.tip()
124 124 if args:
125 125 node = repo.lookup(args[0])
126 126 repo.checkout(node)
127 127
128 128 elif cmd == "add":
129 129 repo.add(args)
130 130
131 131 elif cmd == "remove" or cmd == "rm" or cmd == "del" or cmd == "delete":
132 132 repo.remove(args)
133 133
134 134 elif cmd == "commit" or cmd == "checkin" or cmd == "ci":
135 135 if 1:
136 136 if len(args) > 0:
137 137 repo.commit(repo.current, args)
138 138 else:
139 139 repo.commit(repo.current)
140 140
141 141 elif cmd == "import" or cmd == "patch":
142 142 try:
143 143 import psyco
144 144 psyco.full()
145 145 except:
146 146 pass
147 147
148 148 ioptions = {}
149 149 opts = [('p', 'strip', 1, 'path strip'),
150 150 ('b', 'base', "", 'base path'),
151 151 ('q', 'quiet', "", 'silence diff')
152 152 ]
153 153
154 154 args = fancyopts.fancyopts(args, opts, ioptions,
155 155 'hg import [options] <patch names>')
156 156 d = ioptions["base"]
157 157 strip = ioptions["strip"]
158 158 quiet = ioptions["quiet"] and "> /dev/null" or ""
159 159
160 160 for patch in args:
161 161 ui.status("applying %s\n" % patch)
162 162 pf = os.path.join(d, patch)
163 163
164 164 text = ""
165 165 for l in file(pf):
166 166 if l[:4] == "--- ": break
167 167 text += l
168 168
169 169 f = os.popen("lsdiff --strip %d %s" % (strip, pf))
170 170 files = filter(None, map(lambda x: x.rstrip(), f.read().splitlines()))
171 171 f.close()
172 172
173 173 if files:
174 174 if os.system("patch -p%d < %s %s" % (strip, pf, quiet)):
175 175 raise "patch failed!"
176 176 repo.commit(repo.current, files, text)
177 177
178 178 elif cmd == "status":
179 179 (c, a, d) = repo.diffdir(repo.root, repo.current)
180 180 for f in c: ui.status("C %s\n" % f)
181 181 for f in a: ui.status("? %s\n" % f)
182 182 for f in d: ui.status("R %s\n" % f)
183 183
184 184 elif cmd == "diff":
185 185 revs = []
186 186
187 187 if args:
188 188 doptions = {}
189 189 opts = [('r', 'revision', [], 'revision')]
190 190 args = fancyopts.fancyopts(args, opts, doptions,
191 191 'hg diff [options] [files]')
192 192 revs = map(lambda x: repo.lookup(x), doptions['revision'])
193 193
194 194 if len(revs) > 2:
195 195 self.ui.warn("too many revisions to diff\n")
196 196 sys.exit(1)
197 197
198 198 if os.getcwd() != repo.root:
199 199 relpath = os.getcwd()[len(repo.root) + 1: ]
200 200 if not args: args = [ relpath ]
201 201 else: args = [ os.path.join(relpath, x) for x in args ]
202 202
203 203 diff(args, *revs)
204 204
205 205 elif cmd == "annotate":
206 206 aoptions = {}
207 207 opts = [('r', 'revision', '', 'revision')]
208 208 args = fancyopts.fancyopts(args, opts, aoptions,
209 209 'hg annotate [-r id] [files]')
210 210 if args:
211 211 node = repo.current
212 212 if aoptions['revision']:
213 213 node = repo.changelog.lookup(aoptions['revision'])
214 214 change = repo.changelog.read(node)
215 215 mmap = repo.manifest.read(change[0])
216 216 for f in args:
217 217 for n, l in repo.file(f).annotate(mmap[f]):
218 218 sys.stdout.write("% 6s:%s"%(n, l))
219 219
220 220 elif cmd == "blame":
221 221 aoptions = {}
222 222 opts = [('r', 'revision', '', 'revision')]
223 223 args = fancyopts.fancyopts(args, opts, aoptions,
224 224 'hg blame [-r id] [files]')
225 225 if args:
226 226 bcache = {}
227 227 node = repo.current
228 228 if aoptions['revision']:
229 229 node = repo.changelog.lookup(aoptions['revision'])
230 230 change = repo.changelog.read(node)
231 231 mmap = repo.manifest.read(change[0])
232 232 for f in args:
233 233 for n, l in repo.file(f).annotate(mmap[f]):
234 234 try:
235 235 name = bcache[n]
236 236 except KeyError:
237 237 cl = repo.changelog.read(repo.changelog.node(n))
238 238 name = cl[1]
239 239 f = name.find('@')
240 240 if f >= 0:
241 241 name = name[:f]
242 242 bcache[n] = name
243 243 sys.stdout.write("% 10s:%s"%(name, l))
244 244
245 245 elif cmd == "export":
246 246 node = repo.lookup(args[0])
247 247 prev, other = repo.changelog.parents(node)
248 248 change = repo.changelog.read(node)
249 249 print "# HG changeset patch"
250 250 print "# User %s" % change[1]
251 251 print "# Node ID %s" % hg.hex(node)
252 252 print "# Parent %s" % hg.hex(prev)
253 253 print
254 254 if other != hg.nullid:
255 255 print "# Parent %s" % hg.hex(other)
256 256 print change[4]
257 257
258 258 diff(None, prev, node)
259 259
260 260 elif cmd == "debugchangegroup":
261 261 newer = repo.newer(map(repo.lookup, args))
262 262 for chunk in repo.changegroup(newer):
263 263 sys.stdout.write(chunk)
264 264
265 265 elif cmd == "debugaddchangegroup":
266 266 data = sys.stdin.read()
267 267 repo.addchangegroup(data)
268 268
269 269 elif cmd == "addremove":
270 270 (c, a, d) = repo.diffdir(repo.root, repo.current)
271 271 repo.add(a)
272 272 repo.remove(d)
273 273
274 274 elif cmd == "history":
275 275 for i in range(repo.changelog.count()):
276 276 n = repo.changelog.node(i)
277 277 changes = repo.changelog.read(n)
278 278 (p1, p2) = repo.changelog.parents(n)
279 279 (h, h1, h2) = map(hg.hex, (n, p1, p2))
280 280 (i1, i2) = map(repo.changelog.rev, (p1, p2))
281 281 print "rev: %4d:%s" % (i, h)
282 282 print "parents: %4d:%s" % (i1, h1)
283 283 if i2: print " %4d:%s" % (i2, h2)
284 284 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
285 285 hg.hex(changes[0]))
286 286 print "user:", changes[1]
287 287 print "date:", time.asctime(
288 288 time.localtime(float(changes[2].split(' ')[0])))
289 289 print "files:", " ".join(changes[3])
290 290 print "description:"
291 291 print changes[4]
292 292
293 293 elif cmd == "tip":
294 294 n = repo.changelog.tip()
295 295 t = repo.changelog.rev(n)
296 296 ui.status("%d:%s\n" % (t, hg.hex(n)))
297 297
298 298 elif cmd == "log":
299 299 if args:
300 300 r = repo.file(args[0])
301 301 for i in range(r.count()):
302 302 n = r.node(i)
303 303 (p1, p2) = r.parents(n)
304 304 (h, h1, h2) = map(hg.hex, (n, p1, p2))
305 305 (i1, i2) = map(r.rev, (p1, p2))
306 306 cr = r.linkrev(n)
307 307 cn = hg.hex(repo.changelog.node(cr))
308 308 print "rev: %4d:%s" % (i, h)
309 309 print "changeset: %4d:%s" % (cr, cn)
310 310 print "parents: %4d:%s" % (i1, h1)
311 311 if i2: print " %4d:%s" % (i2, h2)
312 312 else:
313 313 print "missing filename"
314 314
315 315 elif cmd == "dump":
316 316 if args:
317 317 r = repo.file(args[0])
318 318 n = r.tip()
319 319 if len(args) > 1: n = r.lookup(args[1])
320 320 sys.stdout.write(r.read(n))
321 321 else:
322 322 print "missing filename"
323 323
324 324 elif cmd == "dumpmanifest":
325 325 n = repo.manifest.tip()
326 326 if len(args) > 0:
327 327 n = repo.manifest.lookup(args[0])
328 328 m = repo.manifest.read(n)
329 329 files = m.keys()
330 330 files.sort()
331 331
332 332 for f in files:
333 333 print hg.hex(m[f]), f
334 334
335 335 elif cmd == "debughash":
336 336 f = repo.file(args[0])
337 337 print f.encodepath(args[0])
338 338
339 339 elif cmd == "debugindex":
340 340 if ".hg" not in args[0]:
341 341 args[0] = ".hg/data/" + repo.file(args[0]).encodepath(args[0]) + "i"
342 342
343 343 r = hg.revlog(open, args[0], "")
344 344 print " rev offset length base linkrev"+\
345 345 " p1 p2 nodeid"
346 346 for i in range(r.count()):
347 347 e = r.index[i]
348 348 print "% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s.." % (
349 349 i, e[0], e[1], e[2], e[3],
350 350 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5]))
351 351
352 352 elif cmd == "debugindexdot":
353 353 if ".hg" not in args[0]:
354 354 args[0] = ".hg/data/" + repo.file(args[0]).encodepath(args[0]) + "i"
355 355
356 356 r = hg.revlog(open, args[0], "")
357 357 print "digraph G {"
358 358 for i in range(r.count()):
359 359 e = r.index[i]
360 360 print "\t%d -> %d" % (r.rev(e[4]), i)
361 361 if e[5] != hg.nullid:
362 362 print "\t%d -> %d" % (r.rev(e[5]), i)
363 363 print "}"
364 364
365 365 elif cmd == "merge":
366 366 if args:
367 367 other = hg.repository(ui, args[0])
368 368 ui.status("requesting changegroup\n")
369 369 cg = repo.getchangegroup(other)
370 370 repo.addchangegroup(cg)
371 371 else:
372 372 print "missing source repository"
373 373
374 374 elif cmd == "tags":
375 375 repo.lookup(0) # prime the cache
376 376 i = repo.tags.items()
377 377 i.sort()
378 378 for k, n in i:
379 379 try:
380 380 r = repo.changelog.rev(n)
381 381 except KeyError:
382 382 r = "?"
383 383 print "%-30s %5d:%s" % (k, repo.changelog.rev(n), hg.hex(n))
384 384
385 385 elif cmd == "debugoldmerge":
386 386 if args:
387 387 other = hg.repository(ui, args[0])
388 388 repo.merge(other)
389 389 else:
390 390 print "missing source repository"
391 391
392 392 elif cmd == "verify":
393 393 filelinkrevs = {}
394 394 filenodes = {}
395 395 manifestchangeset = {}
396 396 changesets = revisions = files = 0
397 397 errors = 0
398 398
399 399 ui.status("checking changesets\n")
400 400 for i in range(repo.changelog.count()):
401 401 changesets += 1
402 402 n = repo.changelog.node(i)
403 403 for p in repo.changelog.parents(n):
404 404 if p not in repo.changelog.nodemap:
405 405 ui.warn("changeset %s has unknown parent %s\n" %
406 406 (hg.short(n), hg.short(p)))
407 407 errors += 1
408 408 try:
409 409 changes = repo.changelog.read(n)
410 410 except Error, inst:
411 411 ui.warn("unpacking changeset %s: %s\n" % (short(n), inst))
412 412 errors += 1
413 413
414 414 manifestchangeset[changes[0]] = n
415 415 for f in changes[3]:
416 416 revisions += 1
417 417 filelinkrevs.setdefault(f, []).append(i)
418 418
419 419 ui.status("checking manifests\n")
420 420 for i in range(repo.manifest.count()):
421 421 n = repo.manifest.node(i)
422 422 for p in repo.manifest.parents(n):
423 423 if p not in repo.manifest.nodemap:
424 424 ui.warn("manifest %s has unknown parent %s\n" %
425 425 (hg.short(n), hg.short(p)))
426 426 errors += 1
427 427 ca = repo.changelog.node(repo.manifest.linkrev(n))
428 428 cc = manifestchangeset[n]
429 429 if ca != cc:
430 430 ui.warn("manifest %s points to %s, not %s\n" %
431 431 (hg.hex(n), hg.hex(ca), hg.hex(cc)))
432 432 errors += 1
433 433
434 434 try:
435 435 m = repo.manifest.read(n)
436 except Error, inst:
436 except Exception, inst:
437 437 ui.warn("unpacking manifest %s: %s\n" % (hg.short(n), inst))
438 438 errors += 1
439 439
440 440 for f, fn in m.items():
441 441 filenodes.setdefault(f, {})[fn] = 1
442 442
443 443 ui.status("crosschecking files in changesets and manifests\n")
444 444 for f in filenodes:
445 445 if f not in filelinkrevs:
446 446 ui.warn("file %s in manifest but not in changesets\n" % f)
447 447 errors += 1
448 448
449 449 for f in filelinkrevs:
450 450 if f not in filenodes:
451 451 ui.warn("file %s in changeset but not in manifest" % f)
452 452 errors += 1
453 453
454 454 ui.status("checking files\n")
455 455 for f in filenodes:
456 456 files += 1
457 457 fl = repo.file(f)
458 458 nodes = { hg.nullid: 1 }
459 459 for i in range(fl.count()):
460 460 n = fl.node(i)
461 461
462 462 if n not in filenodes[f]:
463 463 ui.warn("%s:%s not in manifests\n" % (f, hg.short(n)))
464 464 errors += 1
465 465 else:
466 466 del filenodes[f][n]
467 467
468 468 flr = fl.linkrev(n)
469 469 if flr not in filelinkrevs[f]:
470 470 ui.warn("%s:%s points to unexpected changeset rev %d\n"
471 471 % (f, hg.short(n), fl.linkrev(n)))
472 472 errors += 1
473 473 else:
474 474 filelinkrevs[f].remove(flr)
475 475
476 476 # verify contents
477 477 try:
478 478 t = fl.read(n)
479 479 except Error, inst:
480 480 ui.warn("unpacking file %s %s: %s\n" % (f, short(n), inst))
481 481 errors += 1
482 482
483 483 # verify parents
484 484 (p1, p2) = fl.parents(n)
485 485 if p1 not in nodes:
486 486 ui.warn("file %s:%s unknown parent 1 %s" %
487 487 (f, hg.short(n), hg.short(p1)))
488 488 errors += 1
489 489 if p2 not in nodes:
490 490 ui.warn("file %s:%s unknown parent 2 %s" %
491 491 (f, hg.short(n), hg.short(p1)))
492 492 errors += 1
493 493 nodes[n] = 1
494 494
495 495 # cross-check
496 496 for flr in filelinkrevs[f]:
497 497 ui.warn("changeset rev %d not in %s\n" % (flr, f))
498 498 errors += 1
499 499
500 500 for node in filenodes[f]:
501 501 ui.warn("node %s in manifests not in %s\n" % (hg.hex(n), f))
502 502 errors += 1
503 503
504 504 ui.status("%d files, %d changesets, %d total revisions\n" %
505 505 (files, changesets, revisions))
506 506
507 507 if errors:
508 ui.warn("%d integrity errors encountered!\n")
508 ui.warn("%d integrity errors encountered!\n" % errors)
509 509 sys.exit(1)
510 510
511 511 else:
512 512 print "unknown command\n"
513 513 help()
514 514 sys.exit(1)
General Comments 0
You need to be logged in to leave comments. Login now