# Path: catkin_tools/common.py
# def mkdir_p(path):
#     """Equivalent to UNIX mkdir -p"""
#     if os.path.exists(path):
#         return
#     try:
#         return os.makedirs(path)
#     except OSError as exc:  # Python >2.5
#         if exc.errno == errno.EEXIST and os.path.isdir(path):
#             pass
#         else:
#             raise
# 
# Path: catkin_tools/terminal_color.py
# def fmt(msg, reset=True):
#     """Replaces color annotations with ansi escape sequences"""
#     global _ansi
#     msg = msg.replace('@!', '@{boldon}')
#     msg = msg.replace('@/', '@{italicson}')
#     msg = msg.replace('@_', '@{ulon}')
#     msg = msg.replace('@|', '@{reset}')
#     t = ColorTemplate(msg)
#     return t.substitute(_ansi) + (ansi('reset') if reset else '')
# 
# Path: catkin_tools/execution/events.py
# class ExecutionEvent(object):
# 
#     """Structure for events generated by the Executor.
# 
#     Events can be jobs starting/finishing, commands starting/failing/finishing,
#     commands producing output (each line is an event), or when the executor
#     quits or fails.
#     """
# 
#     # TODO: Make this a map of ID -> fields
#     EVENT_IDS = [
#         'JOB_STATUS',  # A report of running job states
#         'QUEUED_JOB',  # A job has been queued to be executed
#         'STARTED_JOB',  # A job has started to be executed
#         'FINISHED_JOB',  # A job has finished executing (succeeded or failed)
#         'ABANDONED_JOB',  # A job has been abandoned for some reason
#         'STARTED_STAGE',  # A job stage has started to be executed
#         'FINISHED_STAGE',  # A job stage has finished executing (succeeded or failed)
#         'STAGE_PROGRESS',  # A job stage has executed partially
#         'STDOUT',  # A status message from a job
#         'STDERR',  # A warning or error message from a job
#         'SUBPROCESS',  # A subprocess has been created
#         'MESSAGE'
#     ]
# 
#     def __init__(self, event_id, **kwargs):
#         """Create a new event.
# 
#         :param event_id: One of the valid EVENT_IDS
#         :param **kwargs: The additional data to be passed along with this event.
#         """
#         # Store the time this event was generated
#         self.time = time.time()
# 
#         # Make sure the event ID is valid
#         if event_id not in ExecutionEvent.EVENT_IDS:
#             print(ExecutionEvent.EVENT_IDS)
#             raise ValueError("The event ID %s is not a valid executor event." % event_id)
# 
#         # Store the event data
#         self.event_id = event_id
#         self.data = kwargs


import os
import re
import shutil
from glob import glob
from osrf_pycommon.process_utils import AsyncSubprocessProtocol
from catkin_tools.common import mkdir_p
from catkin_tools.terminal_color import fmt
from .events import ExecutionEvent
        return string.decode('utf-8').encode('utf-8')


class IOBufferContainer(object):

    """A simple buffer container for use in logging.

    This class will open a logfile for a given job stage and write to it
    continuously while receiving stdout and stderr.
    """

    def __init__(self, label, job_id, stage_label, event_queue, log_path):
        self.label = label
        self.job_id = job_id
        self.stage_label = stage_label
        self.event_queue = event_queue
        self.log_path = log_path

        self.is_open = False
        self.stdout_buffer = b""
        self.stderr_buffer = b""
        self.interleaved_buffer = b""

        # Construct the logfile path for this job and stage
        logfile_dir_path = os.path.join(log_path, self.job_id)
        self.logfile_basename = os.path.join(logfile_dir_path, '.'.join([self.label, self.stage_label]))
        self.logfile_name = '{}.log'.format(self.logfile_basename)

        # Create the logfile dir if it doesn't exist
        if not os.path.exists(logfile_dir_path):

