<commit_before>#!/usr/bin/env python
# -- Content-Encoding: UTF-8 --
"""
Core of the COHORTE Forker

**TODO:**
* Review all the code !

:author: <NAME>
:license: GPLv3
"""

# Documentation strings format
__docformat__ = "restructuredtext en"

# Boot module version
__version__ = "1.0.0"

# ------------------------------------------------------------------------------

# COHORTE modules
import cohorte.forker
import cohorte.monitor
import cohorte.utils as utils

# Pelix framework
from pelix.ipopo.decorators import ComponentFactory, Requires, Validate, \
    Invalidate, Provides

# Standard library
import json
import logging
import os
import subprocess
import sys
import threading
import uuid

if sys.version_info[0] == 3:
    # Python 3
    from urllib.parse import quote

else:
    # Python 2
    from urllib import quote

# ------------------------------------------------------------------------------

# Ugly code from Recipe 576780 in ActivateState, by
# http://code.activestate.com/recipes/576780-timeout-for-nearly-any-callable
#
# Uses Thread private/protected methods to kill a thread
if sys.version_info[0] == 3:
    # Python 3
    _Thread_stop = getattr(threading.Thread, '_stop', None)

else:
    # Python 2
    _Thread_stop = getattr(threading.Thread, '_Thread__stop', None)

# ------------------------------------------------------------------------------

MONITOR_KIND = 'osgi'
""" Kind of isolate for the monitor """

MONITOR_NAME = 'cohorte.internals.monitor'
""" All monitors have the same name """

_logger = logging.getLogger(__name__)

# ------------------------------------------------------------------------------

ISOLATE_STATUS_CLASS = "org.psem2m.isolates.base.isolates.boot.IsolateStatus"

ISOLATE_STATUS_SIGNAL = "/psem2m/isolate/status"

# ------------------------------------------------------------------------------

@ComponentFactory('cohorte-forker-factory')
@Provides(cohorte.SERVICE_FORKER)
@Requires('_config', cohorte.SERVICE_CONFIGURATION_READER)
@Requires('_config_broker', cohorte.SERVICE_CONFIGURATION_BROKER)
@Requires('_receiver', cohorte.SERVICE_SIGNALS_RECEIVER)
@Requires('_sender', cohorte.SERVICE_SIGNALS_SENDER)
@Requires('_state_dir', 'cohorte.forker.state')
@Requires('_state_updater', 'cohorte.forker.state.updater')
class Forker(object):
    """
    The forker core component
    """
    def __init__(self):
        """
        Constructor
        """
        # Injected services
        self._config = None
        self._config_broker = None
        self._receiver = None
        self._sender = None
        self._state_dir = None
        self._state_updater = None

        # Bundle context
        self._context = None

        # Get OS specific methods
        self._utils = utils.get_os_utils()

        # Platform is not yet stopped
        self._platform_stopping = False

        # Monitor UID
        self._monitor_uid = None

        # Isolate ID -> process object
        self._isolates = {}

        # List of watching threads Isolate ID -> Thread
        self._threads = {}

        # Loop control of thread watching isolates
        self._watchers_running = False


    def _start_monitor_in_thread(self):
        """
        Starts a new thread to handle the launch of the monitor
        """
        def start_monitor_checker():
            """
            Calls _start_monitor and stops the framework if it fails 
            """
            try:
                if self._start_monitor() not in (0, 1):
                    # Monitor has not been started or is not yet running,
                    # it is a fatal error.
                    _logger.error("Forker couldn't start a monitor. Abandon.")
                    if self._context:
                        # Stop the framework
                        self._context.get_bundle(0).stop()

                else:
                    # All right
                    _logger.debug('Monitor started')

            except Exception as ex:
                # Something went wrong
                _logger.exception("Error starting the monitor: %s", ex)
                if self._context:
                    # Stop the framework
                    self._context.get_bundle(0).stop()

        # Start the thread
        thread = threading.Thread(target=start_monitor_checker,
                                  name="monitor-starter")
        thread.start()


    def _start_monitor(self):
        """
        Starts the monitor isolate, calling the boot module in a new interpreter
        instance.
        
        :return: The start_isolate() result code 
        """
        # Test if the monitor is running
        if self._monitor_uid is not None \
        and self._state_dir.knows(self._monitor_uid):
            # Isolate is already running
            return 1

        # TODO: test a bit more (what if the UID has been reset ?)

        # Store the monitor UID
        self._monitor_uid = str(uuid.uuid4())
        node = self._context.get_property(cohorte.PROP_NODE)

        # Make the configuration
        try:
            # Load the boot-monitor file
            configuration = self._config.prepare_isolate(self._monitor_uid,
                                                         MONITOR_NAME, node,
                                                         MONITOR_KIND,
                                                         'java', 'monitor')

        except IOError as ex:
            _logger.error("Can't read a configuration for the monitor: %s", ex)
            return -1

        except KeyError as ex:
            _logger.error("Missing a parameter in the configuration of the "
                          "monitor: %s", ex)
            return -1

        except ValueError as ex:
            _logger.error("Error reading the the configuration of the "
                          "monitor: %s", ex)
            return -1
<commit_msg>Le forker démarrer un moniteur Python<commit_after>#!/usr/bin/env python
# -- Content-Encoding: UTF-8 --
"""
Core of the COHORTE Forker

**TODO:**
* Review all the code !

:author: <NAME>
:license: GPLv3
"""

