5 from __future__ import print_function
12 from portage.output import bold, blue, yellow, green
14 from .stuff import scan
15 from .collect import (prepare_search_dirs, parse_revdep_config,
16 collect_libraries_from_dir, collect_binaries_from_dir)
17 from .assign import assign_packages
18 from .cache import save_cache
21 def prepare_checks(files_to_check, libraries, bits, cmd_max_args):
22 ''' Calls scanelf for all files_to_check,
23 then returns found libraries and dependencies
26 # libs found by scanelf
28 # list of lists of files (from file_to_check) that uses
29 # library (for dependencies[id] and libs[id] => id==id)
32 ['-M', str(bits), '-nBF', '%F %n'],
33 files_to_check, cmd_max_args
36 parts = line.strip().split(' ')
37 if len(parts) < 2: # no dependencies?
40 deps = parts[1].split(',')
43 index = libs.index(dep)
44 dependencies[index].append(parts[0])
47 dependencies.append([parts[0],])
49 return (libs, dependencies)
52 def extract_dependencies_from_la(la, libraries, to_check, logger):
57 match = re.match('.+\/(.+)\.(so|la|a)(\..+)?', lib)
59 libname = match.group(1)
60 if libname not in libnames:
61 libnames += [libname, ]
64 if not os.path.exists(_file):
67 for line in open(_file, 'r').readlines():
69 if line.startswith('dependency_libs='):
70 match = re.match("dependency_libs='([^']+)'", line)
72 for el in match.group(1).split(' '):
74 if (len(el) < 1 or el.startswith('-L')
75 or el.startswith('-R')
79 if el.startswith('-l') and 'lib'+el[2:] in libnames:
81 elif el in la or el in libraries:
93 logger.info(yellow(' * ') + _file +
94 ' is broken (requires: ' + bold(el)+')')
99 def find_broken(found_libs, system_libraries, to_check):
100 ''' Search for broken libraries.
101 Check if system_libraries contains found_libs, where
102 system_libraries is list of obsolute pathes and found_libs
103 is list of library names.
106 # join libraries and looking at it as string
107 # is way faster than for-jumping
110 syslibs = '|'.join(system_libraries)
113 for found in found_libs:
114 if found + '|' not in syslibs:
115 broken.append(found_libs.index(found))
118 for found in found_libs:
119 if tc in found:# and found+'|' not in syslibs:
120 broken.append(found_libs.index(found))
125 def main_checks(found_libs, broken_list, dependencies, logger):
126 ''' Checks for broken dependencies.
127 found_libs have to be the same as returned by prepare_checks
128 broken_list is list of libraries found by scanelf
129 dependencies is the value returned by prepare_checks
134 for broken in broken_list:
135 found = found_libs[broken]
136 logger.info('Broken files that requires: ' + bold(found))
137 for dep_path in dependencies[broken]:
138 logger.info(yellow(' * ') + dep_path)
139 broken_pathes.append(dep_path)
143 def analyse(settings, logger, libraries=None, la_libraries=None,
144 libraries_links=None, binaries=None, _libs_to_check=set()):
145 """Main program body. It will collect all info and determine the
146 pkgs needing rebuilding.
148 @param logger: logger used for logging messages, instance of logging.Logger
149 class. Can be logging (RootLogger).
150 @param _libs_to_check Libraries that need to be checked only
151 @rtype list: list of pkgs that need rebuilding
154 if libraries and la_libraries and libraries_links and binaries:
155 logger.info(blue(' * ') +
156 bold('Found a valid cache, skipping collecting phase'))
158 #TODO: add partial cache (for ex. only libraries)
159 # when found for some reason
161 logger.warn(green(' * ') +
162 bold('Collecting system binaries and libraries'))
163 bin_dirs, lib_dirs = prepare_search_dirs(logger, settings)
165 masked_dirs, masked_files, ld = \
166 parse_revdep_config(settings['REVDEP_CONFDIR'])
176 logger.info(green(' * ') +
177 bold('Collecting dynamic linking informations'))
178 libraries, la_libraries, libraries_links, symlink_pairs = \
179 collect_libraries_from_dir(lib_dirs, masked_dirs, logger)
180 binaries = collect_binaries_from_dir(bin_dirs, masked_dirs, logger)
182 if settings['USE_TMP_FILES']:
183 save_cache(logger=logger,
184 to_save={'libraries':libraries, 'la_libraries':la_libraries,
185 'libraries_links':libraries_links, 'binaries':binaries
187 temp_path=settings['DEFAULT_TMP_DIR']
191 logger.debug('Found '+ str(len(libraries)) +
192 ' libraries (+' + str(len(libraries_links)) +
193 ' symlinks) and ' + str(len(binaries)) +
196 logger.warn(green(' * ') + bold('Checking dynamic linking consistency'))
197 logger.debug('Search for ' + str(len(binaries)+len(libraries)) +
198 ' within ' + str(len(libraries)+len(libraries_links)))
199 libs_and_bins = libraries+binaries
206 for ltc in _libs_to_check:
207 if os.path.isfile(ltc):
208 ltc = scan(['-nBSF', '%S'], [ltc,], settings['CMD_MAX_ARGS'])[0].split()[0]
210 _libs_to_check = nltc
212 _bits, linkg = platform.architecture()
213 if _bits.startswith('32'):
215 elif _bits.startswith('64'):
219 for av_bits in glob.glob('/lib[0-9]*') or ('/lib32',):
220 bits = int(av_bits[4:])
222 _libraries = libraries+libraries_links
224 found_libs, dependencies = prepare_checks(libs_and_bins,
225 _libraries, bits, settings['CMD_MAX_ARGS'])
226 broken = find_broken(found_libs, _libraries, _libs_to_check)
231 broken_la = extract_dependencies_from_la(la_libraries,
232 libraries+libraries_links, _libs_to_check, logger)
235 broken_pathes = main_checks(found_libs, broken, dependencies, logger)
236 broken_pathes += broken_la
238 logger.warn(green(' * ') + bold('Assign files to packages'))
240 return assign_packages(broken_pathes, logger, settings)
244 if __name__ == '__main__':
245 print("This script shouldn't be called directly")