270
270
# the Format factory and creation methods that are
271
271
# permitted to do this.
272
272
self._set_inventory(_inventory, dirty=False)
273
self._detect_case_handling()
275
def _detect_case_handling(self):
276
wt_trans = self.bzrdir.get_workingtree_transport(None)
278
wt_trans.stat("FoRMaT")
279
except errors.NoSuchFile:
280
self.case_sensitive = True
282
self.case_sensitive = False
284
self._setup_directory_is_tree_reference()
286
274
branch = property(
287
275
fget=lambda self: self._branch,
360
348
return WorkingTree.open(path, _unsupported=True)
363
def find_trees(location):
364
def list_current(transport):
365
return [d for d in transport.list_dir('') if d != '.bzr']
366
def evaluate(bzrdir):
368
tree = bzrdir.open_workingtree()
369
except errors.NoWorkingTree:
373
transport = get_transport(location)
374
iterator = bzrdir.BzrDir.find_bzrdirs(transport, evaluate=evaluate,
375
list_current=list_current)
376
return [t for t in iterator if t is not None]
378
350
# should be deprecated - this is slow and in any case treating them as a
379
351
# container is (we now know) bad style -- mbp 20070302
380
352
## @deprecated_method(zero_fifteen)
483
448
def has_filename(self, filename):
484
449
return osutils.lexists(self.abspath(filename))
486
def get_file(self, file_id, path=None):
488
path = self.id2path(file_id)
489
return self.get_file_byname(path)
451
def get_file(self, file_id):
452
file_id = osutils.safe_file_id(file_id)
453
return self.get_file_byname(self.id2path(file_id))
491
455
def get_file_text(self, file_id):
456
file_id = osutils.safe_file_id(file_id)
492
457
return self.get_file(file_id).read()
494
459
def get_file_byname(self, filename):
505
470
incorrectly attributed to CURRENT_REVISION (but after committing, the
506
471
attribution will be correct).
473
file_id = osutils.safe_file_id(file_id)
508
474
basis = self.basis_tree()
509
475
basis.lock_read()
511
changes = self.iter_changes(basis, True, [self.id2path(file_id)],
477
changes = self._iter_changes(basis, True, [self.id2path(file_id)],
512
478
require_versioned=True).next()
513
479
changed_content, kind = changes[2], changes[6]
514
480
if not changed_content:
618
588
__contains__ = has_id
620
590
def get_file_size(self, file_id):
591
file_id = osutils.safe_file_id(file_id)
621
592
return os.path.getsize(self.id2abspath(file_id))
624
595
def get_file_sha1(self, file_id, path=None, stat_value=None):
596
file_id = osutils.safe_file_id(file_id)
626
598
path = self._inventory.id2path(file_id)
627
599
return self._hashcache.get_sha1(path, stat_value)
629
601
def get_file_mtime(self, file_id, path=None):
602
file_id = osutils.safe_file_id(file_id)
631
604
path = self.inventory.id2path(file_id)
632
605
return os.lstat(self.abspath(path)).st_mtime
634
def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
635
file_id = self.path2id(path)
636
return self._inventory[file_id].executable
638
def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
639
mode = stat_result.st_mode
640
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
642
607
if not supports_executable():
643
608
def is_executable(self, file_id, path=None):
609
file_id = osutils.safe_file_id(file_id)
644
610
return self._inventory[file_id].executable
646
_is_executable_from_path_and_stat = \
647
_is_executable_from_path_and_stat_from_basis
649
612
def is_executable(self, file_id, path=None):
614
file_id = osutils.safe_file_id(file_id)
651
615
path = self.id2path(file_id)
652
616
mode = os.lstat(self.abspath(path)).st_mode
653
617
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
655
_is_executable_from_path_and_stat = \
656
_is_executable_from_path_and_stat_from_stat
658
619
@needs_tree_write_lock
659
620
def _add(self, files, ids, kinds):
660
621
"""See MutableTree._add."""
736
698
self.set_parent_ids(parents, allow_leftmost_as_ghost=True)
738
def path_content_summary(self, path, _lstat=os.lstat,
739
_mapper=osutils.file_kind_from_stat_mode):
740
"""See Tree.path_content_summary."""
741
abspath = self.abspath(path)
743
stat_result = _lstat(abspath)
745
if getattr(e, 'errno', None) == errno.ENOENT:
747
return ('missing', None, None, None)
748
# propagate other errors
750
kind = _mapper(stat_result.st_mode)
752
size = stat_result.st_size
753
# try for a stat cache lookup
754
executable = self._is_executable_from_path_and_stat(path, stat_result)
755
return (kind, size, executable, self._sha_from_stat(
757
elif kind == 'directory':
758
# perhaps it looks like a plain directory, but it's really a
760
if self._directory_is_tree_reference(path):
761
kind = 'tree-reference'
762
return kind, None, None, None
763
elif kind == 'symlink':
764
return ('symlink', None, None, os.readlink(abspath))
766
return (kind, None, None, None)
768
700
@deprecated_method(zero_eleven)
770
702
def pending_merges(self):
861
794
yield Stanza(file_id=file_id.decode('utf8'), hash=hash)
862
795
self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
864
def _sha_from_stat(self, path, stat_result):
865
"""Get a sha digest from the tree's stat cache.
867
The default implementation assumes no stat cache is present.
869
:param path: The path.
870
:param stat_result: The stat result being looked up.
874
797
def _put_rio(self, filename, stanzas, header):
875
798
self._must_be_locked()
876
799
my_file = rio_file(stanzas, header)
1012
938
other_tree.unlock()
1013
939
other_tree.bzrdir.retire_bzrdir()
1015
def _setup_directory_is_tree_reference(self):
1016
if self._branch.repository._format.supports_tree_reference:
1017
self._directory_is_tree_reference = \
1018
self._directory_may_be_tree_reference
1020
self._directory_is_tree_reference = \
1021
self._directory_is_never_tree_reference
1023
def _directory_is_never_tree_reference(self, relpath):
1026
def _directory_may_be_tree_reference(self, relpath):
1027
# as a special case, if a directory contains control files then
1028
# it's a tree reference, except that the root of the tree is not
1029
return relpath and osutils.isdir(self.abspath(relpath) + u"/.bzr")
1030
# TODO: We could ask all the control formats whether they
1031
# recognize this directory, but at the moment there's no cheap api
1032
# to do that. Since we probably can only nest bzr checkouts and
1033
# they always use this name it's ok for now. -- mbp 20060306
1035
# FIXME: There is an unhandled case here of a subdirectory
1036
# containing .bzr but not a branch; that will probably blow up
1037
# when you try to commit it. It might happen if there is a
1038
# checkout in a subdirectory. This can be avoided by not adding
1041
941
@needs_tree_write_lock
1042
942
def extract(self, file_id, format=None):
1043
943
"""Extract a subtree from this tree.
1056
956
sub_path = self.id2path(file_id)
1057
957
branch_transport = mkdirs(sub_path)
1058
958
if format is None:
1059
format = self.bzrdir.cloning_metadir()
959
format = bzrdir.format_registry.make_bzrdir('dirstate-with-subtree')
1060
960
branch_transport.ensure_base()
1061
961
branch_bzrdir = format.initialize_on_transport(branch_transport)
1063
963
repo = branch_bzrdir.find_repository()
1064
964
except errors.NoRepositoryPresent:
1065
965
repo = branch_bzrdir.create_repository()
1066
if not repo.supports_rich_root():
1067
raise errors.RootNotRich()
966
assert repo.supports_rich_root()
968
if not repo.supports_rich_root():
969
raise errors.RootNotRich()
1068
970
new_branch = branch_bzrdir.create_branch()
1069
971
new_branch.pull(self.branch)
1070
972
for parent_id in self.get_parent_ids():
1566
1465
pp.next_phase()
1567
1466
old_revision_info = self.branch.last_revision_info()
1568
1467
basis_tree = self.basis_tree()
1569
count = self.branch.pull(source, overwrite, stop_revision,
1570
possible_transports=possible_transports)
1468
count = self.branch.pull(source, overwrite, stop_revision)
1571
1469
new_revision_info = self.branch.last_revision_info()
1572
1470
if new_revision_info != old_revision_info:
1573
1471
pp.next_phase()
1828
1724
def _create_basis_xml_from_inventory(self, revision_id, inventory):
1829
1725
"""Create the text that will be saved in basis-inventory"""
1830
inventory.revision_id = revision_id
1726
# TODO: jam 20070209 This should be redundant, as the revision_id
1727
# as all callers should have already converted the revision_id to
1729
inventory.revision_id = osutils.safe_revision_id(revision_id)
1831
1730
return xml7.serializer_v7.write_inventory_to_string(inventory)
1833
1732
def _cache_basis_inventory(self, new_revision):
1889
1788
:force: Delete files and directories, even if they are changed and
1890
1789
even if the directories are not empty.
1791
## TODO: Normalize names
1892
1793
if isinstance(files, basestring):
1893
1794
files = [files]
1897
1798
new_files=set()
1898
unknown_nested_files=set()
1799
unknown_files_in_directory=set()
1900
1801
def recurse_directory_to_add_files(directory):
1901
# Recurse directory and add all files
1802
# recurse directory and add all files
1902
1803
# so we can check if they have changed.
1903
1804
for parent_info, file_infos in\
1904
1805
osutils.walkdirs(self.abspath(directory),
1906
1807
for relpath, basename, kind, lstat, abspath in file_infos:
1907
# Is it versioned or ignored?
1908
if self.path2id(relpath) or self.is_ignored(relpath):
1909
# Add nested content for deletion.
1910
new_files.add(relpath)
1912
# Files which are not versioned and not ignored
1913
# should be treated as unknown.
1914
unknown_nested_files.add((relpath, None, kind))
1809
if self.path2id(relpath): #is it versioned?
1810
new_files.add(relpath)
1812
unknown_files_in_directory.add(
1813
(relpath, None, kind))
1916
1815
for filename in files:
1917
1816
# Get file name into canonical form.
1921
1820
new_files.add(filename)
1922
1821
if osutils.isdir(abspath):
1923
1822
recurse_directory_to_add_files(filename)
1925
files = list(new_files)
1823
files = [f for f in new_files]
1927
1825
if len(files) == 0:
1928
1826
return # nothing to do
1930
1828
# Sort needed to first handle directory content before the directory
1931
1829
files.sort(reverse=True)
1933
# Bail out if we are going to delete files we shouldn't
1934
1830
if not keep_files and not force:
1935
has_changed_files = len(unknown_nested_files) > 0
1831
has_changed_files = len(unknown_files_in_directory) > 0
1936
1832
if not has_changed_files:
1937
1833
for (file_id, path, content_change, versioned, parent_id, name,
1938
kind, executable) in self.iter_changes(self.basis_tree(),
1834
kind, executable) in self._iter_changes(self.basis_tree(),
1939
1835
include_unchanged=True, require_versioned=False,
1940
1836
want_unversioned=True, specific_files=files):
1941
if versioned == (False, False):
1942
# The record is unknown ...
1943
if not self.is_ignored(path[1]):
1944
# ... but not ignored
1945
has_changed_files = True
1947
elif content_change and (kind[1] != None):
1948
# Versioned and changed, but not deleted
1837
# check if it's unknown OR changed but not deleted:
1838
if (versioned == (False, False)
1839
or (content_change and kind[1] != None)):
1949
1840
has_changed_files = True
1952
1843
if has_changed_files:
1953
# Make delta show ALL applicable changes in error message.
1844
# make delta to show ALL applicable changes in error message.
1954
1845
tree_delta = self.changes_from(self.basis_tree(),
1955
require_versioned=False, want_unversioned=True,
1956
1846
specific_files=files)
1957
for unknown_file in unknown_nested_files:
1958
if unknown_file not in tree_delta.unversioned:
1959
tree_delta.unversioned.extend((unknown_file,))
1847
for unknown_file in unknown_files_in_directory:
1848
tree_delta.unversioned.extend((unknown_file,))
1960
1849
raise errors.BzrRemoveChangedFilesError(tree_delta)
1962
# Build inv_delta and delete files where applicaple,
1963
# do this before any modifications to inventory.
1851
# do this before any modifications
1964
1852
for f in files:
1965
1853
fid = self.path2id(f)
1968
message = "%s is not versioned." % (f,)
1856
message="%s is not versioned." % (f,)
1971
1859
# having removed it, it must be either ignored or unknown
1975
1863
new_status = '?'
1976
1864
textui.show_status(new_status, self.kind(fid), f,
1977
1865
to_file=to_file)
1979
1867
inv_delta.append((f, None, fid, None))
1980
message = "removed %s" % (f,)
1868
message="removed %s" % (f,)
1982
1870
if not keep_files:
1983
1871
abs_path = self.abspath(f)
1984
1872
if osutils.lexists(abs_path):
1985
1873
if (osutils.isdir(abs_path) and
1986
1874
len(os.listdir(abs_path)) > 0):
1988
osutils.rmtree(abs_path)
1990
message = "%s is not an empty directory "\
1991
"and won't be deleted." % (f,)
1875
message="%s is not empty directory "\
1876
"and won't be deleted." % (f,)
1993
1878
osutils.delete_any(abs_path)
1994
message = "deleted %s" % (f,)
1879
message="deleted %s" % (f,)
1995
1880
elif message is not None:
1996
# Only care if we haven't done anything yet.
1997
message = "%s does not exist." % (f,)
1881
# only care if we haven't done anything yet.
1882
message="%s does not exist." % (f,)
1999
# Print only one message (if any) per file.
1884
# print only one message (if any) per file.
2000
1885
if message is not None:
2002
1887
self.apply_inventory_delta(inv_delta)
2004
1889
@needs_tree_write_lock
2005
def revert(self, filenames=None, old_tree=None, backups=True,
1890
def revert(self, filenames, old_tree=None, backups=True,
2006
1891
pb=DummyProgress(), report_changes=False):
2007
1892
from bzrlib.conflicts import resolve
2010
symbol_versioning.warn('Using [] to revert all files is deprecated'
2011
' as of bzr 0.91. Please use None (the default) instead.',
2012
DeprecationWarning, stacklevel=2)
2013
1893
if old_tree is None:
2014
basis_tree = self.basis_tree()
2015
basis_tree.lock_read()
2016
old_tree = basis_tree
1894
old_tree = self.basis_tree()
1895
conflicts = transform.revert(self, old_tree, filenames, backups, pb,
1897
if not len(filenames):
1898
self.set_parent_ids(self.get_parent_ids()[:1])
2020
conflicts = transform.revert(self, old_tree, filenames, backups, pb,
2022
if filenames is None and len(self.get_parent_ids()) > 1:
2024
last_revision = self.last_revision()
2025
if last_revision != NULL_REVISION:
2026
if basis_tree is None:
2027
basis_tree = self.basis_tree()
2028
basis_tree.lock_read()
2029
parent_trees.append((last_revision, basis_tree))
2030
self.set_parent_trees(parent_trees)
2033
resolve(self, filenames, ignore_misses=True, recursive=True)
2035
if basis_tree is not None:
1901
resolve(self, filenames, ignore_misses=True)
2037
1902
return conflicts
2039
1904
def revision_tree(self, revision_id):
2353
2218
current_inv = None
2354
2219
inv_finished = True
2355
2220
while not inv_finished or not disk_finished:
2357
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
2358
cur_disk_dir_content) = current_disk
2360
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
2361
cur_disk_dir_content) = ((None, None), None)
2362
2221
if not disk_finished:
2363
2222
# strip out .bzr dirs
2364
if (cur_disk_dir_path_from_top[top_strip_len:] == '' and
2365
len(cur_disk_dir_content) > 0):
2366
# osutils.walkdirs can be made nicer -
2223
if current_disk[0][1][top_strip_len:] == '':
2224
# osutils.walkdirs can be made nicer -
2367
2225
# yield the path-from-prefix rather than the pathjoined
2369
bzrdir_loc = bisect_left(cur_disk_dir_content,
2371
if cur_disk_dir_content[bzrdir_loc][0] == '.bzr':
2227
bzrdir_loc = bisect_left(current_disk[1], ('.bzr', '.bzr'))
2228
if current_disk[1][bzrdir_loc][0] == '.bzr':
2372
2229
# we dont yield the contents of, or, .bzr itself.
2373
del cur_disk_dir_content[bzrdir_loc]
2230
del current_disk[1][bzrdir_loc]
2374
2231
if inv_finished:
2375
2232
# everything is unknown
2378
2235
# everything is missing
2381
direction = cmp(current_inv[0][0], cur_disk_dir_relpath)
2238
direction = cmp(current_inv[0][0], current_disk[0][0])
2382
2239
if direction > 0:
2383
2240
# disk is before inventory - unknown
2384
2241
dirblock = [(relpath, basename, kind, stat, None, None) for
2385
relpath, basename, kind, stat, top_path in
2386
cur_disk_dir_content]
2387
yield (cur_disk_dir_relpath, None), dirblock
2242
relpath, basename, kind, stat, top_path in current_disk[1]]
2243
yield (current_disk[0][0], None), dirblock
2389
2245
current_disk = disk_iterator.next()
2390
2246
except StopIteration:
2392
2248
elif direction < 0:
2393
2249
# inventory is before disk - missing.
2394
2250
dirblock = [(relpath, basename, 'unknown', None, fileid, kind)
2395
for relpath, basename, dkind, stat, fileid, kind in
2251
for relpath, basename, dkind, stat, fileid, kind in
2396
2252
current_inv[1]]
2397
2253
yield (current_inv[0][0], current_inv[0][1]), dirblock
2404
2260
# merge the inventory and disk data together
2406
2262
for relpath, subiterator in itertools.groupby(sorted(
2407
current_inv[1] + cur_disk_dir_content,
2408
key=operator.itemgetter(0)), operator.itemgetter(1)):
2263
current_inv[1] + current_disk[1], key=operator.itemgetter(0)), operator.itemgetter(1)):
2409
2264
path_elements = list(subiterator)
2410
2265
if len(path_elements) == 2:
2411
2266
inv_row, disk_row = path_elements
2582
2434
def _last_revision(self):
2583
2435
"""See Mutable.last_revision."""
2585
return self._control_files.get('last-revision').read()
2437
return osutils.safe_revision_id(
2438
self._control_files.get('last-revision').read())
2586
2439
except errors.NoSuchFile:
2587
return _mod_revision.NULL_REVISION
2589
2442
def _change_last_revision(self, revision_id):
2590
2443
"""See WorkingTree._change_last_revision."""
2765
2615
sio = StringIO()
2766
2616
inv = Inventory()
2767
xml5.serializer_v5.write_inventory(inv, sio, working=True)
2617
xml5.serializer_v5.write_inventory(inv, sio)
2769
2619
control_files.put('inventory', sio)
2771
2621
control_files.put_bytes('pending-merges', '')
2774
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2775
accelerator_tree=None, hardlink=False):
2624
def initialize(self, a_bzrdir, revision_id=None):
2776
2625
"""See WorkingTreeFormat.initialize()."""
2777
2626
if not isinstance(a_bzrdir.transport, LocalTransport):
2778
2627
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2779
if from_branch is not None:
2780
branch = from_branch
2782
branch = a_bzrdir.open_branch()
2628
branch = a_bzrdir.open_branch()
2783
2629
if revision_id is None:
2784
2630
revision_id = _mod_revision.ensure_null(branch.last_revision())
2632
revision_id = osutils.safe_revision_id(revision_id)
2785
2633
branch.lock_write()
2787
2635
branch.generate_revision_history(revision_id)
2864
2712
return LockableFiles(transport, self._lock_file_name,
2865
2713
self._lock_class)
2867
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2868
accelerator_tree=None, hardlink=False):
2715
def initialize(self, a_bzrdir, revision_id=None):
2869
2716
"""See WorkingTreeFormat.initialize().
2871
:param revision_id: if supplied, create a working tree at a different
2872
revision than the branch is at.
2873
:param accelerator_tree: A tree which can be used for retrieving file
2874
contents more quickly than the revision tree, i.e. a workingtree.
2875
The revision tree will be used for cases where accelerator_tree's
2876
content is different.
2877
:param hardlink: If true, hard-link files from accelerator_tree,
2718
revision_id allows creating a working tree at a different
2719
revision than the branch is at.
2880
2721
if not isinstance(a_bzrdir.transport, LocalTransport):
2881
2722
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2884
2725
control_files.create_lock()
2885
2726
control_files.lock_write()
2886
2727
control_files.put_utf8('format', self.get_format_string())
2887
if from_branch is not None:
2888
branch = from_branch
2890
branch = a_bzrdir.open_branch()
2728
branch = a_bzrdir.open_branch()
2891
2729
if revision_id is None:
2892
2730
revision_id = _mod_revision.ensure_null(branch.last_revision())
2732
revision_id = osutils.safe_revision_id(revision_id)
2893
2733
# WorkingTree3 can handle an inventory which has a unique root id.
2894
2734
# as of bzr 0.12. However, bzr 0.11 and earlier fail to handle
2895
2735
# those trees. And because there isn't a format bump inbetween, we