Hi. I have just recently been given zope.org SVN write access and made my first bigger change - making zopectl work on Windows. Please review and test my changes. The change I made is based on code that I had in the plone.recipe.zope2instance buildout recipe and has seen quite some use by various developers, so should be reasonable stable.
Hanno Hanno Schlichting wrote: > Log message for revision 75066: > Support for using zopectl on Windows has been added. All commands are > supported and there are two Windows specific ones: install and remove, which > install or remove the Windows service. The start, stop and restart commands > handle the Windows service. > > > Changed: > U Zope/trunk/doc/CHANGES.txt > U Zope/trunk/lib/python/Zope2/Startup/zopectl.py > A Zope/trunk/skel/bin/zopectl.bat.in > > -=- > Modified: Zope/trunk/doc/CHANGES.txt > =================================================================== > --- Zope/trunk/doc/CHANGES.txt 2007-05-03 18:27:55 UTC (rev 75065) > +++ Zope/trunk/doc/CHANGES.txt 2007-05-03 18:35:20 UTC (rev 75066) > @@ -51,6 +51,12 @@ > > Features added > > + - Support for using zopectl on Windows has been added. All commands are > + supported and there are two Windows specific ones: install and > remove, > + which install or remove the Windows service. The start, stop and > + restart commands handle the Windows service. In order to use them, > you > + need to call 'bin\zopectl install' once. > + > - ZCatalog result objects (catalog brains) now have an interface, > ZCatalog.interfaces.ICatalogBrain. > > > Modified: Zope/trunk/lib/python/Zope2/Startup/zopectl.py > =================================================================== > --- Zope/trunk/lib/python/Zope2/Startup/zopectl.py 2007-05-03 18:27:55 UTC > (rev 75065) > +++ Zope/trunk/lib/python/Zope2/Startup/zopectl.py 2007-05-03 18:35:20 UTC > (rev 75066) > @@ -48,6 +48,9 @@ > from ZConfig.components.logger.handlers import FileHandlerFactory > from ZConfig.datatypes import existing_dirpath > > +WIN = False > +if sys.platform[:3].lower() == "win": > + WIN = True > > def string_list(arg): > return arg.split() > @@ -127,6 +130,12 @@ > self.python = sys.executable > self.zdrun = os.path.join(os.path.dirname(zdaemon.__file__), > "zdrun.py") > + if WIN: > + # Add the path to the zopeservice.py script, which is needed for > + # some of the Windows specific commands > + servicescript = os.path.join(self.directory, 'bin', > 'zopeservice.py') > + self.servicescript = '"%s" %s' % (self.python, servicescript) > + > self.exitcodes = [0, 2] > if self.logfile is None and config.eventlog is not None: > for handler in config.eventlog.handler_factories: > @@ -158,11 +167,59 @@ > args = [opt, svalue] > return args > > + if WIN: > + def get_status(self): > + # get_status from zdaemon relies on *nix specific socket > handling. > + # We just don't support getting the status and sending actions to > + # the control server on Windows. This could be extended to ask > for > + # the status of the Windows service though > + self.zd_up = 0 > + self.zd_pid = 0 > + self.zd_status = None > + return > + > + def do_stop(self, arg): > + # Stop the Windows service > + program = "%s stop" % self.options.servicescript > + print program > + os.system(program) > + > + def do_restart(self, arg): > + # Restart the Windows service > + program = "%s restart" % self.options.servicescript > + print program > + os.system(program) > + > + # Add extra commands to install and remove the Windows service > + > + def do_install(self, arg): > + program = "%s install" % self.options.servicescript > + print program > + os.system(program) > + > + def help_install(self): > + print "install -- Installs Zope as a Windows service." > + > + def do_remove(self, arg): > + program = "%s remove" % self.options.servicescript > + print program > + os.system(program) > + > + def help_remove(self): > + print "remove -- Removes the Zope Windows service." > + > def do_start(self, arg): > # signal to Zope that it is being managed > - #(to indicate it's web-restartable) > + # (to indicate it's web-restartable) > os.putenv('ZMANAGED', '1') > - ZDCmd.do_start(self, arg) > + if WIN: > + # On Windows start the service, this fails with a reasonable > + # error message as long as the service is not installed > + program = "%s start" % self.options.servicescript > + print program > + os.system(program) > + else: > + ZDCmd.do_start(self, arg) > > def get_startup_cmd(self, python, more): > cmdline = ( '%s -c "from Zope2 import configure;' > @@ -179,12 +236,17 @@ > os.system(cmdline) > > def do_foreground(self, arg): > - self.options.program[1:1] = ["-X", "debug-mode=on"] > - try: > + if WIN: > + # Adding arguments to the program is not supported on Windows > + # and the runzope script doesn't put you in debug-mode either > ZDCmd.do_foreground(self, arg) > - finally: > - self.options.program.remove("-X") > - self.options.program.remove("debug-mode=on") > + else: > + self.options.program[1:1] = ["-X", "debug-mode=on"] > + try: > + ZDCmd.do_foreground(self, arg) > + finally: > + self.options.program.remove("-X") > + self.options.program.remove("debug-mode=on") > > def help_debug(self): > print "debug -- run the Zope debugger to inspect your database" > @@ -262,19 +324,23 @@ > args.insert(0, self.options.python) > > print 'Running tests via: %s' % ' '.join(args) > - pid = os.fork() > - if pid == 0: # child > - os.execv(self.options.python, args) > - > - # Parent process running (execv replaces process in child > - while True: > - try: > - os.waitpid(pid, 0) > - except (OSError, KeyboardInterrupt): > - continue > - else: > - break > + if WIN: > + # Windows process handling is quite different > + os.system(' '.join(args)) > + else: > + pid = os.fork() > + if pid == 0: # child > + os.execv(self.options.python, args) > > + # Parent process running (execv replaces process in child > + while True: > + try: > + os.waitpid(pid, 0) > + except (OSError, KeyboardInterrupt): > + continue > + else: > + break > + > def help_test(self): > print "test [args]+ -- run unit / functional tests." > print " See $ZOPE_HOME/bin/test.py --help for syntax." > @@ -317,7 +383,8 @@ > # If it is not reset, 'os.wait[pid]' can non-deterministically fail. > # Thus, use a way such that "SIGCHLD" is definitely reset in children. > #signal.signal(signal.SIGCHLD, signal.SIG_IGN) > - if os.uname()[0] != 'Darwin': > + if not WIN and os.uname()[0] != 'Darwin': > + # On Windows the os.uname method does not exist. > # On Mac OS X, setting up a signal handler causes waitpid to > # raise EINTR, which is not preventable via the Python signal > # handler API and can't be dealt with properly as we can't pass > > Copied: Zope/trunk/skel/bin/zopectl.bat.in (from rev 75039, > Zope/trunk/skel/bin/runzope.bat.in) > =================================================================== > --- Zope/trunk/skel/bin/runzope.bat.in 2007-05-03 07:18:30 UTC (rev > 75039) > +++ Zope/trunk/skel/bin/zopectl.bat.in 2007-05-03 18:35:20 UTC (rev > 75066) > @@ -0,0 +1,8 @@ > [EMAIL PROTECTED] ZOPE_HOME=<<ZOPE_HOME>> > [EMAIL PROTECTED] INSTANCE_HOME=<<INSTANCE_HOME>> > [EMAIL PROTECTED] PYTHON=%ZOPE_HOME%\bin\python.exe > [EMAIL PROTECTED] SOFTWARE_HOME=%ZOPE_HOME%\lib\python > [EMAIL PROTECTED] CONFIG_FILE=%INSTANCE_HOME%\etc\zope.conf > [EMAIL PROTECTED] PYTHONPATH=%SOFTWARE_HOME% > [EMAIL PROTECTED] ZDCTL=%SOFTWARE_HOME%\Zope2\Startup\zopectl.py > +"%PYTHON%" "%ZDCTL%" -C "%CONFIG_FILE%" %1 %2 %3 %4 %5 %6 %7 _______________________________________________ Zope-Dev maillist - Zope-Dev@zope.org http://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - http://mail.zope.org/mailman/listinfo/zope-announce http://mail.zope.org/mailman/listinfo/zope )