Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
1from __future__ import print_function 2 3 4import argparse 5import bz2 6import email 7import json 8import logging 9 10from itertools import product 11from operator import itemgetter 12 13import attr 14import pkg_resources 15 16from pathlib2 import Path 17from requests import Session 18from six.moves.urllib_parse import urljoin 19 20 21@attr.s 22class ReleaseElement(object): 23 sha256 = attr.ib(repr=False) 24 size = attr.ib(convert=int) 25 path = attr.ib() 26 27log = logging.getLogger('enpass.updater') 28 29 30parser = argparse.ArgumentParser() 31parser.add_argument('--repo') 32parser.add_argument('--target', type=Path) 33 34 35session = Session() 36 37 38def parse_bz2_msg(msg): 39 msg = bz2.decompress(msg) 40 if '\n\n' in msg: 41 parts = msg.split('\n\n') 42 return list(map(email.message_from_string, parts)) 43 return email.message_from_string(msg) 44 45 46def fetch_meta(repo, name, parse=email.message_from_string, split=False): 47 url = urljoin(repo, 'dists/stable', name) 48 response = session.get("{repo}/dists/stable/{name}".format(**locals())) 49 return parse(response.content) 50 51 52def fetch_filehashes(repo, path): 53 meta = fetch_meta(repo, path, parse=parse_bz2_msg) 54 for item in meta: 55 yield { 56 'version': pkg_resources.parse_version(str(item['Version'])), 57 'path': item['Filename'], 58 'sha256': item['sha256'], 59 } 60 61 62def fetch_archs(repo): 63 m = fetch_meta(repo, 'Release') 64 65 architectures = m['Architectures'].split() 66 elements = [ReleaseElement(*x.split()) for x in m['SHA256'].splitlines()] 67 elements = [x for x in elements if x.path.endswith('bz2')] 68 69 for arch, elem in product(architectures, elements): 70 if arch in elem.path: 71 yield arch, max(fetch_filehashes(repo, elem.path), 72 key=itemgetter('version')) 73 74 75class OurVersionEncoder(json.JSONEncoder): 76 def default(self, obj): 77 # the other way around to avoid issues with 78 # newer setuptools having strict/legacy versions 79 if not isinstance(obj, (dict, str)): 80 return str(obj) 81 return json.JSONEncoder.default(self, obj) 82 83 84def main(repo, target): 85 logging.basicConfig(level=logging.DEBUG) 86 with target.open(mode='wb') as fp: 87 json.dump( 88 dict(fetch_archs(repo)), fp, 89 cls=OurVersionEncoder, 90 indent=2, 91 sort_keys=True) 92 93 94opts = parser.parse_args() 95main(opts.repo, opts.target)