def process_new_dependency(self,dependent, dependent_sha1, dependency, dependency_sha1, path, line_num): if not self.seen_commit(dependency): self.notify_listeners("new_commit", dependency) self.dependencies[dependent_sha1][dependency_sha1] = {} self.notify_listeners("new_dependency", dependent, dependency, path, line_num) self.logger.info( " New dependency %s -> %s via line %s (%s)" % (dependent_sha1[:8], dependency_sha1[:8], line_num, GitUtils.oneline(dependency))) if dependency_sha1 in self.todo_d: self.logger.info( " Dependency on %s via line %s already in TODO" % (dependency_sha1[:8], line_num,)) return if dependency_sha1 in self.done_d: self.logger.info( " Dependency on %s via line %s already done" % (dependency_sha1[:8], line_num,)) return if dependency_sha1 not in self.dependencies: if self.options.recurse: self.todo.append(dependency) self.todo_d[dependency.hex] = True self.logger.info(" + Added %s to TODO" % dependency.hex[:8])
def process_hunk_line(self, dependent, dependent_sha1, parent, path, line, line_to_culprit): self.logger.debug(" ! " + line.rstrip()) m = re.match('^([0-9a-f]{40}) (\d+) (\d+)( \d+)?$', line) if not m: return dependency_sha1, orig_line_num, line_num = m.group(1, 2, 3) line_num = int(line_num) dependency = self.get_commit(dependency_sha1) line_to_culprit[line_num] = dependency.hex if self.is_excluded(dependency): self.logger.debug( " Excluding dependency %s from line %s (%s)" % (dependency_sha1[:8], line_num, GitUtils.oneline(dependency))) return if dependency_sha1 not in self.dependencies[dependent_sha1]: self.process_new_dependency(dependent, dependent_sha1, dependency, dependency_sha1, path, line_num) self.record_dependency_source(parent, dependent, dependent_sha1, dependency, dependency_sha1, path, line_num, line)
def cherry_pick(self, sha): GitExplodeUtils.git('cherry-pick', sha) self.update_current_topic(sha) head = GitExplodeUtils.get_head_sha1() self.exploded[sha] = head commit = GitUtils.ref_commit(self.repo, sha) self.logger.debug( "- cherry-picked %s as %s (%s)" % (sha[:8], self.exploded[sha][:8], GitUtils.oneline(commit)))
def blame_hunk(self, dependent, parent, path, hunk): """Run git blame on the parts of the hunk which exist in the older commit in the diff. The commits generated by git blame are the commits which the newer commit in the diff depends on, because without the lines from those commits, the hunk would not apply correctly. """ line_range_before = "-%d,%d" % (hunk.old_start, hunk.old_lines) line_range_after = "+%d,%d" % (hunk.new_start, hunk.new_lines) self.logger.debug(" Blaming hunk %s @ %s" % (line_range_before, parent.hex[:8])) if not self.tree_lookup(path, parent): # This is probably because dependent added a new directory # which was not previously in the parent. return cmd = [ 'git', 'blame', '--porcelain', '-L', "%d,+%d" % (hunk.old_start, hunk.old_lines), parent.hex, '--', path ] blame = subprocess.check_output(cmd, universal_newlines=True) dependent_sha1 = dependent.hex if dependent_sha1 not in self.dependencies: self.logger.debug(" New dependent: %s" % GitUtils.commit_summary(dependent)) self.dependencies[dependent_sha1] = {} self.notify_listeners("new_dependent", dependent) line_to_culprit = {} for line in blame.split('\n'): self.logger.debug(" !" + line.rstrip()) m = re.match('^([0-9a-f]{40}) (\d+) (\d+)( \d+)?$', line) if not m: continue dependency_sha1, orig_line_num, line_num = m.group(1, 2, 3) line_num = int(line_num) dependency = self.get_commit(dependency_sha1) line_to_culprit[line_num] = dependency.hex if self.is_excluded(dependency): self.logger.debug( " Excluding dependency %s from line %s (%s)" % (dependency_sha1[:8], line_num, GitUtils.oneline(dependency))) continue if dependency_sha1 not in self.dependencies[dependent_sha1]: if not self.seen_commit(dependency): self.notify_listeners("new_commit", dependency) self.dependencies[dependent_sha1][dependency_sha1] = {} self.notify_listeners("new_dependency", dependent, dependency, path, line_num) self.logger.debug( " New dependency %s -> %s via line %s (%s)" % (dependent_sha1[:8], dependency_sha1[:8], line_num, GitUtils.oneline(dependency))) if dependency_sha1 in self.todo_d: self.logger.debug( " Dependency on %s via line %s already in TODO" % ( dependency_sha1[:8], line_num, )) continue if dependency_sha1 in self.done_d: self.logger.debug( " Dependency on %s via line %s already done" % ( dependency_sha1[:8], line_num, )) continue if dependency_sha1 not in self.dependencies: if self.options.recurse: self.todo.append(dependency) self.todo_d[dependency.hex] = True self.logger.debug(" + Added %s to TODO" % dependency.hex[:8]) dep_sources = self.dependencies[dependent_sha1][dependency_sha1] if path not in dep_sources: dep_sources[path] = {} self.notify_listeners('new_path', dependent, dependency, path, line_num) if line_num in dep_sources[path]: abort("line %d already found when blaming %s:%s\n" "old:\n %s\n" "new:\n %s" % (line_num, parent.hex[:8], path, dep_sources[path][line_num], line)) dep_sources[path][line_num] = line self.logger.debug(" New line for %s -> %s: %s" % (dependent_sha1[:8], dependency_sha1[:8], line)) self.notify_listeners('new_line', dependent, dependency, path, line_num) diff_format = ' |%8.8s %5s %s%s' hunk_header = '@@ %s %s @@' % (line_range_before, line_range_after) self.logger.debug(diff_format % ('--------', '-----', '', hunk_header)) line_num = hunk.old_start for line in hunk.lines: if "\n\\ No newline at end of file" == line.content.rstrip(): break if line.origin == '+': rev = ln = '' else: rev = line_to_culprit[line_num] ln = line_num line_num += 1 self.logger.debug(diff_format % (rev, ln, line.origin, line.content.rstrip()))