Merge lp:~jelmer/bzr/testament-tree into lp:bzr

Proposed by Jelmer Vernooij
Status: Merged
Approved by: Jelmer Vernooij
Approved revision: no longer in the source branch.
Merged at revision: 5804
Proposed branch: lp:~jelmer/bzr/testament-tree
Merge into: lp:bzr
Diff against target: 271 lines (+79/-32)
7 files modified
bzrlib/bundle/bundle_data.py (+32/-12)
bzrlib/bundle/serializer/v08.py (+2/-2)
bzrlib/bundle/serializer/v09.py (+2/-2)
bzrlib/repository.py (+3/-1)
bzrlib/testament.py (+22/-12)
bzrlib/tests/test_testament.py (+15/-3)
doc/en/release-notes/bzr-2.4.txt (+3/-0)
To merge this branch: bzr merge lp:~jelmer/bzr/testament-tree
Reviewer Review Type Date Requested Status
Martin Pool Approve
Review via email: mp+58243@code.launchpad.net

This proposal supersedes a proposal from 2011-04-18.

Commit message

Make TestamentTree use a Tree rather than an Inventory.

Description of the change

Make Testament take a Tree rather than an Inventory.

To post a comment you must log in.
Revision history for this message
Martin Pool (mbp) wrote : Posted in a previous version of this proposal

I'm not generally a big fan of changing the expected parameter types for existing methods because it can lead to confusing failures in Python. There may not be an out-of-tree users of these though.

In order of decreasing complexity and decreasing niceness-to-callers:

* add a new method and retain but deprecate the old one.
* rename the methods/classes when you change their parameters
* check the argument type passed in and complain if it's an Inventory

the last is fine with me.

review: Needs Fixing
Revision history for this message
Jelmer Vernooij (jelmer) wrote : Posted in a previous version of this proposal

Thanks for the review. :)

I've added a check to make sure the second argument is an instance of Tree.

Revision history for this message
Martin Pool (mbp) wrote :

Are there tests that will protect against this accidentally changing the generated values? Otherwise, all good.

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

