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