/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

  • Committer: Jonathan Lange
  • Date: 2009-12-09 09:20:42 UTC
  • mfrom: (4881 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4907.
  • Revision ID: jml@canonical.com-20091209092042-s2zgqcf8f39yzxpj
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
58
58
    errors,
59
59
    generate_ids,
60
60
    globbing,
 
61
    graph as _mod_graph,
61
62
    hashcache,
62
63
    ignores,
63
64
    inventory,
64
65
    merge,
65
66
    revision as _mod_revision,
66
67
    revisiontree,
67
 
    textui,
68
68
    trace,
69
69
    transform,
70
70
    ui,
280
280
        self._control_files.break_lock()
281
281
        self.branch.break_lock()
282
282
 
 
283
    def _get_check_refs(self):
 
284
        """Return the references needed to perform a check of this tree.
 
285
        
 
286
        The default implementation returns no refs, and is only suitable for
 
287
        trees that have no local caching and can commit on ghosts at any time.
 
288
 
 
289
        :seealso: bzrlib.check for details about check_refs.
 
290
        """
 
291
        return []
 
292
 
283
293
    def requires_rich_root(self):
284
294
        return self._format.requires_rich_root
285
295
 
477
487
        incorrectly attributed to CURRENT_REVISION (but after committing, the
478
488
        attribution will be correct).
479
489
        """
480
 
        basis = self.basis_tree()
481
 
        basis.lock_read()
482
 
        try:
483
 
            changes = self.iter_changes(basis, True, [self.id2path(file_id)],
484
 
                require_versioned=True).next()
485
 
            changed_content, kind = changes[2], changes[6]
486
 
            if not changed_content:
487
 
                return basis.annotate_iter(file_id)
488
 
            if kind[1] is None:
489
 
                return None
490
 
            import annotate
491
 
            if kind[0] != 'file':
492
 
                old_lines = []
493
 
            else:
494
 
                old_lines = list(basis.annotate_iter(file_id))
495
 
            old = [old_lines]
496
 
            for tree in self.branch.repository.revision_trees(
497
 
                self.get_parent_ids()[1:]):
498
 
                if file_id not in tree:
499
 
                    continue
500
 
                old.append(list(tree.annotate_iter(file_id)))
501
 
            return annotate.reannotate(old, self.get_file(file_id).readlines(),
502
 
                                       default_revision)
503
 
        finally:
504
 
            basis.unlock()
 
490
        maybe_file_parent_keys = []
 
491
        for parent_id in self.get_parent_ids():
 
492
            try:
 
493
                parent_tree = self.revision_tree(parent_id)
 
494
            except errors.NoSuchRevisionInTree:
 
495
                parent_tree = self.branch.repository.revision_tree(parent_id)
 
496
            parent_tree.lock_read()
 
497
            try:
 
498
                if file_id not in parent_tree:
 
499
                    continue
 
500
                ie = parent_tree.inventory[file_id]
 
501
                if ie.kind != 'file':
 
502
                    # Note: this is slightly unnecessary, because symlinks and
 
503
                    # directories have a "text" which is the empty text, and we
 
504
                    # know that won't mess up annotations. But it seems cleaner
 
505
                    continue
 
506
                parent_text_key = (file_id, ie.revision)
 
507
                if parent_text_key not in maybe_file_parent_keys:
 
508
                    maybe_file_parent_keys.append(parent_text_key)
 
509
            finally:
 
510
                parent_tree.unlock()
 
511
        graph = _mod_graph.Graph(self.branch.repository.texts)
 
512
        heads = graph.heads(maybe_file_parent_keys)
 
513
        file_parent_keys = []
 
514
        for key in maybe_file_parent_keys:
 
515
            if key in heads:
 
516
                file_parent_keys.append(key)
 
517
 
 
518
        # Now we have the parents of this content
 
519
        annotator = self.branch.repository.texts.get_annotator()
 
520
        text = self.get_file(file_id).read()
 
521
        this_key =(file_id, default_revision)
 
522
        annotator.add_special_text(this_key, file_parent_keys, text)
 
523
        annotations = [(key[-1], line)
 
524
                       for key, line in annotator.annotate_flat(this_key)]
 
525
        return annotations
505
526
 
506
527
    def _get_ancestors(self, default_revision):
507
528
        ancestors = set([default_revision])
522
543
        else:
523
544
            parents = [last_rev]
524
545
        try:
525
 
            merges_file = self._transport.get('pending-merges')
 
546
            merges_bytes = self._transport.get_bytes('pending-merges')
526
547
        except errors.NoSuchFile:
527
548
            pass
528
549
        else:
529
 
            for l in merges_file.readlines():
 
550
            for l in osutils.split_lines(merges_bytes):
530
551
                revision_id = l.rstrip('\n')
531
552
                parents.append(revision_id)
532
553
        return parents
591
612
 
592
613
    def get_file_size(self, file_id):
593
614
        """See Tree.get_file_size"""
 
615
        # XXX: this returns the on-disk size; it should probably return the
 
616
        # canonical size
594
617
        try:
595
618
            return os.path.getsize(self.id2abspath(file_id))
596
619
        except OSError, e:
612
635
 
613
636
    def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
614
637
        file_id = self.path2id(path)
 
638
        if file_id is None:
 
639
            # For unversioned files on win32, we just assume they are not
 
640
            # executable
 
641
            return False
615
642
        return self._inventory[file_id].executable
616
643
 
617
644
    def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
727
754
            raise
728
755
        kind = _mapper(stat_result.st_mode)
729
756
        if kind == 'file':
730
 
            size = stat_result.st_size
731
 
            # try for a stat cache lookup
732
 
            executable = self._is_executable_from_path_and_stat(path, stat_result)
733
 
            return (kind, size, executable, self._sha_from_stat(
734
 
                path, stat_result))
 
757
            return self._file_content_summary(path, stat_result)
735
758
        elif kind == 'directory':
736
759
            # perhaps it looks like a plain directory, but it's really a
737
760
            # reference.
744
767
        else:
745
768
            return (kind, None, None, None)
746
769
 
 
770
    def _file_content_summary(self, path, stat_result):
 
771
        size = stat_result.st_size
 
772
        executable = self._is_executable_from_path_and_stat(path, stat_result)
 
773
        # try for a stat cache lookup
 
774
        return ('file', size, executable, self._sha_from_stat(
 
775
            path, stat_result))
 
776
 
747
777
    def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
748
778
        """Common ghost checking functionality from set_parent_*.
749
779
 
869
899
 
870
900
    @needs_write_lock # because merge pulls data into the branch.
871
901
    def merge_from_branch(self, branch, to_revision=None, from_revision=None,
872
 
        merge_type=None):
 
902
                          merge_type=None, force=False):
