<commit_before># -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals

import logging
import os
from datetime import datetime

try:
    from subvertpy import (AUTH_PARAM_DEFAULT_PASSWORD,
                           AUTH_PARAM_DEFAULT_USERNAME,
                           ra,
                           SubversionException,
                           __version__)
    from subvertpy.client import Client as SVNClient, api_version, get_config

    has_svn_backend = (__version__ >= (0, 9, 1))
except ImportError:
    # This try-except block is here for the sole purpose of avoiding
    # exceptions with nose if subvertpy isn't installed when someone runs
    # the testsuite.
    has_svn_backend = False

from django.utils import six
from django.utils.datastructures import SortedDict
from django.utils.translation import ugettext as _

from reviewboard.scmtools.core import Revision, HEAD, PRE_CREATION
from reviewboard.scmtools.errors import FileNotFoundError, SCMError
from reviewboard.scmtools.svn import base, SVNTool
from reviewboard.scmtools.svn.utils import (collapse_svn_keywords,
                                            has_expanded_svn_keywords)


B = six.binary_type
DIFF_UNIFIED = [B('-u')]
SVN_KEYWORDS = B('svn:keywords')


class Client(base.Client):
    required_module = 'subvertpy'

    def __init__(self, config_dir, repopath, username=None, password=<PASSWORD>):
        super(Client, self).__init__(config_dir, repopath, username, password)
        self.repopath = B(self.repopath)
        self.config_dir = B(config_dir)

        self._ssl_trust_prompt_cb = None

        auth_providers = [
            ra.get_simple_provider(),
            ra.get_username_provider(),
        ]

        if repopath.startswith('https:'):
            auth_providers += [
                ra.get_ssl_client_cert_file_provider(),
                ra.get_ssl_client_cert_pw_file_provider(),
                ra.get_ssl_server_trust_file_provider(),
                ra.get_ssl_server_trust_prompt_provider(self.ssl_trust_prompt),
            ]

        self.auth = ra.Auth(auth_providers)
        self.username = None
        self.password = <PASSWORD>

        if username:
            self.username = username
            self.auth.set_parameter(AUTH_PARAM_DEFAULT_USERNAME,
                                    B(self.username))

        if password:
            self.password = password
            self.auth.set_parameter(AUTH_PARAM_DEFAULT_PASSWORD,
                                    B(self.password))

        cfg = get_config(self.config_dir)
        self.client = SVNClient(cfg, auth=self.auth)

    def set_ssl_server_trust_prompt(self, cb):
        self._ssl_trust_prompt_cb = cb

    def get_file(self, path, revision=HEAD):
        """Returns the contents of a given file at the given revision."""
        if not path:
            raise FileNotFoundError(path, revision)

        revnum = self._normalize_revision(revision)
        path = B(self.normalize_path(path))
        data = six.StringIO()

        try:
            self.client.cat(path, data, revnum)
        except SubversionException as e:
            raise FileNotFoundError(e)

        contents = data.getvalue()

        if has_expanded_svn_keywords(contents):
            keywords = self.get_keywords(path, revision)

            if keywords:
                contents = collapse_svn_keywords(contents, keywords)

        return contents

    def get_keywords(self, path, revision=HEAD):
        """Returns a list of SVN keywords for a given path."""
        revnum = self._normalize_revision(revision, negatives_allowed=False)
        path = self.normalize_path(path)
        return self.client.propget(SVN_KEYWORDS, path, None, revnum).get(path)

    def _normalize_revision(self, revision, negatives_allowed=True):
        if revision is None:
            return None
        elif revision == HEAD:
            return B('HEAD')
        elif revision == PRE_CREATION:
            raise FileNotFoundError('', revision)
        elif isinstance(revision, Revision):
            revision = int(revision.name)
        elif isinstance(revision, (B,) + six.string_types):
            revision = int(revision)

        return revision

    @property
    def repository_info(self):
        """Returns metadata about the repository:<commit_msg>Fix a crash when using Subvertpy 0.11.<commit_after># -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals

import logging
import os
from datetime import datetime

try:
    from subvertpy import (AUTH_PARAM_DEFAULT_PASSWORD,
                           AUTH_PARAM_DEFAULT_USERNAME,
                           ra,
                           SubversionException,
                           __version__)
    from subvertpy.client import Client as SVNClient, api_version, get_config

    has_svn_backend = (__version__ >= (0, 9, 1))
except ImportError:
    # This try-except block is here for the sole purpose of avoiding
    # exceptions with nose if subvertpy isn't installed when someone runs
    # the testsuite.
    has_svn_backend = False

from django.utils import six
from django.utils.datastructures import SortedDict
from django.utils.translation import ugettext as _

from reviewboard.scmtools.core import Revision, HEAD, PRE_CREATION
from reviewboard.scmtools.errors import FileNotFoundError, SCMError
from reviewboard.scmtools.svn import base, SVNTool
from reviewboard.scmtools.svn.utils import (collapse_svn_keywords,
                                            has_expanded_svn_keywords)


B = six.binary_type
DIFF_UNIFIED = [B('-u')]
SVN_KEYWORDS = B('svn:keywords')


class Client(base.Client):
    required_module = 'subvertpy'

    def __init__(self, config_dir, repopath, username=None, password=<PASSWORD>):
        super(Client, self).__init__(config_dir, repopath, username, password)
        self.repopath = B(self.repopath)
        self.config_dir = B(config_dir)

        self._ssl_trust_prompt_cb = None

        auth_providers = [
            ra.get_simple_provider(),
            ra.get_username_provider(),
        ]

        if repopath.startswith('https:'):
            auth_providers += [
                ra.get_ssl_client_cert_file_provider(),
                ra.get_ssl_client_cert_pw_file_provider(),
                ra.get_ssl_server_trust_file_provider(),
                ra.get_ssl_server_trust_prompt_provider(self.ssl_trust_prompt),
            ]

        self.auth = ra.Auth(auth_providers)
        self.username = None
        self.password = None

        if username:
            self.username = username
            self.auth.set_parameter(AUTH_PARAM_DEFAULT_USERNAME,
                                    B(self.username))

        if password:
            self.password = password
            self.auth.set_parameter(AUTH_PARAM_DEFAULT_PASSWORD,
                                    B(self.password))

        cfg = get_config(self.config_dir)
        self.client = SVNClient(cfg, auth=self.auth)

    def set_ssl_server_trust_prompt(self, cb):
        self._ssl_trust_prompt_cb = cb

    def get_file(self, path, revision=HEAD):
        """Returns the contents of a given file at the given revision."""
        if not path:
            raise FileNotFoundError(path, revision)

        revnum = self._normalize_revision(revision)
        path = B(self.normalize_path(path))
        data = six.StringIO()

        try:
            self.client.cat(path, data, revnum)
        except SubversionException as e:
            raise FileNotFoundError(e)

        contents = data.getvalue()

        if has_expanded_svn_keywords(contents):
            keywords = self.get_keywords(path, revision)

            if keywords:
                contents = collapse_svn_keywords(contents, keywords)

        return contents

    def get_keywords(self, path, revision=HEAD):
        """Returns a list of SVN keywords for a given path."""
        revnum = self._normalize_revision(revision)
        path = self.normalize_path(path)

        # Ideally, we'd use client.propget(), which used to work fine.
        # However, Subvertpy 0.11 broke this (tested on Subversion 1.14).
        # Subvertpy passed in an absolute path, which at some point triggers
        # an assertion error, crashing the process.
        #
        # Getting a property list works fine, so we're using that instead.
        #
        # This fix was introduced in Review Board 4.0.4.
        props = self.client.proplist(path,
                                     peg_revision=None,
                                     revision=revnum,
                                     depth=0)

        if props:
            try:
                return props[0][1][SVN_KEYWORDS]
            except (IndexError, KeyError):
                pass

        return {}

    def _normalize_revision(self, revision):
        """Normalize a revision to an integer or byte string.

        Args:
            revision (object):
                The revision to normalize. This can be an integer, byte string,
                Unicode string,
                :py:class:`~reviewboard.scmtools.core.Revision` object, or
                ``None``.

        Returns:
            object:
            The resulting revision. This may be an integer (if providing
            a revision number) or a Unicode string (if using an identifier
            like "HEAD").

        Raises:
            reviewboard.scmtools.errors.FileNotFoundError:
                The revision indicates that the file does not yet exist.
        """
        if revision is None:
            return None
        elif revision == HEAD:
            return B('HEAD')
        elif revision == PRE_CREATION:
            raise FileNotFoundError('', revision)
        elif isinstance(revision, Revision):
            revision = int(revision.name)
        elif isinstance(revision, (B,) + six.string_types):
            revision = int(revision)

        return revision

    @property
    def repository_info(self):
        """Returns metadata about the repository:
{'fraction_non_alphanumeric': 0.0772289036875062, 'fraction_numerical': 0.0022860550641089356, 'mean_word_length': 2.150281778334377, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 11, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6524304', 'n_tokens_mistral': 2829, 'n_tokens_neox': 2678, 'n_words': 695}