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