10 from revlog import * |
10 from revlog import * |
11 from demandload import * |
11 from demandload import * |
12 demandload(globals(), "re lock urllib urllib2 transaction time socket") |
12 demandload(globals(), "re lock urllib urllib2 transaction time socket") |
13 demandload(globals(), "tempfile httprangereader bdiff") |
13 demandload(globals(), "tempfile httprangereader bdiff") |
14 demandload(globals(), "bisect select") |
14 demandload(globals(), "bisect select") |
|
15 |
|
16 def always(fn): |
|
17 return True |
15 |
18 |
16 class filelog(revlog): |
19 class filelog(revlog): |
17 def __init__(self, opener, path): |
20 def __init__(self, opener, path): |
18 revlog.__init__(self, opener, |
21 revlog.__init__(self, opener, |
19 os.path.join("data", path + ".i"), |
22 os.path.join("data", path + ".i"), |
274 self.dirty = 0 |
277 self.dirty = 0 |
275 self.ui = ui |
278 self.ui = ui |
276 self.map = None |
279 self.map = None |
277 self.pl = None |
280 self.pl = None |
278 self.copies = {} |
281 self.copies = {} |
|
282 self.ignorefunc = None |
|
283 |
|
284 def wjoin(self, f): |
|
285 return os.path.join(self.root, f) |
|
286 |
|
287 def ignore(self, f): |
|
288 if not self.ignorefunc: |
|
289 bigpat = [] |
|
290 try: |
|
291 l = file(self.wjoin(".hgignore")) |
|
292 for pat in l: |
|
293 if pat != "\n": |
|
294 p = util.pconvert(pat[:-1]) |
|
295 try: |
|
296 r = re.compile(p) |
|
297 except: |
|
298 self.ui.warn("ignoring invalid ignore" |
|
299 + " regular expression '%s'\n" % p) |
|
300 else: |
|
301 bigpat.append(util.pconvert(pat[:-1])) |
|
302 except IOError: pass |
|
303 |
|
304 s = "(?:%s)" % (")|(?:".join(bigpat)) |
|
305 r = re.compile(s) |
|
306 self.ignorefunc = r.search |
|
307 |
|
308 return self.ignorefunc(f) |
279 |
309 |
280 def __del__(self): |
310 def __del__(self): |
281 if self.dirty: |
311 if self.dirty: |
282 self.write() |
312 self.write() |
283 |
313 |
331 self.map[f] = e[:4] |
365 self.map[f] = e[:4] |
332 pos += l |
366 pos += l |
333 |
367 |
334 def copy(self, source, dest): |
368 def copy(self, source, dest): |
335 self.read() |
369 self.read() |
336 self.dirty = 1 |
370 self.markdirty() |
337 self.copies[dest] = source |
371 self.copies[dest] = source |
338 |
372 |
339 def copied(self, file): |
373 def copied(self, file): |
340 return self.copies.get(file, None) |
374 return self.copies.get(file, None) |
341 |
375 |
346 r marked for removal |
380 r marked for removal |
347 a marked for addition''' |
381 a marked for addition''' |
348 |
382 |
349 if not files: return |
383 if not files: return |
350 self.read() |
384 self.read() |
351 self.dirty = 1 |
385 self.markdirty() |
352 for f in files: |
386 for f in files: |
353 if state == "r": |
387 if state == "r": |
354 self.map[f] = ('r', 0, 0, 0) |
388 self.map[f] = ('r', 0, 0, 0) |
355 else: |
389 else: |
356 s = os.stat(os.path.join(self.root, f)) |
390 s = os.stat(os.path.join(self.root, f)) |
357 self.map[f] = (state, s.st_mode, s.st_size, s.st_mtime) |
391 self.map[f] = (state, s.st_mode, s.st_size, s.st_mtime) |
358 |
392 |
359 def forget(self, files): |
393 def forget(self, files): |
360 if not files: return |
394 if not files: return |
361 self.read() |
395 self.read() |
362 self.dirty = 1 |
396 self.markdirty() |
363 for f in files: |
397 for f in files: |
364 try: |
398 try: |
365 del self.map[f] |
399 del self.map[f] |
366 except KeyError: |
400 except KeyError: |
367 self.ui.warn("not in dirstate: %s!\n" % f) |
401 self.ui.warn("not in dirstate: %s!\n" % f) |
368 pass |
402 pass |
369 |
403 |
370 def clear(self): |
404 def clear(self): |
371 self.map = {} |
405 self.map = {} |
372 self.dirty = 1 |
406 self.markdirty() |
373 |
407 |
374 def write(self): |
408 def write(self): |
375 st = self.opener("dirstate", "w") |
409 st = self.opener("dirstate", "w") |
376 st.write("".join(self.pl)) |
410 st.write("".join(self.pl)) |
377 for f, e in self.map.items(): |
411 for f, e in self.map.items(): |
380 f = f + "\0" + c |
414 f = f + "\0" + c |
381 e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f)) |
415 e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f)) |
382 st.write(e + f) |
416 st.write(e + f) |
383 self.dirty = 0 |
417 self.dirty = 0 |
384 |
418 |
385 def changes(self, files, ignore): |
419 def walk(self, files = None, match = always): |
386 self.read() |
420 self.read() |
387 dc = self.map.copy() |
421 dc = self.map.copy() |
388 lookup, changed, added, unknown = [], [], [], [] |
422 # walk all files by default |
389 |
|
390 # compare all files by default |
|
391 if not files: files = [self.root] |
423 if not files: files = [self.root] |
392 |
424 def traverse(): |
393 # recursive generator of all files listed |
|
394 def walk(files): |
|
395 for f in util.unique(files): |
425 for f in util.unique(files): |
396 f = os.path.join(self.root, f) |
426 f = os.path.join(self.root, f) |
397 if os.path.isdir(f): |
427 if os.path.isdir(f): |
398 for dir, subdirs, fl in os.walk(f): |
428 for dir, subdirs, fl in os.walk(f): |
399 d = dir[len(self.root) + 1:] |
429 d = dir[len(self.root) + 1:] |
|
430 if d == '.hg': |
|
431 subdirs[:] = [] |
|
432 continue |
400 for sd in subdirs: |
433 for sd in subdirs: |
401 if ignore(os.path.join(d, sd +'/')): |
434 ds = os.path.join(d, sd +'/') |
|
435 if self.ignore(ds) or not match(ds): |
402 subdirs.remove(sd) |
436 subdirs.remove(sd) |
403 for fn in fl: |
437 for fn in fl: |
404 fn = util.pconvert(os.path.join(d, fn)) |
438 fn = util.pconvert(os.path.join(d, fn)) |
405 yield fn |
439 yield fn |
406 else: |
440 else: |
407 yield f[len(self.root) + 1:] |
441 yield f[len(self.root) + 1:] |
408 |
442 |
409 for k in dc.keys(): |
443 for k in dc.keys(): |
410 yield k |
444 yield k |
411 |
445 |
412 for fn in util.unique(walk(files)): |
446 # yield only files that match: all in dirstate, others only if |
|
447 # not in .hgignore |
|
448 |
|
449 for fn in util.unique(traverse()): |
|
450 if fn in dc: |
|
451 del dc[fn] |
|
452 elif self.ignore(fn): |
|
453 continue |
|
454 if match(fn): |
|
455 yield fn |
|
456 |
|
457 def changes(self, files = None, match = always): |
|
458 self.read() |
|
459 dc = self.map.copy() |
|
460 lookup, changed, added, unknown = [], [], [], [] |
|
461 |
|
462 for fn in self.walk(files, match): |
413 try: s = os.stat(os.path.join(self.root, fn)) |
463 try: s = os.stat(os.path.join(self.root, fn)) |
414 except: continue |
464 except: continue |
415 |
465 |
416 if fn in dc: |
466 if fn in dc: |
417 c = dc[fn] |
467 c = dc[fn] |
426 elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100: |
476 elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100: |
427 changed.append(fn) |
477 changed.append(fn) |
428 elif c[1] != s.st_mode or c[3] != s.st_mtime: |
478 elif c[1] != s.st_mode or c[3] != s.st_mtime: |
429 lookup.append(fn) |
479 lookup.append(fn) |
430 else: |
480 else: |
431 if not ignore(fn): unknown.append(fn) |
481 if match(fn): unknown.append(fn) |
432 |
482 |
433 return (lookup, changed, added, dc.keys(), unknown) |
483 return (lookup, changed, added, dc.keys(), unknown) |
434 |
484 |
435 # used to avoid circular references so destructors work |
485 # used to avoid circular references so destructors work |
436 def opener(base): |
486 def opener(base): |
490 |
540 |
491 self.opener = opener(self.path) |
541 self.opener = opener(self.path) |
492 self.wopener = opener(self.root) |
542 self.wopener = opener(self.root) |
493 self.manifest = manifest(self.opener) |
543 self.manifest = manifest(self.opener) |
494 self.changelog = changelog(self.opener) |
544 self.changelog = changelog(self.opener) |
495 self.ignorefunc = None |
|
496 self.tagscache = None |
545 self.tagscache = None |
497 self.nodetagscache = None |
546 self.nodetagscache = None |
498 |
547 |
499 if not self.remote: |
548 if not self.remote: |
500 self.dirstate = dirstate(self.opener, ui, self.root) |
549 self.dirstate = dirstate(self.opener, ui, self.root) |
501 try: |
550 try: |
502 self.ui.readconfig(self.opener("hgrc")) |
551 self.ui.readconfig(self.opener("hgrc")) |
503 except IOError: pass |
552 except IOError: pass |
504 |
|
505 def ignore(self, f): |
|
506 if not self.ignorefunc: |
|
507 bigpat = ["^.hg/$"] |
|
508 try: |
|
509 l = file(self.wjoin(".hgignore")) |
|
510 for pat in l: |
|
511 if pat != "\n": |
|
512 p = util.pconvert(pat[:-1]) |
|
513 try: |
|
514 r = re.compile(p) |
|
515 except: |
|
516 self.ui.warn("ignoring invalid ignore" |
|
517 + " regular expression '%s'\n" % p) |
|
518 else: |
|
519 bigpat.append(util.pconvert(pat[:-1])) |
|
520 except IOError: pass |
|
521 |
|
522 s = "(?:%s)" % (")|(?:".join(bigpat)) |
|
523 r = re.compile(s) |
|
524 self.ignorefunc = r.search |
|
525 |
|
526 return self.ignorefunc(f) |
|
527 |
553 |
528 def hook(self, name, **args): |
554 def hook(self, name, **args): |
529 s = self.ui.config("hooks", name) |
555 s = self.ui.config("hooks", name) |
530 if s: |
556 if s: |
531 self.ui.note("running hook %s: %s\n" % (name, s)) |
557 self.ui.note("running hook %s: %s\n" % (name, s)) |
735 elif s == 'r': |
761 elif s == 'r': |
736 remove.append(f) |
762 remove.append(f) |
737 else: |
763 else: |
738 self.ui.warn("%s not tracked!\n" % f) |
764 self.ui.warn("%s not tracked!\n" % f) |
739 else: |
765 else: |
740 (c, a, d, u) = self.changes(None, None) |
766 (c, a, d, u) = self.changes() |
741 commit = c + a |
767 commit = c + a |
742 remove = d |
768 remove = d |
743 |
769 |
744 if not commit and not remove: |
770 if not commit and not remove: |
745 self.ui.status("nothing changed\n") |
771 self.ui.status("nothing changed\n") |
812 self.dirstate.forget(remove) |
838 self.dirstate.forget(remove) |
813 |
839 |
814 if not self.hook("commit", node=hex(n)): |
840 if not self.hook("commit", node=hex(n)): |
815 return 1 |
841 return 1 |
816 |
842 |
817 def changes(self, node1, node2, files=None): |
843 def walk(self, rev = None, files = [], match = always): |
|
844 if rev is None: fns = self.dirstate.walk(files, match) |
|
845 else: fns = filter(match, self.manifest.read(rev)) |
|
846 for fn in fns: yield fn |
|
847 |
|
848 def changes(self, node1 = None, node2 = None, files = [], match = always): |
818 mf2, u = None, [] |
849 mf2, u = None, [] |
819 |
850 |
820 def fcmp(fn, mf): |
851 def fcmp(fn, mf): |
821 t1 = self.wfile(fn).read() |
852 t1 = self.wfile(fn).read() |
822 t2 = self.file(fn).revision(mf[fn]) |
853 t2 = self.file(fn).revision(mf[fn]) |
823 return cmp(t1, t2) |
854 return cmp(t1, t2) |
824 |
855 |
|
856 def mfmatches(node): |
|
857 mf = dict(self.manifest.read(node)) |
|
858 for fn in mf.keys(): |
|
859 if not match(fn): |
|
860 del mf[fn] |
|
861 return mf |
|
862 |
825 # are we comparing the working directory? |
863 # are we comparing the working directory? |
826 if not node2: |
864 if not node2: |
827 l, c, a, d, u = self.dirstate.changes(files, self.ignore) |
865 l, c, a, d, u = self.dirstate.changes(files, match) |
828 |
866 |
829 # are we comparing working dir against its parent? |
867 # are we comparing working dir against its parent? |
830 if not node1: |
868 if not node1: |
831 if l: |
869 if l: |
832 # do a full compare of any files that might have changed |
870 # do a full compare of any files that might have changed |
833 change = self.changelog.read(self.dirstate.parents()[0]) |
871 change = self.changelog.read(self.dirstate.parents()[0]) |
834 mf2 = self.manifest.read(change[0]) |
872 mf2 = mfmatches(change[0]) |
835 for f in l: |
873 for f in l: |
836 if fcmp(f, mf2): |
874 if fcmp(f, mf2): |
837 c.append(f) |
875 c.append(f) |
838 |
876 |
839 for l in c, a, d, u: |
877 for l in c, a, d, u: |
844 # are we comparing working dir against non-tip? |
882 # are we comparing working dir against non-tip? |
845 # generate a pseudo-manifest for the working dir |
883 # generate a pseudo-manifest for the working dir |
846 if not node2: |
884 if not node2: |
847 if not mf2: |
885 if not mf2: |
848 change = self.changelog.read(self.dirstate.parents()[0]) |
886 change = self.changelog.read(self.dirstate.parents()[0]) |
849 mf2 = self.manifest.read(change[0]).copy() |
887 mf2 = mfmatches(change[0]) |
850 for f in a + c + l: |
888 for f in a + c + l: |
851 mf2[f] = "" |
889 mf2[f] = "" |
852 for f in d: |
890 for f in d: |
853 if f in mf2: del mf2[f] |
891 if f in mf2: del mf2[f] |
854 else: |
892 else: |
855 change = self.changelog.read(node2) |
893 change = self.changelog.read(node2) |
856 mf2 = self.manifest.read(change[0]) |
894 mf2 = mfmatches(change[0]) |
857 |
895 |
858 # flush lists from dirstate before comparing manifests |
896 # flush lists from dirstate before comparing manifests |
859 c, a = [], [] |
897 c, a = [], [] |
860 |
898 |
861 change = self.changelog.read(node1) |
899 change = self.changelog.read(node1) |
862 mf1 = self.manifest.read(change[0]).copy() |
900 mf1 = mfmatches(change[0]) |
863 |
901 |
864 for fn in mf2: |
902 for fn in mf2: |
865 if mf1.has_key(fn): |
903 if mf1.has_key(fn): |
866 if mf1[fn] != mf2[fn]: |
904 if mf1[fn] != mf2[fn]: |
867 if mf2[fn] != "" or fcmp(fn, mf1): |
905 if mf2[fn] != "" or fcmp(fn, mf1): |
1265 m2 = self.manifest.read(m2n) |
1303 m2 = self.manifest.read(m2n) |
1266 mf2 = self.manifest.readflags(m2n) |
1304 mf2 = self.manifest.readflags(m2n) |
1267 ma = self.manifest.read(man) |
1305 ma = self.manifest.read(man) |
1268 mfa = self.manifest.readflags(man) |
1306 mfa = self.manifest.readflags(man) |
1269 |
1307 |
1270 (c, a, d, u) = self.changes(None, None) |
1308 (c, a, d, u) = self.changes() |
1271 |
1309 |
1272 # is this a jump, or a merge? i.e. is there a linear path |
1310 # is this a jump, or a merge? i.e. is there a linear path |
1273 # from p1 to p2? |
1311 # from p1 to p2? |
1274 linear_path = (pa == p1 or pa == p2) |
1312 linear_path = (pa == p1 or pa == p2) |
1275 |
1313 |