← Back to team overview

cloud-init-dev team mailing list archive

[Merge] lp:~harlowja/cloud-init/cloud-init-fix-up-cli into lp:cloud-init

 

Joshua Harlow has proposed merging lp:~harlowja/cloud-init/cloud-init-fix-up-cli into lp:cloud-init.

Requested reviews:
  cloud init development team (cloud-init-dev)

For more details, see:
https://code.launchpad.net/~harlowja/cloud-init/cloud-init-fix-up-cli/+merge/297409
-- 
Your team cloud init development team is requested to review the proposed merge of lp:~harlowja/cloud-init/cloud-init-fix-up-cli into lp:cloud-init.
=== removed directory 'bin'
=== added directory 'cloudinit/cmd'
=== added file 'cloudinit/cmd/__init__.py'
--- cloudinit/cmd/__init__.py	1970-01-01 00:00:00 +0000
+++ cloudinit/cmd/__init__.py	2016-06-14 21:58:15 +0000
@@ -0,0 +1,21 @@
+# vi: ts=4 expandtab
+#
+#    Copyright (C) 2012 Canonical Ltd.
+#    Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
+#    Copyright (C) 2012 Yahoo! Inc.
+#
+#    Author: Scott Moser <scott.moser@xxxxxxxxxxxxx>
+#    Author: Juerg Haefliger <juerg.haefliger@xxxxxx>
+#    Author: Joshua Harlow <harlowja@xxxxxxxxxxxxx>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License version 3, as
+#    published by the Free Software Foundation.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

=== renamed file 'bin/cloud-init' => 'cloudinit/cmd/main.py'
--- bin/cloud-init	2016-05-31 21:17:39 +0000
+++ cloudinit/cmd/main.py	2016-06-14 21:58:15 +0000
@@ -25,17 +25,10 @@
 import json
 import os
 import sys
+import tempfile
 import time
-import tempfile
 import traceback
 
-# This is more just for running from the bin folder so that
-# cloud-init binary can find the cloudinit module
-possible_topdir = os.path.normpath(os.path.join(os.path.abspath(
-        sys.argv[0]), os.pardir, os.pardir))
-if os.path.exists(os.path.join(possible_topdir, "cloudinit", "__init__.py")):
-    sys.path.insert(0, possible_topdir)
-
 from cloudinit import patcher
 patcher.patch()
 
@@ -46,9 +39,10 @@
 from cloudinit import stages
 from cloudinit import templater
 from cloudinit import util
+from cloudinit import version
+
 from cloudinit import reporting
 from cloudinit.reporting import events
-from cloudinit import version
 
 from cloudinit.settings import (PER_INSTANCE, PER_ALWAYS, PER_ONCE,
                                 CLOUD_CONFIG)
@@ -188,7 +182,7 @@
         LOG.debug("Closing stdin")
         util.close_stdin()
         (outfmt, errfmt) = util.fixup_output(init.cfg, name)
-    except:
+    except Exception:
         util.logexc(LOG, "Failed to setup output redirection!")
         print_exc("Failed to setup output redirection!")
     if args.debug:
@@ -325,7 +319,7 @@
         if outfmt_orig != outfmt or errfmt_orig != errfmt:
             LOG.warn("Stdout, stderr changing to (%s, %s)", outfmt, errfmt)
             (outfmt, errfmt) = util.fixup_output(mods.cfg, name)
-    except:
+    except Exception:
         util.logexc(LOG, "Failed to re-adjust output redirection!")
     logging.setupLogging(mods.cfg)
 
@@ -367,7 +361,7 @@
         LOG.debug("Closing stdin")
         util.close_stdin()
         util.fixup_output(mods.cfg, name)
-    except:
+    except Exception:
         util.logexc(LOG, "Failed to setup output redirection!")
     if args.debug:
         # Reset so that all the debug handlers are closed out
@@ -430,7 +424,7 @@
         LOG.debug("Closing stdin")
         util.close_stdin()
         util.fixup_output(mods.cfg, None)
-    except:
+    except Exception:
         util.logexc(LOG, "Failed to setup output redirection!")
     if args.debug:
         # Reset so that all the debug handlers are closed out
@@ -510,7 +504,7 @@
     else:
         try:
             status = json.loads(util.load_file(status_path))
-        except:
+        except Exception:
             pass
 
     if status is None:
@@ -569,8 +563,12 @@
     return len(v1[mode]['errors'])
 
 
