cruft.py 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. """
  2. helper functions for cruft-report
  3. @contact: Debian FTPMaster <ftpmaster@debian.org>
  4. @copyright 2011 Torsten Werner <twerner@debian.org>
  5. """
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2 of the License, or
  9. # (at your option) any later version.
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program; if not, write to the Free Software
  16. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. ################################################################################
  18. from __future__ import print_function
  19. from daklib.dbconn import *
  20. from sqlalchemy import func
  21. from sqlalchemy.orm import object_session
  22. def newer_version(lowersuite_name, highersuite_name, session, include_equal=False):
  23. '''
  24. Finds newer versions in lowersuite_name than in highersuite_name. Returns a
  25. list of tuples (source, higherversion, lowerversion) where higherversion is
  26. the newest version from highersuite_name and lowerversion is the newest
  27. version from lowersuite_name.
  28. '''
  29. lowersuite = get_suite(lowersuite_name, session)
  30. highersuite = get_suite(highersuite_name, session)
  31. query = session.query(DBSource.source, func.max(DBSource.version)). \
  32. with_parent(highersuite).group_by(DBSource.source)
  33. list = []
  34. for (source, higherversion) in query:
  35. q = session.query(func.max(DBSource.version)). \
  36. filter_by(source=source)
  37. if include_equal:
  38. q = q.filter(DBSource.version >= higherversion)
  39. else:
  40. q = q.filter(DBSource.version > higherversion)
  41. lowerversion = q.with_parent(lowersuite).group_by(DBSource.source).scalar()
  42. if lowerversion is not None:
  43. list.append((source, higherversion, lowerversion))
  44. list.sort()
  45. return list
  46. def get_package_names(suite):
  47. '''
  48. Returns a query that selects all distinct package names from suite ordered
  49. by package name.
  50. '''
  51. session = object_session(suite)
  52. return session.query(DBBinary.package).with_parent(suite). \
  53. group_by(DBBinary.package).order_by(DBBinary.package)
  54. class NamedSource(object):
  55. '''
  56. A source package identified by its name with all of its versions in a
  57. suite.
  58. '''
  59. def __init__(self, suite, source):
  60. self.source = source
  61. query = suite.sources.filter_by(source=source). \
  62. order_by(DBSource.version)
  63. self.versions = [src.version for src in query]
  64. def __str__(self):
  65. return "%s(%s)" % (self.source, ", ".join(self.versions))
  66. class DejavuBinary(object):
  67. '''
  68. A binary package identified by its name which gets built by multiple source
  69. packages in a suite. The architecture is ignored which leads to the
  70. following corner case, e.g.:
  71. If a source package 'foo-mips' that builds a binary package 'foo' on mips
  72. and another source package 'foo-mipsel' builds a binary package with the
  73. same name 'foo' on mipsel then the binary package 'foo' will be reported as
  74. built from multiple source packages.
  75. '''
  76. def __init__(self, suite, package):
  77. self.package = package
  78. session = object_session(suite)
  79. # We need a subquery to make sure that both binary and source packages
  80. # are in the right suite.
  81. bin_query = suite.binaries.filter_by(package=package).subquery()
  82. src_query = session.query(DBSource.source).with_parent(suite). \
  83. join(bin_query).order_by(DBSource.source).group_by(DBSource.source)
  84. self.sources = []
  85. if src_query.count() > 1:
  86. for source, in src_query:
  87. self.sources.append(str(NamedSource(suite, source)))
  88. def has_multiple_sources(self):
  89. 'Has the package been built by multiple sources?'
  90. return len(self.sources) > 1
  91. def __str__(self):
  92. return "%s built by: %s" % (self.package, ", ".join(self.sources))
  93. def report_multiple_source(suite):
  94. '''
  95. Reports binary packages built from multiple source package with different
  96. names.
  97. '''
  98. print("Built from multiple source packages")
  99. print("-----------------------------------")
  100. print()
  101. for package, in get_package_names(suite):
  102. binary = DejavuBinary(suite, package)
  103. if binary.has_multiple_sources():
  104. print(binary)
  105. print()
  106. def query_without_source(suite_id, session):
  107. """searches for arch: all packages from suite that do no longer
  108. reference a source package in the same suite
  109. subquery unique_binaries: selects all packages with only 1 version
  110. in suite since 'dak rm' does not allow to specify version numbers"""
  111. query = """
  112. with unique_binaries as
  113. (select package, max(version) as version, max(source) as source
  114. from bin_associations_binaries
  115. where architecture = 2 and suite = :suite_id
  116. group by package having count(*) = 1)
  117. select ub.package, ub.version
  118. from unique_binaries ub
  119. left join src_associations_src sas
  120. on ub.source = sas.src and sas.suite = :suite_id
  121. where sas.id is null
  122. order by ub.package"""
  123. return session.execute(query, {'suite_id': suite_id})
  124. def queryNBS(suite_id, session):
  125. """This one is really complex. It searches arch != all packages that
  126. are no longer built from current source packages in suite.
  127. temp table unique_binaries: will be populated with packages that
  128. have only one version in suite because 'dak rm' does not allow
  129. specifying version numbers
  130. temp table newest_binaries: will be populated with packages that are
  131. built from current sources
  132. subquery uptodate_arch: returns all architectures built from current
  133. sources
  134. subquery unique_binaries_uptodate_arch: returns all packages in
  135. architectures from uptodate_arch
  136. subquery unique_binaries_uptodate_arch_agg: same as
  137. unique_binaries_uptodate_arch but with column architecture
  138. aggregated to array
  139. subquery uptodate_packages: similar to uptodate_arch but returns all
  140. packages built from current sources
  141. subquery outdated_packages: returns all packages with architectures
  142. no longer built from current source
  143. """
  144. query = """
  145. with
  146. unique_binaries as
  147. (select
  148. bab.package,
  149. bab.architecture,
  150. max(bab.source) as source
  151. from bin_associations_binaries bab
  152. where bab.suite = :suite_id and bab.architecture > 2
  153. group by package, architecture having count(*) = 1),
  154. newest_binaries as
  155. (select ub.package, ub.architecture, nsa.source, nsa.version
  156. from unique_binaries ub
  157. join newest_src_association nsa
  158. on ub.source = nsa.src and nsa.suite = :suite_id),
  159. uptodate_arch as
  160. (select architecture, source, version
  161. from newest_binaries
  162. group by architecture, source, version),
  163. unique_binaries_uptodate_arch as
  164. (select ub.package, ub.architecture, ua.source, ua.version
  165. from unique_binaries ub
  166. join source s
  167. on ub.source = s.id
  168. join uptodate_arch ua
  169. on ub.architecture = ua.architecture and s.source = ua.source),
  170. unique_binaries_uptodate_arch_agg as
  171. (select ubua.package,
  172. array(select unnest(array_agg(a.arch_string)) order by 1) as arch_list,
  173. ubua.source, ubua.version
  174. from unique_binaries_uptodate_arch ubua
  175. join architecture a
  176. on ubua.architecture = a.id
  177. group by ubua.source, ubua.version, ubua.package),
  178. uptodate_packages as
  179. (select package, source, version
  180. from newest_binaries
  181. group by package, source, version),
  182. outdated_packages as
  183. (select array(select unnest(array_agg(package)) order by 1) as pkg_list,
  184. arch_list, source, version
  185. from unique_binaries_uptodate_arch_agg
  186. where package not in
  187. (select package from uptodate_packages)
  188. group by arch_list, source, version)
  189. select * from outdated_packages order by source"""
  190. return session.execute(query, {'suite_id': suite_id})