summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbin/revdep-ng51
-rw-r--r--pym/gentoolkit/revdep_rebuild/analyse.py200
-rw-r--r--pym/gentoolkit/revdep_rebuild/assign.py23
-rw-r--r--pym/gentoolkit/revdep_rebuild/cache.py50
-rw-r--r--pym/gentoolkit/revdep_rebuild/collect.py33
-rw-r--r--pym/gentoolkit/revdep_rebuild/rebuild.py30
-rwxr-xr-xpym/gentoolkit/revdep_rebuild/revdep-rebuild.py17
-rw-r--r--pym/gentoolkit/revdep_rebuild/runner.py114
-rw-r--r--pym/gentoolkit/revdep_rebuild/stuff.py4
9 files changed, 409 insertions, 113 deletions
diff --git a/bin/revdep-ng b/bin/revdep-ng
new file mode 100755
index 0000000..a4c8e11
--- /dev/null
+++ b/bin/revdep-ng
@@ -0,0 +1,51 @@
+#!/usr/bin/python
+#
+# Copyright 2010 Brian Dolbec <brian.dolbec@gmail.com>
+# Copyright 2002-2010 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2 or later
+#
+# $Header$
+
+"""'analyse' is a flexible utility for Gentoo linux which can display various
+information about installed packages, such as the USE flags used and the
+packages that use them. It can also be used to help rebuild /etc/portage/package.*
+files in the event of corruption, and possibly more.
+"""
+
+from __future__ import print_function
+
+import sys
+# This block ensures that ^C interrupts are handled quietly.
+try:
+ import signal
+
+ def exithandler(signum,frame):
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+ signal.signal(signal.SIGTERM, signal.SIG_IGN)
+ print()
+ sys.exit(1)
+
+ signal.signal(signal.SIGINT, exithandler)
+ signal.signal(signal.SIGTERM, exithandler)
+ signal.signal(signal.SIGPIPE, signal.SIG_DFL)
+
+
+except KeyboardInterrupt:
+ print()
+ sys.exit(1)
+
+from gentoolkit import errors
+from gentoolkit.revdep_rebuild import rebuild
+
+try:
+ success = rebuild.main(rebuild.parse_options())
+ sys.exit(success)
+except errors.GentoolkitException as err:
+ if '--debug' in sys.argv:
+ raise
+ else:
+ from gentoolkit import pprinter as pp
+ sys.stderr.write(pp.error(str(err)))
+ print()
+ print("Add '--debug' to global options for traceback.")
+ sys.exit(1)
diff --git a/pym/gentoolkit/revdep_rebuild/analyse.py b/pym/gentoolkit/revdep_rebuild/analyse.py
index aad8f81..7b17517 100644
--- a/pym/gentoolkit/revdep_rebuild/analyse.py
+++ b/pym/gentoolkit/revdep_rebuild/analyse.py
@@ -28,27 +28,54 @@ def prepare_checks(files_to_check, libraries, bits, cmd_max_args):
# list of lists of files (from file_to_check) that uses
# library (for dependencies[id] and libs[id] => id==id)
dependencies = []
- for line in scan(
- ['-M', str(bits), '-nBF', '%F %n'],
- files_to_check, cmd_max_args
- ):
- parts = line.strip().split(' ')
- if len(parts) < 2: # no dependencies?
+ bits = []
+
+
+# from runner import ScanRunner
+# sr = ScanRunner(['-M', str(bits), '-nBF', '%F %n'], files_to_check, cmd_max_args)
+# sr.wait()
+
+ for line in scan(['-M', str(bits), '-nBF', '%F %n %M'], files_to_check, cmd_max_args):
+ #call_program(['scanelf', '-M', str(bits), '-nBF', '%F %n',]+files_to_check).strip().split('\n'):
+ r = line.strip().split(' ')
+ if len(r) < 2: # no dependencies?
continue
- deps = parts[1].split(',')
- for dep in deps:
- if dep in libs:
- index = libs.index(dep)
- dependencies[index].append(parts[0])
+ deps = r[1].split(',')
+ for d in deps:
+ if d in libs:
+ i = libs.index(d)
+ dependencies[i].append(r[0])
else:
- libs.append(dep)
- dependencies.append([parts[0],])
-
+ #print d, 'bits:', r[2][8:] # 8: -> strlen('ELFCLASS')
+ libs.append(d)
+ dependencies.append([r[0],])
+
return (libs, dependencies)
+def scan_files(libs_and_bins, cmd_max_args):
+ import os
+
+ scanned_files = {} # {bits: {soname: (filename, needed), ...}, ...}
+ for line in scan(['-nBF', '%F %f %S %n %M'], libs_and_bins, cmd_max_args):
+ filename, sfilename, soname, needed, bits = line.split(' ')
+ filename = os.path.realpath(filename)
+ needed = needed.split(',')
+ bits = bits[8:] # 8: -> strlen('ELFCLASS')
+ if not soname:
+ soname = sfilename
+
+ try:
+ scanned_files[bits][soname] = (filename, needed)
+ except KeyError:
+ scanned_files[bits] = {}
+ scanned_files[bits][soname] = (filename, needed)
+ return scanned_files
+
+
+
def extract_dependencies_from_la(la, libraries, to_check, logger):
broken = []
@@ -122,6 +149,25 @@ def find_broken(found_libs, system_libraries, to_check):
return broken
+def find_broken2(scanned_files, logger):
+ broken_libs = {}
+ for bits, libs in scanned_files.items():
+ logger.debug('Checking for bits: %s' % bits)
+ alllibs = '|'.join(libs.keys()) + '|'
+ for soname, needed in libs.items():
+ for l in needed[1]:
+ if not l+'|' in alllibs:
+ try:
+ broken_libs[bits][l].add(soname)
+ except KeyError:
+ try:
+ broken_libs[bits][l] = set([soname])
+ except KeyError:
+ broken_libs = {bits: {l: set([soname])}}
+
+ return broken_libs
+
+
def main_checks(found_libs, broken_list, dependencies, logger):
''' Checks for broken dependencies.
found_libs have to be the same as returned by prepare_checks
@@ -133,13 +179,25 @@ def main_checks(found_libs, broken_list, dependencies, logger):
for broken in broken_list:
found = found_libs[broken]
- logger.info('Broken files that requires: ' + bold(found))
+ logger.info('Broken files that requires: ' + bold(f))
for dep_path in dependencies[broken]:
logger.info(yellow(' * ') + dep_path)
broken_pathes.append(dep_path)
return broken_pathes
+def main_checks2(broken, scanned_files, logger):
+ broken_pathes = []
+ for bits, _broken in broken.items():
+ for soname, needed in _broken.items():
+ logger.info('Broken files that requires: %s (%s bits)' % (bold(soname), bits))
+ for n in needed:
+ fp = scanned_files[bits][n][0]
+ logger.info(yellow(' * ') + n + ' (' + fp + ')')
+ broken_pathes.append(fp)
+ return broken_pathes
+
+
def analyse(settings, logger, libraries=None, la_libraries=None,
libraries_links=None, binaries=None, _libs_to_check=set()):
"""Main program body. It will collect all info and determine the
@@ -164,14 +222,15 @@ def analyse(settings, logger, libraries=None, la_libraries=None,
masked_dirs, masked_files, ld = \
parse_revdep_config(settings['REVDEP_CONFDIR'])
- lib_dirs.update(ld)
- bin_dirs.update(ld)
- masked_dirs.update([
- '/lib/modules',
- '/lib32/modules',
- '/lib64/modules'
- ]
- )
+ lib_dirs = lib_dirs.union(ld)
+ bin_dirs = bin_dirs.union(ld)
+ masked_dirs = masked_dirs.union(
+ set([
+ '/lib/modules',
+ '/lib32/modules',
+ '/lib64/modules',
+ ])
+ )
logger.info(green(' * ') +
bold('Collecting dynamic linking informations'))
@@ -188,56 +247,79 @@ def analyse(settings, logger, libraries=None, la_libraries=None,
)
- logger.debug('Found '+ str(len(libraries)) +
- ' libraries (+' + str(len(libraries_links)) +
- ' symlinks) and ' + str(len(binaries)) +
- ' binaries')
+ logger.debug('Found %i libraries (+%i symlinks) and %i binaries' %
+ (len(libraries), len(libraries_links), len(binaries))
+ )
+ logger.info(green(' * ') + bold('Scanning files'))
+
+ libs_and_bins = libraries+binaries
+ scanned_files = scan_files(libs_and_bins, settings['CMD_MAX_ARGS'])
+
logger.warn(green(' * ') + bold('Checking dynamic linking consistency'))
- logger.debug('Search for ' + str(len(binaries)+len(libraries)) +
- ' within ' + str(len(libraries)+len(libraries_links)))
- libs_and_bins = libraries+binaries
+ logger.debug('Search for %i within %i' %
+ (len(binaries)+len(libraries), len(libraries)+len(libraries_links))
+ )
+
+ broken = find_broken2(scanned_files, logger)
+ broken_pathes = main_checks2(broken, scanned_files, logger)
+
+ broken_la = extract_dependencies_from_la(la_libraries, libraries+libraries_links, _libs_to_check, logger)
+ broken_pathes += broken_la
- found_libs = []
- dependencies = []
+ logger.warn(green(' * ') + bold('Assign files to packages'))
+
+ return assign_packages(broken_pathes, logger, settings)
- if _libs_to_check:
- nltc = []
- for ltc in _libs_to_check:
- if os.path.isfile(ltc):
- ltc = scan(['-nBSF', '%S'], [ltc,], settings['CMD_MAX_ARGS'])[0].split()[0]
- nltc += [ltc,]
- _libs_to_check = nltc
+ import sys
+ sys.exit()
+
+ #l = []
+ #for line in call_program(['scanelf', '-M', '64', '-BF', '%F',] + libraries).strip().split('\n'):
+ #l.append(line)
+ #libraries = l
- _bits, linkg = platform.architecture()
- if _bits.startswith('32'):
- bits = 32
- elif _bits.startswith('64'):
- bits = 64
+ ## old version from here
+ #found_libs = []
+ #dependencies = []
- broken = []
- for av_bits in glob.glob('/lib[0-9]*') or ('/lib32',):
- bits = int(av_bits[4:])
+ #if _libs_to_check:
+ #nltc = []
+ #for ltc in _libs_to_check:
+ #if os.path.isfile(ltc):
+ #ltc = scan(['-nBSF', '%S'], [ltc,], settings['CMD_MAX_ARGS'])[0].split()[0]
+ #nltc += [ltc,]
+ #_libs_to_check = nltc
- _libraries = libraries+libraries_links
+ #_bits, linkg = platform.architecture()
+ #if _bits.startswith('32'):
+ #bits = 32
+ #elif _bits.startswith('64'):
+ #bits = 64
- found_libs, dependencies = prepare_checks(libs_and_bins,
- _libraries, bits, settings['CMD_MAX_ARGS'])
- broken = find_broken(found_libs, _libraries, _libs_to_check)
+ #import time
+ #broken = []
+ #for av_bits in glob.glob('/lib[0-9]*') or ('/lib32',):
+ #bits = int(av_bits[4:])
- bits /= 2
- bits = int(bits)
+ ##_libraries = scan(['-M', str(bits), '-BF', '%F'], libraries+libraries_links, settings['CMD_MAX_ARGS'])
+ #_libraries = libraries+libraries_links
- broken_la = extract_dependencies_from_la(la_libraries,
- libraries+libraries_links, _libs_to_check, logger)
+ #found_libs, dependencies = prepare_checks(libs_and_bins, _libraries, bits, settings['CMD_MAX_ARGS'])
+ #broken = find_broken(found_libs, _libraries, _libs_to_check)
+ #bits /= 2
+ #bits = int(bits)
- broken_pathes = main_checks(found_libs, broken, dependencies, logger)
- broken_pathes += broken_la
+ #broken_la = extract_dependencies_from_la(la_libraries, libraries+libraries_links, _libs_to_check, logger)
- logger.warn(green(' * ') + bold('Assign files to packages'))
- return assign_packages(broken_pathes, logger, settings)
+ #broken_pathes = main_checks(found_libs, broken, dependencies, logger)
+ #broken_pathes += broken_la
+
+ #logger.warn(green(' * ') + bold('Assign files to packages'))
+
+ #return assign_packages(broken_pathes, logger, settings)
diff --git a/pym/gentoolkit/revdep_rebuild/assign.py b/pym/gentoolkit/revdep_rebuild/assign.py
index e8e87b3..2a93fe1 100644
--- a/pym/gentoolkit/revdep_rebuild/assign.py
+++ b/pym/gentoolkit/revdep_rebuild/assign.py
@@ -27,10 +27,25 @@ def assign_packages(broken, logger, settings):
Broken is list of files
'''
assigned = set()
- if not broken:
- return assigned
+ for group in os.listdir(settings['PKG_DIR']):
+ for pkg in os.listdir(settings['PKG_DIR'] + group):
+ f = settings['PKG_DIR'] + group + '/' + pkg + '/CONTENTS'
+ if os.path.exists(f):
+ try:
+ with open(f, 'r') as cnt:
+ for line in cnt.readlines():
+ m = re.match('^obj (/[^ ]+)', line)
+ if m is not None:
+ m = m.group(1)
+ if m in broken:
+ found = group+'/'+pkg
+ if found not in assigned:
+ assigned.add(found)
+ logger.info('\t' + m + ' -> ' + bold(found))
+ except Exception as e:
+ logger.warn(red(' !! Failed to read ' + f))
- pkgset = set(get_installed_cpvs())
+ return assigned
# Map all files in CONTENTS database to package names
fname_pkg_dict = {}
@@ -88,6 +103,8 @@ def get_best_match(cpv, cp, logger):
def get_slotted_cps(cpvs, logger):
"""Uses portage to reduce the cpv list into a cp:slot list and returns it
"""
+ from portage.versions import catpkgsplit
+ from portage import portdb
cps = []
for cpv in cpvs:
diff --git a/pym/gentoolkit/revdep_rebuild/cache.py b/pym/gentoolkit/revdep_rebuild/cache.py
index d6ef7ce..1be8cb0 100644
--- a/pym/gentoolkit/revdep_rebuild/cache.py
+++ b/pym/gentoolkit/revdep_rebuild/cache.py
@@ -29,9 +29,9 @@ def read_cache(temp_path=DEFAULTS['DEFAULT_TMP_DIR']):
'binaries':[]
}
try:
- for key, val in list(ret.items()):
- _file = open(os.path.join(temp_path, key))
- for line in _file .readlines():
+ for key,val in ret.iteritems():
+ _file = open(os.path.join(temp_path, key))
+ for line in _file.readlines():
val.append(line.strip())
#libraries.remove('\n')
_file .close()
@@ -42,26 +42,22 @@ def read_cache(temp_path=DEFAULTS['DEFAULT_TMP_DIR']):
ret['libraries_links'], ret['binaries'])
-def save_cache(logger, to_save=None, temp_path=DEFAULTS['DEFAULT_TMP_DIR']):
+def save_cache(logger, to_save={}, temp_path=DEFAULTS['DEFAULT_TMP_DIR']):
''' Tries to store caching information.
@param logger
@param to_save have to be dict with keys:
libraries, la_libraries, libraries_links and binaries
'''
- if to_save is None:
- to_save = {}
-
-# TODO: Don't blindly make the cache directory, see Bug 203414
-# if not os.path.exists(temp_path):
-# os.makedirs(temp_path)
+ if not os.path.exists(temp_path):
+ os.makedirs(temp_path)
try:
_file = open(os.path.join(temp_path, 'timestamp'), 'w')
_file.write(str(int(time.time())))
_file.close()
- for key, val in list(to_save.items()):
+ for key,val in to_save.iteritems():
_file = open(os.path.join(temp_path, key), 'w')
for line in val:
_file.write(line + '\n')
@@ -71,8 +67,7 @@ def save_cache(logger, to_save=None, temp_path=DEFAULTS['DEFAULT_TMP_DIR']):
-def check_temp_files(temp_path=DEFAULTS['DEFAULT_TMP_DIR'], max_delay=3600,
- logger=None):
+def check_temp_files(temp_path=DEFAULTS['DEFAULT_TMP_DIR'], max_delay=3600):
''' 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 found
@@ -110,27 +105,26 @@ if __name__ == '__main__':
from .collect import (prepare_search_dirs, parse_revdep_config,
collect_libraries_from_dir, collect_binaries_from_dir)
-
import logging
- bin_dirs, lib_dirs = prepare_search_dirs(logging, DEFAULTS)
+ bin_dirs, lib_dirs = prepare_search_dirs()
- masked_dirs, masked_files, ld = parse_revdep_config("/etc/revdep-rebuild/")
- lib_dirs.update(ld)
- bin_dirs.update(ld)
- masked_dirs = masked_dirs.update([
- '/lib/modules',
- '/lib32/modules',
- '/lib64/modules'
- ]
- )
+ masked_dirs, masked_files, ld = parse_revdep_config()
+ lib_dirs = lib_dirs.union(ld)
+ bin_dirs = bin_dirs.union(ld)
+ masked_dirs = masked_dirs.union(
+ set([
+ '/lib/modules',
+ '/lib32/modules',
+ '/lib64/modules',
+ ])
+ )
- libraries, la_libraries, libraries_links, symlink_pairs = \
- collect_libraries_from_dir(lib_dirs, masked_dirs, logging)
+ libraries, la_libraries, libraries_links, symlink_pairs = collect_libraries_from_dir(lib_dirs, masked_dirs, logging)
binaries = collect_binaries_from_dir(bin_dirs, masked_dirs, logging)
- save_cache(logger=logging,
- to_save={'libraries':libraries, 'la_libraries':la_libraries,
+ save_cache(logger=logging,
+ to_save={'libraries':libraries, 'la_libraries':la_libraries,
'libraries_links':libraries_links, 'binaries':binaries}
)
diff --git a/pym/gentoolkit/revdep_rebuild/collect.py b/pym/gentoolkit/revdep_rebuild/collect.py
index 740ae32..f8ee60d 100644
--- a/pym/gentoolkit/revdep_rebuild/collect.py
+++ b/pym/gentoolkit/revdep_rebuild/collect.py
@@ -21,13 +21,13 @@ def parse_conf(conf_file, visited=None, logger=None):
lib_dirs = set()
to_parse = set()
- if isinstance(conf_file, str):
+ if isinstance(conf_file, basestring):
conf_file = [conf_file]
for conf in conf_file:
try:
with open(conf) as _file:
- for line in _file:
+ for line in _file.readlines():
line = line.strip()
if line.startswith('#'):
continue
@@ -40,7 +40,7 @@ def parse_conf(conf_file, visited=None, logger=None):
else:
path = included
- to_parse.update(glob.glob(path))
+ to_parse = to_parse.union(glob.glob(path))
else:
lib_dirs.add(line)
except EnvironmentError:
@@ -49,10 +49,10 @@ def parse_conf(conf_file, visited=None, logger=None):
if visited is None:
visited = set()
- visited.update(conf_file)
- to_parse.difference_update(visited)
+ visited = visited.union(conf_file)
+ to_parse = to_parse.difference(visited)
if to_parse:
- lib_dirs.update(parse_conf(to_parse, visited, logger=logger))
+ lib_dirs = lib_dirs.union(parse_conf(to_parse, visited, logger=logger))
return lib_dirs
@@ -68,7 +68,7 @@ def prepare_search_dirs(logger, settings):
#try:
with open(os.path.join(
portage.root, settings['DEFAULT_ENV_FILE']), 'r') as _file:
- for line in _file:
+ for line in _file.readlines():
line = line.strip()
match = re.match("^export (ROOT)?PATH='([^']+)'", line)
if match is not None:
@@ -250,13 +250,18 @@ def collect_binaries_from_dir(dirs, mask, logger):
if __name__ == '__main__':
import logging
- from .settings import DEFAULTS
- mbin_dirs, mlib_dirs = prepare_search_dirs(logging, DEFAULTS)
-
- mmasked_dirs, mmasked_files, mld = parse_revdep_config("/etc/revdep-rebuild/")
- mlib_dirs.update(mld)
- mbin_dirs.update(mld)
- mmasked_dirs.update(['/lib/modules', '/lib32/modules', '/lib64/modules'])
+ bin_dirs, lib_dirs = prepare_search_dirs(logging)
+
+ masked_dirs, masked_files, ld = parse_revdep_config()
+ lib_dirs = lib_dirs.union(ld)
+ bin_dirs = bin_dirs.union(ld)
+ masked_dirs = masked_dirs.union(
+ set([
+ '/lib/modules',
+ '/lib32/modules',
+ '/lib64/modules',
+ ])
+ )
libraries, la_libraries, libraries_links, msymlink_pairs = \
collect_libraries_from_dir(mlib_dirs, mmasked_dirs, logging)
diff --git a/pym/gentoolkit/revdep_rebuild/rebuild.py b/pym/gentoolkit/revdep_rebuild/rebuild.py
index 8d21b76..386ac33 100644
--- a/pym/gentoolkit/revdep_rebuild/rebuild.py
+++ b/pym/gentoolkit/revdep_rebuild/rebuild.py
@@ -106,7 +106,8 @@ def parse_options():
do_help = False
for key, val in opts:
if key in ('-h', '--help'):
- do_help = True
+ print_usage()
+ sys.exit(0)
elif key in ('-q', '--quiet'):
settings['quiet'] = True
settings['VERBOSITY'] = 0
@@ -134,9 +135,7 @@ def parse_options():
print(red('Unrecognized option\n'))
print_usage()
sys.exit(2)
- if do_help:
- print_usage()
- sys.exit(0)
+
return settings
@@ -207,13 +206,21 @@ def main(settings=None, logger=None):
logger.warn(blue(' * ') +
yellow('You are not root, adding --pretend to portage options'))
settings['PRETEND'] = True
+ elif not settings['PRETEND'] \
+ and settings['IS_DEV'] \
+ and not settings['NO_PRETEND']:
+ logger.warn(blue(' * ') +
+ yellow('This is a development version, '
+ 'so it may not work correctly'))
+ logger.warn(blue(' * ') +
+ yellow('Adding --pretend to portage options anyway'))
+ logger.info(blue(' * ') +
+ 'If you\'re sure, you can add --no-pretend to revdep options')
+ settings['PRETEND'] = True
- if settings['library']:
- logger.warn(green(' * ') +
- "Looking for libraries: %s" % (bold(', '.join(settings['library']))))
-
+ analyze_cache = {}
if settings['USE_TMP_FILES'] \
- and check_temp_files(settings['DEFAULT_TMP_DIR'], logger=logger):
+ and check_temp_files(settings['DEFAULT_TMP_DIR']):
libraries, la_libraries, libraries_links, binaries = read_cache(
settings['DEFAULT_TMP_DIR'])
assigned = analyse(
@@ -251,3 +258,8 @@ def main(settings=None, logger=None):
success = rebuild(logger, assigned, settings)
logger.debug("rebuild return code = %i" %success)
return success
+
+
+if __name__ == '__main__':
+ main(parse_options())
+
diff --git a/pym/gentoolkit/revdep_rebuild/revdep-rebuild.py b/pym/gentoolkit/revdep_rebuild/revdep-rebuild.py
new file mode 100755
index 0000000..2619ee0
--- /dev/null
+++ b/pym/gentoolkit/revdep_rebuild/revdep-rebuild.py
@@ -0,0 +1,17 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+
+# Author: Sławomir 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
+
+from rebuild import APP_NAME, VERSION, main
+
+if __name__ == '__main__':
+ # instead of revdep-rebuild.py call rebuild.py
+ main()
diff --git a/pym/gentoolkit/revdep_rebuild/runner.py b/pym/gentoolkit/revdep_rebuild/runner.py
new file mode 100644
index 0000000..24411a5
--- /dev/null
+++ b/pym/gentoolkit/revdep_rebuild/runner.py
@@ -0,0 +1,114 @@
+# -*- coding: utf-8 -*-
+
+import threading
+import subprocess
+
+
+class ProcessRunner(threading.Thread):
+ '''
+ ProcessRunner is class designed to run arbitrary command
+ in background (separate thread). It's replacement for old
+ stuff.call_program function.
+
+ When called program is finished, its output can be accessed
+ through .stdout and .stderr fields
+ '''
+
+ def __init__(self, args, autorun=True):
+ '''
+ @param args - program name and its arguments
+ @param autorun - if True, then automatically starts new thread
+ '''
+
+ threading.Thread.__init__(self)
+ self.args = args
+ self.lock = threading.Lock()
+ self.stdout = ''
+ self.stderr = ''
+
+ if autorun:
+ self.start()
+
+
+
+ def run(self):
+ self.lock.acquire()
+
+ subp = subprocess.Popen(self.args, stdout=subprocess.PIPE, \
+ stderr=subprocess.PIPE)
+ self.stdout, self.stderr = subp.communicate()
+ self.lock.release()
+
+
+ def is_ready(self):
+ ''' Checks whether current command is finished '''
+ return not self.lock.locked()
+
+
+ def wait(self):
+ ''' Waits until called program finishes '''
+ self.lock.acquire()
+ self.lock.release()
+
+
+
+
+class ScanRunner(threading.Thread):
+ '''
+ ScanRunner is a class for calling scanelf in separate
+ thread, so several instances could be called at a time,
+ and then all results could be consolidated.
+
+ Consolidated output is available through .out
+ '''
+
+ def __init__(self, params, files, max_args, autorun=True):
+ '''
+ @param params is list of parameters that should be passed into scanelf app.
+ @param files list of files to scan.
+ @param max_args number of files to process at once
+ @param autorun automatically start new thread
+
+ When files count is greater CMD_MAX_ARGS, then scanelf will be called
+ several times.
+ '''
+
+ threading.Thread.__init__(self)
+ self.params = params
+ self.files = files
+ self.max_args = max_args
+
+ self.out = []
+ self.lock = threading.Lock()
+
+ if autorun:
+ self.start()
+
+
+ def run(self):
+ self.lock.acquire()
+
+ process_pool = []
+ for i in range(0, len(self.files), self.max_args):
+ process_pool.append(ProcessRunner(['scanelf'] + self.params + self.files[i:i+self.max_args]))
+
+ while process_pool:
+ p = process_pool.pop()
+ p.wait()
+ self.out += p.stdout.strip().split('\n')
+
+ self.lock.release()
+
+
+ def is_ready(self):
+ ''' Checks whether scanning is finished '''
+ return not self.lock.locked()
+
+
+ def wait(self):
+ ''' Waits until all scanning instances are finished '''
+ self.lock.acquire()
+ self.lock.release()
+
+
+ \ No newline at end of file
diff --git a/pym/gentoolkit/revdep_rebuild/stuff.py b/pym/gentoolkit/revdep_rebuild/stuff.py
index e78748c..0bebce2 100644
--- a/pym/gentoolkit/revdep_rebuild/stuff.py
+++ b/pym/gentoolkit/revdep_rebuild/stuff.py
@@ -43,6 +43,10 @@ def scan(params, files, max_args):
return out
+def exithandler(signum, frame):
+ sys.exit(1)
+
+
def get_masking_status(ebuild):
"""returns the masking status of an ebuild