def _interpolate(message, event): "Expand factoid variables" utcnow = datetime.utcnow() now = utcnow.replace(tzinfo=tzutc()).astimezone(tzlocal()) substitutions = [(u'who', event.sender['nick']), (u'channel', event.channel), (u'source', event.source), (u'year', unicode(now.year)), (u'month2', u'%02i' % now.month), (u'month1', unicode(now.month)), (u'month', unicode(now.strftime('%B'))), (u'mon', unicode(now.strftime('%b'))), (u'day2', u'%02i' % now.day), (u'day', unicode(now.day)), (u'hour', unicode(now.hour)), (u'minute', unicode(now.minute)), (u'second', unicode(now.second)), (u'date', format_date(utcnow, 'date')), (u'time', format_date(utcnow, 'time')), (u'dow', unicode(now.strftime('%A'))), (u'weekday', unicode(now.strftime('%A'))), (u'unixtime', unicode(utcnow.strftime('%s'))), ] for var, expansion in substitutions: message = message.replace(u'$' + var, expansion) return message
def log_revision(self, revision): if self.full: delta = self.branch.repository.get_revision_delta(revision.rev.revision_id) changes = [] if delta.added: changes.append('Added: %s' % ', '.join([file[0] for file in delta.added])) if delta.modified: changes.append('Modified: %s' % ', '.join([file[0] for file in delta.modified])) if delta.removed: changes.append('Removed: %s' % ', '.join([file[0] for file in delta.removed])) if delta.renamed: changes.append('Renamed: %s' % ', '.join(['%s => %s' % (file[0], file[1]) for file in delta.renamed])) timestamp = datetime.utcfromtimestamp(revision.rev.timestamp) commit = 'Commit %s by %s to %s on %s at %s: %s (%s)\n' % ( revision.revno, self.short_author(revision.rev), self.repository, format_date(timestamp, 'date'), format_date(timestamp, 'time'), revision.rev.message.replace('\n', ' '), '; '.join(changes)) else: commit = 'Commit %s by %s to %s %s ago: %s\n' % ( revision.revno, self.short_author(revision.rev), self.repository, ago(datetime.now() - datetime.fromtimestamp(revision.rev.timestamp), 2), revision.rev.get_summary().replace('\n', ' ')) self.to_file.write(commit)
def log_revision(self, revision): if self.full: delta = self.branch.repository.get_revision_delta( revision.rev.revision_id) changes = [] if delta.added: changes.append('Added: %s' % ', '.join([file[0] for file in delta.added])) if delta.modified: changes.append('Modified: %s' % ', '.join([file[0] for file in delta.modified])) if delta.removed: changes.append('Removed: %s' % ', '.join([file[0] for file in delta.removed])) if delta.renamed: changes.append('Renamed: %s' % ', '.join([ '%s => %s' % (file[0], file[1]) for file in delta.renamed ])) timestamp = datetime.utcfromtimestamp(revision.rev.timestamp) commit = 'Commit %s by %s to %s on %s at %s: %s (%s)\n' % ( revision.revno, self.short_author( revision.rev), self.repository, format_date(timestamp, 'date'), format_date(timestamp, 'time'), revision.rev.message.replace('\n', ' '), '; '.join(changes)) else: commit = 'Commit %s by %s to %s %s ago: %s\n' % ( revision.revno, self.short_author( revision.rev), self.repository, ago( datetime.now() - datetime.fromtimestamp(revision.rev.timestamp), 2), revision.rev.get_summary().replace('\n', ' ')) self.to_file.write(commit)
def _interpolate(message, event): "Expand factoid variables" utcnow = datetime.utcnow() now = utcnow.replace(tzinfo=tzutc()).astimezone(tzlocal()) substitutions = [ (u'who', event.sender['nick']), (u'channel', event.channel), (u'source', event.source), (u'year', unicode(now.year)), (u'month2', u'%02i' % now.month), (u'month1', unicode(now.month)), (u'month', unicode(now.strftime('%B'))), (u'mon', unicode(now.strftime('%b'))), (u'day2', u'%02i' % now.day), (u'day', unicode(now.day)), (u'hour', unicode(now.hour)), (u'minute', unicode(now.minute)), (u'second', unicode(now.second)), (u'date', format_date(utcnow, 'date')), (u'time', format_date(utcnow, 'time')), (u'dow', unicode(now.strftime('%A'))), (u'weekday', unicode(now.strftime('%A'))), (u'unixtime', unicode(utcnow.strftime('%s'))), ] for var, expansion in substitutions: message = message.replace(u'$' + var, expansion) return message
def messages_for(self, event, who, source): identities = get_identities(event) if not source: source = event.source else: source = source.lower() # Join on column x isn't possible in SQLAlchemy 0.4: identities_to = event.session.query(Identity) \ .filter_by(source=source, identity=who).all() identities_to = [identity.id for identity in identities_to] memos = event.session.query(Memo) \ .filter_by(delivered=False) \ .filter(Memo.from_id.in_(identities)) \ .filter(Memo.to_id.in_(identities_to)) \ .order_by(Memo.time.asc()).all() if memos: event.addresponse(u'Pending: ' + u', '.join( '%i: %s (%s)' % (i + 1, memo.memo, format_date(memo.time)) for i, memo in enumerate(memos) )) else: event.addresponse(u'Sorry, all your memos to %(who)s on %(source)s ' u'are already delivered', { 'who': who, 'source': source, })
def _interpolate(message, event): "Expand factoid variables" utcnow = datetime.utcnow() now = utcnow.replace(tzinfo=tzutc()).astimezone(tzlocal()) message = message.replace(u'$who', event.sender['nick']) message = message.replace(u'$channel', event.channel) message = message.replace(u'$year', unicode(now.year)) message = message.replace(u'$month', unicode(now.month)) message = message.replace(u'$day', unicode(now.day)) message = message.replace(u'$hour', unicode(now.hour)) message = message.replace(u'$minute', unicode(now.minute)) message = message.replace(u'$second', unicode(now.second)) message = message.replace(u'$date', format_date(utcnow, 'date')) message = message.replace(u'$time', format_date(utcnow, 'time')) message = message.replace(u'$dow', unicode(now.strftime('%A'))) message = message.replace(u'$unixtime', unicode(utcnow.strftime('%s'))) return message
def start_poll(self, event, secret, topic, end, options): if not event.public: event.addresponse(u'Sorry, must be done in public') return if (event.source, event.channel) in self.polls: event.addresponse(u'Sorry, poll on %s in progress.', self.polls[(event.source, event.channel)].topic) return class PollContainer(object): pass poll = PollContainer() self.polls[(event.source, event.channel)] = poll poll.secret = secret is not None if end is None: poll.end = event.time + timedelta(seconds=self.poll_time) else: poll.end = parse(end) if poll.end.tzinfo is None and not self.date_utc: poll.end = poll.end.replace(tzinfo=tzlocal()) if poll.end.tzinfo is not None: poll.end = poll.end.astimezone(tzutc()).replace(tzinfo=None) if poll.end < event.time: event.addresponse(u"I can't end a poll in the past") return poll.topic = topic poll.options = re.split(r'\s+or\s+', options) poll.lower_options = [o.lower() for o in poll.options] poll.votes = {} event.addresponse( u'You heard that, voting has begun. ' u'The polls close at %(end)s. ' u'%(private)s' u'The Options Are:', { 'private': poll.secret and u'You may vote in public or private. ' or u'', 'end': format_date(poll.end), }, address=False) for i, o in enumerate(poll.options): event.addresponse(u'%(id)i: %(option)s', { 'id': i + 1, 'option': o, }, address=False) delay = poll.end - event.time poll.delayed_call = ibid.dispatcher.call_later( delay.days * 86400 + delay.seconds, self.end_poll, event)
def messages(self, event): memos = get_memos(event, True) if memos: event.addresponse(u', '.join('%s: %s (%s)' % ( memos.index(memo) + 1, memo.sender.identity, format_date(memo.time), ) for memo in memos)) else: event.addresponse(u"Sorry, nobody loves you")
def messages(self, event): memos = get_memos(event, True) if memos: event.addresponse(u', '.join( '%s: %s (%s)' % ( memos.index(memo) + 1, memo.sender.identity, format_date(memo.time), ) for memo in memos )) else: event.addresponse(u"Sorry, nobody loves you")
def message(self, event, number): memos = get_memos(event, True) number = int(number) - 1 if number >= len(memos) or number == -1: event.addresponse(u'Sorry, no such message in your archive') return memo = memos[number] event.addresponse(u'From %(sender)s on %(source)s at %(time)s: ' u'%(message)s', { 'sender': memo.sender.identity, 'source': memo.sender.source, 'time': format_date(memo.time), 'message': memo.memo, })
def confirm(self, event): if (event.source, event.channel) not in duels: return duel = duels[(event.source, event.channel)] confirmer = event.sender['nick'].lower() if confirmer not in duel.names or duel.confirmed or confirmer != duel.recipient: return # Correct capitalisation duel.names[confirmer] = event.sender['nick'] duel.confirmed = True duel.cancel_callback.cancel() starttime = event.time + timedelta(seconds=self.start_delay + ((30 - event.time.second) % 30)) starttime = starttime.replace(microsecond=0) delay = starttime - event.time delay = delay.seconds + (delay.microseconds / 10.**6) duel.start_callback = ibid.dispatcher.call_later( delay, self.start, event) event.addresponse( u"%(aggressor)s, %(recipient)s: " u"The duel shall begin on the stroke of %(starttime)s (in %(delay)s seconds). " + choice(( u"You may clean your pistols.", u"Prepare yourselves.", u"Get ready", )), { 'aggressor': duel.names[duel.aggressor], 'recipient': duel.names[duel.recipient], 'starttime': format_date(starttime, 'time'), 'delay': (starttime - event.time).seconds, }, address=False)
def confirm(self, event): if (event.source, event.channel) not in duels: return duel = duels[(event.source, event.channel)] confirmer = event.sender['nick'].lower() if confirmer not in duel.names or duel.confirmed or confirmer != duel.recipient: return # Correct capitalisation duel.names[confirmer] = event.sender['nick'] duel.confirmed = True duel.cancel_callback.cancel() starttime = event.time + timedelta( seconds=self.start_delay + ((30 - event.time.second) % 30)) starttime = starttime.replace(microsecond=0) delay = starttime - event.time delay = delay.seconds + (delay.microseconds / 10.**6) duel.start_callback = ibid.dispatcher.call_later(delay, self.start, event) event.addresponse(u"%(aggressor)s, %(recipient)s: " u"The duel shall begin on the stroke of %(starttime)s (in %(delay)s seconds). " + choice(( u"You may clean your pistols.", u"Prepare yourselves.", u"Get ready", )), { 'aggressor': duel.names[duel.aggressor], 'recipient': duel.names[duel.recipient], 'starttime': format_date(starttime, 'time'), 'delay': (starttime - event.time).seconds, }, address=False)
def format_lastlive(self): return format_date(self.lastlive) if self.lastlive else 'Never'
def handler(self, event, who, source): account = None identity = event.session.query(Identity) \ .filter_by(source=(source or event.source), identity=who) \ .first() if identity and identity.account and not source: account = identity.account if not identity and not source: account = event.session.query(Account).filter_by(username=who) \ .first() if not identity and not account: event.addresponse(u"I don't know who %s is", who) return messages = [] states = [] if account: for identity in account.identities: for sighting in event.session.query(Sighting) \ .filter_by(identity_id=identity.id).all(): if sighting.type == 'message': messages.append(sighting) else: states.append(sighting) else: for sighting in event.session.query(Sighting) \ .filter_by(identity_id=identity.id).all(): if sighting.type == 'message': messages.append(sighting) else: states.append(sighting) if len(messages) == 0 and len(states) == 0: event.addresponse(u"I haven't seen %s", who) return messages.sort(key=lambda x: x.time, reverse=True) states.sort(key=lambda x: x.time, reverse=True) reply = u'' if len(messages) > 0: sighting = messages[0] delta = event.time - sighting.time reply = u'%s was last seen %s ago in %s on %s [%s]' %( who, ago(delta), sighting.channel or 'private', sighting.identity.source, format_date(sighting.time)) if len(states) > 0: sighting = states[0] if reply: reply += u', and' else: reply = who reply += u' has been %s on %s since %s' % ( sighting.value, sighting.identity.source, format_date(sighting.time)) event.addresponse(reply)
def format_log_message(self, log_message, full=False): """ author - string - the name of the author who committed the revision date - float time - the date of the commit message - string - the text of the log message for the commit revision - pysvn.Revision - the revision of the commit changed_paths - list of dictionaries. Each dictionary contains: path - string - the path in the repository action - string copyfrom_path - string - if copied, the original path, else None copyfrom_revision - pysvn.Revision - if copied, the revision of the original, else None """ revision_number = log_message['revision'].number author = log_message['author'] commit_message = log_message['message'] timestamp = log_message['date'] if full: pathinfo, delta = self._generate_delta(log_message['changed_paths']) changes = [] if delta.added: if self.multiline: changes.append('Added:\n\t%s' % '\n\t'.join([file[0] for file in delta.added])) else: changes.append('Added: %s' % ', '.join([file[0] for file in delta.added])) if delta.modified: if self.multiline: changes.append('Modified:\n\t%s' % '\n\t'.join([file[0] for file in delta.modified])) else: changes.append('Modified: %s' % '\, '.join([file[0] for file in delta.modified])) if delta.removed: if self.multiline: changes.append('Removed:\n\t%s' % '\n\t'.join([file[0] for file in delta.removed])) else: changes.append('Removed: %s' % ', '.join([file[0] for file in delta.removed])) if delta.renamed: changes.append('Renamed: %s' % ', '.join(['%s => %s' % (file[0], file[1]) for file in delta.renamed])) timestamp_dt = datetime.utcfromtimestamp(timestamp) if self.multiline: commit = 'Commit %s by %s to %s%s on %s at %s:\n\n\t%s \n\n%s\n' % ( revision_number, author, self.repository, pathinfo, format_date(timestamp_dt, 'date'), format_date(timestamp_dt, 'time'), u'\n'.join(textwrap.wrap(commit_message, initial_indent=" ", subsequent_indent=" ")), '\n\n'.join(changes)) else: commit = 'Commit %s by %s to %s%s on %s at %s: %s (%s)\n' % ( revision_number, author, self.repository, pathinfo, format_date(timestamp_dt, 'date'), format_date(timestamp_dt, 'time'), commit_message.replace('\n', ' '), '; '.join(changes)) else: commit = 'Commit %s by %s to %s %s ago: %s\n' % ( revision_number, author, self.repository, ago(datetime.now() - datetime.fromtimestamp(timestamp), 2), commit_message.replace('\n', ' ')) return commit
class TimeZone(Processor): usage = u"""when is <time> <place|timezone> in <place|timezone> time in <place|timezone>""" features = ('timezone',) zoneinfo = Option('zoneinfo', 'Timezone info directory', '/usr/share/zoneinfo') custom_zones = DictOption('timezones', 'Custom timezone names', CUSTOM_ZONES) countries = {} timezones = {} lowerzones = {} def setup(self): iso3166 = join(self.zoneinfo, 'iso3166.tab') if exists(iso3166): self.countries = {} for line in open(iso3166).readlines(): if not line.startswith('#'): code, name = line.strip().split('\t') self.countries[code] = name zones = join(self.zoneinfo, 'zone.tab') if exists(zones): self.timezones = defaultdict(list) for line in open(zones).readlines(): if not line.startswith('#'): code, coordinates, zone = line.strip().split('\t', 2) if '\t' in zone: zone, comment = zone.split('\t') self.timezones[code].append(zone) self.lowerzones = {} for path, directories, filenames in walk(self.zoneinfo): if path.replace(self.zoneinfo, '').lstrip('/').split('/')[0] not in ('posix', 'right'): for filename in filenames: name = join(path, filename).replace(self.zoneinfo, '').lstrip('/') self.lowerzones[name.lower().replace('etc/', '')] = name def _find_timezone(self, string): for name, zonename in self.custom_zones.items(): if string.lower() == name.lower(): return gettz(zonename) zone = gettz(string) if zone: return zone zone = gettz(string.upper()) if zone: return zone if string.lower() in self.lowerzones: return gettz(self.lowerzones[string.lower()]) ccode = None for code, name in self.countries.items(): if name.lower() == string.lower(): ccode = code if not ccode: if string.replace('.', '').upper() in self.timezones: ccode = string.replace('.', '').upper() if ccode: if len(self.timezones[ccode]) == 1: return gettz(self.timezones[ccode][0]) else: raise TimezoneException(u'%s has multiple timezones: %s' % (self.countries[ccode], human_join(self.timezones[ccode]))) possibles = [] for zones in self.timezones.values(): for name in zones: if string.replace(' ', '_').lower() in [part.lower() for part in name.split('/')]: possibles.append(name) if len(possibles) == 1: return gettz(possibles[0]) elif len(possibles) > 1: raise TimezoneException(u'Multiple timezones found: %s' % (human_join(possibles))) zone = self._geonames_lookup(string) if zone: return zone raise TimezoneException(u"I don't know about the %s timezone" % (string,)) def _geonames_lookup(self, place): search = json_webservice('http://ws.geonames.org/searchJSON', {'q': place, 'maxRows': 1, 'username': '******'}) if search['totalResultsCount'] == 0: return None city = search['geonames'][0] timezone = json_webservice('http://ws.geonames.org/timezoneJSON', {'lat': city['lat'], 'lng': city['lng'], 'username': '******'}) if 'timezoneId' in timezone: return gettz(timezone['timezoneId']) if 'rawOffset' in timezone: offset = timezone['rawOffset'] return tzoffset('UTC%s%s' % (offset>=0 and '+' or '', offset), offset*3600) @match(r'^when\s+is\s+((?:[0-9.:/hT -]|%s)+)(?:\s+in)?(?:\s+(.+))?\s+in\s+(.+)$' % '|'.join(MONTH_SHORT+MONTH_LONG+OTHER_STUFF), simple=False) def convert(self, event, time, from_, to): try: source = time and parse(time) or datetime.now() except ValueError: event.addresponse(u"That's not a real time") return try: if from_: from_zone = self._find_timezone(from_) else: from_zone = tzlocal() to_zone = self._find_timezone(to) except TimezoneException, e: event.addresponse(unicode(e)) return source = source.replace(tzinfo=from_zone) result = source.astimezone(to_zone) event.addresponse(time and u'%(source)s is %(destination)s' or 'It is %(destination)s', { 'source': format_date(source, tolocaltime=False), 'destination': format_date(result, tolocaltime=False), })
def format_log_message(self, log_message, full=False): """ author - string - the name of the author who committed the revision date - float time - the date of the commit message - string - the text of the log message for the commit revision - pysvn.Revision - the revision of the commit changed_paths - list of dictionaries. Each dictionary contains: path - string - the path in the repository action - string copyfrom_path - string - if copied, the original path, else None copyfrom_revision - pysvn.Revision - if copied, the revision of the original, else None """ revision_number = log_message['revision'].number author = log_message['author'] commit_message = log_message['message'] timestamp = log_message['date'] if full: pathinfo, delta = self._generate_delta( log_message['changed_paths']) changes = [] if delta.added: if self.multiline: changes.append( 'Added:\n\t%s' % '\n\t'.join([file[0] for file in delta.added])) else: changes.append('Added: %s' % ', '.join([file[0] for file in delta.added])) if delta.modified: if self.multiline: changes.append( 'Modified:\n\t%s' % '\n\t'.join([file[0] for file in delta.modified])) else: changes.append( 'Modified: %s' % '\, '.join([file[0] for file in delta.modified])) if delta.removed: if self.multiline: changes.append( 'Removed:\n\t%s' % '\n\t'.join([file[0] for file in delta.removed])) else: changes.append( 'Removed: %s' % ', '.join([file[0] for file in delta.removed])) if delta.renamed: changes.append('Renamed: %s' % ', '.join([ '%s => %s' % (file[0], file[1]) for file in delta.renamed ])) timestamp_dt = datetime.utcfromtimestamp(timestamp) if self.multiline: commit = 'Commit %s by %s to %s%s on %s at %s:\n\n\t%s \n\n%s\n' % ( revision_number, author, self.repository, pathinfo, format_date(timestamp_dt, 'date'), format_date(timestamp_dt, 'time'), u'\n'.join( textwrap.wrap( commit_message, initial_indent=" ", subsequent_indent=" ")), '\n\n'.join(changes)) else: commit = 'Commit %s by %s to %s%s on %s at %s: %s (%s)\n' % ( revision_number, author, self.repository, pathinfo, format_date(timestamp_dt, 'date'), format_date(timestamp_dt, 'time'), commit_message.replace('\n', ' '), '; '.join(changes)) else: commit = 'Commit %s by %s to %s %s ago: %s\n' % ( revision_number, author, self.repository, ago(datetime.now() - datetime.fromtimestamp(timestamp), 2), commit_message.replace('\n', ' ')) return commit