[Zope-Checkins] CVS: ZODB3/zdaemon - sample.conf:1.2 schema.xml:1.3 zdctl.py:1.18 zdoptions.py:1.7 zdrun.py:1.3

Guido van Rossum guido@python.org
Mon, 20 Jan 2003 11:21:07 -0500


Update of /cvs-repository/ZODB3/zdaemon
In directory cvs.zope.org:/tmp/cvs-serv3882

Modified Files:
	sample.conf schema.xml zdctl.py zdoptions.py zdrun.py 
Log Message:
Added schema support to zdrun.py.  zdrun.py and zdctl.py share a schema.


=== ZODB3/zdaemon/sample.conf 1.1 => 1.2 ===
--- ZODB3/zdaemon/sample.conf:1.1	Tue Jan 14 17:20:10 2003
+++ ZODB3/zdaemon/sample.conf	Mon Jan 20 11:21:02 2003
@@ -1,5 +1,16 @@
-# Sample config file for zdctl.py.
+# Sample config file for zdctl.py and zdrun.py (which share a schema).
 
 <zdctl>
+  # This is a pure example
   program sleep 100
 </zdctl>
+
+<zdrun>
+  backoff-limit 10
+  daemon	True
+  forever	True
+  socket-name	zdsock
+  exit-codes	0,2
+  # user has no default
+  directory	/
+</zdrun>


=== ZODB3/zdaemon/schema.xml 1.2 => 1.3 ===
--- ZODB3/zdaemon/schema.xml:1.2	Thu Jan 16 20:59:12 2003
+++ ZODB3/zdaemon/schema.xml	Mon Jan 20 11:21:02 2003
@@ -1,13 +1,25 @@
 <schema>
 
   <description>
-    Schema for zdctl.
+    Schema for zdctl.py and zdrun.py.
   </description>
 
   <sectiontype name="zdctl">
     <key name="program" datatype="string-list" required="yes" />
   </sectiontype>
 
+  <sectiontype name="zdrun">
+    <key name="backoff-limit" datatype="integer" default="10" />
+    <key name="daemon" datatype="boolean" default="False" />
+    <key name="forever" datatype="boolean" default="False" />
+    <key name="socket-name" datatype="existing-dirpath" default="zdsock" />
+    <key name="exit-codes" datatype="zdaemon.zdoptions.list_of_ints"
+	       default="0,2" />
+    <key name="user" datatype="string" />
+    <key name="directory" datatype="existing-directory" default="/" />
+  </sectiontype>
+
   <section name="*" type="zdctl" attribute="zdctl" required="yes" />
+  <section name="*" type="zdrun" attribute="zdrun" required="yes" />
 
 </schema>


=== ZODB3/zdaemon/zdctl.py 1.17 => 1.18 ===
--- ZODB3/zdaemon/zdctl.py:1.17	Mon Jan 20 10:11:08 2003
+++ ZODB3/zdaemon/zdctl.py	Mon Jan 20 11:21:02 2003
@@ -14,17 +14,18 @@
 ##############################################################################
 """zdctl -- control an application run by zdaemon.
 
-Usage: python zdctl.py [-C URL] [-p PROGRAM] [action [arguments]]
+Usage: python zdctl.py [-C URL] [-h] [-p PROGRAM] [action [arguments]]
 
 Options:
 -C/--configuration URL -- configuration file or URL
+-h/--help -- print usage message and exit
 -p/--program PROGRAM -- the program to run
 action [arguments] -- see below
 
-If no action is specified on the command line, a "shell" interpreting
-actions typed interactively is started.
-
-Use the action "help" to find out about available actions.
+Actions are commands like "start", "stop" and "status".  If no action
+is specified on the command line, a "shell" interpreting actions typed
+interactively is started.  Use the action "help" to find out about
+available actions.
 """
 
 from __future__ import nested_scopes


