#!/usr/bin/env python3 # Copyright 2011 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 import optparse import os import random import types os.environ["PORTDIR_OVERLAY"] = "" import portage def process_deps(deps, use=None): if not use: use = [] result = [] for index, x in enumerate(deps): if type(x) == list: continue elif x == "||": # Any-of. result.extend(process_deps(deps[index + 1], use)) elif x[-1] == "?": # Use-conditional. result.extend(process_deps(deps[index + 1], use + [x[:-1]])) elif x[0] == "!": # Blocker. result.append((portage.dep_getkey(x), True, use)) else: result.append((portage.dep_getkey(x), False, use)) return result if __name__ == "__main__": parser = optparse.OptionParser() parser.add_option("-i", "--input", dest="input_filename", default="package.keywords", help="Input filename for generated package.keywords file [default=%default]") parser.add_option("-o", "--output", dest="output_filename", default="package.rdeps", help="Output filename for generated package.rdeps file [default=%default]") parser.add_option("-l", "--limit", dest="limit", type="int", default=-1, help="Limit of reverse dependencies per package. Default is no limit.") parser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False) (options, args) = parser.parse_args() if not options.input_filename: parser.error("--input option is required") if not options.output_filename: parser.error("--output option is required") if args: parser.error("unrecognized command-line args") reverse_deps = {} for pkg in portage.portdb.cp_all(): deps = [] for match in portage.portdb.match(pkg): deps.extend(process_deps(portage.dep.paren_reduce(portage.portdb.aux_get(match, ['DEPEND', 'RDEPEND', 'PDEPEND'])[0]))) for cp, blocker, use in deps: if blocker: continue if cp not in reverse_deps: reverse_deps[cp] = {} if pkg not in reverse_deps[cp]: reverse_deps[cp][pkg] = [] if use not in reverse_deps[cp][pkg]: reverse_deps[cp][pkg].append(use) with open(options.input_filename, "r") as input_file: with open(options.output_filename, "w") as output_file: for line in input_file: if line == "\n" or line.startswith("#"): continue if not line.endswith("\n"): line += "\n" cpv = line[1:-1] pn = portage.versions.pkgsplit(cpv)[0] if pn in reverse_deps: output_file.write("# Reverse dependencies for %s\n" % pn) if options.limit == -1: cps = reverse_deps[pn] else: cps = random.sample(reverse_deps[pn], min(options.limit, len(reverse_deps[pn]))) for cp in cps: use_combinations = reverse_deps[pn][cp] if use_combinations != [[]]: output_file.write("# One of the following USE flag combinations is required:\n") for use_combination in use_combinations: output_file.write("#\t%s\n" % ",".join(use_combination)) output_file.write("%s\n" % cp) elif options.verbose: print('No reverse dependencies for %s' % pn)