summaryrefslogtreecommitdiffstats
path: root/bin/reproducible_json.py
blob: 33e218b6bc2244c8c8a3064f429b7d8b4a5faabb (plain)
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
128
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Copyright © 2015 Mattia Rizzolo <mattia@mapreri.org>
# Copyright © 2015-2017 Holger Levsen <holger@layer-acht.org>
# Based on reproducible_json.sh © 2014 Holger Levsen <holger@layer-acht.org>
# Licensed under GPL-2
#
# Depends: python3
#
# Build the reproducible.json and reproducibe-tracker.json files, to provide nice datasources

from reproducible_common import *

from apt_pkg import version_compare
import aptsources.sourceslist
import json
import os
import subprocess
import tempfile


output = []
output4tracker = []

log.info('Creating json dump of current reproducible status')

# filter_query is defined in reproducible_common.py and excludes some FTBFS issues
query = "SELECT s.name, r.version, s.suite, s.architecture, r.status, r.build_date " + \
        "FROM results AS r JOIN sources AS s ON r.package_id = s.id "+ \
        "WHERE status != '' AND status NOT IN ('not for us', '404', 'blacklisted' ) AND (( status != 'FTBFS' ) OR " \
        " ( status = 'FTBFS' and r.package_id NOT IN (SELECT n.package_id FROM NOTES AS n WHERE " + filter_query + " )))"

result = sorted(query_db(query))
log.info('\tprocessing ' + str(len(result)))

keys = ['package', 'version', 'suite', 'architecture', 'status', 'build_date']
crossarchkeys = ['package', 'version', 'suite', 'status']
archdetailkeys = ['architecture', 'version', 'status', 'build_date']

# crossarch is a dictionary of all packages used to build a summary of the
# package's test results across all archs (for suite=unstable only)
crossarch = {}

crossarchversions = {}
for row in result:
    pkg = dict(zip(keys, row))
    log.debug(pkg)
    output.append(pkg)

    # tracker.d.o should only care about results in stretch
    if pkg['suite'] == 'stretch':

        package = pkg['package']
        if package in crossarch:
            # compare statuses to get cross-arch package status
            status1 = crossarch[package]['status']
            status2 = pkg['status']
            newstatus = ''

            # compare the versions (only keep most up to date!)
            version1 = crossarch[package]['version']
            version2 = pkg['version']
            versionscompared = version_compare(version1, version2);

            # if version1 > version2,
            # skip the package results we are currently inspecting
            if (versionscompared > 0):
                continue

            # if version1 < version2,
            # delete the package results with the older version
            elif (versionscompared < 0):
                newstatus = status2
                # remove the old package information from the list
                archlist = crossarch[package]['architecture_details']
                newarchlist = [a for a in archlist if a['version'] != version1]
                crossarch[package]['architecture_details'] = newarchlist

            # if version1 == version 2,
            # we are comparing status for the same (most recent) version
            else:
                if 'FTBFS' in [status1, status2]:
                    newstatus = 'FTBFS'
                elif 'unreproducible' in [status1, status2]:
                    newstatus = 'unreproducible'
                elif 'reproducible' in [status1, status2]:
                    newstatus = 'reproducible'
                else:
                    newstatus = 'depwait'

            # update the crossarch status and version
            crossarch[package]['status'] = newstatus
            crossarch[package]['version'] = version2

            # add arch specific test results to architecture_details list
            newarchdetails = {key:pkg[key] for key in archdetailkeys}
            crossarch[package]['architecture_details'].append(newarchdetails)


        else:
            # add package to crossarch
            crossarch[package] = {key:pkg[key] for key in crossarchkeys}
            crossarch[package]['architecture_details'] = \
                [{key:pkg[key] for key in archdetailkeys}]

output4tracker = list(crossarch.values())

for data, target in (
    (output, REPRODUCIBLE_JSON),
    # json for tracker.d.o, thanks to #785531
    (output4tracker, REPRODUCIBLE_TRACKER_JSON),
):
    tmpfile = tempfile.mkstemp(dir=os.path.dirname(target))[1]
    with open(tmpfile, 'w') as fd:
        json.dump(data, fd, indent=4, sort_keys=True)
    os.rename(tmpfile, target)
    os.chmod(target, 0o644)
    log.info("%s/%s has been updated.", DEBIAN_URL, os.path.dirname(target))

    # Write compressed version
    compressed = '{}.bz2'.format(target)
    tmpfile = tempfile.mkstemp(dir=os.path.dirname(compressed))[1]
    with open(tmpfile, 'w') as fd:
        subprocess.check_call(('bzip2', '-9c', target), stdout=fd)
    os.rename(tmpfile, compressed)
    os.chmod(compressed, 0o644)
    log.info("%s/%s has been updated.", DEBIAN_URL, os.path.dirname(compressed))