示例#1
0
    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)
示例#2
0
    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)
示例#3
0
文件: git.py 项目: kristi/rbtools
    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)