def _check_invalid_tags(self, symbol_map): """Check for commits on any symbols that are to be converted as tags. SYMBOL_MAP is a map {AbstractSymbol : (Trunk|TypedSymbol)} indicating how each AbstractSymbol is to be converted. If there is a commit on a symbol, then it cannot be converted as a tag. If any tags with commits are found, output error messages describing the problems then raise a FatalException.""" logger.quiet("Checking for forced tags with commits...") invalid_tags = [] for symbol in symbol_map.itervalues(): if isinstance(symbol, Tag): stats = self.get_stats(symbol) if stats.branch_commit_count > 0: invalid_tags.append(symbol) if not invalid_tags: # No problems found: return s = [] s.append('%s: The following branches cannot be forced to be tags ' 'because they have commits:\n' % (error_prefix, )) for tag in invalid_tags: s.append(' %s\n' % (tag.name)) s.append('\n') logger.error(''.join(s)) raise FatalException()
def _check_blocked_excludes(self, symbol_map): """Check for any excluded LODs that are blocked by non-excluded symbols. If any are found, describe the problem to logger.error() and raise a FatalException.""" # A list of (lod,[blocker,...]) tuples for excludes that are # blocked by the specified non-excluded blockers: problems = [] for lod in symbol_map.itervalues(): if isinstance(lod, ExcludedSymbol): # Symbol is excluded; make sure that its blockers are also # excluded: lod_blockers = [] for blocker in self.get_stats(lod).branch_blockers: if isinstance(symbol_map.get(blocker, None), IncludedSymbol): lod_blockers.append(blocker) if lod_blockers: problems.append((lod, lod_blockers)) if problems: s = [] for (lod, lod_blockers) in problems: s.append( '%s: %s cannot be excluded because the following symbols ' 'depend on it:\n' % (error_prefix, lod,) ) for blocker in lod_blockers: s.append(' %s\n' % (blocker,)) s.append('\n') logger.error(''.join(s)) raise FatalException()
def run(self, run_options, stats_keeper): Ctx()._projects = read_projects( artifact_manager.get_temp_file(config.PROJECTS)) Ctx()._cvs_path_db = CVSPathDatabase(DB_OPEN_READ) self.symbol_db = SymbolDatabase() Ctx()._symbol_db = self.symbol_db logger.quiet("Checking dependency consistency...") fatal_errors = [] for cvs_item in self.iter_cvs_items(): # Check that the pred_ids and succ_ids are mutually consistent: for pred_id in cvs_item.get_pred_ids(): pred = self.get_cvs_item(pred_id) if not cvs_item.id in pred.get_succ_ids(): fatal_errors.append( '%s lists pred=%s, but not vice versa.' % ( cvs_item, pred, )) for succ_id in cvs_item.get_succ_ids(): succ = self.get_cvs_item(succ_id) if not cvs_item.id in succ.get_pred_ids(): fatal_errors.append( '%s lists succ=%s, but not vice versa.' % ( cvs_item, succ, )) if fatal_errors: raise FatalException('Dependencies inconsistent:\n' '%s\n' 'Exited due to fatal error(s).' % ('\n'.join(fatal_errors), )) self.symbol_db.close() self.symbol_db = None Ctx()._cvs_path_db.close() logger.quiet("Done")
class SymbolStatistics: """Read and handle line of development statistics. The statistics are read from a database created by SymbolStatisticsCollector. This class has methods to process the statistics information and help with decisions about: 1. What tags and branches should be processed/excluded 2. What tags should be forced to be branches and vice versa (this class maintains some statistics to help the user decide) 3. Are there inconsistencies? - A symbol that is sometimes a branch and sometimes a tag - A forced branch with commit(s) on it - A non-excluded branch depends on an excluded branch The data in this class is read from a pickle file.""" def __init__(self, filename): """Read the stats database from FILENAME.""" # A map { LineOfDevelopment -> _Stats } for all lines of # development: self._stats = {} # A map { LineOfDevelopment.id -> _Stats } for all lines of # development: self._stats_by_id = {} stats_list = cPickle.load(open(filename, 'rb')) for stats in stats_list: self._stats[stats.lod] = stats self._stats_by_id[stats.lod.id] = stats def __len__(self): return len(self._stats) def __getitem__(self, lod_id): return self._stats_by_id[lod_id] def get_stats(self, lod): """Return the _Stats object for LineOfDevelopment instance LOD. Raise KeyError if no such lod exists.""" return self._stats[lod] def __iter__(self): return self._stats.itervalues() def _check_blocked_excludes(self, symbol_map): """Check for any excluded LODs that are blocked by non-excluded symbols. If any are found, describe the problem to logger.error() and raise a FatalException.""" # A list of (lod,[blocker,...]) tuples for excludes that are # blocked by the specified non-excluded blockers: problems = [] for lod in symbol_map.itervalues(): if isinstance(lod, ExcludedSymbol): # Symbol is excluded; make sure that its blockers are also # excluded: lod_blockers = [] for blocker in self.get_stats(lod).branch_blockers: if isinstance(symbol_map.get(blocker, None), IncludedSymbol): lod_blockers.append(blocker) if lod_blockers: problems.append((lod, lod_blockers)) if problems: s = [] for (lod, lod_blockers) in problems: s.append( '%s: %s cannot be excluded because the following symbols ' 'depend on it:\n' % ( error_prefix, lod, )) for blocker in lod_blockers: s.append(' %s\n' % (blocker, )) s.append('\n') logger.error(''.join(s)) raise FatalException() def _check_invalid_tags(self, symbol_map): """Check for commits on any symbols that are to be converted as tags. SYMBOL_MAP is a map {AbstractSymbol : (Trunk|TypedSymbol)} indicating how each AbstractSymbol is to be converted. If there is a commit on a symbol, then it cannot be converted as a tag. If any tags with commits are found, output error messages describing the problems then raise a FatalException.""" logger.quiet("Checking for forced tags with commits...") invalid_tags = [] for symbol in symbol_map.itervalues(): if isinstance(symbol, Tag): stats = self.get_stats(symbol) if stats.branch_commit_count > 0: invalid_tags.append(symbol) if not invalid_tags: # No problems found: return s = [] s.append('%s: The following branches cannot be forced to be tags ' 'because they have commits:\n' % (error_prefix, )) for tag in invalid_tags: s.append(' %s\n' % (tag.name)) s.append('\n') logger.error(''.join(s)) raise FatalException() def check_consistency(self, symbol_map): """Check the plan for how to convert symbols for consistency. SYMBOL_MAP is a map {AbstractSymbol : (Trunk|TypedSymbol)} indicating how each AbstractSymbol is to be converted. If any problems are detected, describe the problem to logger.error() and raise a FatalException.""" # We want to do all of the consistency checks even if one of them # fails, so that the user gets as much feedback as possible. Set # this variable to True if any errors are found. error_found = False # Check that the planned preferred parents are OK for all # IncludedSymbols: for lod in symbol_map.itervalues(): if isinstance(lod, IncludedSymbol): stats = self.get_stats(lod) try: stats.check_preferred_parent_allowed(lod) except SymbolPlanException, e: logger.error('%s\n' % (e, )) error_found = True try: self._check_blocked_excludes(symbol_map) except FatalException: error_found = True try: self._check_invalid_tags(symbol_map) except FatalException: error_found = True if error_found: raise FatalException( 'Please fix the above errors and restart CollateSymbolsPass')