summaryrefslogtreecommitdiffstats
path: root/bin/lts-missing-uploads.py
blob: c6f6156594fdecb9ce20c7d7f3ab3245fe35d32c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#!/usr/bin/env python3
#
# Copyright 2016 Chris Lamb <lamby@debian.org>
#
# This file is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This file is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this file.  If not, see <https://www.gnu.org/licenses/>.

import re
import sys
import gzip
import datetime
import requests
import subprocess
import dateutil.relativedelta

from debian.deb822 import Sources

SOURCES = 'http://security.debian.org/dists/wheezy/updates/main/source/Sources.gz'

re_line = re.compile(
    r'(?P<suffix>msg\d+.html).*\[DLA (?P<dla>[\d-]+)\] (?P<source>[^\s]+) security update.*'
)
re_version = re.compile(r'^Version.*: (?P<version>.*)')

session = requests.Session()

def get_dlas(year, month):
    url = 'https://lists.debian.org/debian-lts-announce/{}/{:02}/'.format(
        year,
        month,
    )

    result = parse(session.get(url).content, re_line)

    # Prepend URL as the indices have relative URIs
    for x in result:
        x['url'] = '{}{}'.format(url, x['suffix'])

    return result

def get_dla(url):
    return parse(session.get(url).content, re_version)

def main(*args):
    dlas = {}

    for idx in range(3):
        dt = datetime.datetime.utcnow().replace(day=1) - \
            dateutil.relativedelta.relativedelta(months=idx)

        info("Getting announcements for {}/{:02} ...", dt.year, dt.month)

        # Prefer later DLAs with reversed(..)
        for x in reversed(get_dlas(dt.year, dt.month)):
            # Only comment on the latest upload
            if x['source'] in dlas:
                continue

            info("{source}: parsing announcement from {url} ...", **x)
            x.update(get_dla(x['url'])[0])
            dlas[x['source']] = x

    if not dlas:
        return 0

    sources = get_sources()

    for source, dla in sorted(dlas.items()):
        version = sources[source]

        if subprocess.call((
            'dpkg', '--compare-versions', dla['version'], 'gt', version,
        )) == 0:
            warn("{}: DLA-{} announced version {} but LTS has {} <{}>".format(
                source,
                dla['dla'],
                dla['version'],
                version,
                dla['url'],
            ))

    return 0

def get_sources():
    info("Downloading Sources from {} ...", SOURCES)

    response = requests.get(SOURCES)
    response.raise_for_status()

    val = gzip.decompress(response.content).decode('utf-8')

    return {x['Package']: x['Version'] for x in Sources.iter_paragraphs(val)}

def warn(msg, *args, **kwargs):
    print("W: " + msg.format(*args, **kwargs), file=sys.stderr)

def info(msg, *args, **kwargs):
    print("I: " + msg.format(*args, **kwargs), file=sys.stderr)

def parse(content, pattern):
    result = []

    for x in content.splitlines():
        m = pattern.search(x.decode('utf8'))

        if m is None:
            continue

        result.append(m.groupdict())

    return result

if __name__ == '__main__':
    try:
        sys.exit(main(*sys.argv[1:]))
    except KeyboardInterrupt:
        sys.exit(1)

© 2014-2024 Faster IT GmbH | imprint | privacy policy