Merge lp:~jelmer/bzr/2.1-feature-flags into lp:bzr/2.1

Proposed by Jelmer Vernooij
Status: Merged
Approved by: Vincent Ladeuil
Approved revision: no longer in the source branch.
Merged at revision: 4883
Proposed branch: lp:~jelmer/bzr/2.1-feature-flags
Merge into: lp:bzr/2.1
Diff against target: 156 lines (+78/-1)
7 files modified
NEWS (+4/-0)
bzrlib/branch.py (+2/-1)
bzrlib/bzrdir.py (+28/-0)
bzrlib/errors.py (+20/-0)
bzrlib/repository.py (+1/-0)
bzrlib/tests/test_bzrdir.py (+22/-0)
bzrlib/workingtree.py (+1/-0)
To merge this branch: bzr merge lp:~jelmer/bzr/2.1-feature-flags
Reviewer Review Type Date Requested Status
Vincent Ladeuil Approve
Review via email: mp+97636@code.launchpad.net

Commit message

Add basic support for feature flags.

Description of the change

Add basic support for feature flags to the 2.1 release series.

This does the bare minimum to:
 * ignore optional feature flags
 * raise an appropriate error (non-confusing) for any other feature flags

To post a comment you must log in.
Revision history for this message
Vincent Ladeuil (vila) wrote :

Looks mostly fine :)

I'm unclear about how this diverges from implementation in 2.5 though, can you elaborate ?

This seems to special-case for branch, why is that ? Repo and wt relies on bzrdir but not branch ? Is this also true for 2.2 and up ?

Also, the following tests fails:

=== modified file 'bzrlib/tests/test_bzrdir.py'
--- bzrlib/tests/test_bzrdir.py 2012-03-15 14:54:05 +0000
+++ bzrlib/tests/test_bzrdir.py 2012-03-16 08:27:13 +0000
@@ -1386,3 +1386,11 @@
         self.assertRaises(errors.ParseFormatError,
             bzrdir.extract_format_string, "Bazaar-NG branch, format 0.0.4\n"
                                           "requiredfoo\n")
+
+ def test_with_empty_file(self):
+ self.assertRaises(errors.ParseFormatError,
+ bzrdir.extract_format_string, "")
+
+ def test_with_corrupted_file(self):
+ self.assertRaises(errors.ParseFormatError,
+ bzrdir.extract_format_string, "Bazaar-NG branch")

Again, I'm not sure if this diverges from the *actual* behavior but since the format file is modified when a feature is added/removed, I'd like us to be paranoid about *new* potential failures. I.e. if the actual implementation does not raise ParseFormatError for these tests, fine, otherwise, please consider adding them anf fixing the fallouts ;)

Finally, I don't quite understand why you 4 proposals instead of just this one. If they are all the same, no need for 4 reviews, once this one is approved, just merge up to trunk.

review: Needs Information
Revision history for this message
Vincent Ladeuil (vila) wrote :

I failed to mention: I've dreamed for a looong time of being able to review some code by just adding failing tests... raising the S/N ratio to a factual question.

Thanks for making a proposal focused and well tested allowing my dream to come true ;-)

Revision history for this message
Vincent Ladeuil (vila) wrote :

One more thing: how did you test this ?

For the review purpose I tried './bzr selftest -s bt.test_bzrdir.ExtractFormatStringTests' which failed horribly with the python/subunit/testtools I use on precise. I then switch to your bzr-2.4 proposal (noticing no difference from a causal reading) and things were fine there.

Still, not being able to run the tests for a supported release makes it harder to release or review (not unrelated to the ML thread about selftest ;). So please enlight me :) Some lucid chroot ?

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

> I'm unclear about how this diverges from implementation in 2.5 though, can you
> elaborate ?
It doesn't actually allow users to register features or use them. It just makes bzr 2.1 ignore optional features and raise an appropriate error when non-optional features are encountered. This is why the branch is so simple.

