1""" Queries related to source packages 

2 

3@contact: Debian FTPMaster <ftpmaster@debian.org> 

4@copyright: 2014 Mark Hymers <mhy@debian.org> 

5@copyright: 2014 Joerg Jaspert <joerg@debian.org> 

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

7""" 

8 

9from sqlalchemy import or_ 

10import bottle 

11import json 

12from typing import Optional 

13 

14from daklib.dbconn import DBConn, DBSource, Suite, DSCFile, PoolFile, SourceMetadata, MetadataKey 

15from dakweb.webregister import QueryRegister 

16 

17 

18@bottle.route('/dsc_in_suite/<suite>/<source>') 

19def dsc_in_suite(suite: Optional[str] = None, source: Optional[str] = None) -> str: 

20 """ 

21 Find all dsc files for a given source package name in a given suite. 

22 

23 .. versionadded: December 2014 

24 

25 :param suite: Name of the suite. 

26 :param source: Source package to query for. 

27 :return: List of dictionaries made out of 

28 - version 

29 - component 

30 - filename 

31 - filesize 

32 - sha256sum 

33 

34 .. seealso:: :func:`~dakweb.queries.suite.suites` on how to receive a list of valid suites. 

35 """ 

36 if suite is None: 

37 return bottle.HTTPError(503, 'Suite not specified.') 

38 if source is None: 

39 return bottle.HTTPError(503, 'Source package not specified.') 

40 

41 s = DBConn().session() 

42 q = s.query(DSCFile).join(PoolFile) 

43 q = q.join(DBSource).join(Suite, DBSource.suites) 

44 q = q.filter(or_(Suite.suite_name == suite, Suite.codename == suite)) 

45 q = q.filter(DBSource.source == source) 

46 q = q.filter(PoolFile.filename.endswith('.dsc')) 

47 ret = [] 

48 for p in q: 

49 ret.append({'version': p.source.version, 

50 'component': p.poolfile.component.component_name, 

51 'filename': p.poolfile.filename, 

52 'filesize': p.poolfile.filesize, 

53 'sha256sum': p.poolfile.sha256sum}) 

54 

55 s.close() 

56 

57 bottle.response.content_type = 'application/json; charset=UTF-8' 

58 return json.dumps(ret) 

59 

60 

61QueryRegister().register_path('/dsc_in_suite', dsc_in_suite) 

62 

63 

64@bottle.route('/file_in_archive/<filepattern:path>') 

65def file_in_archive(filepattern: Optional[str] = None) -> str: 

66 """ 

67 Check if a file pattern is known to the archive. Note that the 

68 patterns are matched against the location of the files in the 

69 pool, so for %tmux_2.3-1.dsc it will return t/tmux/tmux_2.3-1.dsc 

70 as filename. 

71 

72 .. versionadded:: October 2016 

73 

74 :param filepattern: Pattern of the filenames to match. SQL LIKE 

75 statement wildcard matches are supported, that 

76 is % for zero, one or more characters, _ for a 

77 single character match. 

78 :return: List of dictionaries made out of 

79 - filename 

80 - sha256sum 

81 - component 

82 """ 

83 if filepattern is None: 

84 return bottle.HTTPError(503, 'Filepattern not specified.') 

85 

86 s = DBConn().session() 

87 q = s.query(PoolFile) 

88 q = q.filter(PoolFile.filename.like(filepattern)) 

89 ret = [] 

90 

91 for p in q: 

92 ret.append({'filename': p.filename, 

93 'component': p.component.component_name, 

94 'sha256sum': p.sha256sum}) 

95 

96 s.close() 

97 

98 bottle.response.content_type = 'application/json; charset=UTF-8' 

99 return json.dumps(ret) 

100 

101 

102QueryRegister().register_path('/file_in_archive', file_in_archive) 

103 

104 

105@bottle.route('/sha256sum_in_archive/<sha256sum>') 

106def sha256sum_in_archive(sha256sum: Optional[str] = None) -> str: 

