[Zope3-checkins] SVN: Zope3/trunk/src/zope/app/server/ Read the username and password interactively.

Fred L. Drake, Jr. fred at zope.com
Fri Jun 18 12:34:13 EDT 2004


Log message for revision 25910:
Read the username and password interactively.

(Merged revision 25908 from the ZopeX3-3.0 branch.) 



-=-
Modified: Zope3/trunk/src/zope/app/server/mkzopeinstance.py
===================================================================
--- Zope3/trunk/src/zope/app/server/mkzopeinstance.py	2004-06-18 16:28:07 UTC (rev 25909)
+++ Zope3/trunk/src/zope/app/server/mkzopeinstance.py	2004-06-18 16:32:54 UTC (rev 25910)
@@ -44,18 +44,35 @@
         else:
             return 0
     app = Application(options)
-    return app.process()
+    try:
+        return app.process()
+    except KeyboardInterrupt:
+        return 1
+    except SystemExit, e:
+        return e.code
 
 
 class Application:
 
     def __init__(self, options):
         self.options = options
+        self.need_blank_line = False
 
     def read_input_line(self, prompt):
         # The tests replace this to make sure the right things happen.
         return raw_input(prompt)
 
+    def read_password(self, prompt):
+        # The tests replace this to make sure the right things happen.
+        import getpass
+        try:
+            return getpass.getpass(prompt)
+        except KeyboardInterrupt:
+            # The cursor was left on the same line as the prompt,
+            # which we don't like.  Print a blank line.
+            print
+            raise
+
     def process(self):
         options = self.options
 
@@ -81,29 +98,58 @@
                                  " non-directories)")
             return 1
 
-        # XXX for now, bail if the username/password hasn't been
-        # provided from the command line; this should be improved
-        # after the ZopeX3 alpha:
-        if not (options.username and options.password):
-            print >>sys.stderr, ("username and password must be"
-                                 " provided using the --user option")
-            return 2
+        if not options.username:
+            options.username = self.get_username()
+        if not options.password:
+            options.password = self.get_password()
 
         # now create the instance!
         self.copy_skeleton()
         return 0
 
     def get_skeltarget(self):
-        print SKELTARGET_MESSAGE
+        self.print_message(SKELTARGET_MESSAGE)
+        self.need_blank_line = True
         while 1:
             skeltarget = self.read_input_line("Directory: ").strip()
             if skeltarget == '':
                 print >>sys.stderr, 'You must specify a directory'
                 continue
-            else:
-                break
-        return os.path.expanduser(skeltarget)
+            return os.path.expanduser(skeltarget)
 
+    def get_username(self):
+        self.print_message(USERNAME_MESSAGE)
+        self.need_blank_line = True
+        while 1:
+            username = self.read_input_line("Username: ").strip()
+            if not username:
+                print >>sys.stderr, "You must specify an administrative user"
+                continue
+            return username
+
+    def get_password(self):
+        self.print_message(PASSWORD_MESSAGE)
+        while 1:
+            password = self.read_password("Password: ")
+            if not password:
+                print >>sys.stderr, "Password may not be empty"
+                continue
+            if password != password.strip() or password.split() != [password]:
+                print >>sys.stderr, "Password may not contain spaces"
+                continue
+            break
+        again = self.read_password("Verify password: ")
+        if again != password:
+            print >>sys.stderr, "Password not verified!"
+            sys.exit(1)
+        return password
+
+    def print_message(self, message):
+        if self.need_blank_line:
+            print
+            self.need_blank_line = False
+        print message
+
     def copy_skeleton(self):
         options = self.options
         # XXX we should be able to compute the script
@@ -127,6 +173,8 @@
         # instead of shutil.copy2().
         assert os.path.isdir(dst), dst
         names = os.listdir(src)
+        if ".svn" in names:
+            names.remove(".svn")
         for name in names:
             srcname = os.path.join(src, name)
             dstname = os.path.join(dst, name)