> This seems to special-case for branch, why is that ? Repo and wt relies on
> bzrdir but not branch ? Is this also true for 2.2 and up ?
I'm not sure I follow; It doesn't special case branch, updating branch is a single line change just like working tree, bzrdir and repository. Can you elaborate perhaps?

>
> Also, the following tests fails:
>
> === modified file 'bzrlib/tests/test_bzrdir.py'
> --- bzrlib/tests/test_bzrdir.py 2012-03-15 14:54:05 +0000
> +++ bzrlib/tests/test_bzrdir.py 2012-03-16 08:27:13 +0000
> @@ -1386,3 +1386,11 @@
> self.assertRaises(errors.ParseFormatError,
> bzrdir.extract_format_string, "Bazaar-NG branch, format 0.0.4\n"
> "requiredfoo\n")
> +
> + def test_with_empty_file(self):
> + self.assertRaises(errors.ParseFormatError,
> + bzrdir.extract_format_string, "")
> +
> + def test_with_corrupted_file(self):
> + self.assertRaises(errors.ParseFormatError,
> + bzrdir.extract_format_string, "Bazaar-NG branch")
>
> Again, I'm not sure if this diverges from the *actual* behavior but since the
> format file is modified when a feature is added/removed, I'd like us to be
> paranoid about *new* potential failures. I.e. if the actual implementation
> does not raise ParseFormatError for these tests, fine, otherwise, please
> consider adding them anf fixing the fallouts ;)
The actual implementation doesn't have extract_format_string, since it doesn't apply there (it has a more complex parsing function). I'll look into the failures.

> Finally, I don't quite understand why you 4 proposals instead of just this
> one. If they are all the same, no need for 4 reviews, once this one is
> approved, just merge up to trunk.
They aren't the same, there are differences to the format infrastructure for each branch that would otherwise cause conflicts.

Revision history for this message
Vincent Ladeuil (vila) wrote :

> > I'm unclear about how this diverges from implementation in 2.5 though, can
> you
> > elaborate ?
> It doesn't actually allow users to register features or use them. It just
> makes bzr 2.1 ignore optional features and raise an appropriate error when
> non-optional features are encountered. This is why the branch is so simple.

Right. I was slightly confused that I couldn't find extract_format_string() in trunk.

>
> > This seems to special-case for branch, why is that ? Repo and wt relies on
> > bzrdir but not branch ? Is this also true for 2.2 and up ?
> I'm not sure I follow; It doesn't special case branch, updating branch is a
> single line change just like working tree, bzrdir and repository. Can you
> elaborate perhaps?

Hmm, yeah, gimme a minute to turn sober....

...

ha, indeed, I missed the single line change in wt and repo, please forgive me ;)

> The actual implementation doesn't have extract_format_string, since it doesn't
> apply there (it has a more complex parsing function).

Ok, so you will remove extract_format_string when merging up then. Ok, I was hoping we could keep it and add the needed features instead to keep a single place to maintain, but no big deal as long as we can keep the tests ?

> I'll look into the
> failures.

Cool.

>
> > Finally, I don't quite understand why you 4 proposals instead of just this
> > one. If they are all the same, no need for 4 reviews, once this one is
> > approved, just merge up to trunk.
> They aren't the same, there are differences to the format infrastructure for
> each branch that would otherwise cause conflicts.

:-/ Let's hope we don't need to fix bugs there then. Maintaining the same feature in 5 (or 6 ?) different forms *for* a dvcs tool sounds like a good way to become insane ;)

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

> > The actual implementation doesn't have extract_format_string, since it
> doesn't
> > apply there (it has a more complex parsing function).
> Ok, so you will remove extract_format_string when merging up then. Ok, I was
> hoping we could keep it and add the needed features instead to keep a single
> place to maintain, but no big deal as long as we can keep the tests ?
Yep.

> > I'll look into the
> > failures.
> Cool.
Fixed now.

