repo-analyzer/analyze-repo-closure.py

198 lines
7 KiB
Python
Raw Permalink Normal View History

2014-11-06 20:49:46 +03:00
#!/usr/bin/python
# -*- coding: utf-8 -*-
import os
import sys
import argparse
import sqlite3
import string
import rpm
import re
import gettext
prepare_repodb = __import__("prepare-repodb")
gettext.install('urpm-tools')
DB = 'repo.db'
def parseargs(args):
parser = argparse.ArgumentParser(description=_('Find a closed subset of the repository\'s for a given list of packages.'))
parser.add_argument('packages_lst', metavar='packages.lst',
help=('path to packages.lst'))
parser.add_argument('--repo', action='append', nargs='+', required=True,
metavar='REPO', help=_('URL or name of a repository'))
opts = parser.parse_args()
return opts
def main(args):
options = parseargs(args)
with open(options.packages_lst, 'r') as f:
ks_cfg = f.read()
section = None
in_packages = False
sel_packages = []
for line in ks_cfg.split('\n'):
ls = line.strip()
if ls and not ls.startswith('#'):
sel_packages.append(ls)
conn = sqlite3.connect(DB)
c = conn.cursor()
repodirs = []
for repo in options.repo:
print repo
rid = c.execute("""
SELECT id FROM repodirs WHERE name = ? OR url = ?
""", [repo[0], repo[0]]).fetchall()
if not rid:
print 'Repository "%s" not found.' % repo
exit(1)
repodirs.append(rid[0][0])
if not repodirs:
print 'No repositories specified.'
exit(1)
if not sel_packages:
print 'No packages specified.'
exit(1)
in_repodirs = ','.join(str(id) for id in repodirs)
package_ids = []
for spackage in sel_packages:
packages_found = c.execute("""
SELECT id, nvra, version, release FROM packages WHERE repodir_id IN (%s) AND name = ?
""" % in_repodirs, [spackage]).fetchall()
if not packages_found:
print 'Package "%s" not found!' % spackage
continue
pid = None
if len(packages_found) > 1:
chosen_nvra = None
chosen_version = None
for vpid in packages_found:
better_found = pid is None
verrel = (vpid[2] if vpid[2] is not None else '') + '-' + \
(vpid[3] if vpid[3] is not None else '')
if not better_found:
better_found = prepare_repodb.version_ok(chosen_version,
prepare_repodb.RPMSENSE_GREATER,
verrel)
if better_found:
pid = vpid[0]
chosen_nvra = vpid[1]
chosen_version = verrel
print ('Multiple versions of "%s" found (%s). Choosing latest: %s.' %
(spackage, ', '.join(cp[1] for cp in packages_found), chosen_nvra))
else:
pid = packages_found[0][0]
package_ids.append(pid)
pre_package_cnt = 0
src_package_cnt = 0
src_package_ids = []
while True:
src_package_cnt = len(src_package_ids)
print >> sys.stderr, "packages processed:", pre_package_cnt, len(package_ids)
if pre_package_cnt == len(package_ids):
break
in_next_packages = ','.join(str(id) for id in package_ids[pre_package_cnt:])
pre_package_cnt = len(package_ids)
for lost_src in c.execute("""
SELECT '"' || nvra || '" (' || sourcerpm || ')' FROM packages
WHERE id IN (%s) AND
sourcerpm IS NOT NULL AND sourcerpm_package IS NULL
ORDER BY nvra
""" % in_next_packages):
print 'Source rpm for package %s not found!' % lost_src
in_packages = ','.join(str(id) for id in package_ids)
in_src_packages = ','.join(str(id) for id in src_package_ids) \
if len(src_package_ids) > 0 else '-1'
for src_package in c.execute("""
SELECT sourcerpm_package FROM packages
WHERE id IN (%s) AND sourcerpm IS NOT NULL AND sourcerpm_package IS NOT NULL
AND sourcerpm_package NOT IN (%s)
""" % (in_packages, in_src_packages)):
src_package_ids.append(src_package[0])
print >> sys.stderr, "src packages processed:", src_package_cnt, len(src_package_ids)
if src_package_cnt == len(src_package_ids):
break
while True:
package_cnt = len(package_ids)
in_packages = ','.join(str(id) for id in package_ids + src_package_ids)
for required_package in c.execute("""
SELECT packages.id, packages.name, nvra
FROM packages, package_requires_res
WHERE packages.id = package_requires_res.dep_package_id AND
packages.repodir_id IN (%s) AND
package_requires_res.package_id IN (%s) AND
packages.id NOT IN (%s)
ORDER BY packages.name
""" % (in_repodirs, in_packages, in_packages)):
package_ids.append(required_package[0])
if package_cnt == len(package_ids):
break
in_src_packages = ','.join(str(id) for id in src_package_ids) \
if len(src_package_ids) > 0 else '-1'
repo_packages_cnt = 0
pre_repodir_id = -1
for reduntant_package in c.execute("""
SELECT repodir_id, repodirs.name, packages.id, packages.nvra
FROM packages, repodirs
WHERE packages.repodir_id = repodirs.id AND
packages.id IN (%s)
ORDER BY repodir_id, nvra
""" % (in_src_packages)):
(repodir_id, repodir_name, package_nvra) = \
(reduntant_package[0], reduntant_package[1], reduntant_package[3])
if pre_repodir_id != repodir_id:
if pre_repodir_id == -1:
print 'Required source packages:'
else:
print 'Total: %d' % repo_packages_cnt
print ''
print '%d) %s' % (repodir_id, repodir_name)
pre_repodir_id = repodir_id
repo_packages_cnt = 0
print '\t%s' % package_nvra
repo_packages_cnt += 1
if pre_repodir_id != -1:
print 'Total: %d' % repo_packages_cnt
print ''
repo_packages_cnt = 0
pre_repodir_id = -1
for reduntant_package in c.execute("""
SELECT repodir_id, repodirs.name, packages.id, packages.nvra
FROM packages, repodirs
WHERE packages.repodir_id = repodirs.id AND
repodirs.name IN (SELECT sources FROM repodirs WHERE id IN (%s)) AND
packages.id NOT IN (%s)
ORDER BY repodir_id, nvra
""" % (in_repodirs, in_src_packages)):
(repodir_id, repodir_name, package_nvra) = \
(reduntant_package[0], reduntant_package[1], reduntant_package[3])
if pre_repodir_id != repodir_id:
if pre_repodir_id == -1:
print 'Redundant source packages:'
else:
print 'Total: %d' % repo_packages_cnt
print ''
print '%d) %s' % (repodir_id, repodir_name)
pre_repodir_id = repodir_id
repo_packages_cnt = 0
print '\t%s' % package_nvra
repo_packages_cnt += 1
if pre_repodir_id != -1:
print 'Total: %d' % repo_packages_cnt
print ''
conn.rollback()
if __name__ == "__main__":
main(sys.argv)