1#! /usr/bin/env python3
3"""
4Generate Maintainers file used by e.g. the Debian Bug Tracking System
5@contact: Debian FTP Master <ftpmaster@debian.org>
6@copyright: 2000, 2001, 2002, 2003, 2004, 2006 James Troup <james@nocrew.org>
7@copyright: 2011 Torsten Werner <twerner@debian.org>
8@license: GNU General Public License version 2 or later
10"""
12# This program is free software; you can redistribute it and/or modify
13# it under the terms of the GNU General Public License as published by
14# the Free Software Foundation; either version 2 of the License, or
15# (at your option) any later version.
17# This program is distributed in the hope that it will be useful,
18# but WITHOUT ANY WARRANTY; without even the implied warranty of
19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20# GNU General Public License for more details.
22# You should have received a copy of the GNU General Public License
23# along with this program; if not, write to the Free Software
24# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26################################################################################
28# ``As opposed to "Linux sucks. Respect my academic authoritah, damn
29# you!" or whatever all this hot air amounts to.''
30# -- ajt@ in _that_ thread on debian-devel@
32################################################################################
34from daklib import daklog
35from daklib import utils
36from daklib.config import Config
37from daklib.dbconn import *
38from daklib.regexes import re_comments
40import apt_pkg
41import sys
43from sqlalchemy.sql import text
45################################################################################
48def usage(exit_code=0):
49 print("""Usage: dak make-maintainers [OPTION] -a ARCHIVE EXTRA_FILE[...]
50Generate an index of packages <=> Maintainers / Uploaders.
52 -a, --archive=ARCHIVE archive to take packages from
53 -s, --source output source packages only
54 -p, --print print package list to stdout instead of writing it to files
55 -h, --help show this help and exit
56""")
57 sys.exit(exit_code)
59################################################################################
62def format(package, person):
63 '''Return a string nicely formatted for writing to the output file.'''
64 return '%-20s %s\n' % (package, person)
66################################################################################
69def main():
70 cnf = Config()
72 Arguments = [('h', "help", "Make-Maintainers::Options::Help"),
73 ('a', "archive", "Make-Maintainers::Options::Archive", 'HasArg'),
74 ('s', "source", "Make-Maintainers::Options::Source"),
75 ('p', "print", "Make-Maintainers::Options::Print")]
76 for i in ["Help", "Source", "Print"]:
77 key = "Make-Maintainers::Options::%s" % i
78 if key not in cnf: 78 ↛ 76line 78 didn't jump to line 76, because the condition on line 78 was never false
79 cnf[key] = ""
81 extra_files = apt_pkg.parse_commandline(cnf.Cnf, Arguments, sys.argv)
82 Options = cnf.subtree("Make-Maintainers::Options")
84 if Options["Help"] or not Options.get('Archive'):
85 usage()
87 Logger = daklog.Logger('make-maintainers')
88 session = DBConn().session()
90 archive = session.query(Archive).filter_by(archive_name=Options['Archive']).one()
92 # dictionary packages to maintainer names
93 maintainers = dict()
94 # dictionary packages to list of uploader names
95 uploaders = dict()
97 query = session.execute(text('''
98SELECT
99 bs.package,
100 bs.name AS maintainer,
101 array_agg(mu.name) OVER (
102 PARTITION BY bs.source, bs.id
103 ORDER BY mu.name
104 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
105 ) AS uploaders
106 FROM (
107 SELECT DISTINCT ON (package)
108 *
109 FROM (
110 SELECT
111 s.id AS source,
112 0 AS id,
113 s.source AS package,
114 s.version,
115 m.name
116 FROM
117 source AS s INNER JOIN
118 maintainer AS m ON s.maintainer = m.id INNER JOIN
119 src_associations AS sa ON s.id = sa.source INNER JOIN
120 suite on sa.suite = suite.id
121 WHERE
122 suite.archive_id = :archive_id
123 UNION SELECT
124 b.source,
125 b.id,
126 b.package,
127 b.version,
128 m.name
129 FROM
130 binaries AS b INNER JOIN
131 maintainer AS m ON b.maintainer = m.id INNER JOIN
132 bin_associations AS ba ON b.id = ba.bin INNER JOIN
133 suite on ba.suite = suite.id
134 WHERE
135 NOT :source_only AND
136 suite.archive_id = :archive_id
137 ) AS bs
138 ORDER BY package, version desc
139 ) AS bs LEFT OUTER JOIN
140 -- find all uploaders for a given source
141 src_uploaders AS su ON bs.source = su.source LEFT OUTER JOIN
142 maintainer AS mu ON su.maintainer = mu.id
143''').params(
144 archive_id=archive.archive_id,
145 source_only="True" if Options["Source"] else "False"
146))
148 Logger.log(['database'])
149 for entry in query:
150 maintainers[entry['package']] = entry['maintainer']
151 if all(x is None for x in entry['uploaders']): 151 ↛ exit, 151 ↛ 1522 missed branches: 1) line 151 didn't finish the generator expression on line 151, 2) line 151 didn't jump to line 152, because the condition on line 151 was never true
152 uploaders[entry['package']] = ['']
153 else:
154 uploaders[entry['package']] = entry['uploaders']
156 Logger.log(['files'])
157 # Process any additional Maintainer files (e.g. from pseudo
158 # packages)
159 for filename in extra_files: 159 ↛ 160line 159 didn't jump to line 160, because the loop on line 159 never started
160 with open(filename) as extrafile:
161 for line in extrafile.readlines():
162 line = re_comments.sub('', line).strip()
163 if line == "":
164 continue
165 (package, maintainer) = line.split(None, 1)
166 maintainers[package] = maintainer
167 uploaders[package] = [maintainer]
169 if Options["Print"]: 169 ↛ 173line 169 didn't jump to line 173, because the condition on line 169 was never false
170 for package in sorted(maintainers):
171 print(format(package, maintainers[package]), end='')
172 else:
173 with open('Maintainers', 'w') as maintainer_file, open('Uploaders', 'w') as uploader_file:
174 for package in sorted(uploaders):
175 maintainer_file.write(format(package, maintainers[package]))
176 for uploader in uploaders[package]:
177 uploader_file.write(format(package, uploader))
179 Logger.close()
181###############################################################################
184if __name__ == '__main__':
185 main()