/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to doc/developers/api-versioning.txt

  • Committer: Robert Collins
  • Date: 2008-01-06 20:04:22 UTC
  • mto: (3221.11.1 StackableBranch)
  • mto: This revision was merged to the branch mainline in revision 3226.
  • Revision ID: robertc@robertcollins.net-20080106200422-x8yz6cxotlzltvwp
The bzrdir format registry now accepts an ``alias`` keyword to
register_metadir, used to indicate that a format name is an alias for
some other format and thus should not be reported when describing the
format. (Robert Collins)
-------------- This line and the fmllowing will be ignored --------------

modified:
  NEWS
  bzrlib/bzrdir.py
  bzrlib/info.py
  bzrlib/tests/test_bzrdir.py
  bzrlib/tests/test_info.py

=== modified file 'NEWS'
--- a/NEWS      2008-01-02 22:30:46 +0000
+++ b/NEWS      2008-01-06 20:04:15 +0000
@@ -135,6 +135,11 @@
     * Patience Diff now supports arbitrary python objects, as long as they
       support ``hash()``. (John Arbash Meinel)
 
+    * The bzrdir format registry now accepts an ``alias`` keyword to
+      register_metadir, used to indicate that a format name is an alias for
+      some other format and thus should not be reported when describing the
+      format. (Robert Collins)
+
   API BREAKS:
 
   TESTING:

=== modified file 'bzrlib/bzrdir.py'
--- a/bzrlib/bzrdir.py  2008-01-02 22:30:46 +0000
+++ b/bzrlib/bzrdir.py  2008-01-06 19:41:29 +0000
@@ -2447,12 +2447,22 @@
     e.g. BzrDirMeta1 with weave repository.  Also, it's more user-oriented.
     """
 
+    def __init__(self):
+        """Create a BzrDirFormatRegistry."""
+        self._aliases = set()
+        super(BzrDirFormatRegistry, self).__init__()
+
+    def aliases(self):
+        """Return a set of the format names which are aliases."""
+        return frozenset(self._aliases)
+
     def register_metadir(self, key,
              repository_format, help, native=True, deprecated=False,
              branch_format=None,
              tree_format=None,
              hidden=False,
-             experimental=False):
+             experimental=False,
+             alias=False):
         """Register a metadir subformat.
 
         These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
@@ -2491,10 +2501,10 @@
                 bd.repository_format = _load(repository_format)
             return bd
         self.register(key, helper, help, native, deprecated, hidden,
-            experimental)
+            experimental, alias)
 
     def register(self, key, factory, help, native=True, deprecated=False,
-                 hidden=False, experimental=False):
+                 hidden=False, experimental=False, alias=False):
         """Register a BzrDirFormat factory.
         
         The factory must be a callable that takes one parameter: the key.
@@ -2505,11 +2515,15 @@
         """
         registry.Registry.register(self, key, factory, help,
             BzrDirFormatInfo(native, deprecated, hidden, experimental))
+        if alias:
+            self._aliases.add(key)
 
     def register_lazy(self, key, module_name, member_name, help, native=True,
-                      deprecated=False, hidden=False, experimental=False):
+        deprecated=False, hidden=False, experimental=False, alias=False):
         registry.Registry.register_lazy(self, key, module_name, member_name,
             help, BzrDirFormatInfo(native, deprecated, hidden, experimental))
+        if alias:
+            self._aliases.add(key)
 
     def set_default(self, key):
         """Set the 'default' key to be a clone of the supplied key.
@@ -2518,6 +2532,7 @@
         """
         registry.Registry.register(self, 'default', self.get(key),
             self.get_help(key), info=self.get_info(key))
