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
_lock_class = LockDir
1466
_lock_file_name = 'lock'
1468
def _open_control_files(self, a_bzrdir):
1469
transport = a_bzrdir.get_workingtree_transport(None)
1470
return LockableFiles(transport, self._lock_file_name,
1473
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1474
accelerator_tree=None, hardlink=False):
1475
"""See WorkingTreeFormat.initialize().
1477
:param revision_id: allows creating a working tree at a different
1478
revision than the branch is at.
1479
:param accelerator_tree: A tree which can be used for retrieving file
1480
contents more quickly than the revision tree, i.e. a workingtree.
1481
The revision tree will be used for cases where accelerator_tree's
1482
content is different.
1483
:param hardlink: If true, hard-link files from accelerator_tree,
1486
These trees get an initial random root id, if their repository supports
1487
rich root data, TREE_ROOT otherwise.
1489
if not isinstance(a_bzrdir.transport, LocalTransport):
1490
raise errors.NotLocalUrl(a_bzrdir.transport.base)
1491
transport = a_bzrdir.get_workingtree_transport(self)
1492
control_files = self._open_control_files(a_bzrdir)
1493
control_files.create_lock()
1494
control_files.lock_write()
1495
transport.put_bytes('format', self.get_format_string(),
1496
mode=a_bzrdir._get_file_mode())
1497
if from_branch is not None:
1498
branch = from_branch
1500
branch = a_bzrdir.open_branch()
1501
if revision_id is None:
1502
revision_id = branch.last_revision()
1503
local_path = transport.local_abspath('dirstate')
1504
# write out new dirstate (must exist when we create the tree)
1505
state = dirstate.DirState.initialize(local_path)
1508
wt = self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
1512
_control_files=control_files)
1514
wt.lock_tree_write()
1516
self._init_custom_control_files(wt)
1517
if revision_id in (None, _mod_revision.NULL_REVISION):
1518
if branch.repository.supports_rich_root():
1519
wt._set_root_id(generate_ids.gen_root_id())
1521
wt._set_root_id(ROOT_ID)
1524
# frequently, we will get here due to branching. The accelerator
1525
# tree will be the tree from the branch, so the desired basis
1526
# tree will often be a parent of the accelerator tree.
1527
if accelerator_tree is not None:
1529
basis = accelerator_tree.revision_tree(revision_id)
1530
except errors.NoSuchRevision:
1533
basis = branch.repository.revision_tree(revision_id)
1534
if revision_id == _mod_revision.NULL_REVISION:
1537
parents_list = [(revision_id, basis)]
1540
wt.set_parent_trees(parents_list, allow_leftmost_as_ghost=True)
1542
# if the basis has a root id we have to use that; otherwise we
1543
# use a new random one
1544
basis_root_id = basis.get_root_id()
1545
if basis_root_id is not None:
1546
wt._set_root_id(basis_root_id)
1548
if wt.supports_content_filtering():
1549
# The original tree may not have the same content filters
1550
# applied so we can't safely build the inventory delta from
1552
delta_from_tree = False
1554
delta_from_tree = True
1555
# delta_from_tree is safe even for DirStateRevisionTrees,
1556
# because wt4.apply_inventory_delta does not mutate the input
1557
# inventory entries.
1558
transform.build_tree(basis, wt, accelerator_tree,
1560
delta_from_tree=delta_from_tree)
1564
control_files.unlock()
1568
def _init_custom_control_files(self, wt):
1569
"""Subclasses with custom control files should override this method.
1571
The working tree and control files are locked for writing when this
1574
:param wt: the WorkingTree object
1577
def open(self, a_bzrdir, _found=False):
1578
"""Return the WorkingTree object for a_bzrdir
1580
_found is a private parameter, do not use it. It is used to indicate
1581
if format probing has already been done.
1584
# we are being called directly and must probe.
1585
raise NotImplementedError
1586
if not isinstance(a_bzrdir.transport, LocalTransport):
1587
raise errors.NotLocalUrl(a_bzrdir.transport.base)
1588
wt = self._open(a_bzrdir, self._open_control_files(a_bzrdir))
1591
def _open(self, a_bzrdir, control_files):
1592
"""Open the tree itself.
1594
:param a_bzrdir: the dir for the tree.
1595
:param control_files: the control files for the tree.
1597
return self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
1598
branch=a_bzrdir.open_branch(),
1601
_control_files=control_files)
1603
def __get_matchingbzrdir(self):
1604
return self._get_matchingbzrdir()
1606
def _get_matchingbzrdir(self):
1607
"""Overrideable method to get a bzrdir for testing."""
1608
# please test against something that will let us do tree references
1609
return bzrdir.format_registry.make_bzrdir(
1610
'dirstate-with-subtree')
1612
_matchingbzrdir = property(__get_matchingbzrdir)
1615
class WorkingTreeFormat4(DirStateWorkingTreeFormat):
1616
"""The first consolidated dirstate working tree format.
1619
- exists within a metadir controlling .bzr
1620
- includes an explicit version marker for the workingtree control
1621
files, separate from the BzrDir format
1622
- modifies the hash cache format
1623
- is new in bzr 0.15
1624
- uses a LockDir to guard access to it.
1627
upgrade_recommended = False
1629
_tree_class = WorkingTree4
1631
def get_format_string(self):
1632
"""See WorkingTreeFormat.get_format_string()."""
1633
return "Bazaar Working Tree Format 4 (bzr 0.15)\n"
1635
def get_format_description(self):
1636
"""See WorkingTreeFormat.get_format_description()."""
1637
return "Working tree format 4"
1640
class WorkingTreeFormat5(DirStateWorkingTreeFormat):
1641
"""WorkingTree format supporting content filtering.
1644
upgrade_recommended = False
1646
_tree_class = WorkingTree5
1648
def get_format_string(self):
1649
"""See WorkingTreeFormat.get_format_string()."""
1650
return "Bazaar Working Tree Format 5 (bzr 1.11)\n"
1652
def get_format_description(self):
1653
"""See WorkingTreeFormat.get_format_description()."""
1654
return "Working tree format 5"
1656
def supports_content_filtering(self):
1660
class WorkingTreeFormat6(DirStateWorkingTreeFormat):
1661
"""WorkingTree format supporting views.
1664
upgrade_recommended = False
1666
_tree_class = WorkingTree6
1668
def get_format_string(self):
1669
"""See WorkingTreeFormat.get_format_string()."""
1670
return "Bazaar Working Tree Format 6 (bzr 1.14)\n"
1672
def get_format_description(self):
1673
"""See WorkingTreeFormat.get_format_description()."""
1674
return "Working tree format 6"
1676
def _init_custom_control_files(self, wt):
1677
"""Subclasses with custom control files should override this method."""
1678
wt._transport.put_bytes('views', '', mode=wt.bzrdir._get_file_mode())
1680
def supports_content_filtering(self):
1683
def supports_views(self):
1687
class DirStateRevisionTree(InventoryTree):
1688
"""A revision tree pulling the inventory from a dirstate.
1690
Note that this is one of the historical (ie revision) trees cached in the
1691
dirstate for easy access, not the workingtree.
1694
def __init__(self, dirstate, revision_id, repository):
1695
self._dirstate = dirstate
1696
self._revision_id = revision_id
1697
self._repository = repository
1698
self._inventory = None
1700
self._dirstate_locked = False
1701
self._repo_supports_tree_reference = getattr(
1702
repository._format, "supports_tree_reference",
1706
return "<%s of %s in %s>" % \
1707
(self.__class__.__name__, self._revision_id, self._dirstate)
1709
def annotate_iter(self, file_id,
1710
default_revision=_mod_revision.CURRENT_REVISION):
1711
"""See Tree.annotate_iter"""
1712
text_key = (file_id, self.get_file_revision(file_id))
1713
annotations = self._repository.texts.annotate(text_key)
1714
return [(key[-1], line) for (key, line) in annotations]
1716
def _comparison_data(self, entry, path):
1717
"""See Tree._comparison_data."""
1719
return None, False, None
1720
# trust the entry as RevisionTree does, but this may not be
1721
# sensible: the entry might not have come from us?
1722
return entry.kind, entry.executable, None
1724
def _file_size(self, entry, stat_value):
1725
return entry.text_size
1727
def filter_unversioned_files(self, paths):
1728
"""Filter out paths that are not versioned.
1730
:return: set of paths.
1732
pred = self.has_filename
1733
return set((p for p in paths if not pred(p)))
1735
def get_root_id(self):
1736
return self.path2id('')
1738
def id2path(self, file_id):
1739
"Convert a file-id to a path."
1740
entry = self._get_entry(file_id=file_id)
1741
if entry == (None, None):
1742
raise errors.NoSuchId(tree=self, file_id=file_id)
1743
path_utf8 = osutils.pathjoin(entry[0][0], entry[0][1])
1744
return path_utf8.decode('utf8')
1746
def iter_references(self):
1747
if not self._repo_supports_tree_reference:
1748
# When the repo doesn't support references, we will have nothing to
1751
# Otherwise, fall back to the default implementation
1752
return super(DirStateRevisionTree, self).iter_references()
1754
def _get_parent_index(self):
1755
"""Return the index in the dirstate referenced by this tree."""
1756
return self._dirstate.get_parent_ids().index(self._revision_id) + 1
1758
def _get_entry(self, file_id=None, path=None):
1759
"""Get the dirstate row for file_id or path.
1761
If either file_id or path is supplied, it is used as the key to lookup.
1762
If both are supplied, the fastest lookup is used, and an error is
1763
raised if they do not both point at the same row.
1765
:param file_id: An optional unicode file_id to be looked up.
1766
:param path: An optional unicode path to be looked up.
1767
:return: The dirstate row tuple for path/file_id, or (None, None)
1769
if file_id is None and path is None:
1770
raise errors.BzrError('must supply file_id or path')
1771
if path is not None:
1772
path = path.encode('utf8')
1773
parent_index = self._get_parent_index()
1774
return self._dirstate._get_entry(parent_index, fileid_utf8=file_id, path_utf8=path)
1776
def _generate_inventory(self):
1777
"""Create and set self.inventory from the dirstate object.
1779
(So this is only called the first time the inventory is requested for
1780
this tree; it then remains in memory until it's out of date.)
1782
This is relatively expensive: we have to walk the entire dirstate.
1784
if not self._locked:
1785
raise AssertionError(
1786
'cannot generate inventory of an unlocked '
1787
'dirstate revision tree')
1788
# separate call for profiling - makes it clear where the costs are.
1789
self._dirstate._read_dirblocks_if_needed()
1790
if self._revision_id not in self._dirstate.get_parent_ids():
1791
raise AssertionError(
1792
'parent %s has disappeared from %s' % (
1793
self._revision_id, self._dirstate.get_parent_ids()))
1794
parent_index = self._dirstate.get_parent_ids().index(self._revision_id) + 1
1795
# This is identical now to the WorkingTree _generate_inventory except
1796
# for the tree index use.
1797
root_key, current_entry = self._dirstate._get_entry(parent_index, path_utf8='')
1798
current_id = root_key[2]
1799
if current_entry[parent_index][0] != 'd':
1800
raise AssertionError()
1801
inv = Inventory(root_id=current_id, revision_id=self._revision_id)
1802
inv.root.revision = current_entry[parent_index][4]
1803
# Turn some things into local variables
1804
minikind_to_kind = dirstate.DirState._minikind_to_kind
1805
factory = entry_factory
1806
utf8_decode = cache_utf8._utf8_decode
1807
inv_byid = inv._byid
1808
# we could do this straight out of the dirstate; it might be fast
1809
# and should be profiled - RBC 20070216
1810
parent_ies = {'' : inv.root}
1811
for block in self._dirstate._dirblocks[1:]: #skip root
1814
parent_ie = parent_ies[dirname]
1816
# all the paths in this block are not versioned in this tree
1818
for key, entry in block[1]:
1819
minikind, fingerprint, size, executable, revid = entry[parent_index]
1820
if minikind in ('a', 'r'): # absent, relocated
1824
name_unicode = utf8_decode(name)[0]
1826
kind = minikind_to_kind[minikind]
1827
inv_entry = factory[kind](file_id, name_unicode,
1829
inv_entry.revision = revid
1831
inv_entry.executable = executable
1832
inv_entry.text_size = size
1833
inv_entry.text_sha1 = fingerprint
1834
elif kind == 'directory':
1835
parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
1836
elif kind == 'symlink':
1837
inv_entry.symlink_target = utf8_decode(fingerprint)[0]
1838
elif kind == 'tree-reference':
1839
inv_entry.reference_revision = fingerprint or None
1841
raise AssertionError("cannot convert entry %r into an InventoryEntry"
1843
# These checks cost us around 40ms on a 55k entry tree
1844
if file_id in inv_byid:
1845
raise AssertionError('file_id %s already in'
1846
' inventory as %s' % (file_id, inv_byid[file_id]))
1847
if name_unicode in parent_ie.children:
1848
raise AssertionError('name %r already in parent'
1850
inv_byid[file_id] = inv_entry
1851
parent_ie.children[name_unicode] = inv_entry
1852
self._inventory = inv
1854
def get_file_mtime(self, file_id, path=None):
1855
"""Return the modification time for this record.
1857
We return the timestamp of the last-changed revision.
1859
# Make sure the file exists
1860
entry = self._get_entry(file_id, path=path)
1861
if entry == (None, None): # do we raise?
1863
parent_index = self._get_parent_index()
1864
last_changed_revision = entry[1][parent_index][4]
1866
rev = self._repository.get_revision(last_changed_revision)
1867
except errors.NoSuchRevision:
1868
raise errors.FileTimestampUnavailable(self.id2path(file_id))
1869
return rev.timestamp
1871
def get_file_sha1(self, file_id, path=None, stat_value=None):
1872
entry = self._get_entry(file_id=file_id, path=path)
1873
parent_index = self._get_parent_index()
1874
parent_details = entry[1][parent_index]
1875
if parent_details[0] == 'f':
1876
return parent_details[1]
1880
def get_file_revision(self, file_id):
1881
return self.inventory[file_id].revision
1883
def get_file(self, file_id, path=None):
1884
return StringIO(self.get_file_text(file_id))
1886
def get_file_size(self, file_id):
1887
"""See Tree.get_file_size"""
1888
return self.inventory[file_id].text_size
1890
def get_file_text(self, file_id, path=None):
1891
_, content = list(self.iter_files_bytes([(file_id, None)]))[0]
1892
return ''.join(content)
1894
def get_reference_revision(self, file_id, path=None):
1895
return self.inventory[file_id].reference_revision
1897
def iter_files_bytes(self, desired_files):
1898
"""See Tree.iter_files_bytes.
1900
This version is implemented on top of Repository.iter_files_bytes"""
1901
parent_index = self._get_parent_index()
1902
repo_desired_files = []
1903
for file_id, identifier in desired_files:
1904
entry = self._get_entry(file_id)
1905
if entry == (None, None):
1906
raise errors.NoSuchId(self, file_id)
1907
repo_desired_files.append((file_id, entry[1][parent_index][4],
1909
return self._repository.iter_files_bytes(repo_desired_files)
1911
def get_symlink_target(self, file_id, path=None):
1912
entry = self._get_entry(file_id=file_id)
1913
parent_index = self._get_parent_index()
1914
if entry[1][parent_index][0] != 'l':
1917
target = entry[1][parent_index][1]
1918
target = target.decode('utf8')
1921
def get_revision_id(self):
1922
"""Return the revision id for this tree."""
1923
return self._revision_id
1925
def _get_inventory(self):
1926
if self._inventory is not None:
1927
return self._inventory
1928
self._must_be_locked()
1929
self._generate_inventory()
1930
return self._inventory
1932
inventory = property(_get_inventory,
1933
doc="Inventory of this Tree")
1935
def get_parent_ids(self):
1936
"""The parents of a tree in the dirstate are not cached."""
1937
return self._repository.get_revision(self._revision_id).parent_ids
1939
def has_filename(self, filename):
1940
return bool(self.path2id(filename))
1942
def kind(self, file_id):
1943
entry = self._get_entry(file_id=file_id)[1]
1945
raise errors.NoSuchId(tree=self, file_id=file_id)
1946
parent_index = self._get_parent_index()
1947
return dirstate.DirState._minikind_to_kind[entry[parent_index][0]]
1949
def stored_kind(self, file_id):
1950
"""See Tree.stored_kind"""
1951
return self.kind(file_id)
1953
def path_content_summary(self, path):
1954
"""See Tree.path_content_summary."""
1955
id = self.inventory.path2id(path)
1957
return ('missing', None, None, None)
1958
entry = self._inventory[id]
1961
return (kind, entry.text_size, entry.executable, entry.text_sha1)
1962
elif kind == 'symlink':
1963
return (kind, None, None, entry.symlink_target)
1965
return (kind, None, None, None)
1967
def is_executable(self, file_id, path=None):
1968
ie = self.inventory[file_id]
1969
if ie.kind != "file":
1971
return ie.executable
1973
def is_locked(self):
1976
def list_files(self, include_root=False, from_dir=None, recursive=True):
1977
# We use a standard implementation, because DirStateRevisionTree is
1978
# dealing with one of the parents of the current state
1979
inv = self._get_inventory()
1980
if from_dir is None:
1983
from_dir_id = inv.path2id(from_dir)
1984
if from_dir_id is None:
1985
# Directory not versioned
1987
entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
1988
if inv.root is not None and not include_root and from_dir is None:
1990
for path, entry in entries:
1991
yield path, 'V', entry.kind, entry.file_id, entry
1993
def lock_read(self):
1994
"""Lock the tree for a set of operations.
1996
:return: A bzrlib.lock.LogicalLockResult.
1998
if not self._locked:
1999
self._repository.lock_read()
2000
if self._dirstate._lock_token is None:
2001
self._dirstate.lock_read()
2002
self._dirstate_locked = True
2004
return LogicalLockResult(self.unlock)
2006
def _must_be_locked(self):
2007
if not self._locked:
2008
raise errors.ObjectNotLocked(self)
2011
def path2id(self, path):
2012
"""Return the id for path in this tree."""
2013
# lookup by path: faster than splitting and walking the ivnentory.
2014
entry = self._get_entry(path=path)
2015
if entry == (None, None):
2020
"""Unlock, freeing any cache memory used during the lock."""
2021
# outside of a lock, the inventory is suspect: release it.
2023
if not self._locked:
2024
self._inventory = None
2026
if self._dirstate_locked:
2027
self._dirstate.unlock()
2028
self._dirstate_locked = False
2029
self._repository.unlock()
2032
def supports_tree_reference(self):
2033
return self._repo_supports_tree_reference
2035
def walkdirs(self, prefix=""):
2036
# TODO: jam 20070215 This is the lazy way by using the RevisionTree
2037
# implementation based on an inventory.
2038
# This should be cleaned up to use the much faster Dirstate code
2039
# So for now, we just build up the parent inventory, and extract
2040
# it the same way RevisionTree does.
2041
_directory = 'directory'
2042
inv = self._get_inventory()
2043
top_id = inv.path2id(prefix)
2047
pending = [(prefix, top_id)]
2050
relpath, file_id = pending.pop()
2051
# 0 - relpath, 1- file-id
2053
relroot = relpath + '/'
2056
# FIXME: stash the node in pending
2057
entry = inv[file_id]
2058
for name, child in entry.sorted_children():
2059
toppath = relroot + name
2060
dirblock.append((toppath, name, child.kind, None,
2061
child.file_id, child.kind
2063
yield (relpath, entry.file_id), dirblock
2064
# push the user specified dirs from dirblock
2065
for dir in reversed(dirblock):
2066
if dir[2] == _directory:
2067
pending.append((dir[0], dir[4]))
2070
class InterDirStateTree(InterTree):
2071
"""Fast path optimiser for changes_from with dirstate trees.
2073
This is used only when both trees are in the dirstate working file, and
2074
the source is any parent within the dirstate, and the destination is
2075
the current working tree of the same dirstate.
2077
# this could be generalized to allow comparisons between any trees in the
2078
# dirstate, and possibly between trees stored in different dirstates.
2080
def __init__(self, source, target):
2081
super(InterDirStateTree, self).__init__(source, target)
2082
if not InterDirStateTree.is_compatible(source, target):
2083
raise Exception, "invalid source %r and target %r" % (source, target)
2086
def make_source_parent_tree(source, target):
2087
"""Change the source tree into a parent of the target."""
2088
revid = source.commit('record tree')
2089
target.branch.fetch(source.branch, revid)
2090
target.set_parent_ids([revid])
2091
return target.basis_tree(), target
2094
def make_source_parent_tree_python_dirstate(klass, test_case, source, target):
2095
result = klass.make_source_parent_tree(source, target)
2096
result[1]._iter_changes = dirstate.ProcessEntryPython
2100
def make_source_parent_tree_compiled_dirstate(klass, test_case, source,
2102
from bzrlib.tests.test__dirstate_helpers import \
2103
compiled_dirstate_helpers_feature
2104
test_case.requireFeature(compiled_dirstate_helpers_feature)
2105
from bzrlib._dirstate_helpers_pyx import ProcessEntryC
2106
result = klass.make_source_parent_tree(source, target)
2107
result[1]._iter_changes = ProcessEntryC
2110
_matching_from_tree_format = WorkingTreeFormat4()
2111
_matching_to_tree_format = WorkingTreeFormat4()
2114
def _test_mutable_trees_to_test_trees(klass, test_case, source, target):
2115
# This method shouldn't be called, because we have python and C
2116
# specific flavours.
2117
raise NotImplementedError
2119
def iter_changes(self, include_unchanged=False,
2120
specific_files=None, pb=None, extra_trees=[],
2121
require_versioned=True, want_unversioned=False):
2122
"""Return the changes from source to target.
2124
:return: An iterator that yields tuples. See InterTree.iter_changes
2126
:param specific_files: An optional list of file paths to restrict the
2127
comparison to. When mapping filenames to ids, all matches in all
2128
trees (including optional extra_trees) are used, and all children of
2129
matched directories are included.
2130
:param include_unchanged: An optional boolean requesting the inclusion of
2131
unchanged entries in the result.
2132
:param extra_trees: An optional list of additional trees to use when
2133
mapping the contents of specific_files (paths) to file_ids.
2134
:param require_versioned: If True, all files in specific_files must be
2135
versioned in one of source, target, extra_trees or
2136
PathsNotVersionedError is raised.
2137
:param want_unversioned: Should unversioned files be returned in the
2138
output. An unversioned file is defined as one with (False, False)
2139
for the versioned pair.
2141
# TODO: handle extra trees in the dirstate.
2142
if (extra_trees or specific_files == []):
2143
# we can't fast-path these cases (yet)
2144
return super(InterDirStateTree, self).iter_changes(
2145
include_unchanged, specific_files, pb, extra_trees,
2146
require_versioned, want_unversioned=want_unversioned)
2147
parent_ids = self.target.get_parent_ids()
2148
if not (self.source._revision_id in parent_ids
2149
or self.source._revision_id == _mod_revision.NULL_REVISION):
2150
raise AssertionError(
2151
"revision {%s} is not stored in {%s}, but %s "
2152
"can only be used for trees stored in the dirstate"
2153
% (self.source._revision_id, self.target, self.iter_changes))
2155
if self.source._revision_id == _mod_revision.NULL_REVISION:
2157
indices = (target_index,)
2159
if not (self.source._revision_id in parent_ids):
2160
raise AssertionError(
2161
"Failure: source._revision_id: %s not in target.parent_ids(%s)" % (
2162
self.source._revision_id, parent_ids))
2163
source_index = 1 + parent_ids.index(self.source._revision_id)
2164
indices = (source_index, target_index)
2165
# -- make all specific_files utf8 --
2167
specific_files_utf8 = set()
2168
for path in specific_files:
2169
# Note, if there are many specific files, using cache_utf8
2170
# would be good here.
2171
specific_files_utf8.add(path.encode('utf8'))
2172
specific_files = specific_files_utf8
2174
specific_files = set([''])
2175
# -- specific_files is now a utf8 path set --
2177
# -- get the state object and prepare it.
2178
state = self.target.current_dirstate()
2179
state._read_dirblocks_if_needed()
2180
if require_versioned:
2181
# -- check all supplied paths are versioned in a search tree. --
2183
for path in specific_files:
2184
path_entries = state._entries_for_path(path)
2185
if not path_entries:
2186
# this specified path is not present at all: error
2187
not_versioned.append(path)
2189
found_versioned = False
2190
# for each id at this path
2191
for entry in path_entries:
2193
for index in indices:
2194
if entry[1][index][0] != 'a': # absent
2195
found_versioned = True
2196
# all good: found a versioned cell
2198
if not found_versioned:
2199
# none of the indexes was not 'absent' at all ids for this
2201
not_versioned.append(path)
2202
if len(not_versioned) > 0:
2203
raise errors.PathsNotVersionedError(not_versioned)
2204
# -- remove redundancy in supplied specific_files to prevent over-scanning --
2205
search_specific_files = osutils.minimum_path_selection(specific_files)
2207
use_filesystem_for_exec = (sys.platform != 'win32')
2208
iter_changes = self.target._iter_changes(include_unchanged,
2209
use_filesystem_for_exec, search_specific_files, state,
2210
source_index, target_index, want_unversioned, self.target)
2211
return iter_changes.iter_changes()
2214
def is_compatible(source, target):
2215
# the target must be a dirstate working tree
2216
if not isinstance(target, DirStateWorkingTree):
2218
# the source must be a revtree or dirstate rev tree.
2219
if not isinstance(source,
2220
(revisiontree.RevisionTree, DirStateRevisionTree)):
2222
# the source revid must be in the target dirstate
2223
if not (source._revision_id == _mod_revision.NULL_REVISION or
2224
source._revision_id in target.get_parent_ids()):
2225
# TODO: what about ghosts? it may well need to
2226
# check for them explicitly.
2230
InterTree.register_optimiser(InterDirStateTree)
2233
class Converter3to4(object):
2234
"""Perform an in-place upgrade of format 3 to format 4 trees."""
2237
self.target_format = WorkingTreeFormat4()
2239
def convert(self, tree):
2240
# lock the control files not the tree, so that we dont get tree
2241
# on-unlock behaviours, and so that noone else diddles with the
2242
# tree during upgrade.
2243
tree._control_files.lock_write()
2245
tree.read_working_inventory()
2246
self.create_dirstate_data(tree)
2247
self.update_format(tree)
2248
self.remove_xml_files(tree)
2250
tree._control_files.unlock()
2252
def create_dirstate_data(self, tree):
2253
"""Create the dirstate based data for tree."""
2254
local_path = tree.bzrdir.get_workingtree_transport(None
2255
).local_abspath('dirstate')
2256
state = dirstate.DirState.from_tree(tree, local_path)
2260
def remove_xml_files(self, tree):
2261
"""Remove the oldformat 3 data."""
2262
transport = tree.bzrdir.get_workingtree_transport(None)
2263
for path in ['basis-inventory-cache', 'inventory', 'last-revision',
2264
'pending-merges', 'stat-cache']:
2266
transport.delete(path)
2267
except errors.NoSuchFile:
2268
# some files are optional - just deal.
2271
def update_format(self, tree):
2272
"""Change the format marker."""
2273
tree._transport.put_bytes('format',
2274
self.target_format.get_format_string(),
2275
mode=tree.bzrdir._get_file_mode())
2278
class Converter4to5(object):
2279
"""Perform an in-place upgrade of format 4 to format 5 trees."""
2282
self.target_format = WorkingTreeFormat5()
2284
def convert(self, tree):
2285
# lock the control files not the tree, so that we don't get tree
2286
# on-unlock behaviours, and so that no-one else diddles with the
2287
# tree during upgrade.
2288
tree._control_files.lock_write()
2290
self.update_format(tree)
2292
tree._control_files.unlock()
2294
def update_format(self, tree):
2295
"""Change the format marker."""
2296
tree._transport.put_bytes('format',
2297
self.target_format.get_format_string(),
2298
mode=tree.bzrdir._get_file_mode())
2301
class Converter4or5to6(object):
2302
"""Perform an in-place upgrade of format 4 or 5 to format 6 trees."""
2305
self.target_format = WorkingTreeFormat6()
2307
def convert(self, tree):
2308
# lock the control files not the tree, so that we don't get tree
2309
# on-unlock behaviours, and so that no-one else diddles with the
2310
# tree during upgrade.
2311
tree._control_files.lock_write()
2313
self.init_custom_control_files(tree)
2314
self.update_format(tree)
2316
tree._control_files.unlock()
2318
def init_custom_control_files(self, tree):
2319
"""Initialize custom control files."""
2320
tree._transport.put_bytes('views', '',
2321
mode=tree.bzrdir._get_file_mode())
2323
def update_format(self, tree):
2324
"""Change the format marker."""
2325
tree._transport.put_bytes('format',
2326
self.target_format.get_format_string(),
2327
mode=tree.bzrdir._get_file_mode())