##// END OF EJS Templates
Add improved rev lookup to diff and export
mpm@selenic.com -
r38:ed1d3e3c default
parent child Browse files
Show More
@@ -1,347 +1,346 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, time
18 import sys, os, time
19 from mercurial import hg, mdiff, fancyopts
19 from mercurial import hg, mdiff, fancyopts
20
20
21 def help():
21 def help():
22 print """\
22 print """\
23 commands:
23 commands:
24
24
25 init create a new repository in this directory
25 init create a new repository in this directory
26 branch <path> create a branch of <path> in this directory
26 branch <path> create a branch of <path> in this directory
27 merge <path> merge changes from <path> into local repository
27 merge <path> merge changes from <path> into local repository
28 checkout [changeset] checkout the latest or given changeset
28 checkout [changeset] checkout the latest or given changeset
29 status show new, missing, and changed files in working dir
29 status show new, missing, and changed files in working dir
30 add [files...] add the given files in the next commit
30 add [files...] add the given files in the next commit
31 remove [files...] remove the given files in the next commit
31 remove [files...] remove the given files in the next commit
32 addremove add all new files, delete all missing files
32 addremove add all new files, delete all missing files
33 commit commit all changes to the repository
33 commit commit all changes to the repository
34 history show changeset history
34 history show changeset history
35 log <file> show revision history of a single file
35 log <file> show revision history of a single file
36 dump <file> [rev] dump the latest or given revision of a file
36 dump <file> [rev] dump the latest or given revision of a file
37 dumpmanifest [rev] dump the latest or given revision of the manifest
37 dumpmanifest [rev] dump the latest or given revision of the manifest
38 diff [files...] diff working directory (or selected files)
38 diff [files...] diff working directory (or selected files)
39 """
39 """
40
40
41 def filterfiles(list, files):
41 def filterfiles(list, files):
42 l = [ x for x in list if x in files ]
42 l = [ x for x in list if x in files ]
43
43
44 for f in files:
44 for f in files:
45 if f[-1] != os.sep: f += os.sep
45 if f[-1] != os.sep: f += os.sep
46 l += [ x for x in list if x.startswith(f) ]
46 l += [ x for x in list if x.startswith(f) ]
47 return l
47 return l
48
48
49 def diff(files = None, node1 = None, node2 = None):
49 def diff(files = None, node1 = None, node2 = None):
50
50
51 if node2:
51 if node2:
52 change = repo.changelog.read(node2)
52 change = repo.changelog.read(node2)
53 mmap2 = repo.manifest.read(change[0])
53 mmap2 = repo.manifest.read(change[0])
54 (c, a, d) = repo.diffrevs(node1, node2)
54 (c, a, d) = repo.diffrevs(node1, node2)
55 def read(f): return repo.file(f).read(mmap2[f])
55 def read(f): return repo.file(f).read(mmap2[f])
56 else:
56 else:
57 if not node1:
57 if not node1:
58 node1 = repo.current
58 node1 = repo.current
59 (c, a, d) = repo.diffdir(repo.root, node1)
59 (c, a, d) = repo.diffdir(repo.root, node1)
60 def read(f): return file(f).read()
60 def read(f): return file(f).read()
61
61
62 change = repo.changelog.read(node1)
62 change = repo.changelog.read(node1)
63 mmap = repo.manifest.read(change[0])
63 mmap = repo.manifest.read(change[0])
64
64
65 if files:
65 if files:
66 (c, a, d) = map(lambda x: filterfiles(x, files), (c, a, d))
66 (c, a, d) = map(lambda x: filterfiles(x, files), (c, a, d))
67
67
68 for f in c:
68 for f in c:
69 to = repo.file(f).read(mmap[f])
69 to = repo.file(f).read(mmap[f])
70 tn = read(f)
70 tn = read(f)
71 sys.stdout.write(mdiff.unidiff(to, tn, f))
71 sys.stdout.write(mdiff.unidiff(to, tn, f))
72 for f in a:
72 for f in a:
73 to = ""
73 to = ""
74 tn = read(f)
74 tn = read(f)
75 sys.stdout.write(mdiff.unidiff(to, tn, f))
75 sys.stdout.write(mdiff.unidiff(to, tn, f))
76 for f in d:
76 for f in d:
77 to = repo.file(f).read(mmap[f])
77 to = repo.file(f).read(mmap[f])
78 tn = ""
78 tn = ""
79 sys.stdout.write(mdiff.unidiff(to, tn, f))
79 sys.stdout.write(mdiff.unidiff(to, tn, f))
80
80
81
81
82 options = {}
82 options = {}
83 opts = [('v', 'verbose', None, 'verbose'),
83 opts = [('v', 'verbose', None, 'verbose'),
84 ('d', 'debug', None, 'debug')]
84 ('d', 'debug', None, 'debug')]
85
85
86 args = fancyopts.fancyopts(sys.argv[1:], opts, options,
86 args = fancyopts.fancyopts(sys.argv[1:], opts, options,
87 'hg [options] <command> [command options] [files]')
87 'hg [options] <command> [command options] [files]')
88
88
89 try:
89 try:
90 cmd = args[0]
90 cmd = args[0]
91 args = args[1:]
91 args = args[1:]
92 except:
92 except:
93 cmd = ""
93 cmd = ""
94
94
95 ui = hg.ui(options["verbose"], options["debug"])
95 ui = hg.ui(options["verbose"], options["debug"])
96
96
97 if cmd == "init":
97 if cmd == "init":
98 repo = hg.repository(ui, ".", create=1)
98 repo = hg.repository(ui, ".", create=1)
99 sys.exit(0)
99 sys.exit(0)
100 elif cmd == "branch" or cmd == "clone":
100 elif cmd == "branch" or cmd == "clone":
101 os.system("cp -al %s/.hg .hg" % args[0])
101 os.system("cp -al %s/.hg .hg" % args[0])
102 sys.exit(0)
102 sys.exit(0)
103 elif cmd == "help":
103 elif cmd == "help":
104 help()
104 help()
105 sys.exit(0)
105 sys.exit(0)
106 else:
106 else:
107 try:
107 try:
108 repo = hg.repository(ui=ui)
108 repo = hg.repository(ui=ui)
109 except:
109 except:
110 print "Unable to open repository"
110 print "Unable to open repository"
111 sys.exit(0)
111 sys.exit(0)
112
112
113 if cmd == "checkout" or cmd == "co":
113 if cmd == "checkout" or cmd == "co":
114 node = repo.changelog.tip()
114 node = repo.changelog.tip()
115 if len(args):
115 if len(args):
116 if len(args[0]) < 40:
116 if len(args[0]) < 40:
117 rev = int(args[0])
117 rev = int(args[0])
118 node = repo.changelog.node(rev)
118 node = repo.changelog.node(rev)
119 else:
119 else:
120 node = args[0]
120 node = args[0]
121 repo.checkout(node)
121 repo.checkout(node)
122
122
123 elif cmd == "add":
123 elif cmd == "add":
124 repo.add(args)
124 repo.add(args)
125
125
126 elif cmd == "remove" or cmd == "rm" or cmd == "del" or cmd == "delete":
126 elif cmd == "remove" or cmd == "rm" or cmd == "del" or cmd == "delete":
127 repo.remove(args)
127 repo.remove(args)
128
128
129 elif cmd == "commit" or cmd == "checkin" or cmd == "ci":
129 elif cmd == "commit" or cmd == "checkin" or cmd == "ci":
130 if 1:
130 if 1:
131 if len(args) > 0:
131 if len(args) > 0:
132 repo.commit(repo.current, args)
132 repo.commit(repo.current, args)
133 else:
133 else:
134 repo.commit(repo.current)
134 repo.commit(repo.current)
135
135
136 elif cmd == "import" or cmd == "patch":
136 elif cmd == "import" or cmd == "patch":
137 ioptions = {}
137 ioptions = {}
138 opts = [('p', 'strip', 1, 'path strip'),
138 opts = [('p', 'strip', 1, 'path strip'),
139 ('b', 'base', "", 'base path')]
139 ('b', 'base', "", 'base path')]
140
140
141 args = fancyopts.fancyopts(args, opts, ioptions,
141 args = fancyopts.fancyopts(args, opts, ioptions,
142 'hg import [options] <patch names>')
142 'hg import [options] <patch names>')
143 d = ioptions["base"]
143 d = ioptions["base"]
144 strip = ioptions["strip"]
144 strip = ioptions["strip"]
145
145
146 for patch in args:
146 for patch in args:
147 ui.status("applying %s\n" % patch)
147 ui.status("applying %s\n" % patch)
148 pf = d + patch
148 pf = d + patch
149 os.system("patch -p%d < %s > /dev/null" % (strip, pf))
149 os.system("patch -p%d < %s > /dev/null" % (strip, pf))
150 f = os.popen("lsdiff --strip %d %s" % (strip, pf))
150 f = os.popen("lsdiff --strip %d %s" % (strip, pf))
151 files = f.read().splitlines()
151 files = f.read().splitlines()
152 f.close()
152 f.close()
153 repo.commit(files)
153 repo.commit(files)
154
154
155 elif cmd == "status":
155 elif cmd == "status":
156 (c, a, d) = repo.diffdir(repo.root, repo.current)
156 (c, a, d) = repo.diffdir(repo.root, repo.current)
157 for f in c: print "C", f
157 for f in c: print "C", f
158 for f in a: print "?", f
158 for f in a: print "?", f
159 for f in d: print "R", f
159 for f in d: print "R", f
160
160
161 elif cmd == "diff":
161 elif cmd == "diff":
162 doptions = {}
163 revs = []
162 revs = []
164
163
165 if args:
164 if args:
165 doptions = {}
166 opts = [('r', 'revision', [], 'revision')]
166 opts = [('r', 'revision', [], 'revision')]
167 args = fancyopts.fancyopts(args, opts, doptions,
167 args = fancyopts.fancyopts(args, opts, doptions,
168 'hg diff [options] [files]')
168 'hg diff [options] [files]')
169 # revs = [ repo.lookup(x) for x in doptions['revision'] ]
169 revs = map(lambda x: repo.changelog.lookup(x), doptions['revision'])
170 revs = [hg.bin(x) for x in doptions['revision']]
171
170
172 if len(revs) > 2:
171 if len(revs) > 2:
173 print "too many revisions to diff"
172 print "too many revisions to diff"
174 sys.exit(1)
173 sys.exit(1)
175 else:
174 else:
176 diff(args, *revs)
175 diff(args, *revs)
177
176
178 elif cmd == "export":
177 elif cmd == "export":
179 node = hg.bin(args[0])
178 node = repo.changelog.lookup(args[0])
180 prev = repo.changelog.parents(node)[0]
179 prev = repo.changelog.parents(node)[0]
181 diff(None, prev, node)
180 diff(None, prev, node)
182
181
183 elif cmd == "addremove":
182 elif cmd == "addremove":
184 (c, a, d) = repo.diffdir(repo.root, repo.current)
183 (c, a, d) = repo.diffdir(repo.root, repo.current)
185 repo.add(a)
184 repo.add(a)
186 repo.remove(d)
185 repo.remove(d)
187
186
188 elif cmd == "history":
187 elif cmd == "history":
189 for i in range(repo.changelog.count()):
188 for i in range(repo.changelog.count()):
190 n = repo.changelog.node(i)
189 n = repo.changelog.node(i)
191 changes = repo.changelog.read(n)
190 changes = repo.changelog.read(n)
192 (p1, p2) = repo.changelog.parents(n)
191 (p1, p2) = repo.changelog.parents(n)
193 (h, h1, h2) = map(hg.hex, (n, p1, p2))
192 (h, h1, h2) = map(hg.hex, (n, p1, p2))
194 (i1, i2) = map(repo.changelog.rev, (p1, p2))
193 (i1, i2) = map(repo.changelog.rev, (p1, p2))
195 print "rev: %4d:%s" % (i, h)
194 print "rev: %4d:%s" % (i, h)
196 print "parents: %4d:%s" % (i1, h1)
195 print "parents: %4d:%s" % (i1, h1)
197 if i2: print " %4d:%s" % (i2, h2)
196 if i2: print " %4d:%s" % (i2, h2)
198 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
197 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
199 hg.hex(changes[0]))
198 hg.hex(changes[0]))
200 print "user:", changes[1]
199 print "user:", changes[1]
201 print "date:", time.asctime(
200 print "date:", time.asctime(
202 time.localtime(float(changes[2].split(' ')[0])))
201 time.localtime(float(changes[2].split(' ')[0])))
203 print "files:", " ".join(changes[3])
202 print "files:", " ".join(changes[3])
204 print "description:"
203 print "description:"
205 print changes[4]
204 print changes[4]
206
205
207 elif cmd == "log":
206 elif cmd == "log":
208 if args:
207 if args:
209 r = repo.file(args[0])
208 r = repo.file(args[0])
210 for i in range(r.count()):
209 for i in range(r.count()):
211 n = r.node(i)
210 n = r.node(i)
212 (p1, p2) = r.parents(n)
211 (p1, p2) = r.parents(n)
213 (h, h1, h2) = map(hg.hex, (n, p1, p2))
212 (h, h1, h2) = map(hg.hex, (n, p1, p2))
214 (i1, i2) = map(r.rev, (p1, p2))
213 (i1, i2) = map(r.rev, (p1, p2))
215 cr = r.linkrev(n)
214 cr = r.linkrev(n)
216 cn = hg.hex(repo.changelog.node(cr))
215 cn = hg.hex(repo.changelog.node(cr))
217 print "rev: %4d:%s" % (i, h)
216 print "rev: %4d:%s" % (i, h)
218 print "changeset: %4d:%s" % (cr, cn)
217 print "changeset: %4d:%s" % (cr, cn)
219 print "parents: %4d:%s" % (i1, h1)
218 print "parents: %4d:%s" % (i1, h1)
220 if i2: print " %4d:%s" % (i2, h2)
219 if i2: print " %4d:%s" % (i2, h2)
221 else:
220 else:
222 print "missing filename"
221 print "missing filename"
223
222
224 elif cmd == "dump":
223 elif cmd == "dump":
225 if args:
224 if args:
226 r = repo.file(args[0])
225 r = repo.file(args[0])
227 n = r.tip()
226 n = r.tip()
228 if len(args) > 1: n = hg.bin(args[1])
227 if len(args) > 1: n = hg.bin(args[1])
229 sys.stdout.write(r.read(n))
228 sys.stdout.write(r.read(n))
230 else:
229 else:
231 print "missing filename"
230 print "missing filename"
232
231
233 elif cmd == "dumpmanifest":
232 elif cmd == "dumpmanifest":
234 n = repo.manifest.tip()
233 n = repo.manifest.tip()
235 if len(args) > 0:
234 if len(args) > 0:
236 n = hg.bin(args[0])
235 n = hg.bin(args[0])
237 m = repo.manifest.read(n)
236 m = repo.manifest.read(n)
238 files = m.keys()
237 files = m.keys()
239 files.sort()
238 files.sort()
240
239
241 for f in files:
240 for f in files:
242 print hg.hex(m[f]), f
241 print hg.hex(m[f]), f
243
242
244 elif cmd == "debughash":
243 elif cmd == "debughash":
245 f = repo.file(args[0])
244 f = repo.file(args[0])
246 print f.encodepath(args[0])
245 print f.encodepath(args[0])
247
246
248 elif cmd == "debugindex":
247 elif cmd == "debugindex":
249 r = hg.revlog(open, args[0], "")
248 r = hg.revlog(open, args[0], "")
250 print " rev offset length base linkrev"+\
249 print " rev offset length base linkrev"+\
251 " p1 p2 nodeid"
250 " p1 p2 nodeid"
252 for i in range(r.count()):
251 for i in range(r.count()):
253 e = r.index[i]
252 e = r.index[i]
254 print "% 6d % 9d % 7d % 5d % 7d %s.. %s.. %s.." % (
253 print "% 6d % 9d % 7d % 5d % 7d %s.. %s.. %s.." % (
255 i, e[0], e[1], e[2], e[3],
254 i, e[0], e[1], e[2], e[3],
256 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5]))
255 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5]))
257
256
258 elif cmd == "merge":
257 elif cmd == "merge":
259 if args:
258 if args:
260 other = hg.repository(ui, args[0])
259 other = hg.repository(ui, args[0])
261 repo.merge(other)
260 repo.merge(other)
262 else:
261 else:
263 print "missing source repository"
262 print "missing source repository"
264
263
265 elif cmd == "verify":
264 elif cmd == "verify":
266 filelinkrevs = {}
265 filelinkrevs = {}
267 filenodes = {}
266 filenodes = {}
268 manifestchangeset = {}
267 manifestchangeset = {}
269 changesets = revisions = files = 0
268 changesets = revisions = files = 0
270
269
271 print "checking changesets"
270 print "checking changesets"
272 for i in range(repo.changelog.count()):
271 for i in range(repo.changelog.count()):
273 changesets += 1
272 changesets += 1
274 n = repo.changelog.node(i)
273 n = repo.changelog.node(i)
275 changes = repo.changelog.read(n)
274 changes = repo.changelog.read(n)
276 manifestchangeset[changes[0]] = n
275 manifestchangeset[changes[0]] = n
277 for f in changes[3]:
276 for f in changes[3]:
278 revisions += 1
277 revisions += 1
279 filelinkrevs.setdefault(f, []).append(i)
278 filelinkrevs.setdefault(f, []).append(i)
280
279
281 print "checking manifests"
280 print "checking manifests"
282 for i in range(repo.manifest.count()):
281 for i in range(repo.manifest.count()):
283 n = repo.manifest.node(i)
282 n = repo.manifest.node(i)
284 ca = repo.changelog.node(repo.manifest.linkrev(n))
283 ca = repo.changelog.node(repo.manifest.linkrev(n))
285 cc = manifestchangeset[n]
284 cc = manifestchangeset[n]
286 if ca != cc:
285 if ca != cc:
287 print "manifest %s points to %s, not %s" % \
286 print "manifest %s points to %s, not %s" % \
288 (hg.hex(n), hg.hex(ca), hg.hex(cc))
287 (hg.hex(n), hg.hex(ca), hg.hex(cc))
289 m = repo.manifest.read(n)
288 m = repo.manifest.read(n)
290 for f, fn in m.items():
289 for f, fn in m.items():
291 filenodes.setdefault(f, {})[fn] = 1
290 filenodes.setdefault(f, {})[fn] = 1
292
291
293 print "crosschecking files in changesets and manifests"
292 print "crosschecking files in changesets and manifests"
294 for f in filenodes:
293 for f in filenodes:
295 if f not in filelinkrevs:
294 if f not in filelinkrevs:
296 print "file %s in manifest but not in changesets"
295 print "file %s in manifest but not in changesets"
297
296
298 for f in filelinkrevs:
297 for f in filelinkrevs:
299 if f not in filenodes:
298 if f not in filenodes:
300 print "file %s in changeset but not in manifest"
299 print "file %s in changeset but not in manifest"
301
300
302 print "checking files"
301 print "checking files"
303 for f in filenodes:
302 for f in filenodes:
304 files += 1
303 files += 1
305 fl = repo.file(f)
304 fl = repo.file(f)
306 nodes = {"\0"*20: 1}
305 nodes = {"\0"*20: 1}
307 for i in range(fl.count()):
306 for i in range(fl.count()):
308 n = fl.node(i)
307 n = fl.node(i)
309
308
310 if n not in filenodes[f]:
309 if n not in filenodes[f]:
311 print "%s:%s not in manifests" % (f, hg.hex(n))
310 print "%s:%s not in manifests" % (f, hg.hex(n))
312 else:
311 else:
313 del filenodes[f][n]
312 del filenodes[f][n]
314
313
315 flr = fl.linkrev(n)
314 flr = fl.linkrev(n)
316 if flr not in filelinkrevs[f]:
315 if flr not in filelinkrevs[f]:
317 print "%s:%s points to unexpected changeset rev %d" \
316 print "%s:%s points to unexpected changeset rev %d" \
318 % (f, hg.hex(n), fl.linkrev(n))
317 % (f, hg.hex(n), fl.linkrev(n))
319 else:
318 else:
320 filelinkrevs[f].remove(flr)
319 filelinkrevs[f].remove(flr)
321
320
322 # verify contents
321 # verify contents
323 t = fl.read(n)
322 t = fl.read(n)
324
323
325 # verify parents
324 # verify parents
326 (p1, p2) = fl.parents(n)
325 (p1, p2) = fl.parents(n)
327 if p1 not in nodes:
326 if p1 not in nodes:
328 print "%s:%s unknown parent 1 %s" % (f, hg.hex(n), hg.hex(p1))
327 print "%s:%s unknown parent 1 %s" % (f, hg.hex(n), hg.hex(p1))
329 if p2 not in nodes:
328 if p2 not in nodes:
330 print "file %s:%s unknown parent %s" % (f, hg.hex(n), hg.hex(p1))
329 print "file %s:%s unknown parent %s" % (f, hg.hex(n), hg.hex(p1))
331 nodes[n] = 1
330 nodes[n] = 1
332
331
333 # cross-check
332 # cross-check
334 for flr in filelinkrevs[f]:
333 for flr in filelinkrevs[f]:
335 print "changeset rev %d not in %s" % (flr, f)
334 print "changeset rev %d not in %s" % (flr, f)
336
335
337 for node in filenodes[f]:
336 for node in filenodes[f]:
338 print "node %s in manifests not in %s" % (hg.hex(n), f)
337 print "node %s in manifests not in %s" % (hg.hex(n), f)
339
338
340
339
341 print "%d files, %d changesets, %d total revisions" % (files, changesets,
340 print "%d files, %d changesets, %d total revisions" % (files, changesets,
342 revisions)
341 revisions)
343
342
344 else:
343 else:
345 print "unknown command\n"
344 print "unknown command\n"
346 help()
345 help()
347 sys.exit(1)
346 sys.exit(1)
General Comments 0
You need to be logged in to leave comments. Login now