# Path: badwolf/utils.py
# def to_text(value, encoding='utf-8', errors='ignore'):
#     """Convert value to unicode, default encoding is utf-8
# 
#     :param value: Value to be converted
#     :param encoding: Desired encoding
#     """
#     if not value:
#         return ''
#     if isinstance(value, str):
#         return value
#     if isinstance(value, bytes):
#         return value.decode(encoding, errors)
#     return str(value)
# 
# def to_binary(value, encoding='utf-8'):
#     """Convert value to binary string, default encoding is utf-8
# 
#     :param value: Value to be converted
#     :param encoding: Desired encoding
#     """
#     if not value:
#         return b''
#     if isinstance(value, bytes):
#         return value
#     if isinstance(value, str):
#         return value.encode(encoding)
#     return bytes(value)
# 
# def sanitize_sensitive_data(s):
#     return _sanitize_urls(s)
# 
# Path: badwolf/extensions.py

# 
# Path: badwolf/bitbucket.py
# class BuildStatus(object):
#     def __init__(self, client, repo, revision, key, url):
#         self.client = client
#         self.repo = repo
#         self.revision = revision
#         self.key = key
#         self.url = url
# 
#     def get(self):
#         endpoint = '2.0/repositories/{repo}/commit/{revision}/statuses/build/{key}'.format(
#             repo=self.repo,
#             revision=self.revision,
#             key=self.key
#         )
#         return self.client.get(endpoint)
# 
#     def update(self, state, name=None, description=None):
#         endpoint = '2.0/repositories/{repo}/commit/{revision}/statuses/build'.format(
#             repo=self.repo,
#             revision=self.revision
#         )
#         return self.client.post(
#             endpoint,
#             data={
#                 'key': self.key,
#                 'state': state,
#                 'url': self.url,
#                 'name': name,
#                 'description': description,
#             }
#         )
# 
# class BitbucketAPIError(requests.RequestException):
#     """Bitbucket API call error"""
#     def __init__(self, code, error, description, *args, **kwargs):
#         super(BitbucketAPIError, self).__init__(*args, **kwargs)
#         self.code = code
#         self.error = error
#         self.description = description
# 
#     def __repr__(self):
#         return "BitbucketAPIError({}, '{}', '{}')".format(
#             self.code,
#             self.error,
#             self.description
#         )
# 
#     def __str__(self):
#         return 'code: {}, error: {}, description: {}'.format(
#             self.code,
#             self.error,
#             self.description
#         )
# 
# Path: badwolf/notification.py
# def send_mail(recipients, subject, html):
#     logger.info('Sending email to %s', recipients)
#     try:
#         mail.send_message(
#             subject=subject,
#             recipients=recipients,
#             html=html,
#         )
#     except smtplib.SMTPException:
#         logger.exception('Error sending email to %s', recipients)
#         sentry.captureException()


import os
import io
import time
import base64
import logging
import shlex
import deansi
import requests
from html import escape as html_escape
from flask import current_app, render_template, url_for
from requests.exceptions import ReadTimeout
from docker import DockerClient
from docker.errors import APIError, DockerException, ImageNotFound, NotFound
from markupsafe import Markup
from badwolf.utils import to_text, to_binary, sanitize_sensitive_data
from badwolf.extensions import bitbucket, sentry
from badwolf.bitbucket import BuildStatus, BitbucketAPIError
from badwolf.notification import send_mail
            except NotFound:
                pass
            except APIError as api_e:
                if 'can not get logs from container which is dead or marked for removal' in str(api_e):
                    output.append('Build cancelled')
                else:
                    logger.exception('Error removing docker container')
            except (DockerException, ReadTimeout):
                logger.exception('Error removing docker container')

        return exit_code, ''.join(output)

    def update_build_status(self, state, description=None):
        try:
            self.build_status.update(state, description=description)
        except BitbucketAPIError:
            logger.exception('Error calling Bitbucket API')
            sentry.captureException()

    def send_notifications(self, context):
        exit_code = context['exit_code']
        template = 'test_success' if exit_code == 0 else 'test_failure'
        html = render_template('mail/' + template + '.html', **context)
        html = sanitize_sensitive_data(html)

        # Save log html
        log_dir = os.path.join(current_app.config['BADWOLF_LOG_DIR'], self.commit_hash, self.context.task_id)
        os.makedirs(log_dir, exist_ok=True)
        log_file = os.path.join(log_dir, 'build.html')
        with open(log_file, 'wb') as f:

