~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

bzr rm removes the working file

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
        
1767
1767
        return result
1768
1768
 
1769
1769
    @needs_tree_write_lock
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.
 
1770
    def remove(self, files, verbose=False, to_file=None, keep_files=True,
 
1771
        force=False):
 
1772
        """Remove nominated files from the working inventor.
 
1773
 
 
1774
        :files: File paths relative to the basedir.
 
1775
        :keep_files: If true, the files will also be kept.
 
1776
        :force: Delete files and directories, even if they are changed and
 
1777
            even if the directories are not empty.
1783
1778
        """
1784
1779
        ## TODO: Normalize names
1785
 
        ## TODO: Remove nested loops; better scalability
 
1780
 
1786
1781
        if isinstance(files, basestring):
1787
1782
            files = [files]
1788
1783
 
1789
1784
        inv = self.inventory
1790
1785
 
 
1786
        new_files=set()
 
1787
        unknown_files_in_directory=set()
 
1788
 
 
1789
        def recurse_directory_to_add_files(directory):
 
1790
            # recurse directory and add all files
 
1791
            # so we can check if they have changed.
 
1792
            for contained_dir_info in self.walkdirs(directory):
 
1793
                for file_info in contained_dir_info[1]:
 
1794
                    if file_info[2] == 'file':
 
1795
                        relpath = self.relpath(file_info[0])
 
1796
                        if file_info[4]: #is it versioned?
 
1797
                            new_files.add(relpath)
 
1798
                        else:
 
1799
                            unknown_files_in_directory.add(
 
1800
                                (relpath, None, file_info[2]))
 
1801
 
 
1802
        for filename in files:
 
1803
            # Get file name into canonical form.
 
1804
            filename = self.relpath(self.abspath(filename))
 
1805
            if len(filename) > 0:
 
1806
                new_files.add(filename)
 
1807
                if osutils.isdir(filename) and len(os.listdir(filename)) > 0:
 
1808
                    recurse_directory_to_add_files(filename)
 
1809
        files = [f for f in new_files]
 
1810
 
 
1811
        # Sort needed to first handle directory content before the directory
 
1812
        files.sort(reverse=True)
 
1813
        if not keep_files and not force:
 
1814
            tree_delta = self.changes_from(self.basis_tree(),
 
1815
                specific_files=files)
 
1816
            for unknown_file in unknown_files_in_directory:
 
1817
                tree_delta.unversioned.extend((unknown_file,))
 
1818
            if bool(tree_delta.modified
 
1819
                    or tree_delta.added
 
1820
                    or tree_delta.renamed
 
1821
                    or tree_delta.kind_changed
 
1822
                    or tree_delta.unversioned):
 
1823
                raise errors.BzrRemoveChangedFilesError(tree_delta)
 
1824
 
1791
1825
        # do this before any modifications
1792
1826
        for f in files:
1793
1827
            fid = inv.path2id(f)
 
1828
            message=None
1794
1829
            if not fid:
1795
 
                note("%s is not versioned."%f)
 
1830
                message="%s is not versioned." % (f,)
1796
1831
            else:
1797
1832
                if verbose:
1798
 
                    # having remove it, it must be either ignored or unknown
 
1833
                    # having removed it, it must be either ignored or unknown
1799
1834
                    if self.is_ignored(f):
1800
1835
                        new_status = 'I'
1801
1836
                    else:
1802
1837
                        new_status = '?'
1803
1838
                    textui.show_status(new_status, inv[fid].kind, f,
1804
1839
                                       to_file=to_file)
 
1840
                # unversion file
1805
1841
                del inv[fid]
1806
 
 
 
1842
                message="removed %s" % (f,)
 
1843
 
 
1844
            if not keep_files:
 
1845
                abs_path = self.abspath(f)
 
1846
                if osutils.lexists(abs_path):
 
1847
                    if (osutils.isdir(abs_path) and
 
1848
                        len(os.listdir(abs_path)) > 0):
 
1849
                        message="%s is not empty directory "\
 
1850
                            "and won't be deleted." % (f,)
 
1851
                    else:
 
1852
                        osutils.delete_any(abs_path)
 
1853
                        message="deleted %s" % (f,)
 
1854
                elif message is not None:
 
1855
                    # only care if we haven't done anything yet.
 
1856
                    message="%s does not exist." % (f,)
 
1857
 
 
1858
            # print only one message (if any) per file.
 
1859
            if message is not None:
 
1860
                note(message)
1807
1861
        self._write_inventory(inv)
1808
1862
 
1809
1863
    @needs_tree_write_lock
2106
2160
    def walkdirs(self, prefix=""):
2107
2161
        """Walk the directories of this tree.
2108
2162
 
 
2163
        returns a generator which yields items in the form:
 
2164
                ((curren_directory_path, fileid),
 
2165
                 [(file1_path, file1_name, file1_kind, (lstat), file1_id,
 
2166
                   file1_kind), ... ])
 
2167
 
2109
2168
        This API returns a generator, which is only valid during the current
2110
2169
        tree transaction - within a single lock_read or lock_write duration.
2111
2170
 
2112
 
        If the tree is not locked, it may cause an error to be raised, depending
2113
 
        on the tree implementation.
 
2171
        If the tree is not locked, it may cause an error to be raised,
 
2172
        depending on the tree implementation.
2114
2173
        """
2115
2174
        disk_top = self.abspath(prefix)
2116
2175
        if disk_top.endswith('/'):
2208
2267
                    disk_finished = True
2209
2268
 
2210
2269
    def _walkdirs(self, prefix=""):
 
2270
        """Walk the directories of this tree.
 
2271
 
 
2272
           :prefix: is used as the directrory to start with.
 
2273
           returns a generator which yields items in the form:
 
2274
                ((curren_directory_path, fileid),
 
2275
                 [(file1_path, file1_name, file1_kind, None, file1_id,
 
2276
                   file1_kind), ... ])
 
2277
        """
2211
2278
        _directory = 'directory'
2212
2279
        # get the root in the inventory
2213
2280
        inv = self.inventory