Merge lp:~frankban/lpsetup/yellow-ppa into lp:lpsetup

Proposed by Francesco Banconi
Status: Merged
Approved by: Brad Crittenden
Approved revision: 12
Merged at revision: 9
Proposed branch: lp:~frankban/lpsetup/yellow-ppa
Merge into: lp:lpsetup
Diff against target: 176 lines (+65/-6)
6 files modified
lpsetup/argparser.py (+26/-1)
lpsetup/settings.py (+1/-0)
lpsetup/subcommands/install.py (+2/-2)
lpsetup/subcommands/lxcinstall.py (+10/-3)
lpsetup/tests/examples.py (+9/-0)
lpsetup/tests/test_argparser.py (+17/-0)
To merge this branch: bzr merge lp:~frankban/lpsetup/yellow-ppa
Reviewer Review Type Date Requested Status
Brad Crittenden (community) code Approve
Review via email: mp+100102@code.launchpad.net

Description of the change

== Changes ==

Updated `lxc-install` subcommand to add the yellow ppa repository in the container.
This is required because we want to install lpsetup (and python-shell-toolbox as a dependency) inside the container.

The helper function `apt_get_install` is now called passing caller=call. This way the output is actually printed to the terminal.

Added a dynamic dispatcher to StepsBasedSubCommand. If a sub command defines a step `mystep`, the dispatcher tries to run the step invoking `subcommand.call_mystep(namespace, step, args)`. If a method named `call_[step name]` is not defined, a default step runner is used. This way, a sub command can easily wrap or override the provided steps. This can be useful in the future, for example, having a step that can or can not be run based on a sub command option.

== Tests ==

$ bin/test
Running zope.testrunner.layer.UnitTests tests:
  Set up zope.testrunner.layer.UnitTests in 0.000 seconds.
  Ran 39 tests with 0 failures and 0 errors in 0.026 seconds.
Tearing down left over layers:
  Tear down zope.testrunner.layer.UnitTests in 0.000 seconds.

To post a comment you must log in.
Revision history for this message
Brad Crittenden (bac) wrote :

Looks good Francesco!

review: Approve (code)
Revision history for this message
Francesco Banconi (frankban) wrote :

