Add "run" command and refactor grep

Add a run command for running shell commands in projects and refactor
grep to use the same base class.
This commit is contained in:
Doug Hellmann 2015-01-21 20:57:52 -05:00
parent afe9eafba5
commit 820caf5555
4 changed files with 81 additions and 19 deletions

View File

@ -6,26 +6,21 @@ import os
from aeromancer import project from aeromancer import project
from aeromancer import project_filter from aeromancer import project_filter
from cliff.command import Command from aeromancer.cli.run import ProjectShellCommandBase
class Grep(Command): class Grep(ProjectShellCommandBase):
"""Search the contents of files""" """Search the contents of files"""
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
def get_parser(self, prog_name): def get_parser(self, prog_name):
parser = super(Grep, self).get_parser(prog_name) parser = super(Grep, self).get_parser(prog_name)
project_filter.ProjectFilter.add_arguments(parser)
parser.add_argument('pattern', parser.add_argument('pattern',
action='store', action='store',
help='regular expression', help='regular expression',
) )
return parser return parser
def take_action(self, parsed_args): def _get_command(self, parsed_args):
session = self.app.get_db_session() return ['git', 'grep', parsed_args.pattern]
pm = project.ProjectManager(session)
prj_filt = project_filter.ProjectFilter.from_parsed_args(parsed_args)
for l in pm.grep(parsed_args.pattern, prj_filt):
print(l)

68
aeromancer/cli/run.py Normal file
View File

@ -0,0 +1,68 @@
from __future__ import print_function
import logging
import os
import shlex
from aeromancer import project
from aeromancer import project_filter
from cliff.command import Command
class ProjectShellCommandBase(Command):
"""Run a command for each project"""
log = logging.getLogger(__name__)
DEFAULT_SEP = ''
def get_parser(self, prog_name):
parser = super(ProjectShellCommandBase, self).get_parser(prog_name)
project_filter.ProjectFilter.add_arguments(parser)
parser.add_argument(
'--sep',
action='store',
default=self.DEFAULT_SEP,
help=('separator between project name and command output, '
'defaults to %(default)r'),
)
return parser
def _show_text_output(self, parsed_args, project, out):
for line in out.decode('utf-8').splitlines():
print(project.name + parsed_args.sep + line)
def _get_command(self, parsed_args):
raise NotImplementedError()
def _show_output(self, parsed_args, proj_obj, out, err):
self._show_text_output(parsed_args, proj_obj, err or out)
def take_action(self, parsed_args):
session = self.app.get_db_session()
pm = project.ProjectManager(session)
prj_filt = project_filter.ProjectFilter.from_parsed_args(parsed_args)
command = self._get_command(parsed_args)
results = pm.run(command, prj_filt)
for proj_obj, out, err in results:
self._show_output(parsed_args, proj_obj, out, err)
class Run(ProjectShellCommandBase):
"""Run a command for each project"""
log = logging.getLogger(__name__)
DEFAULT_SEP = ':'
def get_parser(self, prog_name):
parser = super(Run, self).get_parser(prog_name)
parser.add_argument('command',
action='store',
help='the command to run, probably quoted',
)
return parser
def _get_command(self, parsed_args):
return shlex.shlex(parsed_args.command)

View File

@ -194,11 +194,11 @@ class ProjectManager(object):
self._remove_file_data(obj, reason='file no longer exists') self._remove_file_data(obj, reason='file no longer exists')
self.session.flush() self.session.flush()
def grep(self, pattern, prj_filter): def run(self, command, prj_filter):
"""Given a pattern, search for lines in files in all projects that match it. """Given a command, run it for all projects.
Returns results of the query, including the four columns line Returns sequence of tuples containing project objects, the
number, line content, filename, and project name. output, and the errors from the command.
""" """
# TODO: Would it be more efficient to register the regexp # TODO: Would it be more efficient to register the regexp
@ -212,13 +212,11 @@ class ProjectManager(object):
#return query.yield_per(20).all() #return query.yield_per(20).all()
for project in query.all(): for project in query.all():
cmd = subprocess.Popen( cmd = subprocess.Popen(
['git', 'grep', pattern], command,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
cwd=project.path, cwd=project.path,
env={'PAGER': ''}, env={'PAGER': ''}, # override pager for git commands
) )
out, err = cmd.communicate() out, err = cmd.communicate()
if not out: yield (project, out, err)
continue
for line in out.decode('utf-8').splitlines():
yield project.name + line

View File

@ -62,6 +62,7 @@ aeromancer.cli =
oslo list = aeromancer.oslo.cli:List oslo list = aeromancer.oslo.cli:List
oslo uses = aeromancer.oslo.cli:Uses oslo uses = aeromancer.oslo.cli:Uses
grep = aeromancer.cli.grep:Grep grep = aeromancer.cli.grep:Grep
run = aeromancer.cli.run:Run
aeromancer.filehandler = aeromancer.filehandler =
requirements = aeromancer.requirements.handler:RequirementsHandler requirements = aeromancer.requirements.handler:RequirementsHandler