##// END OF EJS Templates
Make hg verify do more thorough cross-checking.
mpm@selenic.com -
r17:ffe6a5ca default
parent child Browse files
Show More
@@ -1,261 +1,279 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 #
2 #
3 # mercurial - a minimal scalable distributed SCM
3 # mercurial - a minimal scalable distributed SCM
4 # v0.4d "oedipa maas"
4 # v0.4d "oedipa maas"
5 #
5 #
6 # Copyright 2005 Matt Mackall <mpm@selenic.com>
6 # Copyright 2005 Matt Mackall <mpm@selenic.com>
7 #
7 #
8 # This software may be used and distributed according to the terms
8 # This software may be used and distributed according to the terms
9 # of the GNU General Public License, incorporated herein by reference.
9 # of the GNU General Public License, incorporated herein by reference.
10
10
11 # the psyco compiler makes commits about twice as fast
11 # the psyco compiler makes commits about twice as fast
12 try:
12 try:
13 import psyco
13 import psyco
14 psyco.full()
14 psyco.full()
15 except:
15 except:
16 pass
16 pass
17
17
18 import sys, os
18 import sys, os
19 from mercurial import hg, mdiff, fancyopts
19 from mercurial import hg, mdiff, fancyopts
20
20
21 options = {}
21 options = {}
22 opts = [('v', 'verbose', None, 'verbose'),
22 opts = [('v', 'verbose', None, 'verbose'),
23 ('d', 'debug', None, 'debug')]
23 ('d', 'debug', None, 'debug')]
24
24
25 args = fancyopts.fancyopts(sys.argv[1:], opts, options,
25 args = fancyopts.fancyopts(sys.argv[1:], opts, options,
26 'hg [options] <command> [command options] [files]')
26 'hg [options] <command> [command options] [files]')
27
27
28 try:
28 try:
29 cmd = args[0]
29 cmd = args[0]
30 args = args[1:]
30 args = args[1:]
31 except:
31 except:
32 cmd = ""
32 cmd = ""
33
33
34 ui = hg.ui(options["verbose"], options["debug"])
34 ui = hg.ui(options["verbose"], options["debug"])
35
35
36 if cmd == "init":
36 if cmd == "init":
37 repo = hg.repository(ui, ".", create=1)
37 repo = hg.repository(ui, ".", create=1)
38 sys.exit(0)
38 sys.exit(0)
39 elif cmd == "branch" or cmd == "clone":
39 elif cmd == "branch" or cmd == "clone":
40 os.system("cp -al %s/.hg .hg" % args[0])
40 os.system("cp -al %s/.hg .hg" % args[0])
41 sys.exit(0)
41 sys.exit(0)
42 else:
42 else:
43 repo = hg.repository(ui=ui)
43 repo = hg.repository(ui=ui)
44
44
45 if cmd == "checkout" or cmd == "co":
45 if cmd == "checkout" or cmd == "co":
46 node = repo.changelog.tip()
46 node = repo.changelog.tip()
47 if len(args):
47 if len(args):
48 if len(args[0]) < 40:
48 if len(args[0]) < 40:
49 rev = int(args[0])
49 rev = int(args[0])
50 node = repo.changelog.node(rev)
50 node = repo.changelog.node(rev)
51 else:
51 else:
52 node = args[0]
52 node = args[0]
53 repo.checkout(node)
53 repo.checkout(node)
54
54
55 elif cmd == "add":
55 elif cmd == "add":
56 repo.add(args)
56 repo.add(args)
57
57
58 elif cmd == "remove" or cmd == "rm" or cmd == "del" or cmd == "delete":
58 elif cmd == "remove" or cmd == "rm" or cmd == "del" or cmd == "delete":
59 repo.remove(args)
59 repo.remove(args)
60
60
61 elif cmd == "commit" or cmd == "checkin" or cmd == "ci":
61 elif cmd == "commit" or cmd == "checkin" or cmd == "ci":
62 if 1:
62 if 1:
63 if len(args) > 0:
63 if len(args) > 0:
64 repo.commit(args)
64 repo.commit(args)
65 else:
65 else:
66 repo.commit()
66 repo.commit()
67
67
68 elif cmd == "import" or cmd == "patch":
68 elif cmd == "import" or cmd == "patch":
69 ioptions = {}
69 ioptions = {}
70 opts = [('p', 'strip', 1, 'path strip'),
70 opts = [('p', 'strip', 1, 'path strip'),
71 ('b', 'base', "", 'base path')]
71 ('b', 'base', "", 'base path')]
72
72
73 args = fancyopts.fancyopts(args, opts, ioptions,
73 args = fancyopts.fancyopts(args, opts, ioptions,
74 'hg import [options] <patch names>')
74 'hg import [options] <patch names>')
75 d = ioptions["base"]
75 d = ioptions["base"]
76 strip = ioptions["strip"]
76 strip = ioptions["strip"]
77
77
78 for patch in args:
78 for patch in args:
79 ui.status("applying %s\n" % patch)
79 ui.status("applying %s\n" % patch)
80 pf = d + patch
80 pf = d + patch
81 os.system("patch -p%d < %s > /dev/null" % (strip, pf))
81 os.system("patch -p%d < %s > /dev/null" % (strip, pf))
82 f = os.popen("lsdiff --strip %d %s" % (strip, pf))
82 f = os.popen("lsdiff --strip %d %s" % (strip, pf))
83 files = f.read().splitlines()
83 files = f.read().splitlines()
84 f.close()
84 f.close()
85 repo.commit(files)
85 repo.commit(files)
86
86
87 elif cmd == "status":
87 elif cmd == "status":
88 (c, a, d) = repo.diffdir(repo.root)
88 (c, a, d) = repo.diffdir(repo.root)
89 for f in c: print "C", f
89 for f in c: print "C", f
90 for f in a: print "?", f
90 for f in a: print "?", f
91 for f in d: print "R", f
91 for f in d: print "R", f
92
92
93 elif cmd == "diff":
93 elif cmd == "diff":
94 mmap = {}
94 mmap = {}
95 if repo.current:
95 if repo.current:
96 change = repo.changelog.read(repo.current)
96 change = repo.changelog.read(repo.current)
97 mmap = repo.manifest.read(change[0])
97 mmap = repo.manifest.read(change[0])
98
98
99 (c, a, d) = repo.diffdir(repo.root)
99 (c, a, d) = repo.diffdir(repo.root)
100 for f in c:
100 for f in c:
101 to = repo.file(f).read(mmap[f])
101 to = repo.file(f).read(mmap[f])
102 tn = file(f).read()
102 tn = file(f).read()
103 sys.stdout.write(mdiff.unidiff(to, tn, f))
103 sys.stdout.write(mdiff.unidiff(to, tn, f))
104 for f in a:
104 for f in a:
105 to = ""
105 to = ""
106 tn = file(f).read()
106 tn = file(f).read()
107 sys.stdout.write(mdiff.unidiff(to, tn, f))
107 sys.stdout.write(mdiff.unidiff(to, tn, f))
108 for f in d:
108 for f in d:
109 to = repo.file(f).read(mmap[f])
109 to = repo.file(f).read(mmap[f])
110 tn = ""
110 tn = ""
111 sys.stdout.write(mdiff.unidiff(to, tn, f))
111 sys.stdout.write(mdiff.unidiff(to, tn, f))
112
112
113 elif cmd == "addremove":
113 elif cmd == "addremove":
114 (c, a, d) = repo.diffdir(repo.root)
114 (c, a, d) = repo.diffdir(repo.root)
115 repo.add(a)
115 repo.add(a)
116 repo.remove(d)
116 repo.remove(d)
117
117
118 elif cmd == "history":
118 elif cmd == "history":
119 for i in range(repo.changelog.count()):
119 for i in range(repo.changelog.count()):
120 n = repo.changelog.node(i)
120 n = repo.changelog.node(i)
121 changes = repo.changelog.read(n)
121 changes = repo.changelog.read(n)
122 (p1, p2) = repo.changelog.parents(n)
122 (p1, p2) = repo.changelog.parents(n)
123 (h, h1, h2) = map(hg.hex, (n, p1, p2))
123 (h, h1, h2) = map(hg.hex, (n, p1, p2))
124 (i1, i2) = map(repo.changelog.rev, (p1, p2))
124 (i1, i2) = map(repo.changelog.rev, (p1, p2))
125 print "rev: %4d:%s" % (i, h)
125 print "rev: %4d:%s" % (i, h)
126 print "parents: %4d:%s" % (i1, h1)
126 print "parents: %4d:%s" % (i1, h1)
127 if i2: print " %4d:%s" % (i2, h2)
127 if i2: print " %4d:%s" % (i2, h2)
128 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
128 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
129 hg.hex(changes[0]))
129 hg.hex(changes[0]))
130 print "user:", changes[1]
130 print "user:", changes[1]
131 print "files:", " ".join(changes[3])
131 print "files:", " ".join(changes[3])
132 print "description:"
132 print "description:"
133 print changes[4]
133 print changes[4]
134
134
135 elif cmd == "log":
135 elif cmd == "log":
136 if args:
136 if args:
137 r = repo.file(args[0])
137 r = repo.file(args[0])
138 for i in range(r.count()):
138 for i in range(r.count()):
139 n = r.node(i)
139 n = r.node(i)
140 (p1, p2) = r.parents(n)
140 (p1, p2) = r.parents(n)
141 (h, h1, h2) = map(hg.hex, (n, p1, p2))
141 (h, h1, h2) = map(hg.hex, (n, p1, p2))
142 (i1, i2) = map(r.rev, (p1, p2))
142 (i1, i2) = map(r.rev, (p1, p2))
143 cr = r.linkrev(n)
143 cr = r.linkrev(n)
144 cn = hg.hex(repo.changelog.node(cr))
144 cn = hg.hex(repo.changelog.node(cr))
145 print "rev: %4d:%s" % (i, h)
145 print "rev: %4d:%s" % (i, h)
146 print "changeset: %4d:%s" % (cr, cn)
146 print "changeset: %4d:%s" % (cr, cn)
147 print "parents: %4d:%s" % (i1, h1)
147 print "parents: %4d:%s" % (i1, h1)
148 if i2: print " %4d:%s" % (i2, h2)
148 if i2: print " %4d:%s" % (i2, h2)
149 else:
149 else:
150 print "missing filename"
150 print "missing filename"
151
151
152 elif cmd == "dump":
152 elif cmd == "dump":
153 if args:
153 if args:
154 r = repo.file(args[0])
154 r = repo.file(args[0])
155 n = r.tip()
155 n = r.tip()
156 if len(args) > 1: n = hg.bin(args[1])
156 if len(args) > 1: n = hg.bin(args[1])
157 sys.stdout.write(r.read(n))
157 sys.stdout.write(r.read(n))
158 else:
158 else:
159 print "missing filename"
159 print "missing filename"
160
160
161 elif cmd == "dumpmanifest":
161 elif cmd == "dumpmanifest":
162 n = repo.manifest.tip()
162 n = repo.manifest.tip()
163 if len(args) > 0:
163 if len(args) > 0:
164 n = hg.bin(args[0])
164 n = hg.bin(args[0])
165 m = repo.manifest.read(n)
165 m = repo.manifest.read(n)
166 files = m.keys()
166 files = m.keys()
167 files.sort()
167 files.sort()
168
168
169 for f in files:
169 for f in files:
170 print hg.hex(m[f]), f
170 print hg.hex(m[f]), f
171
171
172 elif cmd == "merge":
172 elif cmd == "merge":
173 if args:
173 if args:
174 other = hg.repository(ui, args[0])
174 other = hg.repository(ui, args[0])
175 repo.merge(other)
175 repo.merge(other)
176 else:
176 else:
177 print "missing source repository"
177 print "missing source repository"
178
178
179 elif cmd == "verify":
179 elif cmd == "verify":
180 filelinkrevs = {}
180 filelinkrevs = {}
181 filenodes = {}
181 filenodes = {}
182 manifestchangeset = {}
182 manifestchangeset = {}
183 changesets = revisions = files = 0
183 changesets = revisions = files = 0
184
184
185 print "checking changesets"
185 print "checking changesets"
186 for i in range(repo.changelog.count()):
186 for i in range(repo.changelog.count()):
187 changesets += 1
187 changesets += 1
188 n = repo.changelog.node(i)
188 n = repo.changelog.node(i)
189 changes = repo.changelog.read(n)
189 changes = repo.changelog.read(n)
190 manifestchangeset[changes[0]] = n
190 manifestchangeset[changes[0]] = n
191 for f in changes[3]:
191 for f in changes[3]:
192 revisions += 1
192 revisions += 1
193 filelinkrevs.setdefault(f, []).append(i)
193 filelinkrevs.setdefault(f, []).append(i)
194
194
195 print "checking manifests"
195 print "checking manifests"
196 for i in range(repo.manifest.count()):
196 for i in range(repo.manifest.count()):
197 n = repo.manifest.node(i)
197 n = repo.manifest.node(i)
198 ca = repo.changelog.node(repo.manifest.linkrev(n))
198 ca = repo.changelog.node(repo.manifest.linkrev(n))
199 cc = manifestchangeset[n]
199 cc = manifestchangeset[n]
200 if ca != cc:
200 if ca != cc:
201 print "manifest %s points to %s, not %s" % \
201 print "manifest %s points to %s, not %s" % \
202 (hg.hex(n), hg.hex(ca), hg.hex(cc))
202 (hg.hex(n), hg.hex(ca), hg.hex(cc))
203 m = repo.manifest.read(n)
203 m = repo.manifest.read(n)
204 for f, fn in m.items():
204 for f, fn in m.items():
205 filenodes.setdefault(f, {})[fn] = 1
205 filenodes.setdefault(f, {})[fn] = 1
206
206
207 print "crosschecking files in changesets and manifests"
207 print "crosschecking files in changesets and manifests"
208 for f in filenodes:
208 for f in filenodes:
209 if f not in filelinkrevs:
209 if f not in filelinkrevs:
210 print "file %s in manifest but not in changesets"
210 print "file %s in manifest but not in changesets"
211
211
212 for f in filelinkrevs:
212 for f in filelinkrevs:
213 if f not in filenodes:
213 if f not in filenodes:
214 print "file %s in changeset but not in manifest"
214 print "file %s in changeset but not in manifest"
215
215
216 print "checking files"
216 print "checking files"
217 for f in filenodes:
217 for f in filenodes:
218 files += 1
218 files += 1
219 fl = repo.file(f)
219 fl = repo.file(f)
220 nodes = {"\0"*20: 1}
220 nodes = {"\0"*20: 1}
221 for i in range(fl.count()):
221 for i in range(fl.count()):
222 n = fl.node(i)
222 n = fl.node(i)
223
223 if n not in filenodes[f]:
224 if n not in filenodes[f]:
224 print "%s:%s not in manifests" % (f, hg.hex(n))
225 print "%s:%s not in manifests" % (f, hg.hex(n))
225 if fl.linkrev(n) not in filelinkrevs[f]:
226 else:
227 del filenodes[f][n]
228
229 flr = fl.linkrev(n)
230 if flr not in filelinkrevs[f]:
226 print "%s:%s points to unexpected changeset rev %d" \
231 print "%s:%s points to unexpected changeset rev %d" \
227 % (f, hg.hex(n), fl.linkrev(n))
232 % (f, hg.hex(n), fl.linkrev(n))
233 else:
234 filelinkrevs[f].remove(flr)
235
236 # verify contents
228 t = fl.read(n)
237 t = fl.read(n)
238
239 # verify parents
229 (p1, p2) = fl.parents(n)
240 (p1, p2) = fl.parents(n)
230 if p1 not in nodes:
241 if p1 not in nodes:
231 print "%s:%s unknown parent 1 %s" % (f, hg.hex(n), hg.hex(p1))
242 print "%s:%s unknown parent 1 %s" % (f, hg.hex(n), hg.hex(p1))
232 if p2 not in nodes:
243 if p2 not in nodes:
233 print "file %s:%s unknown parent %s" % (f, hg.hex(n), hg.hex(p1))
244 print "file %s:%s unknown parent %s" % (f, hg.hex(n), hg.hex(p1))
245 nodes[n] = 1
234
246
235 nodes[n] = 1
247 # cross-check
248 for flr in filelinkrevs[f]:
249 print "changeset rev %d not in %s" % (flr, f)
250
251 for node in filenodes[f]:
252 print "node %s in manifests not in %s" % (hg.hex(n), f)
253
236
254
237 print "%d files, %d changesets, %d total revisions" % (files, changesets,
255 print "%d files, %d changesets, %d total revisions" % (files, changesets,
238 revisions)
256 revisions)
239
257
240 else:
258 else:
241 if cmd != "help":
259 if cmd != "help":
242 print "unknown command\n"
260 print "unknown command\n"
243
261
244 print """\
262 print """\
245 commands:
263 commands:
246
264
247 init create a new repository in this directory
265 init create a new repository in this directory
248 branch <path> create a branch of <path> in this directory
266 branch <path> create a branch of <path> in this directory
249 merge <path> merge changes from <path> into local repository
267 merge <path> merge changes from <path> into local repository
250 checkout [changeset] checkout the latest or given changeset
268 checkout [changeset] checkout the latest or given changeset
251 status show new, missing, and changed files in working dir
269 status show new, missing, and changed files in working dir
252 add [files...] add the given files in the next commit
270 add [files...] add the given files in the next commit
253 remove [files...] remove the given files in the next commit
271 remove [files...] remove the given files in the next commit
254 addremove add all new files, delete all missing files
272 addremove add all new files, delete all missing files
255 commit commit all changes to the repository
273 commit commit all changes to the repository
256 history show changeset history
274 history show changeset history
257 log <file> show revision history of a single file
275 log <file> show revision history of a single file
258 dump <file> [rev] dump the latest or given revision of a file
276 dump <file> [rev] dump the latest or given revision of a file
259 dumpmanifest [rev] dump the latest or given revision of the manifest
277 dumpmanifest [rev] dump the latest or given revision of the manifest
260 """
278 """
261 sys.exit(1)
279 sys.exit(1)
General Comments 0
You need to be logged in to leave comments. Login now