575
536
# TODO now merge from tree.last_revision to revision (to preserve
576
537
# user local changes)
577
merge.transform_tree(tree, self)
578
tree.set_parent_ids([revision_id])
539
other_tree = self.revision_tree(revision_id)
540
except errors.NoSuchRevision:
541
other_tree = self.branch.repository.revision_tree(revision_id)
543
merge.transform_tree(tree, other_tree)
544
if revision_id == _mod_revision.NULL_REVISION:
547
new_parents = [revision_id]
548
tree.set_parent_ids(new_parents)
580
550
def id2abspath(self, file_id):
581
551
return self.abspath(self.id2path(file_id))
553
def _check_for_tree_references(self, iterator):
554
"""See if directories have become tree-references."""
555
blocked_parent_ids = set()
556
for path, ie in iterator:
557
if ie.parent_id in blocked_parent_ids:
558
# This entry was pruned because one of its parents became a
559
# TreeReference. If this is a directory, mark it as blocked.
560
if ie.kind == 'directory':
561
blocked_parent_ids.add(ie.file_id)
563
if ie.kind == 'directory' and self._directory_is_tree_reference(path):
564
# This InventoryDirectory needs to be a TreeReference
565
ie = inventory.TreeReference(ie.file_id, ie.name, ie.parent_id)
566
blocked_parent_ids.add(ie.file_id)
569
def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):
570
"""See Tree.iter_entries_by_dir()"""
571
# The only trick here is that if we supports_tree_reference then we
572
# need to detect if a directory becomes a tree-reference.
573
iterator = super(WorkingTree, self).iter_entries_by_dir(
574
specific_file_ids=specific_file_ids,
575
yield_parents=yield_parents)
576
if not self.supports_tree_reference():
579
return self._check_for_tree_references(iterator)
583
581
def get_file_size(self, file_id):
584
582
"""See Tree.get_file_size"""
585
583
# XXX: this returns the on-disk size; it should probably return the
2115
2209
mode=self.bzrdir._get_file_mode())
2116
2210
self._inventory_is_modified = False
2119
def get_file_sha1(self, file_id, path=None, stat_value=None):
2121
path = self._inventory.id2path(file_id)
2122
return self._hashcache.get_sha1(path, stat_value)
2124
2212
def get_file_mtime(self, file_id, path=None):
2125
2213
"""See Tree.get_file_mtime."""
2127
path = self.inventory.id2path(file_id)
2128
return os.lstat(self.abspath(path)).st_mtime
2215
path = self.id2path(file_id)
2217
return os.lstat(self.abspath(path)).st_mtime
2219
if e.errno == errno.ENOENT:
2220
raise errors.FileTimestampUnavailable(path)
2130
2223
def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
2131
file_id = self.path2id(path)
2224
inv, file_id = self._path2inv_file_id(path)
2132
2225
if file_id is None:
2133
2226
# For unversioned files on win32, we just assume they are not
2136
return self._inventory[file_id].executable
2229
return inv[file_id].executable
2138
2231
def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
2139
2232
mode = stat_result.st_mode
2140
2233
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
2142
if not supports_executable():
2143
def is_executable(self, file_id, path=None):
2144
return self._inventory[file_id].executable
2146
_is_executable_from_path_and_stat = \
2147
_is_executable_from_path_and_stat_from_basis
2149
def is_executable(self, file_id, path=None):
2235
def is_executable(self, file_id, path=None):
2236
if not self._supports_executable():
2237
inv, inv_file_id = self._unpack_file_id(file_id)
2238
return inv[inv_file_id].executable
2151
2241
path = self.id2path(file_id)
2152
2242
mode = os.lstat(self.abspath(path)).st_mode
2153
2243
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
2155
_is_executable_from_path_and_stat = \
2156
_is_executable_from_path_and_stat_from_stat
2245
def _is_executable_from_path_and_stat(self, path, stat_result):
2246
if not self._supports_executable():
2247
return self._is_executable_from_path_and_stat_from_basis(path, stat_result)
2249
return self._is_executable_from_path_and_stat_from_stat(path, stat_result)
2158
2251
@needs_tree_write_lock
2159
2252
def _add(self, files, ids, kinds):
2887
3018
if dir[2] == _directory:
2888
3019
pending.append(dir)
2891
class WorkingTree3(InventoryWorkingTree):
2892
"""This is the Format 3 working tree.
2894
This differs from the base WorkingTree by:
2895
- having its own file lock
2896
- having its own last-revision property.
2898
This is new in bzr 0.8
2902
def _last_revision(self):
2903
"""See Mutable.last_revision."""
2905
return self._transport.get_bytes('last-revision')
2906
except errors.NoSuchFile:
2907
return _mod_revision.NULL_REVISION
2909
def _change_last_revision(self, revision_id):
2910
"""See WorkingTree._change_last_revision."""
2911
if revision_id is None or revision_id == _mod_revision.NULL_REVISION:
2913
self._transport.delete('last-revision')
2914
except errors.NoSuchFile:
2918
self._transport.put_bytes('last-revision', revision_id,
2919
mode=self.bzrdir._get_file_mode())
2922
def _get_check_refs(self):
2923
"""Return the references needed to perform a check of this tree."""
2924
return [('trees', self.last_revision())]
2926
@needs_tree_write_lock
2927
def set_conflicts(self, conflicts):
2928
self._put_rio('conflicts', conflicts.to_stanzas(),
2931
@needs_tree_write_lock
2932
def add_conflicts(self, new_conflicts):
2933
conflict_set = set(self.conflicts())
2934
conflict_set.update(set(list(new_conflicts)))
2935
self.set_conflicts(_mod_conflicts.ConflictList(sorted(conflict_set,
2936
key=_mod_conflicts.Conflict.sort_key)))
2939
def conflicts(self):
2941
confile = self._transport.get('conflicts')
2942
except errors.NoSuchFile:
2943
return _mod_conflicts.ConflictList()
2946
if confile.next() != CONFLICT_HEADER_1 + '\n':
2947
raise errors.ConflictFormatError()
2948
except StopIteration:
2949
raise errors.ConflictFormatError()
2950
reader = _mod_rio.RioReader(confile)
2951
return _mod_conflicts.ConflictList.from_stanzas(reader)
2956
# do non-implementation specific cleanup
2958
if self._control_files._lock_count == 1:
2959
# _inventory_is_modified is always False during a read lock.
2960
if self._inventory_is_modified:
2962
self._write_hashcache_if_dirty()
2963
# reverse order of locking.
2965
return self._control_files.unlock()
2967
self.branch.unlock()
3022
def update_feature_flags(self, updated_flags):
3023
"""Update the feature flags for this branch.
3025
:param updated_flags: Dictionary mapping feature names to necessities
3026
A necessity can be None to indicate the feature should be removed
3028
self._format._update_feature_flags(updated_flags)
3029
self.control_transport.put_bytes('format', self._format.as_string())
2970
3032
class WorkingTreeFormatRegistry(controldir.ControlComponentFormatRegistry):
3082
3133
"""True if this format supports stored views."""
3086
@symbol_versioning.deprecated_method(
3087
symbol_versioning.deprecated_in((2, 4, 0)))
3088
def register_format(klass, format):
3089
format_registry.register(format)
3092
@symbol_versioning.deprecated_method(
3093
symbol_versioning.deprecated_in((2, 4, 0)))
3094
def register_extra_format(klass, format):
3095
format_registry.register_extra(format)
3098
@symbol_versioning.deprecated_method(
3099
symbol_versioning.deprecated_in((2, 4, 0)))
3100
def unregister_extra_format(klass, format):
3101
format_registry.unregister_extra(format)
3104
@symbol_versioning.deprecated_method(
3105
symbol_versioning.deprecated_in((2, 4, 0)))
3106
def get_formats(klass):
3107
return format_registry._get_all()
3110
@symbol_versioning.deprecated_method(
3111
symbol_versioning.deprecated_in((2, 4, 0)))
3112
def set_default_format(klass, format):
3113
format_registry.set_default(format)
3116
@symbol_versioning.deprecated_method(
3117
symbol_versioning.deprecated_in((2, 4, 0)))
3118
def unregister_format(klass, format):
3119
format_registry.remove(format)
3122
class WorkingTreeFormat3(WorkingTreeFormat):
3123
"""The second working tree format updated to record a format marker.
3126
- exists within a metadir controlling .bzr
3127
- includes an explicit version marker for the workingtree control
3128
files, separate from the BzrDir format
3129
- modifies the hash cache format
3131
- uses a LockDir to guard access for writes.
3134
upgrade_recommended = True
3136
missing_parent_conflicts = True
3138
def get_format_string(self):
3139
"""See WorkingTreeFormat.get_format_string()."""
3140
return "Bazaar-NG Working Tree format 3"
3142
def get_format_description(self):
3143
"""See WorkingTreeFormat.get_format_description()."""
3144
return "Working tree format 3"
3146
_lock_file_name = 'lock'
3147
_lock_class = LockDir
3149
_tree_class = WorkingTree3
3151
def __get_matchingbzrdir(self):
3152
return bzrdir.BzrDirMetaFormat1()
3154
_matchingbzrdir = property(__get_matchingbzrdir)
3156
def _open_control_files(self, a_bzrdir):
3157
transport = a_bzrdir.get_workingtree_transport(None)
3158
return LockableFiles(transport, self._lock_file_name,
3161
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
3162
accelerator_tree=None, hardlink=False):
3163
"""See WorkingTreeFormat.initialize().
3165
:param revision_id: if supplied, create a working tree at a different
3166
revision than the branch is at.
3167
:param accelerator_tree: A tree which can be used for retrieving file
3168
contents more quickly than the revision tree, i.e. a workingtree.
3169
The revision tree will be used for cases where accelerator_tree's
3170
content is different.
3171
:param hardlink: If true, hard-link files from accelerator_tree,
3174
if not isinstance(a_bzrdir.transport, LocalTransport):
3175
raise errors.NotLocalUrl(a_bzrdir.transport.base)
3176
transport = a_bzrdir.get_workingtree_transport(self)
3177
control_files = self._open_control_files(a_bzrdir)
3178
control_files.create_lock()
3179
control_files.lock_write()
3180
transport.put_bytes('format', self.get_format_string(),
3181
mode=a_bzrdir._get_file_mode())
3182
if from_branch is not None:
3183
branch = from_branch
3185
branch = a_bzrdir.open_branch()
3186
if revision_id is None:
3187
revision_id = _mod_revision.ensure_null(branch.last_revision())
3188
# WorkingTree3 can handle an inventory which has a unique root id.
3189
# as of bzr 0.12. However, bzr 0.11 and earlier fail to handle
3190
# those trees. And because there isn't a format bump inbetween, we
3191
# are maintaining compatibility with older clients.
3192
# inv = Inventory(root_id=gen_root_id())
3193
inv = self._initial_inventory()
3194
wt = self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
3200
_control_files=control_files)
3201
wt.lock_tree_write()
3203
basis_tree = branch.repository.revision_tree(revision_id)
3204
# only set an explicit root id if there is one to set.
3205
if basis_tree.inventory.root is not None:
3206
wt.set_root_id(basis_tree.get_root_id())
3207
if revision_id == _mod_revision.NULL_REVISION:
3208
wt.set_parent_trees([])
3210
wt.set_parent_trees([(revision_id, basis_tree)])
3211
transform.build_tree(basis_tree, wt)
3213
# Unlock in this order so that the unlock-triggers-flush in
3214
# WorkingTree is given a chance to fire.
3215
control_files.unlock()
3219
def _initial_inventory(self):
3220
return inventory.Inventory()
3223
super(WorkingTreeFormat3, self).__init__()
3225
def open(self, a_bzrdir, _found=False):
3226
"""Return the WorkingTree object for a_bzrdir
3228
_found is a private parameter, do not use it. It is used to indicate
3229
if format probing has already been done.
3232
# we are being called directly and must probe.
3233
raise NotImplementedError
3234
if not isinstance(a_bzrdir.transport, LocalTransport):
3235
raise errors.NotLocalUrl(a_bzrdir.transport.base)
3236
wt = self._open(a_bzrdir, self._open_control_files(a_bzrdir))
3239
def _open(self, a_bzrdir, control_files):
3240
"""Open the tree itself.
3242
:param a_bzrdir: the dir for the tree.
3243
:param control_files: the control files for the tree.
3245
return self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
3249
_control_files=control_files)
3252
return self.get_format_string()
3255
__default_format = WorkingTreeFormat6()
3136
def get_controldir_for_branch(self):
3137
"""Get the control directory format for creating branches.
3139
This is to support testing of working tree formats that can not exist
3140
in the same control directory as a branch.
3142
return self._matchingbzrdir
3145
class WorkingTreeFormatMetaDir(bzrdir.BzrFormat, WorkingTreeFormat):
3146
"""Base class for working trees that live in bzr meta directories."""
3149
WorkingTreeFormat.__init__(self)
3150
bzrdir.BzrFormat.__init__(self)
3153
def find_format_string(klass, controldir):
3154
"""Return format name for the working tree object in controldir."""
3156
transport = controldir.get_workingtree_transport(None)
3157
return transport.get_bytes("format")
3158
except errors.NoSuchFile:
3159
raise errors.NoWorkingTree(base=transport.base)
3162
def find_format(klass, controldir):
3163
"""Return the format for the working tree object in controldir."""
3164
format_string = klass.find_format_string(controldir)
3165
return klass._find_format(format_registry, 'working tree',
3168
def check_support_status(self, allow_unsupported, recommend_upgrade=True,
3170
WorkingTreeFormat.check_support_status(self,
3171
allow_unsupported=allow_unsupported, recommend_upgrade=recommend_upgrade,
3173
bzrdir.BzrFormat.check_support_status(self, allow_unsupported=allow_unsupported,
3174
recommend_upgrade=recommend_upgrade, basedir=basedir)
3176
def get_controldir_for_branch(self):
3177
"""Get the control directory format for creating branches.
3179
This is to support testing of working tree formats that can not exist
3180
in the same control directory as a branch.
3182
return self._matchingbzrdir
3185
class WorkingTreeFormatMetaDir(bzrdir.BzrFormat, WorkingTreeFormat):
3186
"""Base class for working trees that live in bzr meta directories."""
3189
WorkingTreeFormat.__init__(self)
3190
bzrdir.BzrFormat.__init__(self)
3193
def find_format_string(klass, controldir):
3194
"""Return format name for the working tree object in controldir."""
3196
transport = controldir.get_workingtree_transport(None)
3197
return transport.get_bytes("format")
3198
except errors.NoSuchFile:
3199
raise errors.NoWorkingTree(base=transport.base)
3202
def find_format(klass, controldir):
3203
"""Return the format for the working tree object in controldir."""
3204
format_string = klass.find_format_string(controldir)
3205
return klass._find_format(format_registry, 'working tree',
3208
def check_support_status(self, allow_unsupported, recommend_upgrade=True,
3210
WorkingTreeFormat.check_support_status(self,
3211
allow_unsupported=allow_unsupported, recommend_upgrade=recommend_upgrade,
3213
bzrdir.BzrFormat.check_support_status(self, allow_unsupported=allow_unsupported,
3214
recommend_upgrade=recommend_upgrade, basedir=basedir)
3256
3217
format_registry.register_lazy("Bazaar Working Tree Format 4 (bzr 0.15)\n",
3257
3218
"bzrlib.workingtree_4", "WorkingTreeFormat4")
3258
3219
format_registry.register_lazy("Bazaar Working Tree Format 5 (bzr 1.11)\n",
3259
3220
"bzrlib.workingtree_4", "WorkingTreeFormat5")
3260
3221
format_registry.register_lazy("Bazaar Working Tree Format 6 (bzr 1.14)\n",
3261
3222
"bzrlib.workingtree_4", "WorkingTreeFormat6")
3262
format_registry.register(WorkingTreeFormat3())
3263
format_registry.set_default(__default_format)
3223
format_registry.register_lazy("Bazaar-NG Working Tree format 3",
3224
"bzrlib.workingtree_3", "WorkingTreeFormat3")
3225
format_registry.set_default_key("Bazaar Working Tree Format 6 (bzr 1.14)\n")