8 import sys, struct, os |
8 import sys, struct, os |
9 import util |
9 import util |
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 urlparse") |
13 demandload(globals(), "tempfile httprangereader bdiff urlparse stat") |
14 demandload(globals(), "bisect select") |
14 demandload(globals(), "bisect select") |
15 |
15 |
16 class filelog(revlog): |
16 class filelog(revlog): |
17 def __init__(self, opener, path): |
17 def __init__(self, opener, path): |
18 revlog.__init__(self, opener, |
18 revlog.__init__(self, opener, |
390 self.copies[dest] = source |
390 self.copies[dest] = source |
391 |
391 |
392 def copied(self, file): |
392 def copied(self, file): |
393 return self.copies.get(file, None) |
393 return self.copies.get(file, None) |
394 |
394 |
395 def update(self, files, state): |
395 def update(self, files, state, **kw): |
396 ''' current states: |
396 ''' current states: |
397 n normal |
397 n normal |
398 m needs merging |
398 m needs merging |
399 r marked for removal |
399 r marked for removal |
400 a marked for addition''' |
400 a marked for addition''' |
405 for f in files: |
405 for f in files: |
406 if state == "r": |
406 if state == "r": |
407 self.map[f] = ('r', 0, 0, 0) |
407 self.map[f] = ('r', 0, 0, 0) |
408 else: |
408 else: |
409 s = os.stat(os.path.join(self.root, f)) |
409 s = os.stat(os.path.join(self.root, f)) |
410 self.map[f] = (state, s.st_mode, s.st_size, s.st_mtime) |
410 st_size = kw.get('st_size', s.st_size) |
|
411 st_mtime = kw.get('st_mtime', s.st_mtime) |
|
412 self.map[f] = (state, s.st_mode, st_size, st_mtime) |
411 |
413 |
412 def forget(self, files): |
414 def forget(self, files): |
413 if not files: return |
415 if not files: return |
414 self.read() |
416 self.read() |
415 self.markdirty() |
417 self.markdirty() |
482 elif self.ignore(fn): |
484 elif self.ignore(fn): |
483 continue |
485 continue |
484 if match(fn): |
486 if match(fn): |
485 yield src, fn |
487 yield src, fn |
486 |
488 |
487 def changes(self, files = None, match = util.always): |
489 def changes(self, files=None, match=util.always): |
488 self.read() |
490 self.read() |
489 dc = self.map.copy() |
491 dc = self.map.copy() |
490 lookup, changed, added, unknown = [], [], [], [] |
492 lookup, modified, added, unknown = [], [], [], [] |
|
493 removed, deleted = [], [] |
491 |
494 |
492 for src, fn in self.walk(files, match): |
495 for src, fn in self.walk(files, match): |
493 try: s = os.stat(os.path.join(self.root, fn)) |
496 try: |
494 except: continue |
497 s = os.stat(os.path.join(self.root, fn)) |
495 |
498 except OSError: |
496 if fn in dc: |
499 continue |
497 c = dc[fn] |
500 if not stat.S_ISREG(s.st_mode): |
|
501 continue |
|
502 c = dc.get(fn) |
|
503 if c: |
498 del dc[fn] |
504 del dc[fn] |
499 |
|
500 if c[0] == 'm': |
505 if c[0] == 'm': |
501 changed.append(fn) |
506 modified.append(fn) |
502 elif c[0] == 'a': |
507 elif c[0] == 'a': |
503 added.append(fn) |
508 added.append(fn) |
504 elif c[0] == 'r': |
509 elif c[0] == 'r': |
505 unknown.append(fn) |
510 unknown.append(fn) |
506 elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100: |
511 elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100: |
507 changed.append(fn) |
512 modified.append(fn) |
508 elif c[1] != s.st_mode or c[3] != s.st_mtime: |
513 elif c[3] != s.st_mtime: |
509 lookup.append(fn) |
514 lookup.append(fn) |
510 else: |
515 else: |
511 if match(fn): unknown.append(fn) |
516 unknown.append(fn) |
512 |
517 |
513 return (lookup, changed, added, filter(match, dc.keys()), unknown) |
518 for fn, c in [(fn, c) for fn, c in dc.items() if match(fn)]: |
|
519 if c[0] == 'r': |
|
520 removed.append(fn) |
|
521 else: |
|
522 deleted.append(fn) |
|
523 return (lookup, modified, added, removed + deleted, unknown) |
514 |
524 |
515 # used to avoid circular references so destructors work |
525 # used to avoid circular references so destructors work |
516 def opener(base): |
526 def opener(base): |
517 p = base |
527 p = base |
518 def o(path, mode="r"): |
528 def o(path, mode="r"): |
1561 for f in files: |
1571 for f in files: |
1562 self.ui.status("merging %s\n" % f) |
1572 self.ui.status("merging %s\n" % f) |
1563 m, o, flag = merge[f] |
1573 m, o, flag = merge[f] |
1564 self.merge3(f, m, o) |
1574 self.merge3(f, m, o) |
1565 util.set_exec(self.wjoin(f), flag) |
1575 util.set_exec(self.wjoin(f), flag) |
1566 if moddirstate and mode == 'm': |
1576 if moddirstate: |
1567 # only update dirstate on branch merge, otherwise we |
1577 if mode == 'm': |
1568 # could mark files with changes as unchanged |
1578 # only update dirstate on branch merge, otherwise we |
1569 self.dirstate.update([f], mode) |
1579 # could mark files with changes as unchanged |
|
1580 self.dirstate.update([f], mode) |
|
1581 elif p2 == nullid: |
|
1582 # update dirstate from parent1's manifest |
|
1583 m1n = self.changelog.read(p1)[0] |
|
1584 m1 = self.manifest.read(m1n) |
|
1585 f_len = len(self.file(f).read(m1[f])) |
|
1586 self.dirstate.update([f], mode, st_size=f_len, st_mtime=0) |
|
1587 else: |
|
1588 self.ui.warn("Second parent without branch merge!?\n" |
|
1589 "Dirstate for file %s may be wrong.\n" % f) |
1570 |
1590 |
1571 remove.sort() |
1591 remove.sort() |
1572 for f in remove: |
1592 for f in remove: |
1573 self.ui.note("removing %s\n" % f) |
1593 self.ui.note("removing %s\n" % f) |
1574 try: |
1594 try: |