~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

  • Committer: Jonathan Lange
  • Date: 2007-04-23 01:30:35 UTC
  • mto: This revision was merged to the branch mainline in revision 2446.
  • Revision ID: jml@canonical.com-20070423013035-zuqiamuro8h1hba9
Can also set the bug config options in branch.conf

Show diffs side-by-side

added added

removed removed

Lines of Context:
367
367
 
368
368
    def abspath(self, filename):
369
369
        return pathjoin(self.basedir, filename)
370
 
 
 
370
    
371
371
    def basis_tree(self):
372
372
        """Return RevisionTree for the current last revision.
373
373
        
813
813
                to_revision = osutils.safe_revision_id(to_revision)
814
814
            merger.other_rev_id = to_revision
815
815
            if merger.other_rev_id is None:
816
 
                raise errors.NoCommits(branch)
 
816
                raise error.NoCommits(branch)
817
817
            self.branch.fetch(branch, last_revision=merger.other_rev_id)
818
818
            merger.other_basis = merger.other_rev_id
819
819
            merger.other_tree = self.branch.repository.revision_tree(
932
932
            transport = self.branch.bzrdir.root_transport
933
933
            for name in segments:
934
934
                transport = transport.clone(name)
935
 
                transport.ensure_base()
 
935
                try:
 
936
                    transport.mkdir('.')
 
937
                except errors.FileExists:
 
938
                    pass
936
939
            return transport
937
940
            
938
941
        sub_path = self.id2path(file_id)
939
942
        branch_transport = mkdirs(sub_path)
940
943
        if format is None:
941
944
            format = bzrdir.format_registry.make_bzrdir('dirstate-with-subtree')
942
 
        branch_transport.ensure_base()
 
945
        try:
 
946
            branch_transport.mkdir('.')
 
947
        except errors.FileExists:
 
948
            pass
943
949
        branch_bzrdir = format.initialize_on_transport(branch_transport)
944
950
        try:
945
951
            repo = branch_bzrdir.find_repository()
1761
1767
        return result
1762
1768
 
1763
1769
    @needs_tree_write_lock
1764
 
    def remove(self, files, verbose=False, to_file=None, keep_files=True,
1765
 
        force=False):
1766
 
        """Remove nominated files from the working inventor.
1767
 
 
1768
 
        :files: File paths relative to the basedir.
1769
 
        :keep_files: If true, the files will also be kept.
1770
 
        :force: Delete files and directories, even if they are changed and
1771
 
            even if the directories are not empty.
 
1770
    def remove(self, files, verbose=False, to_file=None):
 
1771
        """Remove nominated files from the working inventory..
 
1772
 
 
1773
        This does not remove their text.  This does not run on XXX on what? RBC
 
1774
 
 
1775
        TODO: Refuse to remove modified files unless --force is given?
 
1776
 
 
1777
        TODO: Do something useful with directories.
 
1778
 
 
1779
        TODO: Should this remove the text or not?  Tough call; not
 
1780
        removing may be useful and the user can just use use rm, and
 
1781
        is the opposite of add.  Removing it is consistent with most
 
1782
        other tools.  Maybe an option.
1772
1783
        """
1773
1784
        ## TODO: Normalize names
1774
 
 
 
1785
        ## TODO: Remove nested loops; better scalability
1775
1786
        if isinstance(files, basestring):
1776
1787
            files = [files]
1777
1788
 
1778
 
        inv_delta = []
1779
 
 
1780
 
        new_files=set()
1781
 
        unknown_files_in_directory=set()
1782
 
 
1783
 
        def recurse_directory_to_add_files(directory):
1784
 
            # recurse directory and add all files
1785
 
            # so we can check if they have changed.
1786
 
            for parent_info, file_infos in\
1787
 
                osutils.walkdirs(self.abspath(directory),
1788
 
                    directory):
1789
 
                for relpath, basename, kind, lstat, abspath in file_infos:
1790
 
                    if kind == 'file':
1791
 
                        if self.path2id(relpath): #is it versioned?
1792
 
                            new_files.add(relpath)
1793
 
                        else:
1794
 
                            unknown_files_in_directory.add(
1795
 
                                (relpath, None, kind))
1796
 
 
1797
 
        for filename in files:
1798
 
            # Get file name into canonical form.
1799
 
            abspath = self.abspath(filename)
1800
 
            filename = self.relpath(abspath)
1801
 
            if len(filename) > 0:
1802
 
                new_files.add(filename)
1803
 
                if osutils.isdir(abspath):
1804
 
                    recurse_directory_to_add_files(filename)
1805
 
        files = [f for f in new_files]
1806
 
 
1807
 
        # Sort needed to first handle directory content before the directory
1808
 
        files.sort(reverse=True)
1809
 
        if not keep_files and not force:
1810
 
            tree_delta = self.changes_from(self.basis_tree(),
1811
 
                specific_files=files)
1812
 
            for unknown_file in unknown_files_in_directory:
