1#! /usr/bin/env python3 

2 

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 

9 

10""" 

11 

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. 

16 

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. 

21 

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 

25 

26################################################################################ 

27 

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@ 

31 

32################################################################################ 

33 

34from daklib import daklog 

35from daklib import utils 

36from daklib.config import Config 

37from daklib.dbconn import * 

38from daklib.regexes import re_comments 

39 

40import apt_pkg 

41import sys 

42 

43from sqlalchemy.sql import text 

44 

45################################################################################ 

46 

47 

48def usage(exit_code=0): 

49 print("""Usage: dak make-maintainers [OPTION] -a ARCHIVE EXTRA_FILE[...] 

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

51 

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) 

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 

69def main(): 

70 cnf = Config() 

71 

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] = "" 

80 

81 extra_files = apt_pkg.parse_commandline(cnf.Cnf, Arguments, sys.argv) 

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

83 

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

85 usage() 

86 

87 Logger = daklog.Logger('make-maintainers') 

88 session = DBConn().session() 

89 

90 archive = session.query(Archive).filter_by(archive_name=Options['Archive']).one() 

91 

92 # dictionary packages to maintainer names 

93 maintainers = dict() 

94 # dictionary packages to list of uploader names 

95 uploaders = dict() 

96 

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)) 

147 

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'] 

155 

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] 

168 

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)) 

178 

179 Logger.close() 

180 

181############################################################################### 

182 

183 

184if __name__ == '__main__': 

185 main()