Yep, there are existing tests for testaments that assert specific testament strings are generated for specific trees.

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 'bzrlib/bundle/bundle_data.py'
2--- bzrlib/bundle/bundle_data.py 2010-09-28 18:51:47 +0000
3+++ bzrlib/bundle/bundle_data.py 2011-04-19 12:54:51 +0000
4@@ -25,20 +25,22 @@
5 osutils,
6 timestamp,
7 )
8-import bzrlib.errors
9 from bzrlib.bundle import apply_bundle
10-from bzrlib.errors import (TestamentMismatch, BzrError,
11- MalformedHeader, MalformedPatches, NotABundle)
12-from bzrlib.inventory import (Inventory, InventoryEntry,
13- InventoryDirectory, InventoryFile,
14- InventoryLink)
15-from bzrlib.osutils import sha_file, sha_string, pathjoin
16+from bzrlib.errors import (
17+ TestamentMismatch,
18+ BzrError,
19+ )
20+from bzrlib.inventory import (
21+ Inventory,
22+ InventoryDirectory,
23+ InventoryFile,
24+ InventoryLink,
25+ )
26+from bzrlib.osutils import sha_string, pathjoin
27 from bzrlib.revision import Revision, NULL_REVISION
28 from bzrlib.testament import StrictTestament
29 from bzrlib.trace import mutter, warning
30-import bzrlib.transport
31 from bzrlib.tree import Tree
32-import bzrlib.urlutils
33 from bzrlib.xml5 import serializer_v5
34
35
36@@ -206,7 +208,7 @@
37
38 inv = bundle_tree.inventory
39 self._validate_inventory(inv, revision_id)
40- self._validate_revision(inv, revision_id)
41+ self._validate_revision(bundle_tree, revision_id)
42
43 return bundle_tree
44
45@@ -286,7 +288,7 @@
46 warning('Inventory sha hash mismatch for revision %s. %s'
47 ' != %s' % (revision_id, sha1, rev.inventory_sha1))
48
49- def _validate_revision(self, inventory, revision_id):
50+ def _validate_revision(self, tree, revision_id):
51 """Make sure all revision entries match their checksum."""
52
53 # This is a mapping from each revision id to its sha hash
54@@ -298,7 +300,7 @@
55 raise AssertionError()
56 if not (rev.revision_id == revision_id):
57 raise AssertionError()
58- sha1 = self._testament_sha1(rev, inventory)
59+ sha1 = self._testament_sha1(rev, tree)
60 if sha1 != rev_info.sha1:
61 raise TestamentMismatch(rev.revision_id, rev_info.sha1, sha1)
62 if rev.revision_id in rev_to_sha1:
63@@ -462,6 +464,7 @@
64
65
66 class BundleTree(Tree):
67+
68 def __init__(self, base_tree, revision_id):
69 self.base_tree = base_tree
70 self._renamed = {} # Mapping from old_path => new_path
71@@ -739,6 +742,23 @@
72 for path, entry in self.inventory.iter_entries():
73 yield entry.file_id
74
75+ def list_files(self, include_root=False, from_dir=None, recursive=True):
76+ # The only files returned by this are those from the version
77+ inv = self.inventory
78+ if from_dir is None:
79+ from_dir_id = None
80+ else:
81+ from_dir_id = inv.path2id(from_dir)
82+ if from_dir_id is None:
83+ # Directory not versioned
84+ return
85+ entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
86+ if inv.root is not None and not include_root and from_dir is None:
87+ # skip the root for compatability with the current apis.
88+ entries.next()
89+ for path, entry in entries:
90+ yield path, 'V', entry.kind, entry.file_id, entry
91+
92 def sorted_path_id(self):
93 paths = []
94 for result in self._new_id.iteritems():
95
96=== modified file 'bzrlib/bundle/serializer/v08.py'
97--- bzrlib/bundle/serializer/v08.py 2009-06-05 23:15:23 +0000
98+++ bzrlib/bundle/serializer/v08.py 2011-04-19 12:54:51 +0000
99@@ -553,5 +553,5 @@
100 testament = StrictTestament.from_revision(repository, revision_id)
101 return testament.as_sha1()
102
103- def _testament_sha1(self, revision, inventory):
104- return StrictTestament(revision, inventory).as_sha1()
105+ def _testament_sha1(self, revision, tree):
106+ return StrictTestament(revision, tree).as_sha1()
107
108=== modified file 'bzrlib/bundle/serializer/v09.py'
109--- bzrlib/bundle/serializer/v09.py 2009-03-23 14:59:43 +0000
110+++ bzrlib/bundle/serializer/v09.py 2011-04-19 12:54:51 +0000
111@@ -63,8 +63,8 @@
112 testament = StrictTestament3.from_revision(repository, revision_id)
113 return testament.as_sha1()
114
115- def _testament_sha1(self, revision, inventory):
116- return StrictTestament3(revision, inventory).as_sha1()
117+ def _testament_sha1(self, revision, tree):
118+ return StrictTestament3(revision, tree).as_sha1()
119
120
121 class BundleReaderV09(BundleReader):
122
123=== modified file 'bzrlib/repository.py'
124--- bzrlib/repository.py 2011-04-17 18:24:56 +0000
125+++ bzrlib/repository.py 2011-04-19 12:54:51 +0000
126@@ -1163,7 +1163,9 @@
127 if config is not None and config.signature_needed():
128 if inv is None:
129 inv = self.get_inventory(revision_id)
130- plaintext = Testament(rev, inv).as_short_text()
131+ tree = InventoryRevisionTree(self, inv, revision_id)
132+ testament = Testament(rev, tree)
133+ plaintext = testament.as_short_text()
134 self.store_revision_signature(
135 gpg.GPGStrategy(config), plaintext, revision_id)
136 # check inventory present
137
138=== modified file 'bzrlib/testament.py'
139--- bzrlib/testament.py 2009-03-23 14:59:43 +0000
140+++ bzrlib/testament.py 2011-04-19 12:54:51 +0000
141@@ -76,6 +76,7 @@
142 contains_linebreaks,
143 sha,
144 )
145+from bzrlib.tree import Tree
146
147
148 class Testament(object):
149@@ -91,23 +92,33 @@
150
151 long_header = 'bazaar-ng testament version 1\n'
152 short_header = 'bazaar-ng testament short form 1\n'
153+ include_root = False
154
155 @classmethod
156 def from_revision(cls, repository, revision_id):
157- """Produce a new testament from a historical revision"""
158+ """Produce a new testament from a historical revision."""
159 rev = repository.get_revision(revision_id)
160- inventory = repository.get_inventory(revision_id)
161- return cls(rev, inventory)
162-
163- def __init__(self, rev, inventory):
164- """Create a new testament for rev using inventory."""
165+ tree = repository.revision_tree(revision_id)
166+ return cls(rev, tree)
167+
168+ @classmethod
169+ def from_revision_tree(cls, tree):
170+ """Produce a new testament from a revision tree."""
171+ rev = tree._repository.get_revision(tree.get_revision_id())
172+ return cls(rev, tree)
173+
174+ def __init__(self, rev, tree):
175+ """Create a new testament for rev using tree."""
176 self.revision_id = rev.revision_id
177 self.committer = rev.committer
178 self.timezone = rev.timezone or 0
179 self.timestamp = rev.timestamp
180 self.message = rev.message
181 self.parent_ids = rev.parent_ids[:]
182- self.inventory = inventory
183+ if not isinstance(tree, Tree):
184+ raise TypeError("As of bzr 2.4 Testament.__init__() takes a "
185+ "Revision and a Tree.")
186+ self.tree = tree
187 self.revprops = copy(rev.properties)
188 if contains_whitespace(self.revision_id):
189 raise ValueError(self.revision_id)
190@@ -143,9 +154,8 @@
191 return [line.encode('utf-8') for line in r]
192
193 def _get_entries(self):
194- entries = self.inventory.iter_entries()
195- entries.next()
196- return entries
197+ return ((path, ie) for (path, versioned, kind, file_id, ie) in
198+ self.tree.list_files(include_root=self.include_root))
199
200 def _escape_path(self, path):
201 if contains_linebreaks(path):
202@@ -209,6 +219,7 @@
203
204 long_header = 'bazaar-ng testament version 2.1\n'
205 short_header = 'bazaar-ng testament short form 2.1\n'
206+ include_root = False
207 def _entry_to_line(self, path, ie):
208 l = Testament._entry_to_line(self, path, ie)[:-1]
209 l += ' ' + ie.revision
210@@ -224,8 +235,7 @@
211
212 long_header = 'bazaar testament version 3 strict\n'
213 short_header = 'bazaar testament short form 3 strict\n'
214- def _get_entries(self):
215- return self.inventory.iter_entries()
216+ include_root = True
217
218 def _escape_path(self, path):
219 if contains_linebreaks(path):
220
221=== modified file 'bzrlib/tests/test_testament.py'
222--- bzrlib/tests/test_testament.py 2010-11-05 20:54:32 +0000
223+++ bzrlib/tests/test_testament.py 2011-04-19 12:54:51 +0000
224@@ -22,7 +22,11 @@
225
226 from bzrlib import osutils
227 from bzrlib.tests import SymlinkFeature, TestCaseWithTransport
228-from bzrlib.testament import Testament, StrictTestament, StrictTestament3
229+from bzrlib.testament import (
230+ Testament,
231+ StrictTestament,
232+ StrictTestament3,
233+ )
234 from bzrlib.transform import TreeTransform
235
236
237@@ -136,10 +140,18 @@
238 self.assertEqualDiff(
239 self.expected('sample_unicode').encode('utf-8'), t.as_text())
240
241+ def test_from_tree(self):
242+ tree = self.b.repository.revision_tree('test@user-2')
243+ testament = self.testament_class().from_revision_tree(tree)
244+ text_1 = testament.as_short_text()
245+ text_2 = self.from_revision(self.b.repository,
246+ 'test@user-2').as_short_text()
247+ self.assertEqual(text_1, text_2)
248+
249 def test___init__(self):
250 revision = self.b.repository.get_revision('test@user-2')
251- inventory = self.b.repository.get_inventory('test@user-2')
252- testament_1 = self.testament_class()(revision, inventory)
253+ tree = self.b.repository.revision_tree('test@user-2')
254+ testament_1 = self.testament_class()(revision, tree)
255 text_1 = testament_1.as_short_text()
256 text_2 = self.from_revision(self.b.repository,
257 'test@user-2').as_short_text()
258
259=== modified file 'doc/en/release-notes/bzr-2.4.txt'
260--- doc/en/release-notes/bzr-2.4.txt 2011-04-19 04:37:48 +0000
261+++ doc/en/release-notes/bzr-2.4.txt 2011-04-19 12:54:51 +0000
262@@ -138,6 +138,9 @@
263 on ``RepositoryFormat`` rather than a method on ``Repository``.
264 (Jelmer Vernooij)
265
266+* ``Testament`` now takes a ``tree`` rather than an
267+ ``inventory``. (Jelmer Vernooij, #762608)
268+
269 * ``TestCase.failUnlessExists`` and ``failIfExists`` are deprecated in
270 favour of ``assertPathExists`` and ``assertPathDoesNotExist``
271 respectively.