cruft.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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 daklib.dbconn import *
  19. from sqlalchemy import func
  20. from sqlalchemy.orm import object_session
  21. def newer_version(lowersuite_name, highersuite_name, session):
  22. '''
  23. Finds newer versions in lowersuite_name than in highersuite_name. Returns a
  24. list of tuples (source, higherversion, lowerversion) where higherversion is
  25. the newest version from highersuite_name and lowerversion is the newest
  26. version from lowersuite_name.
  27. '''
  28. lowersuite = get_suite(lowersuite_name, session)
  29. highersuite = get_suite(highersuite_name, session)
  30. query = session.query(DBSource.source, func.max(DBSource.version)). \
  31. with_parent(highersuite).group_by(DBSource.source)
  32. list = []
  33. for (source, higherversion) in query:
  34. lowerversion = session.query(func.max(DBSource.version)). \
  35. filter_by(source = source).filter(DBSource.version > higherversion). \
  36. with_parent(lowersuite).group_by(DBSource.source).scalar()
  37. if lowerversion is not None:
  38. list.append((source, higherversion, lowerversion))
  39. list.sort()
  40. return list
  41. def get_package_names(suite):
  42. '''
  43. Returns a query that selects all distinct package names from suite ordered
  44. by package name.
  45. '''
  46. session = object_session(suite)
  47. return session.query(DBBinary.package).with_parent(suite). \
  48. group_by(DBBinary.package).order_by(DBBinary.package)
  49. class NamedSource(object):
  50. '''
  51. A source package identified by its name with all of its versions in a
  52. suite.
  53. '''
  54. def __init__(self, suite, source):
  55. self.source = source
  56. query = suite.sources.filter_by(source = source). \
  57. order_by(DBSource.version)
  58. self.versions = [src.version for src in query]
  59. def __str__(self):
  60. return "%s(%s)" % (self.source, ", ".join(self.versions))
  61. class DejavuBinary(object):
  62. '''
  63. A binary package identified by its name which gets built by multiple source
  64. packages in a suite. The architecture is ignored which leads to the
  65. following corner case, e.g.:
  66. If a source package 'foo-mips' that builds a binary package 'foo' on mips
  67. and another source package 'foo-mipsel' builds a binary package with the
  68. same name 'foo' on mipsel then the binary package 'foo' will be reported as
  69. built from multiple source packages.
  70. '''
  71. def __init__(self, suite, package):
  72. self.package = package
  73. session = object_session(suite)
  74. # We need a subquery to make sure that both binary and source packages
  75. # are in the right suite.
  76. bin_query = suite.binaries.filter_by(package = package).subquery()
  77. src_query = session.query(DBSource.source).with_parent(suite). \
  78. join(bin_query).order_by(DBSource.source).group_by(DBSource.source)
  79. self.sources = []
  80. if src_query.count() > 1:
  81. for source, in src_query:
  82. self.sources.append(str(NamedSource(suite, source)))
  83. def has_multiple_sources(self):
  84. 'Has the package been built by multiple sources?'
  85. return len(self.sources) > 1
  86. def __str__(self):
  87. return "%s built by: %s" % (self.package, ", ".join(self.sources))
  88. def report_multiple_source(suite):
  89. '''
  90. Reports binary packages built from multiple source package with different
  91. names.
  92. '''
  93. print "Built from multiple source packages"
  94. print "-----------------------------------"
  95. print
  96. for package, in get_package_names(suite):
  97. binary = DejavuBinary(suite, package)
  98. if binary.has_multiple_sources():
  99. print binary
  100. print
  101. def query_without_source(suite_id, session):
  102. """searches for arch: all packages from suite that do no longer
  103. reference a source package in the same suite
  104. subquery unique_binaries: selects all packages with only 1 version
  105. in suite since 'dak rm' does not allow to specify version numbers"""
  106. query = """
  107. with unique_binaries as
  108. (select package, max(version) as version, max(source) as source
  109. from bin_associations_binaries
  110. where architecture = 2 and suite = :suite_id
  111. group by package having count(*) = 1)
  112. select ub.package, ub.version
  113. from unique_binaries ub
  114. left join src_associations_src sas
  115. on ub.source = sas.src and sas.suite = :suite_id
  116. where sas.id is null
  117. order by ub.package"""
  118. return session.execute(query, {'suite_id': suite_id})
  119. def queryNBS(suite_id, session):
  120. """This one is really complex. It searches arch != all packages that
  121. are no longer built from current source packages in suite.
  122. temp table unique_binaries: will be populated with packages that
  123. have only one version in suite because 'dak rm' does not allow
  124. specifying version numbers
  125. temp table newest_binaries: will be populated with packages that are
  126. built from current sources
  127. subquery uptodate_arch: returns all architectures built from current
  128. sources
  129. subquery unique_binaries_uptodate_arch: returns all packages in
  130. architectures from uptodate_arch
  131. subquery unique_binaries_uptodate_arch_agg: same as
  132. unique_binaries_uptodate_arch but with column architecture
  133. aggregated to array
  134. subquery uptodate_packages: similar to uptodate_arch but returns all
  135. packages built from current sources
  136. subquery outdated_packages: returns all packages with architectures
  137. no longer built from current source
  138. """
  139. query = """
  140. create temp table unique_binaries (
  141. package text not null,
  142. architecture integer not null,
  143. source integer not null);
  144. insert into unique_binaries
  145. select bab.package, bab.architecture, max(bab.source)
  146. from bin_associations_binaries bab
  147. where bab.suite = :suite_id and bab.architecture > 2
  148. group by package, architecture having count(*) = 1;
  149. create temp table newest_binaries (
  150. package text not null,
  151. architecture integer not null,
  152. source text not null,
  153. version debversion not null);
  154. insert into newest_binaries
  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. with 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})