107 """ 

108 Check if files with matching sha256sums are known to the archive. 

109 

110 .. versionadded:: June 2018 

111 

112 :param sha256sum: SHA256 sum of the file. 

113 :return: List of dictionaries made out of 

114 - filename 

115 - sha256sum 

116 - component 

117 """ 

118 if sha256sum is None: 

119 return bottle.HTTPError(503, 'sha256sum not specified.') 

120 

121 s = DBConn().session() 

122 q = s.query(PoolFile) 

123 q = q.filter(PoolFile.sha256sum == sha256sum) 

124 ret = [] 

125 

126 for p in q: 

127 ret.append({'filename': p.filename, 

128 'component': p.component.component_name, 

129 'sha256sum': p.sha256sum}) 

130 

131 s.close() 

132 

133 bottle.response.content_type = 'application/json; charset=UTF-8' 

134 return json.dumps(ret) 

135 

136 

137QueryRegister().register_path('/sha256sum_in_archive', sha256sum_in_archive) 

138 

139 

140@bottle.route('/sources_in_suite/<suite>') 

141def sources_in_suite(suite: Optional[str] = None) -> str: 

142 """ 

143 Returns all source packages and their versions in a given suite. 

144 

145 .. versionadded:: December 2014 

146 

147 :param suite: Name of the suite. 

148 :return: List of dictionaries made out of 

149 - source 

150 - version 

151 

152 .. seealso:: :func:`~dakweb.queries.suite.suites` on how to receive a list of valid suites. 

153 """ 

154 if suite is None: 

155 return bottle.HTTPError(503, 'Suite not specified.') 

156 

157 s = DBConn().session() 

158 q = s.query(DBSource).join(Suite, DBSource.suites) 

159 q = q.filter(or_(Suite.suite_name == suite, Suite.codename == suite)) 

160 ret = [] 

161 for p in q: 

162 ret.append({'source': p.source, 

163 'version': p.version}) 

164 

165 s.close() 

166 

167 bottle.response.content_type = 'application/json; charset=UTF-8' 

168 return json.dumps(ret) 

169 

170 

171QueryRegister().register_path('/sources_in_suite', sources_in_suite) 

172 

173 

174@bottle.route('/all_sources') 

175def all_sources() -> str: 

176 """ 

177 Returns all source packages and their versions known to the archive 

178 (this includes NEW). 

179 

180 :return: List of dictionaries made out of 

181 - source 

182 - version 

183 """ 

184 

185 s = DBConn().session() 

186 q = s.query(DBSource) 

187 ret = [] 

188 for p in q: 

189 ret.append({'source': p.source, 

190 'version': p.version}) 

191 

192 s.close() 

193 

194 bottle.response.content_type = 'application/json; charset=UTF-8' 

195 return json.dumps(ret) 

196 

197 

198QueryRegister().register_path('/all_sources', all_sources) 

199 

200 

201@bottle.route('/source/by_metadata/<key>') 

202def source_by_metadata(key: Optional[str] = None) -> str: 

203 """ 

204 

205 Finds all Debian source packages which have the specified metadata set. 

206 

207 E.g., to find out the Maintainer of all source packages, query 

208 /source/by_metadata/Maintainer. 

209 

210 :param key: Metadata key to search for. 

211 :return: A list of dictionaries of 

212 - source 

213 - metadata value 

214 """ 

215 

216 if not key: 

217 return bottle.HTTPError(503, 'Metadata key not specified.') 

218 

219 s = DBConn().session() 

220 q = s.query(DBSource.source, SourceMetadata.value) 

221 q = q.join(SourceMetadata).join(MetadataKey) 

222 q = q.filter(MetadataKey.key == key) 

223 ret = [] 

224 for p in q: 

225 ret.append({'source': p.source, 

226 'metadata_value': p.value}) 

227 s.close() 

228 

229 bottle.response.content_type = 'application/json; charset=UTF-8' 

230 return json.dumps(ret) 

231 

232 

233QueryRegister().register_path('/source/by_metadata', source_by_metadata)