Rev 9: Fix the file selection to do the right thing in sub directories. in http://code.launchpad.net/%7Ev-ladeuil/bzr/grep
Vincent Ladeuil
v.ladeuil+lp at free.fr
Wed Jan 16 09:24:07 GMT 2008
At http://code.launchpad.net/%7Ev-ladeuil/bzr/grep
------------------------------------------------------------
revno: 9
revision-id:v.ladeuil+lp at free.fr-20080116092404-o6jg97wylpesvl72
parent: v.ladeuil+lp at free.fr-20080111162538-ie97n1n60nk1bmy7
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: grep
timestamp: Wed 2008-01-16 10:24:04 +0100
message:
Fix the file selection to do the right thing in sub directories.
* __init__.py:
Rework the file selection.
* test_grep.py:
(TestGrepInDirs): Tests behavior in root dir and sub dirs.
modified:
__init__.py __init__.py-20060323100923-17d68e8a2f14f018
test_grep.py test_grep.py-20080111162345-dtinprpim0xk8s6e-1
-------------- next part --------------
=== modified file '__init__.py'
--- a/__init__.py 2008-01-11 16:25:38 +0000
+++ b/__init__.py 2008-01-16 09:24:04 +0000
@@ -16,15 +16,46 @@
"""Grep through your working tree, but only files managed by bzr."""
+import os.path
import subprocess
+import sys
+
from bzrlib import (
builtins,
+ bzrdir,
commands,
option,
osutils,
)
+
+if sys.version_info < (2, 6):
+ # Borrowed from python2.6 until we get there
+ def _relpath(path, start=os.path.curdir):
+ """Return a relative version of a path.
+
+ This a slighty simplified and modified version of the 2.6
+ version. Windows specific error handling deleted since we always calls
+ this function for paths on the same volume.
+ """
+
+ if not path:
+ raise ValueError("no path specified")
+
+ start_list = os.path.abspath(start).split(os.path.sep)
+ path_list = os.path.abspath(path).split(os.path.sep)
+
+ # Work out how much of the filepath is shared by start and path.
+ i = len(os.path.commonprefix([start_list, path_list]))
+
+ rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:]
+ return os.path.join(*rel_list)
+else:
+ _relpath = os.path.relpath
+
+
+# TODO: avoid xargs completely ?
class cmd_grep(commands.Command):
"""Grep through your working tree, but only files managed by bzr.
@@ -40,37 +71,65 @@
takes_args = ['pattern', 'file*']
takes_options = [
option.Option(
- 'no-recurse',
+ 'non-recursive',
help="Don't recursively grep the contents of directories."),
]
+ # TODO: Separate file selection from file processing
@commands.display_command
- def run(self, pattern, no_recurse=False, file_list=None):
+ def run(self, pattern, non_recursive=False, file_list=None):
+
+ curdir = osutils.getcwd()
+
options, file_list = self._read_options(file_list)
- tree, file_list = builtins.tree_files(file_list)
+ versioned = 'V'
+
+ file_list = builtins.tree_files(file_list)[1]
+ tree, b, reldir = bzrdir.BzrDir.open_containing_tree_or_branch('.')
+ if reldir:
+ reldir += '/'
tree.lock_read()
- inv = tree.read_working_inventory()
- tree.unlock()
-
- cmd = ['xargs', '-0', 'grep', '-e', pattern]
- cmd.extend(options)
-
- #print cmd
- #print file_list
-
- xargs = subprocess.Popen(cmd, stdin=subprocess.PIPE)
-
- for path, entry in inv.entries():
- if file_list:
- if no_recurse:
- if not path in file_list:
+
+ try:
+ cmd = ['xargs', '-0', 'grep', '-e', pattern]
+ cmd.extend(options)
+
+ xargs = subprocess.Popen(cmd, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
+
+ for fpath, fclass, fkind, fid, entry \
+ in tree.list_files(include_root=False):
+ # XXX: this selection part is messy, more tests are needed and
+ # a better flow too
+ if fkind == 'directory':
+ continue
+ if file_list:
+ if non_recursive:
+ if not fpath in file_list:
+ continue
+ elif not osutils.is_inside_any(file_list, fpath):
continue
- elif not osutils.is_inside_any(file_list, path):
- continue
- xargs.stdin.write('%s\0' % path)
-
- xargs.communicate()
+ elif reldir and not fpath.startswith(reldir):
+ continue
+ if (non_recursive and reldir
+ and fpath.startswith(reldir)
+ and '/' in fpath[len(reldir):]):
+ continue
+ if fclass != versioned:
+ continue
+ rpath = _relpath(tree.abspath(fpath))
+ xargs.stdin.write(rpath + '\0')
+ xargs.stdin.flush()
+ out, err = xargs.communicate()
+ if out:
+ sys.stdout.write(out)
+ if err:
+ sys.stderr.write(err)
+ finally:
+ tree.unlock()
def _read_options(self, list):
# This is a bit of a hack, but if we scan the file list for
=== modified file 'test_grep.py'
--- a/test_grep.py 2008-01-11 16:25:38 +0000
+++ b/test_grep.py 2008-01-16 09:24:04 +0000
@@ -14,10 +14,43 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+from cStringIO import StringIO
+
+
from bzrlib import tests
-class TestGrep(tests.TestCase):
-
- def test_fake(self):
- pass
+class TestGrepInDirs(tests.TestCaseWithTransport):
+
+ def setUp(self):
+ super(TestGrepInDirs, self).setUp()
+ tree = self.make_branch_and_tree('.')
+ file_list = ['top', 'subdir/', 'subdir/down']
+ self.build_tree(file_list)
+ tree.add(file_list)
+ tree.commit('setup')
+
+ def assertGrepResultIs(self, expected_output, grep_args,
+ working_dir='.',
+ expected_error_re='.*'):
+ out, err = self.run_bzr(['grep'] + grep_args, working_dir=working_dir)
+ self.assertEquals(expected_output, out)
+ self.assertContainsRe(err, expected_error_re)
+
+ def test_grep_in_root_dir(self):
+ self.assertGrepResultIs('subdir/down:contents of subdir/down\n'
+ 'top:contents of top\n' ,
+ ['contents'])
+ self.assertGrepResultIs('contents of top\n', ['top', 'top'])
+ self.assertGrepResultIs('contents of subdir/down\n', ['down',
+ 'subdir/down'])
+
+ def test_grep_in_subir(self):
+ self.assertGrepResultIs('contents of subdir/down\n', ['down', 'down'],
+ working_dir='subdir')
+ self.assertGrepResultIs('contents of top\n', ['top', '../top'],
+ working_dir='subdir')
+
+ def test_grep_in_subdir_doesnt_go_up(self):
+ self.assertGrepResultIs('contents of subdir/down\n', ['contents'],
+ working_dir='subdir')
More information about the bazaar-commits
mailing list