1
# Copyright (C) 2007-2011 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
"""WorkingTree4 format and implementation.
19
WorkingTree4 provides the dirstate based working tree logic.
21
To get a WorkingTree, call bzrdir.open_workingtree() or
22
WorkingTree.open(dir).
25
from cStringIO import StringIO
29
from bzrlib.lazy_import import lazy_import
30
lazy_import(globals(), """
37
conflicts as _mod_conflicts,
41
filters as _mod_filters,
44
revision as _mod_revision,
52
from bzrlib.decorators import needs_read_lock, needs_write_lock
53
from bzrlib.inventory import Inventory, ROOT_ID, entry_factory
54
from bzrlib.lock import LogicalLockResult
55
from bzrlib.lockable_files import LockableFiles
56
from bzrlib.lockdir import LockDir
57
from bzrlib.mutabletree import needs_tree_write_lock
58
from bzrlib.osutils import (
65
from bzrlib.transport.local import LocalTransport
66
from bzrlib.tree import (
70
from bzrlib.workingtree import (
77
class DirStateWorkingTree(InventoryWorkingTree):
79
_DEFAULT_WORTH_SAVING_LIMIT = 10
81
def __init__(self, basedir,
86
"""Construct a WorkingTree for basedir.
88
If the branch is not supplied, it is opened automatically.
89
If the branch is supplied, it must be the branch for this basedir.
90
(branch.base is not cross checked, because for remote branches that
91
would be meaningless).
93
self._format = _format
95
basedir = safe_unicode(basedir)
96
trace.mutter("opening working tree %r", basedir)
98
self.basedir = realpath(basedir)
99
# if branch is at our basedir and is a format 6 or less
100
# assume all other formats have their own control files.
101
self._control_files = _control_files
102
self._transport = self._control_files._transport
105
# during a read or write lock these objects are set, and are
106
# None the rest of the time.
107
self._dirstate = None
108
self._inventory = None
110
self._setup_directory_is_tree_reference()
111
self._detect_case_handling()
112
self._rules_searcher = None
113
self.views = self._make_views()
114
#--- allow tests to select the dirstate iter_changes implementation
115
self._iter_changes = dirstate._process_entry
117
@needs_tree_write_lock
118
def _add(self, files, ids, kinds):
119
"""See MutableTree._add."""
120
state = self.current_dirstate()
121
for f, file_id, kind in zip(files, ids, kinds):
124
# special case tree root handling.
125
if f == '' and self.path2id(f) == ROOT_ID:
126
state.set_path_id('', generate_ids.gen_file_id(f))
129
file_id = generate_ids.gen_file_id(f)
130
# deliberately add the file with no cached stat or sha1
131
# - on the first access it will be gathered, and we can
132
# always change this once tests are all passing.
133
state.add(f, file_id, kind, None, '')
134
self._make_dirty(reset_inventory=True)
136
def _get_check_refs(self):
137
"""Return the references needed to perform a check of this tree."""
138
return [('trees', self.last_revision())]
140
def _make_dirty(self, reset_inventory):
141
"""Make the tree state dirty.
143
:param reset_inventory: True if the cached inventory should be removed
144
(presuming there is one).
147
if reset_inventory and self._inventory is not None:
148
self._inventory = None
150
@needs_tree_write_lock
151
def add_reference(self, sub_tree):
152
# use standard implementation, which calls back to self._add
154
# So we don't store the reference_revision in the working dirstate,
155
# it's just recorded at the moment of commit.
156
self._add_reference(sub_tree)
158
def break_lock(self):
159
"""Break a lock if one is present from another instance.
161
Uses the ui factory to ask for confirmation if the lock may be from
164
This will probe the repository for its lock as well.
166
# if the dirstate is locked by an active process, reject the break lock
169
if self._dirstate is None:
173
state = self._current_dirstate()
174
if state._lock_token is not None:
175
# we already have it locked. sheese, cant break our own lock.
176
raise errors.LockActive(self.basedir)
179
# try for a write lock - need permission to get one anyhow
182
except errors.LockContention:
183
# oslocks fail when a process is still live: fail.
184
# TODO: get the locked lockdir info and give to the user to
185
# assist in debugging.
186
raise errors.LockActive(self.basedir)
191
self._dirstate = None
192
self._control_files.break_lock()
193
self.branch.break_lock()
195
def _comparison_data(self, entry, path):
196
kind, executable, stat_value = \
197
WorkingTree._comparison_data(self, entry, path)
198
# it looks like a plain directory, but it's really a reference -- see
200
if (self._repo_supports_tree_reference and kind == 'directory'
201
and entry is not None and entry.kind == 'tree-reference'):
202
kind = 'tree-reference'
203
return kind, executable, stat_value
206
def commit(self, message=None, revprops=None, *args, **kwargs):
207
# mark the tree as dirty post commit - commit
208
# can change the current versioned list by doing deletes.
209
result = WorkingTree.commit(self, message, revprops, *args, **kwargs)
210
self._make_dirty(reset_inventory=True)
213
def current_dirstate(self):
214
"""Return the current dirstate object.
216
This is not part of the tree interface and only exposed for ease of
219
:raises errors.NotWriteLocked: when not in a lock.
221
self._must_be_locked()
222
return self._current_dirstate()
224
def _current_dirstate(self):
225
"""Internal function that does not check lock status.
227
This is needed for break_lock which also needs the dirstate.
229
if self._dirstate is not None:
230
return self._dirstate
231
local_path = self.bzrdir.get_workingtree_transport(None
232
).local_abspath('dirstate')
233
self._dirstate = dirstate.DirState.on_file(local_path,
234
self._sha1_provider(), self._worth_saving_limit())
235
return self._dirstate
237
def _sha1_provider(self):
238
"""A function that returns a SHA1Provider suitable for this tree.
240
:return: None if content filtering is not supported by this tree.
241
Otherwise, a SHA1Provider is returned that sha's the canonical
242
form of files, i.e. after read filters are applied.
244
if self.supports_content_filtering():
245
return ContentFilterAwareSHA1Provider(self)
249
def _worth_saving_limit(self):
250
"""How many hash changes are ok before we must save the dirstate.
252
:return: an integer. -1 means never save.
254
config = self.branch.get_config()
255
val = config.get_user_option('bzr.workingtree.worth_saving_limit')
257
val = self._DEFAULT_WORTH_SAVING_LIMIT
261
except ValueError, e:
262
trace.warning('Invalid config value for'
263
' "bzr.workingtree.worth_saving_limit"'
264
' value %r is not an integer.'
266
val = self._DEFAULT_WORTH_SAVING_LIMIT
269
def filter_unversioned_files(self, paths):
270
"""Filter out paths that are versioned.
272
:return: set of paths.
274
# TODO: make a generic multi-bisect routine roughly that should list
275
# the paths, then process one half at a time recursively, and feed the
276
# results of each bisect in further still
277
paths = sorted(paths)
279
state = self.current_dirstate()
280
# TODO we want a paths_to_dirblocks helper I think
282
dirname, basename = os.path.split(path.encode('utf8'))
283
_, _, _, path_is_versioned = state._get_block_entry_index(
284
dirname, basename, 0)
285
if not path_is_versioned:
290
"""Write all cached data to disk."""
291
if self._control_files._lock_mode != 'w':
292
raise errors.NotWriteLocked(self)
293
self.current_dirstate().save()
294
self._inventory = None
297
@needs_tree_write_lock
298
def _gather_kinds(self, files, kinds):
299
"""See MutableTree._gather_kinds."""
300
for pos, f in enumerate(files):
301
if kinds[pos] is None:
302
kinds[pos] = self._kind(f)
304
def _generate_inventory(self):
305
"""Create and set self.inventory from the dirstate object.
307
This is relatively expensive: we have to walk the entire dirstate.
308
Ideally we would not, and can deprecate this function.
310
#: uncomment to trap on inventory requests.
311
# import pdb;pdb.set_trace()
312
state = self.current_dirstate()
313
state._read_dirblocks_if_needed()
314
root_key, current_entry = self._get_entry(path='')
315
current_id = root_key[2]
316
if not (current_entry[0][0] == 'd'): # directory
317
raise AssertionError(current_entry)
318
inv = Inventory(root_id=current_id)
319
# Turn some things into local variables
320
minikind_to_kind = dirstate.DirState._minikind_to_kind
321
factory = entry_factory
322
utf8_decode = cache_utf8._utf8_decode
324
# we could do this straight out of the dirstate; it might be fast
325
# and should be profiled - RBC 20070216
326
parent_ies = {'' : inv.root}
327
for block in state._dirblocks[1:]: # skip the root
330
parent_ie = parent_ies[dirname]
332
# all the paths in this block are not versioned in this tree
334
for key, entry in block[1]:
335
minikind, link_or_sha1, size, executable, stat = entry[0]
336
if minikind in ('a', 'r'): # absent, relocated
337
# a parent tree only entry
340
name_unicode = utf8_decode(name)[0]
342
kind = minikind_to_kind[minikind]
343
inv_entry = factory[kind](file_id, name_unicode,
346
# This is only needed on win32, where this is the only way
347
# we know the executable bit.
348
inv_entry.executable = executable
349
# not strictly needed: working tree
350
#inv_entry.text_size = size
351
#inv_entry.text_sha1 = sha1
352
elif kind == 'directory':
353
# add this entry to the parent map.
354
parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
355
elif kind == 'tree-reference':
356
if not self._repo_supports_tree_reference:
357
raise errors.UnsupportedOperation(
358
self._generate_inventory,
359
self.branch.repository)
360
inv_entry.reference_revision = link_or_sha1 or None
361
elif kind != 'symlink':
362
raise AssertionError("unknown kind %r" % kind)
363
# These checks cost us around 40ms on a 55k entry tree
364
if file_id in inv_byid:
365
raise AssertionError('file_id %s already in'
366
' inventory as %s' % (file_id, inv_byid[file_id]))
367
if name_unicode in parent_ie.children:
368
raise AssertionError('name %r already in parent'
370
inv_byid[file_id] = inv_entry
371
parent_ie.children[name_unicode] = inv_entry
372
self._inventory = inv
374
def _get_entry(self, file_id=None, path=None):
375
"""Get the dirstate row for file_id or path.
377
If either file_id or path is supplied, it is used as the key to lookup.
378
If both are supplied, the fastest lookup is used, and an error is
379
raised if they do not both point at the same row.
381
:param file_id: An optional unicode file_id to be looked up.
382
:param path: An optional unicode path to be looked up.
383
:return: The dirstate row tuple for path/file_id, or (None, None)
385
if file_id is None and path is None:
386
raise errors.BzrError('must supply file_id or path')
387
state = self.current_dirstate()
389
path = path.encode('utf8')
390
return state._get_entry(0, fileid_utf8=file_id, path_utf8=path)
392
def get_file_sha1(self, file_id, path=None, stat_value=None):
393
# check file id is valid unconditionally.
394
entry = self._get_entry(file_id=file_id, path=path)
396
raise errors.NoSuchId(self, file_id)
398
path = pathjoin(entry[0][0], entry[0][1]).decode('utf8')
400
file_abspath = self.abspath(path)
401
state = self.current_dirstate()
402
if stat_value is None:
404
stat_value = osutils.lstat(file_abspath)
406
if e.errno == errno.ENOENT:
410
link_or_sha1 = dirstate.update_entry(state, entry, file_abspath,
411
stat_value=stat_value)
412
if entry[1][0][0] == 'f':
413
if link_or_sha1 is None:
414
file_obj, statvalue = self.get_file_with_stat(file_id, path)
416
sha1 = osutils.sha_file(file_obj)
419
self._observed_sha1(file_id, path, (sha1, statvalue))
425
def _get_inventory(self):
426
"""Get the inventory for the tree. This is only valid within a lock."""
427
if 'evil' in debug.debug_flags:
428
trace.mutter_callsite(2,
429
"accessing .inventory forces a size of tree translation.")
430
if self._inventory is not None:
431
return self._inventory
432
self._must_be_locked()
433
self._generate_inventory()
434
return self._inventory
436
inventory = property(_get_inventory,
437
doc="Inventory of this Tree")
440
def get_parent_ids(self):
441
"""See Tree.get_parent_ids.
443
This implementation requests the ids list from the dirstate file.
445
return self.current_dirstate().get_parent_ids()
447
def get_reference_revision(self, file_id, path=None):
448
# referenced tree's revision is whatever's currently there
449
return self.get_nested_tree(file_id, path).last_revision()
451
def get_nested_tree(self, file_id, path=None):
453
path = self.id2path(file_id)
454
# else: check file_id is at path?
455
return WorkingTree.open(self.abspath(path))
458
def get_root_id(self):
459
"""Return the id of this trees root"""
460
return self._get_entry(path='')[0][2]
462
def has_id(self, file_id):
463
state = self.current_dirstate()
464
row, parents = self._get_entry(file_id=file_id)
467
return osutils.lexists(pathjoin(
468
self.basedir, row[0].decode('utf8'), row[1].decode('utf8')))
470
def has_or_had_id(self, file_id):
471
state = self.current_dirstate()
472
row, parents = self._get_entry(file_id=file_id)
473
return row is not None
476
def id2path(self, file_id):
477
"Convert a file-id to a path."
478
state = self.current_dirstate()
479
entry = self._get_entry(file_id=file_id)
480
if entry == (None, None):
481
raise errors.NoSuchId(tree=self, file_id=file_id)
482
path_utf8 = osutils.pathjoin(entry[0][0], entry[0][1])
483
return path_utf8.decode('utf8')
485
def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
486
entry = self._get_entry(path=path)
487
if entry == (None, None):
488
return False # Missing entries are not executable
489
return entry[1][0][3] # Executable?
491
if not osutils.supports_executable():
492
def is_executable(self, file_id, path=None):
493
"""Test if a file is executable or not.
495
Note: The caller is expected to take a read-lock before calling this.
497
entry = self._get_entry(file_id=file_id, path=path)
498
if entry == (None, None):
500
return entry[1][0][3]
502
_is_executable_from_path_and_stat = \
503
_is_executable_from_path_and_stat_from_basis
505
def is_executable(self, file_id, path=None):
506
"""Test if a file is executable or not.
508
Note: The caller is expected to take a read-lock before calling this.
510
self._must_be_locked()
512
path = self.id2path(file_id)
513
mode = osutils.lstat(self.abspath(path)).st_mode
514
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
516
def all_file_ids(self):
517
"""See Tree.iter_all_file_ids"""
518
self._must_be_locked()
520
for key, tree_details in self.current_dirstate()._iter_entries():
521
if tree_details[0][0] in ('a', 'r'): # relocated
528
"""Iterate through file_ids for this tree.
530
file_ids are in a WorkingTree if they are in the working inventory
531
and the working file exists.
534
for key, tree_details in self.current_dirstate()._iter_entries():
535
if tree_details[0][0] in ('a', 'r'): # absent, relocated
536
# not relevant to the working tree
538
path = pathjoin(self.basedir, key[0].decode('utf8'), key[1].decode('utf8'))
539
if osutils.lexists(path):
540
result.append(key[2])
543
def iter_references(self):
544
if not self._repo_supports_tree_reference:
545
# When the repo doesn't support references, we will have nothing to
548
for key, tree_details in self.current_dirstate()._iter_entries():
549
if tree_details[0][0] in ('a', 'r'): # absent, relocated
550
# not relevant to the working tree
553
# the root is not a reference.
555
relpath = pathjoin(key[0].decode('utf8'), key[1].decode('utf8'))
557
if self._kind(relpath) == 'tree-reference':
558
yield relpath, key[2]
559
except errors.NoSuchFile:
560
# path is missing on disk.
563
def _observed_sha1(self, file_id, path, (sha1, statvalue)):
564
"""See MutableTree._observed_sha1."""
565
state = self.current_dirstate()
566
entry = self._get_entry(file_id=file_id, path=path)
567
state._observed_sha1(entry, sha1, statvalue)
569
def kind(self, file_id):
570
"""Return the kind of a file.
572
This is always the actual kind that's on disk, regardless of what it
575
Note: The caller is expected to take a read-lock before calling this.
577
relpath = self.id2path(file_id)
579
raise AssertionError(
580
"path for id {%s} is None!" % file_id)
581
return self._kind(relpath)
583
def _kind(self, relpath):
584
abspath = self.abspath(relpath)
585
kind = file_kind(abspath)
586
if (self._repo_supports_tree_reference and kind == 'directory'):
587
entry = self._get_entry(path=relpath)
588
if entry[1] is not None:
589
if entry[1][0][0] == 't':
590
kind = 'tree-reference'
594
def _last_revision(self):
595
"""See Mutable.last_revision."""
596
parent_ids = self.current_dirstate().get_parent_ids()
600
return _mod_revision.NULL_REVISION
603
"""See Branch.lock_read, and WorkingTree.unlock.
605
:return: A bzrlib.lock.LogicalLockResult.
607
self.branch.lock_read()
609
self._control_files.lock_read()
611
state = self.current_dirstate()
612
if not state._lock_token:
614
# set our support for tree references from the repository in
616
self._repo_supports_tree_reference = getattr(
617
self.branch.repository._format, "supports_tree_reference",
620
self._control_files.unlock()
625
return LogicalLockResult(self.unlock)
627
def _lock_self_write(self):
628
"""This should be called after the branch is locked."""
630
self._control_files.lock_write()
632
state = self.current_dirstate()
633
if not state._lock_token:
635
# set our support for tree references from the repository in
637
self._repo_supports_tree_reference = getattr(
638
self.branch.repository._format, "supports_tree_reference",
641
self._control_files.unlock()
646
return LogicalLockResult(self.unlock)
648
def lock_tree_write(self):
649
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
651
:return: A bzrlib.lock.LogicalLockResult.
653
self.branch.lock_read()
654
return self._lock_self_write()
656
def lock_write(self):
657
"""See MutableTree.lock_write, and WorkingTree.unlock.
659
:return: A bzrlib.lock.LogicalLockResult.
661
self.branch.lock_write()
662
return self._lock_self_write()
664
@needs_tree_write_lock
665
def move(self, from_paths, to_dir, after=False):
666
"""See WorkingTree.move()."""
670
state = self.current_dirstate()
671
if isinstance(from_paths, basestring):
673
to_dir_utf8 = to_dir.encode('utf8')
674
to_entry_dirname, to_basename = os.path.split(to_dir_utf8)
675
id_index = state._get_id_index()
676
# check destination directory
677
# get the details for it
678
to_entry_block_index, to_entry_entry_index, dir_present, entry_present = \
679
state._get_block_entry_index(to_entry_dirname, to_basename, 0)
680
if not entry_present:
681
raise errors.BzrMoveFailedError('', to_dir,
682
errors.NotVersionedError(to_dir))
683
to_entry = state._dirblocks[to_entry_block_index][1][to_entry_entry_index]
684
# get a handle on the block itself.
685
to_block_index = state._ensure_block(
686
to_entry_block_index, to_entry_entry_index, to_dir_utf8)
687
to_block = state._dirblocks[to_block_index]
688
to_abs = self.abspath(to_dir)
689
if not isdir(to_abs):
690
raise errors.BzrMoveFailedError('',to_dir,
691
errors.NotADirectory(to_abs))
693
if to_entry[1][0][0] != 'd':
694
raise errors.BzrMoveFailedError('',to_dir,
695
errors.NotADirectory(to_abs))
697
if self._inventory is not None:
698
update_inventory = True
700
to_dir_id = to_entry[0][2]
701
to_dir_ie = inv[to_dir_id]
703
update_inventory = False
706
def move_one(old_entry, from_path_utf8, minikind, executable,
707
fingerprint, packed_stat, size,
708
to_block, to_key, to_path_utf8):
709
state._make_absent(old_entry)
710
from_key = old_entry[0]
712
lambda:state.update_minimal(from_key,
714
executable=executable,
715
fingerprint=fingerprint,
716
packed_stat=packed_stat,
718
path_utf8=from_path_utf8))
719
state.update_minimal(to_key,
721
executable=executable,
722
fingerprint=fingerprint,
723
packed_stat=packed_stat,
725
path_utf8=to_path_utf8)
726
added_entry_index, _ = state._find_entry_index(to_key, to_block[1])
727
new_entry = to_block[1][added_entry_index]
728
rollbacks.append(lambda:state._make_absent(new_entry))
730
for from_rel in from_paths:
731
# from_rel is 'pathinroot/foo/bar'
732
from_rel_utf8 = from_rel.encode('utf8')
733
from_dirname, from_tail = osutils.split(from_rel)
734
from_dirname, from_tail_utf8 = osutils.split(from_rel_utf8)
735
from_entry = self._get_entry(path=from_rel)
736
if from_entry == (None, None):
737
raise errors.BzrMoveFailedError(from_rel,to_dir,
738
errors.NotVersionedError(path=from_rel))
740
from_id = from_entry[0][2]
741
to_rel = pathjoin(to_dir, from_tail)
742
to_rel_utf8 = pathjoin(to_dir_utf8, from_tail_utf8)
743
item_to_entry = self._get_entry(path=to_rel)
744
if item_to_entry != (None, None):
745
raise errors.BzrMoveFailedError(from_rel, to_rel,
746
"Target is already versioned.")
748
if from_rel == to_rel:
749
raise errors.BzrMoveFailedError(from_rel, to_rel,
750
"Source and target are identical.")
752
from_missing = not self.has_filename(from_rel)
753
to_missing = not self.has_filename(to_rel)
760
raise errors.BzrMoveFailedError(from_rel, to_rel,
761
errors.NoSuchFile(path=to_rel,
762
extra="New file has not been created yet"))
764
# neither path exists
765
raise errors.BzrRenameFailedError(from_rel, to_rel,
766
errors.PathsDoNotExist(paths=(from_rel, to_rel)))
768
if from_missing: # implicitly just update our path mapping
771
raise errors.RenameFailedFilesExist(from_rel, to_rel)
774
def rollback_rename():
775
"""A single rename has failed, roll it back."""
776
# roll back everything, even if we encounter trouble doing one
779
# TODO: at least log the other exceptions rather than just
780
# losing them mbp 20070307
782
for rollback in reversed(rollbacks):
786
exc_info = sys.exc_info()
788
raise exc_info[0], exc_info[1], exc_info[2]
790
# perform the disk move first - its the most likely failure point.
792
from_rel_abs = self.abspath(from_rel)
793
to_rel_abs = self.abspath(to_rel)
795
osutils.rename(from_rel_abs, to_rel_abs)
797
raise errors.BzrMoveFailedError(from_rel, to_rel, e[1])
798
rollbacks.append(lambda: osutils.rename(to_rel_abs, from_rel_abs))
800
# perform the rename in the inventory next if needed: its easy
804
from_entry = inv[from_id]
805
current_parent = from_entry.parent_id
806
inv.rename(from_id, to_dir_id, from_tail)
808
lambda: inv.rename(from_id, current_parent, from_tail))
809
# finally do the rename in the dirstate, which is a little
810
# tricky to rollback, but least likely to need it.
811
old_block_index, old_entry_index, dir_present, file_present = \
812
state._get_block_entry_index(from_dirname, from_tail_utf8, 0)
813
old_block = state._dirblocks[old_block_index][1]
814
old_entry = old_block[old_entry_index]
815
from_key, old_entry_details = old_entry
816
cur_details = old_entry_details[0]
818
to_key = ((to_block[0],) + from_key[1:3])
819
minikind = cur_details[0]
820
move_one(old_entry, from_path_utf8=from_rel_utf8,
822
executable=cur_details[3],
823
fingerprint=cur_details[1],
824
packed_stat=cur_details[4],
828
to_path_utf8=to_rel_utf8)
831
def update_dirblock(from_dir, to_key, to_dir_utf8):
832
"""Recursively update all entries in this dirblock."""
834
raise AssertionError("renaming root not supported")
835
from_key = (from_dir, '')
836
from_block_idx, present = \
837
state._find_block_index_from_key(from_key)
839
# This is the old record, if it isn't present, then
840
# there is theoretically nothing to update.
841
# (Unless it isn't present because of lazy loading,
842
# but we don't do that yet)
844
from_block = state._dirblocks[from_block_idx]
845
to_block_index, to_entry_index, _, _ = \
846
state._get_block_entry_index(to_key[0], to_key[1], 0)
847
to_block_index = state._ensure_block(
848
to_block_index, to_entry_index, to_dir_utf8)
849
to_block = state._dirblocks[to_block_index]
851
# Grab a copy since move_one may update the list.
852
for entry in from_block[1][:]:
853
if not (entry[0][0] == from_dir):
854
raise AssertionError()
855
cur_details = entry[1][0]
856
to_key = (to_dir_utf8, entry[0][1], entry[0][2])
857
from_path_utf8 = osutils.pathjoin(entry[0][0], entry[0][1])
858
to_path_utf8 = osutils.pathjoin(to_dir_utf8, entry[0][1])
859
minikind = cur_details[0]
861
# Deleted children of a renamed directory
862
# Do not need to be updated.
863
# Children that have been renamed out of this
864
# directory should also not be updated
866
move_one(entry, from_path_utf8=from_path_utf8,
868
executable=cur_details[3],
869
fingerprint=cur_details[1],
870
packed_stat=cur_details[4],
874
to_path_utf8=to_path_utf8)
876
# We need to move all the children of this
878
update_dirblock(from_path_utf8, to_key,
880
update_dirblock(from_rel_utf8, to_key, to_rel_utf8)
884
result.append((from_rel, to_rel))
885
state._mark_modified()
886
self._make_dirty(reset_inventory=False)
890
def _must_be_locked(self):
891
if not self._control_files._lock_count:
892
raise errors.ObjectNotLocked(self)
895
"""Initialize the state in this tree to be a new tree."""
899
def path2id(self, path):
900
"""Return the id for path in this tree."""
901
path = path.strip('/')
902
entry = self._get_entry(path=path)
903
if entry == (None, None):
907
def paths2ids(self, paths, trees=[], require_versioned=True):
908
"""See Tree.paths2ids().
910
This specialisation fast-paths the case where all the trees are in the
915
parents = self.get_parent_ids()
917
if not (isinstance(tree, DirStateRevisionTree) and tree._revision_id in
919
return super(DirStateWorkingTree, self).paths2ids(paths,
920
trees, require_versioned)
921
search_indexes = [0] + [1 + parents.index(tree._revision_id) for tree in trees]
922
# -- make all paths utf8 --
925
paths_utf8.add(path.encode('utf8'))
927
# -- paths is now a utf8 path set --
928
# -- get the state object and prepare it.
929
state = self.current_dirstate()
930
if False and (state._dirblock_state == dirstate.DirState.NOT_IN_MEMORY
931
and '' not in paths):
932
paths2ids = self._paths2ids_using_bisect
934
paths2ids = self._paths2ids_in_memory
935
return paths2ids(paths, search_indexes,
936
require_versioned=require_versioned)
938
def _paths2ids_in_memory(self, paths, search_indexes,
939
require_versioned=True):
940
state = self.current_dirstate()
941
state._read_dirblocks_if_needed()
942
def _entries_for_path(path):
943
"""Return a list with all the entries that match path for all ids.
945
dirname, basename = os.path.split(path)
946
key = (dirname, basename, '')
947
block_index, present = state._find_block_index_from_key(key)
949
# the block which should contain path is absent.
952
block = state._dirblocks[block_index][1]
953
entry_index, _ = state._find_entry_index(key, block)
954
# we may need to look at multiple entries at this path: walk while the paths match.
955
while (entry_index < len(block) and
956
block[entry_index][0][0:2] == key[0:2]):
957
result.append(block[entry_index])
960
if require_versioned:
961
# -- check all supplied paths are versioned in a search tree. --
964
path_entries = _entries_for_path(path)
966
# this specified path is not present at all: error
967
all_versioned = False
969
found_versioned = False
970
# for each id at this path
971
for entry in path_entries:
973
for index in search_indexes:
974
if entry[1][index][0] != 'a': # absent
975
found_versioned = True
976
# all good: found a versioned cell
978
if not found_versioned:
979
# none of the indexes was not 'absent' at all ids for this
981
all_versioned = False
983
if not all_versioned:
984
raise errors.PathsNotVersionedError(paths)
985
# -- remove redundancy in supplied paths to prevent over-scanning --
986
search_paths = osutils.minimum_path_selection(paths)
988
# for all search_indexs in each path at or under each element of
989
# search_paths, if the detail is relocated: add the id, and add the
990
# relocated path as one to search if its not searched already. If the
991
# detail is not relocated, add the id.
992
searched_paths = set()
994
def _process_entry(entry):
995
"""Look at search_indexes within entry.
997
If a specific tree's details are relocated, add the relocation
998
target to search_paths if not searched already. If it is absent, do
999
nothing. Otherwise add the id to found_ids.
1001
for index in search_indexes:
1002
if entry[1][index][0] == 'r': # relocated
1003
if not osutils.is_inside_any(searched_paths, entry[1][index][1]):
1004
search_paths.add(entry[1][index][1])
1005
elif entry[1][index][0] != 'a': # absent
1006
found_ids.add(entry[0][2])
1008
current_root = search_paths.pop()
1009
searched_paths.add(current_root)
1010
# process the entries for this containing directory: the rest will be
1011
# found by their parents recursively.
1012
root_entries = _entries_for_path(current_root)
1013
if not root_entries:
1014
# this specified path is not present at all, skip it.
1016
for entry in root_entries:
1017
_process_entry(entry)
1018
initial_key = (current_root, '', '')
1019
block_index, _ = state._find_block_index_from_key(initial_key)
1020
while (block_index < len(state._dirblocks) and
1021
osutils.is_inside(current_root, state._dirblocks[block_index][0])):
1022
for entry in state._dirblocks[block_index][1]:
1023
_process_entry(entry)
1027
def _paths2ids_using_bisect(self, paths, search_indexes,
1028
require_versioned=True):
1029
state = self.current_dirstate()
1032
split_paths = sorted(osutils.split(p) for p in paths)
1033
found = state._bisect_recursive(split_paths)
1035
if require_versioned:
1036
found_dir_names = set(dir_name_id[:2] for dir_name_id in found)
1037
for dir_name in split_paths:
1038
if dir_name not in found_dir_names:
1039
raise errors.PathsNotVersionedError(paths)
1041
for dir_name_id, trees_info in found.iteritems():
1042
for index in search_indexes:
1043
if trees_info[index][0] not in ('r', 'a'):
1044
found_ids.add(dir_name_id[2])
1047
def read_working_inventory(self):
1048
"""Read the working inventory.
1050
This is a meaningless operation for dirstate, but we obey it anyhow.
1052
return self.inventory
1055
def revision_tree(self, revision_id):
1056
"""See Tree.revision_tree.
1058
WorkingTree4 supplies revision_trees for any basis tree.
1060
dirstate = self.current_dirstate()
1061
parent_ids = dirstate.get_parent_ids()
1062
if revision_id not in parent_ids:
1063
raise errors.NoSuchRevisionInTree(self, revision_id)
1064
if revision_id in dirstate.get_ghosts():
1065
raise errors.NoSuchRevisionInTree(self, revision_id)
1066
return DirStateRevisionTree(dirstate, revision_id,
1067
self.branch.repository)
1069
@needs_tree_write_lock
1070
def set_last_revision(self, new_revision):
1071
"""Change the last revision in the working tree."""
1072
parents = self.get_parent_ids()
1073
if new_revision in (_mod_revision.NULL_REVISION, None):
1074
if len(parents) >= 2:
1075
raise AssertionError(
1076
"setting the last parent to none with a pending merge is "
1078
self.set_parent_ids([])
1080
self.set_parent_ids([new_revision] + parents[1:],
1081
allow_leftmost_as_ghost=True)
1083
@needs_tree_write_lock
1084
def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
1085
"""Set the parent ids to revision_ids.
1087
See also set_parent_trees. This api will try to retrieve the tree data
1088
for each element of revision_ids from the trees repository. If you have
1089
tree data already available, it is more efficient to use
1090
set_parent_trees rather than set_parent_ids. set_parent_ids is however
1091
an easier API to use.
1093
:param revision_ids: The revision_ids to set as the parent ids of this
1094
working tree. Any of these may be ghosts.
1097
for revision_id in revision_ids:
1099
revtree = self.branch.repository.revision_tree(revision_id)
1100
# TODO: jam 20070213 KnitVersionedFile raises
1101
# RevisionNotPresent rather than NoSuchRevision if a
1102
# given revision_id is not present. Should Repository be
1103
# catching it and re-raising NoSuchRevision?
1104
except (errors.NoSuchRevision, errors.RevisionNotPresent):
1106
trees.append((revision_id, revtree))
1107
self.set_parent_trees(trees,
1108
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
1110
@needs_tree_write_lock
1111
def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
1112
"""Set the parents of the working tree.
1114
:param parents_list: A list of (revision_id, tree) tuples.
1115
If tree is None, then that element is treated as an unreachable
1116
parent tree - i.e. a ghost.
1118
dirstate = self.current_dirstate()
1119
if len(parents_list) > 0:
1120
if not allow_leftmost_as_ghost and parents_list[0][1] is None:
1121
raise errors.GhostRevisionUnusableHere(parents_list[0][0])
1125
parent_ids = [rev_id for rev_id, tree in parents_list]
1126
graph = self.branch.repository.get_graph()
1127
heads = graph.heads(parent_ids)
1128
accepted_revisions = set()
1130
# convert absent trees to the null tree, which we convert back to
1131
# missing on access.
1132
for rev_id, tree in parents_list:
1133
if len(accepted_revisions) > 0:
1134
# we always accept the first tree
1135
if rev_id in accepted_revisions or rev_id not in heads:
1136
# We have already included either this tree, or its
1137
# descendent, so we skip it.
1139
_mod_revision.check_not_reserved_id(rev_id)
1140
if tree is not None:
1141
real_trees.append((rev_id, tree))
1143
real_trees.append((rev_id,
1144
self.branch.repository.revision_tree(
1145
_mod_revision.NULL_REVISION)))
1146
ghosts.append(rev_id)
1147
accepted_revisions.add(rev_id)
1149
if (len(real_trees) == 1
1151
and self.branch.repository._format.fast_deltas
1152
and isinstance(real_trees[0][1],
1153
revisiontree.InventoryRevisionTree)
1154
and self.get_parent_ids()):
1155
rev_id, rev_tree = real_trees[0]
1156
basis_id = self.get_parent_ids()[0]
1157
# There are times when basis_tree won't be in
1158
# self.branch.repository, (switch, for example)
1160
basis_tree = self.branch.repository.revision_tree(basis_id)
1161
except errors.NoSuchRevision:
1162
# Fall back to the set_parent_trees(), since we can't use
1163
# _make_delta if we can't get the RevisionTree
1166
delta = rev_tree.inventory._make_delta(basis_tree.inventory)
1167
dirstate.update_basis_by_delta(delta, rev_id)
1170
dirstate.set_parent_trees(real_trees, ghosts=ghosts)
1171
self._make_dirty(reset_inventory=False)
1173
def _set_root_id(self, file_id):
1174
"""See WorkingTree.set_root_id."""
1175
state = self.current_dirstate()
1176
state.set_path_id('', file_id)
1177
if state._dirblock_state == dirstate.DirState.IN_MEMORY_MODIFIED:
1178
self._make_dirty(reset_inventory=True)
1180
def _sha_from_stat(self, path, stat_result):
1181
"""Get a sha digest from the tree's stat cache.
1183
The default implementation assumes no stat cache is present.
1185
:param path: The path.
1186
:param stat_result: The stat result being looked up.
1188
return self.current_dirstate().sha1_from_stat(path, stat_result)
1191
def supports_tree_reference(self):
1192
return self._repo_supports_tree_reference
1195
"""Unlock in format 4 trees needs to write the entire dirstate."""
1196
if self._control_files._lock_count == 1:
1197
# do non-implementation specific cleanup
1200
# eventually we should do signature checking during read locks for
1202
if self._control_files._lock_mode == 'w':
1205
if self._dirstate is not None:
1206
# This is a no-op if there are no modifications.
1207
self._dirstate.save()
1208
self._dirstate.unlock()
1209
# TODO: jam 20070301 We shouldn't have to wipe the dirstate at this
1210
# point. Instead, it could check if the header has been
1211
# modified when it is locked, and if not, it can hang on to
1212
# the data it has in memory.
1213
self._dirstate = None
1214
self._inventory = None
1215
# reverse order of locking.
1217
return self._control_files.unlock()
1219
self.branch.unlock()
1221
@needs_tree_write_lock
1222
def unversion(self, file_ids):
1223
"""Remove the file ids in file_ids from the current versioned set.
1225
When a file_id is unversioned, all of its children are automatically
1228
:param file_ids: The file ids to stop versioning.
1229
:raises: NoSuchId if any fileid is not currently versioned.
1233
state = self.current_dirstate()
1234
state._read_dirblocks_if_needed()
1235
ids_to_unversion = set(file_ids)
1236
paths_to_unversion = set()
1238
# check if the root is to be unversioned, if so, assert for now.
1239
# walk the state marking unversioned things as absent.
1240
# if there are any un-unversioned ids at the end, raise
1241
for key, details in state._dirblocks[0][1]:
1242
if (details[0][0] not in ('a', 'r') and # absent or relocated
1243
key[2] in ids_to_unversion):
1244
# I haven't written the code to unversion / yet - it should be
1246
raise errors.BzrError('Unversioning the / is not currently supported')
1248
while block_index < len(state._dirblocks):
1249
# process one directory at a time.
1250
block = state._dirblocks[block_index]
1251
# first check: is the path one to remove - it or its children
1252
delete_block = False
1253
for path in paths_to_unversion:
1254
if (block[0].startswith(path) and
1255
(len(block[0]) == len(path) or
1256
block[0][len(path)] == '/')):
1257
# this entire block should be deleted - its the block for a
1258
# path to unversion; or the child of one
1261
# TODO: trim paths_to_unversion as we pass by paths
1263
# this block is to be deleted: process it.
1264
# TODO: we can special case the no-parents case and
1265
# just forget the whole block.
1267
while entry_index < len(block[1]):
1268
entry = block[1][entry_index]
1269
if entry[1][0][0] in 'ar':
1270
# don't remove absent or renamed entries
1273
# Mark this file id as having been removed
1274
ids_to_unversion.discard(entry[0][2])
1275
if not state._make_absent(entry):
1276
# The block has not shrunk.
1278
# go to the next block. (At the moment we dont delete empty
1283
while entry_index < len(block[1]):
1284
entry = block[1][entry_index]
1285
if (entry[1][0][0] in ('a', 'r') or # absent, relocated
1286
# ^ some parent row.
1287
entry[0][2] not in ids_to_unversion):
1288
# ^ not an id to unversion
1291
if entry[1][0][0] == 'd':
1292
paths_to_unversion.add(pathjoin(entry[0][0], entry[0][1]))
1293
if not state._make_absent(entry):
1295
# we have unversioned this id
1296
ids_to_unversion.remove(entry[0][2])
1298
if ids_to_unversion:
1299
raise errors.NoSuchId(self, iter(ids_to_unversion).next())
1300
self._make_dirty(reset_inventory=False)
1301
# have to change the legacy inventory too.
1302
if self._inventory is not None:
1303
for file_id in file_ids:
1304
if self._inventory.has_id(file_id):
1305
self._inventory.remove_recursive_id(file_id)
1307
@needs_tree_write_lock
1308
def rename_one(self, from_rel, to_rel, after=False):
1309
"""See WorkingTree.rename_one"""
1311
super(DirStateWorkingTree, self).rename_one(from_rel, to_rel, after)
1313
@needs_tree_write_lock
1314
def apply_inventory_delta(self, changes):
1315
"""See MutableTree.apply_inventory_delta"""
1316
state = self.current_dirstate()
1317
state.update_by_delta(changes)
1318
self._make_dirty(reset_inventory=True)
1320
def update_basis_by_delta(self, new_revid, delta):
1321
"""See MutableTree.update_basis_by_delta."""
1322
if self.last_revision() == new_revid:
1323
raise AssertionError()
1324
self.current_dirstate().update_basis_by_delta(delta, new_revid)
1327
def _validate(self):
1328
self._dirstate._validate()
1330
@needs_tree_write_lock
1331
def _write_inventory(self, inv):
1332
"""Write inventory as the current inventory."""
1334
raise AssertionError("attempting to write an inventory when the "
1335
"dirstate is dirty will lose pending changes")
1336
had_inventory = self._inventory is not None
1337
# Setting self._inventory = None forces the dirstate to regenerate the
1338
# working inventory. We do this because self.inventory may be inv, or
1339
# may have been modified, and either case would prevent a clean delta
1341
self._inventory = None
1343
delta = inv._make_delta(self.inventory)
1345
self.apply_inventory_delta(delta)
1347
self._inventory = inv
1350
@needs_tree_write_lock
1351
def reset_state(self, revision_ids=None):
1352
"""Reset the state of the working tree.
1354
This does a hard-reset to a last-known-good state. This is a way to
1355
fix if something got corrupted (like the .bzr/checkout/dirstate file)
1357
if revision_ids is None:
1358
revision_ids = self.get_parent_ids()
1359
if not revision_ids:
1360
base_tree = self.branch.repository.revision_tree(
1361
_mod_revision.NULL_REVISION)
1364
trees = zip(revision_ids,
1365
self.branch.repository.revision_trees(revision_ids))
1366
base_tree = trees[0][1]
1367
state = self.current_dirstate()
1368
# We don't support ghosts yet
1369
state.set_state_from_scratch(base_tree.inventory, trees, [])
1372
class ContentFilterAwareSHA1Provider(dirstate.SHA1Provider):
1374
def __init__(self, tree):
1377
def sha1(self, abspath):
1378
"""See dirstate.SHA1Provider.sha1()."""
1379
filters = self.tree._content_filter_stack(
1380
self.tree.relpath(osutils.safe_unicode(abspath)))
1381
return _mod_filters.internal_size_sha_file_byname(abspath, filters)[1]
1383
def stat_and_sha1(self, abspath):
1384
"""See dirstate.SHA1Provider.stat_and_sha1()."""
1385
filters = self.tree._content_filter_stack(
1386
self.tree.relpath(osutils.safe_unicode(abspath)))
1387
file_obj = file(abspath, 'rb', 65000)
1389
statvalue = os.fstat(file_obj.fileno())
1391
file_obj = _mod_filters.filtered_input_file(file_obj, filters)
1392
sha1 = osutils.size_sha_file(file_obj)[1]
1395
return statvalue, sha1
1398
class ContentFilteringDirStateWorkingTree(DirStateWorkingTree):
1399
"""Dirstate working tree that supports content filtering.
1401
The dirstate holds the hash and size of the canonical form of the file,
1402
and most methods must return that.
1405
def _file_content_summary(self, path, stat_result):
1406
# This is to support the somewhat obsolete path_content_summary method
1407
# with content filtering: see
1408
# <https://bugs.launchpad.net/bzr/+bug/415508>.
1410
# If the dirstate cache is up to date and knows the hash and size,
1412
# Otherwise if there are no content filters, return the on-disk size
1413
# and leave the hash blank.
1414
# Otherwise, read and filter the on-disk file and use its size and
1417
# The dirstate doesn't store the size of the canonical form so we
1418
# can't trust it for content-filtered trees. We just return None.
1419
dirstate_sha1 = self._dirstate.sha1_from_stat(path, stat_result)
1420
executable = self._is_executable_from_path_and_stat(path, stat_result)
1421
return ('file', None, executable, dirstate_sha1)
1424
class WorkingTree4(DirStateWorkingTree):
1425
"""This is the Format 4 working tree.
1427
This differs from WorkingTree by:
1428
- Having a consolidated internal dirstate, stored in a
1429
randomly-accessible sorted file on disk.
1430
- Not having a regular inventory attribute. One can be synthesized
1431
on demand but this is expensive and should be avoided.
1433
This is new in bzr 0.15.
1437
class WorkingTree5(ContentFilteringDirStateWorkingTree):
1438
"""This is the Format 5 working tree.
1440
This differs from WorkingTree4 by:
1441
- Supporting content filtering.
1443
This is new in bzr 1.11.
1447
class WorkingTree6(ContentFilteringDirStateWorkingTree):
1448
"""This is the Format 6 working tree.
1450
This differs from WorkingTree5 by:
1451
- Supporting a current view that may mask the set of files in a tree
1452
impacted by most user operations.
1454
This is new in bzr 1.14.
1457
def _make_views(self):
1458
return views.PathBasedViews(self)
1461
class DirStateWorkingTreeFormat(WorkingTreeFormat):
1463
missing_parent_conflicts = True
1465
supports_versioned_directories = True
1467
_lock_class = LockDir
1468
_lock_file_name = 'lock'
1470
def _open_control_files(self, a_bzrdir):
1471
transport = a_bzrdir.get_workingtree_transport(None)
1472
return LockableFiles(transport, self._lock_file_name,
1475
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1476
accelerator_tree=None, hardlink=False):
1477
"""See WorkingTreeFormat.initialize().
1479
:param revision_id: allows creating a working tree at a different
1480
revision than the branch is at.
1481
:param accelerator_tree: A tree which can be used for retrieving file
1482
contents more quickly than the revision tree, i.e. a workingtree.
1483
The revision tree will be used for cases where accelerator_tree's
1484
content is different.
1485
:param hardlink: If true, hard-link files from accelerator_tree,
1488
These trees get an initial random root id, if their repository supports
1489
rich root data, TREE_ROOT otherwise.
1491
if not isinstance(a_bzrdir.transport, LocalTransport):
1492
raise errors.NotLocalUrl(a_bzrdir.transport.base)
1493
transport = a_bzrdir.get_workingtree_transport(self)
1494
control_files = self._open_control_files(a_bzrdir)
1495
control_files.create_lock()
1496
control_files.lock_write()
1497
transport.put_bytes('format', self.get_format_string(),
1498
mode=a_bzrdir._get_file_mode())
1499
if from_branch is not None:
1500
branch = from_branch
1502
branch = a_bzrdir.open_branch()
1503
if revision_id is None:
1504
revision_id = branch.last_revision()
1505
local_path = transport.local_abspath('dirstate')
1506
# write out new dirstate (must exist when we create the tree)
1507
state = dirstate.DirState.initialize(local_path)
1510
wt = self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
1514
_control_files=control_files)
1516
wt.lock_tree_write()
1518
self._init_custom_control_files(wt)
1519
if revision_id in (None, _mod_revision.NULL_REVISION):
1520
if branch.repository.supports_rich_root():
1521
wt._set_root_id(generate_ids.gen_root_id())
1523
wt._set_root_id(ROOT_ID)
1526
# frequently, we will get here due to branching. The accelerator
1527
# tree will be the tree from the branch, so the desired basis
1528
# tree will often be a parent of the accelerator tree.
1529
if accelerator_tree is not None:
1531
basis = accelerator_tree.revision_tree(revision_id)
1532
except errors.NoSuchRevision:
1535
basis = branch.repository.revision_tree(revision_id)
1536
if revision_id == _mod_revision.NULL_REVISION:
1539
parents_list = [(revision_id, basis)]
1542
wt.set_parent_trees(parents_list, allow_leftmost_as_ghost=True)
1544
# if the basis has a root id we have to use that; otherwise we
1545
# use a new random one
1546
basis_root_id = basis.get_root_id()
1547
if basis_root_id is not None:
1548
wt._set_root_id(basis_root_id)
1550
if wt.supports_content_filtering():
1551
# The original tree may not have the same content filters
1552
# applied so we can't safely build the inventory delta from
1554
delta_from_tree = False
1556
delta_from_tree = True
1557
# delta_from_tree is safe even for DirStateRevisionTrees,
1558
# because wt4.apply_inventory_delta does not mutate the input
1559
# inventory entries.
1560
transform.build_tree(basis, wt, accelerator_tree,
1562
delta_from_tree=delta_from_tree)
1566
control_files.unlock()
1570
def _init_custom_control_files(self, wt):
1571
"""Subclasses with custom control files should override this method.
1573
The working tree and control files are locked for writing when this
1576
:param wt: the WorkingTree object
1579
def open(self, a_bzrdir, _found=False):
1580
"""Return the WorkingTree object for a_bzrdir
1582
_found is a private parameter, do not use it. It is used to indicate
1583
if format probing has already been done.
1586
# we are being called directly and must probe.
1587
raise NotImplementedError
1588
if not isinstance(a_bzrdir.transport, LocalTransport):
1589
raise errors.NotLocalUrl(a_bzrdir.transport.base)
1590
wt = self._open(a_bzrdir, self._open_control_files(a_bzrdir))
1593
def _open(self, a_bzrdir, control_files):
1594
"""Open the tree itself.
1596
:param a_bzrdir: the dir for the tree.
1597
:param control_files: the control files for the tree.
1599
return self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
1600
branch=a_bzrdir.open_branch(),
1603
_control_files=control_files)
1605
def __get_matchingbzrdir(self):
1606
return self._get_matchingbzrdir()
1608
def _get_matchingbzrdir(self):
1609
"""Overrideable method to get a bzrdir for testing."""
1610
# please test against something that will let us do tree references
1611
return bzrdir.format_registry.make_bzrdir(
1612
'dirstate-with-subtree')
1614
_matchingbzrdir = property(__get_matchingbzrdir)
1617
class WorkingTreeFormat4(DirStateWorkingTreeFormat):
1618
"""The first consolidated dirstate working tree format.
1621
- exists within a metadir controlling .bzr
1622
- includes an explicit version marker for the workingtree control
1623
files, separate from the BzrDir format
1624
- modifies the hash cache format
1625
- is new in bzr 0.15
1626
- uses a LockDir to guard access to it.
1629
upgrade_recommended = False
1631
_tree_class = WorkingTree4
1633
def get_format_string(self):
1634
"""See WorkingTreeFormat.get_format_string()."""
1635
return "Bazaar Working Tree Format 4 (bzr 0.15)\n"
1637
def get_format_description(self):
1638
"""See WorkingTreeFormat.get_format_description()."""
1639
return "Working tree format 4"
1642
class WorkingTreeFormat5(DirStateWorkingTreeFormat):
1643
"""WorkingTree format supporting content filtering.
1646
upgrade_recommended = False
1648
_tree_class = WorkingTree5
1650
def get_format_string(self):
1651
"""See WorkingTreeFormat.get_format_string()."""
1652
return "Bazaar Working Tree Format 5 (bzr 1.11)\n"
1654
def get_format_description(self):
1655
"""See WorkingTreeFormat.get_format_description()."""
1656
return "Working tree format 5"
1658
def supports_content_filtering(self):
1662
class WorkingTreeFormat6(DirStateWorkingTreeFormat):
1663
"""WorkingTree format supporting views.
1666
upgrade_recommended = False
1668
_tree_class = WorkingTree6
1670
def get_format_string(self):
1671
"""See WorkingTreeFormat.get_format_string()."""
1672
return "Bazaar Working Tree Format 6 (bzr 1.14)\n"
1674
def get_format_description(self):
1675
"""See WorkingTreeFormat.get_format_description()."""
1676
return "Working tree format 6"
1678
def _init_custom_control_files(self, wt):
1679
"""Subclasses with custom control files should override this method."""
1680
wt._transport.put_bytes('views', '', mode=wt.bzrdir._get_file_mode())
1682
def supports_content_filtering(self):
1685
def supports_views(self):
1689
class DirStateRevisionTree(InventoryTree):
1690
"""A revision tree pulling the inventory from a dirstate.
1692
Note that this is one of the historical (ie revision) trees cached in the
1693
dirstate for easy access, not the workingtree.
1696
def __init__(self, dirstate, revision_id, repository):
1697
self._dirstate = dirstate
1698
self._revision_id = revision_id
1699
self._repository = repository
1700
self._inventory = None
1702
self._dirstate_locked = False
1703
self._repo_supports_tree_reference = getattr(
1704
repository._format, "supports_tree_reference",
1708
return "<%s of %s in %s>" % \
1709
(self.__class__.__name__, self._revision_id, self._dirstate)
1711
def annotate_iter(self, file_id,
1712
default_revision=_mod_revision.CURRENT_REVISION):
1713
"""See Tree.annotate_iter"""
1714
text_key = (file_id, self.get_file_revision(file_id))
1715
annotations = self._repository.texts.annotate(text_key)
1716
return [(key[-1], line) for (key, line) in annotations]
1718
def _comparison_data(self, entry, path):
1719
"""See Tree._comparison_data."""
1721
return None, False, None
1722
# trust the entry as RevisionTree does, but this may not be
1723
# sensible: the entry might not have come from us?
1724
return entry.kind, entry.executable, None
1726
def _file_size(self, entry, stat_value):
1727
return entry.text_size
1729
def filter_unversioned_files(self, paths):
1730
"""Filter out paths that are not versioned.
1732
:return: set of paths.
1734
pred = self.has_filename
1735
return set((p for p in paths if not pred(p)))
1737
def get_root_id(self):
1738
return self.path2id('')
1740
def id2path(self, file_id):
1741
"Convert a file-id to a path."
1742
entry = self._get_entry(file_id=file_id)
1743
if entry == (None, None):
1744
raise errors.NoSuchId(tree=self, file_id=file_id)
1745
path_utf8 = osutils.pathjoin(entry[0][0], entry[0][1])
1746
return path_utf8.decode('utf8')
1748
def iter_references(self):
1749
if not self._repo_supports_tree_reference:
1750
# When the repo doesn't support references, we will have nothing to
1753
# Otherwise, fall back to the default implementation
1754
return super(DirStateRevisionTree, self).iter_references()
1756
def _get_parent_index(self):
1757
"""Return the index in the dirstate referenced by this tree."""
1758
return self._dirstate.get_parent_ids().index(self._revision_id) + 1
1760
def _get_entry(self, file_id=None, path=None):
1761
"""Get the dirstate row for file_id or path.
1763
If either file_id or path is supplied, it is used as the key to lookup.
1764
If both are supplied, the fastest lookup is used, and an error is
1765
raised if they do not both point at the same row.
1767
:param file_id: An optional unicode file_id to be looked up.
1768
:param path: An optional unicode path to be looked up.
1769
:return: The dirstate row tuple for path/file_id, or (None, None)
1771
if file_id is None and path is None:
1772
raise errors.BzrError('must supply file_id or path')
1773
if path is not None:
1774
path = path.encode('utf8')
1775
parent_index = self._get_parent_index()
1776
return self._dirstate._get_entry(parent_index, fileid_utf8=file_id, path_utf8=path)
1778
def _generate_inventory(self):
1779
"""Create and set self.inventory from the dirstate object.
1781
(So this is only called the first time the inventory is requested for
1782
this tree; it then remains in memory until it's out of date.)
1784
This is relatively expensive: we have to walk the entire dirstate.
1786
if not self._locked:
1787
raise AssertionError(
1788
'cannot generate inventory of an unlocked '
1789
'dirstate revision tree')
1790
# separate call for profiling - makes it clear where the costs are.
1791
self._dirstate._read_dirblocks_if_needed()
1792
if self._revision_id not in self._dirstate.get_parent_ids():
1793
raise AssertionError(
1794
'parent %s has disappeared from %s' % (
1795
self._revision_id, self._dirstate.get_parent_ids()))
1796
parent_index = self._dirstate.get_parent_ids().index(self._revision_id) + 1
1797
# This is identical now to the WorkingTree _generate_inventory except
1798
# for the tree index use.
1799
root_key, current_entry = self._dirstate._get_entry(parent_index, path_utf8='')
1800
current_id = root_key[2]
1801
if current_entry[parent_index][0] != 'd':
1802
raise AssertionError()
1803
inv = Inventory(root_id=current_id, revision_id=self._revision_id)
1804
inv.root.revision = current_entry[parent_index][4]
1805
# Turn some things into local variables
1806
minikind_to_kind = dirstate.DirState._minikind_to_kind
1807
factory = entry_factory
1808
utf8_decode = cache_utf8._utf8_decode
1809
inv_byid = inv._byid
1810
# we could do this straight out of the dirstate; it might be fast
1811
# and should be profiled - RBC 20070216
1812
parent_ies = {'' : inv.root}
1813
for block in self._dirstate._dirblocks[1:]: #skip root
1816
parent_ie = parent_ies[dirname]
1818
# all the paths in this block are not versioned in this tree
1820
for key, entry in block[1]:
1821
minikind, fingerprint, size, executable, revid = entry[parent_index]
1822
if minikind in ('a', 'r'): # absent, relocated
1826
name_unicode = utf8_decode(name)[0]
1828
kind = minikind_to_kind[minikind]
1829
inv_entry = factory[kind](file_id, name_unicode,
1831
inv_entry.revision = revid
1833
inv_entry.executable = executable
1834
inv_entry.text_size = size
1835
inv_entry.text_sha1 = fingerprint
1836
elif kind == 'directory':
1837
parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
1838
elif kind == 'symlink':
1839
inv_entry.symlink_target = utf8_decode(fingerprint)[0]
1840
elif kind == 'tree-reference':
1841
inv_entry.reference_revision = fingerprint or None
1843
raise AssertionError("cannot convert entry %r into an InventoryEntry"
1845
# These checks cost us around 40ms on a 55k entry tree
1846
if file_id in inv_byid:
1847
raise AssertionError('file_id %s already in'
1848
' inventory as %s' % (file_id, inv_byid[file_id]))
1849
if name_unicode in parent_ie.children:
1850
raise AssertionError('name %r already in parent'
1852
inv_byid[file_id] = inv_entry
1853
parent_ie.children[name_unicode] = inv_entry
1854
self._inventory = inv
1856
def get_file_mtime(self, file_id, path=None):
1857
"""Return the modification time for this record.
1859
We return the timestamp of the last-changed revision.
1861
# Make sure the file exists
1862
entry = self._get_entry(file_id, path=path)
1863
if entry == (None, None): # do we raise?
1865
parent_index = self._get_parent_index()
1866
last_changed_revision = entry[1][parent_index][4]
1868
rev = self._repository.get_revision(last_changed_revision)
1869
except errors.NoSuchRevision:
1870
raise errors.FileTimestampUnavailable(self.id2path(file_id))
1871
return rev.timestamp
1873
def get_file_sha1(self, file_id, path=None, stat_value=None):
1874
entry = self._get_entry(file_id=file_id, path=path)
1875
parent_index = self._get_parent_index()
1876
parent_details = entry[1][parent_index]
1877
if parent_details[0] == 'f':
1878
return parent_details[1]
1882
def get_file_revision(self, file_id):
1883
return self.inventory[file_id].revision
1885
def get_file(self, file_id, path=None):
1886
return StringIO(self.get_file_text(file_id))
1888
def get_file_size(self, file_id):
1889
"""See Tree.get_file_size"""
1890
return self.inventory[file_id].text_size
1892
def get_file_text(self, file_id, path=None):
1893
_, content = list(self.iter_files_bytes([(file_id, None)]))[0]
1894
return ''.join(content)
1896
def get_reference_revision(self, file_id, path=None):
1897
return self.inventory[file_id].reference_revision
1899
def iter_files_bytes(self, desired_files):
1900
"""See Tree.iter_files_bytes.
1902
This version is implemented on top of Repository.iter_files_bytes"""
1903
parent_index = self._get_parent_index()
1904
repo_desired_files = []
1905
for file_id, identifier in desired_files:
1906
entry = self._get_entry(file_id)
1907
if entry == (None, None):
1908
raise errors.NoSuchId(self, file_id)
1909
repo_desired_files.append((file_id, entry[1][parent_index][4],
1911
return self._repository.iter_files_bytes(repo_desired_files)
1913
def get_symlink_target(self, file_id, path=None):
1914
entry = self._get_entry(file_id=file_id)
1915
parent_index = self._get_parent_index()
1916
if entry[1][parent_index][0] != 'l':
1919
target = entry[1][parent_index][1]
1920
target = target.decode('utf8')
1923
def get_revision_id(self):
1924
"""Return the revision id for this tree."""
1925
return self._revision_id
1927
def _get_inventory(self):
1928
if self._inventory is not None:
1929
return self._inventory
1930
self._must_be_locked()
1931
self._generate_inventory()
1932
return self._inventory
1934
inventory = property(_get_inventory,
1935
doc="Inventory of this Tree")
1937
def get_parent_ids(self):
1938
"""The parents of a tree in the dirstate are not cached."""
1939
return self._repository.get_revision(self._revision_id).parent_ids
1941
def has_filename(self, filename):
1942
return bool(self.path2id(filename))
1944
def kind(self, file_id):
1945
entry = self._get_entry(file_id=file_id)[1]
1947
raise errors.NoSuchId(tree=self, file_id=file_id)
1948
parent_index = self._get_parent_index()
1949
return dirstate.DirState._minikind_to_kind[entry[parent_index][0]]
1951
def stored_kind(self, file_id):
1952
"""See Tree.stored_kind"""
1953
return self.kind(file_id)
1955
def path_content_summary(self, path):
1956
"""See Tree.path_content_summary."""
1957
id = self.inventory.path2id(path)
1959
return ('missing', None, None, None)
1960
entry = self._inventory[id]
1963
return (kind, entry.text_size, entry.executable, entry.text_sha1)
1964
elif kind == 'symlink':
1965
return (kind, None, None, entry.symlink_target)
1967
return (kind, None, None, None)
1969
def is_executable(self, file_id, path=None):
1970
ie = self.inventory[file_id]
1971
if ie.kind != "file":
1973
return ie.executable
1975
def is_locked(self):
1978
def list_files(self, include_root=False, from_dir=None, recursive=True):
1979
# We use a standard implementation, because DirStateRevisionTree is
1980
# dealing with one of the parents of the current state
1981
inv = self._get_inventory()
1982
if from_dir is None:
1985
from_dir_id = inv.path2id(from_dir)
1986
if from_dir_id is None:
1987
# Directory not versioned
1989
entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
1990
if inv.root is not None and not include_root and from_dir is None:
1992
for path, entry in entries:
1993
yield path, 'V', entry.kind, entry.file_id, entry
1995
def lock_read(self):
1996
"""Lock the tree for a set of operations.
1998
:return: A bzrlib.lock.LogicalLockResult.
2000
if not self._locked:
2001
self._repository.lock_read()
2002
if self._dirstate._lock_token is None:
2003
self._dirstate.lock_read()
2004
self._dirstate_locked = True
2006
return LogicalLockResult(self.unlock)
2008
def _must_be_locked(self):
2009
if not self._locked:
2010
raise errors.ObjectNotLocked(self)
2013
def path2id(self, path):
2014
"""Return the id for path in this tree."""
2015
# lookup by path: faster than splitting and walking the ivnentory.
2016
entry = self._get_entry(path=path)
2017
if entry == (None, None):
2022
"""Unlock, freeing any cache memory used during the lock."""
2023
# outside of a lock, the inventory is suspect: release it.
2025
if not self._locked:
2026
self._inventory = None
2028
if self._dirstate_locked:
2029
self._dirstate.unlock()
2030
self._dirstate_locked = False
2031
self._repository.unlock()
2034
def supports_tree_reference(self):
2035
return self._repo_supports_tree_reference
2037
def walkdirs(self, prefix=""):
2038
# TODO: jam 20070215 This is the lazy way by using the RevisionTree
2039
# implementation based on an inventory.
2040
# This should be cleaned up to use the much faster Dirstate code
2041
# So for now, we just build up the parent inventory, and extract
2042
# it the same way RevisionTree does.
2043
_directory = 'directory'
2044
inv = self._get_inventory()
2045
top_id = inv.path2id(prefix)
2049
pending = [(prefix, top_id)]
2052
relpath, file_id = pending.pop()
2053
# 0 - relpath, 1- file-id
2055
relroot = relpath + '/'
2058
# FIXME: stash the node in pending
2059
entry = inv[file_id]
2060
for name, child in entry.sorted_children():
2061
toppath = relroot + name
2062
dirblock.append((toppath, name, child.kind, None,
2063
child.file_id, child.kind
2065
yield (relpath, entry.file_id), dirblock
2066
# push the user specified dirs from dirblock
2067
for dir in reversed(dirblock):
2068
if dir[2] == _directory:
2069
pending.append((dir[0], dir[4]))
2072
class InterDirStateTree(InterTree):
2073
"""Fast path optimiser for changes_from with dirstate trees.
2075
This is used only when both trees are in the dirstate working file, and
2076
the source is any parent within the dirstate, and the destination is
2077
the current working tree of the same dirstate.
2079
# this could be generalized to allow comparisons between any trees in the
2080
# dirstate, and possibly between trees stored in different dirstates.
2082
def __init__(self, source, target):
2083
super(InterDirStateTree, self).__init__(source, target)
2084
if not InterDirStateTree.is_compatible(source, target):
2085
raise Exception, "invalid source %r and target %r" % (source, target)
2088
def make_source_parent_tree(source, target):
2089
"""Change the source tree into a parent of the target."""
2090
revid = source.commit('record tree')
2091
target.branch.fetch(source.branch, revid)
2092
target.set_parent_ids([revid])
2093
return target.basis_tree(), target
2096
def make_source_parent_tree_python_dirstate(klass, test_case, source, target):
2097
result = klass.make_source_parent_tree(source, target)
2098
result[1]._iter_changes = dirstate.ProcessEntryPython
2102
def make_source_parent_tree_compiled_dirstate(klass, test_case, source,
2104
from bzrlib.tests.test__dirstate_helpers import \
2105
compiled_dirstate_helpers_feature
2106
test_case.requireFeature(compiled_dirstate_helpers_feature)
2107
from bzrlib._dirstate_helpers_pyx import ProcessEntryC
2108
result = klass.make_source_parent_tree(source, target)
2109
result[1]._iter_changes = ProcessEntryC
2112
_matching_from_tree_format = WorkingTreeFormat4()
2113
_matching_to_tree_format = WorkingTreeFormat4()
2116
def _test_mutable_trees_to_test_trees(klass, test_case, source, target):
2117
# This method shouldn't be called, because we have python and C
2118
# specific flavours.
2119
raise NotImplementedError
2121
def iter_changes(self, include_unchanged=False,
2122
specific_files=None, pb=None, extra_trees=[],
2123
require_versioned=True, want_unversioned=False):
2124
"""Return the changes from source to target.
2126
:return: An iterator that yields tuples. See InterTree.iter_changes
2128
:param specific_files: An optional list of file paths to restrict the
2129
comparison to. When mapping filenames to ids, all matches in all
2130
trees (including optional extra_trees) are used, and all children of
2131
matched directories are included.
2132
:param include_unchanged: An optional boolean requesting the inclusion of
2133
unchanged entries in the result.
2134
:param extra_trees: An optional list of additional trees to use when
2135
mapping the contents of specific_files (paths) to file_ids.
2136
:param require_versioned: If True, all files in specific_files must be
2137
versioned in one of source, target, extra_trees or
2138
PathsNotVersionedError is raised.
2139
:param want_unversioned: Should unversioned files be returned in the
2140
output. An unversioned file is defined as one with (False, False)
2141
for the versioned pair.
2143
# TODO: handle extra trees in the dirstate.
2144
if (extra_trees or specific_files == []):
2145
# we can't fast-path these cases (yet)
2146
return super(InterDirStateTree, self).iter_changes(
2147
include_unchanged, specific_files, pb, extra_trees,
2148
require_versioned, want_unversioned=want_unversioned)
2149
parent_ids = self.target.get_parent_ids()
2150
if not (self.source._revision_id in parent_ids
2151
or self.source._revision_id == _mod_revision.NULL_REVISION):
2152
raise AssertionError(
2153
"revision {%s} is not stored in {%s}, but %s "
2154
"can only be used for trees stored in the dirstate"
2155
% (self.source._revision_id, self.target, self.iter_changes))
2157
if self.source._revision_id == _mod_revision.NULL_REVISION:
2159
indices = (target_index,)
2161
if not (self.source._revision_id in parent_ids):
2162
raise AssertionError(
2163
"Failure: source._revision_id: %s not in target.parent_ids(%s)" % (
2164
self.source._revision_id, parent_ids))
2165
source_index = 1 + parent_ids.index(self.source._revision_id)
2166
indices = (source_index, target_index)
2167
# -- make all specific_files utf8 --
2169
specific_files_utf8 = set()
2170
for path in specific_files:
2171
# Note, if there are many specific files, using cache_utf8
2172
# would be good here.
2173
specific_files_utf8.add(path.encode('utf8'))
2174
specific_files = specific_files_utf8
2176
specific_files = set([''])
2177
# -- specific_files is now a utf8 path set --
2179
# -- get the state object and prepare it.
2180
state = self.target.current_dirstate()
2181
state._read_dirblocks_if_needed()
2182
if require_versioned:
2183
# -- check all supplied paths are versioned in a search tree. --
2185
for path in specific_files:
2186
path_entries = state._entries_for_path(path)
2187
if not path_entries:
2188
# this specified path is not present at all: error
2189
not_versioned.append(path)
2191
found_versioned = False
2192
# for each id at this path
2193
for entry in path_entries:
2195
for index in indices:
2196
if entry[1][index][0] != 'a': # absent
2197
found_versioned = True
2198
# all good: found a versioned cell
2200
if not found_versioned:
2201
# none of the indexes was not 'absent' at all ids for this
2203
not_versioned.append(path)
2204
if len(not_versioned) > 0:
2205
raise errors.PathsNotVersionedError(not_versioned)
2206
# -- remove redundancy in supplied specific_files to prevent over-scanning --
2207
search_specific_files = osutils.minimum_path_selection(specific_files)
2209
use_filesystem_for_exec = (sys.platform != 'win32')
2210
iter_changes = self.target._iter_changes(include_unchanged,
2211
use_filesystem_for_exec, search_specific_files, state,
2212
source_index, target_index, want_unversioned, self.target)
2213
return iter_changes.iter_changes()
2216
def is_compatible(source, target):
2217
# the target must be a dirstate working tree
2218
if not isinstance(target, DirStateWorkingTree):
2220
# the source must be a revtree or dirstate rev tree.
2221
if not isinstance(source,
2222
(revisiontree.RevisionTree, DirStateRevisionTree)):
2224
# the source revid must be in the target dirstate
2225
if not (source._revision_id == _mod_revision.NULL_REVISION or
2226
source._revision_id in target.get_parent_ids()):
2227
# TODO: what about ghosts? it may well need to
2228
# check for them explicitly.
2232
InterTree.register_optimiser(InterDirStateTree)
2235
class Converter3to4(object):
2236
"""Perform an in-place upgrade of format 3 to format 4 trees."""
2239
self.target_format = WorkingTreeFormat4()
2241
def convert(self, tree):
2242
# lock the control files not the tree, so that we dont get tree
2243
# on-unlock behaviours, and so that noone else diddles with the
2244
# tree during upgrade.
2245
tree._control_files.lock_write()
2247
tree.read_working_inventory()
2248
self.create_dirstate_data(tree)
2249
self.update_format(tree)
2250
self.remove_xml_files(tree)
2252
tree._control_files.unlock()
2254
def create_dirstate_data(self, tree):
2255
"""Create the dirstate based data for tree."""
2256
local_path = tree.bzrdir.get_workingtree_transport(None
2257
).local_abspath('dirstate')
2258
state = dirstate.DirState.from_tree(tree, local_path)
2262
def remove_xml_files(self, tree):
2263
"""Remove the oldformat 3 data."""
2264
transport = tree.bzrdir.get_workingtree_transport(None)
2265
for path in ['basis-inventory-cache', 'inventory', 'last-revision',
2266
'pending-merges', 'stat-cache']:
2268
transport.delete(path)
2269
except errors.NoSuchFile:
2270
# some files are optional - just deal.
2273
def update_format(self, tree):
2274
"""Change the format marker."""
2275
tree._transport.put_bytes('format',
2276
self.target_format.get_format_string(),
2277
mode=tree.bzrdir._get_file_mode())
2280
class Converter4to5(object):
2281
"""Perform an in-place upgrade of format 4 to format 5 trees."""
2284
self.target_format = WorkingTreeFormat5()
2286
def convert(self, tree):
2287
# lock the control files not the tree, so that we don't get tree
2288
# on-unlock behaviours, and so that no-one else diddles with the
2289
# tree during upgrade.
2290
tree._control_files.lock_write()
2292
self.update_format(tree)
2294
tree._control_files.unlock()
2296
def update_format(self, tree):
2297
"""Change the format marker."""
2298
tree._transport.put_bytes('format',
2299
self.target_format.get_format_string(),
2300
mode=tree.bzrdir._get_file_mode())
2303
class Converter4or5to6(object):
2304
"""Perform an in-place upgrade of format 4 or 5 to format 6 trees."""
2307
self.target_format = WorkingTreeFormat6()
2309
def convert(self, tree):
2310
# lock the control files not the tree, so that we don't get tree
2311
# on-unlock behaviours, and so that no-one else diddles with the
2312
# tree during upgrade.
2313
tree._control_files.lock_write()
2315
self.init_custom_control_files(tree)
2316
self.update_format(tree)
2318
tree._control_files.unlock()
2320
def init_custom_control_files(self, tree):
2321
"""Initialize custom control files."""
2322
tree._transport.put_bytes('views', '',
2323
mode=tree.bzrdir._get_file_mode())
2325
def update_format(self, tree):
2326
"""Change the format marker."""
2327
tree._transport.put_bytes('format',
2328
self.target_format.get_format_string(),
2329
mode=tree.bzrdir._get_file_mode())