# Path: catkin_tools/common.py
# def mkdir_p(path):
#     """Equivalent to UNIX mkdir -p"""
#     if os.path.exists(path):
#         return
#     try:
#         return os.makedirs(path)
#     except OSError as exc:  # Python >2.5
#         if exc.errno == errno.EEXIST and os.path.isdir(path):
#             pass
#         else:
#             raise
# 
# Path: catkin_tools/terminal_color.py
# def fmt(msg, reset=True):
#     """Replaces color annotations with ansi escape sequences"""
#     global _ansi
#     msg = msg.replace('@!', '@{boldon}')
#     msg = msg.replace('@/', '@{italicson}')
#     msg = msg.replace('@_', '@{ulon}')
#     msg = msg.replace('@|', '@{reset}')
#     t = ColorTemplate(msg)
#     return t.substitute(_ansi) + (ansi('reset') if reset else '')
# 
# Path: catkin_tools/execution/events.py
# class ExecutionEvent(object):
# 
#     """Structure for events generated by the Executor.
# 
#     Events can be jobs starting/finishing, commands starting/failing/finishing,
#     commands producing output (each line is an event), or when the executor
#     quits or fails.
#     """
# 
#     # TODO: Make this a map of ID -> fields
#     EVENT_IDS = [
#         'JOB_STATUS',  # A report of running job states
#         'QUEUED_JOB',  # A job has been queued to be executed
#         'STARTED_JOB',  # A job has started to be executed
#         'FINISHED_JOB',  # A job has finished executing (succeeded or failed)
#         'ABANDONED_JOB',  # A job has been abandoned for some reason
#         'STARTED_STAGE',  # A job stage has started to be executed
#         'FINISHED_STAGE',  # A job stage has finished executing (succeeded or failed)
#         'STAGE_PROGRESS',  # A job stage has executed partially
#         'STDOUT',  # A status message from a job
#         'STDERR',  # A warning or error message from a job
#         'SUBPROCESS',  # A subprocess has been created
#         'MESSAGE'
#     ]
# 
#     def __init__(self, event_id, **kwargs):
#         """Create a new event.
# 
#         :param event_id: One of the valid EVENT_IDS
#         :param **kwargs: The additional data to be passed along with this event.
#         """
#         # Store the time this event was generated
#         self.time = time.time()
# 
#         # Make sure the event ID is valid
#         if event_id not in ExecutionEvent.EVENT_IDS:
#             print(ExecutionEvent.EVENT_IDS)
#             raise ValueError("The event ID %s is not a valid executor event." % event_id)
# 
#         # Store the event data
#         self.event_id = event_id
#         self.data = kwargs


# Path: catkin_tools/execution/io.py
import os
import re
import shutil
from glob import glob
from osrf_pycommon.process_utils import AsyncSubprocessProtocol
from catkin_tools.common import mkdir_p
from catkin_tools.terminal_color import fmt
from .events import ExecutionEvent

        return string.decode('utf-8').encode('utf-8')


class IOBufferContainer(object):

    """A simple buffer container for use in logging.

    This class will open a logfile for a given job stage and write to it
    continuously while receiving stdout and stderr.
    """

    def __init__(self, label, job_id, stage_label, event_queue, log_path):
        self.label = label
        self.job_id = job_id
        self.stage_label = stage_label
        self.event_queue = event_queue
        self.log_path = log_path

        self.is_open = False
        self.stdout_buffer = b""
        self.stderr_buffer = b""
        self.interleaved_buffer = b""

        # Construct the logfile path for this job and stage
        logfile_dir_path = os.path.join(log_path, self.job_id)
        self.logfile_basename = os.path.join(logfile_dir_path, '.'.join([self.label, self.stage_label]))
        self.logfile_name = '{}.log'.format(self.logfile_basename)

        # Create the logfile dir if it doesn't exist
        if not os.path.exists(logfile_dir_path):

            mkdir_p(logfile_dir_path)