diff options
author | Mattias Andrée <m@maandree.se> | 2025-02-23 21:02:09 +0100 |
---|---|---|
committer | Mattias Andrée <m@maandree.se> | 2025-02-23 21:02:09 +0100 |
commit | a231ffb8d5e49cff8401137b89233d4f51c7f802 (patch) | |
tree | af51f561630a762c46fe4fd1f56cdff4df67e137 /sysrss.py | |
parent | Update e-mail (diff) | |
download | sysrss-a231ffb8d5e49cff8401137b89233d4f51c7f802.tar.gz sysrss-a231ffb8d5e49cff8401137b89233d4f51c7f802.tar.bz2 sysrss-a231ffb8d5e49cff8401137b89233d4f51c7f802.tar.xz |
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to 'sysrss.py')
-rwxr-xr-x | sysrss.py | 322 |
1 files changed, 0 insertions, 322 deletions
diff --git a/sysrss.py b/sysrss.py deleted file mode 100755 index d7f80c8..0000000 --- a/sysrss.py +++ /dev/null @@ -1,322 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -''' -sysrss – Let your system generate a maintenance notification RSS - -Copyright © 2012, 2013 Mattias Andrée (m@maandree.se) - -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 <http://www.gnu.org/licenses/>. -''' - -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('<?xml version="1.0" encoding="utf-8"?>\n'.encode('utf-8')) - file.write('<rss version="2.0">\n'.encode('utf-8')) - file.write(' <channel>\n'.encode('utf-8')) - file.write(' <title>SysRSS</title>\n'.encode('utf-8')) - file.write(' <description>System maintenance notification RSS</description>\n'.encode('utf-8')) - file.write(' <link>http://localhost/</link>\n'.encode('utf-8')) - file.write((' <lastBuildDate>%s</lastBuildDate>\n' % date).encode('utf-8')) - file.write((' <pubDate>%s</pubDate>\n' % date).encode('utf-8')) - file.write(' <ttl>1800</ttl>\n'.encode('utf-8')) - file.write('\n'.encode('utf-8')) - file.write(' </channel>\n'.encode('utf-8')) - file.write('</rss>\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('<pubDate>') + len('<pubDate>'):] - data = data[:data.find('</')] - self.pubdate = data - - - ''' - Initialise site list - - @return :boolean Whether the program can continue - ''' - def initSites(self): - self.sites = [] - sites = self.sites - sitefile = self.root + 'sites' - if os.path.exists(sitefile): - with open(sitefile, 'rb') as file: - code = file.read().decode('utf8', 'replace') + '\n' - code = compile(code, sitefile, 'exec') - exec(code) - else: - with open(sitefile, 'wb') as file: - file.write('# -*- mode: python, coding: utf-8 -*-\n'.encode('utf-8')) - file.write('\n'.encode('utf-8')) - file.write('# self.sites (alternatively sites) is a list that you\n'.encode('utf-8')) - file.write('# should fill with Site:s, a site descripts a subsystem\n'.encode('utf-8')) - file.write('# that generates updates. Site\'s constructor takes 3\n'.encode('utf-8')) - file.write('# arguments: name, interval, implementation. The first\n'.encode('utf-8')) - file.write('# `name` is the name of the subsystme, it is displayed\n'.encode('utf-8')) - file.write('# as the title on all updates. `interval` is the number\n'.encode('utf-8')) - file.write('# is minutes between update checks. `implementation` is\n'.encode('utf-8')) - file.write('# function or functor that returns an update message,\n'.encode('utf-8')) - file.write('# or an empty string if there are no updates.\n'.encode('utf-8')) - file.write('\n'.encode('utf-8')) - file.flush() - printf('Created site file, %s, you should fill it in and then restart this program.\n', sitefile) - flush() - return False - return True - - - ''' - Publish a news item to the RSS - - @param system:str The subsystem that generated the message - @param message:str Message to display - ''' - def publish(self, system, message): - date = self.getTime() - addendum = self.makeNews(system, message).encode('utf-8') - - with open(self.root + 'log', 'ab') as file: - file.write(addendum) - file.flush() - printf('The feed log as been updated with %s.\n', system) - - with open(self.root + 'tmp', 'wb') as file: - file.write('<?xml version="1.0" encoding="utf-8"?>\n'.encode('utf-8')) - file.write('<rss version="2.0">\n'.encode('utf-8')) - file.write(' <channel>\n'.encode('utf-8')) - file.write(' <title>SysRSS</title>\n'.encode('utf-8')) - file.write(' <description>System maintenance notification RSS</description>\n'.encode('utf-8')) - file.write(' <link>http://localhost/</link>\n'.encode('utf-8')) - file.write((' <lastBuildDate>%s</lastBuildDate>\n' % date).encode('utf-8')) - file.write((' <pubDate>%s</pubDate>\n\n' % self.pubdate).encode('utf-8')) - with open(self.root + 'log', 'rb') as logfile: - file.write(logfile.read()) - file.write(' </channel>\n'.encode('utf-8')) - file.write('</rss>\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(']]>', ']]]]><![CDATA[>') - data = data.replace('\n', '<br>') # [sic!] - return '<![CDATA[' + data + ']]>' - return('<item>\n <title>%s</title>\n <guid>%s</guid>\n <pubDate>%s</pubDate>\n <description>%s</description>\n</item>\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() - |