diff -r 384167adad2b -r 20bd76353eb5 cobalt.py --- a/cobalt.py Wed Nov 05 01:38:08 2014 +0200 +++ b/cobalt.py Sun Nov 09 19:13:08 2014 +0200 @@ -33,17 +33,19 @@ import sys import traceback import re -import json import urllib import urllib2 import hgapi import os import suds import math +import json from datetime import datetime -import commandhandler as CommandHandler +import modulecore as ModuleCore +import configfile +from configfile import Config -CommandHandler.init_data() +ModuleCore.init_data() try: uid = os.geteuid() @@ -53,17 +55,9 @@ if uid == 0 and raw_input ('Do you seriously want to run cobalt as root? [y/N] ') != 'y': quit() -print 'Loading configuration...' -try: - with open ('cobalt.json', 'r') as fp: - g_config = json.loads (fp.read()) -except IOError as e: - print 'couldn\'t open cobalt.json: %s' % e - quit() - -g_admins = g_config['admins'] -g_mynick = g_config['nickname'] - +configfile.init() +g_admins = Config.get_value ('admins', default=[]) +g_mynick = Config.get_value ('nickname', default='cobalt') g_BotActive = False g_needCommitsTxtRebuild = True @@ -84,35 +78,28 @@ btannounce_active = False btannounce_timeout = 0 -def save_config(): - with open ('cobalt.json', 'w') as fp: - json.dump (g_config, fp, sort_keys = True, indent = 4) - -def cfg (key, default): - if not hasattr (g_config, key): - g_config[key] = default - save_config() - return default - return g_config[key] - def bt_updatechecktimeout(): global btannounce_timeout - btannounce_timeout = time.time() + (cfg ('btlatest_checkinterval', 5) * 60) + btannounce_timeout = time.time() + (Config.get_node ('bt').get_value ('checkinterval', default=5) * 60) + +def bt_credentials(): + bt = Config.get_node ('bt') + user = bt.get_value ('username', '') + password = bt.get_value ('password', '') + return [user, password] if suds_active: - try: - sys.stdout.write ('Retrieving latest tracker ticket... ') - btannounce_id = suds_client.service.mc_issue_get_biggest_id (g_config['trackeruser'], g_config['trackerpassword'], 0) - btannounce_active = True - bt_updatechecktimeout() - print btannounce_id - except Exception as e: - pass + sys.stdout.write ('Retrieving latest tracker ticket... ') + user, password = bt_credentials() + btannounce_id = suds_client.service.mc_issue_get_biggest_id (user, password, 0) + btannounce_active = True + bt_updatechecktimeout() + print btannounce_id def bt_getissue(ticket): global suds_client - global g_config - return suds_client.service.mc_issue_get (g_config['trackeruser'], g_config['trackerpassword'], ticket) + user, password = bt_credentials() + return suds_client.service.mc_issue_get (user, password, ticket) def bt_checklatest(): global btannounce_timeout @@ -122,7 +109,8 @@ bt_updatechecktimeout() newid = btannounce_id try: - newid = suds_client.service.mc_issue_get_biggest_id (g_config['trackeruser'], g_config['trackerpassword'], 0) + user, password = bt_credentials() + newid = suds_client.service.mc_issue_get_biggest_id (user, password, 0) except Exception as e: pass @@ -162,7 +150,7 @@ continue for channel in client.channels: - if channel['logchannel']: + if channel.get_value ('logchannel', default=False): client.write ("PRIVMSG %s :%s" % (channel['name'], line)) # @@ -275,7 +263,7 @@ check_repo_exists ('zandronum-sandbox-stable', 'crimsondusk') check_repo_exists ('zandronum-everything', '') -repocheck_timeout = {'zandronum':(time.time()) + 15, 'zandronum-stable':(time.time() + 15), 'zandronum-sandbox':(time.time()) + 15, 'zandronum-sandbox-stable':(time.time()) + 15} +repocheck_timeout = {(time.time()) + 15} def get_commit_data (zanrepo, rev, template): return zanrepo.hg_command ('log', '-l', '1', '-r', rev, '--template', template) @@ -318,7 +306,7 @@ #enddef def find_developer_by_email (commit_email): - for developer, emails in g_config['developer_emails'].iteritems(): + for developer, emails in Config.get_value ('developer_emails', default={}).iteritems(): for email in emails: if commit_email == email: return developer @@ -334,19 +322,24 @@ def process_zan_repo_updates (repo_name): global repocheck_timeout global suds_client - global g_config global g_clients + + hgns = Config.get_node ('hg') + + if not hgns.get_value ('track', default=True): + return usestable = repo_name == 'zandronum-stable' usesandbox = repo_name == 'zandronum-sandbox' or repo_name == 'zandronum-sandbox-stable' repo_owner = 'Torr_Samaho' if not usesandbox else 'crimsondusk' repo_url = 'https://bitbucket.org/%s/%s' % (repo_owner, repo_name) num_commits = 0 + btuser, btpassword = bt_credentials() - if time.time() < repocheck_timeout[repo_name]: + if time.time() < repocheck_timeout: return - repocheck_timeout[repo_name] = time.time() + (cfg ('hg_checkinterval', 15) * 60) + repocheck_timeout = time.time() + hgns.get_value ('checkinterval', default=15) * 60 zanrepo = hgapi.Repo (repo_name) commit_data = [] delimeter = '@@@@@@@@@@' @@ -484,8 +477,7 @@ commit_email = "" try: - ticket_data = suds_client.service.mc_issue_get (g_config['trackeruser'], - g_config['trackerpassword'], ticket_id) + ticket_data = suds_client.service.mc_issue_get (btuser, btpassword, ticket_id) except Exception as e: chanlog ('error while processing %s: %s' % (commit_node, `e`)) continue @@ -552,12 +544,12 @@ # Announce on IRC for irc_client in g_clients: - for channel in irc_client.cfg['channels']: - if 'btannounce' in channel and channel['btannounce'] == True: - irc_client.privmsg (channel['name'], + for channel in irc_client.channels: + if channel.get_value ('btannounce', default=True): + irc_client.privmsg (channel.get_value ('name'), "%s: commit %s fixes issue %d: %s" % (repo_name, commit_node, ticket_id, commit_message)) - irc_client.privmsg (channel['name'], + irc_client.privmsg (channel.get_value ('name'), "Read all about it here: " + irc_client.get_ticket_url (ticket_id)) #fi #done @@ -567,10 +559,10 @@ # We need to remove the note data, otherwise the ticket notes # will get unnecessary updates. WTF, MantisBT? ticket_data.notes = [] - suds_client.service.mc_issue_update (g_config['trackeruser'], g_config['trackerpassword'], ticket_id, ticket_data) + suds_client.service.mc_issue_update (btuser, btpassword, ticket_id, ticket_data) #fi - suds_client.service.mc_issue_note_add (g_config['trackeruser'], g_config['trackerpassword'], ticket_id, { 'text': message }) + suds_client.service.mc_issue_note_add (btuser, btpassword, ticket_id, { 'text': message }) num_commits += 1 except Exception as e: chanlog ('Error while processing %s: %s' % (commit_node, `e`)) @@ -589,44 +581,33 @@ # class irc_client (asyncore.dispatcher): def __init__ (self, cfg, flags): - self.name = cfg['name'] - self.host = cfg['address'] - self.port = cfg['port'] - self.password = cfg['password'] if 'password' in cfg else '' - self.channels = cfg['channels'] + self.name = cfg.get_value ('name') + self.host = cfg.get_value ('address') + self.port = cfg.get_value ('port', default=6667) + self.password = cfg.get_value ('password', default='') + self.channels = cfg.get_nodelist ('channels') self.flags = flags - self.send_buffer = list() - self.umode = cfg['umode'] if 'umode' in cfg else '' + self.send_buffer = [] + self.umode = cfg.get_value ('umode', default='') self.cfg = cfg - self.mynick = '' - self.verbose = g_config['verbose'] if 'verbose' in g_config else False - self.commandprefix = g_config['commandprefix'][0] if 'commandprefix' in g_config else '.' + self.desired_name = Config.get_value ('nickname', default='cobalt') + self.mynick = self.desired_name + self.verbose = Config.get_value ('verbose', default=False) + self.commandprefix = Config.get_value ('commandprefix', default='.') - for channel in self.channels: - if not 'logchannel' in channel: - channel['logchannel'] = False - channel['namesdone'] = True - #channel['haslinkbot'] = False - - if not 'conflictsuffix' in self.cfg: - self.cfg['conflictsuffix'] = '`' - - self.desired_name = self.cfg['nickname'] if 'nickname' in self.cfg else g_config['nickname'] g_clients.append (self) asyncore.dispatcher.__init__ (self) self.create_socket (socket.AF_INET, socket.SOCK_STREAM) self.connect ((self.host, self.port)) def register_to_irc (self): - ident = self.cfg['ident'] if 'ident' in self.cfg else g_config['ident'] - gecos = self.cfg['gecos'] if 'gecos' in self.cfg else g_config['gecos'] - if 'password' in self.cfg: - self.write ("PASS %s" % self.cfg['password']) + ident = Config.get_value ('ident', default='cobalt') + gecos = Config.get_value ('gecos', default='cobalt') + self.write ("PASS %s" % self.password) self.write ("USER %s * * :%s" % (ident, gecos)) self.write ("NICK %s" % self.mynick) def handle_connect (self): - self.mynick = self.desired_name print "Connected to [%s] %s:%d" % (self.name, self.host, self.port) self.register_to_irc() @@ -675,19 +656,15 @@ if words[1] == "001": self.flags |= CLIF_CONNECTED - for channel in self.cfg['channels']: - self.write ("JOIN %s %s" % (channel['name'], channel['password'] if 'password' in channel else '')) + for channel in self.channels: + self.write ("JOIN %s %s" % (channel.get_value ('name'), channel.get_value ('password', default=''))) - if 'umode' in self.cfg: - self.write ('MODE %s %s' % (self.mynick, self.cfg['umode'])) + umode = self.cfg.get_value ('umode', '') + + if umode != '': + self.write ('MODE %s %s' % (self.mynick, self.cfg.get_value ('umode', ''))) elif words[1] == "PRIVMSG": self.handle_privmsg (line) - elif words[1] == 'JOIN': - rex = re.compile (r'^:([^!]+)!([^@]+)@([^ ]+) JOIN :#(.+)') - match = rex.match (line) - - #if match and match.group(1).toLower() == 'linkbot': - #channel_by_name (match.group(4))['haslinkbot'] = True elif words[1] == 'QUIT': rex = re.compile (r'^:([^!]+)!([^@]+)@([^ ]+) QUIT') match = rex.match (line) @@ -696,14 +673,10 @@ if match and match.group(1) == self.desired_name: self.mynick = self.desired_name self.write ("NICK %s" % self.mynick) - - #if match and match.group(1).toLower() == 'linkbot': - #for channel in self.channels: - #channels['haslinkbot'] = False elif words[1] == "433": #:irc.localhost 433 * cobalt :Nickname is already in use. - self.mynick = '%s%s' % (self.mynick, self.cfg['conflictsuffix']) - self.write ("NICK %s" % self.mynick) + self.mynick += self.cfg.get_value ('conflictsuffix', default='`') + self.write ("NICK " + self.mynick) # Check for new issues on the bugtracker bt_checklatest() @@ -714,7 +687,7 @@ def channel_by_name (self, name): for channel in self.channels: - if channel['name'].upper() == args[0].upper(): + if channel.get_value ('name').upper() == args[0].upper(): return channel else: raise logical_exception ('unknown channel ' + args[0]) @@ -735,7 +708,8 @@ replyto = channel if channel != g_mynick else sender # Check for tracker url in the message - http_regex = re.compile (r'.*http(s?)://%s/view\.php\?id=([0-9]+).*' % g_config['trackerurl']) + url = Config.get_node ('bt').get_value ('url') + http_regex = re.compile (r'.*http(s?)://%s/view\.php\?id=([0-9]+).*' % url) http_match = http_regex.match (line) # Check for command. @@ -759,7 +733,8 @@ # Get the URL for a specified ticket # def get_ticket_url (self, ticket): - return 'https://%s/view.php?id=%s' % (g_config['trackerurl'], ticket) + url = Config.get_node ('bt').get_value ('url') + return 'https://%s/view.php?id=%s' % (url, ticket) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # @@ -780,7 +755,7 @@ allowprivate = False for channel in self.channels: - if channel['name'] == replyto and 'btprivate' in channel and channel['btprivate'] == True: + if channel.get_value ('name') == replyto and channel.get_value ('btprivate', False): allowprivate = True break #fi @@ -806,9 +781,6 @@ #fi #enddef - def save_config (self): - save_config() - def is_admin (self, ident, host): return ("%s@%s" % (ident, host)) in g_admins @@ -820,13 +792,11 @@ kvargs = {'sender': sender, 'ident': ident, 'host': host, 'replyto': replyto, 'cmdname': command, 'message': message} try: - result = CommandHandler.call_command (self, **kvargs) + result = ModuleCore.call_command (self, **kvargs) if result: return - else: - print 'CommandHandler.call_command returned false' - except CommandHandler.CommandError as e: + except ModuleCore.CommandError as e: lines = str (e).split ('\n') self.privmsg (replyto, 'error: %s' % lines[0]) @@ -1030,9 +1000,9 @@ isprivate = data['view_state']['name'] == 'private' reporter = data['reporter']['name'] if hasattr (data['reporter'], 'name') else '' - for channel in self.cfg['channels']: - if 'btannounce' in channel and channel['btannounce'] == True: - if not isprivate or ('btprivate' in channel and channel['btprivate'] == True): + for channel in self.channels: + if channel.get_value ('btannounce', False): + if not isprivate or (channel.get_value ('btprivate', False)): self.write ("PRIVMSG %s :[%s] New issue %s, reported by %s: %s: %s" % \ (channel['name'], data['project']['name'], idstring, reporter, data['summary'], self.get_ticket_url (idstring))) @@ -1068,14 +1038,20 @@ # Main procedure: # try: - for aconn in g_config['autoconnect']: - for conndata in g_config['connections']: - if conndata['name'] == aconn: + autoconnects = Config.get_value ('autoconnect', []) + + if len (autoconnects) == 0: + print "Nowhere to connect." + quit() + + for aconn in autoconnects: + for conndata in Config.get_nodelist ('connections'): + if conndata.get_value ('name') == aconn: irc_client (conndata, 0) break else: - raise logical_exception ("unknown autoconnect entry %s" % (aconn)) - + raise ValueError ("unknown autoconnect entry %s" % (aconn)) + g_BotActive = True asyncore.loop() except KeyboardInterrupt: