# HG changeset patch # User cmlenz # Date 1119007402 0 # Node ID 9db5f8eddb0df2f8a1dc4a141e6c79599d270c60 # Parent 591a5a836eccaef0485d33d876a2f3f5baddd4ed Proper {{{optparse}}}-based command-line interface for master and slave. diff --git a/bitten/__init__.py b/bitten/__init__.py --- a/bitten/__init__.py +++ b/bitten/__init__.py @@ -18,5 +18,7 @@ # # Author: Christopher Lenz +__version__ = '0.1' + class BuildError(Exception): pass diff --git a/bitten/master.py b/bitten/master.py --- a/bitten/master.py +++ b/bitten/master.py @@ -18,14 +18,13 @@ # # Author: Christopher Lenz -import getopt import logging import os.path -import sys import time from trac.env import Environment +from bitten import __version__ as VERSION from bitten.util import beep from bitten.util.xmlio import Element, parse_xml @@ -36,7 +35,7 @@ def __init__(self, env_path, ip, port): beep.Listener.__init__(self, ip, port) - self.profiles[BittenProfileHandler.URI] = BittenProfileHandler() + self.profiles[OrchestrationProfileHandler.URI] = OrchestrationProfileHandler() self.env = Environment(env_path) self.youngest_rev = None @@ -56,8 +55,11 @@ self.schedule(self.TRIGGER_INTERVAL, self.check_trigger) -class BittenProfileHandler(beep.ProfileHandler): - URI = 'http://bitten.cmlenz.net/beep-profile/' +class OrchestrationProfileHandler(beep.ProfileHandler): + """Handler for communication on the Bitten build orchestration profile from + the perspective of the build master. + """ + URI = 'http://bitten.cmlenz.net/beep/orchestration' def handle_connect(self): self.master = self.session.listener @@ -86,37 +88,43 @@ if __name__ == '__main__': - options, args = getopt.getopt(sys.argv[1:], 'p:dvq', - ['port=', 'debug', 'verbose', 'quiet']) + from optparse import OptionParser + + parser = OptionParser(usage='usage: %prog [options] env-path', + version='%%prog %s' % VERSION) + parser.add_option('-p', '--port', action='store', type='int', dest='port', + help='port number to use') + parser.add_option('-H', '--host', action='store', dest='host', + help='the host name of IP address to bind to') + parser.add_option('--debug', action='store_const', dest='loglevel', + const=logging.DEBUG, help='enable debugging output') + parser.add_option('-v', '--verbose', action='store_const', dest='loglevel', + const=logging.INFO, help='print as much as possible') + parser.add_option('-q', '--quiet', action='store_const', dest='loglevel', + const=logging.ERROR, help='print as little as possible') + parser.set_defaults(port=7633, loglevel=logging.WARNING) + options, args = parser.parse_args() + if len(args) < 1: - print>>sys.stderr, 'usage: %s [options] ENV_PATH' \ - % os.path.basename(sys.argv[0]) - print>>sys.stderr - print>>sys.stderr, 'Valid options:' - print>>sys.stderr, ' -p [--port] arg\tport number to use (default: 7633)' - print>>sys.stderr, ' -q [--quiet]\tprint as little as possible' - print>>sys.stderr, ' -v [--verbose]\tprint as much as possible' - sys.exit(2) + parser.error('incorrect number of arguments') env_path = args[0] - port = 7633 - loglevel = logging.WARNING - for opt, arg in options: - if opt in ('-p', '--port'): - try: - port = int(arg) - except ValueError: - print>>sys.stderr, 'Port must be an integer' - sys.exit(2) - elif opt in ('-d', '--debug'): - loglevel = logging.DEBUG - elif opt in ('-v', '--verbose'): - loglevel = logging.INFO - elif opt in ('-q', '--quiet'): - loglevel = logging.ERROR - logging.getLogger().setLevel(loglevel) + logging.getLogger().setLevel(options.loglevel) + port = options.port + if not (1 <= port <= 65535): + parser.error('port must be an integer in the range 1-65535') - master = Master(env_path, 'localhost', port) + host = options.host + if not host: + import socket + ip = socket.gethostbyname(socket.gethostname()) + try: + host = socket.gethostbyaddr(ip)[0] + except socket.error, e: + logging.warning('Reverse host name lookup failed (%s)', e) + host = ip + + master = Master(env_path, host, port) try: master.run() except KeyboardInterrupt: diff --git a/bitten/slave.py b/bitten/slave.py --- a/bitten/slave.py +++ b/bitten/slave.py @@ -18,12 +18,12 @@ # # Author: Christopher Lenz -import getopt import logging import os import sys import time +from bitten import __version__ as VERSION from bitten.util import beep from bitten.util.xmlio import Element, parse_xml @@ -34,21 +34,22 @@ terminated = False def channel_started(self, channelno, profile_uri): - if profile_uri == BittenProfileHandler.URI: + if profile_uri == OrchestrationProfileHandler.URI: self.channelno = channelno def greeting_received(self, profiles): - if BittenProfileHandler.URI not in profiles: + if OrchestrationProfileHandler.URI not in profiles: logging.error('Peer does not support Bitten profile') raise beep.TerminateSession, 'Peer does not support Bitten profile' - self.channels[0].profile.send_start([BittenProfileHandler], + self.channels[0].profile.send_start([OrchestrationProfileHandler], handle_ok=self.channel_started) -class BittenProfileHandler(beep.ProfileHandler): - """Handles communication on the Bitten profile from the client perspective. +class OrchestrationProfileHandler(beep.ProfileHandler): + """Handler for communication on the Bitten build orchestration profile from + the perspective of the build slave. """ - URI = 'http://bitten.cmlenz.net/beep-profile/' + URI = 'http://bitten.cmlenz.net/beep/orchestration' def handle_connect(self): """Register with the build master.""" @@ -71,45 +72,37 @@ handle_reply) def handle_msg(self, msgno, msg): - # TODO: Handle build initiation requests + # TODO: Handle build initiation requests etc pass if __name__ == '__main__': - options, args = getopt.getopt(sys.argv[1:], 'dvq', - ['debug', 'verbose', 'quiet']) + from optparse import OptionParser + + parser = OptionParser(usage='usage: %prog [options] host [port]', + version='%%prog %s' % VERSION) + parser.add_option('--debug', action='store_const', dest='loglevel', + const=logging.DEBUG, help='enable debugging output') + parser.add_option('-v', '--verbose', action='store_const', dest='loglevel', + const=logging.INFO, help='print as much as possible') + parser.add_option('-q', '--quiet', action='store_const', dest='loglevel', + const=logging.ERROR, help='print as little as possible') + parser.set_defaults(loglevel=logging.WARNING) + options, args = parser.parse_args() + if len(args) < 1: - print>>sys.stderr, 'Usage: %s [options] host [port]' % sys.argv[0] - print>>sys.stderr - print>>sys.stderr, 'Valid options:' - print>>sys.stderr, ' -d [--debug]\tenable debugging output' - print>>sys.stderr, ' -q [--quiet]\tprint as little as possible' - print>>sys.stderr, ' -v [--verbose]\tprint as much as possible' - sys.exit(2) - + parser.error('incorrect number of arguments') host = args[0] if len(args) > 1: try: port = int(args[1]) - except ValueError: - print>>sys.stderr, 'Port must be an integer' - sys.exit(2) + assert (1 <= port <= 65535), 'port number out of range' + except AssertionError, ValueError: + parser.error('port must be an integer in the range 1-65535') else: port = 7633 - loglevel = logging.WARNING - for opt, arg in options: - if opt in ('-d', '--debug'): - loglevel = logging.DEBUG - elif opt in ('-v', '--verbose'): - loglevel = logging.INFO - elif opt in ('-q', '--quiet'): - loglevel = logging.ERROR - logger = logging.getLogger() - logger.setLevel(loglevel) + logging.getLogger().setLevel(options.loglevel) slave = Slave(host, port) - try: - slave.run() - except beep.TerminateSession, e: - print>>sys.stderr, 'Session terminated:', e + slave.run() diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -21,9 +21,10 @@ from distutils.core import setup +from bitten import __version__ as VERSION from bitten.setuptools.testrunner import unittest -setup(name='bitten', version='1.0', - packages=['bitten', 'bitten.distutils', 'bitten.recipe', 'bitten.util'], +setup(name='bitten', version=VERSION, + packages=['bitten', 'bitten.recipe', 'bitten.setuptools', 'bitten.util'], author="Christopher Lenz", author_email="cmlenz@gmx.de", url="http://bitten.cmlenz.net/", cmdclass={'unittest': unittest})