changing to new format
This commit is contained in:
parent
4663c3cd02
commit
436bc3d083
348
arch/relchk.py
348
arch/relchk.py
@ -1,81 +1,293 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import configparser
|
import datetime
|
||||||
|
import json
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
|
import pathlib
|
||||||
import re
|
import re
|
||||||
from bs4 import BeautifulSoup
|
import shutil
|
||||||
from urllib.parse import urljoin, urlparse
|
##
|
||||||
from urllib.request import urlopen
|
import psutil
|
||||||
try:
|
import requests
|
||||||
import lxml
|
from lxml import etree
|
||||||
htmlparser = 'lxml'
|
##
|
||||||
except ImportError:
|
import arch_mirror_ranking # <optools>/arch/arch_mirror_ranking.py
|
||||||
htmlparser = 'html.parser'
|
|
||||||
|
|
||||||
cfgpath = os.path.abspath(os.path.expanduser(
|
|
||||||
'~/.config/optools/relchk/arch.ini'))
|
|
||||||
|
|
||||||
cfg = configparser.ConfigParser()
|
class Updater(object):
|
||||||
cfg['arch'] = {'url': 'https://arch.mirror.square-r00t.net/iso/latest/',
|
_fname_re = re.compile(r'^archlinux-(?P<version>[0-9]{4}\.[0-9]{2}\.[0-9]{2})-(?P<arch>(i686|x86_64)).iso$')
|
||||||
'path': '/boot/iso/arch.iso',
|
_def_hash = 'sha1'
|
||||||
'hashtype': 'sha1',
|
_allowed_hashes = ('md5', 'sha1')
|
||||||
'hashurl': (
|
_allowed_arches = ('x86_64', )
|
||||||
'https://arch.mirror.square-r00t.net/iso/latest/sha1sums.txt')
|
_date_fmt = '%a, %d %b %Y %H:%M:%S %z'
|
||||||
}
|
_datever_fmt = '%Y.%m.%d'
|
||||||
|
_arch = 'x86_64' # Arch Linux proper only offers x86_64.
|
||||||
|
_iso_dir = 'iso/latest'
|
||||||
|
_iso_file = os.path.join(_iso_dir, 'archlinux-{ver}-{arch}.iso')
|
||||||
|
|
||||||
if not os.path.isfile(cfgpath):
|
def __init__(self,
|
||||||
os.makedirs(os.path.dirname(cfgpath), exist_ok = True)
|
dest_dir = '/boot/iso',
|
||||||
with open(cfgpath, 'w') as f:
|
dest_file = 'arch.iso',
|
||||||
cfg.write(f)
|
ver_file = '.arch.json',
|
||||||
else:
|
lock_path = '/tmp/.arch.lck',
|
||||||
cfg.read(cfgpath)
|
feed_url = 'https://archlinux.org/feeds/releases/',
|
||||||
|
grub_cfg = '/etc/grub.d/40_custom_arch',
|
||||||
|
# check_gpg = True, # TODO: GPG sig checking
|
||||||
|
hash_type = 'sha1'):
|
||||||
|
# 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.dest_dir = os.path.abspath(os.path.expanduser(dest_dir))
|
||||||
|
self.dest_file = dest_file
|
||||||
|
self.ver_file = ver_file
|
||||||
|
self.feed_url = feed_url
|
||||||
|
self.grub_cfg = grub_cfg
|
||||||
|
self.lckfile = os.path.abspath(os.path.expanduser(lock_path))
|
||||||
|
# From the JSON.
|
||||||
|
self.rel_notes_url = None
|
||||||
|
self.old_date = None
|
||||||
|
self.old_ver = None
|
||||||
|
self.old_hash = None
|
||||||
|
self.mirror_base = None
|
||||||
|
self.country = None
|
||||||
|
# New vals.
|
||||||
|
self.new_date = None
|
||||||
|
self.new_ver = None
|
||||||
|
self.new_hash = None
|
||||||
|
# Instance vars again.
|
||||||
|
self.do_update = False
|
||||||
|
self.force_update = False
|
||||||
|
self.iso_url = None
|
||||||
|
self.ipv4 = True
|
||||||
|
self.ipv6 = False
|
||||||
|
self.dest_iso = os.path.join(self.dest_dir, self.dest_file)
|
||||||
|
self.dest_ver = os.path.join(self.dest_dir, self.ver_file)
|
||||||
|
self._init_vars()
|
||||||
|
|
||||||
cfg['arch']['path'] = os.path.abspath(os.path.expanduser(cfg['arch']['path']))
|
def _init_vars(self):
|
||||||
|
if self.getRunning():
|
||||||
|
return(None)
|
||||||
|
self.getCountry()
|
||||||
|
self.getNet()
|
||||||
|
self.getCurVer()
|
||||||
|
self.getNewVer()
|
||||||
|
return(None)
|
||||||
|
|
||||||
# We need the hashes first. We'll pop them into memory,
|
def main(self):
|
||||||
# no need to save locally.
|
if self.getRunning():
|
||||||
# Must be in GNU checksum format (i.e. "<HASH> <FILENAME>\n").
|
return(None)
|
||||||
hashes = {}
|
self.lock()
|
||||||
if 'hashurl' in cfg['arch']:
|
if self.do_update or \
|
||||||
with urlopen(cfg['arch']['hashurl']) as h:
|
self.force_update or not \
|
||||||
for i in h.read().decode('utf-8').splitlines():
|
all((self.old_date,
|
||||||
line = [x.strip() for x in i.split()]
|
self.old_ver,
|
||||||
hashes[os.path.basename(line[1])] = line[0]
|
self.old_hash)):
|
||||||
chksum = hashlib.new(cfg['arch']['hashtype'])
|
self.do_update = True
|
||||||
|
self.findMirror()
|
||||||
|
self.download()
|
||||||
|
self.touchVer()
|
||||||
|
self.unlock()
|
||||||
|
return(None)
|
||||||
|
|
||||||
# Now we (try to) get a list of files available for download. We're looking
|
def download(self):
|
||||||
# for .iso or .img files. Compressed images not currently supported; TODO.
|
if self.getRunning():
|
||||||
exts = re.compile('.*\.(iso|img)$', re.IGNORECASE)
|
return(None)
|
||||||
imgfiles = []
|
if not any((self.do_update, self.force_update)):
|
||||||
with urlopen(cfg['arch']['url']) as u:
|
return(None)
|
||||||
dlsoup = BeautifulSoup(u.read().decode('utf-8'), htmlparser)
|
if not self.iso_url:
|
||||||
for a in dlsoup.find_all('a'):
|
raise RuntimeError('iso_url attribute must be set first')
|
||||||
if a['href']:
|
req = requests.get(self.iso_url, stream = True, headers = {'User-Agent': 'curl/7.74.0'})
|
||||||
if exts.search(a['href']):
|
if not req.ok:
|
||||||
if not urlparse(a['href']).netloc:
|
raise RuntimeError('Received non-200/30x {0} for {1}'.format(req.status_code, self.iso_url))
|
||||||
imgfiles.append(urljoin(cfg['arch']['url'], a['href']))
|
with req as uri:
|
||||||
else:
|
with open(self.dest_iso, 'wb') as fh:
|
||||||
imgfiles.append(a['href'])
|
shutil.copyfileobj(uri.raw, fh)
|
||||||
if not imgfiles:
|
hasher = hashlib.new(self.hash_type)
|
||||||
raise RuntimeError('Could not find any ISO or IMG files at {0}'.format(
|
with open(self.dest_iso, 'rb') as fh:
|
||||||
cfg['arch']['url']))
|
hasher.update(fh.read())
|
||||||
# Not foolproof, but will handle standard Arch ISO mirrors just fine.
|
realhash = hasher.hexdigest().lower()
|
||||||
imgfiles.sort()
|
if realhash != self.new_hash:
|
||||||
iso = imgfiles[0]
|
raise RuntimeError('Hash mismatch: {0} (LOCAL), {1} (REMOTE)'.format(realhash, self.new_hash))
|
||||||
|
self.updateVer()
|
||||||
|
return(None)
|
||||||
|
|
||||||
# Now we get the existing file (if it exists) and grab the hash (if we have
|
def findMirror(self):
|
||||||
# one fetched).
|
self.getCountry()
|
||||||
up2date = False
|
if self.mirror_base:
|
||||||
if os.path.isfile(cfg['arch']['path']):
|
return(None)
|
||||||
_fname = os.path.basename(iso)
|
for p in ('http', 'https'):
|
||||||
if _fname in hashes:
|
m = arch_mirror_ranking.MirrorIdx(country = self.country,
|
||||||
with open(cfg['arch']['path'], 'rb') as f:
|
proto = 'http',
|
||||||
chksum.update(f.read())
|
is_active = True,
|
||||||
if chksum.hexdigest().lower() == hashes[_fname].lower():
|
ipv4 = self.ipv4,
|
||||||
up2date = True
|
ipv6 = self.ipv6,
|
||||||
|
isos = True,
|
||||||
|
statuses = False)
|
||||||
|
for s in m.ranked_servers:
|
||||||
|
try:
|
||||||
|
req = requests.get(s['url'])
|
||||||
|
if req.ok:
|
||||||
|
self.mirror_base = s['url']
|
||||||
|
break
|
||||||
|
except (OSError, ConnectionRefusedError):
|
||||||
|
continue
|
||||||
|
return(None)
|
||||||
|
|
||||||
if not up2date:
|
def getCountry(self):
|
||||||
os.makedirs(os.path.dirname(cfg['arch']['path']), exist_ok = True)
|
if self.country: # The API has limited number of accesses for free.
|
||||||
with open(cfg['arch']['path'], 'wb') as f, urlopen(iso) as u:
|
return(None)
|
||||||
f.write(u.read())
|
url = 'https://ipinfo.io/country'
|
||||||
|
req = requests.get(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, url))
|
||||||
|
self.country = req.content.decode('utf-8').strip().upper()
|
||||||
|
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 = datetime.datetime.strptime(ver_info['ver'], self._datever_fmt)
|
||||||
|
self.old_hash = ver_info.get(self.hash_type, self._def_hash)
|
||||||
|
self.country = ver_info.get('country')
|
||||||
|
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 getNet(self):
|
||||||
|
for k in ('ipv4', 'ipv6'):
|
||||||
|
url = 'https://{0}.clientinfo.square-r00t.net'.format(k)
|
||||||
|
try:
|
||||||
|
req = requests.get(url)
|
||||||
|
setattr(self, k, req.json()['ip'])
|
||||||
|
except OSError:
|
||||||
|
setattr(self, k, False)
|
||||||
|
return(None)
|
||||||
|
|
||||||
|
def getNewVer(self):
|
||||||
|
if self.getRunning():
|
||||||
|
return(None)
|
||||||
|
if not self.mirror_base:
|
||||||
|
self.findMirror()
|
||||||
|
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)
|
||||||
|
for item in feed.xpath('//item'):
|
||||||
|
date_xml = item.find('pubDate')
|
||||||
|
ver_xml = item.find('title')
|
||||||
|
notes_xml = item.find('link')
|
||||||
|
date = ver = notes = None
|
||||||
|
if date_xml is not None:
|
||||||
|
date = datetime.datetime.strptime(date_xml.text, self._date_fmt)
|
||||||
|
if ver_xml is not None:
|
||||||
|
ver = ver_xml.text
|
||||||
|
if notes_xml is not None:
|
||||||
|
notes = notes_xml.text
|
||||||
|
new_ver = datetime.datetime.strptime(ver, self._datever_fmt)
|
||||||
|
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.rel_notes_url = notes
|
||||||
|
datever = self.new_ver.strftime(self._datever_fmt)
|
||||||
|
self.iso_url = os.path.join(self.mirror_base,
|
||||||
|
self._iso_file.lstrip('/')).format(ver = datever, arch = self._arch)
|
||||||
|
hash_url = os.path.join(self.mirror_base,
|
||||||
|
self._iso_dir,
|
||||||
|
'{0}sums.txt'.format(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))
|
||||||
|
hash_lines = req.content.decode('utf-8').strip().splitlines()
|
||||||
|
tgt_fname = os.path.basename(self.iso_url)
|
||||||
|
for line in hash_lines:
|
||||||
|
if line.strip().startswith('#'):
|
||||||
|
continue
|
||||||
|
hash_str, fname = line.split()
|
||||||
|
if fname != tgt_fname:
|
||||||
|
continue
|
||||||
|
self.new_hash = hash_str.lower()
|
||||||
|
break
|
||||||
|
break
|
||||||
|
return(None)
|
||||||
|
|
||||||
|
def getRunning(self):
|
||||||
|
if not os.path.isfile(self.lckfile):
|
||||||
|
return(False)
|
||||||
|
my_pid = os.getpid()
|
||||||
|
with open(self.lckfile, 'r') as fh:
|
||||||
|
pid = int(fh.read().strip())
|
||||||
|
if not psutil.pid_exists(pid):
|
||||||
|
os.remove(self.lckfile)
|
||||||
|
return(False)
|
||||||
|
if pid == my_pid:
|
||||||
|
return(False)
|
||||||
|
return(True)
|
||||||
|
|
||||||
|
def lock(self):
|
||||||
|
with open(self.lckfile, 'w') as fh:
|
||||||
|
fh.write(str(os.getpid()))
|
||||||
|
return(None)
|
||||||
|
|
||||||
|
def touchVer(self):
|
||||||
|
if self.getRunning():
|
||||||
|
return(None)
|
||||||
|
ver_path = pathlib.Path(self.dest_ver)
|
||||||
|
ver_path.touch(exist_ok = True)
|
||||||
|
return(None)
|
||||||
|
|
||||||
|
def unlock(self):
|
||||||
|
if os.path.isfile(self.lckfile):
|
||||||
|
os.remove(self.lckfile)
|
||||||
|
return(None)
|
||||||
|
|
||||||
|
def updateVer(self):
|
||||||
|
if self.getRunning():
|
||||||
|
return(None)
|
||||||
|
d = {'date': self.new_date.strftime(self._date_fmt),
|
||||||
|
'mirror': self.mirror_base,
|
||||||
|
'country': self.country,
|
||||||
|
'notes': self.rel_notes_url,
|
||||||
|
'ver': self.new_ver.strftime(self._datever_fmt),
|
||||||
|
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()
|
||||||
|
293
arch/relchk2.py
293
arch/relchk2.py
@ -1,293 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import datetime
|
|
||||||
import json
|
|
||||||
import hashlib
|
|
||||||
import os
|
|
||||||
import pathlib
|
|
||||||
import re
|
|
||||||
import shutil
|
|
||||||
##
|
|
||||||
import psutil
|
|
||||||
import requests
|
|
||||||
from lxml import etree
|
|
||||||
##
|
|
||||||
import arch_mirror_ranking # <optools>/arch/arch_mirror_ranking.py
|
|
||||||
|
|
||||||
|
|
||||||
class Updater(object):
|
|
||||||
_fname_re = re.compile(r'^archlinux-(?P<version>[0-9]{4}\.[0-9]{2}\.[0-9]{2})-(?P<arch>(i686|x86_64)).iso$')
|
|
||||||
_def_hash = 'sha1'
|
|
||||||
_allowed_hashes = ('md5', 'sha1')
|
|
||||||
_allowed_arches = ('x86_64', )
|
|
||||||
_date_fmt = '%a, %d %b %Y %H:%M:%S %z'
|
|
||||||
_datever_fmt = '%Y.%m.%d'
|
|
||||||
_arch = 'x86_64' # Arch Linux proper only offers x86_64.
|
|
||||||
_iso_dir = 'iso/latest'
|
|
||||||
_iso_file = os.path.join(_iso_dir, 'archlinux-{ver}-{arch}.iso')
|
|
||||||
|
|
||||||
def __init__(self,
|
|
||||||
dest_dir = '/boot/iso',
|
|
||||||
dest_file = 'arch.iso',
|
|
||||||
ver_file = '.arch.json',
|
|
||||||
lock_path = '/tmp/.arch.lck',
|
|
||||||
feed_url = 'https://archlinux.org/feeds/releases/',
|
|
||||||
grub_cfg = '/etc/grub.d/40_custom_arch',
|
|
||||||
# check_gpg = True, # TODO: GPG sig checking
|
|
||||||
hash_type = 'sha1'):
|
|
||||||
# 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.dest_dir = os.path.abspath(os.path.expanduser(dest_dir))
|
|
||||||
self.dest_file = dest_file
|
|
||||||
self.ver_file = ver_file
|
|
||||||
self.feed_url = feed_url
|
|
||||||
self.grub_cfg = grub_cfg
|
|
||||||
self.lckfile = os.path.abspath(os.path.expanduser(lock_path))
|
|
||||||
# From the JSON.
|
|
||||||
self.rel_notes_url = None
|
|
||||||
self.old_date = None
|
|
||||||
self.old_ver = None
|
|
||||||
self.old_hash = None
|
|
||||||
self.mirror_base = None
|
|
||||||
self.country = None
|
|
||||||
# New vals.
|
|
||||||
self.new_date = None
|
|
||||||
self.new_ver = None
|
|
||||||
self.new_hash = None
|
|
||||||
# Instance vars again.
|
|
||||||
self.do_update = False
|
|
||||||
self.force_update = False
|
|
||||||
self.iso_url = None
|
|
||||||
self.ipv4 = True
|
|
||||||
self.ipv6 = False
|
|
||||||
self.dest_iso = os.path.join(self.dest_dir, self.dest_file)
|
|
||||||
self.dest_ver = os.path.join(self.dest_dir, self.ver_file)
|
|
||||||
self._init_vars()
|
|
||||||
|
|
||||||
def _init_vars(self):
|
|
||||||
if self.getRunning():
|
|
||||||
return(None)
|
|
||||||
self.getCountry()
|
|
||||||
self.getNet()
|
|
||||||
self.getCurVer()
|
|
||||||
self.getNewVer()
|
|
||||||
return(None)
|
|
||||||
|
|
||||||
def main(self):
|
|
||||||
if self.getRunning():
|
|
||||||
return(None)
|
|
||||||
self.lock()
|
|
||||||
if self.do_update or \
|
|
||||||
self.force_update or not \
|
|
||||||
all((self.old_date,
|
|
||||||
self.old_ver,
|
|
||||||
self.old_hash)):
|
|
||||||
self.do_update = True
|
|
||||||
self.findMirror()
|
|
||||||
self.download()
|
|
||||||
self.touchVer()
|
|
||||||
self.unlock()
|
|
||||||
return(None)
|
|
||||||
|
|
||||||
def download(self):
|
|
||||||
if self.getRunning():
|
|
||||||
return(None)
|
|
||||||
if not any((self.do_update, self.force_update)):
|
|
||||||
return(None)
|
|
||||||
if not self.iso_url:
|
|
||||||
raise RuntimeError('iso_url attribute must be set first')
|
|
||||||
req = requests.get(self.iso_url, stream = True, 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.iso_url))
|
|
||||||
with req as uri:
|
|
||||||
with open(self.dest_iso, 'wb') as fh:
|
|
||||||
shutil.copyfileobj(uri.raw, fh)
|
|
||||||
hasher = hashlib.new(self.hash_type)
|
|
||||||
with open(self.dest_iso, 'rb') as fh:
|
|
||||||
hasher.update(fh.read())
|
|
||||||
realhash = hasher.hexdigest().lower()
|
|
||||||
if realhash != self.new_hash:
|
|
||||||
raise RuntimeError('Hash mismatch: {0} (LOCAL), {1} (REMOTE)'.format(realhash, self.new_hash))
|
|
||||||
self.updateVer()
|
|
||||||
return(None)
|
|
||||||
|
|
||||||
def findMirror(self):
|
|
||||||
self.getCountry()
|
|
||||||
if self.mirror_base:
|
|
||||||
return(None)
|
|
||||||
for p in ('http', 'https'):
|
|
||||||
m = arch_mirror_ranking.MirrorIdx(country = self.country,
|
|
||||||
proto = 'http',
|
|
||||||
is_active = True,
|
|
||||||
ipv4 = self.ipv4,
|
|
||||||
ipv6 = self.ipv6,
|
|
||||||
isos = True,
|
|
||||||
statuses = False)
|
|
||||||
for s in m.ranked_servers:
|
|
||||||
try:
|
|
||||||
req = requests.get(s['url'])
|
|
||||||
if req.ok:
|
|
||||||
self.mirror_base = s['url']
|
|
||||||
break
|
|
||||||
except (OSError, ConnectionRefusedError):
|
|
||||||
continue
|
|
||||||
return(None)
|
|
||||||
|
|
||||||
def getCountry(self):
|
|
||||||
if self.country: # The API has limited number of accesses for free.
|
|
||||||
return(None)
|
|
||||||
url = 'https://ipinfo.io/country'
|
|
||||||
req = requests.get(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, url))
|
|
||||||
self.country = req.content.decode('utf-8').strip().upper()
|
|
||||||
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 = datetime.datetime.strptime(ver_info['ver'], self._datever_fmt)
|
|
||||||
self.old_hash = ver_info.get(self.hash_type, self._def_hash)
|
|
||||||
self.country = ver_info.get('country')
|
|
||||||
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 getNet(self):
|
|
||||||
for k in ('ipv4', 'ipv6'):
|
|
||||||
url = 'https://{0}.clientinfo.square-r00t.net'.format(k)
|
|
||||||
try:
|
|
||||||
req = requests.get(url)
|
|
||||||
setattr(self, k, req.json()['ip'])
|
|
||||||
except OSError:
|
|
||||||
setattr(self, k, False)
|
|
||||||
return(None)
|
|
||||||
|
|
||||||
def getNewVer(self):
|
|
||||||
if self.getRunning():
|
|
||||||
return(None)
|
|
||||||
if not self.mirror_base:
|
|
||||||
self.findMirror()
|
|
||||||
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)
|
|
||||||
for item in feed.xpath('//item'):
|
|
||||||
date_xml = item.find('pubDate')
|
|
||||||
ver_xml = item.find('title')
|
|
||||||
notes_xml = item.find('link')
|
|
||||||
date = ver = notes = None
|
|
||||||
if date_xml is not None:
|
|
||||||
date = datetime.datetime.strptime(date_xml.text, self._date_fmt)
|
|
||||||
if ver_xml is not None:
|
|
||||||
ver = ver_xml.text
|
|
||||||
if notes_xml is not None:
|
|
||||||
notes = notes_xml.text
|
|
||||||
new_ver = datetime.datetime.strptime(ver, self._datever_fmt)
|
|
||||||
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.rel_notes_url = notes
|
|
||||||
datever = self.new_ver.strftime(self._datever_fmt)
|
|
||||||
self.iso_url = os.path.join(self.mirror_base,
|
|
||||||
self._iso_file.lstrip('/')).format(ver = datever, arch = self._arch)
|
|
||||||
hash_url = os.path.join(self.mirror_base,
|
|
||||||
self._iso_dir,
|
|
||||||
'{0}sums.txt'.format(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))
|
|
||||||
hash_lines = req.content.decode('utf-8').strip().splitlines()
|
|
||||||
tgt_fname = os.path.basename(self.iso_url)
|
|
||||||
for line in hash_lines:
|
|
||||||
if line.strip().startswith('#'):
|
|
||||||
continue
|
|
||||||
hash_str, fname = line.split()
|
|
||||||
if fname != tgt_fname:
|
|
||||||
continue
|
|
||||||
self.new_hash = hash_str.lower()
|
|
||||||
break
|
|
||||||
break
|
|
||||||
return(None)
|
|
||||||
|
|
||||||
def getRunning(self):
|
|
||||||
if not os.path.isfile(self.lckfile):
|
|
||||||
return(False)
|
|
||||||
my_pid = os.getpid()
|
|
||||||
with open(self.lckfile, 'r') as fh:
|
|
||||||
pid = int(fh.read().strip())
|
|
||||||
if not psutil.pid_exists(pid):
|
|
||||||
os.remove(self.lckfile)
|
|
||||||
return(False)
|
|
||||||
if pid == my_pid:
|
|
||||||
return(False)
|
|
||||||
return(True)
|
|
||||||
|
|
||||||
def lock(self):
|
|
||||||
with open(self.lckfile, 'w') as fh:
|
|
||||||
fh.write(str(os.getpid()))
|
|
||||||
return(None)
|
|
||||||
|
|
||||||
def touchVer(self):
|
|
||||||
if self.getRunning():
|
|
||||||
return(None)
|
|
||||||
ver_path = pathlib.Path(self.dest_ver)
|
|
||||||
ver_path.touch(exist_ok = True)
|
|
||||||
return(None)
|
|
||||||
|
|
||||||
def unlock(self):
|
|
||||||
if os.path.isfile(self.lckfile):
|
|
||||||
os.remove(self.lckfile)
|
|
||||||
return(None)
|
|
||||||
|
|
||||||
def updateVer(self):
|
|
||||||
if self.getRunning():
|
|
||||||
return(None)
|
|
||||||
d = {'date': self.new_date.strftime(self._date_fmt),
|
|
||||||
'mirror': self.mirror_base,
|
|
||||||
'country': self.country,
|
|
||||||
'notes': self.rel_notes_url,
|
|
||||||
'ver': self.new_ver.strftime(self._datever_fmt),
|
|
||||||
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()
|
|
Loading…
Reference in New Issue
Block a user