def make_diff(self, merge_base, base, tip, include_files, exclude_patterns): """Performs a diff on a particular branch range.""" rev_range = "%s..%s" % (base, tip) if include_files: include_files = ['--'] + include_files git_cmd = [self.git] if self._supports_git_config_flag(): git_cmd.extend(['-c', 'core.quotepath=false']) if self.type in ('svn', 'perforce'): diff_cmd_params = ['--no-color', '--no-prefix', '-r', '-u'] elif self.type == 'git': diff_cmd_params = ['--no-color', '--full-index', '--ignore-submodules'] if self._supports_git_config_flag(): git_cmd.extend(['-c', 'diff.noprefix=false']) if (self.capabilities is not None and self.capabilities.has_capability('diffs', 'moved_files')): diff_cmd_params.append('-M') else: diff_cmd_params.append('--no-renames') else: assert False # By default, don't allow using external diff commands. This prevents # things from breaking horribly if someone configures a graphical diff # viewer like p4merge or kaleidoscope. This can be overridden by # setting GIT_USE_EXT_DIFF = True in ~/.reviewboardrc if not self.config.get('GIT_USE_EXT_DIFF', False): diff_cmd_params.append('--no-ext-diff') diff_cmd = git_cmd + ['diff'] + diff_cmd_params if exclude_patterns: # If we have specified files to exclude, we will get a list of all # changed files and run `git diff` on each un-excluded file # individually. changed_files_cmd = git_cmd + ['diff-tree'] + diff_cmd_params if self.type == 'git': changed_files_cmd.append('-r') changed_files = execute( changed_files_cmd + [rev_range] + include_files, split_lines=True, with_errors=False, ignore_errors=True, none_on_ignored_error=True, log_output_on_error=False) # The output of git diff-tree will be a list of entries that have # changed between the two revisions that we give it. The last part # of the line is the name of the file that has changed. changed_files = remove_filenames_matching_patterns( (filename.split()[-1] for filename in changed_files), exclude_patterns, base_dir=self._get_root_directory()) diff_lines = [] for filename in changed_files: lines = execute(diff_cmd + [rev_range, '--', filename], split_lines=True, with_errors=False, ignore_errors=True, none_on_ignored_error=True, log_output_on_error=False, results_unicode=False) if lines is None: logging.error( 'Could not get diff for all files (git-diff failed ' 'for "%s"). Refusing to return a partial diff.' % filename) diff_lines = None break diff_lines += lines else: diff_lines = execute(diff_cmd + [rev_range] + include_files, split_lines=True, with_errors=False, ignore_errors=True, none_on_ignored_error=True, log_output_on_error=False, results_unicode=False) if self.type == 'svn': return self.make_svn_diff(merge_base, diff_lines) elif self.type == 'perforce': return self.make_perforce_diff(merge_base, diff_lines) else: return b''.join(diff_lines)
def make_diff(self, merge_base, base, tip, include_files, exclude_patterns): """Perform a diff on a particular branch range. Args: merge_base (unicode): The ID of the merge base commit. This is only used when creating diffs with git-svn or git-p4 clones. base (unicode): The ID of the base commit for the diff. tip (unicode): The ID of the tip commit for the diff. include_files (list of unicode): A list of files to whitelist during the diff generation. exclude_patterns (list of unicode): A list of shell-style glob patterns to blacklist during diff generation. Returns: bytes: The diff between (base, tip]. """ rev_range = '%s..%s' % (base, tip) if include_files: include_files = ['--'] + include_files git_cmd = [self.git] if self._supports_git_config_flag(): git_cmd.extend(['-c', 'core.quotepath=false']) if self._type in (self.TYPE_GIT_SVN, self.TYPE_GIT_P4): diff_cmd_params = ['--no-color', '--no-prefix', '-r', '-u'] elif self._type == self.TYPE_GIT: diff_cmd_params = ['--no-color', '--full-index', '--ignore-submodules'] if self._supports_git_config_flag(): git_cmd.extend(['-c', 'diff.noprefix=false']) if (self.capabilities is not None and self.capabilities.has_capability('diffs', 'moved_files')): diff_cmd_params.append('-M') else: diff_cmd_params.append('--no-renames') else: raise ValueError('Unknown git client type %s' % self._type) # By default, don't allow using external diff commands. This prevents # things from breaking horribly if someone configures a graphical diff # viewer like p4merge or kaleidoscope. This can be overridden by # setting GIT_USE_EXT_DIFF = True in ~/.reviewboardrc if not self.config.get('GIT_USE_EXT_DIFF', False): diff_cmd_params.append('--no-ext-diff') diff_cmd = git_cmd + ['diff'] + diff_cmd_params if exclude_patterns: # If we have specified files to exclude, we will get a list of all # changed files and run `git diff` on each un-excluded file # individually. changed_files_cmd = git_cmd + ['diff-tree'] + diff_cmd_params if self._type in (self.TYPE_GIT_SVN, self.TYPE_GIT_P4): # We don't want to send -u along to git diff-tree because it # will generate diff information along with the list of # changed files. changed_files_cmd.remove('-u') elif self._type == self.TYPE_GIT: changed_files_cmd.append('-r') changed_files = self._execute( changed_files_cmd + [rev_range] + include_files, split_lines=True, with_errors=False, ignore_errors=True, none_on_ignored_error=True, log_output_on_error=False) # The output of git diff-tree will be a list of entries that have # changed between the two revisions that we give it. The last part # of the line is the name of the file that has changed. changed_files = remove_filenames_matching_patterns( (filename.split()[-1] for filename in changed_files), exclude_patterns, base_dir=self._git_toplevel) diff_lines = [] for filename in changed_files: lines = self._execute(diff_cmd + [rev_range, '--', filename], split_lines=True, with_errors=False, ignore_errors=True, none_on_ignored_error=True, log_output_on_error=False, results_unicode=False) if lines is None: logging.error( 'Could not get diff for all files (git-diff failed ' 'for "%s"). Refusing to return a partial diff.', filename) diff_lines = None break diff_lines += lines else: diff_lines = self._execute(diff_cmd + [rev_range] + include_files, split_lines=True, with_errors=False, ignore_errors=True, none_on_ignored_error=True, log_output_on_error=False, results_unicode=False) if self._type == self.TYPE_GIT_SVN: return self.make_svn_diff(merge_base, diff_lines) elif self._type == self.TYPE_GIT_P4: return self.make_perforce_diff(merge_base, diff_lines) else: return b''.join(diff_lines)
def make_diff(self, merge_base, base, tip, include_files, exclude_patterns): """Performs a diff on a particular branch range.""" rev_range = "%s..%s" % (base, tip) if include_files: include_files = ['--'] + include_files if self.type in ('svn', 'perforce'): diff_cmd_params = ['--no-color', '--no-prefix', '-r', '-u'] elif self.type == 'git': diff_cmd_params = ['--no-color', '--full-index', '--ignore-submodules'] if (self.capabilities is not None and self.capabilities.has_capability('diffs', 'moved_files')): diff_cmd_params.append('-M') else: diff_cmd_params.append('--no-renames') else: assert False # By default, don't allow using external diff commands. This prevents # things from breaking horribly if someone configures a graphical diff # viewer like p4merge or kaleidoscope. This can be overridden by # setting GIT_USE_EXT_DIFF = True in ~/.reviewboardrc if not self.user_config.get('GIT_USE_EXT_DIFF', False): diff_cmd_params.append('--no-ext-diff') diff_cmd = [self.git, 'diff'] + diff_cmd_params if exclude_patterns: # If we have specified files to exclude, we will get a list of all # changed files and run `git diff` on each un-excluded file # individually. changed_files_cmd = [self.git, 'diff-tree'] + diff_cmd_params if self.type == 'git': changed_files_cmd.append('-r') changed_files = execute( changed_files_cmd + [rev_range] + include_files, split_lines=True, with_errors=False, ignore_errors=True, none_on_ignored_error=True) # The output of git diff-tree will be a list of entries that have # changed between the two revisions that we give it. The last part # of the line is the name of the file that has changed. changed_files = remove_filenames_matching_patterns( (filename.split()[-1] for filename in changed_files), exclude_patterns, base_dir=self._get_root_directory()) diff_lines = [] for filename in changed_files: lines = execute(diff_cmd + [rev_range, '--', filename], split_lines=True, with_errors=False, ignore_errors=True, none_on_ignored_error=True) if lines is None: logging.error( 'Could not get diff for all files (git-diff failed ' 'for "%s"). Refusing to return a partial diff.' % filename) diff_lines = None break diff_lines += lines else: diff_lines = execute(diff_cmd + [rev_range] + include_files, split_lines=True, with_errors=False, ignore_errors=True, none_on_ignored_error=True) if self.type == 'svn': return self.make_svn_diff(merge_base, diff_lines) elif self.type == 'perforce': return self.make_perforce_diff(merge_base, diff_lines) else: return ''.join(diff_lines)