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
246
246
# permitted to do this.
247
247
self._set_inventory(_inventory, dirty=False)
248
248
self._detect_case_handling()
249
self._rules_searcher = None
251
250
def _detect_case_handling(self):
252
251
wt_trans = self.bzrdir.get_workingtree_transport(None)
284
283
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
286
def _set_inventory(self, inv, dirty):
294
287
"""Set the internal cached inventory.
312
path = osutils.getcwd()
305
path = os.path.getcwdu()
313
306
control = bzrdir.BzrDir.open(path, _unsupported)
314
307
return control.open_workingtree(_unsupported)
317
310
def open_containing(path=None):
318
311
"""Open an existing working tree which has its root about path.
320
313
This probes for a working tree at path and searches upwards from there.
322
315
Basically we keep looking up until we find the control directory or
385
378
"""Return RevisionTree for the current last revision.
387
380
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).
381
empty tree - one obtained by calling repository.revision_tree(None).
392
384
revision_id = self.get_parent_ids()[0]
394
386
# no parents, return an empty revision tree.
395
387
# in the future this should return the tree for
396
388
# 'empty:' - the implicit root empty tree.
397
return self.branch.repository.revision_tree(
398
_mod_revision.NULL_REVISION)
389
return self.branch.repository.revision_tree(None)
400
391
return self.revision_tree(revision_id)
401
392
except errors.NoSuchRevision:
412
403
if self.branch.repository.has_revision(revision_id):
414
405
# the basis tree is a ghost so return an empty tree.
415
return self.branch.repository.revision_tree(
416
_mod_revision.NULL_REVISION)
406
return self.branch.repository.revision_tree(None)
418
408
def _cleanup(self):
419
409
self._flush_ignore_list_cache()
430
420
return osutils.lexists(self.abspath(filename))
432
422
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
424
path = self.id2path(file_id)
439
file_obj = self.get_file_byname(path)
440
return (file_obj, _fstat(file_obj.fileno()))
425
return self.get_file_byname(path)
427
def get_file_text(self, file_id):
428
return self.get_file(file_id).read()
442
430
def get_file_byname(self, filename):
443
431
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
434
def annotate_iter(self, file_id, default_revision=CURRENT_REVISION):
455
435
"""See Tree.annotate_iter
539
519
and this one merged in.
541
521
# assumes the target bzr dir format is compatible.
542
result = to_bzrdir.create_workingtree()
522
result = self._format.initialize(to_bzrdir)
543
523
self.copy_content_into(result, revision_id)
723
703
kind = 'tree-reference'
724
704
return kind, None, None, None
725
705
elif kind == 'symlink':
726
return ('symlink', None, None, os.readlink(abspath.encode(osutils._fs_enc)))
706
return ('symlink', None, None, os.readlink(abspath))
728
708
return (kind, None, None, None)
916
896
hashfile = self._transport.get('merge-hashes')
917
897
except errors.NoSuchFile:
922
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
923
raise errors.MergeModifiedFormatError()
924
except StopIteration:
901
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
925
902
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
903
except StopIteration:
904
raise errors.MergeModifiedFormatError()
905
for s in RioReader(hashfile):
906
# RioReader reads in Unicode, so convert file_ids back to utf8
907
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
908
if file_id not in self.inventory:
910
text_hash = s.get("hash")
911
if text_hash == self.get_file_sha1(file_id):
912
merge_hashes[file_id] = text_hash
938
915
@needs_write_lock
939
916
def mkdir(self, path, file_id=None):
947
924
def get_symlink_target(self, file_id):
948
return os.readlink(self.id2abspath(file_id).encode(osutils._fs_enc))
925
return os.readlink(self.id2abspath(file_id))
950
927
@needs_write_lock
951
928
def subsume(self, other_tree):
1338
1315
only_change_inv = True
1339
1316
elif self.has_filename(from_rel) and not self.has_filename(to_rel):
1340
1317
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)):
1318
elif (sys.platform == 'win32'
1319
and from_rel.lower() == to_rel.lower()
1320
and self.has_filename(from_rel)):
1344
1321
only_change_inv = False
1346
1323
# something is wrong, so lets determine what exactly
1614
1591
if subf == '.bzr':
1616
1593
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,
1594
subf_norm, can_access = osutils.normalized_filename(subf)
1625
1595
if subf_norm != subf and can_access:
1626
1596
if subf_norm not in dir_entry.children:
1627
1597
fl.append(subf_norm)
1881
1851
# Recurse directory and add all files
1882
1852
# so we can check if they have changed.
1883
1853
for parent_info, file_infos in\
1884
self.walkdirs(directory):
1885
for relpath, basename, kind, lstat, fileid, kind in file_infos:
1854
osutils.walkdirs(self.abspath(directory),
1856
for relpath, basename, kind, lstat, abspath in file_infos:
1886
1857
# Is it versioned or ignored?
1887
1858
if self.path2id(relpath) or self.is_ignored(relpath):
1888
1859
# Add nested content for deletion.
2343
2315
bzrdir_loc = bisect_left(cur_disk_dir_content,
2344
2316
('.bzr', '.bzr'))
2345
if (bzrdir_loc < len(cur_disk_dir_content)
2346
and cur_disk_dir_content[bzrdir_loc][0] == '.bzr'):
2317
if cur_disk_dir_content[bzrdir_loc][0] == '.bzr':
2347
2318
# we dont yield the contents of, or, .bzr itself.
2348
2319
del cur_disk_dir_content[bzrdir_loc]
2349
2320
if inv_finished:
2440
2411
# FIXME: stash the node in pending
2441
2412
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
2413
for name, child in entry.sorted_children():
2414
dirblock.append((relroot + name, name, child.kind, None,
2415
child.file_id, child.kind
2447
2417
yield (currentdir[0], entry.file_id), dirblock
2448
2418
# push the user specified dirs from dirblock
2449
2419
for dir in reversed(dirblock):
2482
2452
self.set_conflicts(un_resolved)
2483
2453
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
2455
def _validate(self):
2500
2456
"""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
2467
class WorkingTree2(WorkingTree):
2525
2468
"""This is the Format 2 working tree.
2621
2564
except errors.NoSuchFile:
2622
2565
return _mod_conflicts.ConflictList()
2625
if confile.next() != CONFLICT_HEADER_1 + '\n':
2626
raise errors.ConflictFormatError()
2627
except StopIteration:
2567
if confile.next() != CONFLICT_HEADER_1 + '\n':
2628
2568
raise errors.ConflictFormatError()
2629
return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
2569
except StopIteration:
2570
raise errors.ConflictFormatError()
2571
return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
2633
2573
def unlock(self):
2634
2574
# do non-implementation specific cleanup
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
2664
def register_format(klass, format):
2733
2665
klass._formats[format.get_format_string()] = format
2753
2685
"""See WorkingTreeFormat.get_format_description()."""
2754
2686
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.
2688
def _stub_initialize_remote(self, branch):
2689
"""As a special workaround create critical control files for a remote working tree.
2759
2691
This ensures that it can later be updated and dealt with locally,
2760
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2692
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2761
2693
no working tree. (See bug #43064).
2763
2695
sio = StringIO()
2764
2696
inv = Inventory()
2765
2697
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)
2699
branch._transport.put_file('inventory', sio,
2700
mode=branch.control_files._file_mode)
2701
branch._transport.put_bytes('pending-merges', '',
2702
mode=branch.control_files._file_mode)
2770
2705
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2771
2706
accelerator_tree=None, hardlink=False):
2957
2892
__default_format = WorkingTreeFormat4()
2958
2893
WorkingTreeFormat.register_format(__default_format)
2959
WorkingTreeFormat.register_format(WorkingTreeFormat5())
2960
2894
WorkingTreeFormat.register_format(WorkingTreeFormat3())
2961
2895
WorkingTreeFormat.set_default_format(__default_format)
2962
2896
# formats which have no format string are not discoverable