summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDoug Hellmann <doug@doughellmann.com>2015-01-21 20:57:52 -0500
committerDoug Hellmann <doug@doughellmann.com>2015-01-21 20:57:52 -0500
commit820caf5555e95f6d5dc0a3c151c9252673f1b376 (patch)
treebf4070c46fda0e1292d4876d7948c2876f8bac43
parentafe9eafba5c1583f045a0a9ccc5de14eec96d2b2 (diff)
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.
-rw-r--r--aeromancer/cli/grep.py13
-rw-r--r--aeromancer/cli/run.py68
-rw-r--r--aeromancer/project.py18
-rw-r--r--setup.cfg1
4 files changed, 81 insertions, 19 deletions
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
6from aeromancer import project 6from aeromancer import project
7from aeromancer import project_filter 7from aeromancer import project_filter
8 8
9from cliff.command import Command 9from aeromancer.cli.run import ProjectShellCommandBase
10 10
11 11
12class Grep(Command): 12class Grep(ProjectShellCommandBase):
13 """Search the contents of files""" 13 """Search the contents of files"""
14 14
15 log = logging.getLogger(__name__) 15 log = logging.getLogger(__name__)
16 16
17 def get_parser(self, prog_name): 17 def get_parser(self, prog_name):
18 parser = super(Grep, self).get_parser(prog_name) 18 parser = super(Grep, self).get_parser(prog_name)
19 project_filter.ProjectFilter.add_arguments(parser)
20 parser.add_argument('pattern', 19 parser.add_argument('pattern',
21 action='store', 20 action='store',
22 help='regular expression', 21 help='regular expression',
23 ) 22 )
24 return parser 23 return parser
25 24
26 def take_action(self, parsed_args): 25 def _get_command(self, parsed_args):
27 session = self.app.get_db_session() 26 return ['git', 'grep', parsed_args.pattern]
28 pm = project.ProjectManager(session)
29 prj_filt = project_filter.ProjectFilter.from_parsed_args(parsed_args)
30 for l in pm.grep(parsed_args.pattern, prj_filt):
31 print(l)
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 @@
1from __future__ import print_function
2
3import logging
4import os
5import shlex
6
7from aeromancer import project
8from aeromancer import project_filter
9
10from cliff.command import Command
11
12
13class ProjectShellCommandBase(Command):
14 """Run a command for each project"""
15
16 log = logging.getLogger(__name__)
17
18 DEFAULT_SEP = ''
19
20 def get_parser(self, prog_name):
21 parser = super(ProjectShellCommandBase, self).get_parser(prog_name)
22 project_filter.ProjectFilter.add_arguments(parser)
23 parser.add_argument(
24 '--sep',
25 action='store',
26 default=self.DEFAULT_SEP,
27 help=('separator between project name and command output, '
28 'defaults to %(default)r'),
29 )
30 return parser
31
32 def _show_text_output(self, parsed_args, project, out):
33 for line in out.decode('utf-8').splitlines():
34 print(project.name + parsed_args.sep + line)
35
36 def _get_command(self, parsed_args):
37 raise NotImplementedError()
38
39 def _show_output(self, parsed_args, proj_obj, out, err):
40 self._show_text_output(parsed_args, proj_obj, err or out)
41
42 def take_action(self, parsed_args):
43 session = self.app.get_db_session()
44 pm = project.ProjectManager(session)
45 prj_filt = project_filter.ProjectFilter.from_parsed_args(parsed_args)
46 command = self._get_command(parsed_args)
47 results = pm.run(command, prj_filt)
48 for proj_obj, out, err in results:
49 self._show_output(parsed_args, proj_obj, out, err)
50
51
52class Run(ProjectShellCommandBase):
53 """Run a command for each project"""
54
55 log = logging.getLogger(__name__)
56
57 DEFAULT_SEP = ':'
58
59 def get_parser(self, prog_name):
60 parser = super(Run, self).get_parser(prog_name)
61 parser.add_argument('command',
62 action='store',
63 help='the command to run, probably quoted',
64 )
65 return parser
66
67 def _get_command(self, parsed_args):
68 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):
194 self._remove_file_data(obj, reason='file no longer exists') 194 self._remove_file_data(obj, reason='file no longer exists')
195 self.session.flush() 195 self.session.flush()
196 196
197 def grep(self, pattern, prj_filter): 197 def run(self, command, prj_filter):
198 """Given a pattern, search for lines in files in all projects that match it. 198 """Given a command, run it for all projects.
199 199
200 Returns results of the query, including the four columns line 200 Returns sequence of tuples containing project objects, the
201 number, line content, filename, and project name. 201 output, and the errors from the command.
202 202
203 """ 203 """
204 # TODO: Would it be more efficient to register the regexp 204 # TODO: Would it be more efficient to register the regexp
@@ -212,13 +212,11 @@ class ProjectManager(object):
212 #return query.yield_per(20).all() 212 #return query.yield_per(20).all()
213 for project in query.all(): 213 for project in query.all():
214 cmd = subprocess.Popen( 214 cmd = subprocess.Popen(
215 ['git', 'grep', pattern], 215 command,
216 stdout=subprocess.PIPE, 216 stdout=subprocess.PIPE,
217 stderr=subprocess.PIPE,
217 cwd=project.path, 218 cwd=project.path,
218 env={'PAGER': ''}, 219 env={'PAGER': ''}, # override pager for git commands
219 ) 220 )
220 out, err = cmd.communicate() 221 out, err = cmd.communicate()
221 if not out: 222 yield (project, out, err)
222 continue
223 for line in out.decode('utf-8').splitlines():
224 yield project.name + line
diff --git a/setup.cfg b/setup.cfg
index 01efc62..781580b 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -62,6 +62,7 @@ aeromancer.cli =
62 oslo list = aeromancer.oslo.cli:List 62 oslo list = aeromancer.oslo.cli:List
63 oslo uses = aeromancer.oslo.cli:Uses 63 oslo uses = aeromancer.oslo.cli:Uses
64 grep = aeromancer.cli.grep:Grep 64 grep = aeromancer.cli.grep:Grep
65 run = aeromancer.cli.run:Run
65 66
66aeromancer.filehandler = 67aeromancer.filehandler =
67 requirements = aeromancer.requirements.handler:RequirementsHandler 68 requirements = aeromancer.requirements.handler:RequirementsHandler