1
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
79
79
import bzrlib.branch
80
80
from bzrlib.transport import get_transport
82
from bzrlib.workingtree_4 import WorkingTreeFormat4, WorkingTreeFormat5
82
from bzrlib.workingtree_4 import WorkingTreeFormat4
85
85
from bzrlib import symbol_versioning
86
86
from bzrlib.decorators import needs_read_lock, needs_write_lock
87
87
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, TreeReference
88
from bzrlib.lockable_files import LockableFiles
88
from bzrlib.lockable_files import LockableFiles, TransportLock
89
89
from bzrlib.lockdir import LockDir
90
90
import bzrlib.mutabletree
91
91
from bzrlib.mutabletree import needs_tree_write_lock
120
123
ERROR_PATH_NOT_FOUND = 3 # WindowsError errno code, equivalent to ENOENT
126
@deprecated_function(zero_thirteen)
127
def gen_file_id(name):
128
"""Return new file id for the basename 'name'.
130
Use bzrlib.generate_ids.gen_file_id() instead
132
return generate_ids.gen_file_id(name)
135
@deprecated_function(zero_thirteen)
137
"""Return a new tree-root file id.
139
This has been deprecated in favor of bzrlib.generate_ids.gen_root_id()
141
return generate_ids.gen_root_id()
123
144
class TreeEntry(object):
124
145
"""An entry that implements the minimum interface used by commands.
201
222
if not _internal:
202
223
raise errors.BzrError("Please use bzrdir.open_workingtree or "
203
224
"WorkingTree.open() to obtain a WorkingTree.")
225
assert isinstance(basedir, basestring), \
226
"base directory %r is not a string" % basedir
204
227
basedir = safe_unicode(basedir)
205
228
mutter("opening working tree %r", basedir)
206
229
if deprecated_passed(branch):
214
237
self._control_files = self.branch.control_files
216
239
# assume all other formats have their own control files.
240
assert isinstance(_control_files, LockableFiles), \
241
"_control_files must be a LockableFiles, not %r" \
217
243
self._control_files = _control_files
218
self._transport = self._control_files._transport
219
244
# update the whole cache up front and write to disk if anything changed;
220
245
# in the future we might want to do this more selectively
221
246
# two possible ways offer themselves : in self._unlock, write the cache
225
250
wt_trans = self.bzrdir.get_workingtree_transport(None)
226
251
cache_filename = wt_trans.local_abspath('stat-cache')
227
252
self._hashcache = hashcache.HashCache(basedir, cache_filename,
228
self.bzrdir._get_file_mode())
253
self._control_files._file_mode)
229
254
hc = self._hashcache
231
256
# is this scan needed ? it makes things kinda slow.
245
270
# the Format factory and creation methods that are
246
271
# permitted to do this.
247
272
self._set_inventory(_inventory, dirty=False)
248
self._detect_case_handling()
249
self._rules_searcher = None
251
def _detect_case_handling(self):
252
wt_trans = self.bzrdir.get_workingtree_transport(None)
254
wt_trans.stat("FoRMaT")
255
except errors.NoSuchFile:
256
self.case_sensitive = True
258
self.case_sensitive = False
260
self._setup_directory_is_tree_reference()
262
274
branch = property(
263
275
fget=lambda self: self._branch,
284
296
def supports_tree_reference(self):
287
def supports_content_filtering(self):
288
return self._format.supports_content_filtering()
290
def supports_views(self):
291
return self._format.supports_views()
293
299
def _set_inventory(self, inv, dirty):
294
300
"""Set the internal cached inventory.
312
path = osutils.getcwd()
319
path = os.path.getcwdu()
313
320
control = bzrdir.BzrDir.open(path, _unsupported)
314
321
return control.open_workingtree(_unsupported)
317
324
def open_containing(path=None):
318
325
"""Open an existing working tree which has its root about path.
320
327
This probes for a working tree at path and searches upwards from there.
322
329
Basically we keep looking up until we find the control directory or
341
348
return WorkingTree.open(path, _unsupported=True)
344
def find_trees(location):
345
def list_current(transport):
346
return [d for d in transport.list_dir('') if d != '.bzr']
347
def evaluate(bzrdir):
349
tree = bzrdir.open_workingtree()
350
except errors.NoWorkingTree:
354
transport = get_transport(location)
355
iterator = bzrdir.BzrDir.find_bzrdirs(transport, evaluate=evaluate,
356
list_current=list_current)
357
return [t for t in iterator if t is not None]
359
350
# should be deprecated - this is slow and in any case treating them as a
360
351
# container is (we now know) bad style -- mbp 20070302
361
352
## @deprecated_method(zero_fifteen)
370
361
if osutils.lexists(self.abspath(path)):
373
def all_file_ids(self):
374
"""See Tree.iter_all_file_ids"""
375
return set(self.inventory)
377
364
def __repr__(self):
378
365
return "<%s of %s>" % (self.__class__.__name__,
379
366
getattr(self, 'basedir', None))
385
372
"""Return RevisionTree for the current last revision.
387
374
If the left most parent is a ghost then the returned tree will be an
388
empty tree - one obtained by calling
389
repository.revision_tree(NULL_REVISION).
375
empty tree - one obtained by calling repository.revision_tree(None).
392
378
revision_id = self.get_parent_ids()[0]
394
380
# no parents, return an empty revision tree.
395
381
# in the future this should return the tree for
396
382
# 'empty:' - the implicit root empty tree.
397
return self.branch.repository.revision_tree(
398
_mod_revision.NULL_REVISION)
383
return self.branch.repository.revision_tree(None)
400
385
return self.revision_tree(revision_id)
401
386
except errors.NoSuchRevision:
405
390
# at this point ?
407
392
return self.branch.repository.revision_tree(revision_id)
408
except (errors.RevisionNotPresent, errors.NoSuchRevision):
393
except errors.RevisionNotPresent:
409
394
# the basis tree *may* be a ghost or a low level error may have
410
395
# occured. If the revision is present, its a problem, if its not
412
397
if self.branch.repository.has_revision(revision_id):
414
399
# the basis tree is a ghost so return an empty tree.
415
return self.branch.repository.revision_tree(
416
_mod_revision.NULL_REVISION)
400
return self.branch.repository.revision_tree(None)
418
402
def _cleanup(self):
419
403
self._flush_ignore_list_cache()
406
@deprecated_method(zero_eight)
407
def create(branch, directory):
408
"""Create a workingtree for branch at directory.
410
If existing_directory already exists it must have a .bzr directory.
411
If it does not exist, it will be created.
413
This returns a new WorkingTree object for the new checkout.
415
TODO FIXME RBC 20060124 when we have checkout formats in place this
416
should accept an optional revisionid to checkout [and reject this if
417
checking out into the same dir as a pre-checkout-aware branch format.]
419
XXX: When BzrDir is present, these should be created through that
422
warnings.warn('delete WorkingTree.create', stacklevel=3)
423
transport = get_transport(directory)
424
if branch.bzrdir.root_transport.base == transport.base:
426
return branch.bzrdir.create_workingtree()
427
# different directory,
428
# create a branch reference
429
# and now a working tree.
430
raise NotImplementedError
433
@deprecated_method(zero_eight)
434
def create_standalone(directory):
435
"""Create a checkout and a branch and a repo at directory.
437
Directory must exist and be empty.
439
please use BzrDir.create_standalone_workingtree
441
return bzrdir.BzrDir.create_standalone_workingtree(directory)
421
443
def relpath(self, path):
422
444
"""Return the local path portion from a given path.
430
452
return osutils.lexists(self.abspath(filename))
432
454
def get_file(self, file_id, path=None):
433
return self.get_file_with_stat(file_id, path)[0]
435
def get_file_with_stat(self, file_id, path=None, _fstat=os.fstat):
436
"""See MutableTree.get_file_with_stat."""
438
456
path = self.id2path(file_id)
439
file_obj = self.get_file_byname(path)
440
return (file_obj, _fstat(file_obj.fileno()))
457
return self.get_file_byname(path)
459
def get_file_text(self, file_id):
460
return self.get_file(file_id).read()
442
462
def get_file_byname(self, filename):
443
463
return file(self.abspath(filename), 'rb')
445
def get_file_lines(self, file_id, path=None):
446
"""See Tree.get_file_lines()"""
447
file = self.get_file(file_id, path)
449
return file.readlines()
454
466
def annotate_iter(self, file_id, default_revision=CURRENT_REVISION):
455
467
"""See Tree.annotate_iter
464
476
basis = self.basis_tree()
465
477
basis.lock_read()
467
changes = self.iter_changes(basis, True, [self.id2path(file_id)],
479
changes = self._iter_changes(basis, True, [self.id2path(file_id)],
468
480
require_versioned=True).next()
469
481
changed_content, kind = changes[2], changes[6]
470
482
if not changed_content:
539
551
and this one merged in.
541
553
# assumes the target bzr dir format is compatible.
542
result = to_bzrdir.create_workingtree()
554
result = self._format.initialize(to_bzrdir)
543
555
self.copy_content_into(result, revision_id)
574
586
__contains__ = has_id
576
588
def get_file_size(self, file_id):
577
"""See Tree.get_file_size"""
579
return os.path.getsize(self.id2abspath(file_id))
581
if e.errno != errno.ENOENT:
589
return os.path.getsize(self.id2abspath(file_id))
587
592
def get_file_sha1(self, file_id, path=None, stat_value=None):
627
632
# function - they should be part of lock_write and unlock.
628
633
inv = self.inventory
629
634
for f, file_id, kind in zip(files, ids, kinds):
635
assert kind is not None
630
636
if file_id is None:
631
637
inv.add_path(f, kind=kind)
723
729
kind = 'tree-reference'
724
730
return kind, None, None, None
725
731
elif kind == 'symlink':
726
return ('symlink', None, None, os.readlink(abspath.encode(osutils._fs_enc)))
732
return ('symlink', None, None, os.readlink(abspath))
728
734
return (kind, None, None, None)
736
@deprecated_method(zero_eleven)
738
def pending_merges(self):
739
"""Return a list of pending merges.
741
These are revisions that have been merged into the working
742
directory but not yet committed.
744
As of 0.11 this is deprecated. Please see WorkingTree.get_parent_ids()
745
instead - which is available on all tree objects.
747
return self.get_parent_ids()[1:]
730
749
def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
731
750
"""Common ghost checking functionality from set_parent_*.
742
761
def _set_merges_from_parent_ids(self, parent_ids):
743
762
merges = parent_ids[1:]
744
self._transport.put_bytes('pending-merges', '\n'.join(merges),
745
mode=self._control_files._file_mode)
747
def _filter_parent_ids_by_ancestry(self, revision_ids):
748
"""Check that all merged revisions are proper 'heads'.
750
This will always return the first revision_id, and any merged revisions
753
if len(revision_ids) == 0:
755
graph = self.branch.repository.get_graph()
756
heads = graph.heads(revision_ids)
757
new_revision_ids = revision_ids[:1]
758
for revision_id in revision_ids[1:]:
759
if revision_id in heads and revision_id not in new_revision_ids:
760
new_revision_ids.append(revision_id)
761
if new_revision_ids != revision_ids:
762
trace.mutter('requested to set revision_ids = %s,'
763
' but filtered to %s', revision_ids, new_revision_ids)
764
return new_revision_ids
763
self._control_files.put_bytes('pending-merges', '\n'.join(merges))
766
765
@needs_tree_write_lock
767
766
def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
781
780
for revision_id in revision_ids:
782
781
_mod_revision.check_not_reserved_id(revision_id)
784
revision_ids = self._filter_parent_ids_by_ancestry(revision_ids)
786
783
if len(revision_ids) > 0:
787
784
self.set_last_revision(revision_ids[0])
800
797
self._check_parents_for_ghosts(parent_ids,
801
798
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
803
parent_ids = self._filter_parent_ids_by_ancestry(parent_ids)
805
800
if len(parent_ids) == 0:
806
801
leftmost_parent_id = _mod_revision.NULL_REVISION
807
802
leftmost_parent_tree = None
847
842
def _put_rio(self, filename, stanzas, header):
848
843
self._must_be_locked()
849
844
my_file = rio_file(stanzas, header)
850
self._transport.put_file(filename, my_file,
851
mode=self._control_files._file_mode)
845
self._control_files.put(filename, my_file)
853
847
@needs_write_lock # because merge pulls data into the branch.
854
848
def merge_from_branch(self, branch, to_revision=None, from_revision=None,
913
907
still in the working inventory and have that text hash.
916
hashfile = self._transport.get('merge-hashes')
910
hashfile = self._control_files.get('merge-hashes')
917
911
except errors.NoSuchFile:
922
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
923
raise errors.MergeModifiedFormatError()
924
except StopIteration:
915
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
925
916
raise errors.MergeModifiedFormatError()
926
for s in RioReader(hashfile):
927
# RioReader reads in Unicode, so convert file_ids back to utf8
928
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
929
if file_id not in self.inventory:
931
text_hash = s.get("hash")
932
if text_hash == self.get_file_sha1(file_id):
933
merge_hashes[file_id] = text_hash
917
except StopIteration:
918
raise errors.MergeModifiedFormatError()
919
for s in RioReader(hashfile):
920
# RioReader reads in Unicode, so convert file_ids back to utf8
921
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
922
if file_id not in self.inventory:
924
text_hash = s.get("hash")
925
if text_hash == self.get_file_sha1(file_id):
926
merge_hashes[file_id] = text_hash
938
929
@needs_write_lock
939
930
def mkdir(self, path, file_id=None):
947
938
def get_symlink_target(self, file_id):
948
return os.readlink(self.id2abspath(file_id).encode(osutils._fs_enc))
939
return os.readlink(self.id2abspath(file_id))
950
941
@needs_write_lock
951
942
def subsume(self, other_tree):
989
980
other_tree.unlock()
990
981
other_tree.bzrdir.retire_bzrdir()
992
def _setup_directory_is_tree_reference(self):
993
if self._branch.repository._format.supports_tree_reference:
994
self._directory_is_tree_reference = \
995
self._directory_may_be_tree_reference
997
self._directory_is_tree_reference = \
998
self._directory_is_never_tree_reference
1000
def _directory_is_never_tree_reference(self, relpath):
1003
def _directory_may_be_tree_reference(self, relpath):
983
def _directory_is_tree_reference(self, relpath):
1004
984
# as a special case, if a directory contains control files then
1005
985
# it's a tree reference, except that the root of the tree is not
1006
986
return relpath and osutils.isdir(self.abspath(relpath) + u"/.bzr")
1033
1013
sub_path = self.id2path(file_id)
1034
1014
branch_transport = mkdirs(sub_path)
1035
1015
if format is None:
1036
format = self.bzrdir.cloning_metadir()
1016
format = bzrdir.format_registry.make_bzrdir('dirstate-with-subtree')
1037
1017
branch_transport.ensure_base()
1038
1018
branch_bzrdir = format.initialize_on_transport(branch_transport)
1040
1020
repo = branch_bzrdir.find_repository()
1041
1021
except errors.NoRepositoryPresent:
1042
1022
repo = branch_bzrdir.create_repository()
1043
if not repo.supports_rich_root():
1044
raise errors.RootNotRich()
1023
assert repo.supports_rich_root()
1025
if not repo.supports_rich_root():
1026
raise errors.RootNotRich()
1045
1027
new_branch = branch_bzrdir.create_branch()
1046
1028
new_branch.pull(self.branch)
1047
1029
for parent_id in self.get_parent_ids():
1079
1061
sio = StringIO()
1080
1062
self._serialize(self._inventory, sio)
1082
self._transport.put_file('inventory', sio,
1083
mode=self._control_files._file_mode)
1064
self._control_files.put('inventory', sio)
1084
1065
self._inventory_is_modified = False
1086
1067
def _kind(self, relpath):
1247
1228
DeprecationWarning)
1249
1230
# check destination directory
1250
if isinstance(from_paths, basestring):
1231
assert not isinstance(from_paths, basestring)
1252
1232
inv = self.inventory
1253
1233
to_abs = self.abspath(to_dir)
1254
1234
if not isdir(to_abs):
1338
1318
only_change_inv = True
1339
1319
elif self.has_filename(from_rel) and not self.has_filename(to_rel):
1340
1320
only_change_inv = False
1341
elif (not self.case_sensitive
1342
and from_rel.lower() == to_rel.lower()
1343
and self.has_filename(from_rel)):
1321
elif (sys.platform == 'win32'
1322
and from_rel.lower() == to_rel.lower()
1323
and self.has_filename(from_rel)):
1344
1324
only_change_inv = False
1346
1326
# something is wrong, so lets determine what exactly
1518
1498
# - RBC 20060907
1519
1499
self._write_inventory(self._inventory)
1501
@deprecated_method(zero_eight)
1502
def iter_conflicts(self):
1503
"""List all files in the tree that have text or content conflicts.
1504
DEPRECATED. Use conflicts instead."""
1505
return self._iter_conflicts()
1521
1507
def _iter_conflicts(self):
1522
1508
conflicted = set()
1523
1509
for info in self.list_files():
1614
1600
if subf == '.bzr':
1616
1602
if subf not in dir_entry.children:
1619
can_access) = osutils.normalized_filename(subf)
1620
except UnicodeDecodeError:
1621
path_os_enc = path.encode(osutils._fs_enc)
1622
relpath = path_os_enc + '/' + subf
1623
raise errors.BadFilenameEncoding(relpath,
1603
subf_norm, can_access = osutils.normalized_filename(subf)
1625
1604
if subf_norm != subf and can_access:
1626
1605
if subf_norm not in dir_entry.children:
1627
1606
fl.append(subf_norm)
1682
1661
def kind(self, file_id):
1683
1662
return file_kind(self.id2abspath(file_id))
1685
def stored_kind(self, file_id):
1686
"""See Tree.stored_kind"""
1687
return self.inventory[file_id].kind
1689
1664
def _comparison_data(self, entry, path):
1690
1665
abspath = self.abspath(path)
1773
1748
def _reset_data(self):
1774
1749
"""Reset transient data that cannot be revalidated."""
1775
1750
self._inventory_is_modified = False
1776
result = self._deserialize(self._transport.get('inventory'))
1751
result = self._deserialize(self._control_files.get('inventory'))
1777
1752
self._set_inventory(result, dirty=False)
1779
1754
@needs_tree_write_lock
1801
1776
def _write_basis_inventory(self, xml):
1802
1777
"""Write the basis inventory XML to the basis-inventory file"""
1778
assert isinstance(xml, str), 'serialised xml must be bytestring.'
1803
1779
path = self._basis_inventory_name()
1804
1780
sio = StringIO(xml)
1805
self._transport.put_file(path, sio,
1806
mode=self._control_files._file_mode)
1781
self._control_files.put(path, sio)
1808
1783
def _create_basis_xml_from_inventory(self, revision_id, inventory):
1809
1784
"""Create the text that will be saved in basis-inventory"""
1840
1815
def read_basis_inventory(self):
1841
1816
"""Read the cached basis inventory."""
1842
1817
path = self._basis_inventory_name()
1843
return self._transport.get_bytes(path)
1818
return self._control_files.get(path).read()
1845
1820
@needs_read_lock
1846
1821
def read_working_inventory(self):
1856
1831
if self._inventory_is_modified:
1857
1832
raise errors.InventoryModified(self)
1858
result = self._deserialize(self._transport.get('inventory'))
1833
result = self._deserialize(self._control_files.get('inventory'))
1859
1834
self._set_inventory(result, dirty=False)
1881
1856
# Recurse directory and add all files
1882
1857
# so we can check if they have changed.
1883
1858
for parent_info, file_infos in\
1884
self.walkdirs(directory):
1885
for relpath, basename, kind, lstat, fileid, kind in file_infos:
1859
osutils.walkdirs(self.abspath(directory),
1861
for relpath, basename, kind, lstat, abspath in file_infos:
1886
1862
# Is it versioned or ignored?
1887
1863
if self.path2id(relpath) or self.is_ignored(relpath):
1888
1864
# Add nested content for deletion.
1913
1890
has_changed_files = len(unknown_nested_files) > 0
1914
1891
if not has_changed_files:
1915
1892
for (file_id, path, content_change, versioned, parent_id, name,
1916
kind, executable) in self.iter_changes(self.basis_tree(),
1893
kind, executable) in self._iter_changes(self.basis_tree(),
1917
1894
include_unchanged=True, require_versioned=False,
1918
1895
want_unversioned=True, specific_files=files):
1919
if versioned == (False, False):
1920
# The record is unknown ...
1921
if not self.is_ignored(path[1]):
1922
# ... but not ignored
1923
has_changed_files = True
1925
elif content_change and (kind[1] is not None):
1926
# Versioned and changed, but not deleted
1896
# Check if it's an unknown (but not ignored) OR
1897
# changed (but not deleted) :
1898
if ((versioned == (False, False) or
1899
content_change and kind[1] != None)
1900
and not self.is_ignored(path[1])):
1927
1901
has_changed_files = True
2008
1982
self.set_parent_trees(parent_trees)
2011
resolve(self, filenames, ignore_misses=True, recursive=True)
1985
resolve(self, filenames, ignore_misses=True)
2013
1987
if basis_tree is not None:
2014
1988
basis_tree.unlock()
2068
2042
"""Set the root id for this tree."""
2069
2043
# for compatability
2070
2044
if file_id is None:
2072
'WorkingTree.set_root_id with fileid=None')
2073
file_id = osutils.safe_file_id(file_id)
2045
symbol_versioning.warn(symbol_versioning.zero_twelve
2046
% 'WorkingTree.set_root_id with fileid=None',
2051
file_id = osutils.safe_file_id(file_id)
2074
2052
self._set_root_id(file_id)
2076
2054
def _set_root_id(self, file_id):
2343
2321
bzrdir_loc = bisect_left(cur_disk_dir_content,
2344
2322
('.bzr', '.bzr'))
2345
if (bzrdir_loc < len(cur_disk_dir_content)
2346
and cur_disk_dir_content[bzrdir_loc][0] == '.bzr'):
2323
if cur_disk_dir_content[bzrdir_loc][0] == '.bzr':
2347
2324
# we dont yield the contents of, or, .bzr itself.
2348
2325
del cur_disk_dir_content[bzrdir_loc]
2349
2326
if inv_finished:
2440
2417
# FIXME: stash the node in pending
2441
2418
entry = inv[top_id]
2442
if entry.kind == 'directory':
2443
for name, child in entry.sorted_children():
2444
dirblock.append((relroot + name, name, child.kind, None,
2445
child.file_id, child.kind
2419
for name, child in entry.sorted_children():
2420
dirblock.append((relroot + name, name, child.kind, None,
2421
child.file_id, child.kind
2447
2423
yield (currentdir[0], entry.file_id), dirblock
2448
2424
# push the user specified dirs from dirblock
2449
2425
for dir in reversed(dirblock):
2482
2458
self.set_conflicts(un_resolved)
2483
2459
return un_resolved, resolved
2487
tree_basis = self.basis_tree()
2488
tree_basis.lock_read()
2490
repo_basis = self.branch.repository.revision_tree(
2491
self.last_revision())
2492
if len(list(repo_basis.iter_changes(tree_basis))) > 0:
2493
raise errors.BzrCheckError(
2494
"Mismatched basis inventory content.")
2499
2461
def _validate(self):
2500
2462
"""Validate internal structures.
2511
def _get_rules_searcher(self, default_searcher):
2512
"""See Tree._get_rules_searcher."""
2513
if self._rules_searcher is None:
2514
self._rules_searcher = super(WorkingTree,
2515
self)._get_rules_searcher(default_searcher)
2516
return self._rules_searcher
2518
def get_shelf_manager(self):
2519
"""Return the ShelfManager for this WorkingTree."""
2520
from bzrlib.shelf import ShelfManager
2521
return ShelfManager(self, self._transport)
2524
2473
class WorkingTree2(WorkingTree):
2525
2474
"""This is the Format 2 working tree.
2585
2534
def _last_revision(self):
2586
2535
"""See Mutable.last_revision."""
2588
return self._transport.get_bytes('last-revision')
2537
return self._control_files.get('last-revision').read()
2589
2538
except errors.NoSuchFile:
2590
2539
return _mod_revision.NULL_REVISION
2593
2542
"""See WorkingTree._change_last_revision."""
2594
2543
if revision_id is None or revision_id == NULL_REVISION:
2596
self._transport.delete('last-revision')
2545
self._control_files._transport.delete('last-revision')
2597
2546
except errors.NoSuchFile:
2601
self._transport.put_bytes('last-revision', revision_id,
2602
mode=self._control_files._file_mode)
2550
self._control_files.put_bytes('last-revision', revision_id)
2605
2553
@needs_tree_write_lock
2617
2565
@needs_read_lock
2618
2566
def conflicts(self):
2620
confile = self._transport.get('conflicts')
2568
confile = self._control_files.get('conflicts')
2621
2569
except errors.NoSuchFile:
2622
2570
return _mod_conflicts.ConflictList()
2625
if confile.next() != CONFLICT_HEADER_1 + '\n':
2626
raise errors.ConflictFormatError()
2627
except StopIteration:
2572
if confile.next() != CONFLICT_HEADER_1 + '\n':
2628
2573
raise errors.ConflictFormatError()
2629
return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
2574
except StopIteration:
2575
raise errors.ConflictFormatError()
2576
return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
2633
2578
def unlock(self):
2634
2579
# do non-implementation specific cleanup
2651
2596
return path[:-len(suffix)]
2599
@deprecated_function(zero_eight)
2600
def is_control_file(filename):
2601
"""See WorkingTree.is_control_filename(filename)."""
2602
## FIXME: better check
2603
filename = normpath(filename)
2604
while filename != '':
2605
head, tail = os.path.split(filename)
2606
## mutter('check %r for control file' % ((head, tail),))
2609
if filename == head:
2654
2615
class WorkingTreeFormat(object):
2655
2616
"""An encapsulation of the initialization and open routines for a format.
2689
2650
except errors.NoSuchFile:
2690
2651
raise errors.NoWorkingTree(base=transport.base)
2691
2652
except KeyError:
2692
raise errors.UnknownFormatError(format=format_string,
2693
kind="working tree")
2653
raise errors.UnknownFormatError(format=format_string)
2695
2655
def __eq__(self, other):
2696
2656
return self.__class__ is other.__class__
2723
def supports_content_filtering(self):
2724
"""True if this format supports content filtering."""
2727
def supports_views(self):
2728
"""True if this format supports stored views."""
2732
2684
def register_format(klass, format):
2733
2685
klass._formats[format.get_format_string()] = format
2753
2706
"""See WorkingTreeFormat.get_format_description()."""
2754
2707
return "Working tree format 2"
2756
def _stub_initialize_on_transport(self, transport, file_mode):
2757
"""Workaround: create control files for a remote working tree.
2709
def stub_initialize_remote(self, control_files):
2710
"""As a special workaround create critical control files for a remote working tree
2759
2712
This ensures that it can later be updated and dealt with locally,
2760
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2713
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2761
2714
no working tree. (See bug #43064).
2763
2716
sio = StringIO()
2764
2717
inv = Inventory()
2765
2718
xml5.serializer_v5.write_inventory(inv, sio, working=True)
2767
transport.put_file('inventory', sio, file_mode)
2768
transport.put_bytes('pending-merges', '', file_mode)
2770
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2771
accelerator_tree=None, hardlink=False):
2720
control_files.put('inventory', sio)
2722
control_files.put_bytes('pending-merges', '')
2725
def initialize(self, a_bzrdir, revision_id=None, from_branch=None):
2772
2726
"""See WorkingTreeFormat.initialize()."""
2773
2727
if not isinstance(a_bzrdir.transport, LocalTransport):
2774
2728
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2860
2814
return LockableFiles(transport, self._lock_file_name,
2861
2815
self._lock_class)
2863
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2864
accelerator_tree=None, hardlink=False):
2817
def initialize(self, a_bzrdir, revision_id=None, from_branch=None):
2865
2818
"""See WorkingTreeFormat.initialize().
2867
:param revision_id: if supplied, create a working tree at a different
2868
revision than the branch is at.
2869
:param accelerator_tree: A tree which can be used for retrieving file
2870
contents more quickly than the revision tree, i.e. a workingtree.
2871
The revision tree will be used for cases where accelerator_tree's
2872
content is different.
2873
:param hardlink: If true, hard-link files from accelerator_tree,
2820
revision_id allows creating a working tree at a different
2821
revision than the branch is at.
2876
2823
if not isinstance(a_bzrdir.transport, LocalTransport):
2877
2824
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2879
2826
control_files = self._open_control_files(a_bzrdir)
2880
2827
control_files.create_lock()
2881
2828
control_files.lock_write()
2882
transport.put_bytes('format', self.get_format_string(),
2883
mode=control_files._file_mode)
2829
control_files.put_utf8('format', self.get_format_string())
2884
2830
if from_branch is not None:
2885
2831
branch = from_branch
2957
2903
__default_format = WorkingTreeFormat4()
2958
2904
WorkingTreeFormat.register_format(__default_format)
2959
WorkingTreeFormat.register_format(WorkingTreeFormat5())
2960
2905
WorkingTreeFormat.register_format(WorkingTreeFormat3())
2961
2906
WorkingTreeFormat.set_default_format(__default_format)
2962
2907
# formats which have no format string are not discoverable