873
903
        """Merge from a branch into this working tree.
874
904
 
875
905
        :param branch: The branch to merge from.
884
914
            merger = Merger(self.branch, this_tree=self, pb=pb)
885
915
            merger.pp = ProgressPhase("Merge phase", 5, pb)
886
916
            merger.pp.next_phase()
887
 
            # check that there are no
888
 
            # local alterations
889
 
            merger.check_basis(check_clean=True, require_commits=False)
 
917
            # check that there are no local alterations
 
918
            if not force and self.has_changes():
 
919
                raise errors.UncommittedChanges(self)
890
920
            if to_revision is None:
891
921
                to_revision = _mod_revision.ensure_null(branch.last_revision())
892
922
            merger.other_rev_id = to_revision
1464
1494
        from_tail = splitpath(from_rel)[-1]
1465
1495
        from_id = inv.path2id(from_rel)
1466
1496
        if from_id is None:
1467
 
            raise errors.BzrRenameFailedError(from_rel,to_rel,
1468
 
                errors.NotVersionedError(path=str(from_rel)))
1469
 
        from_entry = inv[from_id]
 
1497
            # if file is missing in the inventory maybe it's in the basis_tree
 
1498
            basis_tree = self.branch.basis_tree()
 
1499
            from_id = basis_tree.path2id(from_rel)
 
1500
            if from_id is None:
 
1501
                raise errors.BzrRenameFailedError(from_rel,to_rel,
 
1502
                    errors.NotVersionedError(path=str(from_rel)))
 
1503
            # put entry back in the inventory so we can rename it
 
1504
            from_entry = basis_tree.inventory[from_id].copy()
 
1505
            inv.add(from_entry)
 
1506
        else:
 
1507
            from_entry = inv[from_id]
1470
1508
        from_parent_id = from_entry.parent_id
1471
1509
        to_dir, to_tail = os.path.split(to_rel)
1472
1510
        to_dir_id = inv.path2id(to_dir)
1806
1844
    def _reset_data(self):
1807
1845
        """Reset transient data that cannot be revalidated."""
1808
1846
        self._inventory_is_modified = False
1809
 
        result = self._deserialize(self._transport.get('inventory'))
 
1847
        f = self._transport.get('inventory')
 
1848
        try:
 
1849
            result = self._deserialize(f)
 
1850
        finally:
 
1851
            f.close()
1810
1852
        self._set_inventory(result, dirty=False)
1811
1853
 
1812
1854
    @needs_tree_write_lock
1863
1905
            firstline = xml.split('\n', 1)[0]
1864
1906
            if (not 'revision_id="' in firstline or
1865
1907
                'format="7"' not in firstline):
1866
 
                inv = self.branch.repository.deserialise_inventory(
1867
 
                    new_revision, xml)
 
1908
                inv = self.branch.repository._serializer.read_inventory_from_string(
 
1909
                    xml, new_revision)
1868
1910
                xml = self._create_basis_xml_from_inventory(new_revision, inv)
1869
1911
            self._write_basis_inventory(xml)
1870
1912
        except (errors.NoSuchRevision, errors.RevisionNotPresent):
1888
1930
        # binary.
1889
1931
        if self._inventory_is_modified:
1890
1932
            raise errors.InventoryModified(self)
1891
 
        result = self._deserialize(self._transport.get('inventory'))
 
1933
        f = self._transport.get('inventory')
 
1934
        try:
 
1935
            result = self._deserialize(f)
 
1936
        finally:
 
1937
            f.close()
1892
1938
        self._set_inventory(result, dirty=False)
1893
1939
        return result
1894
1940
 
1909
1955
 
1910
1956
        new_files=set()
1911
1957
        unknown_nested_files=set()
 
1958
        if to_file is None:
 
1959
            to_file = sys.stdout
1912
1960
 
1913
1961
        def recurse_directory_to_add_files(directory):
1914
1962
            # Recurse directory and add all files
1984
2032
                        new_status = 'I'
1985
2033
                    else:
1986
2034
                        new_status = '?'
1987
 
                    textui.show_status(new_status, self.kind(fid), f,
1988
 
                                       to_file=to_file)
 
2035
                    # XXX: Really should be a more abstract reporter interface
 
2036
                    kind_ch = osutils.kind_marker(self.kind(fid))
 
2037
                    to_file.write(new_status + '       ' + f + kind_ch + '\n')
1989
2038
                # Unversion file
1990
2039
                inv_delta.append((f, None, fid, None))
1991
2040
                message = "removed %s" % (f,)
2516
2565
        return un_resolved, resolved
2517
2566
 
2518
2567
    @needs_read_lock
2519
 
    def _check(self):
 
2568
    def _check(self, references):
 
2569
        """Check the tree for consistency.
 
