Coverage for dak/make_maintainers.py: 62%

53 statements  

« prev     ^ index     » next       coverage.py v7.6.0, created at 2026-08-03 16:46 +0000

1""" 

2Generate Maintainers file used by e.g. the Debian Bug Tracking System 

3@contact: Debian FTP Master <ftpmaster@debian.org> 

4@copyright: 2000, 2001, 2002, 2003, 2004, 2006 James Troup <james@nocrew.org> 

5@copyright: 2011 Torsten Werner <twerner@debian.org> 

6@license: GNU General Public License version 2 or later 

7 

8""" 

9 

10# This program is free software; you can redistribute it and/or modify 

11# it under the terms of the GNU General Public License as published by 

12# the Free Software Foundation; either version 2 of the License, or 

13# (at your option) any later version. 

14 

15# This program is distributed in the hope that it will be useful, 

16# but WITHOUT ANY WARRANTY; without even the implied warranty of 

17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

18# GNU General Public License for more details. 

19 

20# You should have received a copy of the GNU General Public License 

21# along with this program; if not, write to the Free Software 

22# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 

23 

24################################################################################ 

25 

26# ``As opposed to "Linux sucks. Respect my academic authoritah, damn 

27# you!" or whatever all this hot air amounts to.'' 

28# -- ajt@ in _that_ thread on debian-devel@ 

29 

30################################################################################ 

31 

32import sys 

33 

34import apt_pkg 

35from sqlalchemy.sql import select, text 

36 

37from daklib import daklog 

38from daklib.config import Config 

39from daklib.dbconn import Archive, DBConn 

40from daklib.regexes import re_comments 

41 

42################################################################################ 

43 

44 

45def usage(exit_code=0): 

46 print( 

47 """Usage: dak make-maintainers [OPTION] -a ARCHIVE EXTRA_FILE[...] 

48Generate an index of packages <=> Maintainers / Uploaders. 

49 

50 -a, --archive=ARCHIVE archive to take packages from 

51 -s, --source output source packages only 

52 -p, --print print package list to stdout instead of writing it to files 

53 -h, --help show this help and exit 

54""" 

55 ) 

56 sys.exit(exit_code) 

57 

58 

59################################################################################ 

60 

61 

62def format(package, person): 

63 """Return a string nicely formatted for writing to the output file.""" 

64 return "%-20s %s\n" % (package, person) 

65 

66 

67################################################################################ 

68 

69 

70def main(): 

71 cnf = Config() 

72 

73 Arguments = [ 

74 ("h", "help", "Make-Maintainers::Options::Help"), 

75 ("a", "archive", "Make-Maintainers::Options::Archive", "HasArg"), 

76 ("s", "source", "Make-Maintainers::Options::Source"), 

77 ("p", "print", "Make-Maintainers::Options::Print"), 

78 ] 

79 for i in ["Help", "Source", "Print"]: 

80 key = "Make-Maintainers::Options::%s" % i 

81 if key not in cnf: 81 ↛ 79line 81 didn't jump to line 79 because the condition on line 81 was always true

82 cnf[key] = "" 

83 

84 extra_files = apt_pkg.parse_commandline(cnf.Cnf, Arguments, sys.argv) # type: ignore[attr-defined] 

85 Options = cnf.subtree("Make-Maintainers::Options") 

86 

87 if Options["Help"] or not Options.get("Archive"): 

88 usage() 

89 

90 Logger = daklog.Logger("make-maintainers") 

91 session = DBConn().session() 

92 

93 archive = session.execute( 

94 select(Archive).filter_by(archive_name=Options["Archive"]) 

95 ).scalar_one() 

96 

97 # dictionary packages to maintainer names 

98 maintainers = {} 

99 # dictionary packages to list of uploader names 

100 uploaders = {} 

101 

102 query = session.execute( 

103 text( 

104 """ 

105SELECT 

106 bs.package, 

107 bs.name AS maintainer, 

108 array_agg(mu.name) OVER ( 

109 PARTITION BY bs.source, bs.id 

110 ORDER BY mu.name 

111 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING 

112 ) AS uploaders 

113 FROM ( 

114 SELECT DISTINCT ON (package) 

115 * 

116 FROM ( 

117 SELECT 

118 s.id AS source, 

119 0 AS id, 

120 s.source AS package, 

121 s.version, 

122 m.name 

123 FROM 

124 source AS s INNER JOIN 

125 maintainer AS m ON s.maintainer = m.id INNER JOIN 

126 src_associations AS sa ON s.id = sa.source INNER JOIN 

127 suite on sa.suite = suite.id 

128 WHERE 

129 suite.archive_id = :archive_id 

130 UNION SELECT 

131 b.source, 

132 b.id, 

133 b.package, 

134 b.version, 

135 m.name 

136 FROM 

137 binaries AS b INNER JOIN 

138 maintainer AS m ON b.maintainer = m.id INNER JOIN 

139 bin_associations AS ba ON b.id = ba.bin INNER JOIN 

140 suite on ba.suite = suite.id 

141 WHERE 

142 NOT :source_only AND 

143 suite.archive_id = :archive_id 

144 ) AS bs 

145 ORDER BY package, version desc 

146 ) AS bs LEFT OUTER JOIN 

147 -- find all uploaders for a given source 

148 src_uploaders AS su ON bs.source = su.source LEFT OUTER JOIN 

149 maintainer AS mu ON su.maintainer = mu.id 

150""" 

151 ).params( 

152 archive_id=archive.archive_id, 

153 source_only="True" if Options["Source"] else "False", 

154 ) 

155 ) 

156 

157 Logger.log(["database"]) 

158 for entry in query.mappings(): 

159 maintainers[entry["package"]] = entry["maintainer"] 

160 if all(x is None for x in entry["uploaders"]): 160 ↛ exit,   160 ↛ 1612 missed branches: 1) line 160 didn't finish the generator expression on line 160, 2) line 160 didn't jump to line 161 because the condition on line 160 was never true

161 uploaders[entry["package"]] = [""] 

162 else: 

163 uploaders[entry["package"]] = entry["uploaders"] 

164 

165 Logger.log(["files"]) 

166 # Process any additional Maintainer files (e.g. from pseudo 

167 # packages) 

168 for filename in extra_files: 168 ↛ 169line 168 didn't jump to line 169 because the loop on line 168 never started

169 with open(filename) as extrafile: 

170 for line in extrafile: 

171 line = re_comments.sub("", line).strip() 

172 if line == "": 

173 continue 

174 (package, maintainer) = line.split(None, 1) 

175 maintainers[package] = maintainer 

176 uploaders[package] = [maintainer] 

177 

178 if Options["Print"]: 178 ↛ 182line 178 didn't jump to line 182 because the condition on line 178 was always true

179 for package in sorted(maintainers): 

180 print(format(package, maintainers[package]), end="") 

181 else: 

182 with ( 

183 open("Maintainers", "w") as maintainer_file, 

184 open("Uploaders", "w") as uploader_file, 

185 ): 

186 for package in sorted(uploaders): 

187 maintainer_file.write(format(package, maintainers[package])) 

188 uploader_file.writelines( 

189 format(package, uploader) for uploader in uploaders[package] 

190 ) 

191 

192 Logger.close()