+        self._aliases.add('default')
 
     def set_default_repository(self, key):
         """Set the FormatRegistry default and Repository default.
@@ -2670,6 +2685,7 @@
     tree_format='bzrlib.workingtree.WorkingTreeFormat4',
     hidden=False,
     )
+# The following two formats should always just be aliases.
 format_registry.register_metadir('development',
     'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0',
     help='Current development format. Can convert data to and from pack-0.92 '
@@ -2681,6 +2697,7 @@
     branch_format='bzrlib.branch.BzrBranchFormat6',
     tree_format='bzrlib.workingtree.WorkingTreeFormat4',
     experimental=True,
+    alias=True,
     )
 format_registry.register_metadir('development-subtree',
     'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0Subtree',
@@ -2693,7 +2710,9 @@
     branch_format='bzrlib.branch.BzrBranchFormat6',
     tree_format='bzrlib.workingtree.WorkingTreeFormat4',
     experimental=True,
+    alias=True,
     )
+# And the development formats which the will have aliased one of follow:
 format_registry.register_metadir('development0',
     'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0',
     help='Trivial rename of pack-0.92 to provide a development format. '

=== modified file 'bzrlib/info.py'
--- a/bzrlib/info.py    2007-11-06 09:00:25 +0000
+++ b/bzrlib/info.py    2008-01-06 20:01:30 +0000
@@ -440,7 +440,9 @@
         tree.bzrdir.root_transport.base):
         branch = None
         repository = None
-    for key in bzrdir.format_registry.keys():
+    non_aliases = set(bzrdir.format_registry.keys())
+    non_aliases.difference_update(bzrdir.format_registry.aliases())
+    for key in non_aliases:
         format = bzrdir.format_registry.make_bzrdir(key)
         if isinstance(format, bzrdir.BzrDirMetaFormat1):
             if (tree and format.workingtree_format !=
@@ -457,11 +459,12 @@
         candidates.append(key)
     if len(candidates) == 0:
         return 'unnamed'
-    new_candidates = [c for c in candidates if c != 'default']
-    if len(new_candidates) > 0:
-        candidates = new_candidates
+    candidates.sort()
     new_candidates = [c for c in candidates if not
         bzrdir.format_registry.get_info(c).hidden]
     if len(new_candidates) > 0:
+        # If there are any non-hidden formats that match, only return those to
+        # avoid listing hidden formats except when only a hidden format will
+        # do.
         candidates = new_candidates
     return ' or '.join(candidates)

=== modified file 'bzrlib/tests/test_bzrdir.py'
--- a/bzrlib/tests/test_bzrdir.py       2007-12-21 20:32:22 +0000
+++ b/bzrlib/tests/test_bzrdir.py       2008-01-06 19:45:00 +0000
@@ -170,6 +170,16 @@
         finally:
             bzrdir.format_registry.set_default_repository(old_default)
 
+    def test_aliases(self):
+        a_registry = bzrdir.BzrDirFormatRegistry()
+        a_registry.register('weave', bzrdir.BzrDirFormat6,
+            'Pre-0.8 format.  Slower and does not support checkouts or shared'
+            ' repositories', deprecated=True)
+        a_registry.register('weavealias', bzrdir.BzrDirFormat6,
+            'Pre-0.8 format.  Slower and does not support checkouts or shared'
+            ' repositories', deprecated=True, alias=True)
+        self.assertEqual(frozenset(['weavealias']), a_registry.aliases())
+    
 
 class SampleBranch(bzrlib.branch.Branch):
     """A dummy branch for guess what, dummy use."""

=== modified file 'bzrlib/tests/test_info.py'
--- a/bzrlib/tests/test_info.py 2007-11-26 13:55:51 +0000
+++ b/bzrlib/tests/test_info.py 2008-01-06 20:02:10 +0000
@@ -126,16 +126,22 @@
 
     def test_describe_tree_format(self):
         for key in bzrdir.format_registry.keys():
-            if key == 'default':
+            if key in bzrdir.format_registry.aliases():
                 continue
             self.assertTreeDescription(key)
 
     def test_describe_checkout_format(self):
         for key in bzrdir.format_registry.keys():
-            if key in ('default', 'weave', 'experimental'):
-                continue
-            if key.startswith('experimental-'):
-                # these are typically hidden or aliases for other formats
+            if key in bzrdir.format_registry.aliases():
+                # Aliases will not describe correctly in the UI because the
+                # real format is found.
+                continue
+            # legacy: weave does not support checkouts
+            if key == 'weave':
+                continue
+            if bzrdir.format_registry.get_info(key).experimental:
+                # We don't require that experimental formats support checkouts
+                # or describe correctly in the UI.
                 continue
             expected = None
             if key in ('dirstate', 'dirstate-tags', 'dirstate-with-subtree',
@@ -149,7 +155,7 @@
 
     def test_describe_branch_format(self):
         for key in bzrdir.format_registry.keys():
-            if key == 'default':
+            if key in bzrdir.format_registry.aliases():
                 continue
             expected = None
             if key in ('dirstate', 'knit'):
@@ -158,7 +164,7 @@
 
     def test_describe_repo_format(self):
         for key in bzrdir.format_registry.keys():
-            if key == 'default':
+            if key in bzrdir.format_registry.aliases():
                 continue
             expected = None
             if key in ('dirstate', 'knit', 'dirstate-tags'):

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
==============
 
2
API Versioning
 
3
==============
 
4
 
 
5
Status
 
6
======
 
7
 
 
8
:Date: 2007-06-26
 
9
 
 
10
bzrlib has a rich API which is used both internally, and externally by
 
11
plugins and scripts. To allow the API to change, specifically to allow
 
12
support for features and methods to be removed, without causing hard to
 
13
diagnose bugs in the clients of the API, bzrlib provides explicit API
 
14
compatibility data, and a compact API to allow scripts and plugins to
 
15
ascertain if the bzrlib they are using is compatible to the API they were
 
16
written against.
 
17
 
 
18
 
 
19
.. contents::
 
20
 
 
21
 
 
22
Motivation
 
23
==========
 
24
 
 
25
To allow plugins to apply their own policy for compatibility with bzrlib,
 
26
without requiring a new release on every library release. Plugins should
 
27
also be able to use the API to export their own compatibility information
 
28
for code reuse between plugins.
 
29
 
 
30
 
 
31
Terminology
 
32
===========
 
33
 
 
34
An **API** is a collection of python objects/modules/packages which can be
 
35
used by plugins and scripts. The ``bzrlib`` **API** covers all of bzrlib,
 
36
but we can be more precise - e.g. the ``WorkingTree API``.
 
37
An **API version** is a tuple ``(major, minor, point)``.
 
38
 
 
39
 
 
40
API versions
 
41
============
 
42
 
 
43
For simplicity we treat API's as being compatible with a range of
 
44
versions: the current release of the API, and some oldest version which is
 
45
also compatible. While we could say that there is a set of older versions
 
46
with which the current version is compatible, a range is easier to
 
47
express, and easier for a human to look at and understand, and finally
 
48
easier to manage. The oldest version with which the API for a python
 
49
object is compatible is obtained by looking up the ``api_minimum_version``
 
50
attribute on the python object handed to ``require_api``, and failing that
 
51
the bzrlib ``api_minimum_version`` is returned. The current version of the
 
52
API is obtained by looking for an ``api_current_version`` attribute, and
 
53
if that is not found, an ``version_info`` attribute (of which the first 3
 
54
elements are used). If no current version can be found, the bzrlib
 
55
``version_info`` attribute is used to generate a current API version.
 
56
This lookup sequence allows users with simple setups (and no python style
 
57
``version_info`` tuple) to still export an API version, and for new API's
 
58
to be managed more granularly later on with a smooth transition -
 
59
everything starts off in lockstep with bzrlib's master version.
 
60
 
 
61
API versions are compared lexically to answer the question 'is
 
62
the requested version X <= the current version, and >= the minimum
 
63
version'.
 
64
 
 
65
Managing API versions
 
66
=====================
 
67
 
 
68
The minimum API versions should be adjusted to the **oldest** API version
 
69
with which client code of the API will successfully run. It should not be
 
70
changed simply because of adding things in a compatible manner, or
 
71
deprecating features, but rather when errors will occur if client code is
 
72
not updated.  Versions for API's from ``bzrlib`` are given the version
 
73
numbers that ``bzrlib`` has had for consistency. Plugins should also take
 
74
this approach and use the version numbering scheme the plugin used.
 
75
 
 
76
Exported API's
 
77
==============
 
78
 
 
79
Currently we export a single API - the ``bzrlib API`` - and no finer
 
80
grained APIs. The API versioning support was introduced in bzrlib 0.18.
 
81
For plugins or tools that want to dynamically check for the presence of
 
82
the API versioning API, you should compare ``bzrlib.version_info[0:3]``
 
83
with ``(0, 18, 0)``.
 
84
 
 
85
+------------+---------------+
 
86
| API        | Covers        | 
 
87
+============+===============+ 
 
88
| bzrlib     | All of bzrlib |
 
89
+------------+---------------+
 
90
 
 
91
Use Cases
 
92
=========
 
93
 
 
94
Some examples of using the API.
 
95
 
 
96
Requiring bzrlib 0.18 in a plugin
 
97
---------------------------------
 
98
 
 
99
In the plugins __init__.py::
 
100
 
 
101
  import bzrlib
 
102
  from bzrlib.api import require_api
 
103
  from bzrlib.errors import IncompatibleAPI
 
104
  try:
 
105
    require_api(bzrlib, (0, 18, 0))
 
106
  except IncompatibleAPI:
 
107
    raise ImportError("A bzrlib compatible with 0.18 is required.")
 
108
 
 
109
Exporting an API from a plugin
 
110
------------------------------
 
111
 
 
112
In the plugin ``foo`` exporting the API (in __init__.py)::
 
113
 
 
114
  version_info = (0, 0, 1, 'beta', 1)
 
115
  api_version = (0, 0, 1)
 
116
 
 
117
In a plugin depending on that plugin (in __init__.py)::
 
118
 
 
119
  import bzrlib.plugins.foo
 
120
  from bzrlib.api import require_api
 
121
  from bzrlib.errors import IncompatibleAPI
 
122
  try:
 
123
    require_api(bzrlib.plugins.foo, (0, 0, 1))
 
124
  except IncompatibleAPI:
 
125
    raise ImportError("A bzrlib compatible with 0.0.1 is required.")
 
126
 
 
127
 
 
128
..
 
129
   vim: ft=rst tw=74 ai
 
130