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