~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

  • Committer: John Arbash Meinel
  • Date: 2007-04-28 15:04:17 UTC
  • mfrom: (2466 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2566.
  • Revision ID: john@arbash-meinel.com-20070428150417-trp3pi0pzd411pu4
[merge] bzr.dev 2466

Show diffs side-by-side

added added

removed removed

Lines of Context:
38
38
 
39
39
from cStringIO import StringIO
40
40
import os
 
41
import sys
41
42
 
42
43
from bzrlib.lazy_import import lazy_import
43
44
lazy_import(globals(), """
119
120
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
120
121
CONFLICT_HEADER_1 = "BZR conflict list format 1"
121
122
 
 
123
ERROR_PATH_NOT_FOUND = 3    # WindowsError errno code, equivalent to ENOENT
 
124
 
122
125
 
123
126
@deprecated_function(zero_thirteen)
124
127
def gen_file_id(name):
364
367
 
365
368
    def abspath(self, filename):
366
369
        return pathjoin(self.basedir, filename)
367
 
    
 
370
 
368
371
    def basis_tree(self):
369
372
        """Return RevisionTree for the current last revision.
370
373
        
1601
1604
            mode = stat_value.st_mode
1602
1605
            kind = osutils.file_kind_from_stat_mode(mode)
1603
1606
            if not supports_executable():
1604
 
                executable = entry.executable
 
1607
                executable = entry is not None and entry.executable
1605
1608
            else:
1606
1609
                executable = bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
1607
1610
        return kind, executable, stat_value
1764
1767
        return result
1765
1768
 
1766
1769
    @needs_tree_write_lock
1767
 
    def remove(self, files, verbose=False, to_file=None):
1768
 
        """Remove nominated files from the working inventory..
1769
 
 
1770
 
        This does not remove their text.  This does not run on XXX on what? RBC
1771
 
 
1772
 
        TODO: Refuse to remove modified files unless --force is given?
1773
 
 
1774
 
        TODO: Do something useful with directories.
1775
 
 
1776
 
        TODO: Should this remove the text or not?  Tough call; not
1777
 
        removing may be useful and the user can just use use rm, and
1778
 
        is the opposite of add.  Removing it is consistent with most
1779
 
        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.
1780
1778
        """
1781
1779
        ## TODO: Normalize names
1782
 
        ## TODO: Remove nested loops; better scalability
 
1780
 
1783
1781
        if isinstance(files, basestring):
1784
1782
            files = [files]
1785
1783
 
1786
1784
        inv = self.inventory
1787
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
 
1788
1825
        # do this before any modifications
1789
1826
        for f in files:
1790
1827
            fid = inv.path2id(f)
 
1828
            message=None
1791
1829
            if not fid:
1792
 
                note("%s is not versioned."%f)
 
1830
                message="%s is not versioned." % (f,)
1793
1831
            else:
1794
1832
                if verbose:
1795
 
                    # having remove it, it must be either ignored or unknown
 
1833
                    # having removed it, it must be either ignored or unknown
1796
1834
                    if self.is_ignored(f):
1797
1835
                        new_status = 'I'
1798
1836
                    else:
1799
1837
                        new_status = '?'
1800
1838
                    textui.show_status(new_status, inv[fid].kind, f,
1801
1839
                                       to_file=to_file)
 
1840
                # unversion file
1802
1841
                del inv[fid]
1803
 
 
 
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)
1804
1861
        self._write_inventory(inv)
1805
1862
 
1806
1863
    @needs_tree_write_lock
2103
2160
    def walkdirs(self, prefix=""):
2104
2161
        """Walk the directories of this tree.
2105
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
 
2106
2168
        This API returns a generator, which is only valid during the current
2107
2169
        tree transaction - within a single lock_read or lock_write duration.
2108
2170
 
2109
 
        If the tree is not locked, it may cause an error to be raised, depending
2110
 
        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.
2111
2173
        """
2112
2174
        disk_top = self.abspath(prefix)
2113
2175
        if disk_top.endswith('/'):
2119
2181
            current_disk = disk_iterator.next()
2120
2182
            disk_finished = False
2121
2183
        except OSError, e:
2122
 
            if e.errno != errno.ENOENT:
 
2184
            if not (e.errno == errno.ENOENT or
 
2185
                (sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
2123
2186
                raise
2124
2187
            current_disk = None
2125
2188
            disk_finished = True
2204
2267
                    disk_finished = True
2205
2268
 
2206
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
        """
2207
2278
        _directory = 'directory'
2208
2279
        # get the root in the inventory
2209
2280
        inv = self.inventory