Merge lp:~garyvdm/bzr/bug492116-ls-file into lp:bzr

Proposed by Gary van der Merwe
Status: Superseded
Proposed branch: lp:~garyvdm/bzr/bug492116-ls-file
Merge into: lp:bzr
Diff against target: 615 lines (+235/-141) (has conflicts)
8 files modified
bzrlib/builtins.py (+21/-16)
bzrlib/revisiontree.py (+30/-13)
bzrlib/tests/blackbox/test_ls.py (+4/-0)
bzrlib/tests/per_tree/test_list_files.py (+56/-82)
bzrlib/transform.py (+44/-7)
bzrlib/workingtree.py (+34/-10)
bzrlib/workingtree_4.py (+31/-13)
doc/en/release-notes/bzr-2.3.txt (+15/-0)
Text conflict in bzrlib/transform.py
Text conflict in doc/en/release-notes/bzr-2.3.txt
To merge this branch: bzr merge lp:~garyvdm/bzr/bug492116-ls-file
Reviewer Review Type Date Requested Status
bzr-core Pending
Review via email: mp+45679@code.launchpad.net

Description of the change

This makes ``bzr ls FILE`` list the file passed, similar to how GNU coreutils ``ls`` behaves.

To achieve this, I changed the behavior of the ``Tree.list_files`` methods so that if passed a file, they will yield just the file.

I originally hoped that this would not be necessary, and that I could just make the necessary changes in ``builtins.cmd_ls``, but this was difficult because that would require logic to get a inventory entry, which for a wt is non-trivial. Hence, I decided to change the behavior ``Tree.list_files``.

A possible alternative to this is:
The inventory entry is only used in builtins.cmd_ls to get a entry.kind_character(), so maybe it would be easier if i were to add a tree.kind_character() method, and then I could get every thing I needed in builtins.cmd_ls with out calling Tree.list_files.

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

This looks good !

I've fixed a couple of minor issues while I was reviewing it (lp:~vila/bzr/bug492116-ls-file), you may want to integrate them:
- yes, root is always a dir,
- don't use os.path when we have an osutils function for it,
- a couple of typos ;)
- some test code duplication.

On the overall, I'm a bit worried of the code duplication there, but you're not responsible for it for the most part so it's probably out of scope to fix them here. BUT, your proposed alternative may avoid to add more of it so may be it would be better to try to add the tree.kind_character method.

Revision history for this message
Andrew King (eurokang) wrote :

This also fixes a traceback I was going to report, which is bzr ls -rREV someFile.

Revision history for this message
John A Meinel (jameinel) wrote :

Putting this back to Needs Review because Gary pulled in Vincent's work, and I don't know where it stands at this point.

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

This patch probably needs a bit of extra work as there are now conflicts. Gary, are you still planning to work on this?

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

Unmerged revisions

5590. By Vincent Ladeuil

Fix typo.

5589. By Vincent Ladeuil

Yes, root is always a dir, use osutils instead of os.path, fix typo, remove commented out debugger call.

5588. By Vincent Ladeuil

Remove debugger call.

5587. By Vincent Ladeuil

Remove duplicated code in tests.

5586. By Vincent Ladeuil

Replace try/finally by addCleanup.

5585. By Gary van der Merwe

Make ``bzr ls FILE`` list the file passed, simillar to how GNU coreutils ``ls`` behaves.

5584. By Gary van der Merwe

Test ``Tree.list_files(from_dir=...) does deprecated warning.

5583. By Gary van der Merwe

Change all ``Tree.list_files`` methods so that if passed a file, rather than a directory, they will yield just the file.

