This repository has been archived on 2022-01-23. You can view files and clone it, but cannot push or open issues or pull requests.
relchk/sysresccd.py

153 lines
5.5 KiB
Python
Executable File

#!/usr/bin/env python3
# TODO: logging
# Example .sysresccd.json:
# {
# "date": "Sun, 22 Nov 2020 18:03:52 +0900",
# "arch": "amd64",
# "ver": 7.01,
# "sha512": "9d8c7e6d5c5f22d42bc20a663(...)"
# }
import datetime
import json
import hashlib
import os
import re
##
import requests
from lxml import etree
##
import _base
class Updater(_base.BaseUpdater):
_fname_re = re.compile(r'^systemrescue-(?P<version>[0-9.]+)-(?P<arch>(i686|amd64)).iso$')
_def_hash = 'sha256'
_allowed_hashes = ('sha256', 'sha512')
_allowed_arches = ('i686', 'amd64')
_tpl_file = 'sysresccd_grub.conf.j2'
def __init__(self,
arch = 'amd64',
dest_dir = '/boot/iso', # Should be subdir of boot_dir
dest_file = 'sysresccd.iso',
ver_file = '.sysresccd.json',
lock_path = '/tmp/.sysresccd.lck',
feed_url = 'https://osdn.net/projects/systemrescuecd/storage/!rss',
do_grub_cfg = True,
boot_dir = '/boot', # ESP or boot partition mount; where GRUB files are installed *under*
grub_cfg = '/etc/grub.d/40_custom_sysresccd',
# check_gpg = True, # TODO: GPG sig checking
hash_type = 'sha512'):
super().__init__(dest_dir, dest_file, ver_file, lock_path, do_grub_cfg, boot_dir, grub_cfg, hash_type)
if arch.lower() not in self._allowed_arches:
raise ValueError('arch must be one of: {0}'.format(', '.join(self._allowed_arches)))
else:
self.arch = arch.lower()
if hash_type.lower() not in self._allowed_hashes:
raise ValueError('hash_type must be one of: {0}'.format(', '.join(self._allowed_hashes)))
else:
self.hash_type = hash_type.lower()
self.feed_url = feed_url
self.dl_base = None
self._init_vars()
def _init_vars(self):
if self.getRunning():
return(None)
self.getCurVer()
self.getNewVer()
return(None)
def getCurVer(self):
if self.getRunning():
return(None)
if not os.path.isfile(self.dest_ver):
self.do_update = True
self.force_update = True
self.old_ver = 0.00
return(None)
with open(self.dest_ver, 'rb') as fh:
ver_info = json.load(fh)
self.old_date = datetime.datetime.strptime(ver_info['date'], self._date_fmt)
self.old_ver = ver_info['ver']
self.old_hash = ver_info.get(self.hash_type, self._def_hash)
self.new_hash = self.old_hash
self.new_ver = self.old_ver
self.new_date = self.old_date
if ver_info.get('arch') != self.arch:
self.do_update = True
self.force_update = True
try:
hasher = hashlib.new(self.hash_type)
with open(self.dest_iso, 'rb') as fh:
hasher.update(fh.read())
if self.old_hash != hasher.hexdigest().lower():
self.do_update = True
self.force_update = True
except FileNotFoundError:
self.do_update = True
self.force_update = True
return(None)
return (None)
def getNewVer(self):
if self.getRunning():
return(None)
req = requests.get(self.feed_url, headers = {'User-Agent': 'curl/7.74.0'})
if not req.ok:
raise RuntimeError('Received non-200/30x {0} for {1}'.format(req.status_code, self.feed_url))
feed = etree.fromstring(req.content)
self.dl_base = feed.xpath('channel/link')[0].text
for item in feed.xpath('//item'):
date_xml = item.find('pubDate')
title_xml = item.find('title')
# link_xml = item.find('link')
date = title = link = None
if date_xml is not None:
date = datetime.datetime.strptime(date_xml.text, self._date_fmt)
if title_xml is not None:
title = title_xml.text
# if link_xml is not None:
# link = link_xml.text
fname_r = self._fname_re.search(os.path.basename(title))
if not fname_r:
continue
ver_info = fname_r.groupdict()
if ver_info['arch'] != self.arch:
continue
new_ver = float(ver_info.get('version', self.old_ver))
if not all((self.old_ver, self.old_date)) or \
(new_ver > self.old_ver) or \
(self.old_date < date):
self.do_update = True
self.new_ver = new_ver
self.new_date = date
self.iso_url = os.path.join(self.dl_base, title.lstrip('/'))
hash_url = '{0}.{1}'.format(self.iso_url, self.hash_type)
req = requests.get(hash_url, headers = {'User-Agent': 'curl/7.74.0'})
if not req.ok:
raise RuntimeError('Received non-200/30x {0} for {1}'.format(req.status_code, hash_url))
self.new_hash = req.content.decode('utf-8').lower().split()[0]
break
return(None)
def updateVer(self):
if self.getRunning():
return(None)
d = {'date': self.new_date.strftime(self._date_fmt),
'arch': self.arch,
'ver': self.new_ver,
self.hash_type: self.new_hash}
j = json.dumps(d, indent = 4)
with open(self.dest_ver, 'w') as fh:
fh.write(j)
fh.write('\n')
return(None)
if __name__ == '__main__':
u = Updater()
u.main()