1769
1769
@needs_tree_write_lock
1770
def remove(self, files, verbose=False, to_file=None):
1771
"""Remove nominated files from the working inventory..
1773
This does not remove their text. This does not run on XXX on what? RBC
1775
TODO: Refuse to remove modified files unless --force is given?
1777
TODO: Do something useful with directories.
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,
1772
"""Remove nominated files from the working inventor.
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.
1784
1779
## TODO: Normalize names
1785
## TODO: Remove nested loops; better scalability
1786
1781
if isinstance(files, basestring):
1787
1782
files = [files]
1789
1784
inv = self.inventory
1787
unknown_files_in_directory=set()
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)
1799
unknown_files_in_directory.add(
1800
(relpath, None, file_info[2]))
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]
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
1820
or tree_delta.renamed
1821
or tree_delta.kind_changed
1822
or tree_delta.unversioned):
1823
raise errors.BzrRemoveChangedFilesError(tree_delta)
1791
1825
# do this before any modifications
1792
1826
for f in files:
1793
1827
fid = inv.path2id(f)
1795
note("%s is not versioned."%f)
1830
message="%s is not versioned." % (f,)
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'
1802
1837
new_status = '?'
1803
1838
textui.show_status(new_status, inv[fid].kind, f,
1804
1839
to_file=to_file)
1842
message="removed %s" % (f,)
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,)
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,)
1858
# print only one message (if any) per file.
1859
if message is not None:
1807
1861
self._write_inventory(inv)
1809
1863
@needs_tree_write_lock
2106
2160
def walkdirs(self, prefix=""):
2107
2161
"""Walk the directories of this tree.
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,
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.
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.
2115
2174
disk_top = self.abspath(prefix)
2116
2175
if disk_top.endswith('/'):