#!/usr/bin/env python # -*- coding: utf-8 -*- ''' sysrss – Let your system generate a maintenance notification RSS Copyright © 2012, 2013 Mattias Andrée (maandree@member.fsf.org) This program 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 3 of the License, or (at your option) any later version. This program 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 program. If not, see . ''' import os import sys import time import datetime from subprocess import Popen, PIPE ''' Hack to enforce UTF-8 in output (in the future, if you see anypony not using utf-8 in programs by default, report them to Princess Celestia so she can banish them to the moon) @param text:str The text to print (empty string is default) @param end:str The appendix to the text to print (line breaking is default) ''' def print(text = '', end = '\n'): sys.stdout.buffer.write((str(text) + end).encode('utf-8')) sys.stdout.buffer.flush() ''' stderr equivalent to print() @param text:str The text to print (empty string is default) @param end:str The appendix to the text to print (line breaking is default) ''' def printerr(text = '', end = '\n'): sys.stderr.buffer.write((str(text) + end).encode('utf-8')) sys.stderr.buffer.flush() ''' Link {@link #print}, only better because this does not take a text ending but takes a format and parameters @param master:str Formated string @param slave:str* Parameters for the formated string ''' def printf(master, *slave): sys.stdout.buffer.write((master % slave).encode('utf-8')) ''' Flush stdout ''' def flush(): sys.stdout.buffer.flush() ''' Mane class @dependency util-linux::uuidgen ''' class SysRSS: ''' Mane method and constructor ''' def __init__(self): self.root = os.getenv('HOME') + '/.sysrss/' self.sysinit() if not self.initSites(): exit(255) if len(self.sites) == 0: print('There are no sites, update %s.' % (self.root + 'sites')) exit(254) proper = [] for site in self.sites: site.interval = int(site.interval) if site.interval <= 0: print('Site %s does not have a positive interval and will therefore only be checked right now.' % site.name) else: proper.append(site) message = site() if (message is not None) and (len(message) > 0): self.publish(site.name, message) self.sites = proper while True: next = min(self.sites, key = lambda site : site.next).next for site in self.sites: if next > 0: time.sleep(next * 60) if site.next == next: message = site() if (message is not None) and (len(message) > 0): self.publish(site.name, message) site.next = site.interval else: site.next -= next ''' Initialise the system ''' def sysinit(self): if not os.path.isdir(self.root): os.mkdir(self.root) printf('Created root directory, %s.\n', self.root) if not os.path.isfile(self.root + 'log'): with open(self.root + 'log', 'wb') as file: file.flush() printf('Created log file, %s, it contains ever thing that have ever happend, ever.\n', self.root + 'log') flush() if not os.path.isfile(self.root + 'maintenance.rss'): date = self.getTime() with open(self.root + 'maintenance.rss', 'wb') as file: file.write('\n'.encode('utf-8')) file.write('\n'.encode('utf-8')) file.write(' \n'.encode('utf-8')) file.write(' SysRSS\n'.encode('utf-8')) file.write(' System maintenance notification RSS\n'.encode('utf-8')) file.write(' http://localhost/\n'.encode('utf-8')) file.write((' %s\n' % date).encode('utf-8')) file.write((' %s\n' % date).encode('utf-8')) file.write(' 1800\n'.encode('utf-8')) file.write('\n'.encode('utf-8')) file.write(' \n'.encode('utf-8')) file.write('\n'.encode('utf-8')) file.write('\n'.encode('utf-8')) file.flush() printf('Created rss file, %s, your should set you news feed aggregator to syndicate this file.\n', self.root + 'maintenance.rss') flush() self.pubdate = date self.publish('Welcome to SysRSS', 'This is going to be so awesome! 😄 \n\nEx animo\nSysRSS\n\n') else: data = None with open(self.root + 'maintenance.rss', 'rb') as file: data = file.read() data = data.decode('utf8', 'replace') data = data[data.find('') + len(''):] data = data[:data.find('\n'.encode('utf-8')) file.write('\n'.encode('utf-8')) file.write(' \n'.encode('utf-8')) file.write(' SysRSS\n'.encode('utf-8')) file.write(' System maintenance notification RSS\n'.encode('utf-8')) file.write(' http://localhost/\n'.encode('utf-8')) file.write((' %s\n' % date).encode('utf-8')) file.write((' %s\n\n' % self.pubdate).encode('utf-8')) with open(self.root + 'log', 'rb') as logfile: file.write(logfile.read()) file.write(' \n'.encode('utf-8')) file.write('\n'.encode('utf-8')) file.write('\n'.encode('utf-8')) file.flush() Popen(['mv', self.root + 'tmp', self.root + 'maintenance.rss']).wait() printf('The feed as been updated with %s.\n', system) ''' Generate RSS item @param system:str The subsystem that generated the message @param message:str Message to display @return :str RSS item ''' def makeNews(self, system, message): def makeUglyButReadable(data): data = data.replace(']]>', ']]]]>') data = data.replace('\n', '
') # [sic!] return '' return('\n %s\n %s\n %s\n %s\n\n\n' % (makeUglyButReadable(system), self.generateUUID(), self.getTime(), makeUglyButReadable(message))) ''' Generate an UUID @return An UUID ''' def generateUUID(self): uuid = Popen(['uuidgen'], stdout=PIPE).communicate()[0].decode('utf-8', 'replace') if uuid[-1] == '\n': uuid = uuid[:-1] return uuid ''' Get a locale independent time stamp in RSS's [poor] format @return :str The current time ''' def getTime(self): time = datetime.datetime.utcnow().strftime('(%w), %d [%m] %Y %H:%M:%S +0000') time = time.replace('(1)', 'Mon') time = time.replace('(2)', 'Tue') time = time.replace('(3)', 'Wed') time = time.replace('(4)', 'Thu') time = time.replace('(5)', 'Fri') time = time.replace('(6)', 'Sat') time = time.replace('(0)', 'Sun') # [sic!] time = time.replace('[01]', 'Jan') time = time.replace('[02]', 'Feb') time = time.replace('[03]', 'Mar') time = time.replace('[04]', 'Apr') time = time.replace('[05]', 'May') time = time.replace('[06]', 'Jun') time = time.replace('[07]', 'Jul') time = time.replace('[08]', 'Aug') time = time.replace('[09]', 'Sep') time = time.replace('[10]', 'Oct') time = time.replace('[11]', 'Nov') time = time.replace('[12]', 'Dec') return time ''' Subsystem definition class ''' class Site: ''' Constructor @param name System name @param interval:int Generation interval in minutes @param implementation:()→str Publish message generator, empty string is ignored ''' def __init__(self, name, interval, implementation): self.name = name self.interval = interval self.implementation = implementation self.next = interval ''' Invocation method @return :str Message to publish ''' def __call__(self): return self.implementation() ''' Execute mane method if started using this file ''' if __name__ == '__main__': SysRSS()