311
346
XXX: When BzrDir is present, these should be created through that
312
347
interface instead.
317
if e.errno != errno.EEXIST:
320
os.mkdir(pathjoin(directory, '.bzr'))
322
if e.errno != errno.EEXIST:
324
inv = branch.repository.revision_tree(branch.last_revision()).inventory
325
wt = WorkingTree(directory, branch, inv)
326
wt._write_inventory(inv)
327
if branch.last_revision() is not None:
328
wt.set_last_revision(branch.last_revision())
329
wt.set_pending_merges([])
349
warn('delete WorkingTree.create', stacklevel=3)
350
transport = get_transport(directory)
351
if branch.bzrdir.root_transport.base == transport.base:
353
return branch.bzrdir.create_workingtree()
354
# different directory,
355
# create a branch reference
356
# and now a working tree.
357
raise NotImplementedError
360
@deprecated_method(zero_eight)
334
361
def create_standalone(directory):
335
"""Create a checkout and a branch at directory.
362
"""Create a checkout and a branch and a repo at directory.
337
364
Directory must exist and be empty.
339
XXX: When BzrDir is present, these should be created through that
366
please use BzrDir.create_standalone_workingtree
342
directory = safe_unicode(directory)
343
b = Branch.create(directory)
344
return WorkingTree.create(b, directory)
368
return bzrdir.BzrDir.create_standalone_workingtree(directory)
346
370
def relpath(self, abs):
347
371
"""Return the local path portion from a given absolute path."""
365
389
## XXX: badly named; this is not in the store at all
366
390
return self.abspath(self.id2path(file_id))
393
def clone(self, to_bzrdir, revision_id=None, basis=None):
394
"""Duplicate this working tree into to_bzr, including all state.
396
Specifically modified files are kept as modified, but
397
ignored and unknown files are discarded.
399
If you want to make a new line of development, see bzrdir.sprout()
402
If not None, the cloned tree will have its last revision set to
403
revision, and and difference between the source trees last revision
404
and this one merged in.
407
If not None, a closer copy of a tree which may have some files in
408
common, and which file content should be preferentially copied from.
410
# assumes the target bzr dir format is compatible.
411
result = self._format.initialize(to_bzrdir)
412
self.copy_content_into(result, revision_id)
416
def copy_content_into(self, tree, revision_id=None):
417
"""Copy the current content and user files of this tree into tree."""
418
if revision_id is None:
419
transform_tree(tree, self)
421
# TODO now merge from tree.last_revision to revision
422
transform_tree(tree, self)
423
tree.set_last_revision(revision_id)
368
425
@needs_write_lock
369
426
def commit(self, *args, **kwargs):
370
427
from bzrlib.commit import Commit
876
953
if old_revision is not None:
878
955
path = self._basis_inventory_name(old_revision)
879
path = self.branch.control_files._escape(path)
880
self.branch.control_files._transport.delete(path)
956
path = self._control_files._escape(path)
957
self._control_files._transport.delete(path)
881
958
except NoSuchFile:
960
if new_revision is None:
961
self.branch.set_revision_history([])
963
# current format is locked in with the branch
964
revision_history = self.branch.revision_history()
966
position = revision_history.index(new_revision)
968
raise errors.NoSuchRevision(self.branch, new_revision)
969
self.branch.set_revision_history(revision_history[:position + 1])
884
971
xml = self.branch.repository.get_inventory_xml(new_revision)
885
972
path = self._basis_inventory_name(new_revision)
886
self.branch.control_files.put_utf8(path, xml)
973
self._control_files.put_utf8(path, xml)
887
974
except WeaveRevisionNotPresent:
890
977
def read_basis_inventory(self, revision_id):
891
978
"""Read the cached basis inventory."""
892
979
path = self._basis_inventory_name(revision_id)
893
return self.branch.control_files.get_utf8(path).read()
980
return self._control_files.get_utf8(path).read()
896
983
def read_working_inventory(self):
897
984
"""Read the working inventory."""
898
985
# ElementTree does its own conversion from UTF-8, so open in
900
return bzrlib.xml5.serializer_v5.read_inventory(
987
result = bzrlib.xml5.serializer_v5.read_inventory(
901
988
self._control_files.get('inventory'))
989
self._set_inventory(result)
903
992
@needs_write_lock
904
993
def remove(self, files, verbose=False):
1025
1126
for suffix in CONFLICT_SUFFIXES:
1026
1127
if path.endswith(suffix):
1027
1128
return path[:-len(suffix)]
1130
def is_control_file(filename):
1131
## FIXME: better check
1132
filename = normpath(filename)
1133
while filename != '':
1134
head, tail = os.path.split(filename)
1135
## mutter('check %r for control file' % ((head, tail),))
1136
if tail == bzrlib.BZRDIR:
1138
if filename == head:
1144
class WorkingTreeFormat(object):
1145
"""An encapsulation of the initialization and open routines for a format.
1147
Formats provide three things:
1148
* An initialization routine,
1152
Formats are placed in an dict by their format string for reference
1153
during workingtree opening. Its not required that these be instances, they
1154
can be classes themselves with class methods - it simply depends on
1155
whether state is needed for a given format or not.
1157
Once a format is deprecated, just deprecate the initialize and open
1158
methods on the format class. Do not deprecate the object, as the
1159
object will be created every time regardless.
1162
_default_format = None
1163
"""The default format used for new trees."""
1166
"""The known formats."""
1169
def find_format(klass, a_bzrdir):
1170
"""Return the format for the working tree object in a_bzrdir."""
1172
transport = a_bzrdir.get_workingtree_transport(None)
1173
format_string = transport.get("format").read()
1174
return klass._formats[format_string]
1176
raise errors.NotBranchError(path=transport.base)
1178
raise errors.UnknownFormatError(format_string)
1181
def get_default_format(klass):
1182
"""Return the current default format."""
1183
return klass._default_format
1185
def get_format_string(self):
1186
"""Return the ASCII format string that identifies this format."""
1187
raise NotImplementedError(self.get_format_string)
1189
def is_supported(self):
1190
"""Is this format supported?
1192
Supported formats can be initialized and opened.
1193
Unsupported formats may not support initialization or committing or
1194
some other features depending on the reason for not being supported.
1199
def register_format(klass, format):
1200
klass._formats[format.get_format_string()] = format
1203
def set_default_format(klass, format):
1204
klass._default_format = format
1207
def unregister_format(klass, format):
1208
assert klass._formats[format.get_format_string()] is format
1209
del klass._formats[format.get_format_string()]
1213
class WorkingTreeFormat2(WorkingTreeFormat):
1214
"""The second working tree format.
1216
This format modified the hash cache from the format 1 hash cache.
1219
def initialize(self, a_bzrdir):
1220
"""See WorkingTreeFormat.initialize()."""
1221
if not isinstance(a_bzrdir.transport, LocalTransport):
1222
raise errors.NotLocalUrl(a_bzrdir.transport.base)
1223
branch = a_bzrdir.open_branch()
1224
revision = branch.last_revision()
1225
basis_tree = branch.repository.revision_tree(revision)
1226
inv = basis_tree.inventory
1227
wt = WorkingTree(a_bzrdir.root_transport.base,
1233
wt._write_inventory(inv)
1234
wt.set_root_id(inv.root.file_id)
1235
wt.set_last_revision(revision)
1236
wt.set_pending_merges([])
1241
super(WorkingTreeFormat2, self).__init__()
1242
self._matchingbzrdir = bzrdir.BzrDirFormat6()
1244
def open(self, a_bzrdir, _found=False):
1245
"""Return the WorkingTree object for a_bzrdir
1247
_found is a private parameter, do not use it. It is used to indicate
1248
if format probing has already been done.
1251
# we are being called directly and must probe.
1252
raise NotImplementedError
1253
if not isinstance(a_bzrdir.transport, LocalTransport):
1254
raise errors.NotLocalUrl(a_bzrdir.transport.base)
1255
return WorkingTree(a_bzrdir.root_transport.base,
1261
class WorkingTreeFormat3(WorkingTreeFormat):
1262
"""The second working tree format updated to record a format marker.
1264
This format modified the hash cache from the format 1 hash cache.
1267
def get_format_string(self):
1268
"""See WorkingTreeFormat.get_format_string()."""
1269
return "Bazaar-NG Working Tree format 3"
1271
def initialize(self, a_bzrdir):
1272
"""See WorkingTreeFormat.initialize()."""
1273
if not isinstance(a_bzrdir.transport, LocalTransport):
1274
raise errors.NotLocalUrl(a_bzrdir.transport.base)
1275
transport = a_bzrdir.get_workingtree_transport(self)
1276
control_files = LockableFiles(transport, 'lock')
1277
control_files.put_utf8('format', self.get_format_string())
1278
branch = a_bzrdir.open_branch()
1279
revision = branch.last_revision()
1280
basis_tree = branch.repository.revision_tree(revision)
1281
inv = basis_tree.inventory
1282
wt = WorkingTree(a_bzrdir.root_transport.base,
1288
wt._write_inventory(inv)
1289
wt.set_root_id(inv.root.file_id)
1290
wt.set_last_revision(revision)
1291
wt.set_pending_merges([])
1296
super(WorkingTreeFormat3, self).__init__()
1297
self._matchingbzrdir = bzrdir.BzrDirMetaFormat1()
1299
def open(self, a_bzrdir, _found=False):
1300
"""Return the WorkingTree object for a_bzrdir
1302
_found is a private parameter, do not use it. It is used to indicate
1303
if format probing has already been done.
1306
# we are being called directly and must probe.
1307
raise NotImplementedError
1308
if not isinstance(a_bzrdir.transport, LocalTransport):
1309
raise errors.NotLocalUrl(a_bzrdir.transport.base)
1310
return WorkingTree(a_bzrdir.root_transport.base,
1316
# formats which have no format string are not discoverable
1317
# and not independently creatable, so are not registered.
1318
__default_format = WorkingTreeFormat3()
1319
WorkingTreeFormat.register_format(__default_format)
1320
WorkingTreeFormat.set_default_format(__default_format)
1321
_legacy_formats = [WorkingTreeFormat2(),
1325
class WorkingTreeTestProviderAdapter(object):
1326
"""A tool to generate a suite testing multiple workingtree formats at once.
1328
This is done by copying the test once for each transport and injecting
1329
the transport_server, transport_readonly_server, and workingtree_format
1330
classes into each copy. Each copy is also given a new id() to make it
1334
def __init__(self, transport_server, transport_readonly_server, formats):
1335
self._transport_server = transport_server
1336
self._transport_readonly_server = transport_readonly_server
1337
self._formats = formats
1339
def adapt(self, test):
1340
from bzrlib.tests import TestSuite
1341
result = TestSuite()
1342
for workingtree_format, bzrdir_format in self._formats:
1343
new_test = deepcopy(test)
1344
new_test.transport_server = self._transport_server
1345
new_test.transport_readonly_server = self._transport_readonly_server
1346
new_test.bzrdir_format = bzrdir_format
1347
new_test.workingtree_format = workingtree_format
1348
def make_new_test_id():
1349
new_id = "%s(%s)" % (new_test.id(), workingtree_format.__class__.__name__)
1350
return lambda: new_id
1351
new_test.id = make_new_test_id()
1352
result.addTest(new_test)