As is checkin of fn-fmsread, fn-fmsnotify. Needs cleanup.
diff --git a/infocalypse/__init__.py b/infocalypse/__init__.py --- a/infocalypse/__init__.py +++ b/infocalypse/__init__.py @@ -155,7 +155,7 @@ from mercurial import commands, util from infcmds import get_config_info, execute_create, execute_pull, \ execute_push, execute_setup, execute_copy, execute_reinsert, \ - execute_info + execute_info, execute_fmsread, execute_fmsnotify def set_target_version(ui_, repo, opts, params, msg_fmt): """ INTERNAL: Update TARGET_VERSION in params. """ @@ -301,6 +301,47 @@ def infocalypse_info(ui_, repo, **opts): params['REQUEST_URI'] = request_uri execute_info(ui_, repo, params, stored_cfg) +def infocalypse_fmsread(ui_, repo, **opts): + """ Read repository update information from fms. + """ + # FCP not required. Hmmm... Hack + opts['fcphost'] = '' + opts['fcpport'] = 0 + params, stored_cfg = get_config_info(ui_, opts) + request_uri = opts['uri'] + if request_uri == '': + request_uri = stored_cfg.get_request_uri(repo.root) + if not request_uri: + ui_.status("There is no stored request URI for this repo.\n") + request_uri = None + + if opts['listall']: + params['FMSREAD'] = 'listall' + elif opts['list']: + params['FMSREAD'] = 'list' + else: + params['FMSREAD'] = 'update' + params['DRYRUN'] = opts['dryrun'] + params['REQUEST_URI'] = request_uri + execute_fmsread(ui_, repo, params, stored_cfg) + +def infocalypse_fmsnotify(ui_, repo, **opts): + """ Post an update with the current repository USK + index to fms. + """ + params, stored_cfg = get_config_info(ui_, opts) + insert_uri = stored_cfg.get_dir_insert_uri(repo.root) + if not insert_uri: + ui_.warn("You can't notify because there's no stored " + + "insert URI for this repo.\n" + + "Run from the directory you inserted from.\n") + return + + params['ANNOUNCE'] = opts['announce'] + params['DRYRUN'] = opts['dryrun'] + params['INSERT_URI'] = insert_uri + execute_fmsnotify(ui_, repo, params, stored_cfg) + def infocalypse_setup(ui_, **opts): """ Setup the extension for use for the first time. """ @@ -359,7 +400,21 @@ cmdtable = { "fn-info": (infocalypse_info, [('', 'uri', '', 'request URI'),], "[options]"), - + + + "fn-fmsread": (infocalypse_fmsread, + [('', 'uri', '', 'request URI'), + ('', 'list', None, 'show repo USKs from trusted fms identities'), + ('', 'listall', None, 'show all repo USKs'), + ('', 'dryrun', None, "don't update the index cache"),], + "[options]"), + + "fn-fmsnotify": (infocalypse_fmsnotify, + [('', 'dryrun', None, "don't send fms message"), + ('', 'announce', None, "include full URI update"), ] + + FCP_OPTS, # Needs to invert the insert uri + "[options]"), + "fn-setup": (infocalypse_setup, [('', 'tmpdir', '~/infocalypse_tmp', 'temp directory'),] + FCP_OPTS, diff --git a/infocalypse/config.py b/infocalypse/config.py --- a/infocalypse/config.py +++ b/infocalypse/config.py @@ -26,6 +26,7 @@ import sys from fcpclient import get_usk_hash, is_usk_file, get_version, \ get_usk_for_usk_version +from knownrepos import DEFAULT_TRUST, DEFAULT_GROUPS from mercurial import util from ConfigParser import ConfigParser @@ -62,6 +63,10 @@ class Config: self.request_usks = {} # repo_id -> insert uri map self.insert_usks = {} + # fms_id -> (usk_hash, ...) map + self.fmsread_trust_map = {} + self.fmsread_groups = () + self.file_name = None # Use a dict instead of members to avoid pylint R0902. @@ -71,6 +76,11 @@ class Config: self.defaults['TMP_DIR'] = None self.defaults['DEFAULT_PRIVATE_KEY'] = None + self.defaults['FMS_HOST'] = '127.0.0.1' + self.defaults['FMS_PORT'] = 1119 + self.defaults['FMS_ID'] = None # REDFLAG? + self.defaults['FMSNOTIFY_GROUP'] = None # REDFLAG? + def get_index(self, usk_or_id): """ Returns the highest known USK version for a USK or None. """ return self.version_table.get(normalize(usk_or_id)) @@ -150,6 +160,23 @@ class Config: if parser.has_section('insert_usks'): for repo_id in parser.options('insert_usks'): cfg.insert_usks[repo_id] = parser.get('insert_usks', repo_id) + + # ignored = fms_id|usk_hash|usk_hash|... + if parser.has_section('fmsread_trust_map'): + for ordinal in parser.options('fmsread_trust_map'): + fields = parser.get('fmsread_trust_map', + ordinal).strip().split('|') + # REDFLAG: better validation for fms_id, hashes? + if fields[0].find('@') == -1: + raise ValueError("%s doesn't look like an fms id." % + fields[0]) + if len(fields) < 2: + raise ValueError("No USK hashes for fms id: %s?" % + fields[0]) + cfg.fmsread_trust_map[fields[0]] = tuple(fields[1:]) + else: + cfg.fmsread_trust_map = DEFAULT_TRUST + if parser.has_section('default'): if parser.has_option('default','host'): cfg.defaults['HOST'] = parser.get('default','host') @@ -161,6 +188,21 @@ class Config: cfg.defaults['DEFAULT_PRIVATE_KEY'] = ( parser.get('default','default_private_key')) + if parser.has_option('default','fms_host'): + cfg.defaults['FMS_HOST'] = parser.get('default','fms_host') + if parser.has_option('default','fms_port'): + cfg.defaults['FMS_PORT'] = parser.getint('default','fms_port') + if parser.has_option('default','fms_id'): + cfg.defaults['FMS_ID'] = parser.get('default','fms_id') + if parser.has_option('default','fmsnotify_group'): + cfg.defaults['FMSNOTIFY_GROUP'] = parser.get('default', + 'fmsnotify_group') + if parser.has_option('default','fmsread_groups'): + cfg.fmsread_groups = (parser.get('default','fmsread_groups'). + strip().split('|')) + else: + cfg.fmsread_groups = DEFAULT_GROUPS + cfg.file_name = file_name return cfg @@ -199,6 +241,14 @@ class Config: parser.set('default', 'tmp_dir', cfg.defaults['TMP_DIR']) parser.set('default', 'default_private_key', cfg.defaults['DEFAULT_PRIVATE_KEY']) + + parser.set('default', 'fms_host', cfg.defaults['FMS_HOST']) + parser.set('default', 'fms_port', cfg.defaults['FMS_PORT']) + parser.set('default', 'fms_id', cfg.defaults['FMS_ID']) + parser.set('default', 'fmsnotify_group', + cfg.defaults['FMSNOTIFY_GROUP']) + parser.set('default', 'fmsread_groups', '|'.join(cfg.fmsread_groups)) + parser.add_section('index_values') for repo_id in cfg.version_table: parser.set('index_values', repo_id, cfg.version_table[repo_id]) @@ -208,6 +258,12 @@ class Config: parser.add_section('insert_usks') for repo_id in cfg.insert_usks: parser.set('insert_usks', repo_id, cfg.insert_usks[repo_id]) + parser.add_section('fmsread_trust_map') + for index, fms_id in enumerate(cfg.fmsread_trust_map): + entry = cfg.fmsread_trust_map[fms_id] + assert len(entry) > 0 + parser.set('fmsread_trust_map', str(index), + fms_id + '|' + '|'.join(entry)) out_file = open(file_name, 'wb') try: diff --git a/infocalypse/fms.py b/infocalypse/fms.py new file mode 100644 --- /dev/null +++ b/infocalypse/fms.py @@ -0,0 +1,381 @@ +""" Code to support sending and receiving update notifications via fms. + + Copyright (C) 2009 Darrell Karbott + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Author: djk@isFiaD04zgAgnrEC5XJt1i4IE7AkNPqhBG5bONi6Yks +""" + +import nntplib +import StringIO + +from fcpclient import get_usk_hash, get_version, is_usk_file, \ + get_usk_for_usk_version + + +MSG_TEMPLATE = """From: %s +Newsgroups: %s +Subject: %s + +%s""" + +# msg_tuple = (sender, group, subject, text) +def send_msgs(fms_host, fms_port, msg_tuples): + """ Send messages via fms. + msg_tuple format is: (sender, group, subject, text) + """ + + server = nntplib.NNTP(fms_host, fms_port) + + try: + for msg_tuple in msg_tuples: + raw_msg = MSG_TEMPLATE % (msg_tuple[0], + msg_tuple[1], + msg_tuple[2], + msg_tuple[3]) + in_file = StringIO.StringIO(raw_msg) + print raw_msg + try: + #server.post(in_file) + pass + finally: + in_file.close() + finally: + server.quit() + + +class IFmsMessageSink: + def __init__(self): + pass + + def wants_msg(self, group, item): + return True + + def recv_fms_msg(self, group, item, lines): + pass + +def recv_msgs(fms_host, fms_port, msg_sink, groups): + """ Read messages from fms. """ + server = nntplib.NNTP(fms_host, fms_port) + try: + for group in groups: + result = server.group(group) + if result[1] == '0': + continue + # Doesn't return msg lines as shown in python doc? + # http://docs.python.org/library/nntplib.html + # Is this an fms bug? + result, items = server.xover(result[2], result[3]) + if result.split(' ')[0] != '224': + # REDFLAG: untested code path + raise Exception(result) + for item in items: + if not msg_sink.wants_msg(group, item): + continue + result = server.article(item[0]) + if result[0].split(' ')[0] != '220': + # REDFLAG: untested code path + raise Exception(result[0]) + pos = result[3].index('') + lines = [] + if pos != -1: + lines = result[3][pos + 1:] + msg_sink.recv_fms_msg(group, item, lines) + finally: + server.quit() + +############################################################ +# Infocalypse specific stuff. +############################################################ +def clean_nym(fms_id): + pos = fms_id.index('@') + if pos == -1: + return fms_id + + return fms_id[pos + 1:] + +def to_msg_string(updates, announcements=None): + """ Dump updates and announcements in a format which can + be read by parse. """ + if updates is None: + updates = [] + + if announcements is None: + announcements = [] + + # Make sure we always get the same string rep. + updates = list(updates) + updates.sort() + announcements = list(announcements) + announcements.sort() + + text = '' + for value in announcements: + assert is_usk_file(value) + text += "A:%s\n" % value + + for update in updates: + assert is_hex_string(update[0], 12) + assert update[1] >= 0 + text += "U:%s:%i\n" % (update[0], update[1]) + + return text + +# A grepper, not a parser... +def parse(text, is_lines=False): + """ Parse updates and announcements from raw text. """ + if is_lines: + lines = text + else: + lines = text.split('\n') + + announcements = set([]) + updates = set([]) + + for line in lines: + line = line.strip() # Handle crlf bs on Windoze. + fields = line.split(':') + if fields[0] == 'U' and len(fields) >= 3: + try: + if is_hex_string(fields[1]): + updates.add((fields[1], int(fields[2]))) + except ValueError: + continue + elif fields[0] == 'A' and len(fields) >= 2: + try: + if is_usk_file(fields[1]): + announcements.add(fields[1]) + # Implicit update. + updates.add((get_usk_hash(fields[1]), get_version(fields[1]))) + except ValueError: + continue + # else, silently fail... hmmmm + + # Perhaps a bit too metrosexual... + # Make sure you always get the same tuple for a given text. + updates = list(updates) + updates.sort() + announcements = list(announcements) + announcements.sort() + return (tuple(updates), tuple(announcements)) + + +def strip_names(trust_map): + clean = {} + for nym in trust_map: + cleaned = clean_nym(nym) + if nym in clean: + print "strip_name -- nym appears multiple times w/ different " \ + + "name part: " + nym + clean[cleaned] = list(set(list(trust_map[nym]) + + clean.get(cleaned, []))) + return clean + +# REDFLAG: Trust map ids are w/o names +# 'isFiaD04zgAgnrEC5XJt1i4IE7AkNPqhBG5bONi6Yks', not +# 'djk@isFiaD04zgAgnrEC5XJt1i4IE7AkNPqhBG5bONi6Yks' +class USKIndexUpdateParser(IFmsMessageSink): + """ Class which accumulates USK index update notifications + from fms messages. """ + def __init__(self, trust_map): + self.trust_map = strip_names(trust_map) + self.updates = {} + + def wants_msg(self, group, items): + if len(items[5]) != 0: + # Skip replies + return False + + if clean_nym(items[2]) not in self.trust_map: + #print "Not trusted: ", items[2] + # Sender not authoritative on any USK. + return False + + return True + + def recv_fms_msg(self, group, items, lines): + """ recv_messages message callback implementation. """ + allowed_hashes = self.trust_map[clean_nym(items[2])] + + #print "---\nSender: %s\nSubject: %s\n" % (items[2], items[1]) + for update in parse(lines, True)[0]: + if update[0] in allowed_hashes: + # Only update if the nym is trusted *for the specific USK*. + #print "UPDATING ---\nSender: %s\nSubject: %s\n" % (items[2], items[1]) + self.handle_update(update) + + def handle_update(self, update): + """ INTERNAL: Handle a single update. """ + index = update[1] + value = self.updates.get(update[0], index) + if index >= value: + self.updates[update[0]] = index + + def updated(self, previous=None): + """ Returns a USK hash -> index map for USKs which + have been updated. """ + if previous is None: + previous = {} + ret = {} + for usk_hash in self.updates: + if not usk_hash in previous: + ret[usk_hash] = self.updates[usk_hash] + continue + if self.updates[usk_hash] > previous[usk_hash]: + ret[usk_hash] = self.updates[usk_hash] + + return ret + +class USKAnnouncementParser(IFmsMessageSink): + """ Class which accumulates USK announcement notifications + from fms messages. """ + # None means accept all announcements. + def __init__(self, trust_map = None): + if not trust_map is None: + trust_map = strip_names(trust_map) + self.trust_map = trust_map + self.usks = {} + + def wants_msg(self, group, items): + if len(items[5]) != 0: + # Skip replies + return False + + if self.trust_map is None: + return True + + if clean_nym(items[2]) not in self.trust_map: + #print "Not trusted: ", items[2] + # Sender not authoritative on any USK. + return False + + return True + + def recv_fms_msg(self, group, items, lines): + #print "---\nSender: %s\nSubject: %s\n" % (items[2], items[1]) + for usk in parse(lines, True)[1]: + self.handle_announcement(items[2], usk) + + def handle_announcement(self, sender, usk): + """ INTERNAL: Handle a single announcement """ + usk = get_usk_for_usk_version(usk, 0) + entry = self.usks.get(usk, []) + if not sender in entry: + entry.append(sender) + self.usks[usk] = entry + +HEX_CHARS = frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f']) +# REQUIRES: Lowercase! +def is_hex_string(value, length=12): + if not length is None: + if len(value) != length: + raise ValueError("Expected hex string of length: %i" % length) + for char in value: + if not char in HEX_CHARS: + return False + return True + +############################################################ + +DEFAULT_SUBJECT = 'Ignore' +def make_update_msg(fms_id, group, updates, announcements=None, + subject=DEFAULT_SUBJECT): + print "updates: ", updates + print "announcements: ", announcements + + # fms doesn't want to see the full id? + fms_id = fms_id.split('@')[0] + text = to_msg_string(updates, announcements) + return (fms_id, group, subject, text) + +############################################################ + +MSG_FMT = """--- +Sender : %s +Subject: %s +Date : %s +Group : %s +%s +--- +""" +class MsgSink(IFmsMessageSink): + def __init__(self): + IFmsMessageSink.__init__(self) + + def recv_fms_msg(self, group, item, lines): + print MSG_FMT % (item[2], item[1], item[3], group, '\n'.join(lines)) + +def smoke_test(): + # trust_map = {'djk@isFiaD04zgAgnrEC5XJt1i4IE7AkNPqhBG5bONi6Yks': + # ('be68e8feccdd', ),} + + + trust_map = {'falafel@IxVqeqM0LyYdTmYAf5z49SJZUxr7NtQkOqVYG0hvITw': + ('1' * 12, ), + 'SDiZ@17fy9sQtAvZI~nwDt5xXJkTZ9KlXon1ucEakK0vOFTc': + ('2' * 12, ), + } + + parser = USKIndexUpdateParser(trust_map) + recv_msgs('127.0.0.1', 11119, parser, ('test',)) + print + print "fms updates:" + print parser.updated() + print + print + parser = USKAnnouncementParser(trust_map) + recv_msgs('127.0.0.1', 11119, parser, ('test',)) + print + print "fms announcements:" + print parser.usks + print + print + + values0 = ((('be68e8feccdd', 23), ('e246cc31bc42', 3)), + ('USK@kRM~jJVREwnN2qnA8R0Vt8HmpfRzBZ0j4rHC2cQ-0hw,' + + '2xcoQVdQLyqfTpF2DpkdUIbHFCeL4W~2X1phUYymnhM,AQACAAE/' + + 'infocalypse.hgext.R1/12', )) + + # Includes implicit update from announcement. + values2 = ((('be68e8feccdd', 12), ('be68e8feccdd', 23), ('e246cc31bc42', 3)), + ('USK@kRM~jJVREwnN2qnA8R0Vt8HmpfRzBZ0j4rHC2cQ-0hw,' + + '2xcoQVdQLyqfTpF2DpkdUIbHFCeL4W~2X1phUYymnhM,AQACAAE/' + + 'infocalypse.hgext.R1/12',)) + + # From tuple to string + print "---" + print values0 + + text = to_msg_string(values0[0], values0[1]) + print "---" + # And back + print text + values1 = parse(text) + print "---" + print values1 + # Not values0 because of implicit update. + assert values1 == values2 + + msg = make_update_msg('djk@isFiaD04zgAgnrEC5XJt1i4IE7AkNPqhBG5bONi6Yks' + 'test', + 'test', + values0[0], + values0[1]) + send_msgs('127.0.0.1', 11119, (msg, )) + +if __name__ == "__main__": + smoke_test() diff --git a/infocalypse/infcmds.py b/infocalypse/infcmds.py --- a/infocalypse/infcmds.py +++ b/infocalypse/infcmds.py @@ -31,7 +31,8 @@ import time from mercurial import util from fcpclient import parse_progress, is_usk, is_ssk, get_version, \ - get_usk_for_usk_version, FCPClient, is_usk_file, is_negative_usk + get_usk_for_usk_version, FCPClient, is_usk_file, is_negative_usk, \ + get_usk_hash from fcpconnection import FCPConnection, PolledSocket, CONNECTION_STATES, \ get_code, FCPError @@ -46,6 +47,9 @@ from updatesm import UpdateStateMachine, from config import Config, DEFAULT_CFG_PATH, normalize +from fms import USKAnnouncementParser, USKIndexUpdateParser, recv_msgs, \ + to_msg_string, MSG_TEMPLATE, send_msgs + DEFAULT_PARAMS = { # FCP params 'MaxRetries':3, @@ -317,7 +321,7 @@ def setup(ui_, repo, params, stored_cfg) # REDFLAG: Hack to work around 1208 cancel bug. Remove. if update_sm.params['FREENET_BUILD'] == '1208': ui_.warn("DISABLING request canceling to work around 1208 FCP bug.\n" - "This may cause requests to hang. :-(\n") + "This may cause requests to hang. :-(\n\n") disable_cancel(update_sm) # Patch state machine to re-enable canceling on shutdown. @@ -410,8 +414,8 @@ def do_key_setup(ui_, update_sm, params, # Update the inverted insert URI to the latest known version. params['INVERTED_INSERT_URI'] = get_usk_for_usk_version( - inverted_uri, - max_index) + inverted_uri, + max_index) # Update the index of the request uri using the stored config. request_uri = params.get('REQUEST_URI') @@ -675,7 +679,7 @@ NO_INFO_FMT = """There's no stored infor USK hash: %s """ -INFO_FMT ="""USK hash: %s +INFO_FMT = """USK hash: %s index : %i Request URI: @@ -704,6 +708,152 @@ def execute_info(ui_, repo, params, stor ui_.status(INFO_FMT % (usk_hash, max_index or -1, request_uri, insert_uri)) +def execute_fmsread(ui_, repo, params, stored_cfg): + action = params['FMSREAD'] + if params['VERBOSITY'] >= 2: + ui_.status(('Connecting to fms on %s:%i\n' + + 'Searching groups: %s\n') % + (stored_cfg.defaults['FMS_HOST'], + stored_cfg.defaults['FMS_PORT'], + ' '.join(stored_cfg.fmsread_groups))) + + if action == 'list' or action == 'listall': + if action == 'listall': + parser = USKAnnouncementParser() + if params['VERBOSITY'] >= 2: + ui_.status('Listing all repo USKs.\n') + else: + trust_map = stored_cfg.fmsread_trust_map.copy() # paranoid copy + if params['VERBOSITY'] >= 2: + fms_ids = trust_map.keys() + fms_ids.sort() + ui_.status(("Only listing repo USKs from trusted " + + "fms IDs:\n%s\n\n") % '\n'.join(fms_ids)) + parser = USKAnnouncementParser(trust_map) + recv_msgs(stored_cfg.defaults['FMS_HOST'], + stored_cfg.defaults['FMS_PORT'], + parser, + stored_cfg.fmsread_groups) + if len(parser.usks) == 0: + ui_.status("No USKs found.\n") + return + ui_.status("\n") + for usk in parser.usks: + usk_entry = parser.usks[usk] + ui_.status("USK Hash: %s\n%s\n%s\n\n" % + (get_usk_hash(usk), usk, + '\n'.join(usk_entry))) + else: + trust_map = stored_cfg.fmsread_trust_map.copy() # paranoid copy + if params['VERBOSITY'] >= 2: + fms_ids = trust_map.keys() + fms_ids.sort() + ui_.status("Update Trust Map:\n") + for fms_id in fms_ids: + ui_.status(" %s: %s\n" % (fms_id, + ' '.join(trust_map[fms_id]))) + ui_.status("\n") + parser = USKIndexUpdateParser(trust_map) + recv_msgs(stored_cfg.defaults['FMS_HOST'], + stored_cfg.defaults['FMS_PORT'], + parser, + stored_cfg.fmsread_groups) + changed = parser.updated(stored_cfg.version_table) + if len(changed) == 0: + ui_.status('No updates found.\n') + return + + for usk_hash in changed: + ui_.status('%s:%i\n' % (usk_hash, changed[usk_hash])) + + if params['DRYRUN']: + ui_.status('Exiting without saving because --dryrun was set.\n') + return + + for usk_hash in changed: + stored_cfg.update_index(usk_hash, changed[usk_hash]) + + Config.to_file(stored_cfg) + ui_.status('Saved updated indices.\n') + # Back map to uris and print + # show message if current repo was updated + # support dry run + +# REDFLAG: Catch this in config when depersisting? +def is_none(value): + return value is None or value == 'None' + +def execute_fmsnotify(ui_, repo, params, stored_cfg): + update_sm = None + try: + # REDFLAG: dci, test non uri keys + update_sm = setup(ui_, repo, params, stored_cfg) + request_uri, dummy = do_key_setup(ui_, update_sm, + params, stored_cfg) + if request_uri is None: + ui_.warn("Only works for USK file URIs.\n") + return + + usk_hash = get_usk_hash(request_uri) + index = stored_cfg.get_index(usk_hash) + # REDFLAG: DCI. Needed? + request_uri = get_usk_for_usk_version(request_uri, index) + if index is None: + ui_.warn("Can't notify because there's no stored index " + + "for %s.\n" % usk_hash) + return + + if is_none(stored_cfg.defaults['FMS_ID']): + ui_.warn("Can't notify because the fms ID isn't set in the " + + "config file.\n") + ui_.status("Update the fms_id = line and try again.\n") + return + + if is_none(stored_cfg.defaults['FMSNOTIFY_GROUP']): + ui_.warn("Can't notify because fms group isn't set in the " + + "config file.\n") + ui_.status("Update the fmsnotify_group = line and try again.\n") + return + + if params['ANNOUNCE']: + text = to_msg_string(None, (request_uri, )) + else: + text = to_msg_string(((usk_hash, index), )) + + subject = 'Update:' + '/'.join(request_uri.split('/')[1:]) + msg_tuple = (stored_cfg.defaults['FMS_ID'], + stored_cfg.defaults['FMSNOTIFY_GROUP'], + subject, + text) + + if params['VERBOSITY'] >= 2: + ui_.status('Connecting to fms on %s:%i\n' % + (stored_cfg.defaults['FMS_HOST'], + stored_cfg.defaults['FMS_PORT'])) + + ui_.status('Group: %s\nSubject: %s\n%s\n' % + (stored_cfg.defaults['FMSNOTIFY_GROUP'], + subject, text)) + + if params['VERBOSITY'] >= 5: + raw_msg = MSG_TEMPLATE % (msg_tuple[0], + msg_tuple[1], + msg_tuple[2], + msg_tuple[3]) + ui_.status('--- Raw Message ---\n%s\n---\n' % raw_msg) + + if params['DRYRUN']: + ui_.status('Exiting without sending because --dryrun was set.\n') + return + + send_msgs(stored_cfg.defaults['FMS_HOST'], + stored_cfg.defaults['FMS_PORT'], + (msg_tuple, )) + + ui_.status('Notification message sent.\n') + finally: + cleanup(update_sm) + def setup_tmp_dir(ui_, tmp): """ INTERNAL: Setup the temp directory. """ tmp = os.path.expanduser(tmp) diff --git a/infocalypse/knownrepos.py b/infocalypse/knownrepos.py new file mode 100644 --- /dev/null +++ b/infocalypse/knownrepos.py @@ -0,0 +1,15 @@ + +# If you maintain a repository that doesn't contain illicit content +# let me know and I'll add it here. +KNOW_REPOS = ( + 'USK@kRM~jJVREwnN2qnA8R0Vt8HmpfRzBZ0j4rHC2cQ-0hw,' + + '2xcoQVdQLyqfTpF2DpkdUIbHFCeL4W~2X1phUYymnhM,AQACAAE/' + + 'infocalypse.hgext.R1/23', + ) + +DEFAULT_TRUST = { + 'djk@isFiaD04zgAgnrEC5XJt1i4IE7AkNPqhBG5bONi6Yks': + ('be68e8feccdd', ), + } + +DEFAULT_GROUPS = ('test', )