1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
1
# Copyright (C) 2005, 2006, 2007, 2008 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
17
17
"""WorkingTree object and friends.
19
19
A WorkingTree represents the editable working copy of a branch.
20
Operations which represent the WorkingTree are also done here,
21
such as renaming or adding files. The WorkingTree has an inventory
22
which is updated by these operations. A commit produces a
20
Operations which represent the WorkingTree are also done here,
21
such as renaming or adding files. The WorkingTree has an inventory
22
which is updated by these operations. A commit produces a
23
23
new revision based on the workingtree and its inventory.
25
25
At the moment every WorkingTree has its own branch. Remote
79
80
import bzrlib.branch
80
81
from bzrlib.transport import get_transport
82
from bzrlib.workingtree_4 import WorkingTreeFormat4
83
from bzrlib.workingtree_4 import WorkingTreeFormat4, WorkingTreeFormat5
85
86
from bzrlib import symbol_versioning
86
87
from bzrlib.decorators import needs_read_lock, needs_write_lock
87
88
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, TreeReference
88
from bzrlib.lockable_files import LockableFiles, TransportLock
89
from bzrlib.lockable_files import LockableFiles
89
90
from bzrlib.lockdir import LockDir
90
91
import bzrlib.mutabletree
91
92
from bzrlib.mutabletree import needs_tree_write_lock
124
125
class TreeEntry(object):
125
126
"""An entry that implements the minimum interface used by commands.
127
This needs further inspection, it may be better to have
128
This needs further inspection, it may be better to have
128
129
InventoryEntries without ids - though that seems wrong. For now,
129
130
this is a parallel hierarchy to InventoryEntry, and needs to become
130
131
one of several things: decorates to that hierarchy, children of, or
133
134
no InventoryEntry available - i.e. for unversioned objects.
134
135
Perhaps they should be UnversionedEntry et al. ? - RBC 20051003
137
138
def __eq__(self, other):
138
139
# yes, this us ugly, TODO: best practice __eq__ style.
139
140
return (isinstance(other, TreeEntry)
140
141
and other.__class__ == self.__class__)
142
143
def kind_character(self):
186
187
not listed in the Inventory and vice versa.
190
# override this to set the strategy for storing views
191
def _make_views(self):
192
return views.DisabledViews(self)
189
194
def __init__(self, basedir='.',
190
195
branch=DEPRECATED_PARAMETER,
227
232
cache_filename = wt_trans.local_abspath('stat-cache')
228
233
self._hashcache = hashcache.HashCache(basedir, cache_filename,
229
234
self.bzrdir._get_file_mode(),
230
lambda path, file_id: self._content_filter_stack(path, file_id))
235
self._content_filter_stack_provider())
231
236
hc = self._hashcache
233
238
# is this scan needed ? it makes things kinda slow.
249
254
self._set_inventory(_inventory, dirty=False)
250
255
self._detect_case_handling()
251
256
self._rules_searcher = None
257
self.views = self._make_views()
253
259
def _detect_case_handling(self):
254
260
wt_trans = self.bzrdir.get_workingtree_transport(None)
286
292
def supports_tree_reference(self):
295
def supports_content_filtering(self):
296
return self._format.supports_content_filtering()
298
def supports_views(self):
299
return self.views.supports_views()
289
301
def _set_inventory(self, inv, dirty):
290
302
"""Set the internal cached inventory.
308
path = os.path.getcwdu()
320
path = osutils.getcwd()
309
321
control = bzrdir.BzrDir.open(path, _unsupported)
310
322
return control.open_workingtree(_unsupported)
313
325
def open_containing(path=None):
314
326
"""Open an existing working tree which has its root about path.
316
328
This probes for a working tree at path and searches upwards from there.
318
330
Basically we keep looking up until we find the control directory or
380
392
def basis_tree(self):
381
393
"""Return RevisionTree for the current last revision.
383
395
If the left most parent is a ghost then the returned tree will be an
384
empty tree - one obtained by calling repository.revision_tree(None).
396
empty tree - one obtained by calling
397
repository.revision_tree(NULL_REVISION).
387
400
revision_id = self.get_parent_ids()[0]
389
402
# no parents, return an empty revision tree.
390
403
# in the future this should return the tree for
391
404
# 'empty:' - the implicit root empty tree.
392
return self.branch.repository.revision_tree(None)
405
return self.branch.repository.revision_tree(
406
_mod_revision.NULL_REVISION)
394
408
return self.revision_tree(revision_id)
395
409
except errors.NoSuchRevision:
406
420
if self.branch.repository.has_revision(revision_id):
408
422
# the basis tree is a ghost so return an empty tree.
409
return self.branch.repository.revision_tree(None)
423
return self.branch.repository.revision_tree(
424
_mod_revision.NULL_REVISION)
411
426
def _cleanup(self):
412
427
self._flush_ignore_list_cache()
414
429
def relpath(self, path):
415
430
"""Return the local path portion from a given path.
417
The path may be absolute or relative. If its a relative path it is
432
The path may be absolute or relative. If its a relative path it is
418
433
interpreted relative to the python current working directory.
420
435
return osutils.relpath(self.basedir, path)
423
438
return osutils.lexists(self.abspath(filename))
425
440
def get_file(self, file_id, path=None, filtered=True):
441
return self.get_file_with_stat(file_id, path, filtered=filtered)[0]
443
def get_file_with_stat(self, file_id, path=None, filtered=True,
445
"""See MutableTree.get_file_with_stat."""
427
447
path = self.id2path(file_id)
428
return self.get_file_byname(path, filtered=filtered)
448
file_obj = self.get_file_byname(path, filtered=False)
449
stat_value = _fstat(file_obj.fileno())
450
if self.supports_content_filtering() and filtered:
451
filters = self._content_filter_stack(path)
452
file_obj = filtered_input_file(file_obj, filters)
453
return (file_obj, stat_value)
430
def get_file_text(self, file_id, filtered=True):
431
return self.get_file(file_id, filtered=filtered).read()
455
def get_file_text(self, file_id, path=None, filtered=True):
456
return self.get_file(file_id, path=path, filtered=filtered).read()
433
458
def get_file_byname(self, filename, filtered=True):
434
459
path = self.abspath(filename)
435
460
f = file(path, 'rb')
461
if self.supports_content_filtering() and filtered:
437
462
filters = self._content_filter_stack(filename)
438
463
return filtered_input_file(f, filters)
442
def get_special_file(self, type):
443
"""Get a file special to Bazaar.
445
:type: a type of XXX maps to a file path .bzrXXX
446
:return: a file-like object or None if the file does not exist
448
path = self.abspath(".bzr" + type)
467
def get_file_lines(self, file_id, path=None, filtered=True):
468
"""See Tree.get_file_lines()"""
469
file = self.get_file(file_id, path, filtered=filtered)
450
return open(path, 'rb')
471
return file.readlines()
455
476
def annotate_iter(self, file_id, default_revision=CURRENT_REVISION):
529
550
def clone(self, to_bzrdir, revision_id=None):
530
551
"""Duplicate this working tree into to_bzr, including all state.
532
553
Specifically modified files are kept as modified, but
533
554
ignored and unknown files are discarded.
535
556
If you want to make a new line of development, see bzrdir.sprout()
538
If not None, the cloned tree will have its last revision set to
559
If not None, the cloned tree will have its last revision set to
539
560
revision, and and difference between the source trees last revision
540
561
and this one merged in.
542
563
# assumes the target bzr dir format is compatible.
543
result = self._format.initialize(to_bzrdir)
564
result = to_bzrdir.create_workingtree()
544
565
self.copy_content_into(result, revision_id)
624
645
"""See MutableTree._add."""
625
646
# TODO: Re-adding a file that is removed in the working copy
626
647
# should probably put it back with the previous ID.
627
# the read and write working inventory should not occur in this
648
# the read and write working inventory should not occur in this
628
649
# function - they should be part of lock_write and unlock.
629
650
inv = self.inventory
630
651
for f, file_id, kind in zip(files, ids, kinds):
724
745
kind = 'tree-reference'
725
746
return kind, None, None, None
726
747
elif kind == 'symlink':
727
return ('symlink', None, None, os.readlink(abspath))
748
return ('symlink', None, None,
749
os.readlink(abspath.encode(osutils._fs_enc)
750
).decode(osutils._fs_enc))
729
752
return (kind, None, None, None)
767
790
@needs_tree_write_lock
768
791
def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
769
792
"""Set the parent ids to revision_ids.
771
794
See also set_parent_trees. This api will try to retrieve the tree data
772
795
for each element of revision_ids from the trees repository. If you have
773
796
tree data already available, it is more efficient to use
906
929
def merge_modified(self):
907
930
"""Return a dictionary of files modified by a merge.
909
The list is initialized by WorkingTree.set_merge_modified, which is
932
The list is initialized by WorkingTree.set_merge_modified, which is
910
933
typically called after we make some automatic updates to the tree
911
934
because of a merge.
917
940
hashfile = self._transport.get('merge-hashes')
918
941
except errors.NoSuchFile:
922
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
946
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
947
raise errors.MergeModifiedFormatError()
948
except StopIteration:
923
949
raise errors.MergeModifiedFormatError()
924
except StopIteration:
925
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
950
for s in RioReader(hashfile):
951
# RioReader reads in Unicode, so convert file_ids back to utf8
952
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
953
if file_id not in self.inventory:
955
text_hash = s.get("hash")
956
if text_hash == self.get_file_sha1(file_id):
957
merge_hashes[file_id] = text_hash
936
962
@needs_write_lock
937
963
def mkdir(self, path, file_id=None):
1001
1027
def _directory_may_be_tree_reference(self, relpath):
1002
# as a special case, if a directory contains control files then
1028
# as a special case, if a directory contains control files then
1003
1029
# it's a tree reference, except that the root of the tree is not
1004
1030
return relpath and osutils.isdir(self.abspath(relpath) + u"/.bzr")
1005
1031
# TODO: We could ask all the control formats whether they
1115
1141
# directory file_id, relative path, absolute path, reverse sorted children
1116
1142
children = os.listdir(self.basedir)
1117
1143
children.sort()
1118
# jam 20060527 The kernel sized tree seems equivalent whether we
1144
# jam 20060527 The kernel sized tree seems equivalent whether we
1119
1145
# use a deque and popleft to keep them sorted, or if we use a plain
1120
1146
# list and just reverse() them.
1121
1147
children = collections.deque(children)
1202
1228
to_dir must exist in the inventory.
1204
1230
If to_dir exists and is a directory, the files are moved into
1205
it, keeping their old names.
1231
it, keeping their old names.
1207
1233
Note that to_dir is only the last component of the new name;
1208
1234
this doesn't change the directory.
1336
1362
only_change_inv = True
1337
1363
elif self.has_filename(from_rel) and not self.has_filename(to_rel):
1338
1364
only_change_inv = False
1339
elif (sys.platform == 'win32'
1340
and from_rel.lower() == to_rel.lower()
1341
and self.has_filename(from_rel)):
1365
elif (not self.case_sensitive
1366
and from_rel.lower() == to_rel.lower()
1367
and self.has_filename(from_rel)):
1342
1368
only_change_inv = False
1344
1370
# something is wrong, so lets determine what exactly
1485
1511
These are files in the working directory that are not versioned or
1486
1512
control files or ignored.
1488
# force the extras method to be fully executed before returning, to
1514
# force the extras method to be fully executed before returning, to
1489
1515
# prevent race conditions with the lock
1491
1517
[subp for subp in self.extras() if not self.is_ignored(subp)])
1507
1533
raise errors.NoSuchId(self, file_id)
1508
1534
if len(file_ids):
1509
# in the future this should just set a dirty bit to wait for the
1535
# in the future this should just set a dirty bit to wait for the
1510
1536
# final unlock. However, until all methods of workingtree start
1511
# with the current in -memory inventory rather than triggering
1537
# with the current in -memory inventory rather than triggering
1512
1538
# a read, it is more complex - we need to teach read_inventory
1513
1539
# to know when to read, and when to not read first... and possibly
1514
1540
# to save first when the in memory one may be corrupted.
1515
1541
# so for now, we just only write it if it is indeed dirty.
1516
1542
# - RBC 20060907
1517
1543
self._write_inventory(self._inventory)
1519
1545
def _iter_conflicts(self):
1520
1546
conflicted = set()
1521
1547
for info in self.list_files():
1564
1590
# reuse the revisiontree we merged against to set the new
1566
1592
parent_trees = [(self.branch.last_revision(), new_basis_tree)]
1567
# we have to pull the merge trees out again, because
1568
# merge_inner has set the ids. - this corner is not yet
1593
# we have to pull the merge trees out again, because
1594
# merge_inner has set the ids. - this corner is not yet
1569
1595
# layered well enough to prevent double handling.
1570
1596
# XXX TODO: Fix the double handling: telling the tree about
1571
1597
# the already known parent data is wasteful.
1814
1840
# as commit already has that ready-to-use [while the format is the
1815
1841
# same, that is].
1817
# this double handles the inventory - unpack and repack -
1843
# this double handles the inventory - unpack and repack -
1818
1844
# but is easier to understand. We can/should put a conditional
1819
1845
# in here based on whether the inventory is in the latest format
1820
1846
# - perhaps we should repack all inventories on a repository
1822
1848
# the fast path is to copy the raw xml from the repository. If the
1823
# xml contains 'revision_id="', then we assume the right
1849
# xml contains 'revision_id="', then we assume the right
1824
1850
# revision_id is set. We must check for this full string, because a
1825
1851
# root node id can legitimately look like 'revision_id' but cannot
1826
1852
# contain a '"'.
1827
1853
xml = self.branch.repository.get_inventory_xml(new_revision)
1828
1854
firstline = xml.split('\n', 1)[0]
1829
if (not 'revision_id="' in firstline or
1855
if (not 'revision_id="' in firstline or
1830
1856
'format="7"' not in firstline):
1831
1857
inv = self.branch.repository.deserialise_inventory(
1832
1858
new_revision, xml)
1839
1865
"""Read the cached basis inventory."""
1840
1866
path = self._basis_inventory_name()
1841
1867
return self._transport.get_bytes(path)
1843
1869
@needs_read_lock
1844
1870
def read_working_inventory(self):
1845
1871
"""Read the working inventory.
1847
1873
:raises errors.InventoryModified: read_working_inventory will fail
1848
1874
when the current in memory inventory has been modified.
1850
# conceptually this should be an implementation detail of the tree.
1876
# conceptually this should be an implementation detail of the tree.
1851
1877
# XXX: Deprecate this.
1852
1878
# ElementTree does its own conversion from UTF-8, so open in
1879
1905
# Recurse directory and add all files
1880
1906
# so we can check if they have changed.
1881
1907
for parent_info, file_infos in\
1882
osutils.walkdirs(self.abspath(directory),
1884
for relpath, basename, kind, lstat, abspath in file_infos:
1908
self.walkdirs(directory):
1909
for relpath, basename, kind, lstat, fileid, kind in file_infos:
1885
1910
# Is it versioned or ignored?
1886
1911
if self.path2id(relpath) or self.is_ignored(relpath):
1887
1912
# Add nested content for deletion.
2052
2076
name = os.path.basename(path)
2055
# fixme, there should be a factory function inv,add_??
2079
# fixme, there should be a factory function inv,add_??
2056
2080
if kind == 'directory':
2057
2081
inv.add(InventoryDirectory(file_id, name, parent))
2058
2082
elif kind == 'file':
2076
2100
def _set_root_id(self, file_id):
2077
2101
"""Set the root id for this tree, in a format specific manner.
2079
:param file_id: The file id to assign to the root. It must not be
2103
:param file_id: The file id to assign to the root. It must not be
2080
2104
present in the current inventory or an error will occur. It must
2081
2105
not be None, but rather a valid file id.
2102
2126
def unlock(self):
2103
2127
"""See Branch.unlock.
2105
2129
WorkingTree locking just uses the Branch locking facilities.
2106
2130
This is current because all working trees have an embedded branch
2107
2131
within them. IF in the future, we were to make branch data shareable
2108
between multiple working trees, i.e. via shared storage, then we
2132
between multiple working trees, i.e. via shared storage, then we
2109
2133
would probably want to lock both the local tree, and the branch.
2111
2135
raise NotImplementedError(self.unlock)
2163
2187
# cant set that until we update the working trees last revision to be
2164
2188
# one from the new branch, because it will just get absorbed by the
2165
2189
# parent de-duplication logic.
2167
2191
# We MUST save it even if an error occurs, because otherwise the users
2168
2192
# local work is unreferenced and will appear to have been lost.
2172
2196
last_rev = self.get_parent_ids()[0]
2343
2367
bzrdir_loc = bisect_left(cur_disk_dir_content,
2344
2368
('.bzr', '.bzr'))
2345
if cur_disk_dir_content[bzrdir_loc][0] == '.bzr':
2369
if (bzrdir_loc < len(cur_disk_dir_content)
2370
and cur_disk_dir_content[bzrdir_loc][0] == '.bzr'):
2346
2371
# we dont yield the contents of, or, .bzr itself.
2347
2372
del cur_disk_dir_content[bzrdir_loc]
2348
2373
if inv_finished:
2439
2464
# FIXME: stash the node in pending
2440
2465
entry = inv[top_id]
2441
for name, child in entry.sorted_children():
2442
dirblock.append((relroot + name, name, child.kind, None,
2443
child.file_id, child.kind
2466
if entry.kind == 'directory':
2467
for name, child in entry.sorted_children():
2468
dirblock.append((relroot + name, name, child.kind, None,
2469
child.file_id, child.kind
2445
2471
yield (currentdir[0], entry.file_id), dirblock
2446
2472
# push the user specified dirs from dirblock
2447
2473
for dir in reversed(dirblock):
2513
2539
self)._get_rules_searcher(default_searcher)
2514
2540
return self._rules_searcher
2542
def get_shelf_manager(self):
2543
"""Return the ShelfManager for this WorkingTree."""
2544
from bzrlib.shelf import ShelfManager
2545
return ShelfManager(self, self._transport)
2517
2548
class WorkingTree2(WorkingTree):
2518
2549
"""This is the Format 2 working tree.
2520
This was the first weave based working tree.
2551
This was the first weave based working tree.
2521
2552
- uses os locks for locking.
2522
2553
- uses the branch last-revision.
2614
2645
except errors.NoSuchFile:
2615
2646
return _mod_conflicts.ConflictList()
2617
if confile.next() != CONFLICT_HEADER_1 + '\n':
2649
if confile.next() != CONFLICT_HEADER_1 + '\n':
2650
raise errors.ConflictFormatError()
2651
except StopIteration:
2618
2652
raise errors.ConflictFormatError()
2619
except StopIteration:
2620
raise errors.ConflictFormatError()
2621
return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
2653
return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
2623
2657
def unlock(self):
2624
2658
# do non-implementation specific cleanup
2649
2683
* a format string,
2650
2684
* an open routine.
2652
Formats are placed in an dict by their format string for reference
2686
Formats are placed in an dict by their format string for reference
2653
2687
during workingtree opening. Its not required that these be instances, they
2654
can be classes themselves with class methods - it simply depends on
2688
can be classes themselves with class methods - it simply depends on
2655
2689
whether state is needed for a given format or not.
2657
2691
Once a format is deprecated, just deprecate the initialize and open
2658
methods on the format class. Do not deprecate the object, as the
2692
methods on the format class. Do not deprecate the object, as the
2659
2693
object will be created every time regardless.
2705
2739
"""Is this format supported?
2707
2741
Supported formats can be initialized and opened.
2708
Unsupported formats may not support initialization or committing or
2742
Unsupported formats may not support initialization or committing or
2709
2743
some other features depending on the reason for not being supported.
2747
def supports_content_filtering(self):
2748
"""True if this format supports content filtering."""
2751
def supports_views(self):
2752
"""True if this format supports stored views."""
2714
2756
def register_format(klass, format):
2715
2757
klass._formats[format.get_format_string()] = format
2735
2777
"""See WorkingTreeFormat.get_format_description()."""
2736
2778
return "Working tree format 2"
2738
def _stub_initialize_remote(self, branch):
2739
"""As a special workaround create critical control files for a remote working tree.
2780
def _stub_initialize_on_transport(self, transport, file_mode):
2781
"""Workaround: create control files for a remote working tree.
2741
2783
This ensures that it can later be updated and dealt with locally,
2742
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2784
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2743
2785
no working tree. (See bug #43064).
2745
2787
sio = StringIO()
2746
2788
inv = Inventory()
2747
2789
xml5.serializer_v5.write_inventory(inv, sio, working=True)
2749
branch._transport.put_file('inventory', sio,
2750
mode=branch.control_files._file_mode)
2751
branch._transport.put_bytes('pending-merges', '',
2752
mode=branch.control_files._file_mode)
2791
transport.put_file('inventory', sio, file_mode)
2792
transport.put_bytes('pending-merges', '', file_mode)
2755
2794
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2756
2795
accelerator_tree=None, hardlink=False):
2843
2882
def _open_control_files(self, a_bzrdir):
2844
2883
transport = a_bzrdir.get_workingtree_transport(None)
2845
return LockableFiles(transport, self._lock_file_name,
2884
return LockableFiles(transport, self._lock_file_name,
2846
2885
self._lock_class)
2848
2887
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2849
2888
accelerator_tree=None, hardlink=False):
2850
2889
"""See WorkingTreeFormat.initialize().
2852
2891
:param revision_id: if supplied, create a working tree at a different
2853
2892
revision than the branch is at.
2854
2893
:param accelerator_tree: A tree which can be used for retrieving file
2942
2981
__default_format = WorkingTreeFormat4()
2943
2982
WorkingTreeFormat.register_format(__default_format)
2983
WorkingTreeFormat.register_format(WorkingTreeFormat5())
2944
2984
WorkingTreeFormat.register_format(WorkingTreeFormat3())
2945
2985
WorkingTreeFormat.set_default_format(__default_format)
2946
2986
# formats which have no format string are not discoverable