8 from portage.output import bold, red, blue, yellow, green, nocolor
10 from stuff import scan
11 from collect import prepare_search_dirs, parse_revdep_config, collect_libraries_from_dir, collect_binaries_from_dir
12 from assign import assign_packages
13 from cache import save_cache
16 def prepare_checks(files_to_check, libraries, bits, cmd_max_args):
17 ''' Calls scanelf for all files_to_check, then returns found libraries and dependencies
20 libs = [] # libs found by scanelf
21 dependencies = [] # list of lists of files (from file_to_check) that uses
22 # library (for dependencies[id] and libs[id] => id==id)
24 for line in scan(['-M', str(bits), '-nBF', '%F %n'], files_to_check, cmd_max_args):
25 #call_program(['scanelf', '-M', str(bits), '-nBF', '%F %n',]+files_to_check).strip().split('\n'):
26 r = line.strip().split(' ')
27 if len(r) < 2: # no dependencies?
30 deps = r[1].split(',')
34 dependencies[i].append(r[0])
37 dependencies.append([r[0],])
39 return (libs, dependencies)
42 def extract_dependencies_from_la(la, libraries, to_check, logger):
47 m = re.match('.+\/(.+)\.(so|la|a)(\..+)?', l)
50 if ln not in libnames:
54 if not os.path.exists(f):
57 for line in open(f, 'r').readlines():
59 if line.startswith('dependency_libs='):
60 m = re.match("dependency_libs='([^']+)'", line)
62 for el in m.group(1).split(' '):
64 if len(el) < 1 or el.startswith('-L') or el.startswith('-R'):
67 if el.startswith('-l') and 'lib'+el[2:] in libnames:
69 elif el in la or el in libraries:
81 logger.info(yellow(' * ') + f + ' is broken (requires: ' + bold(el)+')')
86 def find_broken(found_libs, system_libraries, to_check):
87 ''' Search for broken libraries.
88 Check if system_libraries contains found_libs, where
89 system_libraries is list of obsolute pathes and found_libs
90 is list of library names.
93 # join libraries and looking at it as string is way too faster than for-jumping
96 sl = '|'.join(system_libraries)
101 broken.append(found_libs.index(f))
105 if tc in f:# and f+'|' not in sl:
106 broken.append(found_libs.index(f))
111 def main_checks(found_libs, broken, dependencies, logger):
112 ''' Checks for broken dependencies.
113 found_libs have to be the same as returned by prepare_checks
114 broken is list of libraries found by scanelf
115 dependencies is the value returned by prepare_checks
122 logger.info('Broken files that requires: ' + bold(f))
123 for d in dependencies[b]:
124 logger.info(yellow(' * ') + d)
125 broken_pathes.append(d)
129 def analyse(settings, logger, libraries=None, la_libraries=None,
130 libraries_links=None, binaries=None, _libs_to_check=set()):
131 """Main program body. It will collect all info and determine the
132 pkgs needing rebuilding.
134 @param logger: logger used for logging messages, instance of logging.Logger
135 class. Can be logging (RootLogger).
136 @param _libs_to_check Libraries that need to be checked only
137 @rtype list: list of pkgs that need rebuilding
140 if libraries and la_libraries and libraries_links and binaries:
141 logger.info(blue(' * ') + bold('Found a valid cache, skipping collecting phase'))
143 #TODO: add partial cache (for ex. only libraries) when found for some reason
145 logger.warn(green(' * ') + bold('Collecting system binaries and libraries'))
146 bin_dirs, lib_dirs = prepare_search_dirs(logger, settings)
148 masked_dirs, masked_files, ld = parse_revdep_config(settings['REVDEP_CONFDIR'])
151 masked_dirs = masked_dirs.union(set(['/lib/modules', '/lib32/modules', '/lib64/modules',]))
153 logger.info(green(' * ') + bold('Collecting dynamic linking informations'))
154 libraries, la_libraries, libraries_links, symlink_pairs = collect_libraries_from_dir(lib_dirs, masked_dirs, logger)
155 binaries = collect_binaries_from_dir(bin_dirs, masked_dirs, logger)
157 if settings['USE_TMP_FILES']:
158 save_cache(logger=logger,
159 to_save={'libraries':libraries, 'la_libraries':la_libraries,
160 'libraries_links':libraries_links, 'binaries':binaries
162 temp_path=settings['DEFAULT_TMP_DIR']
166 logger.debug('Found '+ str(len(libraries)) + ' libraries (+' + str(len(libraries_links)) + ' symlinks) and ' + str(len(binaries)) + ' binaries')
168 logger.warn(green(' * ') + bold('Checking dynamic linking consistency'))
169 logger.debug('Search for ' + str(len(binaries)+len(libraries)) + ' within ' + str(len(libraries)+len(libraries_links)))
170 libs_and_bins = libraries+binaries
173 #for line in call_program(['scanelf', '-M', '64', '-BF', '%F',] + libraries).strip().split('\n'):
182 for ltc in _libs_to_check:
183 if os.path.isfile(ltc):
184 ltc = scan(['-nBSF', '%S'], [ltc,], settings['CMD_MAX_ARGS'])[0].split()[0]
186 _libs_to_check = nltc
188 _bits, linkg = platform.architecture()
189 if _bits.startswith('32'):
191 elif _bits.startswith('64'):
196 for av_bits in glob.glob('/lib[0-9]*') or ('/lib32',):
197 bits = int(av_bits[4:])
199 #_libraries = scan(['-M', str(bits), '-BF', '%F'], libraries+libraries_links, settings['CMD_MAX_ARGS'])
200 _libraries = libraries+libraries_links
202 found_libs, dependencies = prepare_checks(libs_and_bins, _libraries, bits, settings['CMD_MAX_ARGS'])
203 broken = find_broken(found_libs, _libraries, _libs_to_check)
208 broken_la = extract_dependencies_from_la(la_libraries, libraries+libraries_links, _libs_to_check, logger)
211 broken_pathes = main_checks(found_libs, broken, dependencies, logger)
212 broken_pathes += broken_la
214 logger.warn(green(' * ') + bold('Assign files to packages'))
216 return assign_packages(broken_pathes, logger, settings)
220 if __name__ == '__main__':
221 print("This script shouldn't be called directly")