From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from pigeon.gentoo.org ([208.92.234.80] helo=lists.gentoo.org) by finch.gentoo.org with esmtp (Exim 4.60) (envelope-from <gentoo-commits+bounces-362095-garchives=archives.gentoo.org@lists.gentoo.org>) id 1Qgkn2-0002LD-10 for garchives@archives.gentoo.org; Tue, 12 Jul 2011 21:46:48 +0000 Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id CA14421C0AF; Tue, 12 Jul 2011 21:45:25 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) by pigeon.gentoo.org (Postfix) with ESMTP id 336A721C0AF for <gentoo-commits@lists.gentoo.org>; Tue, 12 Jul 2011 21:45:25 +0000 (UTC) Received: from pelican.gentoo.org (unknown [66.219.59.40]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 8CD311B4086 for <gentoo-commits@lists.gentoo.org>; Tue, 12 Jul 2011 21:45:24 +0000 (UTC) Received: from localhost.localdomain (localhost [127.0.0.1]) by pelican.gentoo.org (Postfix) with ESMTP id EBD058003F for <gentoo-commits@lists.gentoo.org>; Tue, 12 Jul 2011 21:45:23 +0000 (UTC) From: "Paul Varner" <fuzzyray@gentoo.org> To: gentoo-commits@lists.gentoo.org Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Paul Varner" <fuzzyray@gentoo.org> Message-ID: <9ccb3af94c0b2ffc12e8c9b149f9894af5fa81a4.fuzzyray@gentoo> Subject: [gentoo-commits] proj/gentoolkit:gentoolkit commit in: pym/gentoolkit/revdep_rebuild/ X-VCS-Repository: proj/gentoolkit X-VCS-Files: pym/gentoolkit/revdep_rebuild/revdep-rebuild.py X-VCS-Directories: pym/gentoolkit/revdep_rebuild/ X-VCS-Committer: fuzzyray X-VCS-Committer-Name: Paul Varner X-VCS-Revision: 9ccb3af94c0b2ffc12e8c9b149f9894af5fa81a4 Date: Tue, 12 Jul 2011 21:45:23 +0000 (UTC) Precedence: bulk List-Post: <mailto:gentoo-commits@lists.gentoo.org> List-Help: <mailto:gentoo-commits+help@lists.gentoo.org> List-Unsubscribe: <mailto:gentoo-commits+unsubscribe@lists.gentoo.org> List-Subscribe: <mailto:gentoo-commits+subscribe@lists.gentoo.org> List-Id: Gentoo Linux mail <gentoo-commits.gentoo.org> X-BeenThere: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: quoted-printable X-Archives-Salt: X-Archives-Hash: b8a2d503bff5ae4a9ce9ef941f7c6453 commit: 9ccb3af94c0b2ffc12e8c9b149f9894af5fa81a4 Author: lis.slawek <lis.slawek <AT> 5234894e-44cd-11de-9a4c-a76526a19= 3c6> AuthorDate: Mon Oct 25 09:24:47 2010 +0000 Commit: Paul Varner <fuzzyray <AT> gentoo <DOT> org> CommitDate: Tue Jul 12 21:29:00 2011 +0000 URL: http://git.overlays.gentoo.org/gitweb/?p=3Dproj/gentoolkit.gi= t;a=3Dcommit;h=3D9ccb3af9 Initial revision of revdep-rebuild python version git-svn-id: http://genscripts.googlecode.com/svn/trunk/gentoolkit@471 523= 4894e-44cd-11de-9a4c-a76526a193c6 --- pym/gentoolkit/revdep_rebuild/revdep-rebuild.py | 723 +++++++++++++++++= ++++++ 1 files changed, 723 insertions(+), 0 deletions(-) diff --git a/pym/gentoolkit/revdep_rebuild/revdep-rebuild.py b/pym/gentoo= lkit/revdep_rebuild/revdep-rebuild.py new file mode 100755 index 0000000..23298f9 --- /dev/null +++ b/pym/gentoolkit/revdep_rebuild/revdep-rebuild.py @@ -0,0 +1,723 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + + +# Author: S=C5=82awomir Lis <lis.slawek@gmail.com> +# revdep-rebuild original author: Stanislav Brabec +# revdep-rebuild original rewrite Author: Michael A. Smith +# Current Maintainer: Paul Varner <fuzzyray@gentoo.org> + +# Creation date: 2010/10/17 +# License: BSD + +import subprocess +import os +import sys +import re +import getopt +import signal +import stat +import time +import glob +import portage +from portage import portdb +from portage.output import bold, red, blue, yellow, green, nocolor + +APP_NAME =3D sys.argv[0] +VERSION =3D '0.1-r2' + + +__productname__ =3D "revdep-ng" + + + +# configuration variables +DEFAULT_LD_FILE =3D 'etc/ld.so.conf' +DEFAULT_ENV_FILE =3D 'etc/profile.env' + + +# global variables +PRINT_DEBUG =3D False #program in debug mode + +PRETEND =3D False #pretend only +EXACT =3D False #exact package version +USE_TMP_FILES =3D True #if program should use temporary files from previ= ous run +DEFAULT_TMP_DIR =3D '/tmp/revdep-rebuild' #cache default location +VERBOSITY =3D 1 #verbosity level; 0-quiet, 1-norm., 2-verbose + +IS_DEV =3D True #True for dev. version, False for stable +NO_PRETEND =3D False #used when IS_DEV is True, forces to call emerge f= rom script + + + +# util. functions +def call_program(args): + ''' Calls program with specified parameters and returns stdout ''' + subp =3D subprocess.Popen(args, stdout=3Dsubprocess.PIPE, \ + stderr=3Dsubprocess.PIPE) + stdout, stderr =3D subp.communicate() + return stdout + + +def print_v(verbosity, args): + """Prints to stdout according to the verbosity level=20 + and the global VERBOSITY level + =20 + @param verbosity: integer + @param args: string to print + """ + if verbosity > VERBOSITY: + return + print args + + +def exithandler(signum, frame): + print 'Signal catched!' + print 'Bye!' + signal.signal(signal.SIGINT, signal.SIG_IGN) + signal.signal(signal.SIGTERM, signal.SIG_IGN) + sys.exit(1) + + +def print_usage(): + print APP_NAME + ': (' + VERSION +')' + print + print 'This is free software; see the source for copying conditions.= ' + print + print 'Usage: ' + APP_NAME + ' [OPTIONS] [--] [EMERGE_OPTIONS]' + print + print 'Broken reverse dependency rebuilder, python implementation.' + print + print 'Available options:' + print ''' + -C, --nocolor Turn off colored output + -d, --debug Print debug informations + -e, --exact Emerge based on exact package version + -h, --help Print this usage + -i, --ignore Ignore temporary files from previous runs (also w= on't create any) + -L, --library NAME Emerge existing packages that use the library wit= h NAME + --library=3DNAME NAME can be a full path to the library or a bas= ic + regular expression (man grep) + -l, --no-ld-path Do not set LD_LIBRARY_PATH + -o, --no-order Do not check the build order + (Saves time, but may cause breakage.) + -p, --pretend Do a trial run without actually emerging anything + (also passed to emerge command) + -q, --quiet Be less verbose (also passed to emerge command) + -v, --verbose Be more verbose (also passed to emerge command) +''' + print 'Calls emerge, options after -- are ignored by ' + APP_NAME + print 'and passed directly to emerge.' + + + +# functions +def parse_conf(conf_file=3DNone, visited=3DNone): + ''' Parses supplied conf_file for libraries pathes. + conf_file is file or files to parse + visited is set of files already parsed + ''' + + if conf_file is None: + conf_file =3D os.path.join(portage.root, DEFAULT_LD_FILE) + + lib_dirs =3D set() + to_parse =3D set() + + if isinstance(conf_file, basestring): + conf_file =3D [conf_file] + + for conf in conf_file: + try: + with open(conf) as f: + for line in f.readlines(): + line =3D line.strip() + if line.startswith('#'): + continue + elif line.startswith('include'): + include_line =3D line.split()[1:] + for included in include_line: + if not included.startswith('/'): + path =3D os.path.join(os.path.dirname(co= nf), \ + included) + else: + path =3D included + + to_parse =3D to_parse.union(glob.glob(path)) + else: + lib_dirs.add(line) + except EnvironmentError: + print_v(2, 'Error when parsing file %s' %conf) + + if visited is None: + visited =3D set() + + visited =3D visited.union(conf_file) + to_parse =3D to_parse.difference(visited) + if to_parse: + lib_dirs =3D lib_dirs.union(parse_conf(to_parse, visited)) + + return lib_dirs + + +def prepare_search_dirs(): + ''' Lookup for search dirs. Returns tuple with two lists, + (list_of_bin_dirs, list_of_lib_dirs) + ''' + + bin_dirs =3D set(['/bin', '/usr/bin', ]) + lib_dirs =3D set(['/lib', '/usr/lib', ]) + + try: + with open(os.path.join(portage.root, DEFAULT_ENV_FILE), 'r') as = f: + for line in f.readlines(): + line =3D line.strip() + m =3D re.match("^export (ROOT)?PATH=3D'([^']+)'", line) + if m is not None: + bin_dirs =3D bin_dirs.union(set(m.group(2).split(':'= ))) + except EnvironmentError: + print_v(2, 'Could not open file %s' % f) + + lib_dirs =3D parse_conf() + return (bin_dirs, lib_dirs) + + +def parse_revdep_config(): + ''' Parses all files under /etc/revdep-rebuild/ and returns + tuple of: (masked_dirs, masked_files, search_dirs)''' + + search_dirs =3D set() + masked_dirs =3D set() + masked_files =3D set() + + for f in os.listdir('/etc/revdep-rebuild/'): + for line in open(os.path.join('/etc/revdep-rebuild', f)): + line =3D line.strip() + if not line.startswith('#'): #first check for comment, we do= not want to regex all lines + m =3D re.match('LD_LIBRARY_MASK=3D\\"([^"]+)\\"', line) + if m is not None: + s =3D m.group(1).split(' ') + masked_files =3D masked_files.union(s) + continue + m =3D re.match('SEARCH_DIRS_MASK=3D\\"([^"]+)\\"', line) + if m is not None: + s =3D m.group(1).split(' ') + for ss in s: + masked_dirs =3D masked_dirs.union(glob.glob(ss)) + continue + m =3D re.match('SEARCH_DIRS=3D\\"([^"]+)\\"', line) + if m is not None: + s =3D m.group(1).split(' ') + for ss in s: + search_dirs =3D masked_dirs.union(glob.glob(ss)) + continue + + return (masked_dirs, masked_files, search_dirs) + + +def collect_libraries_from_dir(dirs, mask): + ''' Collects all libraries from specified list of directories. + mask is list of pathes, that are ommited in scanning, can be eig= hter single file or entire directory + Returns tuple composed of: list of libraries, list of symlinks, = and toupe with pair + (symlink_id, library_id) for resolving dependencies + ''' + + + found_directories =3D [] # contains list of directories found; allo= w us to reduce number of fnc calls + found_files =3D [] + found_symlinks =3D [] + found_la_files =3D [] # la libraries + symlink_pairs =3D [] # list of pairs symlink_id->library_id + + for d in dirs: + if d in mask: + continue + + try: + for l in os.listdir(d): + l =3D os.path.join(d, l) + if l in mask: + continue + + if os.path.isdir(l): + if os.path.islink(l): + #we do not want scan symlink-directories + pass + else: + found_directories.append(l) + elif os.path.isfile(l): + if l.endswith('.so') or '.so.' in l: + if l in found_files or l in found_symlinks: + continue + + if os.path.islink(l): + found_symlinks.append(l) + abs_path =3D os.path.realpath(l) + if abs_path in found_files: + i =3D found_files.index(abs_path) + else: + found_files.append(abs_path) + i =3D len(found_files)-1 + symlink_pairs.append((len(found_symlinks)-1,= i,)) + else: + found_files.append(l) + continue + elif l.endswith('.la'): + if l in found_la_files: + continue + + found_la_files.append(l) + else: + # sometimes there are binaries in libs' subdir, = for example in nagios + if not os.path.islink(l): + if l in found_files or l in found_symlinks: + continue + prv =3D os.stat(l)[stat.ST_MODE] + if prv & stat.S_IXUSR =3D=3D stat.S_IXUSR or= \ + prv & stat.S_IXGRP =3D=3D stat.S_IXG= RP or \ + prv & stat.S_IXOTH =3D=3D stat.S_IXO= TH: + found_files.append(l) + except: + pass + + + if found_directories: + f,a,l,p =3D collect_libraries_from_dir(found_directories, mask) + found_files+=3Df + found_la_files+=3Da + found_symlinks+=3Dl + symlink_pairs+=3Dp + + return (found_files, found_la_files, found_symlinks, symlink_pairs) + + +def collect_binaries_from_dir(dirs, mask): + ''' Collects all binaries from specified list of directories. + mask is list of pathes, that are ommited in scanning, can be eig= hter single file or entire directory + Returns list of binaries + ''' + + found_directories =3D [] # contains list of directories found; allo= w us to reduce number of fnc calls + found_files =3D [] + + for d in dirs: + if d in mask: + continue + + try: + for l in os.listdir(d): + l =3D os.path.join(d, l) + if d in mask: + continue + + if os.path.isdir(l): + if os.path.islink(l): + #we do not want scan symlink-directories + pass + else: + found_directories.append(l) + elif os.path.isfile(l): + #we're looking for binaries, and with binaries we do= not need links, thus we can optimize a bit + if not os.path.islink(l): + prv =3D os.stat(l)[stat.ST_MODE] + if prv & stat.S_IXUSR =3D=3D stat.S_IXUSR or \ + prv & stat.S_IXGRP =3D=3D stat.S_IXGRP o= r \ + prv & stat.S_IXOTH =3D=3D stat.S_IXOTH: + found_files.append(l) + except: + pass + + if found_directories: + found_files +=3D collect_binaries_from_dir(found_directories, ma= sk) + + return found_files + + +def _match_str_in_list(lst, stri): + for l in lst: + if stri.endswith(l): + return l + return False + + +def prepare_checks(files_to_check, libraries): + ''' Calls scanelf for all files_to_check, then returns found librari= es and dependencies ''' + + libs =3D [] # libs found by scanelf + dependencies =3D [] # list of lists of files (from file_to_check) th= at uses + # library (for dependencies[id] and libs[id] =3D> = id=3D=3Did) + + for line in call_program(['scanelf', '-nBF', '%F %n',]+files_to_chec= k).strip().split('\n'): + r =3D line.strip().split(' ') + if len(r) < 2: # no dependencies? + continue + + deps =3D r[1].split(',') + for d in deps: + if d in libs: + i =3D libs.index(d) + dependencies[i].append(r[0]) + else: + libs.append(d) + dependencies.append([r[0],]) + return (libs, dependencies) + + +def extract_dependencies_from_la(la, libraries, to_check): + broken =3D [] + for f in la: + for line in open(f, 'r').readlines(): + line =3D line.strip() + if line.startswith('dependency_libs=3D'): + m =3D re.match("dependency_libs=3D'([^']+)'", line) + if m is not None: + for el in m.group(1).split(' '): + el =3D el.strip() + if len(el) < 1 or el.startswith('-'): + continue + + if el in la or el in libraries: + pass + else: + if to_check: + _break =3D False + for tc in to_check: + if tc in el: + _break =3D True + break + if not _break: + continue + + print_v(1, yellow(' * ') + f + ' is broken (= requires: ' + bold(el)) + broken.append(f) + return broken + + + +def find_broken(found_libs, system_libraries, to_check): + ''' Search for broken libraries. + Check if system_libraries contains found_libs, where + system_libraries is list of obsolute pathes and found_libs + is list of library names. + ''' + + # join libraries and looking at it as string is way too faster than = for-jumping + + broken =3D [] + sl =3D '|'.join(system_libraries) + + if not to_check: + for f in found_libs: + if f+'|' not in sl: + broken.append(found_libs.index(f)) + else: + for tc in to_check: + for f in found_libs: + if tc in f and f+'|' not in sl: + broken.append(found_libs.index(f)) + #print broken + + return broken + + +def main_checks(found_libs, broken, dependencies): + ''' Checks for broken dependencies. + found_libs have to be the same as returned by prepare_checks + broken is list of libraries found by scanelf + dependencies is the value returned by prepare_checks + ''' + + broken_pathes =3D [] + + for b in broken: + f =3D found_libs[b] + print_v(1, 'Broken files that requires: ' + bold(f)) + for d in dependencies[b]: + print_v(1, yellow(' * ') + d) + broken_pathes.append(d) + return broken_pathes + + +def assign_packages(broken, output): + ''' Finds and returns packages that owns files placed in broken. + Broken is list of files + ''' + assigned =3D set() + for group in os.listdir('/var/db/pkg'): + for pkg in os.listdir('/var/db/pkg/' + group): + f =3D '/var/db/pkg/' + group + '/' + pkg + '/CONTENTS' + if os.path.exists(f): + try: + with open(f, 'r') as cnt: + for line in cnt.readlines(): + m =3D re.match('^obj (/[^ ]+)', line) + if m is not None: + m =3D m.group(1) + if m in broken: + found =3D group+'/'+pkg + if found not in assigned: + assigned.add(found) + print_v(1, '\t' + m + ' -> ' + bold(= found)) + except: + output(1, red(' !! Failed to read ' + f)) + + return assigned + + +def get_best_match(cpv, cp): + """Tries to find another version of the pkg with the same slot + as the deprecated installed version. Failing that attempt to get an= y version + of the same app + =20 + @param cpv: string + @param cp: string + @rtype tuple: ([cpv,...], SLOT) + """ + + slot =3D portage.db[portage.root]["vartree"].dbapi.aux_get(cpv, ["SL= OT"]) + print_v(1, yellow('Warn: ebuild ' + cpv + ' not found.')) + print_v(1, 'Looking for %s:%s' %(cp, slot)) + try: + m =3D portdb.match('%s:%s' %(cp, slot)) + except portage.exception.InvalidAtom: + m =3D None + + if not m: + print_v(1, red('Could not find ebuild for %s:%s' %(cp, slot))) + slot =3D [''] + m =3D portdb.match(cp) + if not m: + print_v(1, red('Could not find ebuild for ' + cp)) + return m, slot + + +def get_slotted_cps(cpvs): + """Uses portage to reduce the cpv list into a cp:slot list and retur= ns it + """ + from portage.versions import catpkgsplit + from portage import portdb + + cps =3D [] + for cpv in cpvs: + parts =3D catpkgsplit(cpv) + cp =3D parts[0] + '/' + parts[1] + try: + slot =3D portdb.aux_get(cpv, ["SLOT"]) + except KeyError: + m, slot =3D get_best_match(cpv, cp) + if not m: + print_v(1, red("Installed package: %s is no longer avail= able" %cp)) + continue + + if slot[0]: + cps.append(cp + ":" + slot[0]) + else: + cps.append(cp) + + return cps + + +def read_cache(temp_path=3DDEFAULT_TMP_DIR): + ''' Reads cache information needed by analyse function. + This function does not checks if files exists nor timestamps, + check_temp_files should be called first + @param temp_path: directory where all temp files should reside + @return tuple with values of: libraries, la_libraries, libraries= _links, symlink_pairs, binaries + ''' + + ret =3D {'libraries':[], 'la_libraries':[], 'libraries_links':[], 'b= inaries':[]} + try: + for key,val in ret.iteritems(): + f =3D open(os.path.join(temp_path, key)) + for line in f.readlines(): + val.append(line.strip()) + #libraries.remove('\n') + f.close() + except EnvironmentError: + pass + + return (ret['libraries'], ret['la_libraries'], ret['libraries_links'= ], ret['binaries']) + + +def save_cache(to_save, temp_path=3DDEFAULT_TMP_DIR): + ''' Tries to store caching information. + @param to_save have to be dict with keys: libraries, la_librarie= s, libraries_links and binaries + ''' + + if not os.path.exists(temp_path): + os.makedirs(temp_path) + + f =3D open(os.path.join(temp_path, 'timestamp'), 'w') + f.write(str(int(time.time()))) + f.close() + + for key,val in to_save.iteritems(): + f =3D open(os.path.join(temp_path, key), 'w') + for line in val: + f.write(line + '\n') + f.close() + + +def analyse(output=3Dprint_v, libraries=3DNone, la_libraries=3DNone, lib= raries_links=3DNone, binaries=3DNone): + """Main program body. It will collect all info and determine the + pkgs needing rebuilding. + + @param output: optional print/data gathering routine. Defaults to pr= int_v + which prints to sys.stdout. Refer to print_v parameters for = more detail. + @rtype list: list of pkgs that need rebuilding + """ + + if libraries and la_libraries and libraries_links and binaries: + output(1, blue(' * ') + bold('Found cache, skipping collecting p= hase')) + else: + #TODO: add partial cache (for ex. only libraries) when found for= some reason + + output(1, green(' * ') + bold('Collecting system binaries and li= braries')) + bin_dirs, lib_dirs =3D prepare_search_dirs() + + masked_dirs, masked_files, ld =3D parse_revdep_config() + lib_dirs =3D lib_dirs.union(ld) + bin_dirs =3D bin_dirs.union(ld) + masked_dirs =3D masked_dirs.union(set(['/lib/modules', '/lib32/m= odules', '/lib64/modules',])) + + output(1, green(' * ') + bold('Collecting dynamic linking inform= ations')) + libraries, la_libraries, libraries_links, symlink_pairs =3D coll= ect_libraries_from_dir(lib_dirs, masked_dirs) + binaries =3D collect_binaries_from_dir(bin_dirs, masked_dirs) + + if USE_TMP_FILES: + save_cache(to_save=3D{'libraries':libraries, 'la_libraries':= la_libraries, 'libraries_links':libraries_links, 'binaries':binaries}) + + + output(2, 'Found '+ str(len(libraries)) + ' libraries (+' + str(len(= libraries_links)) + ' symlinks) and ' + str(len(binaries)) + ' binaries') + + output(1, green(' * ') + bold('Checking dynamic linking consistency'= )) + output(2,'Search for ' + str(len(binaries)+len(libraries)) + ' withi= n ' + str(len(libraries)+len(libraries_links))) + libs_and_bins =3D libraries+binaries + + found_libs, dependencies =3D prepare_checks(libs_and_bins, libraries= +libraries_links) + + broken =3D find_broken(found_libs, libraries+libraries_links, _libs_= to_check) + broken_la =3D extract_dependencies_from_la(la_libraries, libraries+l= ibraries_links, _libs_to_check) + + broken_pathes =3D main_checks(found_libs, broken, dependencies) + broken_pathes +=3D broken_la + + output(1, green(' * ') + bold('Assign files to packages')) + + return assign_packages(broken_pathes, output) + + +def check_temp_files(temp_path=3DDEFAULT_TMP_DIR, max_delay=3D3600): + ''' Checks if temporary files from previous run are still available + and if they aren't too old + @param temp_path is directory, where temporary files should be f= ound + @param max_delay is maximum time difference (in seconds) when th= ose files + are still considered fresh and useful + returns True, when files can be used, or False, when they don't + exists or they are too old + ''' + + if not os.path.exists(temp_path) or not os.path.isdir(temp_path): + return False + + timestamp_path =3D os.path.join(temp_path, 'timestamp') + if not os.path.exists(timestamp_path) or not os.path.isfile(timestam= p_path): + return False + + try: + f =3D open(timestamp_path) + timestamp =3D int(f.readline()) + f.close() + except: + timestamp =3D 0 + return False + + diff =3D int(time.time()) - timestamp + return max_delay > diff + + +# Runs from here +if __name__ =3D=3D "__main__": + _libs_to_check =3D set() + + try: + opts, args =3D getopt.getopt(sys.argv[1:], 'dehiklopqvCL:P', ['n= ocolor', 'debug', 'exact', 'help', 'ignore',\ + 'keep-temp', 'library=3D', 'no-ld-path', 'no-order', 'preten= d', 'no-pretend', 'no-progress', 'quiet', 'verbose']) + + for key,val in opts: + if key in ('-h', '--help'): + print_usage() + sys.exit(0) + elif key in ('-q', '--quiet'): + VERBOSITY =3D 0 + elif key in ('-v', '--verbose'): + VERBOSITY =3D 2 + elif key in ('-d', '--debug'): + PRINT_DEBUG =3D True + elif key in ('-p', '--pretend'): + PRETEND =3D True + elif key =3D=3D '--no-pretend': + NO_PRETEND =3D True + elif key in ('-e', '--exact'): + EXACT =3D True + elif key in ('-C', '--nocolor', '--no-color'): + nocolor() + elif key in ('-L', '--library', '--library=3D'): + _libs_to_check =3D _libs_to_check.union(val.split(',')) + elif key in ('-i', '--ignore'): + USE_TMP_FILES =3D False + + args =3D " ".join(args) + except getopt.GetoptError: + print_v(1, red('Unrecognized option\n')) + print_usage() + sys.exit(2) + + if not sys.stdout.isatty(): + nocolor() + + if os.getuid() !=3D 0 and not PRETEND: + print_v(1, blue(' * ') + yellow('You are not root, adding --pret= end to portage options')) + PRETEND =3D True + elif not PRETEND and IS_DEV and not NO_PRETEND: + print_v(1, blue(' * ') + yellow('This is dev. version, so it cou= ld not work correctly')) + print_v(1, blue(' * ') + yellow('Adding --pretend to portage opt= ions anyway')) + print_v(1, blue(' * ') + 'If you\'re sure, you can add --no-pret= end to revdep options') + PRETEND =3D True + + + signal.signal(signal.SIGINT, exithandler) + signal.signal(signal.SIGTERM, exithandler) + signal.signal(signal.SIGPIPE, signal.SIG_DFL) + + analyze_cache =3D {} + if USE_TMP_FILES and check_temp_files(): + libraries, la_libraries, libraries_links, binaries =3D read_cach= e() + assigned =3D analyse(libraries=3Dlibraries, la_libraries=3Dla_li= braries, \ + libraries_links=3Dlibraries_links, binaries=3Dbin= aries) + else: + assigned =3D analyse() + + if not assigned: + print_v(1, '\n' + bold('Your system is consistent')) + sys.exit(0) + + if EXACT: + emerge_command =3D '=3D' + ' =3D'.join(assigned) + else: + emerge_command =3D ' '.join(get_slotted_cps(assigned)) + if PRETEND: + args +=3D ' --pretend' + if VERBOSITY >=3D 2: + args +=3D ' --verbose' + elif VERBOSITY < 1: + args +=3D ' --quiet' + emerge_command =3D args + ' --oneshot ' + emerge_command + + + #if PRETEND: + print_v(1, yellow('\nemerge') + bold(emerge_command)) + #else: + #call_program(emerge_command.split()) + os.system('emerge ' + emerge_command) +