# Path: badwolf/utils.py
# def to_text(value, encoding='utf-8', errors='ignore'):
#     """Convert value to unicode, default encoding is utf-8
# 
#     :param value: Value to be converted
#     :param encoding: Desired encoding
#     """
#     if not value:
#         return ''
#     if isinstance(value, str):
#         return value
#     if isinstance(value, bytes):
#         return value.decode(encoding, errors)
#     return str(value)
# 
# def to_binary(value, encoding='utf-8'):
#     """Convert value to binary string, default encoding is utf-8
# 
#     :param value: Value to be converted
#     :param encoding: Desired encoding
#     """
#     if not value:
#         return b''
#     if isinstance(value, bytes):
#         return value
#     if isinstance(value, str):
#         return value.encode(encoding)
#     return bytes(value)
# 
# def sanitize_sensitive_data(s):
#     return _sanitize_urls(s)
# 
# Path: badwolf/extensions.py

# 
# Path: badwolf/bitbucket.py
# class BuildStatus(object):
#     def __init__(self, client, repo, revision, key, url):
#         self.client = client
#         self.repo = repo
#         self.revision = revision
#         self.key = key
#         self.url = url
# 
#     def get(self):
#         endpoint = '2.0/repositories/{repo}/commit/{revision}/statuses/build/{key}'.format(
#             repo=self.repo,
#             revision=self.revision,
#             key=self.key
#         )
#         return self.client.get(endpoint)
# 
#     def update(self, state, name=None, description=None):
#         endpoint = '2.0/repositories/{repo}/commit/{revision}/statuses/build'.format(
#             repo=self.repo,
#             revision=self.revision
#         )
#         return self.client.post(
#             endpoint,
#             data={
#                 'key': self.key,
#                 'state': state,
#                 'url': self.url,
#                 'name': name,
#                 'description': description,
#             }
#         )
# 
# class BitbucketAPIError(requests.RequestException):
#     """Bitbucket API call error"""
#     def __init__(self, code, error, description, *args, **kwargs):
#         super(BitbucketAPIError, self).__init__(*args, **kwargs)
#         self.code = code
#         self.error = error
#         self.description = description
# 
#     def __repr__(self):
#         return "BitbucketAPIError({}, '{}', '{}')".format(
#             self.code,
#             self.error,
#             self.description
#         )
# 
#     def __str__(self):
#         return 'code: {}, error: {}, description: {}'.format(
#             self.code,
#             self.error,
#             self.description
#         )
# 
# Path: badwolf/notification.py
# def send_mail(recipients, subject, html):
#     logger.info('Sending email to %s', recipients)
#     try:
#         mail.send_message(
#             subject=subject,
#             recipients=recipients,
#             html=html,
#         )
#     except smtplib.SMTPException:
#         logger.exception('Error sending email to %s', recipients)
#         sentry.captureException()


# Path: badwolf/builder.py
import os
import io
import time
import base64
import logging
import shlex
import deansi
import requests
from html import escape as html_escape
from flask import current_app, render_template, url_for
from requests.exceptions import ReadTimeout
from docker import DockerClient
from docker.errors import APIError, DockerException, ImageNotFound, NotFound
from markupsafe import Markup
from badwolf.utils import to_text, to_binary, sanitize_sensitive_data
from badwolf.extensions import bitbucket, sentry
from badwolf.bitbucket import BuildStatus, BitbucketAPIError
from badwolf.notification import send_mail

            except NotFound:
                pass
            except APIError as api_e:
                if 'can not get logs from container which is dead or marked for removal' in str(api_e):
                    output.append('Build cancelled')
                else:
                    logger.exception('Error removing docker container')
            except (DockerException, ReadTimeout):
                logger.exception('Error removing docker container')

        return exit_code, ''.join(output)

    def update_build_status(self, state, description=None):
        try:
            self.build_status.update(state, description=description)
        except BitbucketAPIError:
            logger.exception('Error calling Bitbucket API')
            sentry.captureException()

    def send_notifications(self, context):
        exit_code = context['exit_code']
        template = 'test_success' if exit_code == 0 else 'test_failure'
        html = render_template('mail/' + template + '.html', **context)
        html = sanitize_sensitive_data(html)

        # Save log html
        log_dir = os.path.join(current_app.config['BADWOLF_LOG_DIR'], self.commit_hash, self.context.task_id)
        os.makedirs(log_dir, exist_ok=True)
        log_file = os.path.join(log_dir, 'build.html')
        with open(log_file, 'wb') as f:

            f.write(to_binary(html))