23
# TODO: remove unittest dependency; put that stuff inside the test suite
25
23
from copy import deepcopy
26
25
from cStringIO import StringIO
28
from stat import S_ISDIR
29
26
from unittest import TestSuite
32
29
import bzrlib.errors as errors
33
from bzrlib.lockable_files import LockableFiles, TransportLock
34
from bzrlib.lockdir import LockDir
30
from bzrlib.lockable_files import LockableFiles
31
from bzrlib.osutils import safe_unicode
35
32
from bzrlib.osutils import (
42
from bzrlib.store.revision.text import TextRevisionStore
43
39
from bzrlib.store.text import TextStore
44
from bzrlib.store.versioned import WeaveStore
40
from bzrlib.store.weave import WeaveStore
41
from bzrlib.symbol_versioning import *
45
42
from bzrlib.trace import mutter
46
from bzrlib.transactions import WriteTransaction
43
from bzrlib.transactions import PassThroughTransaction
47
44
from bzrlib.transport import get_transport
48
45
from bzrlib.transport.local import LocalTransport
49
import bzrlib.urlutils as urlutils
50
46
from bzrlib.weave import Weave
47
from bzrlib.weavefile import read_weave, write_weave
51
48
from bzrlib.xml4 import serializer_v4
49
from bzrlib.xml5 import serializer_v5
55
52
class BzrDir(object):
64
61
a transport connected to the directory this bzr was opened from.
68
"""Invoke break_lock on the first object in the bzrdir.
70
If there is a tree, the tree is opened and break_lock() called.
71
Otherwise, branch is tried, and finally repository.
74
thing_to_unlock = self.open_workingtree()
75
except (errors.NotLocalUrl, errors.NoWorkingTree):
77
thing_to_unlock = self.open_branch()
78
except errors.NotBranchError:
80
thing_to_unlock = self.open_repository()
81
except errors.NoRepositoryPresent:
83
thing_to_unlock.break_lock()
85
64
def can_convert_format(self):
86
65
"""Return true if this bzrdir is one whose format we can convert from."""
90
def _check_supported(format, allow_unsupported):
68
def _check_supported(self, format, allow_unsupported):
91
69
"""Check whether format is a supported format.
93
71
If allow_unsupported is True, this is a no-op.
95
73
if not allow_unsupported and not format.is_supported():
96
# see open_downlevel to open legacy branches.
97
raise errors.UnsupportedFormatError(format=format)
74
raise errors.UnsupportedFormatError(format)
99
76
def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
100
77
"""Clone this bzrdir and its contents to url verbatim.
132
105
result_repo.fetch(local_repo, revision_id=revision_id)
133
106
except errors.NoRepositoryPresent:
134
107
# needed to make one anyway.
135
result_repo = local_repo.clone(
137
revision_id=revision_id,
139
result_repo.set_make_working_trees(local_repo.make_working_trees())
108
local_repo.clone(result, revision_id=revision_id, basis=basis_repo)
140
109
# 1 if there is a branch present
141
110
# make sure its content is available in the target repository
171
140
basis_repo = None
172
141
return basis_repo, basis_branch, basis_tree
174
# TODO: This should be given a Transport, and should chdir up; otherwise
175
# this will open a new connection.
176
143
def _make_tail(self, url):
177
head, tail = urlutils.split(url)
178
if tail and tail != '.':
179
t = bzrlib.transport.get_transport(head)
144
segments = url.split('/')
145
if segments and segments[-1] not in ('', '.'):
146
parent = '/'.join(segments[:-1])
147
t = bzrlib.transport.get_transport(parent)
149
t.mkdir(segments[-1])
182
150
except errors.FileExists:
185
# TODO: Should take a Transport
187
def create(cls, base):
188
155
"""Create a new BzrDir at the url 'base'.
190
157
This will call the current default formats initialize with base
193
160
If you need a specific format, consider creating an instance
194
161
of that and calling initialize().
196
if cls is not BzrDir:
197
raise AssertionError("BzrDir.create always creates the default format, "
198
"not one of %r" % cls)
199
head, tail = urlutils.split(base)
200
if tail and tail != '.':
201
t = bzrlib.transport.get_transport(head)
163
segments = base.split('/')
164
if segments and segments[-1] not in ('', '.'):
165
parent = '/'.join(segments[:-1])
166
t = bzrlib.transport.get_transport(parent)
168
t.mkdir(segments[-1])
204
169
except errors.FileExists:
206
171
return BzrDirFormat.get_default_format().initialize(safe_unicode(base))
241
206
return self.create_repository()
244
def create_branch_convenience(base, force_new_repo=False,
245
force_new_tree=None, format=None):
209
def create_branch_convenience(base, force_new_repo=False, force_new_tree=None):
246
210
"""Create a new BzrDir, Branch and Repository at the url 'base'.
248
212
This is a convenience function - it will use an existing repository
264
228
:param force_new_repo: If True a new repository is always created.
265
229
:param force_new_tree: If True or False force creation of a tree or
266
230
prevent such creation respectively.
267
:param format: Override for the for the bzrdir format to create
269
232
if force_new_tree:
270
233
# check for non local urls
271
234
t = get_transport(safe_unicode(base))
272
235
if not isinstance(t, LocalTransport):
273
236
raise errors.NotLocalUrl(base)
275
bzrdir = BzrDir.create(base)
277
bzrdir = format.initialize(base)
237
bzrdir = BzrDir.create(base)
278
238
repo = bzrdir._find_or_create_repository(force_new_repo)
279
239
result = bzrdir.create_branch()
280
240
if force_new_tree or (repo.make_working_trees() and
343
303
next_transport = self.root_transport.clone('..')
345
# find the next containing bzrdir
347
306
found_bzrdir = BzrDir.open_containing_from_transport(
348
307
next_transport)[0]
349
308
except errors.NotBranchError:
351
309
raise errors.NoRepositoryPresent(self)
352
# does it have a repository ?
354
311
repository = found_bzrdir.open_repository()
355
312
except errors.NoRepositoryPresent:
356
313
next_transport = found_bzrdir.root_transport.clone('..')
357
if (found_bzrdir.root_transport.base == next_transport.base):
358
# top of the file system
362
315
if ((found_bzrdir.root_transport.base ==
363
316
self.root_transport.base) or repository.is_shared()):
364
317
return repository
418
371
self.transport = _transport.clone('.bzr')
419
372
self.root_transport = _transport
421
def is_control_filename(self, filename):
422
"""True if filename is the name of a path which is reserved for bzrdir's.
424
:param filename: A filename within the root transport of this bzrdir.
426
This is true IF and ONLY IF the filename is part of the namespace reserved
427
for bzr control dirs. Currently this is the '.bzr' directory in the root
428
of the root_transport. it is expected that plugins will need to extend
429
this in the future - for instance to make bzr talk with svn working
432
# this might be better on the BzrDirFormat class because it refers to
433
# all the possible bzrdir disk formats.
434
# This method is tested via the workingtree is_control_filename tests-
435
# it was extracted from WorkingTree.is_control_filename. If the methods
436
# contract is extended beyond the current trivial implementation please
437
# add new tests for it to the appropriate place.
438
return filename == '.bzr' or filename.startswith('.bzr/')
440
374
def needs_format_conversion(self, format=None):
441
375
"""Return true if this bzrdir needs convert_format run on it.
462
396
t = get_transport(base)
463
397
mutter("trying to open %r with transport %r", base, t)
464
398
format = BzrDirFormat.find_format(t)
465
BzrDir._check_supported(format, _unsupported)
399
if not _unsupported and not format.is_supported():
400
# see open_downlevel to open legacy branches.
401
raise errors.UnsupportedFormatError(
402
'sorry, format %s not supported' % format,
403
['use a different bzr version',
404
'or remove the .bzr directory'
405
' and "bzr init" again'])
466
406
return format.open(t, _found=True)
468
408
def open_branch(self, unsupported=False):
495
435
If there is one and it is either an unrecognised format or an unsupported
496
436
format, UnknownFormatError or UnsupportedFormatError are raised.
497
437
If there is one, it is returned, along with the unused portion of url.
499
:return: The BzrDir that contains the path, and a Unicode path
500
for the rest of the URL.
502
439
# this gets the normalised url back. I.e. '.' -> the full path.
503
440
url = a_transport.base
506
443
format = BzrDirFormat.find_format(a_transport)
507
BzrDir._check_supported(format, False)
508
return format.open(a_transport), urlutils.unescape(a_transport.relpath(url))
444
return format.open(a_transport), a_transport.relpath(url)
509
445
except errors.NotBranchError, e:
510
## mutter('not a branch in: %r %s', a_transport.base, e)
446
mutter('not a branch in: %r %s', a_transport.base, e)
512
447
new_t = a_transport.clone('..')
513
448
if new_t.base == a_transport.base:
514
449
# reached the root, whatever that may be
535
470
raise NotImplementedError(self.open_workingtree)
537
def has_branch(self):
538
"""Tell if this bzrdir contains a branch.
540
Note: if you're going to open the branch, you should just go ahead
541
and try, and not ask permission first. (This method just opens the
542
branch and discards it, and that's somewhat expensive.)
547
except errors.NotBranchError:
550
def has_workingtree(self):
551
"""Tell if this bzrdir contains a working tree.
553
This will still raise an exception if the bzrdir has a workingtree that
554
is remote & inaccessible.
556
Note: if you're going to open the working tree, you should just go ahead
557
and try, and not ask permission first. (This method just opens the
558
workingtree and discards it, and that's somewhat expensive.)
561
self.open_workingtree()
563
except errors.NoWorkingTree:
566
472
def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
567
473
"""Create a copy of this bzrdir prepared for use as a new line of
604
510
# no repo available, make a new one
605
511
result.create_repository()
606
512
elif source_repository is not None and result_repo is None:
607
# have source, and want to make a new target repo
608
# we don't clone the repo because that preserves attributes
609
# like is_shared(), and we have not yet implemented a
610
# repository sprout().
611
result_repo = result.create_repository()
612
if result_repo is not None:
513
# have soure, and want to make a new target repo
514
source_repository.clone(result,
515
revision_id=revision_id,
613
518
# fetch needed content into target.
615
520
# XXX FIXME RBC 20060214 need tests for this when the basis
633
540
def __init__(self, _transport, _format):
634
541
"""See BzrDir.__init__."""
635
542
super(BzrDirPreSplitOut, self).__init__(_transport, _format)
636
assert self._format._lock_class == TransportLock
637
assert self._format._lock_file_name == 'branch-lock'
638
543
self._control_files = LockableFiles(self.get_branch_transport(None),
639
self._format._lock_file_name,
640
self._format._lock_class)
642
def break_lock(self):
643
"""Pre-splitout bzrdirs do not suffer from stale locks."""
644
raise NotImplementedError(self.break_lock)
646
546
def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
647
547
"""See BzrDir.clone()."""
648
548
from bzrlib.workingtree import WorkingTreeFormat2
649
549
self._make_tail(url)
650
result = self._format._initialize_for_clone(url)
550
result = self._format.initialize(url, _cloning=True)
651
551
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
652
552
self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
653
from_branch = self.open_branch()
654
from_branch.clone(result, revision_id=revision_id)
553
self.open_branch().clone(result, revision_id=revision_id)
656
555
self.open_workingtree().clone(result, basis=basis_tree)
657
556
except errors.NotLocalUrl:
658
557
# make a new one, this format always has to have one.
660
WorkingTreeFormat2().initialize(result)
661
except errors.NotLocalUrl:
662
# but we cannot do it for remote trees.
663
to_branch = result.open_branch()
664
WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
558
WorkingTreeFormat2().initialize(result)
667
561
def create_branch(self):
747
641
self.open_branch().sprout(result, revision_id=revision_id)
748
642
except errors.NotBranchError:
750
# we always want a working tree
751
WorkingTreeFormat2().initialize(result)
645
self.open_workingtree().clone(result, basis=basis_tree)
646
except (errors.NotBranchError, errors.NotLocalUrl):
647
# we always want a working tree
648
WorkingTreeFormat2().initialize(result)
833
728
from bzrlib.workingtree import WorkingTreeFormat
834
729
return WorkingTreeFormat.get_default_format().initialize(self, revision_id)
836
def _get_mkdir_mode(self):
837
"""Figure out the mode to use when creating a bzrdir subdir."""
838
temp_control = LockableFiles(self.transport, '', TransportLock)
839
return temp_control._dir_mode
841
731
def get_branch_transport(self, branch_format):
842
732
"""See BzrDir.get_branch_transport()."""
843
733
if branch_format is None:
944
834
"""The known formats."""
946
_control_formats = []
947
"""The registered control formats - .bzr, ....
949
This is a list of BzrDirFormat objects.
952
_lock_file_name = 'branch-lock'
954
# _lock_class must be set in subclasses to the lock type, typ.
955
# TransportLock or LockDir
958
837
def find_format(klass, transport):
959
"""Return the format present at transport."""
960
for format in klass._control_formats:
962
return format.probe_transport(transport)
963
except errors.NotBranchError:
964
# this format does not find a control dir here.
966
raise errors.NotBranchError(path=transport.base)
969
def probe_transport(klass, transport):
970
"""Return the .bzrdir style transport present at URL."""
838
"""Return the format registered for URL."""
972
840
format_string = transport.get(".bzr/branch-format").read()
841
return klass._formats[format_string]
973
842
except errors.NoSuchFile:
974
843
raise errors.NotBranchError(path=transport.base)
977
return klass._formats[format_string]
979
raise errors.UnknownFormatError(format=format_string)
845
raise errors.UnknownFormatError(format_string)
982
848
def get_default_format(klass):
987
853
"""Return the ASCII format string that identifies this format."""
988
854
raise NotImplementedError(self.get_format_string)
990
def get_format_description(self):
991
"""Return the short description for this format."""
992
raise NotImplementedError(self.get_format_description)
994
856
def get_converter(self, format=None):
995
857
"""Return the converter to use to convert bzrdirs needing converts.
997
859
This returns a bzrlib.bzrdir.Converter object.
999
861
This should return the best upgrader to step this format towards the
1000
current default format. In the case of plugins we can/should provide
862
current default format. In the case of plugins we can/shouold provide
1001
863
some means for them to extend the range of returnable converters.
1003
:param format: Optional format to override the default format of the
865
:param format: Optional format to override the default foramt of the
1006
868
raise NotImplementedError(self.get_converter)
1008
870
def initialize(self, url):
1009
"""Create a bzr control dir at this url and return an opened copy.
1011
Subclasses should typically override initialize_on_transport
1012
instead of this method.
1014
return self.initialize_on_transport(get_transport(url))
1016
def initialize_on_transport(self, transport):
1017
"""Initialize a new bzrdir in the base directory of a Transport."""
871
"""Create a bzr control dir at this url and return an opened copy."""
1018
872
# Since we don't have a .bzr directory, inherit the
1019
873
# mode from the root directory
1020
temp_control = LockableFiles(transport, '', TransportLock)
874
t = get_transport(url)
875
temp_control = LockableFiles(t, '')
1021
876
temp_control._transport.mkdir('.bzr',
1022
# FIXME: RBC 20060121 don't peek under
877
# FIXME: RBC 20060121 dont peek under
1024
879
mode=temp_control._dir_mode)
1025
880
file_mode = temp_control._file_mode
1026
881
del temp_control
1027
mutter('created control directory in ' + transport.base)
1028
control = transport.clone('.bzr')
882
mutter('created control directory in ' + t.base)
883
control = t.clone('.bzr')
884
lock_file = 'branch-lock'
1029
885
utf8_files = [('README',
1030
886
"This is a Bazaar-NG control directory.\n"
1031
887
"Do not change any files in this directory.\n"),
1032
888
('branch-format', self.get_format_string()),
1034
890
# NB: no need to escape relative paths that are url safe.
1035
control_files = LockableFiles(control, self._lock_file_name,
1037
control_files.create_lock()
891
control.put(lock_file, StringIO(), mode=file_mode)
892
control_files = LockableFiles(control, lock_file)
1038
893
control_files.lock_write()
1040
895
for file, content in utf8_files:
1041
896
control_files.put_utf8(file, content)
1043
898
control_files.unlock()
1044
return self.open(transport, _found=True)
899
return self.open(t, _found=True)
1046
901
def is_supported(self):
1047
902
"""Is this format supported?
1056
def known_formats(klass):
1057
"""Return all the known formats.
1059
Concrete formats should override _known_formats.
1061
# There is double indirection here to make sure that control
1062
# formats used by more than one dir format will only be probed
1063
# once. This can otherwise be quite expensive for remote connections.
1065
for format in klass._control_formats:
1066
result.update(format._known_formats())
1070
def _known_formats(klass):
1071
"""Return the known format instances for this control format."""
1072
return set(klass._formats.values())
1074
910
def open(self, transport, _found=False):
1075
911
"""Return an instance of this format for the dir transport points at.
1094
930
klass._formats[format.get_format_string()] = format
1097
def register_control_format(klass, format):
1098
"""Register a format that does not use '.bzrdir' for its control dir.
1100
TODO: This should be pulled up into a 'ControlDirFormat' base class
1101
which BzrDirFormat can inherit from, and renamed to register_format
1102
there. It has been done without that for now for simplicity of
1105
klass._control_formats.append(format)
1108
933
def set_default_format(klass, format):
1109
934
klass._default_format = format
1138
955
removed in format 5; write support for this format has been removed.
1141
_lock_class = TransportLock
1143
958
def get_format_string(self):
1144
959
"""See BzrDirFormat.get_format_string()."""
1145
960
return "Bazaar-NG branch, format 0.0.4\n"
1147
def get_format_description(self):
1148
"""See BzrDirFormat.get_format_description()."""
1149
return "All-in-one format 4"
1151
962
def get_converter(self, format=None):
1152
963
"""See BzrDirFormat.get_converter()."""
1153
964
# there is one and only one upgrade path here.
1154
965
return ConvertBzrDir4To5()
1156
def initialize_on_transport(self, transport):
967
def initialize(self, url):
1157
968
"""Format 4 branches cannot be created."""
1158
969
raise errors.UninitializableFormat(self)
1188
999
Unhashed stores in the repository.
1191
_lock_class = TransportLock
1193
1002
def get_format_string(self):
1194
1003
"""See BzrDirFormat.get_format_string()."""
1195
1004
return "Bazaar-NG branch, format 5\n"
1197
def get_format_description(self):
1198
"""See BzrDirFormat.get_format_description()."""
1199
return "All-in-one format 5"
1201
1006
def get_converter(self, format=None):
1202
1007
"""See BzrDirFormat.get_converter()."""
1203
1008
# there is one and only one upgrade path here.
1204
1009
return ConvertBzrDir5To6()
1206
def _initialize_for_clone(self, url):
1207
return self.initialize_on_transport(get_transport(url), _cloning=True)
1209
def initialize_on_transport(self, transport, _cloning=False):
1011
def initialize(self, url, _cloning=False):
1210
1012
"""Format 5 dirs always have working tree, branch and repository.
1212
1014
Except when they are being cloned.
1242
1044
- Format 6 repositories [always]
1245
_lock_class = TransportLock
1247
1047
def get_format_string(self):
1248
1048
"""See BzrDirFormat.get_format_string()."""
1249
1049
return "Bazaar-NG branch, format 6\n"
1251
def get_format_description(self):
1252
"""See BzrDirFormat.get_format_description()."""
1253
return "All-in-one format 6"
1255
1051
def get_converter(self, format=None):
1256
1052
"""See BzrDirFormat.get_converter()."""
1257
1053
# there is one and only one upgrade path here.
1258
1054
return ConvertBzrDir6ToMeta()
1260
def _initialize_for_clone(self, url):
1261
return self.initialize_on_transport(get_transport(url), _cloning=True)
1263
def initialize_on_transport(self, transport, _cloning=False):
1056
def initialize(self, url, _cloning=False):
1264
1057
"""Format 6 dirs always have working tree, branch and repository.
1266
1059
Except when they are being cloned.
1317
1108
"""See BzrDirFormat.get_format_string()."""
1318
1109
return "Bazaar-NG meta directory, format 1\n"
1320
def get_format_description(self):
1321
"""See BzrDirFormat.get_format_description()."""
1322
return "Meta directory format 1"
1324
1111
def _open(self, transport):
1325
1112
"""See BzrDirFormat._open."""
1326
1113
return BzrDirMeta1(transport, self)
1335
1122
def __set_repository_format(self, value):
1336
1123
"""Allow changint the repository format for metadir formats."""
1337
1124
self._repository_format = value
1339
1125
repository_format = property(__return_repository_format, __set_repository_format)
1342
1128
BzrDirFormat.register_format(BzrDirFormat4())
1343
1129
BzrDirFormat.register_format(BzrDirFormat5())
1344
BzrDirFormat.register_format(BzrDirFormat6())
1345
__default_format = BzrDirMetaFormat1()
1130
BzrDirFormat.register_format(BzrDirMetaFormat1())
1131
__default_format = BzrDirFormat6()
1346
1132
BzrDirFormat.register_format(__default_format)
1347
1133
BzrDirFormat.set_default_format(__default_format)
1165
class ScratchDir(BzrDir6):
1166
"""Special test class: a bzrdir that cleans up itself..
1168
>>> d = ScratchDir()
1169
>>> base = d.transport.base
1172
>>> b.transport.__del__()
1177
def __init__(self, files=[], dirs=[], transport=None):
1178
"""Make a test branch.
1180
This creates a temporary directory and runs init-tree in it.
1182
If any files are listed, they are created in the working copy.
1184
if transport is None:
1185
transport = bzrlib.transport.local.ScratchTransport()
1186
# local import for scope restriction
1187
BzrDirFormat6().initialize(transport.base)
1188
super(ScratchDir, self).__init__(transport, BzrDirFormat6())
1189
self.create_repository()
1190
self.create_branch()
1191
self.create_workingtree()
1193
super(ScratchDir, self).__init__(transport, BzrDirFormat6())
1195
# BzrBranch creates a clone to .bzr and then forgets about the
1196
# original transport. A ScratchTransport() deletes itself and
1197
# everything underneath it when it goes away, so we need to
1198
# grab a local copy to prevent that from happening
1199
self._transport = transport
1202
self._transport.mkdir(d)
1205
self._transport.put(f, 'content of %s' % f)
1209
>>> orig = ScratchDir(files=["file1", "file2"])
1210
>>> os.listdir(orig.base)
1211
[u'.bzr', u'file1', u'file2']
1212
>>> clone = orig.clone()
1213
>>> if os.name != 'nt':
1214
... os.path.samefile(orig.base, clone.base)
1216
... orig.base == clone.base
1219
>>> os.listdir(clone.base)
1220
[u'.bzr', u'file1', u'file2']
1222
from shutil import copytree
1223
from bzrlib.osutils import mkdtemp
1226
copytree(self.base, base, symlinks=True)
1228
transport=bzrlib.transport.local.ScratchTransport(base))
1379
1231
class Converter(object):
1380
1232
"""Converts a disk format object from one format to another."""
1475
1326
controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
1476
1327
weave_transport = self.bzrdir.transport.clone('weaves')
1477
1328
weaves = WeaveStore(weave_transport, prefixed=False)
1478
transaction = WriteTransaction()
1329
transaction = PassThroughTransaction()
1331
controlweaves.put_weave('inventory', self.inv_weave, transaction)
1482
1334
for file_id, file_weave in self.text_weaves.items():
1483
1335
self.pb.update('writing weave', i, len(self.text_weaves))
1484
weaves._put_weave(file_id, file_weave, transaction)
1336
weaves.put_weave(file_id, file_weave, transaction)
1486
self.pb.update('inventory', 0, 1)
1487
controlweaves._put_weave('inventory', self.inv_weave, transaction)
1488
self.pb.update('inventory', 1, 1)
1490
1339
self.pb.clear()
1495
1344
self.bzrdir.transport.mkdir('revision-store')
1496
1345
revision_transport = self.bzrdir.transport.clone('revision-store')
1497
1346
# TODO permissions
1498
_revision_store = TextRevisionStore(TextStore(revision_transport,
1347
revision_store = TextStore(revision_transport,
1502
transaction = bzrlib.transactions.WriteTransaction()
1503
1351
for i, rev_id in enumerate(self.converted_revs):
1504
1352
self.pb.update('write revision', i, len(self.converted_revs))
1505
_revision_store.add_revision(self.revisions[rev_id], transaction)
1353
rev_tmp = StringIO()
1354
serializer_v5.write_revision(self.revisions[rev_id], rev_tmp)
1356
revision_store.add(rev_tmp, rev_id)
1507
1358
self.pb.clear()
1514
1365
self.pb.update('loading revision',
1515
1366
len(self.revisions),
1516
1367
len(self.known_revisions))
1517
if not self.branch.repository.has_revision(rev_id):
1368
if not self.branch.repository.revision_store.has_id(rev_id):
1518
1369
self.pb.clear()
1519
1370
self.pb.note('revision {%s} not present in branch; '
1520
1371
'will be converted as a ghost',
1522
1373
self.absent_revisions.add(rev_id)
1524
rev = self.branch.repository._revision_store.get_revision(rev_id,
1525
self.branch.repository.get_transaction())
1375
rev_xml = self.branch.repository.revision_store.get(rev_id).read()
1376
rev = serializer_v4.read_revision_from_string(rev_xml)
1526
1377
for parent_id in rev.parent_ids:
1527
1378
self.known_revisions.add(parent_id)
1528
1379
self.to_read.append(parent_id)
1564
1415
assert hasattr(ie, 'revision'), \
1565
1416
'no revision on {%s} in {%s}' % \
1566
1417
(file_id, rev.revision_id)
1567
new_inv_xml = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
1418
new_inv_xml = serializer_v5.write_inventory_to_string(inv)
1568
1419
new_inv_sha1 = sha_string(new_inv_xml)
1569
self.inv_weave.add_lines(rev.revision_id,
1571
new_inv_xml.splitlines(True))
1420
self.inv_weave.add(rev.revision_id,
1422
new_inv_xml.splitlines(True),
1572
1424
rev.inventory_sha1 = new_inv_sha1
1574
1426
def _convert_revision_contents(self, rev, inv, present_parents):
1622
1471
if ie._unchanged(previous_ie):
1623
1472
ie.revision = previous_ie.revision
1474
parent_indexes = map(w.lookup, previous_revisions)
1625
1475
if ie.has_text():
1626
1476
text = self.branch.repository.text_store.get(ie.text_id)
1627
1477
file_lines = text.readlines()
1628
1478
assert sha_strings(file_lines) == ie.text_sha1
1629
1479
assert sum(map(len, file_lines)) == ie.text_size
1630
w.add_lines(rev_id, previous_revisions, file_lines)
1480
w.add(rev_id, parent_indexes, file_lines, ie.text_sha1)
1631
1481
self.text_count += 1
1633
w.add_lines(rev_id, previous_revisions, [])
1483
w.add(rev_id, parent_indexes, [], None)
1634
1484
ie.revision = rev_id
1636
1486
def _make_order(self):
1668
1518
return BzrDir.open(self.bzrdir.root_transport.base)
1670
1520
def _convert_to_prefixed(self):
1671
from bzrlib.store import TransportStore
1521
from bzrlib.store import hash_prefix
1672
1522
self.bzrdir.transport.delete('branch-format')
1673
1523
for store_name in ["weaves", "revision-store"]:
1674
self.pb.note("adding prefixes to %s" % store_name)
1524
self.pb.note("adding prefixes to %s" % store_name)
1675
1525
store_transport = self.bzrdir.transport.clone(store_name)
1676
store = TransportStore(store_transport, prefixed=True)
1677
for urlfilename in store_transport.list_dir('.'):
1678
filename = urlutils.unescape(urlfilename)
1526
for filename in store_transport.list_dir('.'):
1679
1527
if (filename.endswith(".weave") or
1680
1528
filename.endswith(".gz") or
1681
1529
filename.endswith(".sig")):
1682
1530
file_id = os.path.splitext(filename)[0]
1684
1532
file_id = filename
1685
prefix_dir = store.hash_prefix(file_id)
1533
prefix_dir = hash_prefix(file_id)
1686
1534
# FIXME keep track of the dirs made RBC 20060121
1688
1536
store_transport.move(filename, prefix_dir + '/' + filename)
1715
1563
# find out whats there
1716
1564
self.step('Finding branch files')
1717
last_revision = self.bzrdir.open_branch().last_revision()
1565
last_revision = self.bzrdir.open_workingtree().last_revision()
1718
1566
bzrcontents = self.bzrdir.transport.list_dir('.')
1719
1567
for name in bzrcontents:
1720
1568
if name.startswith('basis-inventory.'):
1721
1569
self.garbage_inventories.append(name)
1722
1570
# create new directories for repository, working tree and branch
1723
self.dir_mode = self.bzrdir._control_files._dir_mode
1571
dir_mode = self.bzrdir._control_files._dir_mode
1724
1572
self.file_mode = self.bzrdir._control_files._file_mode
1725
1573
repository_names = [('inventory.weave', True),
1726
1574
('revision-store', True),
1727
1575
('weaves', True)]
1728
1576
self.step('Upgrading repository ')
1729
self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
1577
self.bzrdir.transport.mkdir('repository', mode=dir_mode)
1730
1578
self.make_lock('repository')
1731
1579
# we hard code the formats here because we are converting into
1732
1580
# the meta format. The meta format upgrader can take this to a
1736
1584
self.move_entry('repository', entry)
1738
1586
self.step('Upgrading branch ')
1739
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
1587
self.bzrdir.transport.mkdir('branch', mode=dir_mode)
1740
1588
self.make_lock('branch')
1741
1589
self.put_format('branch', bzrlib.branch.BzrBranchFormat5())
1742
1590
branch_files = [('revision-history', True),
1746
1594
self.move_entry('branch', entry)
1748
1596
self.step('Upgrading working tree')
1749
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
1597
self.bzrdir.transport.mkdir('checkout', mode=dir_mode)
1750
1598
self.make_lock('checkout')
1751
1599
self.put_format('checkout', bzrlib.workingtree.WorkingTreeFormat3())
1752
1600
self.bzrdir.transport.delete_multi(self.garbage_inventories, self.pb)
1764
1612
def make_lock(self, name):
1765
1613
"""Make a lock for the new control dir name."""
1766
1614
self.step('Make %s lock' % name)
1767
ld = LockDir(self.bzrdir.transport,
1769
file_modebits=self.file_mode,
1770
dir_modebits=self.dir_mode)
1615
self.bzrdir.transport.put('%s/lock' % name, StringIO(), mode=self.file_mode)
1773
1617
def move_entry(self, new_dir, entry):
1774
1618
"""Move then entry name into new_dir."""