23
23
# TODO: remove unittest dependency; put that stuff inside the test suite
25
from copy import deepcopy
25
# TODO: The Format probe_transport seems a bit redundant with just trying to
26
# open the bzrdir. -- mbp
28
# TODO: Can we move specific formats into separate modules to make this file
26
31
from cStringIO import StringIO
35
from bzrlib.lazy_import import lazy_import
36
lazy_import(globals(), """
37
from copy import deepcopy
28
38
from stat import S_ISDIR
29
from unittest import TestSuite
32
import bzrlib.errors as errors
33
from bzrlib.lockable_files import LockableFiles, TransportLock
34
from bzrlib.lockdir import LockDir
47
revision as _mod_revision,
48
repository as _mod_repository,
35
54
from bzrlib.osutils import (
42
59
from bzrlib.store.revision.text import TextRevisionStore
43
60
from bzrlib.store.text import TextStore
44
61
from bzrlib.store.versioned import WeaveStore
45
from bzrlib.trace import mutter
46
62
from bzrlib.transactions import WriteTransaction
47
63
from bzrlib.transport import get_transport
64
from bzrlib.weave import Weave
67
from bzrlib.trace import mutter
48
68
from bzrlib.transport.local import LocalTransport
49
import bzrlib.urlutils as urlutils
50
from bzrlib.weave import Weave
51
from bzrlib.xml4 import serializer_v4
55
71
class BzrDir(object):
185
206
# TODO: Should take a Transport
187
def create(cls, base):
208
def create(cls, base, format=None):
188
209
"""Create a new BzrDir at the url 'base'.
190
211
This will call the current default formats initialize with base
191
212
as the only parameter.
193
If you need a specific format, consider creating an instance
194
of that and calling initialize().
214
:param format: If supplied, the format of branch to create. If not
215
supplied, the default is used.
196
217
if cls is not BzrDir:
197
raise AssertionError("BzrDir.create always creates the default format, "
198
"not one of %r" % cls)
218
raise AssertionError("BzrDir.create always creates the default"
219
" format, not one of %r" % cls)
199
220
head, tail = urlutils.split(base)
200
221
if tail and tail != '.':
201
t = bzrlib.transport.get_transport(head)
222
t = get_transport(head)
204
225
except errors.FileExists:
206
return BzrDirFormat.get_default_format().initialize(safe_unicode(base))
228
format = BzrDirFormat.get_default_format()
229
return format.initialize(safe_unicode(base))
208
231
def create_branch(self):
209
232
"""Create a branch in this BzrDir.
515
558
raise errors.NotBranchError(path=url)
516
559
a_transport = new_t
562
def open_containing_tree_or_branch(klass, location):
563
"""Return the branch and working tree contained by a location.
565
Returns (tree, branch, relpath).
566
If there is no tree at containing the location, tree will be None.
567
If there is no branch containing the location, an exception will be
569
relpath is the portion of the path that is contained by the branch.
571
bzrdir, relpath = klass.open_containing(location)
573
tree = bzrdir.open_workingtree()
574
except (errors.NoWorkingTree, errors.NotLocalUrl):
576
branch = bzrdir.open_branch()
579
return tree, branch, relpath
518
581
def open_repository(self, _unsupported=False):
519
582
"""Open the repository object at this BzrDir if one is present.
833
938
from bzrlib.workingtree import WorkingTreeFormat
834
939
return WorkingTreeFormat.get_default_format().initialize(self, revision_id)
941
def destroy_workingtree(self):
942
"""See BzrDir.destroy_workingtree."""
943
wt = self.open_workingtree()
944
repository = wt.branch.repository
945
empty = repository.revision_tree(_mod_revision.NULL_REVISION)
946
wt.revert([], old_tree=empty)
947
self.destroy_workingtree_metadata()
949
def destroy_workingtree_metadata(self):
950
self.transport.delete_tree('checkout')
836
952
def _get_mkdir_mode(self):
837
953
"""Figure out the mode to use when creating a bzrdir subdir."""
838
temp_control = LockableFiles(self.transport, '', TransportLock)
954
temp_control = lockable_files.LockableFiles(self.transport, '',
955
lockable_files.TransportLock)
839
956
return temp_control._dir_mode
841
958
def get_branch_transport(self, branch_format):
1731
1869
# we hard code the formats here because we are converting into
1732
1870
# the meta format. The meta format upgrader can take this to a
1733
1871
# future format within each component.
1734
self.put_format('repository', bzrlib.repository.RepositoryFormat7())
1872
self.put_format('repository', _mod_repository.RepositoryFormat7())
1735
1873
for entry in repository_names:
1736
1874
self.move_entry('repository', entry)
1738
1876
self.step('Upgrading branch ')
1739
1877
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
1740
1878
self.make_lock('branch')
1741
self.put_format('branch', bzrlib.branch.BzrBranchFormat5())
1879
self.put_format('branch', BzrBranchFormat5())
1742
1880
branch_files = [('revision-history', True),
1743
1881
('branch-name', True),
1744
1882
('parent', False)]
1745
1883
for entry in branch_files:
1746
1884
self.move_entry('branch', entry)
1748
self.step('Upgrading working tree')
1749
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
1750
self.make_lock('checkout')
1751
self.put_format('checkout', bzrlib.workingtree.WorkingTreeFormat3())
1752
self.bzrdir.transport.delete_multi(self.garbage_inventories, self.pb)
1753
1886
checkout_files = [('pending-merges', True),
1754
1887
('inventory', True),
1755
1888
('stat-cache', False)]
1756
for entry in checkout_files:
1757
self.move_entry('checkout', entry)
1758
if last_revision is not None:
1759
self.bzrdir._control_files.put_utf8('checkout/last-revision',
1761
self.bzrdir._control_files.put_utf8('branch-format', BzrDirMetaFormat1().get_format_string())
1889
# If a mandatory checkout file is not present, the branch does not have
1890
# a functional checkout. Do not create a checkout in the converted
1892
for name, mandatory in checkout_files:
1893
if mandatory and name not in bzrcontents:
1894
has_checkout = False
1898
if not has_checkout:
1899
self.pb.note('No working tree.')
1900
# If some checkout files are there, we may as well get rid of them.
1901
for name, mandatory in checkout_files:
1902
if name in bzrcontents:
1903
self.bzrdir.transport.delete(name)
1905
from bzrlib.workingtree import WorkingTreeFormat3
1906
self.step('Upgrading working tree')
1907
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
1908
self.make_lock('checkout')
1910
'checkout', WorkingTreeFormat3())
1911
self.bzrdir.transport.delete_multi(
1912
self.garbage_inventories, self.pb)
1913
for entry in checkout_files:
1914
self.move_entry('checkout', entry)
1915
if last_revision is not None:
1916
self.bzrdir._control_files.put_utf8(
1917
'checkout/last-revision', last_revision)
1918
self.bzrdir._control_files.put_utf8(
1919
'branch-format', BzrDirMetaFormat1().get_format_string())
1762
1920
return BzrDir.open(self.bzrdir.root_transport.base)
1764
1922
def make_lock(self, name):
1765
1923
"""Make a lock for the new control dir name."""
1766
1924
self.step('Make %s lock' % name)
1767
ld = LockDir(self.bzrdir.transport,
1769
file_modebits=self.file_mode,
1770
dir_modebits=self.dir_mode)
1925
ld = lockdir.LockDir(self.bzrdir.transport,
1927
file_modebits=self.file_mode,
1928
dir_modebits=self.dir_mode)
1773
1931
def move_entry(self, new_dir, entry):
1813
1971
converter = CopyConverter(self.target_format.repository_format)
1814
1972
converter.convert(repo, pb)
1815
1973
return to_convert
1976
class BzrDirFormatInfo(object):
1978
def __init__(self, native, deprecated):
1979
self.deprecated = deprecated
1980
self.native = native
1983
class BzrDirFormatRegistry(registry.Registry):
1984
"""Registry of user-selectable BzrDir subformats.
1986
Differs from BzrDirFormat._control_formats in that it provides sub-formats,
1987
e.g. BzrDirMeta1 with weave repository. Also, it's more user-oriented.
1990
def register_metadir(self, key, repo, help, native=True, deprecated=False):
1991
"""Register a metadir subformat.
1993
repo is the repository format name as a string.
1995
# This should be expanded to support setting WorkingTree and Branch
1996
# formats, once BzrDirMetaFormat1 supports that.
1998
import bzrlib.repository
1999
repo_format = getattr(bzrlib.repository, repo)
2000
bd = BzrDirMetaFormat1()
2001
bd.repository_format = repo_format()
2003
self.register(key, helper, help, native, deprecated)
2005
def register(self, key, factory, help, native=True, deprecated=False):
2006
"""Register a BzrDirFormat factory.
2008
The factory must be a callable that takes one parameter: the key.
2009
It must produce an instance of the BzrDirFormat when called.
2011
This function mainly exists to prevent the info object from being
2014
registry.Registry.register(self, key, factory, help,
2015
BzrDirFormatInfo(native, deprecated))
2017
def register_lazy(self, key, module_name, member_name, help, native=True,
2019
registry.Registry.register_lazy(self, key, module_name, member_name,
2020
help, BzrDirFormatInfo(native, deprecated))
2022
def set_default(self, key):
2023
"""Set the 'default' key to be a clone of the supplied key.
2025
This method must be called once and only once.
2027
registry.Registry.register(self, 'default', self.get(key),
2028
self.get_help(key), info=self.get_info(key))
2030
def set_default_repository(self, key):
2031
"""Set the FormatRegistry default and Repository default.
2033
This is a transitional method while Repository.set_default_format
2036
if 'default' in self:
2037
self.remove('default')
2038
self.set_default(key)
2039
format = self.get('default')()
2040
assert isinstance(format, BzrDirMetaFormat1)
2041
from bzrlib import repository
2042
repository.RepositoryFormat._set_default_format(
2043
format.repository_format)
2045
def make_bzrdir(self, key):
2046
return self.get(key)()
2048
def help_topic(self, topic):
2049
output = textwrap.dedent("""\
2050
Bazaar directory formats
2051
------------------------
2053
These formats can be used for creating branches, working trees, and
2057
default_help = self.get_help('default')
2059
for key in self.keys():
2060
if key == 'default':
2062
help = self.get_help(key)
2063
if help == default_help:
2064
default_realkey = key
2066
help_pairs.append((key, help))
2068
def wrapped(key, help, info):
2070
help = '(native) ' + help
2071
return ' %s:\n%s\n\n' % (key,
2072
textwrap.fill(help, initial_indent=' ',
2073
subsequent_indent=' '))
2074
output += wrapped('%s/default' % default_realkey, default_help,
2075
self.get_info('default'))
2076
deprecated_pairs = []
2077
for key, help in help_pairs:
2078
info = self.get_info(key)
2080
deprecated_pairs.append((key, help))
2082
output += wrapped(key, help, info)
2083
if len(deprecated_pairs) > 0:
2084
output += "Deprecated formats\n------------------\n\n"
2085
for key, help in deprecated_pairs:
2086
info = self.get_info(key)
2087
output += wrapped(key, help, info)
2092
format_registry = BzrDirFormatRegistry()
2093
format_registry.register('weave', BzrDirFormat6,
2094
'Pre-0.8 format. Slower than knit and does not'
2095
' support checkouts or shared repositories.', deprecated=True)
2096
format_registry.register_metadir('knit', 'RepositoryFormatKnit1',
2097
'Format using knits. Recommended.')
2098
format_registry.set_default('knit')
2099
format_registry.register_metadir('metaweave', 'RepositoryFormat7',
2100
'Transitional format in 0.8. Slower than knit.',
2102
format_registry.register_metadir('experimental-knit2', 'RepositoryFormatKnit2',
2103
'Experimental successor to knit. Use at your own risk.')