Merge lp:~harlowja/cloud-init/cloud-init-fix-up-cli into lp:~cloud-init-dev/cloud-init/trunk

Proposed by Joshua Harlow on 2016-06-14
Status: Merged
Merged at revision: 1238
Proposed branch: lp:~harlowja/cloud-init/cloud-init-fix-up-cli
Merge into: lp:~cloud-init-dev/cloud-init/trunk
Diff against target: 274 lines (+65/-60)
6 files modified
cloudinit/cmd/__init__.py (+21/-0)
cloudinit/cmd/main.py (+21/-25)
setup.py (+6/-2)
tests/unittests/test_cli.py (+14/-29)
tools/run-pep8 (+2/-3)
tools/run-pyflakes (+1/-1)
To merge this branch: bzr merge lp:~harlowja/cloud-init/cloud-init-fix-up-cli
Reviewer Review Type Date Requested Status
cloud-init commiters 2016-06-14 Pending
Review via email: mp+297409@code.launchpad.net
To post a comment you must log in.
1238. By Joshua Harlow on 2016-06-14

Retain the prior attribute missing handling

1239. By Joshua Harlow on 2016-06-14

Don't continue running with no action

1240. By Joshua Harlow on 2016-06-15

Silence pep8 warnings due to patcher activation

1241. By Joshua Harlow on 2016-06-15

Fix a few tools and tests for newer pep8

1242. By Joshua Harlow on 2016-06-15

Remove /bin from run-pyflakes

1243. By Joshua Harlow on 2016-06-15

Remove some unused imports

Scott Moser (smoser) wrote :

can you merge with trunk now ?
there is one conflict, and what i think you end up needing is just
 http://paste.ubuntu.com/17386285/

Scott Moser (smoser) wrote :