@@ -159,7 +207,16 @@
 etc.
 """
 
+USERNAME_MESSAGE = """\
+Please choose a username for the initial administrator account.
+This is required to allow Zope's management interface to be used.
+"""
 
+PASSWORD_MESSAGE = """\
+Please provide a password for the initial administrator account.
+"""
+
+
 def parse_args(argv):
     """Parse the command line, returning an object representing the input."""
     path, prog = os.path.split(os.path.realpath(argv[0]))

Modified: Zope3/trunk/src/zope/app/server/tests/test_mkzopeinstance.py
===================================================================
--- Zope3/trunk/src/zope/app/server/tests/test_mkzopeinstance.py	2004-06-18 16:28:07 UTC (rev 25909)
+++ Zope3/trunk/src/zope/app/server/tests/test_mkzopeinstance.py	2004-06-18 16:32:54 UTC (rev 25910)
@@ -161,6 +161,7 @@
         self.assertEqual(skel, "foo")
         self.assertEqual(input, [])
         self.assert_(self.stdout.getvalue())
+        self.failUnless(app.all_input_consumed())
 
     def test_process_creates_destination(self):
         options = self.createOptions()
@@ -169,6 +170,7 @@
         self.assertEqual(app.process(), 0)
         self.assert_(os.path.isdir(self.instance))
         self.assertEqual(input, [])
+        self.failUnless(app.all_input_consumed())
 
     def test_process_aborts_on_file_destination(self):
         options = self.createOptions()
@@ -185,7 +187,77 @@
         self.assertEqual(app.process(), 1)
         self.assert_(self.stderr.getvalue())
 
+    def test_get_username(self):
+        options = self.createOptions()
+        app = ControlledInputApplication(options, ["myuser"])
+        usr = app.get_username()
+        self.assertEqual(usr, "myuser")
+        self.failIf(self.stderr.getvalue())
+        self.failUnless(self.stdout.getvalue())
+        self.failUnless(app.all_input_consumed())
 
+    def test_get_username_strips_whitespace(self):
+        options = self.createOptions()
+        app = ControlledInputApplication(options, ["  myuser\t"])
+        usr = app.get_username()
+        self.assertEqual(usr, "myuser")
+        self.failIf(self.stderr.getvalue())
+        self.failUnless(self.stdout.getvalue())
+        self.failUnless(app.all_input_consumed())
+
+    def test_get_username_ignores_empty_names(self):
+        options = self.createOptions()
+        app = ControlledInputApplication(options, ["", "  ", "\t", "myuser"])
+        usr = app.get_username()
+        self.assertEqual(usr, "myuser")
+        self.failUnless(self.stderr.getvalue())
+        self.failUnless(self.stdout.getvalue())
+        self.failUnless(app.all_input_consumed())
+
+    def test_get_password(self):
+        options = self.createOptions()
+        app = ControlledInputApplication(options, ["foo", "foo"])
+        pw = app.get_password()
+        self.assertEqual(pw, "foo")
+        self.failIf(self.stderr.getvalue())
+        self.failUnless(self.stdout.getvalue())
+        self.failUnless(app.all_input_consumed())
+
+    def test_get_password_not_verified(self):
+        options = self.createOptions()
+        app = ControlledInputApplication(options, ["foo", "bar"])
+        try:
+            app.get_password()
+        except SystemExit, e:
+            self.assertEqual(e.code, 1)
+        else:
+            self.fail("expected SystemExit")
+        self.failUnless(self.stderr.getvalue())
+        self.failUnless(self.stdout.getvalue())
+        self.failUnless(app.all_input_consumed())
+
+    def test_get_password_empty(self):
+        # Make sure the empty password is ignored.
+        options = self.createOptions()
+        app = ControlledInputApplication(options, ["", "foo", "foo"])
+        pw = app.get_password()
+        self.assertEqual(pw, "foo")
+        self.failUnless(self.stderr.getvalue())
+        self.failUnless(self.stdout.getvalue())
+        self.failUnless(app.all_input_consumed())
+
+    def test_get_password_disallows_whitespace(self):
+        # Any password that contains spaces is disallowed.
+        options = self.createOptions()
+        app = ControlledInputApplication(options, [" ", "\t", "a b",
+                                                   " a", "b ", "foo", "foo"])
+        pw = app.get_password()
+        self.assertEqual(pw, "foo")
+        self.failUnless(self.stderr.getvalue())
+        self.failUnless(self.stdout.getvalue())
+        self.failUnless(app.all_input_consumed())
+
+
 class ControlledInputApplication(mkzopeinstance.Application):
 
     def __init__(self, options, input_lines):
@@ -195,7 +267,12 @@
     def read_input_line(self, prompt):
         return self.__input.pop(0)
 
+    read_password = read_input_line
 
+    def all_input_consumed(self):
+        return not self.__input
+
+
 class Options:
 
     username = "[test-username]"




More information about the Zope3-Checkins mailing list