2570
 
 
2571
        :param references: A dict with keys matching the items returned by
 
2572
            self._get_check_refs(), and values from looking those keys up in
 
2573
            the repository.
 
2574
        """
2520
2575
        tree_basis = self.basis_tree()
2521
2576
        tree_basis.lock_read()
2522
2577
        try:
2523
 
            repo_basis = self.branch.repository.revision_tree(
2524
 
                self.last_revision())
 
2578
            repo_basis = references[('trees', self.last_revision())]
2525
2579
            if len(list(repo_basis.iter_changes(tree_basis))) > 0:
2526
2580
                raise errors.BzrCheckError(
2527
2581
                    "Mismatched basis inventory content.")
2540
2594
        """
2541
2595
        return
2542
2596
 
2543
 
    @needs_read_lock
2544
2597
    def _get_rules_searcher(self, default_searcher):
2545
2598
        """See Tree._get_rules_searcher."""
2546
2599
        if self._rules_searcher is None:
2573
2626
        if self._inventory is None:
2574
2627
            self.read_working_inventory()
2575
2628
 
 
2629
    def _get_check_refs(self):
 
2630
        """Return the references needed to perform a check of this tree."""
 
2631
        return [('trees', self.last_revision())]
 
2632
 
2576
2633
    def lock_tree_write(self):
2577
2634
        """See WorkingTree.lock_tree_write().
2578
2635
 
2635
2692
                mode=self.bzrdir._get_file_mode())
2636
2693
            return True
2637
2694
 
 
2695
    def _get_check_refs(self):
 
2696
        """Return the references needed to perform a check of this tree."""
 
2697
        return [('trees', self.last_revision())]
 
2698
 
2638
2699
    @needs_tree_write_lock
2639
2700
    def set_conflicts(self, conflicts):
2640
2701
        self._put_rio('conflicts', conflicts.to_stanzas(),
2717
2778
        """Return the format for the working tree object in a_bzrdir."""
2718
2779
        try:
2719
2780
            transport = a_bzrdir.get_workingtree_transport(None)
2720
 
            format_string = transport.get("format").read()
 
2781
            format_string = transport.get_bytes("format")
2721
2782
            return klass._formats[format_string]
2722
2783
        except errors.NoSuchFile:
2723
2784
            raise errors.NoWorkingTree(base=transport.base)
2987
3048
        return self.get_format_string()
2988
3049
 
2989
3050
 
2990
 
__default_format = WorkingTreeFormat4()
 
3051
__default_format = WorkingTreeFormat6()
2991
3052
WorkingTreeFormat.register_format(__default_format)
2992
 
WorkingTreeFormat.register_format(WorkingTreeFormat6())
2993
3053
WorkingTreeFormat.register_format(WorkingTreeFormat5())
 
3054
WorkingTreeFormat.register_format(WorkingTreeFormat4())
2994
3055
WorkingTreeFormat.register_format(WorkingTreeFormat3())
2995
3056
WorkingTreeFormat.set_default_format(__default_format)
2996
3057
# formats which have no format string are not discoverable