Merge lp:~bzr/bzr/list-files-norecurse into lp:~bzr/bzr/trunk-old
- list-files-norecurse
- Merge into trunk-old
Proposed by
Ian Clatworthy
Status: | Merged |
---|---|
Approved by: | Ian Clatworthy |
Approved revision: | no longer in the source branch. |
Merged at revision: | not available |
Proposed branch: | lp:~bzr/bzr/list-files-norecurse |
Merge into: | lp:~bzr/bzr/trunk-old |
Diff against target: | 272 lines |
To merge this branch: | bzr merge lp:~bzr/bzr/list-files-norecurse |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Martin Pool | Approve | ||
John A Meinel | Needs Information | ||
Review via email: mp+6669@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Ian Clatworthy (ian-clatworthy) wrote : | # |
Revision history for this message
John A Meinel (jameinel) wrote : | # |
I believe Tree.list_files() is actually meant to be a 'deprecated' function that we just never got around to actually deprecating.
I'd rather see the code changed to use Tree.iter_
Also, as near as I can tell, this doesn't actually update any callers to *use* the new functionality, is that true?
review:
Needs Information
Revision history for this message
Ian Clatworthy (ian-clatworthy) wrote : | # |
John A Meinel wrote:
> Also, as near as I can tell, this doesn't actually update any callers to *use* the new functionality, is that true?
>
That's right. Another patch builds on this one, namely
https:/
Ian C.
Revision history for this message
Martin Pool (mbp) wrote : | # |
It's ok with me to merge this if you're finding it useful. I think John is right that the interfaces here could be cleaned up though.
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'bzrlib/revisiontree.py' |
2 | --- bzrlib/revisiontree.py 2009-06-10 03:56:49 +0000 |
3 | +++ bzrlib/revisiontree.py 2009-06-16 02:38:01 +0000 |
4 | @@ -114,11 +114,18 @@ |
5 | def has_filename(self, filename): |
6 | return bool(self.inventory.path2id(filename)) |
7 | |
8 | - def list_files(self, include_root=False): |
9 | + def list_files(self, include_root=False, from_dir=None, recursive=True): |
10 | # The only files returned by this are those from the version |
11 | - entries = self.inventory.iter_entries() |
12 | - # skip the root for compatability with the current apis. |
13 | - if self.inventory.root is not None and not include_root: |
14 | + inv = self.inventory |
15 | + if from_dir is None: |
16 | + from_dir_id = None |
17 | + else: |
18 | + from_dir_id = inv.path2id(from_dir) |
19 | + if from_dir_id is None: |
20 | + # Directory not versioned |
21 | + return |
22 | + entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive) |
23 | + if inv.root is not None and not include_root and from_dir is None: |
24 | # skip the root for compatability with the current apis. |
25 | entries.next() |
26 | for path, entry in entries: |
27 | |
28 | === modified file 'bzrlib/tests/tree_implementations/test_list_files.py' |
29 | --- bzrlib/tests/tree_implementations/test_list_files.py 2009-03-23 14:59:43 +0000 |
30 | +++ bzrlib/tests/tree_implementations/test_list_files.py 2009-06-16 02:38:01 +0000 |
31 | @@ -49,7 +49,68 @@ |
32 | try: |
33 | actual = [(path, status, kind, file_id) |
34 | for path, status, kind, file_id, ie in |
35 | - tree.list_files(include_root=False)] |
36 | + tree.list_files()] |
37 | + finally: |
38 | + tree.unlock() |
39 | + self.assertEqual(expected, actual) |
40 | + |
41 | + def test_list_files_with_root_no_recurse(self): |
42 | + work_tree = self.make_branch_and_tree('wt') |
43 | + tree = self.get_tree_no_parents_abc_content(work_tree) |
44 | + expected = [('', 'V', 'directory', 'root-id'), |
45 | + ('a', 'V', 'file', 'a-id'), |
46 | + ('b', 'V', 'directory', 'b-id'), |
47 | + ] |
48 | + tree.lock_read() |
49 | + try: |
50 | + actual = [(path, status, kind, file_id) |
51 | + for path, status, kind, file_id, ie in |
52 | + tree.list_files(include_root=True, recursive=False)] |
53 | + finally: |
54 | + tree.unlock() |
55 | + self.assertEqual(expected, actual) |
56 | + |
57 | + def test_list_files_no_root_no_recurse(self): |
58 | + work_tree = self.make_branch_and_tree('wt') |
59 | + tree = self.get_tree_no_parents_abc_content(work_tree) |
60 | + expected = [('a', 'V', 'file', 'a-id'), |
61 | + ('b', 'V', 'directory', 'b-id'), |
62 | + ] |
63 | + tree.lock_read() |
64 | + try: |
65 | + actual = [(path, status, kind, file_id) |
66 | + for path, status, kind, file_id, ie in |
67 | + tree.list_files(recursive=False)] |
68 | + finally: |
69 | + tree.unlock() |
70 | + self.assertEqual(expected, actual) |
71 | + |
72 | + def test_list_files_from_dir(self): |
73 | + work_tree = self.make_branch_and_tree('wt') |
74 | + tree = self.get_tree_no_parents_abc_content(work_tree) |
75 | + expected = [('c', 'V', 'file', 'c-id'), |
76 | + ] |
77 | + tree.lock_read() |
78 | + try: |
79 | + actual = [(path, status, kind, file_id) |
80 | + for path, status, kind, file_id, ie in |
81 | + tree.list_files(from_dir='b')] |
82 | + finally: |
83 | + tree.unlock() |
84 | + self.assertEqual(expected, actual) |
85 | + |
86 | + def test_list_files_from_dir_no_recurse(self): |
87 | + # The test trees don't have much nesting so test with an explicit root |
88 | + work_tree = self.make_branch_and_tree('wt') |
89 | + tree = self.get_tree_no_parents_abc_content(work_tree) |
90 | + expected = [('a', 'V', 'file', 'a-id'), |
91 | + ('b', 'V', 'directory', 'b-id'), |
92 | + ] |
93 | + tree.lock_read() |
94 | + try: |
95 | + actual = [(path, status, kind, file_id) |
96 | + for path, status, kind, file_id, ie in |
97 | + tree.list_files(from_dir='', recursive=False)] |
98 | finally: |
99 | tree.unlock() |
100 | self.assertEqual(expected, actual) |
101 | |
102 | === modified file 'bzrlib/transform.py' |
103 | --- bzrlib/transform.py 2009-06-10 03:56:49 +0000 |
104 | +++ bzrlib/transform.py 2009-06-16 02:38:01 +0000 |
105 | @@ -1748,7 +1748,7 @@ |
106 | if self._transform.final_file_id(trans_id) is None: |
107 | yield self._final_paths._determine_path(trans_id) |
108 | |
109 | - def _make_inv_entries(self, ordered_entries, specific_file_ids): |
110 | + def _make_inv_entries(self, ordered_entries, specific_file_ids=None): |
111 | for trans_id, parent_file_id in ordered_entries: |
112 | file_id = self._transform.final_file_id(trans_id) |
113 | if file_id is None: |
114 | @@ -1791,14 +1791,41 @@ |
115 | specific_file_ids): |
116 | yield unicode(self._final_paths.get_path(trans_id)), entry |
117 | |
118 | - def list_files(self, include_root=False): |
119 | - """See Tree.list_files.""" |
120 | + def _iter_entries_for_dir(self, dir_path): |
121 | + """Return path, entry for items in a directory without recursing down.""" |
122 | + dir_file_id = self.path2id(dir_path) |
123 | + ordered_ids = [] |
124 | + for file_id in self.iter_children(dir_file_id): |
125 | + trans_id = self._transform.trans_id_file_id(file_id) |
126 | + ordered_ids.append((trans_id, file_id)) |
127 | + for entry, trans_id in self._make_inv_entries(ordered_ids): |
128 | + yield unicode(self._final_paths.get_path(trans_id)), entry |
129 | + |
130 | + def list_files(self, include_root=False, from_dir=None, recursive=True): |
131 | + """See WorkingTree.list_files.""" |
132 | # XXX This should behave like WorkingTree.list_files, but is really |
133 | # more like RevisionTree.list_files. |
134 | - for path, entry in self.iter_entries_by_dir(): |
135 | - if entry.name == '' and not include_root: |
136 | - continue |
137 | - yield path, 'V', entry.kind, entry.file_id, entry |
138 | + if recursive: |
139 | + prefix = None |
140 | + if from_dir: |
141 | + prefix = from_dir + '/' |
142 | + entries = self.iter_entries_by_dir() |
143 | + for path, entry in entries: |
144 | + if entry.name == '' and not include_root: |
145 | + continue |
146 | + if prefix: |
147 | + if not path.startswith(prefix): |
148 | + continue |
149 | + path = path[len(prefix):] |
150 | + yield path, 'V', entry.kind, entry.file_id, entry |
151 | + else: |
152 | + if from_dir is None and include_root is True: |
153 | + root_entry = inventory.make_entry('directory', '', |
154 | + ROOT_PARENT, self.get_root_id()) |
155 | + yield '', 'V', 'directory', root_entry.file_id, root_entry |
156 | + entries = self._iter_entries_for_dir(from_dir or '') |
157 | + for path, entry in entries: |
158 | + yield path, 'V', entry.kind, entry.file_id, entry |
159 | |
160 | def kind(self, file_id): |
161 | trans_id = self._transform.trans_id_file_id(file_id) |
162 | |
163 | === modified file 'bzrlib/workingtree.py' |
164 | --- bzrlib/workingtree.py 2009-06-15 15:47:45 +0000 |
165 | +++ bzrlib/workingtree.py 2009-06-16 02:38:01 +0000 |
166 | @@ -1115,15 +1115,16 @@ |
167 | def _kind(self, relpath): |
168 | return osutils.file_kind(self.abspath(relpath)) |
169 | |
170 | - def list_files(self, include_root=False): |
171 | - """Recursively list all files as (path, class, kind, id, entry). |
172 | + def list_files(self, include_root=False, from_dir=None, recursive=True): |
173 | + """List all files as (path, class, kind, id, entry). |
174 | |
175 | Lists, but does not descend into unversioned directories. |
176 | - |
177 | This does not include files that have been deleted in this |
178 | - tree. |
179 | + tree. Skips the control directory. |
180 | |
181 | - Skips the control directory. |
182 | + :param include_root: if True, do not return an entry for the root |
183 | + :param from_dir: start from this directory or None for the root |
184 | + :param recursive: whether to recurse into subdirectories or not |
185 | """ |
186 | # list_files is an iterator, so @needs_read_lock doesn't work properly |
187 | # with it. So callers should be careful to always read_lock the tree. |
188 | @@ -1131,7 +1132,7 @@ |
189 | raise errors.ObjectNotLocked(self) |
190 | |
191 | inv = self.inventory |
192 | - if include_root is True: |
193 | + if from_dir is None and include_root is True: |
194 | yield ('', 'V', 'directory', inv.root.file_id, inv.root) |
195 | # Convert these into local objects to save lookup times |
196 | pathjoin = osutils.pathjoin |
197 | @@ -1144,13 +1145,22 @@ |
198 | fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink} |
199 | |
200 | # directory file_id, relative path, absolute path, reverse sorted children |
201 | - children = os.listdir(self.basedir) |
202 | + if from_dir is not None: |
203 | + from_dir_id = inv.path2id(from_dir) |
204 | + if from_dir_id is None: |
205 | + # Directory not versioned |
206 | + return |
207 | + from_dir_abspath = pathjoin(self.basedir, from_dir) |
208 | + else: |
209 | + from_dir_id = inv.root.file_id |
210 | + from_dir_abspath = self.basedir |
211 | + children = os.listdir(from_dir_abspath) |
212 | children.sort() |
213 | # jam 20060527 The kernel sized tree seems equivalent whether we |
214 | # use a deque and popleft to keep them sorted, or if we use a plain |
215 | # list and just reverse() them. |
216 | children = collections.deque(children) |
217 | - stack = [(inv.root.file_id, u'', self.basedir, children)] |
218 | + stack = [(from_dir_id, u'', from_dir_abspath, children)] |
219 | while stack: |
220 | from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1] |
221 | |
222 | @@ -1214,14 +1224,15 @@ |
223 | if fk != 'directory': |
224 | continue |
225 | |
226 | - # But do this child first |
227 | - new_children = os.listdir(fap) |
228 | - new_children.sort() |
229 | - new_children = collections.deque(new_children) |
230 | - stack.append((f_ie.file_id, fp, fap, new_children)) |
231 | - # Break out of inner loop, |
232 | - # so that we start outer loop with child |
233 | - break |
234 | + # But do this child first if recursing down |
235 | + if recursive: |
236 | + new_children = os.listdir(fap) |
237 | + new_children.sort() |
238 | + new_children = collections.deque(new_children) |
239 | + stack.append((f_ie.file_id, fp, fap, new_children)) |
240 | + # Break out of inner loop, |
241 | + # so that we start outer loop with child |
242 | + break |
243 | else: |
244 | # if we finished all children, pop it off the stack |
245 | stack.pop() |
246 | |
247 | === modified file 'bzrlib/workingtree_4.py' |
248 | --- bzrlib/workingtree_4.py 2009-06-11 04:23:53 +0000 |
249 | +++ bzrlib/workingtree_4.py 2009-06-16 02:38:01 +0000 |
250 | @@ -1844,12 +1844,19 @@ |
251 | return None |
252 | return ie.executable |
253 | |
254 | - def list_files(self, include_root=False): |
255 | + def list_files(self, include_root=False, from_dir=None, recursive=True): |
256 | # We use a standard implementation, because DirStateRevisionTree is |
257 | # dealing with one of the parents of the current state |
258 | inv = self._get_inventory() |
259 | - entries = inv.iter_entries() |
260 | - if self.inventory.root is not None and not include_root: |
261 | + if from_dir is None: |
262 | + from_dir_id = None |
263 | + else: |
264 | + from_dir_id = inv.path2id(from_dir) |
265 | + if from_dir_id is None: |
266 | + # Directory not versioned |
267 | + return |
268 | + entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive) |
269 | + if inv.root is not None and not include_root and from_dir is None: |
270 | entries.next() |
271 | for path, entry in entries: |
272 | yield path, 'V', entry.kind, entry.file_id, entry |
This patch is the core of the work to make the ls command faster. 2 new parameters are added to the tree.list_files() API: from_dir and recursive. Numerous tests are added to cover these new parameters.
Implementation- wise, this builds on the iter-entries- norecurse branch.