Merge lp:~jelmer/brz/per-tree-git-revtree into lp:brz

Proposed by Jelmer Vernooij on 2018-09-09
Status: Merged
Approved by: Jelmer Vernooij on 2018-09-15
Approved revision: 7105
Merge reported by: The Breezy Bot
Merged at revision: not available
Proposed branch: lp:~jelmer/brz/per-tree-git-revtree
Merge into: lp:brz
Diff against target: 470 lines (+139/-58)
9 files modified
breezy/git/mapping.py (+1/-1)
breezy/git/tests/test_mapping.py (+1/-1)
breezy/git/tree.py (+69/-23)
breezy/tests/per_tree/__init__.py (+15/-3)
breezy/tests/per_tree/test_list_files.py (+1/-1)
breezy/tests/per_tree/test_path_content_summary.py (+6/-2)
breezy/tests/per_tree/test_test_trees.py (+3/-3)
breezy/tests/per_tree/test_walkdirs.py (+30/-23)
breezy/tests/test_selftest.py (+13/-1)
To merge this branch: bzr merge lp:~jelmer/brz/per-tree-git-revtree
Reviewer Review Type Date Requested Status
Martin Packman 2018-09-09 Approve on 2018-09-14
Review via email: mp+354530@code.launchpad.net

Commit message

Run per_tree tests against GitRevisionTree.

Description of the change

Run per_tree tests against GitRevisionTree.

To post a comment you must log in.
Martin Packman (gz) wrote :

Changes look reasonable enough to me.

review: Approve
The Breezy Bot (the-breezy-bot) wrote :

Running landing tests failed
https://ci.breezy-vcs.org/job/land-brz/475/

The Breezy Bot (the-breezy-bot) wrote :

Running landing tests failed
https://ci.breezy-vcs.org/job/land-brz/481/

The Breezy Bot (the-breezy-bot) wrote :

Running landing tests failed
https://ci.breezy-vcs.org/job/land-brz/482/

lp:~jelmer/brz/per-tree-git-revtree updated on 2018-09-15
7105. By Jelmer Vernooij on 2018-09-15