> > > Finally, I don't quite understand why you 4 proposals instead of just this
> > > one. If they are all the same, no need for 4 reviews, once this one is
> > > approved, just merge up to trunk.
> > They aren't the same, there are differences to the format infrastructure for
> > each branch that would otherwise cause conflicts.
> :-/ Let's hope we don't need to fix bugs there then. Maintaining the same
> feature in 5 (or 6 ?) different forms *for* a dvcs tool sounds like a good way
> to become insane ;
It's not radically different, but simply upmerging triggers conflicts.

I've tested this in a lucid chroot, as 2.1's testsuite indeed doesn't run on precise.

Cheers,

Jelmer

Revision history for this message
Vincent Ladeuil (vila) wrote :

> > > The actual implementation doesn't have extract_format_string, since it
> > doesn't
> > > apply there (it has a more complex parsing function).
> > Ok, so you will remove extract_format_string when merging up then. Ok, I was
> > hoping we could keep it and add the needed features instead to keep a single
> > place to maintain, but no big deal as long as we can keep the tests ?
> Yep.

Great.

>
> > > I'll look into the
> > > failures.
> > Cool.
> Fixed now.

Thanks.

>
> > > > Finally, I don't quite understand why you 4 proposals instead of just
> this
> > > > one. If they are all the same, no need for 4 reviews, once this one is
> > > > approved, just merge up to trunk.
> > > They aren't the same, there are differences to the format infrastructure
> for
> > > each branch that would otherwise cause conflicts.
> > :-/ Let's hope we don't need to fix bugs there then. Maintaining the same
> > feature in 5 (or 6 ?) different forms *for* a dvcs tool sounds like a good
> way
> > to become insane ;
> It's not radically different, but simply upmerging triggers conflicts.
>

:-/

> I've tested this in a lucid chroot, as 2.1's testsuite indeed doesn't run on
> precise.
>

Ok.

review: Approve
Revision history for this message
Vincent Ladeuil (vila) wrote :

Unless you encounter issues or want more feedback for your other related proposals, just merge up the tests and land them too.

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

sent to pqm by email

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

sent to pqm by email

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

sent to pqm by email

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

