Merge lp:~allenap/postgresfixture/run-with-command into lp:~lazr-developers/postgresfixture/trunk

Proposed by Gavin Panella on 2012-05-22
Status: Merged
Approved by: Graham Binns on 2012-05-22
Approved revision: 6
Merged at revision: 4
Proposed branch: lp:~allenap/postgresfixture/run-with-command
Merge into: lp:~lazr-developers/postgresfixture/trunk
Diff against target: 313 lines (+96/-69)
2 files modified
postgresfixture/main.py (+69/-55)
postgresfixture/tests/test_main.py (+27/-14)
To merge this branch: bzr merge lp:~allenap/postgresfixture/run-with-command
Reviewer Review Type Date Requested Status
Graham Binns (community) code 2012-05-22 Approve on 2012-05-22
Review via email: mp+106830@code.launchpad.net

Commit Message

Recast actions as subparsers, and enable run to take a command to execute.

Description of the Change

Recast actions as subparsers, and enable run to take a command to execute.

To post a comment you must log in.
Graham Binns (gmb) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'postgresfixture/main.py'
2--- postgresfixture/main.py 2012-05-21 10:53:51 +0000
3+++ postgresfixture/main.py 2012-05-22 15:17:19 +0000
4@@ -62,17 +62,9 @@
5 return print(*args, **kwargs)
6
7
8-def get_database_name(default="data"):
9- """Return the desired database name, used by some commands.
10-
11- Obtained from the ``PGDATABASE`` environment variable.
12- """
13- return environ.get("PGDATABASE", default)
14-
15-
16-def action_destroy(cluster):
17- """Destroy a cluster."""
18- action_stop(cluster)
19+def action_destroy(cluster, arguments):
20+ """Destroy the cluster."""
21+ action_stop(cluster, arguments)
22 cluster.destroy()
23 if cluster.exists:
24 if cluster.lock.locked:
25@@ -84,41 +76,34 @@
26 raise SystemExit(2)
27
28
29-def action_run(cluster):
30- """Create and run a cluster.
31-
32- If specified in the ``PGDATABASE`` environment variable, a database will
33- also be created within the cluster.
34- """
35- database_name = get_database_name(default=None)
36+def action_run(cluster, arguments):
37+ """Create and run the cluster."""
38+ database_name = arguments.dbname
39+ command = arguments.command
40 with cluster:
41 if database_name is not None:
42 cluster.createdb(database_name)
43- while cluster.running:
44- sleep(5.0)
45-
46-
47-def action_shell(cluster):
48- """Spawn a ``psql`` shell for a database in the cluster.
49-
50- The database name can be specified in the ``PGDATABASE`` environment
51- variable.
52- """
53- database_name = get_database_name()
54+ if command is None or len(command) == 0:
55+ while cluster.running:
56+ sleep(5.0)
57+ else:
58+ cluster.execute(*command)
59+
60+
61+def action_shell(cluster, arguments):
62+ """Spawn a `psql` shell for a database in the cluster."""
63+ database_name = arguments.dbname
64 with cluster:
65 cluster.createdb(database_name)
66 cluster.shell(database_name)
67
68
69-def action_status(cluster):
70+def action_status(cluster, arguments):
71 """Display a message about the state of the cluster.
72
73- The return code is also set:
74-
75- - 0: cluster is running.
76- - 1: cluster exists, but is not running.
77- - 2: cluster does not exist.
78-
79+ The return code is also set: 0 indicates that the cluster is running; 1
80+ indicates that it exists, but is not running; 2 indicates that it does not
81+ exist.
82 """
83 if cluster.exists:
84 if cluster.running:
85@@ -132,8 +117,8 @@
86 raise SystemExit(2)
87
88
89-def action_stop(cluster):
90- """Stop a cluster."""
91+def action_stop(cluster, arguments):
92+ """Stop the cluster."""
93 cluster.stop()
94 if cluster.running:
95 if cluster.lock.locked:
96@@ -145,22 +130,10 @@
97 raise SystemExit(2)
98
99
100-actions = {
101- "destroy": action_destroy,
102- "run": action_run,
103- "shell": action_shell,
104- "status": action_status,
105- "stop": action_stop,
106- }
107-
108-
109 argument_parser = argparse.ArgumentParser(description=__doc__)
110 argument_parser.add_argument(
111- "action", choices=sorted(actions), nargs="?", default="shell",
112- help="the action to perform (default: %(default)s)")
113-argument_parser.add_argument(
114- "-D", "--datadir", dest="datadir", action="store_true",
115- default="db", help=(
116+ "-D", "--datadir", dest="datadir", action="store",
117+ metavar="PGDATA", default="db", help=(
118 "the directory in which to place, or find, the cluster "
119 "(default: %(default)s)"))
120 argument_parser.add_argument(
121@@ -169,16 +142,57 @@
122 "preserve the cluster and its databases when exiting, "
123 "even if it was necessary to create and start it "
124 "(default: %(default)s)"))
125+argument_subparsers = argument_parser.add_subparsers(
126+ title="actions")
127+
128+
129+def add_action(name, handler, *args, **kwargs):
130+ """Configure a subparser for the given name and function."""
131+ parser = argument_subparsers.add_parser(
132+ name, *args, help=handler.__doc__, **kwargs)
133+ parser.set_defaults(handler=handler)
134+ return parser
135+
136+
137+def get_action(name):
138+ """Retrieve the named subparser."""
139+ return argument_subparsers.choices[name]
140+
141+
142+# Register actions.
143+add_action("destroy", action_destroy)
144+add_action("run", action_run)
145+add_action("shell", action_shell)
146+add_action("status", action_status)
147+add_action("stop", action_stop)
148+
149+
150+# Customise argument lists for individual actions.
151+get_action("run").add_argument(
152+ "-d", "--dbname", dest="dbname", action="store", metavar="PGDATABASE",
153+ default=environ.get("PGDATABASE", None), help=(
154+ "if specified, the database to create. The default is taken from "
155+ "the PGDATABASE environment variable (current default: "
156+ "%(default)s)."))
157+get_action("run").add_argument(
158+ "command", nargs="*", default=None, help=(
159+ "the command to execute (default: %(default)s)"))
160+get_action("shell").add_argument(
161+ "-d", "--dbname", dest="dbname", action="store", metavar="PGDATABASE",
162+ default=environ.get("PGDATABASE", "data"), help=(
163+ "the database to create and connect to. The default is taken from "
164+ "the PGDATABASE environment variable, otherwise 'data' (current "
165+ "default: %(default)s)."))
166
167
168 def main(args=None):
169 args = argument_parser.parse_args(args)
170 try:
171 setup()
172- action = actions[args.action]
173 cluster = ClusterFixture(
174- datadir=args.datadir, preserve=args.preserve)
175- action(cluster)
176+ datadir=args.datadir,
177+ preserve=args.preserve)
178+ args.handler(cluster, args)
179 except CalledProcessError, error:
180 raise SystemExit(error.returncode)
181 except KeyboardInterrupt:
182
183=== modified file 'postgresfixture/tests/test_main.py'
184--- postgresfixture/tests/test_main.py 2012-05-14 19:19:23 +0000
185+++ postgresfixture/tests/test_main.py 2012-05-22 15:17:19 +0000
186@@ -32,13 +32,17 @@
187 def get_random_database_name(self):
188 return "db%s" % b16encode(urandom(8)).lower()
189
190+ def parse_args(self, *args):
191+ try:
192+ return main.argument_parser.parse_args(args)
193+ except SystemExit, error:
194+ self.fail("parse_args%r failed with %r" % (args, error))
195+
196 def test_run(self):
197 cluster = ClusterFixture(self.make_dir())
198 self.addCleanup(cluster.stop)
199
200 database_name = self.get_random_database_name()
201- self.useFixture(
202- EnvironmentVariableFixture("PGDATABASE", database_name))
203
204 # Instead of sleeping, check the cluster is running, then break out.
205 def sleep_patch(time):
206@@ -47,7 +51,9 @@
207 raise self.Finished
208
209 self.patch(main, "sleep", sleep_patch)
210- self.assertRaises(self.Finished, main.action_run, cluster)
211+ self.assertRaises(
212+ self.Finished, main.action_run, cluster,
213+ self.parse_args("run", "--dbname", database_name))
214
215 def test_run_without_database(self):
216 # A database is not created if it's not specified in the PGDATABASE
217@@ -68,22 +74,24 @@
218 raise self.Finished
219
220 self.patch(main, "sleep", sleep_patch)
221- self.assertRaises(self.Finished, main.action_run, cluster)
222+ self.assertRaises(
223+ self.Finished, main.action_run, cluster,
224+ self.parse_args("run"))
225
226 def test_shell(self):
227 cluster = ClusterFixture(self.make_dir())
228 self.addCleanup(cluster.stop)
229
230 database_name = self.get_random_database_name()
231- self.useFixture(
232- EnvironmentVariableFixture("PGDATABASE", database_name))
233
234 def shell_patch(database):
235 self.assertEqual(database_name, database)
236 raise self.Finished
237
238 self.patch(cluster, "shell", shell_patch)
239- self.assertRaises(self.Finished, main.action_shell, cluster)
240+ self.assertRaises(
241+ self.Finished, main.action_shell, cluster,
242+ self.parse_args("shell", "--dbname", database_name))
243
244 def test_status_running(self):
245 cluster = ClusterFixture(self.make_dir())
246@@ -91,7 +99,8 @@
247 cluster.start()
248 self.patch(sys, "stdout", StringIO())
249 code = self.assertRaises(
250- SystemExit, main.action_status, cluster).code
251+ SystemExit, main.action_status, cluster,
252+ self.parse_args("status")).code
253 self.assertEqual(0, code)
254 self.assertEqual(
255 "%s: running\n" % cluster.datadir,
256@@ -102,7 +111,8 @@
257 cluster.create()
258 self.patch(sys, "stdout", StringIO())
259 code = self.assertRaises(
260- SystemExit, main.action_status, cluster).code
261+ SystemExit, main.action_status, cluster,
262+ self.parse_args("status")).code
263 self.assertEqual(1, code)
264 self.assertEqual(
265 "%s: not running\n" % cluster.datadir,
266@@ -112,7 +122,8 @@
267 cluster = ClusterFixture(self.make_dir())
268 self.patch(sys, "stdout", StringIO())
269 code = self.assertRaises(
270- SystemExit, main.action_status, cluster).code
271+ SystemExit, main.action_status, cluster,
272+ self.parse_args("status")).code
273 self.assertEqual(2, code)
274 self.assertEqual(
275 "%s: not created\n" % cluster.datadir,
276@@ -122,7 +133,7 @@
277 cluster = ClusterFixture(self.make_dir())
278 self.addCleanup(cluster.stop)
279 cluster.start()
280- main.action_stop(cluster)
281+ main.action_stop(cluster, self.parse_args("stop"))
282 self.assertFalse(cluster.running)
283 self.assertTrue(cluster.exists)
284
285@@ -134,7 +145,8 @@
286 cluster.lock.acquire()
287 self.patch(sys, "stderr", StringIO())
288 error = self.assertRaises(
289- SystemExit, main.action_stop, cluster)
290+ SystemExit, main.action_stop, cluster,
291+ self.parse_args("stop"))
292 self.assertEqual(2, error.code)
293 self.assertThat(
294 sys.stderr.getvalue(), StartsWith(
295@@ -145,7 +157,7 @@
296 cluster = ClusterFixture(self.make_dir())
297 self.addCleanup(cluster.stop)
298 cluster.start()
299- main.action_destroy(cluster)
300+ main.action_destroy(cluster, self.parse_args("destroy"))
301 self.assertFalse(cluster.running)
302 self.assertFalse(cluster.exists)
303
304@@ -155,7 +167,8 @@
305 cluster.lock.acquire()
306 self.patch(sys, "stderr", StringIO())
307 error = self.assertRaises(
308- SystemExit, main.action_destroy, cluster)
309+ SystemExit, main.action_destroy, cluster,
310+ self.parse_args("destroy"))
311 self.assertEqual(2, error.code)
312 self.assertThat(
313 sys.stderr.getvalue(), StartsWith(

Subscribers

People subscribed via source and target branches

to all changes: