Exemple #1
0
    def diff(self,
             revisions,
             include_files=[],
             exclude_patterns=[],
             extra_args=[],
             **kwargs):
        """Perform a diff using the given revisions.

        If the revision spec is empty, this returns the diff of the current
        branch with respect to its parent. If a single revision is passed in,
        this returns the diff of the change introduced in that revision. If two
        revisions are passed in, this will do a diff between those two
        revisions.

        Args:
            revisions (dict):
                A dictionary of revisions, as returned by
                :py:meth:`parse_revision_spec`.

            include_files (list of unicode, optional):
                A list of files to whitelist during the diff generation.

            exclude_patterns (list of unicode, optional):
                A list of shell-style glob patterns to blacklist during diff
                generation.

            extra_args (list, unused):
                Additional arguments to be passed to the diff generation.
                Unused for Bazaar.

            **kwargs (dict, unused):
                Unused keyword arguments.

        Returns:
            dict:
            A dictionary containing the following keys:

            ``diff`` (:py:class:`bytes`):
                The contents of the diff to upload.

            ``parent_diff`` (:py:class:`bytes`, optional):
                The contents of the parent diff, if available.
        """
        exclude_patterns = normalize_patterns(exclude_patterns,
                                              self.get_repository_info().path)

        diff = self._get_range_diff(revisions['base'], revisions['tip'],
                                    include_files, exclude_patterns)

        if 'parent_base' in revisions:
            parent_diff = self._get_range_diff(revisions['parent_base'],
                                               revisions['base'],
                                               include_files, exclude_patterns)
        else:
            parent_diff = None

        return {
            'diff': diff,
            'parent_diff': parent_diff,
        }
Exemple #2
0
    def diff(self, revisions, include_files=[], exclude_patterns=[],
             extra_args=[]):
        """Returns the diff for the given revision spec.

        If the revision spec is empty, this returns the diff of the current
        branch with respect to its parent. If a single revision is passed in,
        this returns the diff of the change introduced in that revision. If two
        revisions are passed in, this will do a diff between those two
        revisions.

        The summary and description are set if guessing is enabled.
        """
        exclude_patterns = normalize_patterns(exclude_patterns,
                                              self.get_repository_info().path)

        diff = self._get_range_diff(revisions['base'], revisions['tip'],
                                    include_files, exclude_patterns)

        if 'parent_base' in revisions:
            parent_diff = self._get_range_diff(
                revisions['parent_base'], revisions['base'], include_files,
                exclude_patterns)
        else:
            parent_diff = None

        return {
            'diff': diff,
            'parent_diff': parent_diff,
        }
Exemple #3
0
    def diff(self,
             revisions,
             include_files=[],
             exclude_patterns=[],
             extra_args=[]):
        """Returns the diff for the given revision spec.

        If the revision spec is empty, this returns the diff of the current
        branch with respect to its parent. If a single revision is passed in,
        this returns the diff of the change introduced in that revision. If two
        revisions are passed in, this will do a diff between those two
        revisions.

        The summary and description are set if guessing is enabled.
        """
        exclude_patterns = normalize_patterns(exclude_patterns)

        diff = self._get_range_diff(revisions['base'], revisions['tip'],
                                    include_files, exclude_patterns)

        if 'parent_base' in revisions:
            parent_diff = self._get_range_diff(revisions['parent_base'],
                                               revisions['base'],
                                               include_files, exclude_patterns)
        else:
            parent_diff = None

        return {
            'diff': diff,
            'parent_diff': parent_diff,
        }
Exemple #4
0
    def diff(self,
             revisions,
             include_files=[],
             exclude_patterns=[],
             extra_args=[]):
        """Get the diff for the given revisions.

        If revision_spec is empty, this will return the diff for the modified
        files in the working directory. If it's not empty and contains two
        revisions, this will do a diff between those revisions.
        """
        exclude_patterns = normalize_patterns(exclude_patterns)

        include_files = include_files or []

        # Diff returns "1" if differences were found.
        diff_cmd = ['cvs', 'diff', '-uN']

        base = revisions['base']
        tip = revisions['tip']
        if (not (base == 'BASE' and tip == self.REVISION_WORKING_COPY)):
            diff_cmd.extend(['-r', base, '-r', tip])

        diff = execute(diff_cmd + include_files,
                       extra_ignore_errors=(1, ),
                       split_lines=True)

        if exclude_patterns:
            # CVS diffs are relative to the current working directory, so the
            # base_dir parameter to filter_diff is unnecessary.
            diff = filter_diff(diff, self.INDEX_FILE_RE, exclude_patterns)

        return {'diff': b''.join(diff)}
Exemple #5
0
    def diff(self, revisions, include_files=[], exclude_patterns=[],
             no_renames=False, extra_args=[]):
        """Get the diff for the given revisions.

        If revision_spec is empty, this will return the diff for the modified
        files in the working directory. If it's not empty and contains two
        revisions, this will do a diff between those revisions.
        """
        # CVS paths are always relative to the current working directory.
        cwd = os.getcwd()
        exclude_patterns = normalize_patterns(exclude_patterns, cwd, cwd)

        include_files = include_files or []

        # Diff returns "1" if differences were found.
        diff_cmd = ['cvs', 'diff', '-uN']

        base = revisions['base']
        tip = revisions['tip']
        if (not (base == 'BASE' and
                 tip == self.REVISION_WORKING_COPY)):
            diff_cmd.extend(['-r', base, '-r', tip])

        diff = execute(diff_cmd + include_files, extra_ignore_errors=(1,),
                       log_output_on_error=False, split_lines=True)

        if exclude_patterns:
            # CVS diffs are relative to the current working directory, so the
            # base_dir parameter to filter_diff is unnecessary.
            diff = filter_diff(diff, self.INDEX_FILE_RE, exclude_patterns,
                               base_dir=cwd)

        return {
            'diff': b''.join(diff)
        }
Exemple #6
0
    def diff(self, revisions, include_files=[], exclude_patterns=[],
             extra_args=[], **kwargs):
        """Perform a diff using the given revisions.

        If the revision spec is empty, this returns the diff of the current
        branch with respect to its parent. If a single revision is passed in,
        this returns the diff of the change introduced in that revision. If two
        revisions are passed in, this will do a diff between those two
        revisions.

        Args:
            revisions (dict):
                A dictionary of revisions, as returned by
                :py:meth:`parse_revision_spec`.

            include_files (list of unicode, optional):
                A list of files to whitelist during the diff generation.

            exclude_patterns (list of unicode, optional):
                A list of shell-style glob patterns to blacklist during diff
                generation.

            extra_args (list, unused):
                Additional arguments to be passed to the diff generation.
                Unused for Bazaar.

            **kwargs (dict, unused):
                Unused keyword arguments.

        Returns:
            dict:
            A dictionary containing the following keys:

            ``diff`` (:py:class:`bytes`):
                The contents of the diff to upload.

            ``parent_diff`` (:py:class:`bytes`, optional):
                The contents of the parent diff, if available.
        """
        exclude_patterns = normalize_patterns(exclude_patterns,
                                              self.get_repository_info().path)

        diff = self._get_range_diff(revisions['base'], revisions['tip'],
                                    include_files, exclude_patterns)

        if 'parent_base' in revisions:
            parent_diff = self._get_range_diff(
                revisions['parent_base'], revisions['base'], include_files,
                exclude_patterns)
        else:
            parent_diff = None

        return {
            'diff': diff,
            'parent_diff': parent_diff,
        }
Exemple #7
0
    def diff(self, revisions, include_files=[], exclude_patterns=[],
             no_renames=False, extra_args=[]):
        """Perform a diff using the given revisions.

        If no revisions are specified, this will do a diff of the contents of
        the current branch since the tracking branch (which defaults to
        'master'). If one revision is specified, this will get the diff of that
        specific change. If two revisions are specified, this will do a diff
        between those two revisions.

        If a parent branch is specified via the command-line options, or would
        make sense given the requested revisions and the tracking branch, this
        will also return a parent diff.
        """
        exclude_patterns = normalize_patterns(exclude_patterns,
                                              self._get_root_directory(),
                                              cwd=self.original_cwd)

        try:
            merge_base = revisions['parent_base']
        except KeyError:
            merge_base = revisions['base']

        diff_lines = self.make_diff(merge_base,
                                    revisions['base'],
                                    revisions['tip'],
                                    include_files,
                                    exclude_patterns,
                                    no_renames)

        if 'parent_base' in revisions:
            parent_diff_lines = self.make_diff(merge_base,
                                               revisions['parent_base'],
                                               revisions['base'],
                                               include_files,
                                               exclude_patterns,
                                               no_renames)

            base_commit_id = revisions['parent_base']
        else:
            parent_diff_lines = None
            base_commit_id = revisions['base']

        return {
            'diff': diff_lines,
            'parent_diff': parent_diff_lines,
            'commit_id': revisions.get('commit_id'),
            'base_commit_id': base_commit_id,
        }
Exemple #8
0
    def diff(self, revisions, include_files=[], exclude_patterns=[],
             extra_args=[]):
        """Get the diff for the given revisions.

        If revision_spec is empty, this will return the diff for the modified
        files in the working directory. If it's not empty and contains two
        revisions, this will do a diff between those revisions.
        """
        exclude_patterns = normalize_patterns(exclude_patterns)

        include_files = include_files or []

        # Diff returns "1" if differences were found.
        diff_cmd = ['cvs', 'diff', '-uN']

        base = revisions['base']
        tip = revisions['tip']
        if (not (base == 'BASE' and
                 tip == self.REVISION_WORKING_COPY)):
            diff_cmd.extend(['-r', base, '-r', tip])

        cwd = os.getcwd()
        os.chdir(self._get_repository_root())

        try:
            diff = execute(diff_cmd + include_files, extra_ignore_errors=(1,),
                           split_lines=True, results_unicode=False)
        finally:
            os.chdir(cwd)

        if exclude_patterns:
            diff = filter_diff(diff, self.INDEX_FILE_RE, exclude_patterns,
                               base_dir=self._get_repository_root())

        return {
            'diff': b''.join(diff)
        }
Exemple #9
0
    def diff(self, revisions, include_files=[], exclude_patterns=[],
             extra_args=[]):
        """Get the diff for the given revisions.

        If revision_spec is empty, this will return the diff for the modified
        files in the working directory. If it's not empty and contains two
        revisions, this will do a diff between those revisions.
        """
        exclude_patterns = normalize_patterns(exclude_patterns)

        include_files = include_files or []

        # Diff returns "1" if differences were found.
        diff_cmd = ['cvs', 'diff', '-uN']

        base = revisions['base']
        tip = revisions['tip']
        if (not (base == 'BASE' and
                 tip == self.REVISION_WORKING_COPY)):
            diff_cmd.extend(['-r', base, '-r', tip])

        cwd = os.getcwd()
        os.chdir(self._get_repository_root())

        try:
            diff = execute(diff_cmd + include_files, extra_ignore_errors=(1,),
                           split_lines=True)
        finally:
            os.chdir(cwd)

        if exclude_patterns:
            diff = filter_diff(diff, self.INDEX_FILE_RE, exclude_patterns,
                               base_dir=self._get_repository_root())

        return {
            'diff': ''.join(diff)
        }
Exemple #10
0
    def diff(self, revisions, include_files=[], exclude_patterns=[],
             extra_args=[]):
        """Perform a diff using the given revisions.

        If no revisions are specified, this will do a diff of the contents of
        the current branch since the tracking branch (which defaults to
        'master'). If one revision is specified, this will get the diff of that
        specific change. If two revisions are specified, this will do a diff
        between those two revisions.

        If a parent branch is specified via the command line options, or would
        make sense given the requested revisions and the tracking branch, this
        will also return a parent diff.

        Args:
            revisions (dict):
                A dictionary of revisions, as returned by
                :py:meth:`parse_revision_spec`.

            include_files (list of unicode, optional):
                A list of files to whitelist during the diff generation.

            exclude_patterns (list of unicode, optional):
                A list of shell-style glob patterns to blacklist during diff
                generation.

            extra_args (list, unused):
                Additional arguments to be passed to the diff generation.
                Unused for git.

        Returns:
            dict:
            A dictionary containing the following keys:

            ``diff`` (:py:class:`bytes`):
                The contents of the diff to upload.

            ``parent_diff`` (:py:class:`bytes`, optional):
                The contents of the parent diff, if available.

            ``commit_id`` (:py:class:`unicode`, optional):
                The commit ID to include when posting, if available.

            ``base_commit_id` (:py:class:`unicode`, optional):
                The ID of the commit that the change is based on, if available.
                This is necessary for some hosting services that don't provide
                individual file access.
        """
        exclude_patterns = normalize_patterns(exclude_patterns,
                                              self._git_toplevel,
                                              cwd=os.getcwd())

        try:
            merge_base = revisions['parent_base']
        except KeyError:
            merge_base = revisions['base']

        diff_lines = self.make_diff(merge_base,
                                    revisions['base'],
                                    revisions['tip'],
                                    include_files,
                                    exclude_patterns)

        if 'parent_base' in revisions:
            parent_diff_lines = self.make_diff(merge_base,
                                               revisions['parent_base'],
                                               revisions['base'],
                                               include_files,
                                               exclude_patterns)

            base_commit_id = revisions['parent_base']
        else:
            parent_diff_lines = None
            base_commit_id = revisions['base']

        return {
            'diff': diff_lines,
            'parent_diff': parent_diff_lines,
            'commit_id': revisions.get('commit_id'),
            'base_commit_id': base_commit_id,
        }
Exemple #11
0
    def diff(self,
             revisions,
             include_files=[],
             exclude_patterns=[],
             extra_args=[]):
        """
        Performs a diff in a Subversion repository.

        If the given revision spec is empty, this will do a diff of the
        modified files in the working directory. If the spec is a changelist,
        it will do a diff of the modified files in that changelist. If the spec
        is a single revision, it will show the changes in that revision. If the
        spec is two revisions, this will do a diff between the two revisions.

        SVN repositories do not support branches of branches in a way that
        makes parent diffs possible, so we never return a parent diff.
        """
        repository_info = self.get_repository_info()

        # SVN paths are always relative to the root of the repository, so we
        # compute the current path we are checked out at and use that as the
        # current working directory. We use / for the base_dir because we do
        # not normalize the paths to be filesystem paths, but instead use SVN
        # paths.
        exclude_patterns = normalize_patterns(exclude_patterns, '/',
                                              repository_info.base_path)

        # Keep track of information needed for handling empty files later.
        empty_files_revisions = {
            'base': None,
            'tip': None,
        }

        base = str(revisions['base'])
        tip = str(revisions['tip'])

        diff_cmd = ['diff', '--diff-cmd=diff', '--notice-ancestry']
        changelist = None

        if tip == self.REVISION_WORKING_COPY:
            # Posting the working copy
            diff_cmd.extend(['-r', base])
        elif tip.startswith(self.REVISION_CHANGELIST_PREFIX):
            # Posting a changelist
            changelist = tip[len(self.REVISION_CHANGELIST_PREFIX):]
            diff_cmd.extend(['--changelist', changelist])
        else:
            # Diff between two separate revisions. Behavior depends on whether
            # or not there's a working copy
            if self.options.repository_url:
                # No working copy--create 'old' and 'new' URLs
                if len(include_files) == 1:
                    # If there's a single file or directory passed in, we use
                    # that as part of the URL instead of as a separate
                    # filename.
                    repository_info.set_base_path(include_files[0])
                    include_files = []

                new_url = (repository_info.path + repository_info.base_path +
                           '@' + tip)

                # When the source revision is '0', assume the user wants to
                # upload a diff containing all the files in 'base_path' as
                # new files. If the base path within the repository is added to
                # both the old and new URLs, `svn diff` will error out, since
                # the base_path didn't exist at revision 0. To avoid that
                # error, use the repository's root URL as the source for the
                # diff.
                if base == '0':
                    old_url = repository_info.path + '@' + base
                else:
                    old_url = (repository_info.path +
                               repository_info.base_path + '@' + base)

                diff_cmd.extend([old_url, new_url])

                empty_files_revisions['base'] = '(revision %s)' % base
                empty_files_revisions['tip'] = '(revision %s)' % tip
            else:
                # Working copy--do a normal range diff
                diff_cmd.extend(['-r', '%s:%s' % (base, tip)])

                empty_files_revisions['base'] = '(revision %s)' % base
                empty_files_revisions['tip'] = '(revision %s)' % tip

        diff_cmd.extend(include_files)

        if is_valid_version(self.subversion_client_version,
                            self.SHOW_COPIES_AS_ADDS_MIN_VERSION):
            svn_show_copies_as_adds = getattr(self.options,
                                              'svn_show_copies_as_adds', None)

            if svn_show_copies_as_adds is None:
                if self.history_scheduled_with_commit(changelist,
                                                      include_files,
                                                      exclude_patterns):
                    sys.stderr.write("One or more files in your changeset has "
                                     "history scheduled with commit. Please "
                                     "try again with "
                                     "'--svn-show-copies-as-adds=y/n'.\n")
                    sys.exit(1)
            else:
                if svn_show_copies_as_adds in 'Yy':
                    diff_cmd.append("--show-copies-as-adds")

        diff = self._run_svn(diff_cmd,
                             split_lines=True,
                             results_unicode=False,
                             log_output_on_error=False)
        diff = self.handle_renames(diff)

        if self.supports_empty_files():
            diff = self._handle_empty_files(diff, diff_cmd,
                                            empty_files_revisions)

        diff = self.convert_to_absolute_paths(diff, repository_info)

        if exclude_patterns:
            diff = filter_diff(diff, self.INDEX_FILE_RE, exclude_patterns)

        return {
            'diff': b''.join(diff),
        }
Exemple #12
0
    def diff(self, revisions, include_files=[], exclude_patterns=[],
             extra_args=[]):
        """
        Performs a diff in a Subversion repository.

        If the given revision spec is empty, this will do a diff of the
        modified files in the working directory. If the spec is a changelist,
        it will do a diff of the modified files in that changelist. If the spec
        is a single revision, it will show the changes in that revision. If the
        spec is two revisions, this will do a diff between the two revisions.

        SVN repositories do not support branches of branches in a way that
        makes parent diffs possible, so we never return a parent diff.
        """
        repository_info = self.get_repository_info()

        # SVN paths are always relative to the root of the repository, so we
        # compute the current path we are checked out at and use that as the
        # current working directory. We use / for the base_dir because we do
        # not normalize the paths to be filesystem paths, but instead use SVN
        # paths.
        exclude_patterns = normalize_patterns(exclude_patterns,
                                              '/',
                                              repository_info.base_path)

        # Keep track of information needed for handling empty files later.
        empty_files_revisions = {
            'base': None,
            'tip': None,
        }

        base = str(revisions['base'])
        tip = str(revisions['tip'])

        diff_cmd = ['diff', '--diff-cmd=diff', '--notice-ancestry']
        changelist = None

        if tip == self.REVISION_WORKING_COPY:
            # Posting the working copy
            diff_cmd.extend(['-r', base])
        elif tip.startswith(self.REVISION_CHANGELIST_PREFIX):
            # Posting a changelist
            changelist = tip[len(self.REVISION_CHANGELIST_PREFIX):]
            diff_cmd.extend(['--changelist', changelist])
        else:
            # Diff between two separate revisions. Behavior depends on whether
            # or not there's a working copy
            if self.options.repository_url:
                # No working copy--create 'old' and 'new' URLs
                if len(include_files) == 1:
                    # If there's a single file or directory passed in, we use
                    # that as part of the URL instead of as a separate
                    # filename.
                    repository_info.set_base_path(include_files[0])
                    include_files = []

                new_url = (repository_info.path + repository_info.base_path +
                           '@' + tip)

                # When the source revision is '0', assume the user wants to
                # upload a diff containing all the files in 'base_path' as
                # new files. If the base path within the repository is added to
                # both the old and new URLs, `svn diff` will error out, since
                # the base_path didn't exist at revision 0. To avoid that
                # error, use the repository's root URL as the source for the
                # diff.
                if base == '0':
                    old_url = repository_info.path + '@' + base
                else:
                    old_url = (repository_info.path +
                               repository_info.base_path + '@' + base)

                diff_cmd.extend([old_url, new_url])

                empty_files_revisions['base'] = '(revision %s)' % base
                empty_files_revisions['tip'] = '(revision %s)' % tip
            else:
                # Working copy--do a normal range diff
                diff_cmd.extend(['-r', '%s:%s' % (base, tip)])

                empty_files_revisions['base'] = '(revision %s)' % base
                empty_files_revisions['tip'] = '(revision %s)' % tip

        diff_cmd.extend(include_files)

        if is_valid_version(self.subversion_client_version,
                            self.SHOW_COPIES_AS_ADDS_MIN_VERSION):
            svn_show_copies_as_adds = getattr(
                self.options, 'svn_show_copies_as_adds', None)

            if svn_show_copies_as_adds is None:
                if self.history_scheduled_with_commit(changelist,
                                                      include_files,
                                                      exclude_patterns):
                    sys.stderr.write("One or more files in your changeset has "
                                     "history scheduled with commit. Please "
                                     "try again with "
                                     "'--svn-show-copies-as-adds=y/n'.\n")
                    sys.exit(1)
            else:
                if svn_show_copies_as_adds in 'Yy':
                    diff_cmd.append("--show-copies-as-adds")

        diff = self._run_svn(diff_cmd, split_lines=True, results_unicode=False,
                             log_output_on_error=False)
        diff = self.handle_renames(diff)

        if self.supports_empty_files():
            diff = self._handle_empty_files(diff, diff_cmd,
                                            empty_files_revisions)

        diff = self.convert_to_absolute_paths(diff, repository_info)

        if exclude_patterns:
            diff = filter_diff(diff, self.INDEX_FILE_RE, exclude_patterns)

        return {
            'diff': b''.join(diff),
        }
Exemple #13
0
    def diff(self, revisions, include_files=[], exclude_patterns=[],
             extra_args=[], **kwargs):
        """Perform a diff using the given revisions.

        If no revisions are specified, this will return the diff for the
        modified files in the working directory. If it's not empty and contains
        two revisions, this will do a diff between those revisions.

        Args:
            revisions (dict):
                A dictionary of revisions, as returned by
                :py:meth:`parse_revision_spec`.

            include_files (list of unicode, optional):
                A list of files to whitelist during the diff generation.

            exclude_patterns (list of unicode, optional):
                A list of shell-style glob patterns to blacklist during diff
                generation.

            extra_args (list, unused):
                Additional arguments to be passed to the diff generation.
                Unused for CVS.

            **kwargs (dict, unused):
                Unused keyword arguments.

        Returns:
            dict:
            A dictionary containing the following keys:

            ``diff`` (:py:class:`bytes`):
                The contents of the diff to upload.
        """
        # CVS paths are always relative to the current working directory.
        cwd = os.getcwd()
        exclude_patterns = normalize_patterns(exclude_patterns, cwd, cwd)

        include_files = include_files or []

        # Diff returns "1" if differences were found.
        diff_cmd = ['cvs', 'diff', '-uN']

        base = revisions['base']
        tip = revisions['tip']
        if not (base == 'BASE' and
                tip == self.REVISION_WORKING_COPY):
            diff_cmd.extend(['-r', base, '-r', tip])

        diff = execute(diff_cmd + include_files,
                       extra_ignore_errors=(1,),
                       log_output_on_error=False,
                       split_lines=True,
                       results_unicode=False)

        if exclude_patterns:
            # CVS diffs are relative to the current working directory, so the
            # base_dir parameter to filter_diff is unnecessary.
            diff = filter_diff(diff, self.INDEX_FILE_RE, exclude_patterns,
                               base_dir=cwd)

        return {
            'diff': b''.join(diff)
        }
Exemple #14
0
    def diff(self,
             revisions,
             include_files=[],
             exclude_patterns=[],
             extra_args=[]):
        """
        Performs a diff in a Subversion repository.

        If the given revision spec is empty, this will do a diff of the
        modified files in the working directory. If the spec is a changelist,
        it will do a diff of the modified files in that changelist. If the spec
        is a single revision, it will show the changes in that revision. If the
        spec is two revisions, this will do a diff between the two revisions.

        SVN repositories do not support branches of branches in a way that
        makes parent diffs possible, so we never return a parent diff.
        """
        exclude_patterns = normalize_patterns(exclude_patterns)

        # Keep track of information needed for handling empty files later.
        empty_files_revisions = {
            'base': None,
            'tip': None,
        }

        base = str(revisions['base'])
        tip = str(revisions['tip'])

        repository_info = self.get_repository_info()

        diff_cmd = ['diff', '--diff-cmd=diff', '--notice-ancestry']
        changelist = None

        if tip == self.REVISION_WORKING_COPY:
            # Posting the working copy
            diff_cmd.extend(['-r', base])
        elif tip.startswith(self.REVISION_CHANGELIST_PREFIX):
            # Posting a changelist
            changelist = tip[len(self.REVISION_CHANGELIST_PREFIX):]
            diff_cmd.extend(['--changelist', changelist])
        else:
            # Diff between two separate revisions. Behavior depends on whether
            # or not there's a working copy
            # Working copy--do a normal range diff

            diff_cmd.extend(['-r', '%s:%s' % (base, tip)])

            empty_files_revisions['base'] = '(revision %s)' % base
            empty_files_revisions['tip'] = '(revision %s)' % tip

        diff_cmd.extend(include_files)

        if self.history_scheduled_with_commit(changelist):
            svn_show_copies_as_adds = getattr(self.options,
                                              'svn_show_copies_as_adds', None)
            if svn_show_copies_as_adds is None:
                sys.stderr.write("One or more files in your changeset has "
                                 "history scheduled with commit. Please try "
                                 "again with '--svn-show-copies-as-adds=y/n"
                                 "'\n")
                sys.exit(1)
            else:
                if svn_show_copies_as_adds in 'Yy':
                    diff_cmd.append("--show-copies-as-adds")

        this_dir = os.getcwd()

        try:
            if getattr(self.options, 'repository_url', None):
                diff_cmd.append(self.options.repository_url)

            diff = self._run_svn(diff_cmd, split_lines=True)
        finally:
            os.chdir(this_dir)

        return {
            'diff': ''.join(diff),
        }
Exemple #15
0
    def diff(self, revisions, include_files=[], exclude_patterns=[],
             extra_args=[], **kwargs):
        """Perform a diff using the given revisions.

        If no revisions are specified, this will return the diff for the
        modified files in the working directory. If it's not empty and contains
        two revisions, this will do a diff between those revisions.

        Args:
            revisions (dict):
                A dictionary of revisions, as returned by
                :py:meth:`parse_revision_spec`.

            include_files (list of unicode, optional):
                A list of files to whitelist during the diff generation.

            exclude_patterns (list of unicode, optional):
                A list of shell-style glob patterns to blacklist during diff
                generation.

            extra_args (list, unused):
                Additional arguments to be passed to the diff generation.
                Unused for CVS.

            **kwargs (dict, unused):
                Unused keyword arguments.

        Returns:
            dict:
            A dictionary containing the following keys:

            ``diff`` (:py:class:`bytes`):
                The contents of the diff to upload.
        """
        # CVS paths are always relative to the current working directory.
        cwd = os.getcwd()
        exclude_patterns = normalize_patterns(exclude_patterns, cwd, cwd)

        include_files = include_files or []

        # Diff returns "1" if differences were found.
        diff_cmd = ['cvs', 'diff', '-uN']

        base = revisions['base']
        tip = revisions['tip']
        if not (base == 'BASE' and
                tip == self.REVISION_WORKING_COPY):
            diff_cmd.extend(['-r', base, '-r', tip])

        diff = execute(diff_cmd + include_files,
                       extra_ignore_errors=(1,),
                       log_output_on_error=False,
                       split_lines=True,
                       results_unicode=False)

        if exclude_patterns:
            # CVS diffs are relative to the current working directory, so the
            # base_dir parameter to filter_diff is unnecessary.
            diff = filter_diff(diff, self.INDEX_FILE_RE, exclude_patterns,
                               base_dir=cwd)

        return {
            'diff': b''.join(diff)
        }