29
29
WorkingTree.open(dir).
32
# TODO: Give the workingtree sole responsibility for the working inventory;
33
# remove the variable and references to it from the branch. This may require
34
# updating the commit code so as to update the inventory within the working
35
# copy, and making sure there's only one WorkingTree for any directory on disk.
36
# At the moment they may alias the inventory and have old copies of it in
37
# memory. (Now done? -- mbp 20060309)
33
39
from cStringIO import StringIO
95
101
from bzrlib.filters import filtered_input_file
96
102
from bzrlib.trace import mutter, note
97
103
from bzrlib.transport.local import LocalTransport
104
from bzrlib.progress import DummyProgress, ProgressPhase
98
105
from bzrlib.revision import CURRENT_REVISION
99
106
from bzrlib.rio import RioReader, rio_file, Stanza
100
107
from bzrlib.symbol_versioning import (
106
113
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
107
# TODO: Modifying the conflict objects or their type is currently nearly
108
# impossible as there is no clear relationship between the working tree format
109
# and the conflict list file format.
110
114
CONFLICT_HEADER_1 = "BZR conflict list format 1"
112
116
ERROR_PATH_NOT_FOUND = 3 # WindowsError errno code, equivalent to ENOENT
250
250
self._rules_searcher = None
251
251
self.views = self._make_views()
254
def user_transport(self):
255
return self.bzrdir.user_transport
258
def control_transport(self):
259
return self._transport
261
253
def _detect_case_handling(self):
262
254
wt_trans = self.bzrdir.get_workingtree_transport(None)
371
363
return True, None
373
365
return True, tree
374
t = transport.get_transport(location)
375
iterator = bzrdir.BzrDir.find_bzrdirs(t, evaluate=evaluate,
366
transport = get_transport(location)
367
iterator = bzrdir.BzrDir.find_bzrdirs(transport, evaluate=evaluate,
376
368
list_current=list_current)
377
return [tr for tr in iterator if tr is not None]
369
return [t for t in iterator if t is not None]
379
371
# should be deprecated - this is slow and in any case treating them as a
380
372
# container is (we now know) bad style -- mbp 20070302
465
457
return (file_obj, stat_value)
467
459
def get_file_text(self, file_id, path=None, filtered=True):
468
my_file = self.get_file(file_id, path=path, filtered=filtered)
470
return my_file.read()
460
return self.get_file(file_id, path=path, filtered=filtered).read()
474
462
def get_file_byname(self, filename, filtered=True):
475
463
path = self.abspath(filename)
530
518
# Now we have the parents of this content
531
519
annotator = self.branch.repository.texts.get_annotator()
532
text = self.get_file_text(file_id)
520
text = self.get_file(file_id).read()
533
521
this_key =(file_id, default_revision)
534
522
annotator.add_special_text(this_key, file_parent_keys, text)
535
523
annotations = [(key[-1], line)
921
909
branch.last_revision().
923
911
from bzrlib.merge import Merger, Merge3Merger
924
merger = Merger(self.branch, this_tree=self)
925
# check that there are no local alterations
926
if not force and self.has_changes():
927
raise errors.UncommittedChanges(self)
928
if to_revision is None:
929
to_revision = _mod_revision.ensure_null(branch.last_revision())
930
merger.other_rev_id = to_revision
931
if _mod_revision.is_null(merger.other_rev_id):
932
raise errors.NoCommits(branch)
933
self.branch.fetch(branch, last_revision=merger.other_rev_id)
934
merger.other_basis = merger.other_rev_id
935
merger.other_tree = self.branch.repository.revision_tree(
937
merger.other_branch = branch
938
if from_revision is None:
941
merger.set_base_revision(from_revision, branch)
942
if merger.base_rev_id == merger.other_rev_id:
943
raise errors.PointlessMerge
944
merger.backup_files = False
945
if merge_type is None:
946
merger.merge_type = Merge3Merger
948
merger.merge_type = merge_type
949
merger.set_interesting_files(None)
950
merger.show_base = False
951
merger.reprocess = False
952
conflicts = merger.do_merge()
912
pb = ui.ui_factory.nested_progress_bar()
914
merger = Merger(self.branch, this_tree=self, pb=pb)
915
merger.pp = ProgressPhase("Merge phase", 5, pb)
916
merger.pp.next_phase()
917
# check that there are no local alterations
918
if not force and self.has_changes():
919
raise errors.UncommittedChanges(self)
920
if to_revision is None:
921
to_revision = _mod_revision.ensure_null(branch.last_revision())
922
merger.other_rev_id = to_revision
923
if _mod_revision.is_null(merger.other_rev_id):
924
raise errors.NoCommits(branch)
925
self.branch.fetch(branch, last_revision=merger.other_rev_id)
926
merger.other_basis = merger.other_rev_id
927
merger.other_tree = self.branch.repository.revision_tree(
929
merger.other_branch = branch
930
merger.pp.next_phase()
931
if from_revision is None:
934
merger.set_base_revision(from_revision, branch)
935
if merger.base_rev_id == merger.other_rev_id:
936
raise errors.PointlessMerge
937
merger.backup_files = False
938
if merge_type is None:
939
merger.merge_type = Merge3Merger
941
merger.merge_type = merge_type
942
merger.set_interesting_files(None)
943
merger.show_base = False
944
merger.reprocess = False
945
conflicts = merger.do_merge()
1103
1098
tree_transport = self.bzrdir.root_transport.clone(sub_path)
1104
1099
if tree_transport.base != branch_transport.base:
1105
1100
tree_bzrdir = format.initialize_on_transport(tree_transport)
1106
branch.BranchReferenceFormat().initialize(tree_bzrdir,
1107
target_branch=new_branch)
1101
branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
1109
1103
tree_bzrdir = branch_bzrdir
1110
1104
wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
1148
1142
This does not include files that have been deleted in this
1149
1143
tree. Skips the control directory.
1151
:param include_root: if True, return an entry for the root
1145
:param include_root: if True, do not return an entry for the root
1152
1146
:param from_dir: start from this directory or None for the root
1153
1147
:param recursive: whether to recurse into subdirectories or not
1608
1602
@needs_write_lock
1609
1603
def pull(self, source, overwrite=False, stop_revision=None,
1610
1604
change_reporter=None, possible_transports=None, local=False):
1605
top_pb = ui.ui_factory.nested_progress_bar()
1611
1606
source.lock_read()
1608
pp = ProgressPhase("Pull phase", 2, top_pb)
1613
1610
old_revision_info = self.branch.last_revision_info()
1614
1611
basis_tree = self.basis_tree()
1615
1612
count = self.branch.pull(source, overwrite, stop_revision,
1626
1625
new_basis_tree,
1628
1627
this_tree=self,
1630
1629
change_reporter=change_reporter)
1631
1630
basis_root_id = basis_tree.get_root_id()
1632
1631
new_root_id = new_basis_tree.get_root_id()
1633
1632
if basis_root_id != new_root_id:
1634
1633
self.set_root_id(new_root_id)
1636
1636
basis_tree.unlock()
1637
1637
# TODO - dedup parents list with things merged by pull ?
1638
1638
# reuse the revisiontree we merged against to set the new
1805
1806
raise errors.ObjectNotLocked(self)
1807
1808
def lock_read(self):
1808
"""Lock the tree for reading.
1810
This also locks the branch, and can be unlocked via self.unlock().
1812
:return: A bzrlib.lock.LogicalLockResult.
1809
"""See Branch.lock_read, and WorkingTree.unlock."""
1814
1810
if not self.is_locked():
1815
1811
self._reset_data()
1816
1812
self.branch.lock_read()
1818
self._control_files.lock_read()
1819
return LogicalLockResult(self.unlock)
1814
return self._control_files.lock_read()
1821
1816
self.branch.unlock()
1824
1819
def lock_tree_write(self):
1825
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
1827
:return: A bzrlib.lock.LogicalLockResult.
1820
"""See MutableTree.lock_tree_write, and WorkingTree.unlock."""
1829
1821
if not self.is_locked():
1830
1822
self._reset_data()
1831
1823
self.branch.lock_read()
1833
self._control_files.lock_write()
1834
return LogicalLockResult(self.unlock)
1825
return self._control_files.lock_write()
1836
1827
self.branch.unlock()
1839
1830
def lock_write(self):
1840
"""See MutableTree.lock_write, and WorkingTree.unlock.
1842
:return: A bzrlib.lock.LogicalLockResult.
1831
"""See MutableTree.lock_write, and WorkingTree.unlock."""
1844
1832
if not self.is_locked():
1845
1833
self._reset_data()
1846
1834
self.branch.lock_write()
1848
self._control_files.lock_write()
1849
return LogicalLockResult(self.unlock)
1836
return self._control_files.lock_write()
1851
1838
self.branch.unlock()
1917
1904
# revision_id is set. We must check for this full string, because a
1918
1905
# root node id can legitimately look like 'revision_id' but cannot
1919
1906
# contain a '"'.
1920
xml = self.branch.repository._get_inventory_xml(new_revision)
1907
xml = self.branch.repository.get_inventory_xml(new_revision)
1921
1908
firstline = xml.split('\n', 1)[0]
1922
1909
if (not 'revision_id="' in firstline or
1923
1910
'format="7"' not in firstline):
1977
1964
def recurse_directory_to_add_files(directory):
1978
1965
# Recurse directory and add all files
1979
1966
# so we can check if they have changed.
1980
for parent_info, file_infos in self.walkdirs(directory):
1967
for parent_info, file_infos in\
1968
self.walkdirs(directory):
1981
1969
for relpath, basename, kind, lstat, fileid, kind in file_infos:
1982
1970
# Is it versioned or ignored?
1983
1971
if self.path2id(relpath) or self.is_ignored(relpath):
2018
2006
# ... but not ignored
2019
2007
has_changed_files = True
2021
elif (content_change and (kind[1] is not None) and
2022
osutils.is_inside_any(files, path[1])):
2023
# Versioned and changed, but not deleted, and still
2024
# in one of the dirs to be deleted.
2009
elif content_change and (kind[1] is not None):
2010
# Versioned and changed, but not deleted
2025
2011
has_changed_files = True
2081
2067
@needs_tree_write_lock
2082
2068
def revert(self, filenames=None, old_tree=None, backups=True,
2083
pb=None, report_changes=False):
2069
pb=DummyProgress(), report_changes=False):
2084
2070
from bzrlib.conflicts import resolve
2085
2071
if filenames == []:
2086
2072
filenames = None
2275
2261
# We MUST save it even if an error occurs, because otherwise the users
2276
2262
# local work is unreferenced and will appear to have been lost.
2280
2266
last_rev = self.get_parent_ids()[0]
2281
2267
except IndexError:
2282
2268
last_rev = _mod_revision.NULL_REVISION
2283
2269
if revision is None:
2284
2270
revision = self.branch.last_revision()
2286
old_tip = old_tip or _mod_revision.NULL_REVISION
2288
if not _mod_revision.is_null(old_tip) and old_tip != last_rev:
2289
# the branch we are bound to was updated
2290
# merge those changes in first
2291
base_tree = self.basis_tree()
2292
other_tree = self.branch.repository.revision_tree(old_tip)
2293
nb_conflicts = merge.merge_inner(self.branch, other_tree,
2294
base_tree, this_tree=self,
2295
change_reporter=change_reporter)
2297
self.add_parent_tree((old_tip, other_tree))
2298
trace.note('Rerun update after fixing the conflicts.')
2272
if revision not in self.branch.revision_history():
2273
raise errors.NoSuchRevision(self.branch, revision)
2301
2274
if last_rev != _mod_revision.ensure_null(revision):
2302
# the working tree is up to date with the branch
2303
# we can merge the specified revision from master
2304
to_tree = self.branch.repository.revision_tree(revision)
2305
to_root_id = to_tree.get_root_id()
2275
# merge tree state up to specified revision.
2307
2276
basis = self.basis_tree()
2308
2277
basis.lock_read()
2279
to_tree = self.branch.repository.revision_tree(revision)
2280
to_root_id = to_tree.get_root_id()
2310
2281
if (basis.inventory.root is None
2311
2282
or basis.inventory.root.file_id != to_root_id):
2312
2283
self.set_root_id(to_root_id)
2285
result += merge.merge_inner(
2290
change_reporter=change_reporter)
2291
self.set_last_revision(revision)
2317
# determine the branch point
2318
graph = self.branch.repository.get_graph()
2319
base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
2321
base_tree = self.branch.repository.revision_tree(base_rev_id)
2323
nb_conflicts = merge.merge_inner(self.branch, to_tree, base_tree,
2325
change_reporter=change_reporter)
2326
self.set_last_revision(revision)
2327
2294
# TODO - dedup parents list with things merged by pull ?
2328
2295
# reuse the tree we've updated to to set the basis:
2329
2296
parent_trees = [(revision, to_tree)]
2336
2303
for parent in merges:
2337
2304
parent_trees.append(
2338
2305
(parent, self.branch.repository.revision_tree(parent)))
2339
if not _mod_revision.is_null(old_tip):
2306
if (old_tip is not None and not _mod_revision.is_null(old_tip)):
2340
2307
parent_trees.append(
2341
2308
(old_tip, self.branch.repository.revision_tree(old_tip)))
2342
2309
self.set_parent_trees(parent_trees)
2343
2310
last_rev = parent_trees[0][0]
2312
# the working tree had the same last-revision as the master
2313
# branch did. We may still have pivot local work from the local
2314
# branch into old_tip:
2315
if (old_tip is not None and not _mod_revision.is_null(old_tip)):
2316
self.add_parent_tree_id(old_tip)
2317
if (old_tip is not None and not _mod_revision.is_null(old_tip)
2318
and old_tip != last_rev):
2319
# our last revision was not the prior branch last revision
2320
# and we have converted that last revision to a pending merge.
2321
# base is somewhere between the branch tip now
2322
# and the now pending merge
2324
# Since we just modified the working tree and inventory, flush out
2325
# the current state, before we modify it again.
2326
# TODO: jam 20070214 WorkingTree3 doesn't require this, dirstate
2327
# requires it only because TreeTransform directly munges the
2328
# inventory and calls tree._write_inventory(). Ultimately we
2329
# should be able to remove this extra flush.
2331
graph = self.branch.repository.get_graph()
2332
base_rev_id = graph.find_unique_lca(revision, old_tip)
2333
base_tree = self.branch.repository.revision_tree(base_rev_id)
2334
other_tree = self.branch.repository.revision_tree(old_tip)
2335
result += merge.merge_inner(
2340
change_reporter=change_reporter)
2346
2343
def _write_hashcache_if_dirty(self):
2347
2344
"""Write out the hashcache if it is dirty."""