=== ZODB3/zdaemon/zdoptions.py 1.6 => 1.7 ===
--- ZODB3/zdaemon/zdoptions.py:1.6	Fri Jan 17 15:18:38 2003
+++ ZODB3/zdaemon/zdoptions.py	Mon Jan 20 11:21:02 2003
@@ -273,6 +273,15 @@
         EventLogger.event_logger.logger = logger
 
 
+# ZConfig datatype
+
+def list_of_ints(arg):
+    if not arg:
+        return []
+    else:
+        return map(int, arg.split(","))
+
+
 def _test():
     # Stupid test program
     z = ZDOptions()


=== ZODB3/zdaemon/zdrun.py 1.2 => 1.3 ===
--- ZODB3/zdaemon/zdrun.py:1.2	Sun Jan 19 09:32:43 2003
+++ ZODB3/zdaemon/zdrun.py	Mon Jan 20 11:21:02 2003
@@ -18,16 +18,17 @@
 Or:    python zrdun.py -c [command]
 
 Options:
-  -b SECONDS -- set backoff limit to SECONDS (default 10; see below)
-  -c -- client mode, to sends a command to the daemon manager; see below
-  -d -- run as a proper daemon; fork a background process, close files etc.
-  -f -- run forever (by default, exit when the backoff limit is exceeded)
-  -h -- print usage message and exit
-  -s SOCKET -- Unix socket name for client communication (default "zdsock")
-  -u USER -- run as this user (or numeric uid)
-  -x LIST -- list of fatal exit codes (default "0,2"; use "" to disable)
-  -z DIRECTORY -- directory to chdir into when using -d; default "/"
-  program [program-arguments] -- an arbitrary application to run
+-C/--configuration URL -- configuration file or URL
+-b/--backoff-limit SECONDS -- set backoff limit to SECONDS (default 10)
+-c/--client -- client mode, to sends a command to the daemon manager
+-d/--daemon-- run as a proper daemon; fork a subprocess, close files etc.
+-f/--forever -- run forever (by default, exit when backoff limit is exceeded)
+-h/--help -- print this usage message and exit
+-s/--socket-name SOCKET -- Unix socket name for client (default "zdsock")
+-u/--user USER -- run as this user (or numeric uid)
+-x/--exit-codes LIST -- list of fatal exit codes (default "0,2")
+-z/--directory DIRECTORY -- directory to chdir to when using -d (default "/")
+program [program-arguments] -- an arbitrary application to run
 
 Client mode options:
   -s SOCKET -- socket name (a Unix pathname) for client communication
@@ -48,7 +49,7 @@
 application in the background, detached from the foreground tty
 session that started it (if any).
 
-Important: if at any point the application exits with an exit status
+Exit codes: if at any point the application exits with an exit status
 listed by the -x option, it is not restarted.  Any other form of
 termination (either being killed by a signal or exiting with an exit
 status not listed in the -x option) causes it to be restarted.
@@ -69,7 +70,7 @@
 """
 XXX TO DO
 
-- True OO design -- use multiple classes rather than folding
+- Finish OO design -- use multiple classes rather than folding
   everything into one class.
 
 - Add unit tests.
@@ -93,97 +94,30 @@
     from os.path import dirname, abspath, normpath
     sys.path.append(dirname(dirname(normpath(abspath(sys.argv[0])))))
 
+import ZConfig.datatypes
 import zLOG
+from zdaemon.zdoptions import ZDOptions, list_of_ints
 
-class Options:
+class ZDRunOptions(ZDOptions):
 
-    """A class to parse and hold the command line options.
+    positional_args_allowed = 1
 