-def main():
-    parser = argparse.ArgumentParser()
+def main(sysv_args=None):
+    if sysv_args is not None:
+        parser = argparse.ArgumentParser(prog=sysv_args[0])
+        sysv_args = sysv_args[1:]
+    else:
+        parser = argparse.ArgumentParser()
 
     # Top level args
     parser.add_argument('--version', '-v', action='version',
@@ -646,7 +644,7 @@
                                      ' pass to this module'))
     parser_single.set_defaults(action=('single', main_single))
 
-    args = parser.parse_args()
+    args = parser.parse_args(args=sysv_args)
 
     # Setup basic logging to start (until reinitialized)
     # iff in debug mode...
@@ -656,9 +654,8 @@
     # Setup signal handlers before running
     signal_handler.attach_handlers()
 
-    if not hasattr(args, 'action'):
-        parser.error('too few arguments')
     (name, functor) = args.action
+
     if name in ("modules", "init"):
         functor = status_wrapper
 
@@ -683,7 +680,3 @@
         return util.log_time(
             logfunc=LOG.debug, msg="cloud-init mode '%s'" % name,
             get_uptime=True, func=functor, args=(name, args))
-
-
-if __name__ == '__main__':
-    sys.exit(main())

=== modified file 'setup.py'
--- setup.py	2016-06-07 01:42:29 +0000
+++ setup.py	2016-06-14 21:58:15 +0000
@@ -204,10 +204,14 @@
     author_email='scott.moser@xxxxxxxxxxxxx',
     url='http://launchpad.net/cloud-init/',
     packages=setuptools.find_packages(exclude=['tests']),
-    scripts=['bin/cloud-init',
-             'tools/cloud-init-per'],
+    scripts=['tools/cloud-init-per'],
     license='GPLv3',
     data_files=data_files,
     install_requires=requirements,
     cmdclass=cmdclass,
+    entry_points={
+        'console_scripts': [
+            'cloud-init = cloudinit.cmd.main:main'
+        ],
+    }
 )

=== modified file 'tests/unittests/test_cli.py'
--- tests/unittests/test_cli.py	2016-05-19 21:26:30 +0000
+++ tests/unittests/test_cli.py	2016-06-14 21:58:15 +0000
@@ -6,7 +6,7 @@
 from . import helpers as test_helpers
 mock = test_helpers.mock
 
-BIN_CLOUDINIT = "bin/cloud-init"
+from cloudinit.cmd import main as cli
 
 
 class TestCLI(test_helpers.FilesystemMockingTestCase):
@@ -15,35 +15,22 @@
         super(TestCLI, self).setUp()
         self.stderr = six.StringIO()
         self.patchStdoutAndStderr(stderr=self.stderr)
-        self.sys_exit = mock.MagicMock()
-        self.patched_funcs.enter_context(
-            mock.patch.object(sys, 'exit', self.sys_exit))
 
-    def _call_main(self):
-        self.patched_funcs.enter_context(
-            mock.patch.object(sys, 'argv', ['cloud-init']))
-        cli = imp.load_module(
-            'cli', open(BIN_CLOUDINIT), '', ('', 'r', imp.PY_SOURCE))
+    def _call_main(self, sysv_args=None):
+        if not sysv_args:
+            sysv_args = ['cloud-init']
         try:
-            return cli.main()
-        except Exception:
-            pass
+            return cli.main(sysv_args=sysv_args)
+        except SystemExit as e:
+            return e.code
 
-    @test_helpers.skipIf(not os.path.isfile(BIN_CLOUDINIT), "no bin/cloudinit")
     def test_no_arguments_shows_usage(self):
-        self._call_main()
+        exit_code = self._call_main()
         self.assertIn('usage: cloud-init', self.stderr.getvalue())
-
-    @test_helpers.skipIf(not os.path.isfile(BIN_CLOUDINIT), "no bin/cloudinit")
-    def test_no_arguments_exits_2(self):
-        exit_code = self._call_main()
-        if self.sys_exit.call_count:
-            self.assertEqual(mock.call(2), self.sys_exit.call_args)
-        else:
-            self.assertEqual(2, exit_code)
-
-    @test_helpers.skipIf(not os.path.isfile(BIN_CLOUDINIT), "no bin/cloudinit")
+        self.assertEqual(2, exit_code)
+
     def test_no_arguments_shows_error_message(self):
-        self._call_main()
+        exit_code = self._call_main()
         self.assertIn('cloud-init: error: too few arguments',
                       self.stderr.getvalue())
+        self.assertEqual(2, exit_code)


Follow ups