oops. wrong mp

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== removed directory 'bin'
2=== added directory 'cloudinit/cmd'
3=== added file 'cloudinit/cmd/__init__.py'
4--- cloudinit/cmd/__init__.py 1970-01-01 00:00:00 +0000
5+++ cloudinit/cmd/__init__.py 2016-06-15 19:19:29 +0000
6@@ -0,0 +1,21 @@
7+# vi: ts=4 expandtab
8+#
9+# Copyright (C) 2012 Canonical Ltd.
10+# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
11+# Copyright (C) 2012 Yahoo! Inc.
12+#
13+# Author: Scott Moser <scott.moser@canonical.com>
14+# Author: Juerg Haefliger <juerg.haefliger@hp.com>
15+# Author: Joshua Harlow <harlowja@yahoo-inc.com>
16+#
17+# This program is free software: you can redistribute it and/or modify
18+# it under the terms of the GNU General Public License version 3, as
19+# published by the Free Software Foundation.
20+#
21+# This program is distributed in the hope that it will be useful,
22+# but WITHOUT ANY WARRANTY; without even the implied warranty of
23+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24+# GNU General Public License for more details.
25+#
26+# You should have received a copy of the GNU General Public License
27+# along with this program. If not, see <http://www.gnu.org/licenses/>.
28
29=== renamed file 'bin/cloud-init' => 'cloudinit/cmd/main.py'
30--- bin/cloud-init 2016-05-31 21:17:39 +0000
31+++ cloudinit/cmd/main.py 2016-06-15 19:19:29 +0000
32@@ -25,19 +25,12 @@
33 import json
34 import os
35 import sys
36+import tempfile
37 import time
38-import tempfile
39 import traceback
40
41-# This is more just for running from the bin folder so that
42-# cloud-init binary can find the cloudinit module
43-possible_topdir = os.path.normpath(os.path.join(os.path.abspath(
44- sys.argv[0]), os.pardir, os.pardir))
45-if os.path.exists(os.path.join(possible_topdir, "cloudinit", "__init__.py")):
46- sys.path.insert(0, possible_topdir)
47-
48 from cloudinit import patcher
49-patcher.patch()
50+patcher.patch() # noqa
51
52 from cloudinit import log as logging
53 from cloudinit import netinfo
54@@ -46,9 +39,10 @@
55 from cloudinit import stages
56 from cloudinit import templater
57 from cloudinit import util
58+from cloudinit import version
59+
60 from cloudinit import reporting
61 from cloudinit.reporting import events
62-from cloudinit import version
63
64 from cloudinit.settings import (PER_INSTANCE, PER_ALWAYS, PER_ONCE,
65 CLOUD_CONFIG)
66@@ -188,7 +182,7 @@
67 LOG.debug("Closing stdin")
68 util.close_stdin()
69 (outfmt, errfmt) = util.fixup_output(init.cfg, name)
70- except:
71+ except Exception:
72 util.logexc(LOG, "Failed to setup output redirection!")
73 print_exc("Failed to setup output redirection!")
74 if args.debug:
75@@ -325,7 +319,7 @@
76 if outfmt_orig != outfmt or errfmt_orig != errfmt:
77 LOG.warn("Stdout, stderr changing to (%s, %s)", outfmt, errfmt)
78 (outfmt, errfmt) = util.fixup_output(mods.cfg, name)
79- except:
80+ except Exception:
81 util.logexc(LOG, "Failed to re-adjust output redirection!")
82 logging.setupLogging(mods.cfg)
83
84@@ -367,7 +361,7 @@
85 LOG.debug("Closing stdin")
86 util.close_stdin()
87 util.fixup_output(mods.cfg, name)
88- except:
89+ except Exception:
90 util.logexc(LOG, "Failed to setup output redirection!")
91 if args.debug:
92 # Reset so that all the debug handlers are closed out
93@@ -430,7 +424,7 @@
94 LOG.debug("Closing stdin")
95 util.close_stdin()
96 util.fixup_output(mods.cfg, None)
97- except:
98+ except Exception:
99 util.logexc(LOG, "Failed to setup output redirection!")
100 if args.debug:
101 # Reset so that all the debug handlers are closed out
102@@ -510,7 +504,7 @@
103 else:
104 try:
105 status = json.loads(util.load_file(status_path))
106- except:
107+ except Exception:
108 pass
109
110 if status is None:
111@@ -569,8 +563,12 @@
112 return len(v1[mode]['errors'])
113
114
115-def main():
116- parser = argparse.ArgumentParser()
117+def main(sysv_args=None):
118+ if sysv_args is not None:
119+ parser = argparse.ArgumentParser(prog=sysv_args[0])
120+ sysv_args = sysv_args[1:]
121+ else:
122+ parser = argparse.ArgumentParser()
123
124 # Top level args
125 parser.add_argument('--version', '-v', action='version',
126@@ -646,7 +644,12 @@
127 ' pass to this module'))
128 parser_single.set_defaults(action=('single', main_single))
129
130- args = parser.parse_args()
131+ args = parser.parse_args(args=sysv_args)
132+
133+ try:
134+ (name, functor) = args.action
135+ except AttributeError:
136+ parser.error('too few arguments')
137
138 # Setup basic logging to start (until reinitialized)
139 # iff in debug mode...
140@@ -656,9 +659,6 @@
141 # Setup signal handlers before running
142 signal_handler.attach_handlers()
143
144- if not hasattr(args, 'action'):
145- parser.error('too few arguments')
146- (name, functor) = args.action
147 if name in ("modules", "init"):
148 functor = status_wrapper
149
150@@ -683,7 +683,3 @@
151 return util.log_time(
152 logfunc=LOG.debug, msg="cloud-init mode '%s'" % name,
153 get_uptime=True, func=functor, args=(name, args))
154-
155-
156-if __name__ == '__main__':
157- sys.exit(main())
158
159=== modified file 'setup.py'
160--- setup.py 2016-06-07 01:42:29 +0000
161+++ setup.py 2016-06-15 19:19:29 +0000
162@@ -204,10 +204,14 @@
163 author_email='scott.moser@canonical.com',
164 url='http://launchpad.net/cloud-init/',
165 packages=setuptools.find_packages(exclude=['tests']),
166- scripts=['bin/cloud-init',
167- 'tools/cloud-init-per'],
168+ scripts=['tools/cloud-init-per'],
169 license='GPLv3',
170 data_files=data_files,
171 install_requires=requirements,
172 cmdclass=cmdclass,
173+ entry_points={
174+ 'console_scripts': [
175+ 'cloud-init = cloudinit.cmd.main:main'
176+ ],
177+ }
178 )
179
180=== modified file 'tests/unittests/test_cli.py'
181--- tests/unittests/test_cli.py 2016-05-19 21:26:30 +0000
182+++ tests/unittests/test_cli.py 2016-06-15 19:19:29 +0000
183@@ -1,13 +1,11 @@
184-import imp
185-import os
186 import six
187-import sys
188
189 from . import helpers as test_helpers
190+
191+from cloudinit.cmd import main as cli
192+
193 mock = test_helpers.mock
194
195-BIN_CLOUDINIT = "bin/cloud-init"
196-
197
198 class TestCLI(test_helpers.FilesystemMockingTestCase):
199
200@@ -15,35 +13,22 @@
201 super(TestCLI, self).setUp()
202 self.stderr = six.StringIO()
203 self.patchStdoutAndStderr(stderr=self.stderr)
204- self.sys_exit = mock.MagicMock()
205- self.patched_funcs.enter_context(
206- mock.patch.object(sys, 'exit', self.sys_exit))
207
208- def _call_main(self):
209- self.patched_funcs.enter_context(
210- mock.patch.object(sys, 'argv', ['cloud-init']))
211- cli = imp.load_module(
212- 'cli', open(BIN_CLOUDINIT), '', ('', 'r', imp.PY_SOURCE))
213+ def _call_main(self, sysv_args=None):
214+ if not sysv_args:
215+ sysv_args = ['cloud-init']
216 try:
217- return cli.main()
218- except Exception:
219- pass
220+ return cli.main(sysv_args=sysv_args)
221+ except SystemExit as e:
222+ return e.code
223
224- @test_helpers.skipIf(not os.path.isfile(BIN_CLOUDINIT), "no bin/cloudinit")
225 def test_no_arguments_shows_usage(self):
226- self._call_main()
227+ exit_code = self._call_main()
228 self.assertIn('usage: cloud-init', self.stderr.getvalue())
229-
230- @test_helpers.skipIf(not os.path.isfile(BIN_CLOUDINIT), "no bin/cloudinit")
231- def test_no_arguments_exits_2(self):
232- exit_code = self._call_main()
233- if self.sys_exit.call_count:
234- self.assertEqual(mock.call(2), self.sys_exit.call_args)
235- else:
236- self.assertEqual(2, exit_code)
237-
238- @test_helpers.skipIf(not os.path.isfile(BIN_CLOUDINIT), "no bin/cloudinit")
239+ self.assertEqual(2, exit_code)
240+
241 def test_no_arguments_shows_error_message(self):
242- self._call_main()
243+ exit_code = self._call_main()
244 self.assertIn('cloud-init: error: too few arguments',
245 self.stderr.getvalue())
246+ self.assertEqual(2, exit_code)
247
248=== modified file 'tools/run-pep8'
249--- tools/run-pep8 2016-03-03 22:20:10 +0000
250+++ tools/run-pep8 2016-06-15 19:19:29 +0000
251@@ -1,8 +1,7 @@
252 #!/bin/bash
253
254-pycheck_dirs=( "cloudinit/" "bin/" "tests/" "tools/" )
255-# FIXME: cloud-init modifies sys module path, pep8 does not like
256-# bin_files=( "bin/cloud-init" )
257+pycheck_dirs=( "cloudinit/" "tests/" "tools/" )
258+
259 CR="
260 "
261 [ "$1" = "-v" ] && { verbose="$1"; shift; } || verbose=""
262
263=== modified file 'tools/run-pyflakes'
264--- tools/run-pyflakes 2016-03-03 22:32:32 +0000
265+++ tools/run-pyflakes 2016-06-15 19:19:29 +0000
266@@ -3,7 +3,7 @@
267 PYTHON_VERSION=${PYTHON_VERSION:-2}
268 CR="
269 "
270-pycheck_dirs=( "cloudinit/" "bin/" "tests/" "tools/" )
271+pycheck_dirs=( "cloudinit/" "tests/" "tools/" )
272
273 set -f
274 if [ $# -eq 0 ]; then