~ubuntu-archive/ubuntu-archive-scripts/trunk

234.2.1 by Balint Reczey
Generate report on per team Bazaar packaging repositories
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
4
# Copyright (C) 2018 Canonical Ltd
5
6
# This program is free software; you can redistribute it and/or
7
# modify it under the terms of the GNU General Public License
8
# as published by the Free Software Foundation; either version 2
9
# of the License, or (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
# GNU General Public License for more details.
15
#
16
# A copy of the GNU General Public License version 2 is in LICENSE.
17
18
import apt_pkg
19
import argparse
20
import atexit
21
from collections import defaultdict
22
from datetime import datetime
23
import gzip
24
import json
25
import os
26
import re
27
import shutil
28
import tempfile
29
from textwrap import dedent
30
from urllib.request import urlopen
31
32
import attr
33
from jinja2 import Environment, FileSystemLoader
34
import yaml
35
36
env = Environment(
37
    loader=FileSystemLoader(os.path.dirname(os.path.abspath(__file__)) + '/templates'),
38
    autoescape=True,
39
    extensions=['jinja2.ext.i18n'],
40
)
41
env.install_null_translations(True)
42
43
tempdir = None
44
307 by Łukasz 'sil2100' Zemczak
Style cleanup of generate-team-bzr
45
234.2.1 by Balint Reczey
Generate report on per team Bazaar packaging repositories
46
# copied from component-mismatches
47
def ensure_tempdir():
48
    global tempdir
49
    if not tempdir:
50
        tempdir = tempfile.mkdtemp(prefix='component-mismatches')
51
        atexit.register(shutil.rmtree, tempdir)
52
53
54
# copied from component-mismatches
55
def decompress_open(tagfile):
56
    ensure_tempdir()
57
    decompressed = tempfile.mktemp(dir=tempdir)
58
    fin = gzip.GzipFile(filename=tagfile)
59
    with open(decompressed, 'wb') as fout:
60
        fout.write(fin.read())
61
    return open(decompressed, 'r')
62
63
64
# copied from generate-team-p-m
65
def get_subscribers_json(packages, subscribers_json):
66
    if subscribers_json is None:
349 by Steve Langasek
ubuntu-archive-team is https-only
67
        j = urlopen("https://ubuntu-archive-team.ubuntu.com/package-team-mapping.json")
234.2.1 by Balint Reczey
Generate report on per team Bazaar packaging repositories
68
    else:
69
        j = open(subscribers_json, 'rb')
70
    with j:
71
        team_to_packages = json.loads(j.read().decode('utf-8'))
72
    package_to_teams = {}
73
    for team, team_packages in team_to_packages.items():
74
        for package in team_packages:
75
            if package in packages:
76
                package_to_teams.setdefault(package, []).append(team)
77
    return package_to_teams
78
307 by Łukasz 'sil2100' Zemczak
Style cleanup of generate-team-bzr
79
234.2.1 by Balint Reczey
Generate report on per team Bazaar packaging repositories
80
def packages_with_bzr_repos(options):
81
    pkgs = {}
82
    for component in options.components.split(','):
83
        sources_path = "%s/dists/%s/%s/source/Sources.gz" % (
84
            options.archive_dir, options.suite, component)
85
        for section in apt_pkg.TagFile(decompress_open(sources_path)):
86
            if 'Package' in section and 'Vcs-Bzr' in section:
87
                pkgs[section['Package']] = section['Vcs-Bzr']
88
    return pkgs
89
90
91
def repo_url(repo):
307 by Łukasz 'sil2100' Zemczak
Style cleanup of generate-team-bzr
92
    return re.sub('^lp:', 'https://code.launchpad.net/', repo)
93
234.2.1 by Balint Reczey
Generate report on per team Bazaar packaging repositories
94
95
def main():
96
    parser = argparse.ArgumentParser()
97
    parser.add_argument('--archive-dir', action='store', default=os.path.expanduser("~/mirror/ubuntu"))
98
    parser.add_argument('--components', action='store', default="main,restricted,universe,multiverse")
99
    parser.add_argument('--suite', action='store')
100
    parser.add_argument('--subscribers-json', action='store')
101
    parser.add_argument('output')
102
    args = parser.parse_args()
103
104
    pkgs = packages_with_bzr_repos(args)
105
106
    print("getting subscribers")
107
    subscribers = get_subscribers_json(set(pkgs.keys()), args.subscribers_json)
108
    for p in set(pkgs.keys()):
109
        if p not in subscribers:
110
            subscribers[p] = ['unknown']
111
112
    all_teams = set()
113
    team_to_pkgs = defaultdict(list)
114
    for package, teams in subscribers.items():
115
        all_teams |= set(teams)
116
        for team in teams:
117
            team_to_pkgs[team].append(package)
118
119
    team_to_attn_count = {}
120
    for team, packages in team_to_pkgs.items():
121
        team_to_attn_count[team] = len(packages)
122
        team_to_pkgs[team] = [(package, repo_url(pkgs[package])) for package in sorted(packages)]
123
124
    print("rendering")
125
    t = env.get_template('team-report-bzr.html')
126
    now = datetime.utcnow()
127
    with open(args.output, 'w', encoding='utf-8') as fp:
128
        fp.write(t.render(
129
            all_teams=all_teams,
309 by Łukasz 'sil2100' Zemczak
Missed in review: make the date nicer in the bzr report.
130
            now="%s UTC" % now.strftime("%Y-%m-%d %H:%M:%S"),
234.2.1 by Balint Reczey
Generate report on per team Bazaar packaging repositories
131
            team_to_pkgs=team_to_pkgs,
132
            team_to_attn_count=team_to_attn_count))
133
307 by Łukasz 'sil2100' Zemczak
Style cleanup of generate-team-bzr
134
234.2.1 by Balint Reczey
Generate report on per team Bazaar packaging repositories
135
if __name__ == '__main__':
136
    main()