1813
 
                tree_delta.unversioned.extend((unknown_file,))
1814
 
            if bool(tree_delta.modified
1815
 
                    or tree_delta.added
1816
 
                    or tree_delta.renamed
1817
 
                    or tree_delta.kind_changed
1818
 
                    or tree_delta.unversioned):
1819
 
                raise errors.BzrRemoveChangedFilesError(tree_delta)
 
1789
        inv = self.inventory
1820
1790
 
1821
1791
        # do this before any modifications
1822
1792
        for f in files:
1823
 
            fid = self.path2id(f)
1824
 
            message=None
 
1793
            fid = inv.path2id(f)
1825
1794
            if not fid:
1826
 
                message="%s is not versioned." % (f,)
 
1795
                note("%s is not versioned."%f)
1827
1796
            else:
1828
1797
                if verbose:
1829
 
                    # having removed it, it must be either ignored or unknown
 
1798
                    # having remove it, it must be either ignored or unknown
1830
1799
                    if self.is_ignored(f):
1831
1800
                        new_status = 'I'
1832
1801
                    else:
1833
1802
                        new_status = '?'
1834
 
                    textui.show_status(new_status, self.kind(fid), f,
 
1803
                    textui.show_status(new_status, inv[fid].kind, f,
1835
1804
                                       to_file=to_file)
1836
 
                # unversion file
1837
 
                inv_delta.append((f, None, fid, None))
1838
 
                message="removed %s" % (f,)
1839
 
 
1840
 
            if not keep_files:
1841
 
                abs_path = self.abspath(f)
1842
 
                if osutils.lexists(abs_path):
1843
 
                    if (osutils.isdir(abs_path) and
1844
 
                        len(os.listdir(abs_path)) > 0):
1845
 
                        message="%s is not empty directory "\
1846
 
                            "and won't be deleted." % (f,)
1847
 
                    else:
1848
 
                        osutils.delete_any(abs_path)
1849
 
                        message="deleted %s" % (f,)
1850
 
                elif message is not None:
1851
 
                    # only care if we haven't done anything yet.
1852
 
                    message="%s does not exist." % (f,)
1853
 
 
1854
 
            # print only one message (if any) per file.
1855
 
            if message is not None:
1856
 
                note(message)
1857
 
        self.apply_inventory_delta(inv_delta)
 
1805
                del inv[fid]
 
1806
 
 
1807
        self._write_inventory(inv)
1858
1808
 
1859
1809
    @needs_tree_write_lock
1860
1810
    def revert(self, filenames, old_tree=None, backups=True, 
2085
2035
            #       inventory and calls tree._write_inventory(). Ultimately we
2086
2036
            #       should be able to remove this extra flush.
2087
2037
            self.flush()
2088
 
            graph = self.branch.repository.get_graph()
2089
 
            base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
2090
 
                                                old_tip)
 
2038
            from bzrlib.revision import common_ancestor
 
2039
            try:
 
2040
                base_rev_id = common_ancestor(self.branch.last_revision(),
 
2041
                                              old_tip,
 
2042
                                              self.branch.repository)
 
2043
            except errors.NoCommonAncestor:
 
2044
                base_rev_id = None
2091
2045
            base_tree = self.branch.repository.revision_tree(base_rev_id)
2092
2046
            other_tree = self.branch.repository.revision_tree(old_tip)
2093
2047
            result += merge.merge_inner(
2152
2106
    def walkdirs(self, prefix=""):
2153
2107
        """Walk the directories of this tree.
2154
2108
 
2155
 
        returns a generator which yields items in the form:
2156
 
                ((curren_directory_path, fileid),
2157
 
                 [(file1_path, file1_name, file1_kind, (lstat), file1_id,
2158
 
                   file1_kind), ... ])
2159
 
 
2160
2109
        This API returns a generator, which is only valid during the current
2161
2110
        tree transaction - within a single lock_read or lock_write duration.
2162
2111
 
2163
 
        If the tree is not locked, it may cause an error to be raised,
2164
 
        depending on the tree implementation.
 
2112
        If the tree is not locked, it may cause an error to be raised, depending
 
2113
        on the tree implementation.
2165
2114
        """
2166
2115
        disk_top = self.abspath(prefix)
2167
2116
        if disk_top.endswith('/'):
2259
2208
                    disk_finished = True
2260
2209
 
2261
2210
    def _walkdirs(self, prefix=""):
2262
 
        """Walk the directories of this tree.
2263
 
 
2264
 
           :prefix: is used as the directrory to start with.
2265
 
           returns a generator which yields items in the form:
2266
 
                ((curren_directory_path, fileid),
2267
 
                 [(file1_path, file1_name, file1_kind, None, file1_id,
2268
 
                   file1_kind), ... ])
2269
 
        """
2270
2211
        _directory = 'directory'
2271
2212
        # get the root in the inventory
2272
2213
        inv = self.inventory