Thanks Brad.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lpsetup/argparser.py'
2--- lpsetup/argparser.py 2012-03-22 10:39:05 +0000
3+++ lpsetup/argparser.py 2012-03-30 11:06:25 +0000
4@@ -394,6 +394,24 @@
5
6 >>> trace
7 ['step1 received eggs']
8+
9+ A dynamic dispatcher takes care of running the steps. This way, a
10+ sub command can easily wrap or override the provided steps, defining a
11+ method named 'call_[step name]'::
12+
13+ >>> trace = []
14+
15+ >>> class DynamicSubCommand(SubCommand):
16+ ... def call_step1(self, namespace, step, args):
17+ ... trace.append('running step')
18+ ... step(*args)
19+
20+ >>> parser = ArgumentParser()
21+ >>> _ = parser.register_subcommand('sub', DynamicSubCommand)
22+ >>> namespace = parser.parse_args('sub --foo eggs --bar spam'.split())
23+ >>> namespace.main(namespace)
24+ >>> trace
25+ ['running step', 'step1 received eggs', 'step2 received eggs and spam']
26 """
27
28 steps = ()
29@@ -441,15 +459,22 @@
30 '--skip-steps', nargs='+', choices=self._step_names,
31 help='Skip one or more internal functions.')
32
33+ def _call_step(self, namespace, step, args):
34+ """Default callable used to run a `step`, using given `args`."""
35+ return step(*args)
36+
37 def handle(self, namespace):
38 skip_steps = namespace.skip_steps or []
39 step_names = filter(
40 lambda step_name: step_name not in skip_steps,
41 namespace.steps or self._step_names)
42+ default_step_runner = self._call_step
43 for step_name in step_names:
44 step, arg_names = self._steps[step_name]
45 args = [getattr(namespace, i) for i in arg_names]
46+ step_runner = getattr(
47+ self, 'call_' + step_name, default_step_runner)
48 try:
49- step(*args)
50+ step_runner(namespace, step, args)
51 except subprocess.CalledProcessError as err:
52 return err
53
54=== modified file 'lpsetup/settings.py'
55--- lpsetup/settings.py 2012-03-16 17:03:20 +0000
56+++ lpsetup/settings.py 2012-03-30 11:06:25 +0000
57@@ -56,6 +56,7 @@
58 )
59 LP_SOURCE_DEPS = (
60 'http://bazaar.launchpad.net/~launchpad/lp-source-dependencies/trunk')
61+LPSETUP_PPA = 'ppa:yellow/ppa'
62 LXC_CONFIG_TEMPLATE = '/etc/lxc/local.conf'
63 LXC_GUEST_ARCH = 'i386'
64 LXC_GUEST_CHOICES = ('lucid', 'oneiric', 'precise')
65
66=== modified file 'lpsetup/subcommands/install.py'
67--- lpsetup/subcommands/install.py 2012-03-22 10:48:50 +0000
68+++ lpsetup/subcommands/install.py 2012-03-30 11:06:25 +0000
69@@ -118,7 +118,7 @@
70 """Initialize host machine."""
71 # Install necessary deb packages. This requires Oneiric or later.
72 call('apt-get', 'update')
73- apt_get_install(*BASE_PACKAGES)
74+ apt_get_install(*BASE_PACKAGES, caller=call)
75 # Create the user (if he does not exist).
76 if not user_exists(user):
77 call('useradd', '-m', '-s', '/bin/bash', '-U', user)
78@@ -181,7 +181,7 @@
79 call("echo 'mountall hold' | dpkg --set-selections", shell=True)
80 call('apt-get', 'update')
81 # Install base and Launchpad deb packages.
82- apt_get_install(*LP_PACKAGES, LANG='C')
83+ apt_get_install(*LP_PACKAGES, LANG='C', caller=call)
84
85
86 def setup_launchpad(user, dependencies_dir, directory, valid_ssh_keys):
87
88=== modified file 'lpsetup/subcommands/lxcinstall.py'
89--- lpsetup/subcommands/lxcinstall.py 2012-03-22 17:28:04 +0000
90+++ lpsetup/subcommands/lxcinstall.py 2012-03-30 11:06:25 +0000
91@@ -31,6 +31,7 @@
92 from lpsetup.settings import (
93 BASE_PACKAGES,
94 DHCP_FILE,
95+ LPSETUP_PPA,
96 LXC_CONFIG_TEMPLATE,
97 LXC_GUEST_ARCH,
98 LXC_GUEST_CHOICES,
99@@ -57,7 +58,7 @@
100 for parallel testing using ephemeral instances.
101 """
102 # Install necessary deb packages.
103- apt_get_install(*LXC_PACKAGES)
104+ apt_get_install(*LXC_PACKAGES, caller=call)
105 # XXX 2012-02-02 gmb bug=925024:
106 # These calls need to be removed once the lxc vs. apparmor bug
107 # is resolved, since having apparmor enabled for lxc is very
108@@ -116,10 +117,16 @@
109 break
110
111
112-def initialize_lxc(lxc_name, ssh_key_path):
113+def initialize_lxc(lxc_name, ssh_key_path, lxc_os):
114 """Initialize LXC container."""
115 base_packages = list(BASE_PACKAGES) + ['lpsetup']
116 sshcall = ssh(lxc_name, key=ssh_key_path)
117+ args = {
118+ 'assume_yes': '' if lxc_os == 'lucid' else '-y',
119+ 'repository': LPSETUP_PPA,
120+ }
121+ sshcall('apt-add-repository {assume_yes} {repository}'.format(**args))
122+ sshcall('apt-get clean && apt-get update')
123 sshcall(
124 'DEBIAN_FRONTEND=noninteractive '
125 'apt-get install -y ' + ' '.join(base_packages))
126@@ -158,7 +165,7 @@
127 (wait_for_lxc,
128 'lxc_name', 'ssh_key_path'),
129 (initialize_lxc,
130- 'lxc_name', 'ssh_key_path'),
131+ 'lxc_name', 'ssh_key_path', 'lxc_os'),
132 (setup_launchpad_lxc,
133 'user', 'dependencies_dir', 'directory',
134 'valid_ssh_keys', 'ssh_key_path', 'lxc_name'),
135
136=== modified file 'lpsetup/tests/examples.py'
137--- lpsetup/tests/examples.py 2012-03-22 10:56:14 +0000
138+++ lpsetup/tests/examples.py 2012-03-30 11:06:25 +0000
139@@ -67,3 +67,12 @@
140 (bad_step, 'foo'),
141 (step2, 'foo', 'bar'),
142 )
143+
144+
145+class DynamicStepsBasedSubCommand(StepsBasedSubCommand):
146+ """An example steps based sub command (using internal step dispatcher)."""
147+
148+ def call_step1(self, namespace, step, args):
149+ print 'running step1 with {args} while bar is {bar}'.format(
150+ args=','.join(args), bar=namespace.bar)
151+ step(*args)
152
153=== modified file 'lpsetup/tests/test_argparser.py'
154--- lpsetup/tests/test_argparser.py 2012-03-22 10:56:14 +0000
155+++ lpsetup/tests/test_argparser.py 2012-03-30 11:06:25 +0000
156@@ -188,3 +188,20 @@
157 error = self.parse_and_call_main('--foo eggs')
158 self.assertEqual(1, error.returncode)
159 self.check_output(['step1 received eggs'], output)
160+
161+
162+class DynamicStepsBasedSubCommandTest(SubCommandTestMixin, unittest.TestCase):
163+
164+ sub_command_class = examples.DynamicStepsBasedSubCommand
165+
166+ def test_dynamic_dispatcher(self):
167+ # The test runner calls a function named 'call_[step name]' if it is
168+ # defined.
169+ with capture_output() as output:
170+ self.parse_and_call_main('--foo eggs --bar spam')
171+ expected = [
172+ 'running step1 with eggs while bar is spam',
173+ 'step1 received eggs',
174+ 'step2 received eggs and spam'
175+ ]
176+ self.check_output(expected, output)

Subscribers

People subscribed via source and target branches

to all changes: