import os.path
import shutil
import tempfile
+import types
import urllib.parse
import urllib.request
import xml.dom.minidom
from typing import (
- Any,
Dict,
Iterable,
List,
)
+class InfoTableEntry(types.SimpleNamespace):
+ content: bytes
+ digest: str
+ file: str
+ size: int
+ url: str
+
+
+class Info(types.SimpleNamespace):
+ channel_html: bytes
+ forwarded_url: str
+ git_revision: str
+ table: Dict[str, InfoTableEntry]
+ url: str
+
+
class VerificationError(Exception):
pass
return filecmp.cmpfiles(a, b, files, shallow=False)
-def fetch(v: Verification, channel_url: str) -> Dict[str, Any]:
- info: Dict[str, Any] = {'url': channel_url}
+def fetch(v: Verification, channel_url: str) -> Info:
+ info = Info()
+ info.url = channel_url
v.status('Fetching channel')
request = urllib.request.urlopen(
'https://channels.nixos.org/nixos-20.03', timeout=10)
- info['channel_html'] = request.read()
- info['forwarded_url'] = request.geturl()
+ info.channel_html = request.read()
+ info.forwarded_url = request.geturl()
v.result(request.status == 200)
- v.check('Got forwarded', info['url'] != info['forwarded_url'])
+ v.check('Got forwarded', info.url != info.forwarded_url)
return info
-def parse(v: Verification, info: Dict[str, Any]) -> None:
+def parse(v: Verification, info: Info) -> None:
v.status('Parsing channel description as XML')
- d = xml.dom.minidom.parseString(info['channel_html'])
+ d = xml.dom.minidom.parseString(info.channel_html)
v.ok()
v.status('Extracting git commit')
git_commit_node = d.getElementsByTagName('tt')[0]
- info['git_commit'] = git_commit_node.firstChild.nodeValue
+ info.git_commit = git_commit_node.firstChild.nodeValue
v.ok()
v.status('Verifying git commit label')
v.result(git_commit_node.previousSibling.nodeValue == 'Git commit ')
v.status('Parsing table')
- info['table'] = {}
+ info.table = {}
for row in d.getElementsByTagName('tr')[1:]:
name = row.childNodes[0].firstChild.firstChild.nodeValue
url = row.childNodes[0].firstChild.getAttribute('href')
size = int(row.childNodes[1].firstChild.nodeValue)
digest = row.childNodes[2].firstChild.firstChild.nodeValue
- info['table'][name] = {'url': url, 'digest': digest, 'size': size}
+ info.table[name] = InfoTableEntry(url=url, digest=digest, size=size)
v.ok()
-def fetch_resources(v: Verification, info: Dict[str, Any]) -> None:
+def fetch_resources(v: Verification, info: Info) -> None:
for resource in ['git-revision', 'nixexprs.tar.xz']:
- fields = info['table'][resource]
+ fields = info.table[resource]
v.status('Fetching resource "%s"' % resource)
- url = urllib.parse.urljoin(info['forwarded_url'], fields['url'])
+ url = urllib.parse.urljoin(info.forwarded_url, fields.url)
request = urllib.request.urlopen(url, timeout=10)
- if fields['size'] < 4096:
- fields['content'] = request.read()
+ if fields.size < 4096:
+ fields.content = request.read()
else:
with tempfile.NamedTemporaryFile(suffix='.nixexprs.tar.xz', delete=False) as tmp_file:
shutil.copyfileobj(request, tmp_file)
- fields['file'] = tmp_file.name
+ fields.file = tmp_file.name
v.result(request.status == 200)
v.status('Verifying digest for "%s"' % resource)
- if fields['size'] < 4096:
- actual_hash = hashlib.sha256(fields['content']).hexdigest()
+ if fields.size < 4096:
+ actual_hash = hashlib.sha256(fields.content).hexdigest()
else:
hasher = hashlib.sha256()
- with open(fields['file'], 'rb') as f:
+ with open(fields.file, 'rb') as f:
# pylint: disable=cell-var-from-loop
for block in iter(lambda: f.read(4096), b''):
hasher.update(block)
actual_hash = hasher.hexdigest()
- v.result(actual_hash == fields['digest'])
+ v.result(actual_hash == fields.digest)
v.check('Verifying git commit on main page matches git commit in table',
- info['table']['git-revision']['content'].decode() == info['git_commit'])
+ info.table['git-revision'].content.decode() == info.git_commit)
-def extract_channel(v: Verification, info: Dict[str, Any]) -> None:
+def extract_channel(v: Verification, info: Info) -> None:
with tempfile.TemporaryDirectory() as d:
v.status('Extracting nixexprs.tar.xz')
- shutil.unpack_archive(info['table']['nixexprs.tar.xz']['file'], d)
+ shutil.unpack_archive(info.table['nixexprs.tar.xz'].file, d)
v.ok()
v.status('Removing temporary directory')
v.ok()