180
181
even if one is available.
182
183
transport.ensure_base()
183
result = self._format.initialize_on_transport(transport)
184
result = self.cloning_metadir().initialize_on_transport(transport)
185
repository_policy = None
185
187
local_repo = self.find_repository()
186
188
except errors.NoRepositoryPresent:
187
189
local_repo = None
189
191
# may need to copy content in
191
result_repo = local_repo.clone(
193
revision_id=revision_id)
194
result_repo.set_make_working_trees(local_repo.make_working_trees())
197
result_repo = result.find_repository()
198
# fetch content this dir needs.
199
result_repo.fetch(local_repo, revision_id=revision_id)
200
except errors.NoRepositoryPresent:
201
# needed to make one anyway.
202
result_repo = local_repo.clone(
204
revision_id=revision_id)
205
result_repo.set_make_working_trees(local_repo.make_working_trees())
192
repository_policy = result.determine_repository_policy(
194
make_working_trees = local_repo.make_working_trees()
195
result_repo = repository_policy.acquire_repository(
196
make_working_trees, local_repo.is_shared())
197
result_repo.fetch(local_repo, revision_id=revision_id)
206
198
# 1 if there is a branch present
207
199
# make sure its content is available in the target repository
210
self.open_branch().clone(result, revision_id=revision_id)
202
local_branch = self.open_branch()
211
203
except errors.NotBranchError:
206
result_branch = local_branch.clone(result, revision_id=revision_id)
207
if repository_policy is not None:
208
repository_policy.configure_branch(result_branch)
214
210
result_repo = result.find_repository()
215
211
except errors.NoRepositoryPresent:
356
351
bzrdir._find_or_create_repository(force_new_repo)
357
352
return bzrdir.create_branch()
354
def determine_repository_policy(self, force_new_repo=False):
355
"""Return an object representing a policy to use.
357
This controls whether a new repository is created, or a shared
358
repository used instead.
360
def repository_policy(found_bzrdir):
362
# does it have a repository ?
364
repository = found_bzrdir.open_repository()
365
except errors.NoRepositoryPresent:
368
if ((found_bzrdir.root_transport.base !=
369
self.root_transport.base) and not repository.is_shared()):
376
return UseExistingRepository(repository), True
378
return CreateRepository(self), True
380
if not force_new_repo:
381
policy = self._find_containing(repository_policy)
382
if policy is not None:
384
return CreateRepository(self)
359
386
def _find_or_create_repository(self, force_new_repo):
360
387
"""Create a new repository if needed, returning the repository."""
362
return self.create_repository()
364
return self.find_repository()
365
except errors.NoRepositoryPresent:
366
return self.create_repository()
388
policy = self.determine_repository_policy(force_new_repo)
389
return policy.acquire_repository()
369
392
def create_branch_convenience(base, force_new_repo=False,
370
393
force_new_tree=None, format=None,
414
@deprecated_function(zero_ninetyone)
415
def create_repository(base, shared=False, format=None):
416
"""Create a new BzrDir and Repository at the url 'base'.
418
If no format is supplied, this will default to the current default
419
BzrDirFormat by default, and use whatever repository format that that
420
uses for bzrdirformat.create_repository.
422
:param shared: Create a shared repository rather than a standalone
424
The Repository object is returned.
426
This must be overridden as an instance method in child classes, where
427
it should take no parameters and construct whatever repository format
428
that child class desires.
430
This method is deprecated, please call create_repository on a bzrdir
433
bzrdir = BzrDir.create(base, format)
434
return bzrdir.create_repository(shared)
437
437
def create_standalone_workingtree(base, format=None):
438
438
"""Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
509
509
raise NotImplementedError(self.destroy_workingtree_metadata)
511
def _find_containing(self, evaluate):
512
"""Find something in a containing control directory.
514
This method will scan containing control dirs, until it finds what
515
it is looking for, decides that it will never find it, or runs out
516
of containing control directories to check.
518
It is used to implement find_repository and
519
determine_repository_policy.
521
:param evaluate: A function returning (value, stop). If stop is True,
522
the value will be returned.
526
result, stop = evaluate(found_bzrdir)
529
next_transport = found_bzrdir.root_transport.clone('..')
530
if (found_bzrdir.root_transport.base == next_transport.base):
531
# top of the file system
533
# find the next containing bzrdir
535
found_bzrdir = BzrDir.open_containing_from_transport(
537
except errors.NotBranchError:
511
540
def find_repository(self):
512
541
"""Find the repository that should be used.
515
544
new branches as well as to hook existing branches up to their
519
return self.open_repository()
520
except errors.NoRepositoryPresent:
522
next_transport = self.root_transport.clone('..')
524
# find the next containing bzrdir
526
found_bzrdir = BzrDir.open_containing_from_transport(
528
except errors.NotBranchError:
530
raise errors.NoRepositoryPresent(self)
547
def usable_repository(found_bzrdir):
531
548
# does it have a repository ?
533
550
repository = found_bzrdir.open_repository()
534
551
except errors.NoRepositoryPresent:
535
next_transport = found_bzrdir.root_transport.clone('..')
536
if (found_bzrdir.root_transport.base == next_transport.base):
537
# top of the file system
541
if ((found_bzrdir.root_transport.base ==
542
self.root_transport.base) or repository.is_shared()):
553
if found_bzrdir.root_transport.base == self.root_transport.base:
554
return repository, True
555
elif repository.is_shared():
556
return repository, True
545
raise errors.NoRepositoryPresent(self)
546
raise errors.NoRepositoryPresent(self)
560
found_repo = self._find_containing(usable_repository)
561
if found_repo is None:
562
raise errors.NoRepositoryPresent(self)
548
565
def get_branch_reference(self):
549
566
"""Return the referenced URL for the branch in this bzrdir.
566
583
guaranteed to point to an existing directory ready for use.
568
585
raise NotImplementedError(self.get_branch_transport)
587
def _find_creation_modes(self):
588
"""Determine the appropriate modes for files and directories.
590
They're always set to be consistent with the base directory,
591
assuming that this transport allows setting modes.
593
# TODO: Do we need or want an option (maybe a config setting) to turn
594
# this off or override it for particular locations? -- mbp 20080512
595
if self._mode_check_done:
597
self._mode_check_done = True
599
st = self.transport.stat('.')
600
except errors.TransportNotPossible:
601
self._dir_mode = None
602
self._file_mode = None
604
# Check the directory mode, but also make sure the created
605
# directories and files are read-write for this user. This is
606
# mostly a workaround for filesystems which lie about being able to
607
# write to a directory (cygwin & win32)
608
self._dir_mode = (st.st_mode & 07777) | 00700
609
# Remove the sticky and execute bits for files
610
self._file_mode = self._dir_mode & ~07111
612
def _get_file_mode(self):
613
"""Return Unix mode for newly created files, or None.
615
if not self._mode_check_done:
616
self._find_creation_modes()
617
return self._file_mode
619
def _get_dir_mode(self):
620
"""Return Unix mode for newly created directories, or None.
622
if not self._mode_check_done:
623
self._find_creation_modes()
624
return self._dir_mode
570
626
def get_repository_transport(self, repository_format):
571
627
"""Get the transport for use by repository format in this BzrDir.
999
1056
def __init__(self, _transport, _format):
1000
1057
"""See BzrDir.__init__."""
1001
1058
super(BzrDirPreSplitOut, self).__init__(_transport, _format)
1002
assert self._format._lock_class == lockable_files.TransportLock
1003
assert self._format._lock_file_name == 'branch-lock'
1004
1059
self._control_files = lockable_files.LockableFiles(
1005
1060
self.get_branch_transport(None),
1006
1061
self._format._lock_file_name,
1010
1065
"""Pre-splitout bzrdirs do not suffer from stale locks."""
1011
1066
raise NotImplementedError(self.break_lock)
1068
def cloning_metadir(self):
1069
"""Produce a metadir suitable for cloning with."""
1070
return self._format.__class__()
1013
1072
def clone(self, url, revision_id=None, force_new_repo=False):
1014
1073
"""See BzrDir.clone()."""
1015
1074
from bzrlib.workingtree import WorkingTreeFormat2
1488
1547
win32utils.set_file_attr_hidden(transport._abspath('.bzr'))
1489
1548
file_mode = temp_control._file_mode
1490
1549
del temp_control
1491
mutter('created control directory in ' + transport.base)
1492
control = transport.clone('.bzr')
1493
utf8_files = [('README',
1494
"This is a Bazaar-NG control directory.\n"
1495
"Do not change any files in this directory.\n"),
1550
bzrdir_transport = transport.clone('.bzr')
1551
utf8_files = [('README',
1552
"This is a Bazaar control directory.\n"
1553
"Do not change any files in this directory.\n"
1554
"See http://bazaar-vcs.org/ for more information about Bazaar.\n"),
1496
1555
('branch-format', self.get_format_string()),
1498
1557
# NB: no need to escape relative paths that are url safe.
1499
control_files = lockable_files.LockableFiles(control,
1500
self._lock_file_name, self._lock_class)
1558
control_files = lockable_files.LockableFiles(bzrdir_transport,
1559
self._lock_file_name, self._lock_class)
1501
1560
control_files.create_lock()
1502
1561
control_files.lock_write()
1504
for file, content in utf8_files:
1505
control_files.put_utf8(file, content)
1563
for (filename, content) in utf8_files:
1564
bzrdir_transport.put_bytes(filename, content,
1507
1567
control_files.unlock()
1508
1568
return self.open(transport, _found=True)
1587
1647
klass._control_server_formats.append(format)
1590
@symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
1591
def set_default_format(klass, format):
1592
klass._set_default_format(format)
1595
1650
def _set_default_format(klass, format):
1596
1651
"""Set default format (for testing behavior of defaults only)"""
1597
1652
klass._default_format = format
1954
2008
self.pb.note(' %6d revisions not present', len(self.absent_revisions))
1955
2009
self.pb.note(' %6d texts', self.text_count)
1956
2010
self._cleanup_spare_files_after_format4()
1957
self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
2011
self.branch._transport.put_bytes(
2013
BzrDirFormat5().get_format_string(),
2014
mode=self.bzrdir._get_file_mode())
1959
2016
def _cleanup_spare_files_after_format4(self):
1960
2017
# FIXME working tree upgrade foo.
1970
2027
def _convert_working_inv(self):
1971
2028
inv = xml4.serializer_v4.read_inventory(
1972
self.branch.control_files.get('inventory'))
2029
self.branch._transport.get('inventory'))
1973
2030
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv, working=True)
1974
# FIXME inventory is a working tree change.
1975
self.branch.control_files.put('inventory', StringIO(new_inv_xml))
2031
self.branch._transport.put_bytes('inventory', new_inv_xml,
2032
mode=self.bzrdir._get_file_mode())
1977
2034
def _write_all_weaves(self):
1978
2035
controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
2032
2089
self.revisions[rev_id] = rev
2034
2091
def _load_old_inventory(self, rev_id):
2035
assert rev_id not in self.converted_revs
2036
2092
old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
2037
2093
inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
2038
2094
inv.revision_id = rev_id
2039
2095
rev = self.revisions[rev_id]
2040
if rev.inventory_sha1:
2041
assert rev.inventory_sha1 == sha_string(old_inv_xml), \
2042
'inventory sha mismatch for {%s}' % rev_id
2045
2098
def _load_updated_inventory(self, rev_id):
2046
assert rev_id in self.converted_revs
2047
2099
inv_xml = self.inv_weave.get_text(rev_id)
2048
2100
inv = xml5.serializer_v5.read_inventory_from_string(inv_xml, rev_id)
2059
2111
self.converted_revs.add(rev_id)
2061
2113
def _store_new_inv(self, rev, inv, present_parents):
2062
# the XML is now updated with text versions
2064
entries = inv.iter_entries()
2066
for path, ie in entries:
2067
assert getattr(ie, 'revision', None) is not None, \
2068
'no revision on {%s} in {%s}' % \
2069
(file_id, rev.revision_id)
2070
2114
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
2071
2115
new_inv_sha1 = sha_string(new_inv_xml)
2072
2116
self.inv_weave.add_lines(rev.revision_id,
2101
2145
self.text_weaves[file_id] = w
2102
2146
text_changed = False
2103
2147
parent_candiate_entries = ie.parent_candidates(parent_invs)
2104
for old_revision in parent_candiate_entries.keys():
2105
# if this fails, its a ghost ?
2106
assert old_revision in self.converted_revs, \
2107
"Revision {%s} not in converted_revs" % old_revision
2108
2148
heads = graph.Graph(self).heads(parent_candiate_entries.keys())
2109
2149
# XXX: Note that this is unordered - and this is tolerable because
2110
2150
# the previous code was also unordered.
2205
2242
except errors.NoSuchFile: # catches missing dirs strangely enough
2206
2243
store_transport.mkdir(prefix_dir)
2207
2244
store_transport.move(filename, prefix_dir + '/' + filename)
2208
self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
2245
self.bzrdir.transport.put_bytes(
2247
BzrDirFormat6().get_format_string(),
2248
mode=self.bzrdir._get_file_mode())
2211
2251
class ConvertBzrDir6ToMeta(Converter):
2221
2261
self.total = 20 # the steps we know about
2222
2262
self.garbage_inventories = []
2263
self.dir_mode = self.bzrdir._get_dir_mode()
2264
self.file_mode = self.bzrdir._get_file_mode()
2224
2266
self.pb.note('starting upgrade from format 6 to metadir')
2225
self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
2267
self.bzrdir.transport.put_bytes(
2269
"Converting to format 6",
2270
mode=self.file_mode)
2226
2271
# its faster to move specific files around than to open and use the apis...
2227
2272
# first off, nuke ancestry.weave, it was never used.
2238
2283
if name.startswith('basis-inventory.'):
2239
2284
self.garbage_inventories.append(name)
2240
2285
# create new directories for repository, working tree and branch
2241
self.dir_mode = self.bzrdir._control_files._dir_mode
2242
self.file_mode = self.bzrdir._control_files._file_mode
2243
2286
repository_names = [('inventory.weave', True),
2244
2287
('revision-store', True),
2245
2288
('weaves', True)]
2293
2336
for entry in checkout_files:
2294
2337
self.move_entry('checkout', entry)
2295
2338
if last_revision is not None:
2296
self.bzrdir._control_files.put_utf8(
2339
self.bzrdir.transport.put_bytes(
2297
2340
'checkout/last-revision', last_revision)
2298
self.bzrdir._control_files.put_utf8(
2299
'branch-format', BzrDirMetaFormat1().get_format_string())
2341
self.bzrdir.transport.put_bytes(
2343
BzrDirMetaFormat1().get_format_string(),
2344
mode=self.file_mode)
2300
2345
return BzrDir.open(self.bzrdir.root_transport.base)
2302
2347
def make_lock(self, name):
2322
2367
def put_format(self, dirname, format):
2323
self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
2368
self.bzrdir.transport.put_bytes('%s/format' % dirname,
2369
format.get_format_string(),
2326
2373
class ConvertMetaToMeta(Converter):
2393
2440
def probe_transport(klass, transport):
2394
2441
"""Return a RemoteBzrDirFormat object if it looks possible."""
2396
client = transport.get_smart_client()
2443
medium = transport.get_smart_medium()
2397
2444
except (NotImplementedError, AttributeError,
2398
errors.TransportNotPossible):
2445
errors.TransportNotPossible, errors.NoSmartMedium,
2446
errors.SmartProtocolError):
2399
2447
# no smart server, so not a branch for this format type.
2400
2448
raise errors.NotBranchError(path=transport.base)
2402
# Send a 'hello' request in protocol version one, and decline to
2403
# open it if the server doesn't support our required version (2) so
2404
# that the VFS-based transport will do it.
2405
request = client.get_request()
2406
smart_protocol = protocol.SmartClientRequestProtocolOne(request)
2407
server_version = smart_protocol.query_version()
2408
if server_version != 2:
2409
raise errors.NotBranchError(path=transport.base)
2450
# Decline to open it if the server doesn't support our required
2451
# version (3) so that the VFS-based transport will do it.
2452
if medium.should_probe():
2454
server_version = medium.protocol_version()
2455
except errors.SmartProtocolError:
2456
# Apparently there's no usable smart server there, even though
2457
# the medium supports the smart protocol.
2458
raise errors.NotBranchError(path=transport.base)
2459
if server_version != '2':
2460
raise errors.NotBranchError(path=transport.base)
2412
2463
def initialize_on_transport(self, transport):
2414
2465
# hand off the request to the smart server
2415
shared_medium = transport.get_shared_medium()
2466
client_medium = transport.get_smart_medium()
2416
2467
except errors.NoSmartMedium:
2417
2468
# TODO: lookup the local format from a server hint.
2418
2469
local_dir_format = BzrDirMetaFormat1()
2419
2470
return local_dir_format.initialize_on_transport(transport)
2420
client = _SmartClient(shared_medium)
2471
client = _SmartClient(client_medium)
2421
2472
path = client.remote_path_from_transport(transport)
2422
response = _SmartClient(shared_medium).call('BzrDirFormat.initialize',
2424
assert response[0] in ('ok', ), 'unexpected response code %s' % (response,)
2473
response = client.call('BzrDirFormat.initialize', path)
2474
if response[0] != 'ok':
2475
raise errors.SmartProtocolError('unexpected response code %s' % (response,))
2425
2476
return remote.RemoteBzrDir(transport)
2427
2478
def _open(self, transport):
2660
class RepositoryAcquisitionPolicy(object):
2661
"""Abstract base class for repository acquisition policies.
2663
A repository acquisition policy decides how a BzrDir acquires a repository
2664
for a branch that is being created. The most basic policy decision is
2665
whether to create a new repository or use an existing one.
2668
def configure_branch(self, branch):
2669
"""Apply any configuration data from this policy to the branch.
2671
Default implementation does nothing.
2675
def acquire_repository(self, make_working_trees=None, shared=False):
2676
"""Acquire a repository for this bzrdir.
2678
Implementations may create a new repository or use a pre-exising
2680
:param make_working_trees: If creating a repository, set
2681
make_working_trees to this value (if non-None)
2682
:param shared: If creating a repository, make it shared if True
2683
:return: A repository
2685
raise NotImplemented(RepositoryAcquisitionPolicy.acquire_repository)
2688
class CreateRepository(RepositoryAcquisitionPolicy):
2689
"""A policy of creating a new repository"""
2691
def __init__(self, bzrdir):
2692
RepositoryAcquisitionPolicy.__init__(self)
2693
self._bzrdir = bzrdir
2695
def acquire_repository(self, make_working_trees=None, shared=False):
2696
"""Implementation of RepositoryAcquisitionPolicy.acquire_repository
2698
Creates the desired repository in the bzrdir we already have.
2700
repository = self._bzrdir.create_repository(shared=shared)
2701
if make_working_trees is not None:
2702
repository.set_make_working_trees(make_working_trees)
2706
class UseExistingRepository(RepositoryAcquisitionPolicy):
2707
"""A policy of reusing an existing repository"""
2709
def __init__(self, repository):
2710
RepositoryAcquisitionPolicy.__init__(self)
2711
self._repository = repository
2713
def acquire_repository(self, make_working_trees=None, shared=False):
2714
"""Implementation of RepositoryAcquisitionPolicy.acquire_repository
2716
Returns an existing repository to use
2718
return self._repository
2610
2721
format_registry = BzrDirFormatRegistry()
2611
2722
format_registry.register('weave', BzrDirFormat6,
2612
2723
'Pre-0.8 format. Slower than knit and does not'