Fix scenarios test.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'breezy/git/mapping.py'
2--- breezy/git/mapping.py 2018-08-04 17:32:58 +0000
3+++ breezy/git/mapping.py 2018-09-15 00:21:08 +0000
4@@ -429,7 +429,7 @@
5 parents.append(lookup_parent_revid(p))
6 except KeyError:
7 parents.append(self.revision_id_foreign_to_bzr(p))
8- rev.parent_ids = tuple(parents)
9+ rev.parent_ids = list(parents)
10 unknown_extra_fields = []
11 extra_lines = []
12 for k, v in commit.extra:
13
14=== modified file 'breezy/git/tests/test_mapping.py'
15--- breezy/git/tests/test_mapping.py 2018-08-04 17:32:58 +0000
16+++ breezy/git/tests/test_mapping.py 2018-09-15 00:21:08 +0000
17@@ -117,7 +117,7 @@
18 self.assertEqual(u"Committer", rev.committer)
19 self.assertEqual(u"Author", rev.properties[u'author'])
20 self.assertEqual(300, rev.timezone)
21- self.assertEqual((), rev.parent_ids)
22+ self.assertEqual([], rev.parent_ids)
23 self.assertEqual("5", rev.properties[u'author-timestamp'])
24 self.assertEqual("180", rev.properties[u'author-timezone'])
25 self.assertEqual(b"git-v1:" + c.id, rev.revision_id)
26
27=== modified file 'breezy/git/tree.py'
28--- breezy/git/tree.py 2018-08-18 21:01:10 +0000
29+++ breezy/git/tree.py 2018-09-15 00:21:08 +0000
30@@ -19,6 +19,7 @@
31
32 from __future__ import absolute_import
33
34+from collections import deque
35 import errno
36 from io import BytesIO
37 import os
38@@ -289,7 +290,7 @@
39 try:
40 revid = self.get_file_revision(path, file_id)
41 except KeyError:
42- raise _mod_tree.FileTimestampUnavailable(path)
43+ raise errors.NoSuchFile(path)
44 try:
45 rev = self._repository.get_revision(revid)
46 except errors.NoSuchRevision:
47@@ -311,13 +312,15 @@
48 def path2id(self, path):
49 if self.mapping.is_special_file(path):
50 return None
51+ if not self.is_versioned(path):
52+ return None
53 return self._fileid_map.lookup_file_id(osutils.safe_unicode(path))
54
55 def all_file_ids(self):
56- return set(self._fileid_map.all_file_ids())
57+ return {self.path2id(path) for path in self.all_versioned_paths()}
58
59 def all_versioned_paths(self):
60- ret = set()
61+ ret = {u''}
62 todo = [(self.store, b'', self.tree)]
63 while todo:
64 (store, path, tree_id) = todo.pop()
65@@ -326,10 +329,9 @@
66 tree = store[tree_id]
67 for name, mode, hexsha in tree.items():
68 subpath = posixpath.join(path, name)
69+ ret.add(subpath.decode('utf-8'))
70 if stat.S_ISDIR(mode):
71 todo.append((store, subpath, hexsha))
72- else:
73- ret.add(subpath.decode('utf-8'))
74 return ret
75
76 def get_root_id(self):
77@@ -393,32 +395,33 @@
78 if mode is None: # Root
79 root_ie = self._get_dir_ie(b"", None)
80 else:
81- parent_path = posixpath.dirname(from_dir.encode("utf-8"))
82+ parent_path = posixpath.dirname(from_dir)
83 parent_id = self._fileid_map.lookup_file_id(parent_path)
84 if mode_kind(mode) == 'directory':
85 root_ie = self._get_dir_ie(from_dir.encode("utf-8"), parent_id)
86 else:
87 root_ie = self._get_file_ie(store, from_dir.encode("utf-8"),
88 posixpath.basename(from_dir), mode, hexsha)
89- if from_dir != "" or include_root:
90+ if include_root:
91 yield (from_dir, "V", root_ie.kind, root_ie.file_id, root_ie)
92 todo = []
93 if root_ie.kind == 'directory':
94- todo.append((store, from_dir.encode("utf-8"), hexsha, root_ie.file_id))
95+ todo.append((store, from_dir.encode("utf-8"), b"", hexsha, root_ie.file_id))
96 while todo:
97- (store, path, hexsha, parent_id) = todo.pop()
98+ (store, path, relpath, hexsha, parent_id) = todo.pop()
99 tree = store[hexsha]
100 for name, mode, hexsha in tree.iteritems():
101 if self.mapping.is_special_file(name):
102 continue
103 child_path = posixpath.join(path, name)
104+ child_relpath = posixpath.join(relpath, name)
105 if stat.S_ISDIR(mode):
106 ie = self._get_dir_ie(child_path, parent_id)
107 if recursive:
108- todo.append((store, child_path, hexsha, ie.file_id))
109+ todo.append((store, child_path, child_relpath, hexsha, ie.file_id))
110 else:
111 ie = self._get_file_ie(store, child_path, name, mode, hexsha, parent_id)
112- yield child_path.decode('utf-8'), "V", ie.kind, ie.file_id, ie
113+ yield child_relpath.decode('utf-8'), "V", ie.kind, ie.file_id, ie
114
115 def _get_file_ie(self, store, path, name, mode, hexsha, parent_id):
116 if not isinstance(path, bytes):
117@@ -449,7 +452,7 @@
118 def iter_child_entries(self, path, file_id=None):
119 (store, mode, tree_sha) = self._lookup_path(path)
120
121- if not stat.S_ISDIR(mode):
122+ if mode is not None and not stat.S_ISDIR(mode):
123 return
124
125 encoded_path = path.encode('utf-8')
126@@ -476,25 +479,38 @@
127 specific_files = None
128 else:
129 specific_files = set([p.encode('utf-8') for p in specific_files])
130- todo = [(self.store, b"", self.tree, None)]
131+ todo = deque([(self.store, b"", self.tree, self.get_root_id())])
132+ if specific_files is None or u"" in specific_files:
133+ yield u"", self._get_dir_ie(b"", None)
134 while todo:
135- store, path, tree_sha, parent_id = todo.pop()
136- ie = self._get_dir_ie(path, parent_id)
137- if specific_files is None or path in specific_files:
138- yield path.decode("utf-8"), ie
139+ store, path, tree_sha, parent_id = todo.popleft()
140 tree = store[tree_sha]
141+ extradirs = []
142 for name, mode, hexsha in tree.iteritems():
143 if self.mapping.is_special_file(name):
144 continue
145 child_path = posixpath.join(path, name)
146+ child_path_decoded = child_path.decode('utf-8')
147 if stat.S_ISDIR(mode):
148 if (specific_files is None or
149 any(filter(lambda p: p.startswith(child_path), specific_files))):
150- todo.append((store, child_path, hexsha, ie.file_id))
151- elif specific_files is None or child_path in specific_files:
152- yield (child_path.decode("utf-8"),
153- self._get_file_ie(store, child_path, name, mode, hexsha,
154- ie.file_id))
155+ extradirs.append(
156+ (store, child_path, hexsha, self.path2id(child_path_decoded)))
157+ if specific_files is None or child_path in specific_files:
158+ if stat.S_ISDIR(mode):
159+ yield (child_path_decoded,
160+ self._get_dir_ie(child_path, parent_id))
161+ else:
162+ yield (child_path_decoded,
163+ self._get_file_ie(store, child_path, name, mode,
164+ hexsha, parent_id))
165+ todo.extendleft(reversed(extradirs))
166+
167+ def iter_references(self):
168+ if self.supports_tree_reference():
169+ for path, entry in self.iter_entries_by_dir():
170+ if entry.kind == 'tree-reference':
171+ yield path, self.mapping.generate_file_id(b'')
172
173 def get_revision_id(self):
174 """See RevisionTree.get_revision_id."""
175@@ -509,6 +525,12 @@
176 (store, mode, hexsha) = self._lookup_path(path)
177 return ("GIT", hexsha)
178
179+ def get_file_size(self, path, file_id=None):
180+ (store, mode, hexsha) = self._lookup_path(path)
181+ if stat.S_ISREG(mode):
182+ return len(store[hexsha].data)
183+ return None
184+
185 def get_file_text(self, path, file_id=None):
186 """See RevisionTree.get_file_text."""
187 (store, mode, hexsha) = self._lookup_path(path)
188@@ -551,7 +573,7 @@
189 contents = store[hexsha].data
190 return (kind, len(contents), executable, osutils.sha_string(contents))
191 elif kind == 'symlink':
192- return (kind, None, None, store[hexsha].data)
193+ return (kind, None, None, store[hexsha].data.decode('utf-8'))
194 elif kind == 'tree-reference':
195 nested_repo = self._get_nested_repository(path)
196 return (kind, None, None,
197@@ -605,6 +627,30 @@
198 for key, line in annotator.annotate_flat(this_key)]
199 return annotations
200
201+ def _get_rules_searcher(self, default_searcher):
202+ return default_searcher
203+
204+ def walkdirs(self, prefix=u""):
205+ (store, mode, hexsha) = self._lookup_path(prefix)
206+ todo = deque([(store, prefix.encode('utf-8'), hexsha, self.path2id(prefix))])
207+ while todo:
208+ store, path, tree_sha, parent_id = todo.popleft()
209+ path_decoded = path.decode('utf-8')
210+ tree = store[tree_sha]
211+ children = []
212+ for name, mode, hexsha in tree.iteritems():
213+ if self.mapping.is_special_file(name):
214+ continue
215+ child_path = posixpath.join(path, name)
216+ file_id = self.path2id(child_path.decode('utf-8'))
217+ if stat.S_ISDIR(mode):
218+ todo.append((store, child_path, hexsha, file_id))
219+ children.append(
220+ (child_path.decode('utf-8'), name.decode('utf-8'),
221+ mode_kind(mode), None,
222+ file_id, mode_kind(mode)))
223+ yield (path_decoded, parent_id), children
224+
225
226 def tree_delta_from_git_changes(changes, mapping,
227 fileid_maps, specific_files=None,
228
229=== modified file 'breezy/tests/per_tree/__init__.py'
230--- breezy/tests/per_tree/__init__.py 2018-09-14 14:13:30 +0000
231+++ breezy/tests/per_tree/__init__.py 2018-09-15 00:21:08 +0000
232@@ -31,6 +31,8 @@
233 transform,
234 transport,
235 )
236+from breezy.git.tree import GitRevisionTree
237+from breezy.git.workingtree import GitWorkingTreeFormat
238 from breezy.tests.per_controldir.test_controldir import TestCaseWithControlDir
239 from breezy.tests.per_workingtree import (
240 make_scenarios as wt_make_scenarios,
241@@ -91,10 +93,15 @@
242
243 class TestTreeImplementationSupport(tests.TestCaseWithTransport):
244
245+ def test_revision_tree_from_workingtree_bzr(self):
246+ tree = self.make_branch_and_tree('.', format='bzr')
247+ tree = revision_tree_from_workingtree(self, tree)
248+ self.assertIsInstance(tree, RevisionTree)
249+
250 def test_revision_tree_from_workingtree(self):
251- tree = self.make_branch_and_tree('.')
252+ tree = self.make_branch_and_tree('.', format='git')
253 tree = revision_tree_from_workingtree(self, tree)
254- self.assertIsInstance(tree, RevisionTree)
255+ self.assertIsInstance(tree, GitRevisionTree)
256
257
258 class TestCaseWithTree(TestCaseWithControlDir):
259@@ -279,6 +286,8 @@
260 DirStateRevisionTree by committing a working tree to create the revision
261 tree.
262 """
263+ # TODO(jelmer): Test MemoryTree here
264+ # TODO(jelmer): Test GitMemoryTree here
265 scenarios = wt_make_scenarios(transport_server, transport_readonly_server,
266 formats)
267 # now adjust the scenarios and add the non-working-tree tree scenarios.
268@@ -290,6 +299,9 @@
269 scenarios.append((RevisionTree.__name__,
270 create_tree_scenario(transport_server, transport_readonly_server,
271 workingtree_format, revision_tree_from_workingtree,)))
272+ scenarios.append((GitRevisionTree.__name__,
273+ create_tree_scenario(transport_server, transport_readonly_server,
274+ GitWorkingTreeFormat(), revision_tree_from_workingtree,)))
275
276 # also test WorkingTree4/5's RevisionTree implementation which is
277 # specialised.
278@@ -347,7 +359,7 @@
279 'walkdirs',
280 ]
281 submod_tests = loader.loadTestsFromModuleNames(
282- ['breezy.tests.per_tree.test_' + name
283+ [__name__ + '.test_' + name
284 for name in per_tree_mod_names])
285 scenarios = make_scenarios(
286 tests.default_transport,
287
288=== modified file 'breezy/tests/per_tree/test_list_files.py'
289--- breezy/tests/per_tree/test_list_files.py 2018-02-26 13:36:15 +0000
290+++ breezy/tests/per_tree/test_list_files.py 2018-09-15 00:21:08 +0000
291@@ -92,7 +92,7 @@
292 try:
293 actual = [(path, status, kind, file_id)
294 for path, status, kind, file_id, ie in
295- tree.list_files(from_dir='b')]
296+ tree.list_files(from_dir=u'b')]
297 finally:
298 tree.unlock()
299 self.assertEqual(expected, actual)
300
301=== modified file 'breezy/tests/per_tree/test_path_content_summary.py'
302--- breezy/tests/per_tree/test_path_content_summary.py 2018-07-27 18:57:21 +0000
303+++ breezy/tests/per_tree/test_path_content_summary.py 2018-09-15 00:21:08 +0000
304@@ -142,8 +142,12 @@
305 tree = self.make_branch_and_tree('tree')
306 self.build_tree(['tree/path/'])
307 tree.add(['path'])
308- summary = self._convert_tree(tree).path_content_summary('path')
309- self.assertEqual(('directory', None, None, None), summary)
310+ converted_tree = self._convert_tree(tree)
311+ summary = converted_tree.path_content_summary('path')
312+ if converted_tree.has_versioned_directories() or converted_tree.has_filename('path'):
313+ self.assertEqual(('directory', None, None, None), summary)
314+ else:
315+ self.assertEqual(('missing', None, None, None), summary)
316
317 def test_tree_content_summary(self):
318 tree = self.make_branch_and_tree('tree')
319
320=== modified file 'breezy/tests/per_tree/test_test_trees.py'
321--- breezy/tests/per_tree/test_test_trees.py 2018-07-27 18:57:21 +0000
322+++ breezy/tests/per_tree/test_test_trees.py 2018-09-15 00:21:08 +0000
323@@ -141,7 +141,7 @@
324 self.addCleanup(tree.unlock)
325 self.assertEqual([], tree.get_parent_ids())
326 self.assertEqual([], tree.conflicts())
327- if tree.has_versioned_directories():
328+ if tree.has_versioned_directories() or not tree.has_filename('b'):
329 self.assertEqual([], list(tree.unknowns()))
330 else:
331 self.assertEqual(['b'], list(tree.unknowns()))
332@@ -169,7 +169,7 @@
333 self.addCleanup(tree.unlock)
334 self.assertEqual([], tree.get_parent_ids())
335 self.assertEqual([], tree.conflicts())
336- if tree.has_versioned_directories():
337+ if tree.has_versioned_directories() or not tree.has_filename('1top-dir/1dir-in-1topdir'):
338 self.assertEqual([], list(tree.unknowns()))
339 else:
340 self.assertEqual(['1top-dir/1dir-in-1topdir'], list(tree.unknowns()))
341@@ -218,7 +218,7 @@
342 self.addCleanup(tree.unlock)
343 self.assertEqual([], tree.get_parent_ids())
344 self.assertEqual([], tree.conflicts())
345- if tree.has_versioned_directories():
346+ if tree.has_versioned_directories() or not tree.has_filename('1top-dir/1dir-in-1topdir'):
347 self.assertEqual([], list(tree.unknowns()))
348 else:
349 self.assertEqual(['1top-dir/1dir-in-1topdir'], list(tree.unknowns()))
350
351=== modified file 'breezy/tests/per_tree/test_walkdirs.py'
352--- breezy/tests/per_tree/test_walkdirs.py 2018-03-17 21:00:51 +0000
353+++ breezy/tests/per_tree/test_walkdirs.py 2018-09-15 00:21:08 +0000
354@@ -19,6 +19,7 @@
355 import os
356
357 from breezy import tests
358+from breezy.mutabletree import MutableTree
359 from breezy.osutils import has_symlinks
360 from breezy.tests.per_tree import TestCaseWithTree
361
362@@ -26,36 +27,42 @@
363 class TestWalkdirs(TestCaseWithTree):
364
365 def get_all_subdirs_expected(self, tree, symlinks):
366- dirblocks = [
367- (('', tree.path2id('')),
368- [('0file', '0file', 'file', None, tree.path2id('0file'), 'file'),
369- ('1top-dir', '1top-dir', 'directory', None,
370- tree.path2id('1top-dir'), 'directory'),
371- (u'2utf\u1234file', u'2utf\u1234file', 'file', None,
372- tree.path2id(u'2utf\u1234file'), 'file'),
373- ]),
374- (('1top-dir', tree.path2id('1top-dir')),
375- [('1top-dir/0file-in-1topdir', '0file-in-1topdir',
376- 'file', None, tree.path2id('1top-dir/0file-in-1topdir'), 'file'),
377- ('1top-dir/1dir-in-1topdir', '1dir-in-1topdir',
378- 'directory',
379- None if tree.has_versioned_directories() else os.stat(tree.abspath('1top-dir/1dir-in-1topdir')),
380+ empty_dirs_present = (tree.has_versioned_directories() or
381+ isinstance(tree, MutableTree))
382+ empty_dirs_are_versioned = tree.has_versioned_directories()
383+ dirblocks = {}
384+
385+ dirblocks[''] = [
386+ ('0file', '0file', 'file', None,
387+ tree.path2id('0file'), 'file'),
388+ ('1top-dir', '1top-dir', 'directory', None,
389+ tree.path2id('1top-dir'), 'directory'),
390+ (u'2utf\u1234file', u'2utf\u1234file', 'file', None,
391+ tree.path2id(u'2utf\u1234file'), 'file')]
392+
393+ dirblocks['1top-dir'] = [
394+ ('1top-dir/0file-in-1topdir', '0file-in-1topdir',
395+ 'file', None, tree.path2id('1top-dir/0file-in-1topdir'), 'file')]
396+ if empty_dirs_present:
397+ dirblocks['1top-dir'].append(
398+ ('1top-dir/1dir-in-1topdir', '1dir-in-1topdir', 'directory',
399+ None if empty_dirs_are_versioned else os.stat(tree.abspath('1top-dir/1dir-in-1topdir')),
400 tree.path2id('1top-dir/1dir-in-1topdir'),
401- 'directory' if tree.has_versioned_directories() else None,
402- )]),
403- (('1top-dir/1dir-in-1topdir', tree.path2id('1top-dir/1dir-in-1topdir')),
404- []),
405- ]
406+ 'directory' if empty_dirs_are_versioned else None))
407+ dirblocks['1top-dir/1dir-in-1topdir'] = []
408 if symlinks:
409- dirblocks[0][1].append(('symlink', 'symlink', 'symlink', None,
410- tree.path2id('symlink'), 'symlink'))
411- return dirblocks
412+ dirblocks[''].append(
413+ ('symlink', 'symlink', 'symlink', None,
414+ tree.path2id('symlink'), 'symlink'))
415+ return [((path, tree.path2id(path)), list(sorted(entries)))
416+ for (path, entries) in dirblocks.items()]
417
418 def test_walkdir_root(self):
419 tree = self.get_tree_with_subdirs_and_all_supported_content_types(
420 has_symlinks())
421 tree.lock_read()
422- expected_dirblocks = self.get_all_subdirs_expected(tree, has_symlinks())
423+ expected_dirblocks = self.get_all_subdirs_expected(
424+ tree, has_symlinks())
425 # test that its iterable by iterating
426 result = []
427 for dirinfo, block in tree.walkdirs():
428
429=== modified file 'breezy/tests/test_selftest.py'
430--- breezy/tests/test_selftest.py 2018-08-26 14:16:26 +0000
431+++ breezy/tests/test_selftest.py 2018-09-15 00:21:08 +0000
432@@ -64,6 +64,9 @@
433 from ..bzr import (
434 groupcompress_repo,
435 )
436+from ..git import (
437+ workingtree as git_workingtree,
438+ )
439 from ..sixish import (
440 PY3,
441 StringIO,
442@@ -402,11 +405,12 @@
443 formats = [workingtree_4.WorkingTreeFormat4(),
444 workingtree_3.WorkingTreeFormat3(),]
445 scenarios = make_scenarios(server1, server2, formats)
446- self.assertEqual(8, len(scenarios))
447+ self.assertEqual(9, len(scenarios))
448 default_wt_format = workingtree.format_registry.get_default()
449 wt4_format = workingtree_4.WorkingTreeFormat4()
450 wt5_format = workingtree_4.WorkingTreeFormat5()
451 wt6_format = workingtree_4.WorkingTreeFormat6()
452+ git_wt_format = git_workingtree.GitWorkingTreeFormat()
453 expected_scenarios = [
454 ('WorkingTreeFormat4',
455 {'bzrdir_format': formats[0]._matchingcontroldir,
456@@ -438,6 +442,14 @@
457 'transport_server': 'a',
458 'workingtree_format': default_wt_format,
459 }),
460+ ('GitRevisionTree',
461+ {'_workingtree_to_test_tree': revision_tree_from_workingtree,
462+ 'bzrdir_format': git_wt_format._matchingcontroldir,
463+ 'transport_readonly_server': 'b',
464+ 'transport_server': 'a',
465+ 'workingtree_format': git_wt_format,
466+ }
467+ ),
468 ('DirStateRevisionTree,WT4',
469 {'_workingtree_to_test_tree': _dirstate_tree_from_workingtree,
470 'bzrdir_format': wt4_format._matchingcontroldir,

Subscribers

People subscribed via source and target branches