# Documentation strings format
__docformat__ = "restructuredtext en"

# Boot module version
__version__ = "1.0.0"

# ------------------------------------------------------------------------------

# COHORTE modules
import cohorte.forker
import cohorte.monitor
import cohorte.utils as utils

# Pelix framework
from pelix.ipopo.decorators import ComponentFactory, Requires, Validate, \
    Invalidate, Provides

# Standard library
import json
import logging
import os
import subprocess
import sys
import threading
import uuid

if sys.version_info[0] == 3:
    # Python 3
    from urllib.parse import quote

else:
    # Python 2
    from urllib import quote

# ------------------------------------------------------------------------------

# Ugly code from Recipe 576780 in ActivateState, by
# http://code.activestate.com/recipes/576780-timeout-for-nearly-any-callable
#
# Uses Thread private/protected methods to kill a thread
if sys.version_info[0] == 3:
    # Python 3
    _Thread_stop = getattr(threading.Thread, '_stop', None)

else:
    # Python 2
    _Thread_stop = getattr(threading.Thread, '_Thread__stop', None)

# ------------------------------------------------------------------------------

MONITOR_KIND = 'pelix'
""" Kind of isolate for the monitor """

MONITOR_LANGUAGE = 'python'
""" Language of implementation of the monitor """

MONITOR_NAME = 'cohorte.internals.monitor'
""" All monitors have the same name """

_logger = logging.getLogger(__name__)

# ------------------------------------------------------------------------------

ISOLATE_STATUS_CLASS = "org.psem2m.isolates.base.isolates.boot.IsolateStatus"

ISOLATE_STATUS_SIGNAL = "/psem2m/isolate/status"

# ------------------------------------------------------------------------------

@ComponentFactory('cohorte-forker-factory')
@Provides(cohorte.SERVICE_FORKER)
@Requires('_config', cohorte.SERVICE_CONFIGURATION_READER)
@Requires('_config_broker', cohorte.SERVICE_CONFIGURATION_BROKER)
@Requires('_receiver', cohorte.SERVICE_SIGNALS_RECEIVER)
@Requires('_sender', cohorte.SERVICE_SIGNALS_SENDER)
@Requires('_state_dir', 'cohorte.forker.state')
@Requires('_state_updater', 'cohorte.forker.state.updater')
class Forker(object):
    """
    The forker core component
    """
    def __init__(self):
        """
        Constructor
        """
        # Injected services
        self._config = None
        self._config_broker = None
        self._receiver = None
        self._sender = None
        self._state_dir = None
        self._state_updater = None

        # Bundle context
        self._context = None

        # Get OS specific methods
        self._utils = utils.get_os_utils()

        # Platform is not yet stopped
        self._platform_stopping = False

        # Monitor UID
        self._monitor_uid = None

        # Isolate ID -> process object
        self._isolates = {}

        # List of watching threads Isolate ID -> Thread
        self._threads = {}

        # Loop control of thread watching isolates
        self._watchers_running = False


    def _start_monitor_in_thread(self):
        """
        Starts a new thread to handle the launch of the monitor
        """
        def start_monitor_checker():
            """
            Calls _start_monitor and stops the framework if it fails 
            """
            try:
                if self._start_monitor() not in (0, 1):
                    # Monitor has not been started or is not yet running,
                    # it is a fatal error.
                    _logger.error("Forker couldn't start a monitor. Abandon.")
                    if self._context:
                        # Stop the framework
                        self._context.get_bundle(0).stop()

                else:
                    # All right
                    _logger.debug('Monitor started')

            except Exception as ex:
                # Something went wrong
                _logger.exception("Error starting the monitor: %s", ex)
                if self._context:
                    # Stop the framework
                    self._context.get_bundle(0).stop()

        # Start the thread
        thread = threading.Thread(target=start_monitor_checker,
                                  name="monitor-starter")
        thread.start()


    def _start_monitor(self):
        """
        Starts the monitor isolate, calling the boot module in a new interpreter
        instance.
        
        :return: The start_isolate() result code 
        """
        # Test if the monitor is running
        if self._monitor_uid is not None \
        and self._state_dir.knows(self._monitor_uid):
            # Isolate is already running
            return 1

        # TODO: test a bit more (what if the UID has been reset ?)

        # Store the monitor UID
        self._monitor_uid = str(uuid.uuid4())
        node = self._context.get_property(cohorte.PROP_NODE)

        # Make the configuration
        try:
            # Load the boot-monitor file
            configuration = self._config.prepare_isolate(self._monitor_uid,
                                                         MONITOR_NAME, node,
                                                         MONITOR_KIND,
                                                         MONITOR_LANGUAGE,
                                                         'monitor')

        except IOError as ex:
            _logger.error("Can't read a configuration for the monitor: %s", ex)
            return -1

        except KeyError as ex:
            _logger.error("Missing a parameter in the configuration of the "
                          "monitor: %s", ex)
            return -1

        except ValueError as ex:
            _logger.error("Error reading the the configuration of the "
                          "monitor: %s", ex)
            return -1

{'fraction_non_alphanumeric': 0.14388670074583088, 'fraction_numerical': 0.006033688091846141, 'mean_word_length': 1.6051080550098231, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1080320', 'n_tokens_mistral': 3201, 'n_tokens_neox': 3046, 'n_words': 865}