In order to represent this, the ``from_dir`` argument has been renamed to ``from_path``, and the ``from_dir`` argument is deprecated.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bzrlib/builtins.py'
2--- bzrlib/builtins.py 2011-01-12 01:01:53 +0000
3+++ bzrlib/builtins.py 2011-01-13 07:27:10 +0000
4@@ -2579,28 +2579,33 @@
5 tree, branch, relpath = \
6 _open_directory_or_containing_tree_or_branch(fs_path, directory)
7
8+ if revision is not None or tree is None:
9+ tree = _get_one_revision_tree('ls', revision, branch=branch)
10+
11+ apply_view = False
12+ if isinstance(tree, WorkingTree) and tree.supports_views():
13+ view_files = tree.views.lookup_view()
14+ if view_files:
15+ apply_view = True
16+ view_str = views.view_display_str(view_files)
17+ note("Ignoring files outside view. View is %s" % view_str)
18+
19+ self.add_cleanup(tree.lock_read().unlock)
20+
21 # Calculate the prefix to use
22 prefix = None
23 if from_root:
24 if relpath:
25 prefix = relpath + '/'
26- elif fs_path != '.' and not fs_path.endswith('/'):
27- prefix = fs_path + '/'
28-
29- if revision is not None or tree is None:
30- tree = _get_one_revision_tree('ls', revision, branch=branch)
31-
32- apply_view = False
33- if isinstance(tree, WorkingTree) and tree.supports_views():
34- view_files = tree.views.lookup_view()
35- if view_files:
36- apply_view = True
37- view_str = views.view_display_str(view_files)
38- note("Ignoring files outside view. View is %s" % view_str)
39-
40- self.add_cleanup(tree.lock_read().unlock)
41+ else:
42+ if tree.path_content_summary(relpath)[0] == 'directory':
43+ if fs_path != '.' and not fs_path.endswith('/'):
44+ prefix = fs_path + '/'
45+ else:
46+ prefix = os.path.split(fs_path)[0]
47+
48 for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
49- from_dir=relpath, recursive=recursive):
50+ from_path=relpath, recursive=recursive):
51 # Apply additional masking
52 if not all and not selection[fc]:
53 continue
54
55=== modified file 'bzrlib/revisiontree.py'
56--- bzrlib/revisiontree.py 2010-11-29 23:35:13 +0000
57+++ bzrlib/revisiontree.py 2011-01-13 07:27:10 +0000
58@@ -1,4 +1,4 @@
59-# Copyright (C) 2006-2010 Canonical Ltd
60+# Copyright (C) 2006-2011 Canonical Ltd
61 #
62 # This program is free software; you can redistribute it and/or modify
63 # it under the terms of the GNU General Public License as published by
64@@ -20,8 +20,10 @@
65
66 from bzrlib import (
67 errors,
68+ osutils,
69 revision,
70 tree,
71+ symbol_versioning,
72 )
73
74
75@@ -116,22 +118,37 @@
76 def has_filename(self, filename):
77 return bool(self.inventory.path2id(filename))
78
79- def list_files(self, include_root=False, from_dir=None, recursive=True):
80+ def list_files(self, include_root=False, from_path=None, recursive=True,
81+ from_dir=symbol_versioning.DEPRECATED_PARAMETER):
82+ if symbol_versioning.deprecated_passed(from_dir):
83+ symbol_versioning.warn(symbol_versioning.deprecated_in((2,3,0)) %
84+ '"from_dir" parameter to Tree.list_files()'
85+ ' Use Tree.list_files(from_path=) instead.',
86+ DeprecationWarning, stacklevel=2)
87+ from_path=from_dir
88 # The only files returned by this are those from the version
89 inv = self.inventory
90- if from_dir is None:
91- from_dir_id = None
92+ if from_path is None:
93+ from_path_id = None
94+ from_path_kind = 'directory'
95 else:
96- from_dir_id = inv.path2id(from_dir)
97- if from_dir_id is None:
98- # Directory not versioned
99+ from_path_id = inv.path2id(from_path)
100+ if from_path_id is None:
101+ # Path not versioned
102 return
103- entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
104- if inv.root is not None and not include_root and from_dir is None:
105- # skip the root for compatability with the current apis.
106- entries.next()
107- for path, entry in entries:
108- yield path, 'V', entry.kind, entry.file_id, entry
109+ from_path_kind = self.kind(from_path_id)
110+ if from_path_kind == 'directory':
111+ entries = inv.iter_entries(from_dir=from_path_id,
112+ recursive=recursive)
113+ if inv.root is not None and not include_root and from_path is None:
114+ # skip the root for compatibility with the current apis.
115+ entries.next()
116+ for path, entry in entries:
117+ yield path, 'V', entry.kind, entry.file_id, entry
118+ else:
119+ entry = inv[from_path_id]
120+ file_path = osutils.split(from_path)[1]
121+ yield file_path, 'V', from_path_kind, from_path_id, entry
122
123 def get_symlink_target(self, file_id):
124 ie = self._inventory[file_id]
125
126=== modified file 'bzrlib/tests/__init__.py'
127=== modified file 'bzrlib/tests/blackbox/test_ls.py'
128--- bzrlib/tests/blackbox/test_ls.py 2010-05-02 20:10:25 +0000
129+++ bzrlib/tests/blackbox/test_ls.py 2011-01-13 07:27:10 +0000
130@@ -141,8 +141,12 @@
131 """If a path is specified, files are listed with that prefix"""
132 self.build_tree(['subdir/', 'subdir/b'])
133 self.wt.add(['subdir', 'subdir/b'])
134+ self.ls_equals('a\n',
135+ 'a')
136 self.ls_equals('subdir/b\n' ,
137 'subdir')
138+ self.ls_equals('subdir/b\n' ,
139+ 'subdir/b')
140 os.chdir('subdir')
141 self.ls_equals('../.bzrignore\n'
142 '../a\n'
143
144=== modified file 'bzrlib/tests/per_tree/test_list_files.py'
145--- bzrlib/tests/per_tree/test_list_files.py 2009-07-10 07:14:02 +0000
146+++ bzrlib/tests/per_tree/test_list_files.py 2011-01-13 07:27:10 +0000
147@@ -1,4 +1,4 @@
148-# Copyright (C) 2007 Canonical Ltd
149+# Copyright (C) 2007, 2009, 2011 Canonical Ltd
150 #
151 # This program is free software; you can redistribute it and/or modify
152 # it under the terms of the GNU General Public License as published by
153@@ -16,101 +16,75 @@
154
155 """Test that all trees support Tree.list_files()"""
156
157+from bzrlib import symbol_versioning
158 from bzrlib.tests.per_tree import TestCaseWithTree
159
160
161 class TestListFiles(TestCaseWithTree):
162
163+ def setUp(self):
164+ super(TestListFiles, self).setUp()
165+ work_tree = self.make_branch_and_tree('wt')
166+ self.tree = self.get_tree_no_parents_abc_content(work_tree)
167+
168+ def assertListFiles(self, expected, **kwargs):
169+ self.tree.lock_read()
170+ self.addCleanup(self.tree.unlock)
171+ actual = [(path, status, kind, file_id)
172+ for path, status, kind, file_id, ie in
173+ self.tree.list_files(**kwargs)]
174+ self.assertEqual(expected, actual)
175+
176 def test_list_files_with_root(self):
177- work_tree = self.make_branch_and_tree('wt')
178- tree = self.get_tree_no_parents_abc_content(work_tree)
179- expected = [('', 'V', 'directory', 'root-id'),
180- ('a', 'V', 'file', 'a-id'),
181- ('b', 'V', 'directory', 'b-id'),
182- ('b/c', 'V', 'file', 'c-id'),
183- ]
184- tree.lock_read()
185- try:
186- actual = [(path, status, kind, file_id)
187- for path, status, kind, file_id, ie in
188- tree.list_files(include_root=True)]
189- finally:
190- tree.unlock()
191- self.assertEqual(expected, actual)
192+ self.assertListFiles([('', 'V', 'directory', 'root-id'),
193+ ('a', 'V', 'file', 'a-id'),
194+ ('b', 'V', 'directory', 'b-id'),
195+ ('b/c', 'V', 'file', 'c-id'),],
196+ include_root=True)
197
198 def test_list_files_no_root(self):
199- work_tree = self.make_branch_and_tree('wt')
200- tree = self.get_tree_no_parents_abc_content(work_tree)
201- expected = [('a', 'V', 'file', 'a-id'),
202- ('b', 'V', 'directory', 'b-id'),
203- ('b/c', 'V', 'file', 'c-id'),
204- ]
205- tree.lock_read()
206- try:
207- actual = [(path, status, kind, file_id)
208- for path, status, kind, file_id, ie in
209- tree.list_files()]
210- finally:
211- tree.unlock()
212- self.assertEqual(expected, actual)
213+ self.assertListFiles([('a', 'V', 'file', 'a-id'),
214+ ('b', 'V', 'directory', 'b-id'),
215+ ('b/c', 'V', 'file', 'c-id'),
216+ ])
217
218 def test_list_files_with_root_no_recurse(self):
219- work_tree = self.make_branch_and_tree('wt')
220- tree = self.get_tree_no_parents_abc_content(work_tree)
221- expected = [('', 'V', 'directory', 'root-id'),
222- ('a', 'V', 'file', 'a-id'),
223- ('b', 'V', 'directory', 'b-id'),
224- ]
225- tree.lock_read()
226- try:
227- actual = [(path, status, kind, file_id)
228- for path, status, kind, file_id, ie in
229- tree.list_files(include_root=True, recursive=False)]
230- finally:
231- tree.unlock()
232- self.assertEqual(expected, actual)
233+ self.assertListFiles([('', 'V', 'directory', 'root-id'),
234+ ('a', 'V', 'file', 'a-id'),
235+ ('b', 'V', 'directory', 'b-id'),
236+ ],
237+ include_root=True, recursive=False)
238
239 def test_list_files_no_root_no_recurse(self):
240- work_tree = self.make_branch_and_tree('wt')
241- tree = self.get_tree_no_parents_abc_content(work_tree)
242- expected = [('a', 'V', 'file', 'a-id'),
243- ('b', 'V', 'directory', 'b-id'),
244- ]
245- tree.lock_read()
246- try:
247- actual = [(path, status, kind, file_id)
248- for path, status, kind, file_id, ie in
249- tree.list_files(recursive=False)]
250- finally:
251- tree.unlock()
252- self.assertEqual(expected, actual)
253+ self.assertListFiles([('a', 'V', 'file', 'a-id'),
254+ ('b', 'V', 'directory', 'b-id'),
255+ ],
256+ recursive=False)
257
258 def test_list_files_from_dir(self):
259- work_tree = self.make_branch_and_tree('wt')
260- tree = self.get_tree_no_parents_abc_content(work_tree)
261- expected = [('c', 'V', 'file', 'c-id'),
262- ]
263- tree.lock_read()
264- try:
265- actual = [(path, status, kind, file_id)
266- for path, status, kind, file_id, ie in
267- tree.list_files(from_dir='b')]
268- finally:
269- tree.unlock()
270- self.assertEqual(expected, actual)
271+ self.assertListFiles([('c', 'V', 'file', 'c-id'),],
272+ from_path='b')
273
274 def test_list_files_from_dir_no_recurse(self):
275 # The test trees don't have much nesting so test with an explicit root
276- work_tree = self.make_branch_and_tree('wt')
277- tree = self.get_tree_no_parents_abc_content(work_tree)
278- expected = [('a', 'V', 'file', 'a-id'),
279- ('b', 'V', 'directory', 'b-id'),
280- ]
281- tree.lock_read()
282- try:
283- actual = [(path, status, kind, file_id)
284- for path, status, kind, file_id, ie in
285- tree.list_files(from_dir='', recursive=False)]
286- finally:
287- tree.unlock()
288- self.assertEqual(expected, actual)
289+ self.assertListFiles([('a', 'V', 'file', 'a-id'),
290+ ('b', 'V', 'directory', 'b-id'),],
291+ from_path='', recursive=False)
292+
293+ def test_list_files_from_file(self):
294+ self.assertListFiles([('a', 'V', 'file', 'a-id'),],
295+ from_path='a')
296+
297+ def test_list_files_from_file2(self):
298+ self.assertListFiles([('c', 'V', 'file', 'c-id'),],
299+ from_path='b/c')
300+
301+ def test_list_files_from_dir_deprecated(self):
302+ self.tree.lock_read()
303+ self.addCleanup(self.tree.unlock)
304+ self.callDeprecated(
305+ [symbol_versioning.deprecated_in((2, 3, 0)) %
306+ '"from_dir" parameter to Tree.list_files()'
307+ ' Use Tree.list_files(from_path=) instead.'],
308+ list,
309+ self.tree.list_files(from_dir='b'))
310
311=== modified file 'bzrlib/transform.py'
312--- bzrlib/transform.py 2011-01-13 02:43:21 +0000
313+++ bzrlib/transform.py 2011-01-13 07:27:10 +0000
314@@ -24,7 +24,11 @@
315 errors,
316 lazy_import,
317 registry,
318+<<<<<<< TREE
319 tree,
320+=======
321+ symbol_versioning,
322+>>>>>>> MERGE-SOURCE
323 )
324 lazy_import.lazy_import(globals(), """
325 from bzrlib import (
326@@ -60,11 +64,24 @@
327 )
328 from bzrlib.progress import ProgressPhase
329 from bzrlib.symbol_versioning import (
330+<<<<<<< TREE
331 deprecated_function,
332 deprecated_in,
333 deprecated_method,
334 )
335 from bzrlib.trace import warning
336+=======
337+ deprecated_function,
338+ deprecated_in,
339+ deprecated_method,
340+ deprecated_passed,
341+ DEPRECATED_PARAMETER,
342+ )
343+from bzrlib.trace import mutter, warning
344+from bzrlib import tree
345+import bzrlib.ui
346+import bzrlib.urlutils as urlutils
347+>>>>>>> MERGE-SOURCE
348
349
350 ROOT_PARENT = "root-parent"
351@@ -2112,14 +2129,30 @@
352 for entry, trans_id in self._make_inv_entries(ordered_ids):
353 yield unicode(self._final_paths.get_path(trans_id)), entry
354
355- def list_files(self, include_root=False, from_dir=None, recursive=True):
356+ def list_files(self, include_root=False, from_path=None, recursive=True,
357+ from_dir=DEPRECATED_PARAMETER):
358 """See WorkingTree.list_files."""
359+ if deprecated_passed(from_dir):
360+ symbol_versioning.warn(deprecated_in((2,3,0)) %
361+ '"from_dir" parameter to Tree.list_files()'
362+ ' Use Tree.list_files(from_path=) instead.',
363+ DeprecationWarning, stacklevel=2)
364+ from_path=from_dir
365 # XXX This should behave like WorkingTree.list_files, but is really
366 # more like RevisionTree.list_files.
367- if recursive:
368+ if from_path is None:
369+ from_path_id = None
370+ from_path_kind = 'directory'
371+ else:
372+ from_path_id = self.path2id(from_path)
373+ if from_path is None:
374+ # Path not versioned
375+ return
376+ from_path_kind = self.kind(from_path_id)
377+ if recursive and from_path_kind == 'directory':
378 prefix = None
379- if from_dir:
380- prefix = from_dir + '/'
381+ if from_path:
382+ prefix = from_path + '/'
383 entries = self.iter_entries_by_dir()
384 for path, entry in entries:
385 if entry.name == '' and not include_root:
386@@ -2129,14 +2162,18 @@
387 continue
388 path = path[len(prefix):]
389 yield path, 'V', entry.kind, entry.file_id, entry
390- else:
391- if from_dir is None and include_root is True:
392+ elif from_path_kind == 'directory':
393+ if from_path is None and include_root is True:
394 root_entry = inventory.make_entry('directory', '',
395 ROOT_PARENT, self.get_root_id())
396 yield '', 'V', 'directory', root_entry.file_id, root_entry
397- entries = self._iter_entries_for_dir(from_dir or '')
398+ entries = self._iter_entries_for_dir(from_path or '')
399 for path, entry in entries:
400 yield path, 'V', entry.kind, entry.file_id, entry
401+ else:
402+ for path, entry in self.iter_entries_by_dir((from_path_id,)):
403+ path = osutils.split(path)[1]
404+ yield path, 'V', entry.kind, entry.file_id, entry
405
406 def kind(self, file_id):
407 trans_id = self._transform.trans_id_file_id(file_id)
408
409=== modified file 'bzrlib/workingtree.py'
410--- bzrlib/workingtree.py 2010-11-04 17:48:47 +0000
411+++ bzrlib/workingtree.py 2011-01-13 07:27:10 +0000
412@@ -1,4 +1,4 @@
413-# Copyright (C) 2005-2010 Canonical Ltd
414+# Copyright (C) 2005-2011 Canonical Ltd
415 #
416 # This program is free software; you can redistribute it and/or modify
417 # it under the terms of the GNU General Public License as published by
418@@ -98,9 +98,11 @@
419 from bzrlib.transport.local import LocalTransport
420 from bzrlib.revision import CURRENT_REVISION
421 from bzrlib.rio import RioReader, rio_file, Stanza
422+from bzrlib import symbol_versioning
423 from bzrlib.symbol_versioning import (
424 deprecated_passed,
425 DEPRECATED_PARAMETER,
426+ deprecated_in,
427 )
428
429
430@@ -1207,7 +1209,8 @@
431 def _kind(self, relpath):
432 return osutils.file_kind(self.abspath(relpath))
433
434- def list_files(self, include_root=False, from_dir=None, recursive=True):
435+ def list_files(self, include_root=False, from_path=None, recursive=True,
436+ from_dir=DEPRECATED_PARAMETER):
437 """List all files as (path, class, kind, id, entry).
438
439 Lists, but does not descend into unversioned directories.
440@@ -1215,16 +1218,24 @@
441 tree. Skips the control directory.
442
443 :param include_root: if True, return an entry for the root
444- :param from_dir: start from this directory or None for the root
445+ :param from_path: if a directory, start from this directory
446+ (None for the root); otherwise yield this entry
447 :param recursive: whether to recurse into subdirectories or not
448 """
449+ if deprecated_passed(from_dir):
450+ symbol_versioning.warn(deprecated_in((2,3,0)) %
451+ '"from_dir" parameter to Tree.list_files()'
452+ ' Use Tree.list_files(from_path=) instead.',
453+ DeprecationWarning, stacklevel=2)
454+ from_path=from_dir
455+
456 # list_files is an iterator, so @needs_read_lock doesn't work properly
457 # with it. So callers should be careful to always read_lock the tree.
458 if not self.is_locked():
459 raise errors.ObjectNotLocked(self)
460
461 inv = self.inventory
462- if from_dir is None and include_root is True:
463+ if from_path is None and include_root is True:
464 yield ('', 'V', 'directory', inv.root.file_id, inv.root)
465 # Convert these into local objects to save lookup times
466 pathjoin = osutils.pathjoin
467@@ -1234,20 +1245,33 @@
468 # between the last two slashes
469 transport_base_dir = self.bzrdir.transport.base.rsplit('/', 2)[1]
470
471- fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
472-
473- # directory file_id, relative path, absolute path, reverse sorted children
474+ fk_entries = {'directory':TreeDirectory, 'file':TreeFile,
475+ 'symlink':TreeLink}
476+
477+ # directory file_id, relative path, absolute path, reverse sorted
478+ # children
479+ from_path_is_dir = (from_path is None
480+ or file_kind(from_path) == 'directory')
481+ if not from_path_is_dir:
482+ from_dir, from_file = os.path.split(from_path)
483+ children = [from_file]
484+ else:
485+ from_dir = from_path
486+
487 if from_dir is not None:
488 from_dir_id = inv.path2id(from_dir)
489+ from_dir_abspath = pathjoin(self.basedir, from_dir)
490 if from_dir_id is None:
491 # Directory not versioned
492 return
493- from_dir_abspath = pathjoin(self.basedir, from_dir)
494 else:
495 from_dir_id = inv.root.file_id
496 from_dir_abspath = self.basedir
497- children = os.listdir(from_dir_abspath)
498- children.sort()
499+
500+ if from_path_is_dir:
501+ children = os.listdir(from_dir_abspath)
502+ children.sort()
503+
504 # jam 20060527 The kernel sized tree seems equivalent whether we
505 # use a deque and popleft to keep them sorted, or if we use a plain
506 # list and just reverse() them.
507
508=== modified file 'bzrlib/workingtree_4.py'
509--- bzrlib/workingtree_4.py 2010-12-02 10:41:05 +0000
510+++ bzrlib/workingtree_4.py 2011-01-13 07:27:10 +0000
511@@ -1,4 +1,4 @@
512-# Copyright (C) 2007-2010 Canonical Ltd
513+# Copyright (C) 2007-2011 Canonical Ltd
514 #
515 # This program is free software; you can redistribute it and/or modify
516 # it under the terms of the GNU General Public License as published by
517@@ -45,6 +45,7 @@
518 trace,
519 transform,
520 views,
521+ symbol_versioning,
522 )
523 import bzrlib.branch
524 import bzrlib.ui
525@@ -1873,22 +1874,39 @@
526 def is_locked(self):
527 return self._locked
528
529- def list_files(self, include_root=False, from_dir=None, recursive=True):
530+ def list_files(self, include_root=False, from_path=None, recursive=True,
531+ from_dir=symbol_versioning.DEPRECATED_PARAMETER):
532+ if symbol_versioning.deprecated_passed(from_dir):
533+ symbol_versioning.warn(symbol_versioning.deprecated_in((2,3,0)) %
534+ '"from_dir" parameter to Tree.list_files()'
535+ ' Use Tree.list_files(from_path=) instead.',
536+ DeprecationWarning, stacklevel=2)
537+ from_path=from_dir
538 # We use a standard implementation, because DirStateRevisionTree is
539 # dealing with one of the parents of the current state
540- inv = self._get_inventory()
541- if from_dir is None:
542- from_dir_id = None
543+ # The only files returned by this are those from the version
544+ inv = self.inventory
545+ if from_path is None:
546+ from_path_id = None
547+ from_path_kind = 'directory'
548 else:
549- from_dir_id = inv.path2id(from_dir)
550- if from_dir_id is None:
551- # Directory not versioned
552+ from_path_id = inv.path2id(from_path)
553+ if from_path is None:
554+ # Path not versioned
555 return
556- entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
557- if inv.root is not None and not include_root and from_dir is None:
558- entries.next()
559- for path, entry in entries:
560- yield path, 'V', entry.kind, entry.file_id, entry
561+ from_path_kind = self.kind(from_path_id)
562+ if from_path_kind == 'directory':
563+ entries = inv.iter_entries(from_dir=from_path_id,
564+ recursive=recursive)
565+ if inv.root is not None and not include_root and from_path is None:
566+ # skip the root for compatability with the current apis.
567+ entries.next()
568+ for path, entry in entries:
569+ yield path, 'V', entry.kind, entry.file_id, entry
570+ else:
571+ entry = inv[from_path_id]
572+ file_path = osutils.split(from_path)[1]
573+ yield file_path, 'V', from_path_kind, from_path_id, entry
574
575 def lock_read(self):
576 """Lock the tree for a set of operations.
577
578=== modified file 'doc/en/release-notes/bzr-2.3.txt'
579--- doc/en/release-notes/bzr-2.3.txt 2011-01-12 23:37:16 +0000
580+++ doc/en/release-notes/bzr-2.3.txt 2011-01-13 07:27:10 +0000
581@@ -35,9 +35,15 @@
582 once. This avoids some unnecessary IO, and removes a network roundtrip
583 when doing ``bzr branch`` to a smart server URL. (Andrew Bennetts)
584
585+<<<<<<< TREE
586 * ``bzr modified`` now read-locks the working tree (and branch and
587 repository) just once. (Andrew Bennetts)
588
589+=======
590+* ``bzr ls FILE`` now lists the file passed, similar to how GNU coreutils
591+ ``ls`` behaves. (Gary van der Merwe, #492116)
592+
593+>>>>>>> MERGE-SOURCE
594 * ``bzr resolve`` now accepts ``--take-this`` and ``--take-other`` actions
595 for text conflicts. This *replace* the whole file with the content
596 designated by the action. This will *ignore* all differences that would
597@@ -123,10 +129,19 @@
598 already opened that repository). Implementations of these APIs will
599 need to be updated to accept these arguments. (Andrew Bennetts)
600
601+<<<<<<< TREE
602 * ``bzrlib.tuned_gzip.GzipFile`` is now deprecated and will be removed in
603 the bzr-2.4 series. Code that was using it can just use the python
604 stdlib ``gzip.GzipFile``. (John Arbash Meinel)
605
606+=======
607+* ``Tree.list_files`` if passed a file, rather than a directory, will yield
608+ just the file. In order to represent this, the ``from_dir`` argument has
609+ been renamed to ``from_path``, and the ``from_dir`` argument is deprecated.
610+ (Gary van der Merwe)
611+
612+
613+>>>>>>> MERGE-SOURCE
614 Internals
615 *********
616