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)