187
187
not listed in the Inventory and vice versa.
190
def __init__(self, basedir='.', branch=None, _inventory=None, _control_files=None, _internal=False):
190
def __init__(self, basedir='.', branch=None, _inventory=None, _control_files=None, _internal=False, _format=None):
191
191
"""Construct a WorkingTree for basedir.
193
193
If the branch is not supplied, it is opened automatically.
195
195
(branch.base is not cross checked, because for remote branches that
196
196
would be meaningless).
198
self._format = _format
198
199
if not _internal:
199
200
# created via open etc.
200
wt = WorkingTree.open(basedir, branch)
201
wt = WorkingTree.open(basedir)
201
202
self.branch = wt.branch
202
203
self.basedir = wt.basedir
203
204
self._control_files = wt._control_files
204
205
self._hashcache = wt._hashcache
205
206
self._set_inventory(wt._inventory)
207
self._format = wt._format
206
208
from bzrlib.hashcache import HashCache
207
209
from bzrlib.trace import note, mutter
208
210
assert isinstance(basedir, basestring), \
216
218
self.branch = branch
217
219
self.basedir = realpath(basedir)
218
220
# if branch is at our basedir and is a format 6 or less
219
if (isinstance(self.branch._format,
221
if (isinstance(self._format, WorkingTreeFormat2)
221
222
# might be able to share control object
222
223
and self.branch.base.split('/')[-2] == self.basedir.split('/')[-1]):
223
224
self._control_files = self.branch.control_files
235
236
# if needed, or, when the cache sees a change, append it to the hash
236
237
# cache file, and have the parser take the most recent entry for a
237
238
# given path only.
238
hc = self._hashcache = HashCache(basedir)
239
hc = self._hashcache = HashCache(basedir, self._control_files._file_mode)
241
# is this scan needed ? it makes things kinda slow.
242
244
if hc.needs_write:
378
380
return self.abspath(self.id2path(file_id))
381
def clone(self, to_directory, revision=None):
382
"""Copy this working tree to a new directory.
383
def clone(self, to_bzrdir, revision_id=None, basis=None):
384
"""Duplicate this working tree into to_bzr, including all state.
384
Currently this will make a new standalone branch at to_directory,
385
but it is planned to change this to use the same branch style that this
386
current tree uses (standalone if standalone, repository if repository)
387
- so that this really is a clone. FIXME RBC 20060127 do this.
388
FIXME MORE RBC 20060127 failed to reach consensus on this in #bzr.
386
Specifically modified files are kept as modified, but
387
ignored and unknown files are discarded.
390
If you want a standalone branch, please use branch.clone(to_directory)
391
followed by WorkingTree.create(cloned_branch, to_directory) which is
392
the supported api to produce that.
389
If you want to make a new line of development, see bzrdir.sprout()
395
392
If not None, the cloned tree will have its last revision set to
396
revision, and if a branch is being copied it will be informed
397
of the revision to result in.
399
to_directory -- The destination directory: Must not exist.
393
revision, and and difference between the source trees last revision
394
and this one merged in.
397
If not None, a closer copy of a tree which may have some files in
398
common, and which file content should be preferentially copied from.
401
to_directory = safe_unicode(to_directory)
402
os.mkdir(to_directory)
403
# FIXME here is where the decision to clone the branch should happen.
405
revision = self.last_revision()
406
cloned_branch = self.branch.clone(to_directory, revision)
407
return WorkingTree.create(cloned_branch, to_directory)
400
# assumes the target bzr dir format is compatible.
401
result = self._format.initialize(to_bzrdir)
402
self.copy_content_into(result, revision_id)
406
def copy_content_into(self, tree, revision_id=None):
407
"""Copy the current content and user files of this tree into tree."""
408
if revision_id is None:
409
transform_tree(tree, self)
411
# TODO now merge from tree.last_revision to revision
412
transform_tree(tree, self)
413
tree.set_last_revision(revision_id)
409
415
@needs_write_lock
410
416
def commit(self, *args, **kwargs):
917
921
def lock_read(self):
918
922
"""See Branch.lock_read, and WorkingTree.unlock."""
919
return self.branch.lock_read()
923
self.branch.lock_read()
925
return self._control_files.lock_read()
921
930
def lock_write(self):
922
931
"""See Branch.lock_write, and WorkingTree.unlock."""
923
return self.branch.lock_write()
932
self.branch.lock_write()
934
return self._control_files.lock_write()
925
939
def _basis_inventory_name(self, revision_id):
926
940
return 'basis-inventory.%s' % revision_id
1070
1084
# of a nasty hack; probably it's better to have a transaction object,
1071
1085
# which can do some finalization when it's either successfully or
1072
1086
# unsuccessfully completed. (Denys's original patch did that.)
1073
if self._hashcache.needs_write and self._control_files._lock_count==1:
1087
# RBC 20060206 hookinhg into transaction will couple lock and transaction
1088
# wrongly. Hookinh into unllock on the control files object is fine though.
1090
# TODO: split this per format so there is no ugly if block
1091
if self._hashcache.needs_write and (
1092
self._control_files._lock_count==1 or
1093
(self._control_files is self.branch.control_files and
1094
self._control_files._lock_count==2)):
1074
1095
self._hashcache.write()
1075
return self.branch.unlock()
1096
# reverse order of locking.
1097
result = self._control_files.unlock()
1099
self.branch.unlock()
1077
1103
@needs_write_lock
1078
1104
def _write_inventory(self, inv):
1184
1210
"""See WorkingTreeFormat.initialize()."""
1185
1211
if not isinstance(a_bzrdir.transport, LocalTransport):
1186
1212
raise errors.NotLocalUrl(a_bzrdir.transport.base)
1187
b = a_bzrdir.open_branch()
1188
r = a_bzrdir.open_repository()
1189
revision = b.last_revision()
1190
basis_tree = r.revision_tree(revision)
1213
branch = a_bzrdir.open_branch()
1214
revision = branch.last_revision()
1215
basis_tree = branch.repository.revision_tree(revision)
1191
1216
inv = basis_tree.inventory
1192
wt = WorkingTree(a_bzrdir.transport.clone('..').base, b, inv, _internal=True)
1217
wt = WorkingTree(a_bzrdir.root_transport.base,
1193
1222
wt._write_inventory(inv)
1194
1223
wt.set_root_id(inv.root.file_id)
1195
1224
wt.set_last_revision(revision)
1196
1225
wt.set_pending_merges([])
1198
1227
wt.bzrdir = a_bzrdir
1202
1230
def __init__(self):
1214
1242
raise NotImplementedError
1215
1243
if not isinstance(a_bzrdir.transport, LocalTransport):
1216
1244
raise errors.NotLocalUrl(a_bzrdir.transport.base)
1217
result = WorkingTree(a_bzrdir.transport.clone('..').base, _internal=True)
1245
result = WorkingTree(a_bzrdir.root_transport.base, _internal=True, _format=self)
1218
1246
result.bzrdir = a_bzrdir
1219
result._format = self
1237
1264
transport = a_bzrdir.get_workingtree_transport(self)
1238
1265
control_files = LockableFiles(transport, 'lock')
1239
1266
control_files.put_utf8('format', self.get_format_string())
1240
b = a_bzrdir.open_branch()
1241
r = a_bzrdir.open_repository()
1242
revision = b.last_revision()
1243
basis_tree = r.revision_tree(revision)
1267
branch = a_bzrdir.open_branch()
1268
revision = branch.last_revision()
1269
basis_tree = branch.repository.revision_tree(revision)
1244
1270
inv = basis_tree.inventory
1245
wt = WorkingTree(a_bzrdir.transport.clone('..').base, b, inv, _internal=True)
1271
wt = WorkingTree(a_bzrdir.root_transport.base,
1246
1276
wt._write_inventory(inv)
1247
1277
wt.set_root_id(inv.root.file_id)
1248
1278
wt.set_last_revision(revision)
1249
1279
wt.set_pending_merges([])
1251
1281
wt.bzrdir = a_bzrdir
1255
1284
def __init__(self):
1267
1296
raise NotImplementedError
1268
1297
if not isinstance(a_bzrdir.transport, LocalTransport):
1269
1298
raise errors.NotLocalUrl(a_bzrdir.transport.base)
1270
result = WorkingTree(a_bzrdir.transport.clone('..').base, _internal=True)
1299
result = WorkingTree(a_bzrdir.root_transport.base, _internal=True, _format=self)
1271
1300
result.bzrdir = a_bzrdir
1272
result._format = self