Log message for revision 71643: Bugs Fixed ---------- - In non-daemon mode, start hung, producing annoying dots when the program exited. - The start command hung producing annoying dots if the deamon failed to start. - foreground and start had different semantics because one used os.system and another used os.spawn New Features ------------ - Documentation - Command-line arguments can now be supplied to the start and foreground (fg) commands - zdctl now invokes itself to run zdrun. This means that it's no-longer necessary to generate a separate zdrun script. This especially when the magic techniques to find and run zdrun using directory sniffing fail to set the path corrrectly. - The daemon mode is now enabled by default. To get non-deamon mode, you have to use a configuration file and set deamon to off there. The old -d option is kept for backward compatibility, but is a no-op.
Changed: U zdaemon/trunk/CHANGES.txt A zdaemon/trunk/src/zdaemon/README.txt U zdaemon/trunk/src/zdaemon/component.xml A zdaemon/trunk/src/zdaemon/tests/tests.py U zdaemon/trunk/src/zdaemon/zdctl.py U zdaemon/trunk/src/zdaemon/zdoptions.py -=- Modified: zdaemon/trunk/CHANGES.txt =================================================================== --- zdaemon/trunk/CHANGES.txt 2006-12-21 17:27:38 UTC (rev 71642) +++ zdaemon/trunk/CHANGES.txt 2006-12-21 23:46:14 UTC (rev 71643) @@ -1,19 +1,88 @@ zdaemon Changelog -================= +***************** +To-Dos +====== + +Tests: + +- non-daemon mode + +- no infinite loop when program fails on start + +More docs: + +- Document/demonstrate some important features, such as: + + - transcript log + + - working directory + +- Reference docs + + +Features + +- environment variables + +- transcript log rotation + +Bugs + +- help command + + +zdaemon 2.0a1 (2006/12/21) +========================== + +Bugs Fixed +---------- + +- In non-daemon mode, start hung, producing annoying dots + when the program exited. + +- The start command hung producing annoying dots if the deamon failed + to start. + +- foreground and start had different semantics because one used + os.system and another used os.spawn + +New Features +------------ + +- Documentation + +- Command-line arguments can now be supplied to the start and + foreground (fg) commands + +- zdctl now invokes itself to run zdrun. This means that it's + no-longer necessary to generate a separate zdrun script. This + especially when the magic techniques to find and run zdrun using + directory sniffing fail to set the path corrrectly. + +- The daemon mode is now enabled by default. To get non-deamon mode, + you have to use a configuration file and set deamon to off + there. The old -d option is kept for backward compatibility, but is + a no-op. + +zdaemon 1.4a1 (2005/11/21) +========================== + +Fixed a bug in the distribution setup file. + zdaemon 1.4a1 (2005/11/05) --------------------------- +========================== First semi-formal release. After some unknown release(???) -------------------------------- +=============================== - Made 'zdaemon.zdoptions' not fail for --help when __main__.__doc__ is None. After zdaemon 1.1 ------------------ +================= - Updated test 'testRunIgnoresParentSignals': @@ -40,7 +109,7 @@ forceful warning. zdaemon 1.1 (2005/06/09) ------------------------- +======================== - SVN tag: svn://svn.zope.org/repos/main/zdaemon/tags/zdaemon-1.1 Added: zdaemon/trunk/src/zdaemon/README.txt =================================================================== --- zdaemon/trunk/src/zdaemon/README.txt 2006-12-21 17:27:38 UTC (rev 71642) +++ zdaemon/trunk/src/zdaemon/README.txt 2006-12-21 23:46:14 UTC (rev 71643) @@ -0,0 +1,139 @@ +Using zdaemon +============= + +zdaemon provides a script, zdaemon, that can be used to running other +programs as POSIX (Unix) daemons. (Of course, it is only usable on +POSIX-complient systems. + +Using zdaemon requires specifying a number of options, which can be +given in a configuration file, or as command-line options. It also +accepts commands teling it what do do. The commants are: + +start + Start a process as a daemon + +stop + Stop a running daemon process + +restart + Stop and then restart a program + +status + Find out if the program is running + +foreground or fg + Run a program + +kill signal + Send a signal to the daemon process + +help command + Get help on a command + + +Commands can be given on a command line, or can be given using an +interactive interpreter. + +Let's start with a simple example. We'll use command-line options to +run the echo command: + + >>> system("./zdaemon -p 'echo hello world' fg") + echo hello world + hello world + +Here we used the -p option to specify a program to run. We can +specify a program name and command-line options in the program +command. Note, however, that the command-line parsing is pretty +primitive. Quotes and spaces aren't handled correctly. Let's look at +a slightly more complex example. We'll run the sleep command as a +daemon :) + + >>> system("./zdaemon -p 'sleep 100' start") + . daemon process started, pid=819 + +This ran the sleep deamon. We can check whether it ran with the +status command: + + >>> system("./zdaemon -p 'sleep 100' status") + program running; pid=819 + +We can stop it with the stop command: + + >>> system("./zdaemon -p 'sleep 100' stop") + daemon process stopped + + >>> system("./zdaemon -p 'sleep 100' status") + daemon manager not running + +Normally, we control zdaemon using a configuration file. Let's create +a typical configuration file: + + >>> open('conf', 'w').write( + ... ''' + ... <runner> + ... program sleep 100 + ... </runner> + ... ''') + +Now, we can run with the -C option to read the configuration file: + + >>> system("./zdaemon -Cconf start") + . daemon process started, pid=1136 + +If we list the directory: + + >>> system("ls") + conf + zdaemon + zdsock + +We'll see that a file, zdsock, was created. This is a unix-domain +socket used internally by ZDaemon. We'll normally want to control +where this goes. + + >>> system("./zdaemon -Cconf stop") + daemon process stopped + + >>> open('conf', 'w').write( + ... ''' + ... <runner> + ... program sleep 100 + ... socket-name /tmp/demo.zdsock + ... </runner> + ... ''') + + + >>> system("./zdaemon -Cconf start") + . daemon process started, pid=1139 + + >>> system("ls") + conf + zdaemon + + >>> import os + >>> os.path.exists("/tmp/demo.zdsock") + True + + >>> system("./zdaemon -Cconf stop") + daemon process stopped + +In the example, we included a command-line argument in the program +option. We can also provide options on the command line: + + >>> open('conf', 'w').write( + ... ''' + ... <runner> + ... program sleep + ... socket-name /tmp/demo.zdsock + ... </runner> + ... ''') + + >>> system("./zdaemon -Cconf start 100") + . daemon process started, pid=1149 + + >>> system("./zdaemon -Cconf status") + program running; pid=1149 + + >>> system("./zdaemon -Cconf stop") + daemon process stopped + Property changes on: zdaemon/trunk/src/zdaemon/README.txt ___________________________________________________________________ Name: svn:eol-style + native Modified: zdaemon/trunk/src/zdaemon/component.xml =================================================================== --- zdaemon/trunk/src/zdaemon/component.xml 2006-12-21 17:27:38 UTC (rev 71642) +++ zdaemon/trunk/src/zdaemon/component.xml 2006-12-21 23:46:14 UTC (rev 71643) @@ -93,7 +93,7 @@ <key name="daemon" datatype="boolean" required="no" - default="false"> + default="on"> <description> Command-line option: -d or --daemon. Added: zdaemon/trunk/src/zdaemon/tests/tests.py =================================================================== --- zdaemon/trunk/src/zdaemon/tests/tests.py 2006-12-21 17:27:38 UTC (rev 71642) +++ zdaemon/trunk/src/zdaemon/tests/tests.py 2006-12-21 23:46:14 UTC (rev 71643) @@ -0,0 +1,87 @@ +############################################################################## +# +# Copyright (c) 2004 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +"""XXX short summary goes here. + +$Id$ +""" + +import os, re, shutil, sys, tempfile, unittest +import ZConfig, zdaemon +from zope.testing import doctest, renormalizing + +try: + import pkg_resources +except ImportError: + zdaemon_loc = os.path.dirname(os.path.dirname(zdaemon.__file__)) + zconfig_loc = os.path.dirname(os.path.dirname(ZConfig.__file__)) +else: + zdaemon_loc = pkg_resources.working_set.find( + pkg_resources.Requirement.parse('zdaemon')).location + zconfig_loc = pkg_resources.working_set.find( + pkg_resources.Requirement.parse('ZConfig')).location + +def setUp(test): + test.globs['_td'] = td = [] + here = os.getcwd() + td.append(lambda : os.chdir(here)) + workspace = tempfile.mkdtemp() + td.append(lambda : shutil.rmtree(workspace)) + os.chdir(workspace) + open('zdaemon', 'w').write(zdaemon_template % dict( + python = sys.executable, + zdaemon = zdaemon_loc, + ZConfig = zconfig_loc, + )) + os.chmod('zdaemon', 0755) + test.globs.update(dict( + system = system + )) + +def tearDown(test): + for f in test.globs['_td']: + f() + +def system(command, input=''): + i, o = os.popen4(command) + if input: + i.write(input) + i.close() + print o.read(), + + +def test_suite(): + return unittest.TestSuite(( + doctest.DocFileSuite( + '../README.txt', + setUp=setUp, tearDown=tearDown, + checker=renormalizing.RENormalizing([ + (re.compile('pid=\d+'), 'pid=NNN'), + ]) + ), + )) + + +zdaemon_template = """#!%(python)s + +import sys +sys.path[0:0] = [ + %(zdaemon)r, + %(ZConfig)r, + ] + +import zdaemon.zdctl + +if __name__ == '__main__': + zdaemon.zdctl.main() +""" Property changes on: zdaemon/trunk/src/zdaemon/tests/tests.py ___________________________________________________________________ Name: svn:keywords + Id Name: svn:eol-style + native Modified: zdaemon/trunk/src/zdaemon/zdctl.py =================================================================== --- zdaemon/trunk/src/zdaemon/zdctl.py 2006-12-21 17:27:38 UTC (rev 71642) +++ zdaemon/trunk/src/zdaemon/zdctl.py 2006-12-21 23:46:14 UTC (rev 71643) @@ -76,7 +76,7 @@ class ZDCtlOptions(RunnerOptions): - positional_args_allowed = 1 + positional_args_allowed = True def __init__(self): RunnerOptions.__init__(self) @@ -111,16 +111,6 @@ if not self.python: self.python = sys.executable - # Where's zdrun? - if not self.zdrun: - if __name__ == "__main__": - file = sys.argv[0] - else: - file = __file__ - file = os.path.normpath(os.path.abspath(file)) - dir = os.path.dirname(file) - self.zdrun = os.path.join(dir, "zdrun.py") - def set_schemafile(self, file): self.schemafile = file @@ -138,9 +128,10 @@ if m: s = m.group(1) args = eval(s, {"__builtins__": {}}) - if args != self.options.program: + program = self.options.program + if args[:len(program)] != program: print "WARNING! zdrun is managing a different program!" - print "our program =", self.options.program + print "our program =", program print "daemon's args =", args def emptyline(self): @@ -175,22 +166,27 @@ self.zd_status = None resp = self.send_action("status") if not resp: - return + return resp m = re.search("(?m)^application=(\d+)$", resp) if not m: - return + return resp self.zd_up = 1 self.zd_pid = int(m.group(1)) self.zd_status = resp + return resp def awhile(self, cond, msg): + n = 0 try: self.get_status() while not cond(): sys.stdout.write(". ") sys.stdout.flush() time.sleep(1) - self.get_status() + n += 1 + if not self.get_status() and n > 10: + print "\nDaemon manager not running." + return except KeyboardInterrupt: print "^C" else: @@ -210,14 +206,14 @@ def do_start(self, arg): self.get_status() if not self.zd_up: - args = [ - self.options.python, - self.options.zdrun, - ] + if self.options.zdrun: + args = [self.options.python, self.options.zdrun] + else: + args = [self.options.python, sys.argv[0], '--zdrun'] + args += self._get_override("-S", "schemafile") args += self._get_override("-C", "configfile") args += self._get_override("-b", "backofflimit") - args += self._get_override("-d", "daemon", flag=1) args += self._get_override("-f", "forever", flag=1) args += self._get_override("-s", "sockname") args += self._get_override("-u", "user") @@ -228,6 +224,7 @@ "-x", "exitcodes", ",".join(map(str, self.options.exitcodes))) args += self._get_override("-z", "directory") args.extend(self.options.program) + args.extend(self.options.args[1:]) if self.options.daemon: flag = os.P_NOWAIT else: @@ -238,8 +235,9 @@ else: print "daemon process already running; pid=%d" % self.zd_pid return - self.awhile(lambda: self.zd_pid, - "daemon process started, pid=%(zd_pid)d") + if self.options.daemon: + self.awhile(lambda: self.zd_pid, + "daemon process started, pid=%(zd_pid)d") def _get_override(self, opt, name, svalue=None, flag=0): value = getattr(self.options, name) @@ -486,10 +484,12 @@ if pid: print "To run the program in the foreground, please stop it first." return - program = " ".join(self.options.program) - print program + + program = self.options.program + self.options.args[1:] + print " ".join(program) + sys.stdout.flush() try: - os.system(program) + os.spawnlp(os.P_WAIT, program[0], *program) except KeyboardInterrupt: print @@ -580,6 +580,12 @@ return os.fstat(self.f.fileno())[stat.ST_SIZE] def main(args=None, options=None, cmdclass=ZDCmd): + if args is None: + args = sys.argv[1:] + if args[0] == '--zdrun': + import zdaemon.zdrun + return zdaemon.zdrun.main(args[1:]) + if options is None: options = ZDCtlOptions() options.realize(args) Modified: zdaemon/trunk/src/zdaemon/zdoptions.py =================================================================== --- zdaemon/trunk/src/zdaemon/zdoptions.py 2006-12-21 17:27:38 UTC (rev 71642) +++ zdaemon/trunk/src/zdaemon/zdoptions.py 2006-12-21 23:46:14 UTC (rev 71643) @@ -347,7 +347,7 @@ ZDOptions.__init__(self) self.add("backofflimit", "runner.backoff_limit", "b:", "backoff-limit=", int, default=10) - self.add("daemon", "runner.daemon", "d", "daemon", flag=1, default=0) + self.add("daemon", "runner.daemon", "d", "daemon", flag=1, default=1) self.add("forever", "runner.forever", "f", "forever", flag=1, default=0) self.add("sockname", "runner.socket_name", "s:", "socket-name=", _______________________________________________ Zope-Checkins maillist - Zope-Checkins@zope.org http://mail.zope.org/mailman/listinfo/zope-checkins