-    Options are represented by various attributes (backofflimit etc.).
-    Positional arguments are represented by the args attribute.
+    def __init__(self):
+        ZDOptions.__init__(self)
+        self.add("backofflimit", "zdrun.backoff_limit",
+                 "b:", "backoff-limit=", int, default=10)
+        self.add("isclient", None, "c", "client", flag=1, default=0)
+        self.add("daemon", "zdrun.daemon", "d", "daemon", flag=1, default=0)
+        self.add("forever", "zdrun.forever", "f", "forever",
+                 flag=1, default=0)
+        self.add("sockname", "zdrun.socket_name", "s:", "socket-name=",
+                 ZConfig.datatypes.existing_dirpath, default="zdsock")
+        self.add("exitcodes", "zdrun.exit_codes", "x:", "exit-codes=",
+                 list_of_ints, default=[0, 2])
+        self.add("user", "zdrun.user", "u:", "user=")
+        self.add("zdirectory", "zdrun.directory", "z:", "directory=",
+                 ZConfig.datatypes.existing_directory, default="/")
 
-    This also has a public usage() method that can be used to report
-    errors related to the command line.
-    """
-
-    progname = "zrdun.py"             # Program name for usage message
-
-    # Options we know of, and their defaults
-    backofflimit = 10                   # -b SECONDS
-    isclient = 0                        # -c
-    daemon = 0                          # -d
-    forever = 0                         # -f
-    sockname = "zdsock"                 # -s SOCKET
-    exitcodes = [0, 2]                  # -x LIST
-    user = None                         # -u USER
-    zdirectory = "/"                    # -z DIRECTORY
-
-    args = []                           # Positional arguments
-
-    def __init__(self, args=None, progname=None):
-        """Constructor.
-
-        Optional arguments:
-
-        args     -- the command line arguments, less the program name
-                    (default is sys.argv[1:] at the time of call)
-
-        progname -- the program name (default "zrdun.py")
-        """
-
-        if args is None:
-            args = sys.argv[1:]
-        if progname:
-            self.progname = progname
-        try:
-            self.options, self.args = getopt.getopt(args, "b:cdfhs:u:x:z:")
-        except getopt.error, msg:
-            self.usage(str(msg))
-        self._interpret_options()
-
-    def _interpret_options(self):
-        """Internal: interpret the options parsed by getopt.getopt().
-
-        This sets the various instance variables overriding the defaults.
-
-        When -h is detected, print the module docstring to stdout and exit(0).
-        """
-        for o, a in self.options:
-            # Keep these in alphabetical order please!
-            if o == "-b":
-                try:
-                    self.backofflimit = float(a)
-                except:
-                    self.usage("invalid number: %r" % a)
-            if o == "-c":
-                self.isclient += 1
-            if o == "-d":
-                self.daemon += 1
-            if o == "-f":
-                self.forever += 1
-            if o == "-h":
-                print __doc__,
-                sys.exit(0)
-            if o == "-s":
-                self.sockname = os.path.abspath(a)
-            if o == "-u":
-                self.user = a
-            if o == "-x":
-                if a == "":
-                    self.exitcodes = []
-                else:
-                    try:
-                        self.exitcodes = map(int, a.split(","))
-                    except:
-                        self.usage("list of ints required: %r" % a)
-            if o == "-z":
-                self.zdirectory = a
-
-    def usage(self, msg):
-        """Write an error message to stderr and exit(2)."""
-        sys.stderr.write("Error: %s\n" % str(msg))
-        sys.stderr.write("For help, use %s -h\n" % self.progname)
-        sys.exit(2)
 
 class Subprocess:
 
@@ -196,7 +130,7 @@
     def __init__(self, options, args=None):
         """Constructor.
 
-        Arguments are an Options instance and a list of program
+        Arguments are a ZDRunOptions instance and a list of program
         arguments; the latter's first item must be the program name.
         """
         if args is None:
@@ -297,7 +231,7 @@
     def __init__(self, options, args=None):
         """Constructor.
 
-        Arguments are an Options instance and a list of program
+        Arguments are an ZDRunOptions instance and a list of program
         arguments representing the command to send to the server.
         """
         self.options = options
@@ -335,7 +269,8 @@
 class Daemonizer:
 
     def main(self, args=None):
-        self.options = Options(args)
+        self.options = ZDRunOptions()
+        self.options.realize(args)
         self.set_uid()
         if self.options.isclient:
             clt = Client(self.options)