source.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. """ Queries related to source packages
  2. @contact: Debian FTPMaster <ftpmaster@debian.org>
  3. @copyright: 2014 Mark Hymers <mhy@debian.org>
  4. @copyright: 2014 Joerg Jaspert <joerg@debian.org>
  5. @license: GNU General Public License version 2 or later
  6. """
  7. from sqlalchemy import or_
  8. import bottle
  9. import json
  10. from typing import Optional
  11. from daklib.dbconn import DBConn, DBSource, Suite, DSCFile, PoolFile, SourceMetadata, MetadataKey
  12. from dakweb.webregister import QueryRegister
  13. @bottle.route('/dsc_in_suite/<suite>/<source>')
  14. def dsc_in_suite(suite: Optional[str] = None, source: Optional[str] = None) -> str:
  15. """
  16. Find all dsc files for a given source package name in a given suite.
  17. .. versionadded: December 2014
  18. :param suite: Name of the suite.
  19. :param source: Source package to query for.
  20. :return: List of dictionaries made out of
  21. - version
  22. - component
  23. - filename
  24. - filesize
  25. - sha256sum
  26. .. seealso:: :func:`~dakweb.queries.suite.suites` on how to receive a list of valid suites.
  27. """
  28. if suite is None:
  29. return bottle.HTTPError(503, 'Suite not specified.')
  30. if source is None:
  31. return bottle.HTTPError(503, 'Source package not specified.')
  32. s = DBConn().session()
  33. q = s.query(DSCFile).join(PoolFile)
  34. q = q.join(DBSource).join(Suite, DBSource.suites)
  35. q = q.filter(or_(Suite.suite_name == suite, Suite.codename == suite))
  36. q = q.filter(DBSource.source == source)
  37. q = q.filter(PoolFile.filename.endswith('.dsc'))
  38. ret = []
  39. for p in q:
  40. ret.append({'version': p.source.version,
  41. 'component': p.poolfile.component.component_name,
  42. 'filename': p.poolfile.filename,
  43. 'filesize': p.poolfile.filesize,
  44. 'sha256sum': p.poolfile.sha256sum})
  45. s.close()
  46. bottle.response.content_type = 'application/json; charset=UTF-8'
  47. return json.dumps(ret)
  48. QueryRegister().register_path('/dsc_in_suite', dsc_in_suite)
  49. @bottle.route('/file_in_archive/<filepattern:path>')
  50. def file_in_archive(filepattern: Optional[str] = None) -> str:
  51. """
  52. Check if a file pattern is known to the archive. Note that the
  53. patterns are matched against the location of the files in the
  54. pool, so for %tmux_2.3-1.dsc it will return t/tmux/tmux_2.3-1.dsc
  55. as filename.
  56. .. versionadded:: October 2016
  57. :param filepattern: Pattern of the filenames to match. SQL LIKE
  58. statement wildcard matches are supported, that
  59. is % for zero, one or more characters, _ for a
  60. single character match.
  61. :return: List of dictionaries made out of
  62. - filename
  63. - sha256sum
  64. - component
  65. """
  66. if filepattern is None:
  67. return bottle.HTTPError(503, 'Filepattern not specified.')
  68. s = DBConn().session()
  69. q = s.query(PoolFile)
  70. q = q.filter(PoolFile.filename.like(filepattern))
  71. ret = []
  72. for p in q:
  73. ret.append({'filename': p.filename,
  74. 'component': p.component.component_name,
  75. 'sha256sum': p.sha256sum})
  76. s.close()
  77. bottle.response.content_type = 'application/json; charset=UTF-8'
  78. return json.dumps(ret)
  79. QueryRegister().register_path('/file_in_archive', file_in_archive)
  80. @bottle.route('/sha256sum_in_archive/<sha256sum>')
  81. def sha256sum_in_archive(sha256sum: Optional[str] = None) -> str:
  82. """
  83. Check if files with matching sha256sums are known to the archive.
  84. .. versionadded:: June 2018
  85. :param sha256sum: SHA256 sum of the file.
  86. :return: List of dictionaries made out of
  87. - filename
  88. - sha256sum
  89. - component
  90. """
  91. if sha256sum is None:
  92. return bottle.HTTPError(503, 'sha256sum not specified.')
  93. s = DBConn().session()
  94. q = s.query(PoolFile)
  95. q = q.filter(PoolFile.sha256sum == sha256sum)
  96. ret = []
  97. for p in q:
  98. ret.append({'filename': p.filename,
  99. 'component': p.component.component_name,
  100. 'sha256sum': p.sha256sum})
  101. s.close()
  102. bottle.response.content_type = 'application/json; charset=UTF-8'
  103. return json.dumps(ret)
  104. QueryRegister().register_path('/sha256sum_in_archive', sha256sum_in_archive)
  105. @bottle.route('/sources_in_suite/<suite>')
  106. def sources_in_suite(suite: Optional[str] = None) -> str:
  107. """
  108. Returns all source packages and their versions in a given suite.
  109. .. versionadded:: December 2014
  110. :param suite: Name of the suite.
  111. :return: List of dictionaries made out of
  112. - source
  113. - version
  114. .. seealso:: :func:`~dakweb.queries.suite.suites` on how to receive a list of valid suites.
  115. """
  116. if suite is None:
  117. return bottle.HTTPError(503, 'Suite not specified.')
  118. s = DBConn().session()
  119. q = s.query(DBSource).join(Suite, DBSource.suites)
  120. q = q.filter(or_(Suite.suite_name == suite, Suite.codename == suite))
  121. ret = []
  122. for p in q:
  123. ret.append({'source': p.source,
  124. 'version': p.version})
  125. s.close()
  126. bottle.response.content_type = 'application/json; charset=UTF-8'
  127. return json.dumps(ret)
  128. QueryRegister().register_path('/sources_in_suite', sources_in_suite)
  129. @bottle.route('/all_sources')
  130. def all_sources() -> str:
  131. """
  132. Returns all source packages and their versions known to the archive
  133. (this includes NEW).
  134. :return: List of dictionaries made out of
  135. - source
  136. - version
  137. """
  138. s = DBConn().session()
  139. q = s.query(DBSource)
  140. ret = []
  141. for p in q:
  142. ret.append({'source': p.source,
  143. 'version': p.version})
  144. s.close()
  145. bottle.response.content_type = 'application/json; charset=UTF-8'
  146. return json.dumps(ret)
  147. QueryRegister().register_path('/all_sources', all_sources)
  148. @bottle.route('/source/by_metadata/<key>')
  149. def source_by_metadata(key: Optional[str] = None) -> str:
  150. """
  151. Finds all Debian source packages which have the specified metadata set.
  152. E.g., to find out the Maintainer of all source packages, query
  153. /source/by_metadata/Maintainer.
  154. :param key: Metadata key to search for.
  155. :return: A list of dictionaries of
  156. - source
  157. - metadata value
  158. """
  159. if not key:
  160. return bottle.HTTPError(503, 'Metadata key not specified.')
  161. s = DBConn().session()
  162. q = s.query(DBSource.source, SourceMetadata.value)
  163. q = q.join(SourceMetadata).join(MetadataKey)
  164. q = q.filter(MetadataKey.key == key)
  165. ret = []
  166. for p in q:
  167. ret.append({'source': p.source,
  168. 'metadata_value': p.value})
  169. s.close()
  170. bottle.response.content_type = 'application/json; charset=UTF-8'
  171. return json.dumps(ret)
  172. QueryRegister().register_path('/source/by_metadata', source_by_metadata)