sent to pqm by email

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS'
2--- NEWS 2011-08-19 12:49:28 +0000
3+++ NEWS 2012-03-18 19:06:24 +0000
4@@ -47,6 +47,10 @@
5 Improvements
6 ************
7
8+ * When opening formats with feature flags, optional features are
9+ ignored and an improved error is printed for non-optional features.
10+ (Jelmer Vernooij)
11+
12 Documentation
13 *************
14
15
16=== modified file 'bzrlib/branch.py'
17--- bzrlib/branch.py 2010-02-17 17:11:16 +0000
18+++ bzrlib/branch.py 2012-03-18 19:06:24 +0000
19@@ -1438,7 +1438,8 @@
20 """Return the format for the branch object in a_bzrdir."""
21 try:
22 transport = a_bzrdir.get_branch_transport(None)
23- format_string = transport.get_bytes("format")
24+ format_string = bzrdir.extract_format_string(
25+ transport.get_bytes("format"))
26 return klass._formats[format_string]
27 except errors.NoSuchFile:
28 raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
29
30=== modified file 'bzrlib/bzrdir.py'
31--- bzrlib/bzrdir.py 2010-11-26 18:10:01 +0000
32+++ bzrlib/bzrdir.py 2012-03-18 19:06:24 +0000
33@@ -87,6 +87,32 @@
34 )
35
36
37+def extract_format_string(text):
38+ """Read a format string from a file.
39+
40+ The first line is returned. The other lines can contain
41+ optional features. An exception is raised when a
42+ required feature is present.
43+ """
44+ lines = text.splitlines(True)
45+ try:
46+ firstline = lines.pop(0)
47+ except IndexError:
48+ raise errors.UnknownFormatError(format=text, kind='')
49+ for lineno, line in enumerate(lines):
50+ try:
51+ (necessity, feature) = line.split(" ", 1)
52+ except ValueError:
53+ raise errors.ParseFormatError(lineno=lineno+2,
54+ line=line, text=text)
55+ else:
56+ if necessity == "optional":
57+ mutter("Ignoring optional feature %s", feature)
58+ else:
59+ raise errors.MissingFeature(feature)
60+ return firstline
61+
62+
63 class BzrDir(object):
64 """A .bzr control diretory.
65
66@@ -1829,6 +1855,8 @@
67 except errors.NoSuchFile:
68 raise errors.NotBranchError(path=transport.base)
69
70+ format_string = extract_format_string(format_string)
71+
72 try:
73 return klass._formats[format_string]
74 except KeyError:
75
76=== modified file 'bzrlib/errors.py'
77--- bzrlib/errors.py 2010-09-10 05:13:57 +0000
78+++ bzrlib/errors.py 2012-03-18 19:06:24 +0000
79@@ -3136,3 +3136,23 @@
80
81 def __init__(self, path):
82 self.path = path
83+
84+
85+class MissingFeature(BzrError):
86+
87+ _fmt = ("Missing feature %(feature)s not provided by this "
88+ "version of Bazaar or any plugin.")
89+
90+ def __init__(self, feature):
91+ self.feature = feature
92+
93+
94+class ParseFormatError(BzrError):
95+
96+ _fmt = "Parse error on line %(lineno)d of format name: %(line)s"
97+
98+ def __init__(self, lineno, line, text):
99+ BzrError.__init__(self)
100+ self.lineno = lineno
101+ self.line = line
102+ self.text = text
103
104=== modified file 'bzrlib/repository.py'
105--- bzrlib/repository.py 2010-11-30 20:42:42 +0000
106+++ bzrlib/repository.py 2012-03-18 19:06:24 +0000
107@@ -3107,6 +3107,7 @@
108 try:
109 transport = a_bzrdir.get_repository_transport(None)
110 format_string = transport.get_bytes("format")
111+ format_string = bzrdir.extract_format_string(format_string)
112 return format_registry.get(format_string)
113 except errors.NoSuchFile:
114 raise errors.NoRepositoryPresent(a_bzrdir)
115
116=== modified file 'bzrlib/tests/test_bzrdir.py'
117--- bzrlib/tests/test_bzrdir.py 2010-02-17 17:11:16 +0000
118+++ bzrlib/tests/test_bzrdir.py 2012-03-18 19:06:24 +0000
119@@ -1333,3 +1333,25 @@
120 url = transport.base
121 err = self.assertRaises(errors.BzrError, bzrdir.BzrDir.open, url)
122 self.assertEqual('fail', err._preformatted_string)
123+
124+
125+class ExtractFormatStringTests(TestCase):
126+
127+ def test_normal(self):
128+ self.assertEquals("Bazaar-NG branch, format 0.0.4\n",
129+ bzrdir.extract_format_string("Bazaar-NG branch, format 0.0.4\n"))
130+
131+ def test_with_optional_feature(self):
132+ self.assertEquals("Bazaar-NG branch, format 0.0.4\n",
133+ bzrdir.extract_format_string("Bazaar-NG branch, format 0.0.4\n"
134+ "optional feature foo\n"))
135+
136+ def test_with_required_feature(self):
137+ self.assertRaises(errors.MissingFeature,
138+ bzrdir.extract_format_string, "Bazaar-NG branch, format 0.0.4\n"
139+ "required feature foo\n")
140+
141+ def test_with_invalid_line(self):
142+ self.assertRaises(errors.ParseFormatError,
143+ bzrdir.extract_format_string, "Bazaar-NG branch, format 0.0.4\n"
144+ "requiredfoo\n")
145
146=== modified file 'bzrlib/workingtree.py'
147--- bzrlib/workingtree.py 2010-01-21 17:54:58 +0000
148+++ bzrlib/workingtree.py 2012-03-18 19:06:24 +0000
149@@ -2799,6 +2799,7 @@
150 try:
151 transport = a_bzrdir.get_workingtree_transport(None)
152 format_string = transport.get_bytes("format")
153+ format_string = bzrdir.extract_format_string(format_string)
154 return klass._formats[format_string]
155 except errors.NoSuchFile:
156 raise errors.NoWorkingTree(base=transport.base)

Subscribers

People subscribed via source and target branches