diff --git a/aeromancer/cli/grep.py b/aeromancer/cli/grep.py index 6c79b26..3ad58b2 100644 --- a/aeromancer/cli/grep.py +++ b/aeromancer/cli/grep.py @@ -6,26 +6,21 @@ import os from aeromancer import project 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""" log = logging.getLogger(__name__) def get_parser(self, prog_name): parser = super(Grep, self).get_parser(prog_name) - project_filter.ProjectFilter.add_arguments(parser) parser.add_argument('pattern', action='store', help='regular expression', ) return parser - 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) - for l in pm.grep(parsed_args.pattern, prj_filt): - print(l) + def _get_command(self, parsed_args): + return ['git', 'grep', parsed_args.pattern] diff --git a/aeromancer/cli/run.py b/aeromancer/cli/run.py new file mode 100644 index 0000000..4363c0e --- /dev/null +++ b/aeromancer/cli/run.py @@ -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) diff --git a/aeromancer/project.py b/aeromancer/project.py index e1bf9a7..a13d273 100644 --- a/aeromancer/project.py +++ b/aeromancer/project.py @@ -194,11 +194,11 @@ class ProjectManager(object): self._remove_file_data(obj, reason='file no longer exists') self.session.flush() - def grep(self, pattern, prj_filter): - """Given a pattern, search for lines in files in all projects that match it. + def run(self, command, prj_filter): + """Given a command, run it for all projects. - Returns results of the query, including the four columns line - number, line content, filename, and project name. + Returns sequence of tuples containing project objects, the + output, and the errors from the command. """ # TODO: Would it be more efficient to register the regexp @@ -212,13 +212,11 @@ class ProjectManager(object): #return query.yield_per(20).all() for project in query.all(): cmd = subprocess.Popen( - ['git', 'grep', pattern], + command, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, cwd=project.path, - env={'PAGER': ''}, + env={'PAGER': ''}, # override pager for git commands ) out, err = cmd.communicate() - if not out: - continue - for line in out.decode('utf-8').splitlines(): - yield project.name + line + yield (project, out, err) diff --git a/setup.cfg b/setup.cfg index 01efc62..781580b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -62,6 +62,7 @@ aeromancer.cli = oslo list = aeromancer.oslo.cli:List oslo uses = aeromancer.oslo.cli:Uses grep = aeromancer.cli.grep:Grep + run = aeromancer.cli.run:Run aeromancer.filehandler = requirements = aeromancer.requirements.handler:RequirementsHandler