<commit_before># -*- coding: utf-8 -*-
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from base64 import b64encode
from select import select

from airflow import configuration
from airflow.contrib.hooks.ssh_hook import SSHHook
from airflow.exceptions import AirflowException
from airflow.models import BaseOperator
from airflow.utils.decorators import apply_defaults

class SSHOperator(BaseOperator):
    """
    SSHOperator to execute commands on given remote host using the ssh_hook.

    :param ssh_hook: predefined ssh_hook to use for remote execution
    :type ssh_hook: :class:`SSHHook`
    :param ssh_conn_id: connection id from airflow Connections
    :type ssh_conn_id: str
    :param remote_host: remote host to connect
    :type remote_host: str
    :param command: command to execute on remote host
    :type command: str
    :param timeout: timeout (in seconds) for executing the command.
    :type timeout: int
    :param do_xcom_push: return the stdout which also get set in xcom by airflow platform
    :type do_xcom_push: bool
    """

    template_fields = ('command',)

    @apply_defaults
    def __init__(self,
                 ssh_hook=None,
                 ssh_conn_id=None,
                 remote_host=None,
                 command=None,
                 timeout=10,
                 do_xcom_push=False,
                 *args,
                 **kwargs):
        super(SSHOperator, self).__init__(*args, **kwargs)
        self.ssh_hook = ssh_hook
        self.ssh_conn_id = ssh_conn_id
        self.remote_host = remote_host
        self.command = command
        self.timeout = timeout
        self.do_xcom_push = do_xcom_push

    def execute(self, context):
        try:
            if self.ssh_conn_id and not self.ssh_hook:
                self.ssh_hook = SSHHook(ssh_conn_id=self.ssh_conn_id)

            if not self.ssh_hook:
                raise AirflowException("can not operate without ssh_hook or ssh_conn_id")

            if self.remote_host is not None:
                self.ssh_hook.remote_host = self.remote_host

            ssh_client = self.ssh_hook.get_conn()

            if not self.command:
                raise AirflowException("no command specified so nothing to execute here.")

            # Auto apply tty when its required in case of sudo
            get_pty = False
            if self.command.startswith('sudo'):
                get_pty = True

            # set timeout taken as params
            stdin, stdout, stderr = ssh_client.exec_command(command=self.command,
                                                            get_pty=get_pty,
                                                            timeout=self.timeout
                                                            )
            # get channels
            channel = stdout.channel

            # closing stdin
            stdin.close()
            channel.shutdown_write()

            agg_stdout = b''
            agg_stderr = b''

            # capture any initial output in case channel is closed already
            stdout_buffer_length = len(stdout.channel.in_buffer)

            if stdout_buffer_length > 0:
                agg_stdout += stdout.channel.recv(stdout_buffer_length)

            # read from both stdout and stderr
            while not channel.closed or channel.recv_ready() or channel.recv_stderr_ready():
                readq, _, _ = select([channel], [], [], self.timeout)
                for c in readq:
                    if c.recv_ready():
                        line = stdout.channel.recv(len(c.in_buffer))
                        line = line
                        agg_stdout += line
                        self.log.info(line.decode('utf-8').strip('\n'))
                    if c.recv_stderr_ready():
                        line = stderr.channel.recv_stderr(len(c.in_stderr_buffer))
                        line = line
                        agg_stderr += line
                        self.log.warning(line.decode('utf-8').strip('\n'))
                if stdout.channel.exit_status_ready()\
                        and not stderr.channel.recv_stderr_ready()\
                        and not stdout.channel.recv_ready():
                    stdout.channel.shutdown_read()
                    stdout.channel.close()
                    break

            stdout.close()
            stderr.close()

            exit_status = stdout.channel.recv_exit_status()
            if exit_status is 0:
                # returning output if do_xcom_push is set
                if self.do_xcom_push:
                    enable_pickling = configuration.getboolean('core',
                                                               'enable_xcom_pickling')
                    if enable_pickling:
                        return agg_stdout
                    else:
                        return b64encode(agg_stdout).decode('utf-8')

            else:
                error_msg = agg_stderr.decode('utf-8')
                raise AirflowException("error running cmd: {0}, error: {1}"
                                       .format(self.command, error_msg))

        except Exception as e:
            raise AirflowException("SSH operator error: {0}".format(str(e)))

        return True

    def tunnel(self):
        ssh_client = self.ssh_hook.get_conn()
        ssh_client.get_transport()
<commit_msg>[AIRFLOW-2260] [AIRFLOW-2260] SSHOperator add command template .sh files<commit_after># -*- coding: utf-8 -*-
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from base64 import b64encode
from select import select

from airflow import configuration
from airflow.contrib.hooks.ssh_hook import SSHHook
from airflow.exceptions import AirflowException
from airflow.models import BaseOperator
from airflow.utils.decorators import apply_defaults

class SSHOperator(BaseOperator):
    """
    SSHOperator to execute commands on given remote host using the ssh_hook.

    :param ssh_hook: predefined ssh_hook to use for remote execution
    :type ssh_hook: :class:`SSHHook`
    :param ssh_conn_id: connection id from airflow Connections
    :type ssh_conn_id: str
    :param remote_host: remote host to connect
    :type remote_host: str
    :param command: command to execute on remote host
    :type command: str
    :param timeout: timeout (in seconds) for executing the command.
    :type timeout: int
    :param do_xcom_push: return the stdout which also get set in xcom by airflow platform
    :type do_xcom_push: bool
    """

    template_fields = ('command',)
    template_ext = ('.sh',)

    @apply_defaults
    def __init__(self,
                 ssh_hook=None,
                 ssh_conn_id=None,
                 remote_host=None,
                 command=None,
                 timeout=10,
                 do_xcom_push=False,
                 *args,
                 **kwargs):
        super(SSHOperator, self).__init__(*args, **kwargs)
        self.ssh_hook = ssh_hook
        self.ssh_conn_id = ssh_conn_id
        self.remote_host = remote_host
        self.command = command
        self.timeout = timeout
        self.do_xcom_push = do_xcom_push

    def execute(self, context):
        try:
            if self.ssh_conn_id and not self.ssh_hook:
                self.ssh_hook = SSHHook(ssh_conn_id=self.ssh_conn_id)

            if not self.ssh_hook:
                raise AirflowException("can not operate without ssh_hook or ssh_conn_id")

            if self.remote_host is not None:
                self.ssh_hook.remote_host = self.remote_host

            ssh_client = self.ssh_hook.get_conn()

            if not self.command:
                raise AirflowException("no command specified so nothing to execute here.")

            # Auto apply tty when its required in case of sudo
            get_pty = False
            if self.command.startswith('sudo'):
                get_pty = True

            # set timeout taken as params
            stdin, stdout, stderr = ssh_client.exec_command(command=self.command,
                                                            get_pty=get_pty,
                                                            timeout=self.timeout
                                                            )
            # get channels
            channel = stdout.channel

            # closing stdin
            stdin.close()
            channel.shutdown_write()

            agg_stdout = b''
            agg_stderr = b''

            # capture any initial output in case channel is closed already
            stdout_buffer_length = len(stdout.channel.in_buffer)

            if stdout_buffer_length > 0:
                agg_stdout += stdout.channel.recv(stdout_buffer_length)

            # read from both stdout and stderr
            while not channel.closed or channel.recv_ready() or channel.recv_stderr_ready():
                readq, _, _ = select([channel], [], [], self.timeout)
                for c in readq:
                    if c.recv_ready():
                        line = stdout.channel.recv(len(c.in_buffer))
                        line = line
                        agg_stdout += line
                        self.log.info(line.decode('utf-8').strip('\n'))
                    if c.recv_stderr_ready():
                        line = stderr.channel.recv_stderr(len(c.in_stderr_buffer))
                        line = line
                        agg_stderr += line
                        self.log.warning(line.decode('utf-8').strip('\n'))
                if stdout.channel.exit_status_ready()\
                        and not stderr.channel.recv_stderr_ready()\
                        and not stdout.channel.recv_ready():
                    stdout.channel.shutdown_read()
                    stdout.channel.close()
                    break

            stdout.close()
            stderr.close()

            exit_status = stdout.channel.recv_exit_status()
            if exit_status is 0:
                # returning output if do_xcom_push is set
                if self.do_xcom_push:
                    enable_pickling = configuration.getboolean('core',
                                                               'enable_xcom_pickling')
                    if enable_pickling:
                        return agg_stdout
                    else:
                        return b64encode(agg_stdout).decode('utf-8')

            else:
                error_msg = agg_stderr.decode('utf-8')
                raise AirflowException("error running cmd: {0}, error: {1}"
                                       .format(self.command, error_msg))

        except Exception as e:
            raise AirflowException("SSH operator error: {0}".format(str(e)))

        return True

    def tunnel(self):
        ssh_client = self.ssh_hook.get_conn()
        ssh_client.get_transport()
<|endoftext|>


<commit_before>from __future__ import unicode_literals

# The version of Review Board.
#
# This is in the format of:
#
#   (Major, Minor, Micro, Patch, alpha/beta/rc/final, Release Number, Released)
#
VERSION = (2, 0, 17, 0, 'final', 0, True)

# Required version of Django
django_version = 'Django>=1.6.11,<1.7'

def get_version_string():
    version = '%s.%s' % (VERSION[0], VERSION[1])

    if VERSION[2] or VERSION[3]:
        version += ".%s" % VERSION[2]

    if VERSION[3]:
        version += ".%s" % VERSION[3]

    if VERSION[4] != 'final':
        if VERSION[4] == 'rc':
            version += ' RC%s' % VERSION[5]
        else:
            version += ' %s %s' % (VERSION[4], VERSION[5])

    if not is_release():
        version += " (dev)"

    return version

def get_package_version():
    version = '%s.%s' % (VERSION[0], VERSION[1])

    if VERSION[2] or VERSION[3]:
        version += ".%s" % VERSION[2]

    if VERSION[3]:
        version += ".%s" % VERSION[3]

    if VERSION[4] != 'final':
        version += '%s%s' % (VERSION[4], VERSION[5])

    return version

def is_release():
    return VERSION[6]

def get_manual_url():
    if VERSION[2] == 0 and VERSION[4] != 'final':
        manual_ver = 'dev'
    else:
        manual_ver = '%s.%s' % (VERSION[0], VERSION[1])

    return 'https://www.reviewboard.org/docs/manual/%s/' % manual_ver

def initialize():
    """Begins initialization of Review Board.

    This sets up the logging, generates cache serial numbers, and then
    fires an initializing signal that other parts of the codebase can
    connect to. This must be called for such features as e-mail notification
    to work.
    """
    import logging
    import os

    import settings_local

    # Set RBSITE_PYTHON_PATH to the path we need for any RB-bundled
    # scripts we may call.
    os.environ['RBSITE_PYTHONPATH'] = \
        os.path.dirname(settings_local.__file__)

    from Crypto import Random
    from django.conf import settings
    from django.db import DatabaseError
    from djblets import log
    from djblets.cache.serials import generate_ajax_serial

    from reviewboard import signals
    from reviewboard.admin.siteconfig import load_site_config
    from reviewboard.extensions.base import get_extension_manager

    # This overrides a default django templatetag (url), and we want to make
    # sure it will always get loaded in every python instance.
    import reviewboard.site.templatetags

    is_running_test = getattr(settings, 'RUNNING_TEST', False)

    if not is_running_test:
        # Force PyCrypto to re-initialize the random number generator.
        Random.atfork()

        # Set up logging.
        log.init_logging()

    load_site_config()

    if not is_running_test:
        if settings.DEBUG:
            logging.debug("Log file for Review Board v%s (PID %s)" %
                          (get_version_string(), os.getpid()))

        # Generate the AJAX serial, used for AJAX request caching.
        generate_ajax_serial()

        # Store the AJAX serial as a template serial, so we have a reference
        # to the real serial last modified timestamp of our templates. This
        # is useful since the extension manager will be modifying AJAX_SERIAL
        # to prevent stale caches for templates using hooks. Not all templates
        # use hooks, and may want to base cache keys off TEMPLATE_SERIAL
        # instead.
        #
        # We only want to do this once, so we don't end up replacing it
        # later with a modified AJAX_SERIAL later.
        if not getattr(settings, 'TEMPLATE_SERIAL', None):
            settings.TEMPLATE_SERIAL = settings.AJAX_SERIAL

        # Load all extensions
        try:
            get_extension_manager().load()
        except DatabaseError:
            # This database is from a time before extensions, so don't attempt
            # to load any extensions yet.
            pass

    signals.initializing.send(sender=None)

__version_info__ = VERSION[:-1]
__version__ = get_package_version()
<commit_msg>Bump to 2.0.18 dev.<commit_after>from __future__ import unicode_literals

# The version of Review Board.
#
# This is in the format of:
#
#   (Major, Minor, Micro, Patch, alpha/beta/rc/final, Release Number, Released)
#
VERSION = (2, 0, 18, 0, 'alpha', 0, False)

# Required version of Django
django_version = 'Django>=1.6.11,<1.7'

def get_version_string():
    version = '%s.%s' % (VERSION[0], VERSION[1])

    if VERSION[2] or VERSION[3]:
        version += ".%s" % VERSION[2]

    if VERSION[3]:
        version += ".%s" % VERSION[3]

    if VERSION[4] != 'final':
        if VERSION[4] == 'rc':
            version += ' RC%s' % VERSION[5]
        else:
            version += ' %s %s' % (VERSION[4], VERSION[5])

    if not is_release():
        version += " (dev)"

    return version

def get_package_version():
    version = '%s.%s' % (VERSION[0], VERSION[1])

    if VERSION[2] or VERSION[3]:
        version += ".%s" % VERSION[2]

    if VERSION[3]:
        version += ".%s" % VERSION[3]

    if VERSION[4] != 'final':
        version += '%s%s' % (VERSION[4], VERSION[5])

    return version

def is_release():
    return VERSION[6]

def get_manual_url():
    if VERSION[2] == 0 and VERSION[4] != 'final':
        manual_ver = 'dev'
    else:
        manual_ver = '%s.%s' % (VERSION[0], VERSION[1])

    return 'https://www.reviewboard.org/docs/manual/%s/' % manual_ver

def initialize():
    """Begins initialization of Review Board.

    This sets up the logging, generates cache serial numbers, and then
    fires an initializing signal that other parts of the codebase can
    connect to. This must be called for such features as e-mail notification
    to work.
    """
    import logging
    import os

    import settings_local

    # Set RBSITE_PYTHON_PATH to the path we need for any RB-bundled
    # scripts we may call.
    os.environ['RBSITE_PYTHONPATH'] = \
        os.path.dirname(settings_local.__file__)

    from Crypto import Random
    from django.conf import settings
    from django.db import DatabaseError
    from djblets import log
    from djblets.cache.serials import generate_ajax_serial

    from reviewboard import signals
    from reviewboard.admin.siteconfig import load_site_config
    from reviewboard.extensions.base import get_extension_manager

    # This overrides a default django templatetag (url), and we want to make
    # sure it will always get loaded in every python instance.
    import reviewboard.site.templatetags

    is_running_test = getattr(settings, 'RUNNING_TEST', False)

    if not is_running_test:
        # Force PyCrypto to re-initialize the random number generator.
        Random.atfork()

        # Set up logging.
        log.init_logging()

    load_site_config()

    if not is_running_test:
        if settings.DEBUG:
            logging.debug("Log file for Review Board v%s (PID %s)" %
                          (get_version_string(), os.getpid()))

        # Generate the AJAX serial, used for AJAX request caching.
        generate_ajax_serial()

        # Store the AJAX serial as a template serial, so we have a reference
        # to the real serial last modified timestamp of our templates. This
        # is useful since the extension manager will be modifying AJAX_SERIAL
        # to prevent stale caches for templates using hooks. Not all templates
        # use hooks, and may want to base cache keys off TEMPLATE_SERIAL
        # instead.
        #
        # We only want to do this once, so we don't end up replacing it
        # later with a modified AJAX_SERIAL later.
        if not getattr(settings, 'TEMPLATE_SERIAL', None):
            settings.TEMPLATE_SERIAL = settings.AJAX_SERIAL

        # Load all extensions
        try:
            get_extension_manager().load()
        except DatabaseError:
            # This database is from a time before extensions, so don't attempt
            # to load any extensions yet.
            pass

    signals.initializing.send(sender=None)

__version_info__ = VERSION[:-1]
__version__ = get_package_version()
<|endoftext|>


<commit_before>"""Review Board version and package information.

These variables and functions can be used to identify the version of
Review Board. They're largely used for packaging purposes.
"""

from __future__ import unicode_literals

#: The version of Review Board.
#:
#: This is in the format of:
#:
#: (Major, Minor, Micro, Patch, alpha/beta/rc/final, Release Number, Released)
#:
VERSION = (2, 5, 1, 0, 'final', 0, True)

#: The major version of Django we're using.
django_major_version = '1.6'

#: The required version of Django.
django_version = 'Django>=1.6.11,<1.7'

def get_version_string():
    """Return the Review Board version as a human-readable string."""
    version = '%s.%s' % (VERSION[0], VERSION[1])

    if VERSION[2] or VERSION[3]:
        version += ".%s" % VERSION[2]

    if VERSION[3]:
        version += ".%s" % VERSION[3]

    if VERSION[4] != 'final':
        if VERSION[4] == 'rc':
            version += ' RC%s' % VERSION[5]
        else:
            version += ' %s %s' % (VERSION[4], VERSION[5])

    if not is_release():
        version += " (dev)"

    return version

def get_package_version():
    """Return the Review Board version as a Python package version string."""
    version = '%s.%s' % (VERSION[0], VERSION[1])

    if VERSION[2] or VERSION[3]:
        version += ".%s" % VERSION[2]

    if VERSION[3]:
        version += ".%s" % VERSION[3]

    if VERSION[4] != 'final':
        version += '%s%s' % (VERSION[4], VERSION[5])

    return version

def is_release():
    """Return whether this is a released version of Review Board."""
    return VERSION[6]

def get_manual_url():
    """Return the URL to the Review Board manual for this version."""
    if VERSION[2] == 0 and VERSION[4] != 'final':
        manual_ver = 'dev'
    else:
        manual_ver = '%s.%s' % (VERSION[0], VERSION[1])

    return 'https://www.reviewboard.org/docs/manual/%s/' % manual_ver

def initialize():
    """Begin initialization of Review Board.

    This sets up the logging, generates cache serial numbers, loads extensions,
    and sets up other aspects of Review Board. Once it has finished, it will
    fire the :py:data:`reviewboard.signals.initializing` signal.

    This must be called at some point before most features will work, but it
    will be called automatically in a standard install. If you are writing
    an extension or management command, you do not need to call this yourself.
    """
    import logging
    import os

    import settings_local

    # Set RBSITE_PYTHON_PATH to the path we need for any RB-bundled
    # scripts we may call.
    os.environ[b'RBSITE_PYTHONPATH'] = \
        os.path.dirname(settings_local.__file__)

    from Crypto import Random
    from django.conf import settings
    from django.db import DatabaseError
    from djblets import log
    from djblets.cache.serials import generate_ajax_serial

    from reviewboard import signals
    from reviewboard.admin.siteconfig import load_site_config
    from reviewboard.extensions.base import get_extension_manager

    # This overrides a default django templatetag (url), and we want to make
    # sure it will always get loaded in every python instance.
    import reviewboard.site.templatetags

    is_running_test = getattr(settings, 'RUNNING_TEST', False)

    if not is_running_test:
        # Force PyCrypto to re-initialize the random number generator.
        Random.atfork()

        # Set up logging.
        log.init_logging()

    load_site_config()

    if not is_running_test:
        if settings.DEBUG:
            logging.debug("Log file for Review Board v%s (PID %s)" %
                          (get_version_string(), os.getpid()))

        # Generate the AJAX serial, used for AJAX request caching.
        generate_ajax_serial()

        # Store the AJAX serial as a template serial, so we have a reference
        # to the real serial last modified timestamp of our templates. This
        # is useful since the extension manager will be modifying AJAX_SERIAL
        # to prevent stale caches for templates using hooks. Not all templates
        # use hooks, and may want to base cache keys off TEMPLATE_SERIAL
        # instead.
        #
        # We only want to do this once, so we don't end up replacing it
        # later with a modified AJAX_SERIAL later.
        if not getattr(settings, 'TEMPLATE_SERIAL', None):
            settings.TEMPLATE_SERIAL = settings.AJAX_SERIAL

        # Load all extensions
        try:
            get_extension_manager().load()
        except DatabaseError:
            # This database is from a time before extensions, so don't attempt
            # to load any extensions yet.
            pass

    signals.initializing.send(sender=None)

#: An alias for the the version information from :py:data:`VERSION`.
#:
#: This does not include the last entry in the tuple (the released state).
__version_info__ = VERSION[:-1]

#: An alias for the version used for the Python package.
__version__ = get_package_version()
<commit_msg>Bump to 2.5.2 dev.<commit_after>"""Review Board version and package information.

These variables and functions can be used to identify the version of
Review Board. They're largely used for packaging purposes.
"""

from __future__ import unicode_literals

#: The version of Review Board.
#:
#: This is in the format of:
#:
#: (Major, Minor, Micro, Patch, alpha/beta/rc/final, Release Number, Released)
#:
VERSION = (2, 5, 2, 0, 'alpha', 0, False)

#: The major version of Django we're using.
django_major_version = '1.6'

#: The required version of Django.
django_version = 'Django>=1.6.11,<1.7'

def get_version_string():
    """Return the Review Board version as a human-readable string."""
    version = '%s.%s' % (VERSION[0], VERSION[1])

    if VERSION[2] or VERSION[3]:
        version += ".%s" % VERSION[2]

    if VERSION[3]:
        version += ".%s" % VERSION[3]

    if VERSION[4] != 'final':
        if VERSION[4] == 'rc':
            version += ' RC%s' % VERSION[5]
        else:
            version += ' %s %s' % (VERSION[4], VERSION[5])

    if not is_release():
        version += " (dev)"

    return version

def get_package_version():
    """Return the Review Board version as a Python package version string."""
    version = '%s.%s' % (VERSION[0], VERSION[1])

    if VERSION[2] or VERSION[3]:
        version += ".%s" % VERSION[2]

    if VERSION[3]:
        version += ".%s" % VERSION[3]

    if VERSION[4] != 'final':
        version += '%s%s' % (VERSION[4], VERSION[5])

    return version

def is_release():
    """Return whether this is a released version of Review Board."""
    return VERSION[6]

def get_manual_url():
    """Return the URL to the Review Board manual for this version."""
    if VERSION[2] == 0 and VERSION[4] != 'final':
        manual_ver = 'dev'
    else:
        manual_ver = '%s.%s' % (VERSION[0], VERSION[1])

    return 'https://www.reviewboard.org/docs/manual/%s/' % manual_ver

def initialize():
    """Begin initialization of Review Board.

    This sets up the logging, generates cache serial numbers, loads extensions,
    and sets up other aspects of Review Board. Once it has finished, it will
    fire the :py:data:`reviewboard.signals.initializing` signal.

    This must be called at some point before most features will work, but it
    will be called automatically in a standard install. If you are writing
    an extension or management command, you do not need to call this yourself.
    """
    import logging
    import os

    import settings_local

    # Set RBSITE_PYTHON_PATH to the path we need for any RB-bundled
    # scripts we may call.
    os.environ[b'RBSITE_PYTHONPATH'] = \
        os.path.dirname(settings_local.__file__)

    from Crypto import Random
    from django.conf import settings
    from django.db import DatabaseError
    from djblets import log
    from djblets.cache.serials import generate_ajax_serial

    from reviewboard import signals
    from reviewboard.admin.siteconfig import load_site_config
    from reviewboard.extensions.base import get_extension_manager

    # This overrides a default django templatetag (url), and we want to make
    # sure it will always get loaded in every python instance.
    import reviewboard.site.templatetags

    is_running_test = getattr(settings, 'RUNNING_TEST', False)

    if not is_running_test:
        # Force PyCrypto to re-initialize the random number generator.
        Random.atfork()

        # Set up logging.
        log.init_logging()

    load_site_config()

    if not is_running_test:
        if settings.DEBUG:
            logging.debug("Log file for Review Board v%s (PID %s)" %
                          (get_version_string(), os.getpid()))

        # Generate the AJAX serial, used for AJAX request caching.
        generate_ajax_serial()

        # Store the AJAX serial as a template serial, so we have a reference
        # to the real serial last modified timestamp of our templates. This
        # is useful since the extension manager will be modifying AJAX_SERIAL
        # to prevent stale caches for templates using hooks. Not all templates
        # use hooks, and may want to base cache keys off TEMPLATE_SERIAL
        # instead.
        #
        # We only want to do this once, so we don't end up replacing it
        # later with a modified AJAX_SERIAL later.
        if not getattr(settings, 'TEMPLATE_SERIAL', None):
            settings.TEMPLATE_SERIAL = settings.AJAX_SERIAL

        # Load all extensions
        try:
            get_extension_manager().load()
        except DatabaseError:
            # This database is from a time before extensions, so don't attempt
            # to load any extensions yet.
            pass

    signals.initializing.send(sender=None)

#: An alias for the the version information from :py:data:`VERSION`.
#:
#: This does not include the last entry in the tuple (the released state).
__version_info__ = VERSION[:-1]

#: An alias for the version used for the Python package.
__version__ = get_package_version()
<|endoftext|>


<commit_before>import logging
from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.exc import IntegrityError, SQLAlchemyError

from prf.utils import dictset, DataProxy, split_strip, process_limit
from prf.json_httpexceptions import JHTTPConflict, JHTTPBadRequest, JHTTPNotFound

log = logging.getLogger(__name__)

def includeme(config):
    import pyramid
    config.add_tween('prf.sqla.sqla_exc_tween', over=pyramid.tweens.MAIN)

def sqla2http(exc, session):
    _, _, failed = exc.message.partition(':')
    _, _, param = failed.partition('.')

    try:
        if isinstance(exc, IntegrityError) and 'unique' in exc.message.lower():
            msg = "Must be unique '%s'" % param
            return JHTTPConflict(msg, extra={'data': exc})
        elif isinstance(exc, IntegrityError) and 'not null' in exc.message.lower():

            msg = "Missing '%s'" % param
            return JHTTPBadRequest(msg, extra={'data': exc})
        else:
            return exc
    finally:
        session.rollback()

def sqla_exc_tween(handler, registry):

    def exc_dict(e):
        return {'class': e.__class__, 'message': e.message}

    def exc(request):
        try:
            return handler(request)
        except SQLAlchemyError, e:
            import traceback
            log.error(traceback.format_exc())
            raise JHTTPBadRequest('Unknown', request=request,
                                  exception=exc_dict(e))
        except:
            raise
        finally:
            request.db.rollback()

    return exc

def order_by_clauses(model, _sort):
    _sort_param = []

    def _raise(attr):
        model.get_session().rollback()
        raise JHTTPBadRequest("Bad attribute '%s'" % attr)

    for each in split_strip(_sort):
        if each.startswith('-'):
            each = each[1:]
            attr = getattr(model, each, None)
            if not attr:
                _raise(each)

            _sort_param.append(attr.desc())
            continue
        elif each.startswith('+'):

            each = each[1:]

        attr = getattr(model, each, None)
        if not attr:
            _raise(each)

        _sort_param.append(attr.asc())

    return _sort_param

class Base(object):

    _type = property(lambda self: self.__class__.__name__)

    @classmethod
    def get_session(cls):
        raise NotImplementedError('Must return a session')

    @declared_attr
    def __tablename__(cls):
        return cls.__name__.lower()

    def to_dict(self, request=None, **kw):

        def get_data():
            _dict = dictset()
            att_names = [attr for attr in dir(self)
                         if not callable(getattr(self, attr))
                         and not attr.startswith('__')]

            for attr in att_names:
                _dict[attr] = getattr(self, attr)

            return _dict

        _data = get_data()

        _data['_type'] = self._type
        _data.update(kw.pop('override', {}))
        return DataProxy(_data).to_dict(**kw)

    def repr_parts(self):
        return []

    def __repr__(self):
        parts = []

        if hasattr(self, 'id'):
            parts.append('id=%s' % self.id)

        if hasattr(self, '_version'):
            parts.append('v=%s' % self._version)

        parts.extend(self.repr_parts())

        return '<%s: %s>' % (self.__class__.__name__, ', '.join(parts))

    def save(self, commit=True):
        session = self.get_session()

        session.add(self)
        try:
            session.commit()
        except IntegrityError, e:
            raise sqla2http(e, session)

        return self

    def _update(self, params, **kw):
        for key, value in params.items():
            setattr(self, key, value)

        return self.save(**kw)

    def delete(self):
        session = self.get_session()
        session.delete(self)
        try:
            session.commit()
        except IntegrityError as e:
            raise sqla2http(e, session)

    @classmethod
    def prep_params(cls, params):
        params = dictset(params)

        __confirmation = '__confirmation' in params
        params.pop('__confirmation', False)

        _sort = split_strip(params.pop('_sort', []))
        _fields = split_strip(params.pop('_fields', []))
        _limit = params.pop('_limit', None)
        _page = params.pop('_page', None)
        _start = params.pop('_start', None)
        _count = '_count' in params
        params.pop('_count', None)

        return params, locals()

    @classmethod
    def query(cls, *args, **kw):
        return cls.get_session().query(cls)

    @classmethod
    def objects(cls, **params):
        params, specials = cls.prep_params(params)
        return cls.get_session().query(cls).filter_by(**params)

    @classmethod
    def get_collection(cls, *args, **params):
        session = cls.get_session()
        params, specials = cls.prep_params(params)

        if specials['_limit'] is None:
            session.rollback()
            raise KeyError('Missing _limit')

        query = session.query(cls)

        if args:
            query = query.filter(*args)

        if params:
            query = session.query(cls).filter_by(**params)

        if specials['_sort']:
            query = query.order_by(*order_by_clauses(cls, specials['_sort']))

        start, limit = process_limit(specials['_start'], specials['_page'],
                                     specials['_limit'])

        total = query.count()

        query = query.offset(start).limit(limit)

        if specials['_count']:
            return total

        query._prf_meta = dict(total=total, start=start,
                               fields=specials['_fields'])

        return query

    @classmethod
    def get_resource(cls, _raise=True, **params):
        params['_limit'] = 1
        params, specials = cls.prep_params(params)
        try:
            obj = cls.get_session().query(cls).filter_by(**params).one()
            obj._prf_meta = dict(fields=specials['_fields'])
            return obj
        except NoResultFound, e:
            msg = "'%s(%s)' resource not found" % (cls.__name__, params)
            if _raise:
                session.rollback()
                raise JHTTPNotFound(msg)
            else:
                log.debug(msg)
                return None

    @classmethod
    def get(cls, **params):
        return cls.get_resource(_raise=False, **params)

    @classmethod
    def get_or_create(cls, **kw):
        params = kw.pop('defaults', {})
        params.update(kw)
        obj = cls.get(**kw)
        if obj:
            return obj, False
        else:
            return cls(**params).save(), True
<commit_msg>* added NoResultFound<commit_after>import logging
from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.exc import IntegrityError, SQLAlchemyError

from prf.utils import dictset, DataProxy, split_strip, process_limit
from prf.json_httpexceptions import JHTTPConflict, JHTTPBadRequest, JHTTPNotFound

log = logging.getLogger(__name__)

def includeme(config):
    import pyramid
    config.add_tween('prf.sqla.sqla_exc_tween', over=pyramid.tweens.MAIN)

def sqla2http(exc, session):
    _, _, failed = exc.message.partition(':')
    _, _, param = failed.partition('.')

    try:
        if isinstance(exc, IntegrityError) and 'unique' in exc.message.lower():
            msg = "Must be unique '%s'" % param
            return JHTTPConflict(msg, extra={'data': exc})

        elif isinstance(exc, IntegrityError) and 'not null' in exc.message.lower():
            msg = "Missing '%s'" % param
            return JHTTPBadRequest(msg, extra={'data': exc})

        elif isinstance(exc, NoResultFound):
            return JHTTPNotFound()

        else:
            return exc
    finally:
        session.rollback()

def sqla_exc_tween(handler, registry):

    def exc_dict(e):
        return {'class': e.__class__, 'message': e.message}

    def exc(request):
        try:
            return handler(request)
        except (IntegrityError, NoResultFound) as e:
            raise sqla2http(e, request.db)
        except SQLAlchemyError as e:
            import traceback
            log.error(traceback.format_exc())
            raise JHTTPBadRequest('Unknown', request=request,
                                  exception=exc_dict(e))
        except:
            raise
        finally:
            request.db.rollback()

    return exc

def order_by_clauses(model, _sort):
    _sort_param = []

    def _raise(attr):
        model.get_session().rollback()
        raise JHTTPBadRequest("Bad attribute '%s'" % attr)

    for each in split_strip(_sort):
        if each.startswith('-'):
            each = each[1:]
            attr = getattr(model, each, None)
            if not attr:
                _raise(each)

            _sort_param.append(attr.desc())
            continue
        elif each.startswith('+'):

            each = each[1:]

        attr = getattr(model, each, None)
        if not attr:
            _raise(each)

        _sort_param.append(attr.asc())

    return _sort_param

class Base(object):

    _type = property(lambda self: self.__class__.__name__)

    @classmethod
    def get_session(cls):
        raise NotImplementedError('Must return a session')

    @declared_attr
    def __tablename__(cls):
        return cls.__name__.lower()

    def to_dict(self, request=None, **kw):

        def get_data():
            _dict = dictset()
            att_names = [attr for attr in dir(self)
                         if not callable(getattr(self, attr))
                         and not attr.startswith('__')]

            for attr in att_names:
                _dict[attr] = getattr(self, attr)

            return _dict

        _data = get_data()

        _data['_type'] = self._type
        _data.update(kw.pop('override', {}))
        return DataProxy(_data).to_dict(**kw)

    def repr_parts(self):
        return []

    def __repr__(self):
        parts = []

        if hasattr(self, 'id'):
            parts.append('id=%s' % self.id)

        if hasattr(self, '_version'):
            parts.append('v=%s' % self._version)

        parts.extend(self.repr_parts())

        return '<%s: %s>' % (self.__class__.__name__, ', '.join(parts))

    def save(self, commit=True):
        session = self.get_session()

        session.add(self)
        try:
            session.commit()
        except IntegrityError, e:
            raise sqla2http(e, session)

        return self

    def _update(self, params, **kw):
        for key, value in params.items():
            setattr(self, key, value)

        return self.save(**kw)

    def delete(self):
        session = self.get_session()
        session.delete(self)
        try:
            session.commit()
        except IntegrityError as e:
            raise sqla2http(e, session)

    @classmethod
    def prep_params(cls, params):
        params = dictset(params)

        __confirmation = '__confirmation' in params
        params.pop('__confirmation', False)

        _sort = split_strip(params.pop('_sort', []))
        _fields = split_strip(params.pop('_fields', []))
        _limit = params.pop('_limit', None)
        _page = params.pop('_page', None)
        _start = params.pop('_start', None)
        _count = '_count' in params
        params.pop('_count', None)

        return params, locals()

    @classmethod
    def query(cls, *args, **kw):
        return cls.get_session().query(cls, *args, **kw)

    @classmethod
    def objects(cls, **params):
        params, specials = cls.prep_params(params)
        return cls.get_session().query(cls).filter_by(**params)

    @classmethod
    def get_collection(cls, *args, **params):
        session = cls.get_session()
        params, specials = cls.prep_params(params)

        if specials['_limit'] is None:
            session.rollback()
            raise KeyError('Missing _limit')

        query = session.query(cls)

        if args:
            query = query.filter(*args)

        if params:
            query = session.query(cls).filter_by(**params)

        if specials['_sort']:
            query = query.order_by(*order_by_clauses(cls, specials['_sort']))

        start, limit = process_limit(specials['_start'], specials['_page'],
                                     specials['_limit'])

        total = query.count()

        query = query.offset(start).limit(limit)

        if specials['_count']:
            return total

        query._prf_meta = dict(total=total, start=start,
                               fields=specials['_fields'])

        return query

    @classmethod
    def get_resource(cls, _raise=True, **params):
        session = cls.get_session()
        params['_limit'] = 1
        params, specials = cls.prep_params(params)
        try:
            obj = session.query(cls).filter_by(**params).one()
            obj._prf_meta = dict(fields=specials['_fields'])
            return obj
        except NoResultFound, e:
            msg = "'%s(%s)' resource not found" % (cls.__name__, params)
            if _raise:
                session.rollback()
                raise JHTTPNotFound(msg)
            else:
                log.debug(msg)
                return None

    @classmethod
    def get(cls, **params):
        return cls.get_resource(_raise=False, **params)

    @classmethod
    def get_or_create(cls, **kw):
        params = kw.pop('defaults', {})
        params.update(kw)
        obj = cls.get(**kw)
        if obj:
            return obj, False
        else:
            return cls(**params).save(), True
<|endoftext|>


<commit_before>import logging
import socket
import json
import random
import os

class Spooler():
    def __init__(self, spooldir):
        try:
            os.chdir(spooldir)
        except OSError as e:
            logging.debug("Could not chdir to spooldir: %s", e)
            logging.warning("Couldn't open spooler directory, trying to create...")
            try:
                os.mkdir(spooldir)
                logging.info("Successfully created spooler directory %s", spooldir)
                os.chdir(spooldir)
            except OSError as e:
                logging.error("Could not use specified spooling directory: %s", e)
        logging.info("Spooler successfully initialized")

    def rndSpoolFile(self):
        num = random.random()
        num *= 10000
        return str(int(num))

    def spoolJob(self, jobToSpool):
        job = {}
        logging.debug("Locking job")
        job["locked"] = True
        logging.info("Spooling Job")
        job["postScript"] = jobToSpool
        jobFile = open(self.rndSpoolFile(), 'w')
        json.dump(job, jobFile)

class Printer():
    def __init__(self, bindaddr, port, name):
        logging.info("Creating new printer %s on %s:%s", name, bindaddr, port)
        try:
            self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.s.bind((bindaddr, port))
        except Exception as e:
            logging.error("Failed to bind printer %s", name)
            logging.error(e)
        logging.info("Initializing new spooler for %s", name)
        self.spooler = Spooler(name)

    def listener(self):
        self.s.listen(1)
        con, addr = self.s.accept()
        self.getJob(con, addr)

    def getJob(self, con, addr):
        job = ""
        data = ""
        con.settimeout(1)
        while("%%EOF" not in job):
            try:
                data = con.recv(1024)
                job += data
            except Exception as e:
                logging.error("Encountered error %s", e)
                break
        logging.debug("{} wrote:".format(addr))
        logging.debug(job)
        self.spooler.spoolJob(job)

if __name__=="__main__":
    logging.basicConfig(level=logging.DEBUG)
    logging.debug("Initializing prntSrv in test mode")
    printer = Printer(socket.gethostbyname(socket.gethostname()), 9001, "test")
    printer.listener()
<commit_msg>detect duplex options in postscript<commit_after>import logging
import socket
import json
import random
import os

class Spooler():
    def __init__(self, spooldir):
        try:
            os.chdir(spooldir)
        except OSError as e:
            logging.debug("Could not chdir to spooldir: %s", e)
            logging.warning("Couldn't open spooler directory, trying to create...")
            try:
                os.mkdir(spooldir)
                logging.info("Successfully created spooler directory %s", spooldir)
                os.chdir(spooldir)
            except OSError as e:
                logging.error("Could not use specified spooling directory: %s", e)
        logging.info("Spooler successfully initialized")

    def rndSpoolFile(self):
        num = random.random()
        num *= 10000
        return str(int(num))

    def spoolJob(self, jobToSpool):
        job = {}
        logging.debug("Locking job")
        job["locked"] = True
        logging.info("Spooling Job")
        if "/Duplex true" in jobToSpool:
            job["duplex"] = True
        else:
            job["duplex"] = False
        job["postScript"] = jobToSpool
        jobFile = open(self.rndSpoolFile(), 'w')
        json.dump(job, jobFile)

class Printer():
    def __init__(self, bindaddr, port, name):
        logging.info("Creating new printer %s on %s:%s", name, bindaddr, port)
        try:
            self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.s.bind((bindaddr, port))
        except Exception as e:
            logging.error("Failed to bind printer %s", name)
            logging.error(e)
        logging.info("Initializing new spooler for %s", name)
        self.spooler = Spooler(name)

    def listener(self):
        self.s.listen(1)
        con, addr = self.s.accept()
        self.getJob(con, addr)

    def getJob(self, con, addr):
        job = ""
        data = ""
        con.settimeout(1)
        while("%%EOF" not in job):
            try:
                data = con.recv(1024)
                job += data
            except Exception as e:
                logging.error("Encountered error %s", e)
                break
        logging.debug("{} wrote:".format(addr))
        logging.debug(job)
        self.spooler.spoolJob(job)

if __name__=="__main__":
    logging.basicConfig(level=logging.DEBUG)
    logging.debug("Initializing prntSrv in test mode")
    printer = Printer(socket.gethostbyname(socket.gethostname()), 9001, "test")
    printer.listener()
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

"""Utilities for working with Markdoc configurations."""

import os

import cherrypy.wsgiserver
import markdown
import yaml

import markdoc.exc

class ConfigNotFound(markdoc.exc.AbortError):
    """The configuration file was not found."""
    pass

class MarkdocConfig(dict):

    """A dictionary which represents a single wiki's Markdoc configuration."""

    def __init__(self, config_file, config):
        super(MarkdocConfig, self).__init__(config)
        self.setdefault('meta', {})['config_file'] = config_file
        self['meta']['root'] = os.path.dirname(config_file)

    @classmethod
    def for_directory(cls, directory=None):

        """
        Get the configuration from the 'markdoc.yaml' file in a directory.

        If you do not specify a directory, this method will use the current
        working directory.
        """

        if directory is None:
            directory = os.getcwd()

        config_file = os.path.join(directory, 'markdoc.yaml')

        if not os.path.exists(config_file):
            relpath = os.path.relpath(directory)
            if relpath == '.':
                raise ConfigNotFound("markdoc.yaml was not found in the current directory")
            raise ConfigNotFound("markdoc.yaml was not found in %s" % relpath)

        fp = open(config_file)
        try:
            config = yaml.load(fp)
        finally:
            fp.close()

        return cls(config_file, config)

    def markdown(self, **config):
        """Return a `markdown.Markdown` instance for this configuration."""

        # Set up the default markdown configuration.
        mdconfig = self.setdefault('markdown', {})
        mdconfig.setdefault('extensions', [])
        mdconfig.setdefault('extension_configs', {})
        mdconfig.setdefault('safe_mode', False)
        mdconfig.setdefault('output_format', 'xhtml1')

        config.update(mdconfig) # Include any extra kwargs.
        return markdown.Markdown(**mdconfig)

    def server_maker(self, **config):

        """
        Return a server-making callable to create a CherryPy WSGI server.

        The server-making callable should be passed a WSGI application, and it
        will return an instance of `cherrypy.wsgiserver.CherryPyWSGIServer`.
        """

        svconfig = self.setdefault('server', {})
        bind = svconfig.setdefault('bind', '127.0.0.1')
        port = svconfig.setdefault('port', 8008)
        num_threads = svconfig.setdefault('num_threads', 10)
        server_name = svconfig.setdefault('server_name', None)
        request_queue_size = svconfig.setdefault('request_queue_size', 5)
        timeout = svconfig.setdefault('timeout', 10)

        bind_addr = (bind, port)
        kwargs = {
            'num_threads': threads,
            'server_name': server_name,
            'request_queue_size': request_queue_size,
            'timeout': timeout}

        return lambda wsgi_app: cherrypy.wsgiserver.CherryPyWSGIServer(bind_addr, wsgi_app, **kwargs)
<commit_msg>Added a Jinja2 template environment property to MarkdocConfig.<commit_after># -*- coding: utf-8 -*-

"""Utilities for working with Markdoc configurations."""

import os

import cherrypy.wsgiserver
import jinja2
import markdown
import yaml

import markdoc.exc

class ConfigNotFound(markdoc.exc.AbortError):
    """The configuration file was not found."""
    pass

class MarkdocConfig(dict):

    """A dictionary which represents a single wiki's Markdoc configuration."""

    def __init__(self, config_file, config):
        super(MarkdocConfig, self).__init__(config)
        self.setdefault('meta', {})['config_file'] = config_file
        self['meta'].setdefault('root', os.path.dirname(config_file))

    @classmethod
    def for_directory(cls, directory=None):

        """
        Get the configuration from the 'markdoc.yaml' file in a directory.

        If you do not specify a directory, this method will use the current
        working directory.
        """

        if directory is None:
            directory = os.getcwd()

        config_file = os.path.join(directory, 'markdoc.yaml')

        if not os.path.exists(config_file):
            relpath = os.path.relpath(directory)
            if relpath == '.':
                raise ConfigNotFound("markdoc.yaml was not found in the current directory")
            raise ConfigNotFound("markdoc.yaml was not found in %s" % relpath)

        fp = open(config_file)
        try:
            config = yaml.load(fp)
        finally:
            fp.close()

        return cls(config_file, config)

    @property
    def template_env(self):
        if not self.__template_env:
            template_dir = os.path.join(self['meta']['root'], '.templates')
            loader = jinja2.FileSystemLoader(template_dir)
            self.__template_env = jinja2.Environment(loader=loader)
        return self.__template_env

    def markdown(self, **config):
        """Return a `markdown.Markdown` instance for this configuration."""

        # Set up the default markdown configuration.
        mdconfig = self.setdefault('markdown', {})
        mdconfig.setdefault('extensions', [])
        mdconfig.setdefault('extension_configs', {})
        mdconfig.setdefault('safe_mode', False)
        mdconfig.setdefault('output_format', 'xhtml1')

        config.update(mdconfig) # Include any extra kwargs.
        return markdown.Markdown(**mdconfig)

    def server_maker(self, **config):

        """
        Return a server-making callable to create a CherryPy WSGI server.

        The server-making callable should be passed a WSGI application, and it
        will return an instance of `cherrypy.wsgiserver.CherryPyWSGIServer`.
        """

        svconfig = self.setdefault('server', {})
        bind = svconfig.setdefault('bind', '127.0.0.1')
        port = svconfig.setdefault('port', 8008)
        num_threads = svconfig.setdefault('num_threads', 10)
        server_name = svconfig.setdefault('server_name', None)
        request_queue_size = svconfig.setdefault('request_queue_size', 5)
        timeout = svconfig.setdefault('timeout', 10)

        bind_addr = (bind, port)
        kwargs = {
            'num_threads': threads,
            'server_name': server_name,
            'request_queue_size': request_queue_size,
            'timeout': timeout}

        return lambda wsgi_app: cherrypy.wsgiserver.CherryPyWSGIServer(bind_addr, wsgi_app, **kwargs)
<|endoftext|>


<commit_before># -*- coding: UTF8

'''
Created on 17.08.2015

@author: mEDI
'''

import os
import re
from datetime import datetime

class location(object):
    '''
    location.getLocation() return the current system
    '''

    mydb = None
    location = None
    _lastCDate = None
    _lastFile = None
    _lastPos = None

    def __init__(self, mydb):
        '''
        Constructor
        '''
        self.mydb = mydb
        self.eliteLogDir = self.mydb.getConfig('EliteLogDir')

    def getLocation(self):

        cDate, logfile = self.getLastLog()

        if logfile:
            if not self._lastCDate or cDate > self._lastCDate:
                self._lastCDate = cDate
                self.readLog(logfile)

        if not self.location:
            self.location = ""

        return self.location

    def getLastLog(self):
        if not os.path.isdir(self.eliteLogDir):
            print("Warning: EliteLogDir:'%s' does not exist" % self.eliteLogDir)
            return (None, None)

        logfiles = []
        for f in os.listdir(self.eliteLogDir):
            if os.path.isfile(os.path.join(self.eliteLogDir, f)) and len(f) > 4 and re.match(r"^netLog.*\.log$", f):

                path = os.path.join(self.eliteLogDir, f)
                cDate = datetime.fromtimestamp(os.path.getmtime(path))

                logfiles.append([cDate, path])

        logfiles = sorted(logfiles, key=lambda f: f[0], reverse=True)

        return (logfiles[0][0], logfiles[0][1])

    def readLog(self, logfile):

        fh = open(logfile, 'rb')

        if self._lastFile == logfile and self._lastPos:
            fh.seek(self._lastPos, 0)
        else:
            self._lastFile = logfile

        for line in fh:
            locationma = re.search("^\{\d{2}:\d{2}:\d{2}\} System\:\d+\((.*?)\) .*", line.decode(encoding='ascii', errors='replace'))

            if locationma:
                if locationma.group(1):
                    self.location = locationma.group(1)

        self._lastPos = fh.tell()
        fh.close()
<commit_msg>fix crast with wrong log path<commit_after># -*- coding: UTF8

'''
Created on 17.08.2015

@author: mEDI
'''

import os
import re
from datetime import datetime

class location(object):
    '''
    location.getLocation() return the current system
    '''

    mydb = None
    location = None
    _lastCDate = None
    _lastFile = None
    _lastPos = None

    def __init__(self, mydb):
        '''
        Constructor
        '''
        self.mydb = mydb
        self.eliteLogDir = self.mydb.getConfig('EliteLogDir')

    def getLocation(self):

        cDate, logfile = self.getLastLog()

        if logfile:
            if not self._lastCDate or cDate > self._lastCDate:
                self._lastCDate = cDate
                self.readLog(logfile)

        if not self.location:
            self.location = ""

        return self.location

    def getLastLog(self):
        if not os.path.isdir(self.eliteLogDir):
            print("Warning: EliteLogDir:'%s' does not exist" % self.eliteLogDir)
            return (None, None)

        logfiles = []
        for f in os.listdir(self.eliteLogDir):
            if os.path.isfile(os.path.join(self.eliteLogDir, f)) and len(f) > 4 and re.match(r"^netLog.*\.log$", f):

                path = os.path.join(self.eliteLogDir, f)
                cDate = datetime.fromtimestamp(os.path.getmtime(path))

                logfiles.append([cDate, path])

        if logfiles:
            logfiles = sorted(logfiles, key=lambda f: f[0], reverse=True)
            return (logfiles[0][0], logfiles[0][1])
        else:
            return (None, None)

    def readLog(self, logfile):

        fh = open(logfile, 'rb')

        if self._lastFile == logfile and self._lastPos:
            fh.seek(self._lastPos, 0)
        else:
            self._lastFile = logfile

        for line in fh:
            locationma = re.search("^\{\d{2}:\d{2}:\d{2}\} System\:\d+\((.*?)\) .*", line.decode(encoding='ascii', errors='replace'))

            if locationma:
                if locationma.group(1):
                    self.location = locationma.group(1)

        self._lastPos = fh.tell()
        fh.close()
<|endoftext|>


<commit_before>"""
Monitors crashes.
Can also be set to warn and kick crashing players.
"""

from autostew_back.gameserver.event import EventType, BaseEvent
from autostew_back.gameserver.participant import Participant
from autostew_back.gameserver.server import Server as DedicatedServer
from autostew_back.gameserver.session import SessionState
from autostew_back.plugins.db_session_writer_libs import db_safety_rating
from autostew_web_users.models import SteamUser

name = 'crash monitor'

warn_at = 0.7
ban_time = 0
crash_points_limit = 4000  # Set to zero to disable kicking
environment_crash_multiplier = 4
crash_points = {}

def event(server: DedicatedServer, event: BaseEvent):
    if event.type == EventType.impact:
        for participant in event.participants:
            if participant.is_player.get():
                add_crash_points(
                    event.magnitude if event.human_to_human else int(event.magnitude / environment_crash_multiplier),
                    participant,
                    server
                )

    if event.type == EventType.state_changed and event.new_state == SessionState.lobby:
        reset_crash_points()

def reset_crash_points():
    global crash_points
    crash_points = {}

def add_crash_points(crash_points_increase: int, participant: Participant, server: DedicatedServer):
    steam_id = server.members.get_by_id(participant.refid.get()).steam_id.get()
    crash_points[steam_id] = crash_points.setdefault(steam_id, 0) + crash_points_increase

    try:
        steam_user = SteamUser.objects.get(steam_id=participant.get_member(server).steam_id.get())
        db_safety_rating.impact(steam_user, crash_points_increase)
        if steam_user.over_class_kick_impact_threshold(crash_points_increase):
            participant.kick(server, ban_time)
    except SteamUser.DoesNotExist:
        pass

    crash_notification(crash_points_increase, participant, server)

    if crash_points_limit and crash_points[steam_id] > crash_points_limit:
        participant.kick(server, ban_time)
    elif crash_points_limit and crash_points[steam_id] > warn_at * crash_points_limit:
        crash_limit_warning(participant, server, steam_id)

def crash_notification(crash_points_increase, participant, server):
    participant.send_chat("", server)
    participant.send_chat(
        "CONTACT logged for {points} points.".format(points=crash_points_increase),
        server
    )

def crash_limit_warning(participant, server, steam_id):
    participant.send_chat(
        "CONTACT: You have collected {points} crash points.".format(points=crash_points[steam_id]),
        server
    )
    participant.send_chat(
        "CONTACT: Disqualification at {max_crash_points} points.".format(max_crash_points=crash_points_limit),
        server
    )
<commit_msg>Bugfix<commit_after>"""
Monitors crashes.
Can also be set to warn and kick crashing players.
"""

from autostew_back.gameserver.event import EventType, BaseEvent
from autostew_back.gameserver.participant import Participant
from autostew_back.gameserver.server import Server as DedicatedServer
from autostew_back.gameserver.session import SessionState
from autostew_back.plugins.db_session_writer_libs import db_safety_rating
from autostew_web_users.models import SteamUser

name = 'crash monitor'

warn_at = 0.7
ban_time = 0
crash_points_limit = 4000  # Set to zero to disable kicking
environment_crash_multiplier = 4
crash_points = {}

def event(server: DedicatedServer, event: BaseEvent):
    if event.type == EventType.impact:
        for participant in event.participants:
            if participant and participant.is_player.get():
                add_crash_points(
                    event.magnitude if event.human_to_human else int(event.magnitude / environment_crash_multiplier),
                    participant,
                    server
                )

    if event.type == EventType.state_changed and event.new_state == SessionState.lobby:
        reset_crash_points()

def reset_crash_points():
    global crash_points
    crash_points = {}

def add_crash_points(crash_points_increase: int, participant: Participant, server: DedicatedServer):
    steam_id = server.members.get_by_id(participant.refid.get()).steam_id.get()
    crash_points[steam_id] = crash_points.setdefault(steam_id, 0) + crash_points_increase

    try:
        steam_user = SteamUser.objects.get(steam_id=participant.get_member(server).steam_id.get())
        db_safety_rating.impact(steam_user, crash_points_increase)
        if steam_user.over_class_kick_impact_threshold(crash_points_increase):
            participant.kick(server, ban_time)
    except SteamUser.DoesNotExist:
        pass

    crash_notification(crash_points_increase, participant, server)

    if crash_points_limit and crash_points[steam_id] > crash_points_limit:
        participant.kick(server, ban_time)
    elif crash_points_limit and crash_points[steam_id] > warn_at * crash_points_limit:
        crash_limit_warning(participant, server, steam_id)

def crash_notification(crash_points_increase, participant, server):
    participant.send_chat("", server)
    participant.send_chat(
        "CONTACT logged for {points} points.".format(points=crash_points_increase),
        server
    )

def crash_limit_warning(participant, server, steam_id):
    participant.send_chat(
        "CONTACT: You have collected {points} crash points.".format(points=crash_points[steam_id]),
        server
    )
    participant.send_chat(
        "CONTACT: Disqualification at {max_crash_points} points.".format(max_crash_points=crash_points_limit),
        server
    )
<|endoftext|>


<commit_before># Copyright (c) 2016 SUSE.  All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""
Data-disks are virtual disks attached to a virtual machine, backed by a virtual
hard disk (VHD) image in Azure storage.

usage: azurectl compute data-disk -h | --help
       azurectl compute data-disk create --disk-basename=<name>
           [--size=<disk-size-in-GB>]
           [--label=<label>]
       azurectl compute data-disk delete --disk-name=<name>
       azurectl compute data-disk attach --cloud-service-name=<name> --disk-name=<name>
           [--instance-name=<name>]
           [--label=<label>]
           [--lun=<lun>]
           [--no-cache|--read-only-cache|--read-write-cache]
           [--wait]
       azurectl compute data-disk detach --cloud-service-name=<name> --lun=<lun>
           [--instance-name=<name>]
           [--wait]
       azurectl compute data-disk list
       azurectl compute data-disk show --disk-name=<name>
       azurectl compute data-disk show attached --cloud-service-name=<name>
           [--lun=<lun>]
           [--instance-name=<name>]
       azurectl compute data-disk help

commands:
    create
        create a new, empty data disk. The data disk vhd file will be
        created using the following naming schema:
        <disk-basename>-data-disk-<utctime>, e.g
        disk-basename-data-disk-2016-08-22T09_15_25.950289.
        The default data disk size is set to 10GB
    delete
        delete the specified data disk. The call will fail if the disk
        is still attached to an instance
    detach
        detach a data disk from the selected virtual machine and retain the
        data disk vhd file
    list
        return list of all disks from your image repository
    show
        return details of the specified disk
    show attached
        return details about the data disk(s) attached to the selected
        virtual machine. If a lun is specified only details about the
        disk connected to that lun will be shown

options:
    --cloud-service-name=<name>
        name of the cloud service where the virtual machine may be found
    --disk-name=<name>
        name of the data disk as registered in the image repository
    --disk-basename=<name>
        data disk basename used as part of the complete data disk name.
        Usually this is set to the instance name this data disk should be
        attached to later
    --instance-name=<name>
        name of the virtual machine instance. If no name is given the
        instance name is assumed to be the same as the cloud service name
    --label=<label>
        custom label name for the disk
    --lun=<lun>
        logical unit number where the disk is mounted. Must be an integer
        between 0 and 15. If omitted during create, the first available LUN
        will be selected automatically
    --no-cache
        disable caching on the data disk
    --read-only-cache
        enable cached reads from the data disk. If a cache method is not
        selected, read-only will be selected by default
    --read-write-cache
        enable cached reads from and writes to the data disk
    --size=<disk-size-in-GB>
        size of the disk, in GB, that will be provisioned. Must be an integer,
        and less than 1024 [default: 10]
    --wait
        wait for the request to succeed
"""
# project
from ..logger import log
from ..account.service import AzureAccount
from base import CliTask
from ..utils.collector import DataCollector
from ..instance.data_disk import DataDisk
from ..utils.output import DataOutput
from ..defaults import Defaults
from ..help import Help

class ComputeDataDiskTask(CliTask):
    """
        Process image commands
    """
    def process(self):
        self.manual = Help()
        if self.__help():
            return

        self.result = DataCollector()
        self.out = DataOutput(
            self.result,
            self.global_args['--output-format'],
            self.global_args['--output-style']
        )

        self.load_config()

        self.account = AzureAccount(self.config)
        self.data_disk = DataDisk(self.account)

        if self.command_args['create']:
            self.__create()
        if self.command_args['delete']:
            self.__delete()
        if self.command_args['attach']:
            self.__attach()
        if self.command_args['detach']:
            self.__detach()
        if self.command_args['attached']:
            if self.command_args['show']:
                self.__show_attached()
        else:
            if self.command_args['list']:
                self.__list()
            if self.command_args['show']:
                self.__show()

    def __help(self):
        if self.command_args['help']:
            self.manual.show('azurectl::compute::data_disk')
        else:
            return False
        return self.manual

    def __create(self):
        self.data_disk.create(
            self.command_args['--disk-basename'],
            self.command_args['--size'],
            self.command_args['--label']
        )
        log.info(
            'Created new data disk %s',
            self.data_disk.data_disk_name.replace('.vhd', '')
        )

    def __show(self):
        self.result.add(
            'data-disk', self.data_disk.show(self.command_args['--disk-name'])
        )
        self.out.display()

    def __show_attached(self):
        request_params = [
            self.command_args['--cloud-service-name'],
            (
                self.command_args['--instance-name'] or
                self.command_args['--cloud-service-name']
            ),
            self.command_args['--lun'] or 'on_all_luns'
        ]
        self.result.add(
            'data-disk:%s:%s:%s' % tuple(request_params),
            self.data_disk.show_attached(
                self.command_args['--cloud-service-name'],
                self.command_args['--instance-name'],
                self.command_args['--lun']
            )
        )
        self.out.display()

    def __delete(self):
        self.data_disk.delete(
            self.command_args['--disk-name']
        )
        log.info('Deleted data disk %s', self.command_args['--disk-name'])

    def __attach(self):
        optional_args = {}
        if self.command_args['--label']:
            optional_args['label'] = self.command_args['--label']
        if self.command_args['--lun']:
            optional_args['lun'] = int(self.command_args['--lun'])
        if (
            self.command_args['--no-cache'] or
            self.command_args['--read-only-cache'] or
            self.command_args['--read-write-cache']
        ):
            optional_args['host_caching'] = Defaults.host_caching_for_docopts(
                self.command_args
            )
        request_id = self.data_disk.attach(
            self.command_args['--disk-name'],
            self.command_args['--cloud-service-name'],
            self.command_args['--instance-name'],
            **optional_args
        )
        request_params = [
            self.command_args['--cloud-service-name'],
            (
                self.command_args['--instance-name'] or
                self.command_args['--cloud-service-name']
            ),
            int(self.data_disk.attached_lun)
        ]
        self.result.add(
            'data-disk attach:%s:%s:%d' % tuple(request_params), request_id
        )
        if self.command_args['--wait']:
            self.request_wait(request_id)
        self.out.display()

    def __detach(self):
        request_params = [
            self.command_args['--cloud-service-name'],
            (
                self.command_args['--instance-name'] or
                self.command_args['--cloud-service-name']
            ),
            int(self.command_args['--lun'])
        ]
        request_id = self.result.add(
            'data-disk detach:%s:%s:%d' % tuple(request_params),
            self.data_disk.detach(
                int(self.command_args['--lun']),
                self.command_args['--cloud-service-name'],
                self.command_args['--instance-name']
            )
        )
        if self.command_args['--wait']:
            self.request_wait(request_id)
        self.out.display()

    def __list(self):
        self.result.add(
            'data-disks', self.data_disk.list()
        )
        self.out.display()
<commit_msg>Add missing data-disk attach subcomand help<commit_after># Copyright (c) 2016 SUSE.  All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""
Data-disks are virtual disks attached to a virtual machine, backed by a virtual
hard disk (VHD) image in Azure storage.

usage: azurectl compute data-disk -h | --help
       azurectl compute data-disk create --disk-basename=<name>
           [--size=<disk-size-in-GB>]
           [--label=<label>]
       azurectl compute data-disk delete --disk-name=<name>
       azurectl compute data-disk attach --cloud-service-name=<name> --disk-name=<name>
           [--instance-name=<name>]
           [--label=<label>]
           [--lun=<lun>]
           [--no-cache|--read-only-cache|--read-write-cache]
           [--wait]
       azurectl compute data-disk detach --cloud-service-name=<name> --lun=<lun>
           [--instance-name=<name>]
           [--wait]
       azurectl compute data-disk list
       azurectl compute data-disk show --disk-name=<name>
       azurectl compute data-disk show attached --cloud-service-name=<name>
           [--lun=<lun>]
           [--instance-name=<name>]
       azurectl compute data-disk help

commands:
    create
        create a new, empty data disk. The data disk vhd file will be
        created using the following naming schema:
        <disk-basename>-data-disk-<utctime>, e.g
        disk-basename-data-disk-2016-08-22T09_15_25.950289.
        The default data disk size is set to 10GB
    delete
        delete the specified data disk. The call will fail if the disk
        is still attached to an instance
    attach
        attach the specified data disk to the selected virtual machine
    detach
        detach a data disk from the selected virtual machine and retain the
        data disk vhd file
    list
        return list of all disks from your image repository
    show
        return details of the specified disk
    show attached
        return details about the data disk(s) attached to the selected
        virtual machine. If a lun is specified only details about the
        disk connected to that lun will be shown

options:
    --cloud-service-name=<name>
        name of the cloud service where the virtual machine may be found
    --disk-name=<name>
        name of the data disk as registered in the image repository
    --disk-basename=<name>
        data disk basename used as part of the complete data disk name.
        Usually this is set to the instance name this data disk should be
        attached to later
    --instance-name=<name>
        name of the virtual machine instance. If no name is given the
        instance name is assumed to be the same as the cloud service name
    --label=<label>
        custom label name for the disk
    --lun=<lun>
        logical unit number where the disk is mounted. Must be an integer
        between 0 and 15. If omitted during create, the first available LUN
        will be selected automatically
    --no-cache
        disable caching on the data disk
    --read-only-cache
        enable cached reads from the data disk. If a cache method is not
        selected, read-only will be selected by default
    --read-write-cache
        enable cached reads from and writes to the data disk
    --size=<disk-size-in-GB>
        size of the disk, in GB, that will be provisioned. Must be an integer,
        and less than 1024 [default: 10]
    --wait
        wait for the request to succeed
"""
# project
from ..logger import log
from ..account.service import AzureAccount
from base import CliTask
from ..utils.collector import DataCollector
from ..instance.data_disk import DataDisk
from ..utils.output import DataOutput
from ..defaults import Defaults
from ..help import Help

class ComputeDataDiskTask(CliTask):
    """
        Process image commands
    """
    def process(self):
        self.manual = Help()
        if self.__help():
            return

        self.result = DataCollector()
        self.out = DataOutput(
            self.result,
            self.global_args['--output-format'],
            self.global_args['--output-style']
        )

        self.load_config()

        self.account = AzureAccount(self.config)
        self.data_disk = DataDisk(self.account)

        if self.command_args['create']:
            self.__create()
        if self.command_args['delete']:
            self.__delete()
        if self.command_args['attach']:
            self.__attach()
        if self.command_args['detach']:
            self.__detach()
        if self.command_args['attached']:
            if self.command_args['show']:
                self.__show_attached()
        else:
            if self.command_args['list']:
                self.__list()
            if self.command_args['show']:
                self.__show()

    def __help(self):
        if self.command_args['help']:
            self.manual.show('azurectl::compute::data_disk')
        else:
            return False
        return self.manual

    def __create(self):
        self.data_disk.create(
            self.command_args['--disk-basename'],
            self.command_args['--size'],
            self.command_args['--label']
        )
        log.info(
            'Created new data disk %s',
            self.data_disk.data_disk_name.replace('.vhd', '')
        )

    def __show(self):
        self.result.add(
            'data-disk', self.data_disk.show(self.command_args['--disk-name'])
        )
        self.out.display()

    def __show_attached(self):
        request_params = [
            self.command_args['--cloud-service-name'],
            (
                self.command_args['--instance-name'] or
                self.command_args['--cloud-service-name']
            ),
            self.command_args['--lun'] or 'on_all_luns'
        ]
        self.result.add(
            'data-disk:%s:%s:%s' % tuple(request_params),
            self.data_disk.show_attached(
                self.command_args['--cloud-service-name'],
                self.command_args['--instance-name'],
                self.command_args['--lun']
            )
        )
        self.out.display()

    def __delete(self):
        self.data_disk.delete(
            self.command_args['--disk-name']
        )
        log.info('Deleted data disk %s', self.command_args['--disk-name'])

    def __attach(self):
        optional_args = {}
        if self.command_args['--label']:
            optional_args['label'] = self.command_args['--label']
        if self.command_args['--lun']:
            optional_args['lun'] = int(self.command_args['--lun'])
        if (
            self.command_args['--no-cache'] or
            self.command_args['--read-only-cache'] or
            self.command_args['--read-write-cache']
        ):
            optional_args['host_caching'] = Defaults.host_caching_for_docopts(
                self.command_args
            )
        request_id = self.data_disk.attach(
            self.command_args['--disk-name'],
            self.command_args['--cloud-service-name'],
            self.command_args['--instance-name'],
            **optional_args
        )
        request_params = [
            self.command_args['--cloud-service-name'],
            (
                self.command_args['--instance-name'] or
                self.command_args['--cloud-service-name']
            ),
            int(self.data_disk.attached_lun)
        ]
        self.result.add(
            'data-disk attach:%s:%s:%d' % tuple(request_params), request_id
        )
        if self.command_args['--wait']:
            self.request_wait(request_id)
        self.out.display()

    def __detach(self):
        request_params = [
            self.command_args['--cloud-service-name'],
            (
                self.command_args['--instance-name'] or
                self.command_args['--cloud-service-name']
            ),
            int(self.command_args['--lun'])
        ]
        request_id = self.result.add(
            'data-disk detach:%s:%s:%d' % tuple(request_params),
            self.data_disk.detach(
                int(self.command_args['--lun']),
                self.command_args['--cloud-service-name'],
                self.command_args['--instance-name']
            )
        )
        if self.command_args['--wait']:
            self.request_wait(request_id)
        self.out.display()

    def __list(self):
        self.result.add(
            'data-disks', self.data_disk.list()
        )
        self.out.display()
<|endoftext|>


<commit_before>#!/usr/bin/env python
# vim: set encoding=utf-8

"""
Main wttr.in rendering function implementation
"""

import logging
import os
from flask import render_template, send_file, make_response

import wttrin_png
import parse_query
from translations import get_message, FULL_TRANSLATION, PARTIAL_TRANSLATION, SUPPORTED_LANGS
from buttons import add_buttons
from globals import get_help_file, log, \
                    BASH_FUNCTION_FILE, TRANSLATION_FILE, LOG_FILE, \
                    NOT_FOUND_LOCATION, \
                    MALFORMED_RESPONSE_HTML_PAGE, \
                    PLAIN_TEXT_AGENTS, PLAIN_TEXT_PAGES, \
                    MY_EXTERNAL_IP, QUERY_LIMITS
from location import is_location_blocked, location_processing
from limits import Limits
from wttr import get_wetter, get_moon
from wttr_line import wttr_line

if not os.path.exists(os.path.dirname(LOG_FILE)):
    os.makedirs(os.path.dirname(LOG_FILE))
logging.basicConfig(filename=LOG_FILE, level=logging.DEBUG, format='%(asctime)s %(message)s')

LIMITS = Limits(whitelist=[MY_EXTERNAL_IP], limits=QUERY_LIMITS)

def show_text_file(name, lang):
    """
    show static file `name` for `lang`
    """
    text = ""
    if name == ":help":
        text = open(get_help_file(lang), 'r').read()
        text = text.replace('FULL_TRANSLATION', ' '.join(FULL_TRANSLATION))
        text = text.replace('PARTIAL_TRANSLATION', ' '.join(PARTIAL_TRANSLATION))
    elif name == ":bash.function":
        text = open(BASH_FUNCTION_FILE, 'r').read()
    elif name == ":translation":
        text = open(TRANSLATION_FILE, 'r').read()
        text = text\
                .replace('NUMBER_OF_LANGUAGES', str(len(SUPPORTED_LANGS)))\
                .replace('SUPPORTED_LANGUAGES', ' '.join(SUPPORTED_LANGS))
    return text.decode('utf-8')

def client_ip_address(request):
    """
    Return client ip address for `request`.
    Flask related
    """

    if request.headers.getlist("X-Forwarded-For"):
        ip_addr = request.headers.getlist("X-Forwarded-For")[0]
        if ip_addr.startswith('::ffff:'):
            ip_addr = ip_addr[7:]
    else:
        ip_addr = request.remote_addr

    return ip_addr

def get_answer_language(request):
    """
    Return preferred answer language based on
    domain name, query arguments and headers
    """

    def _parse_accept_language(accept_language):
        languages = accept_language.split(",")
        locale_q_pairs = []

        for language in languages:
            try:
                if language.split(";")[0] == language:
                    # no q => q = 1
                    locale_q_pairs.append((language.strip(), "1"))
                else:
                    locale = language.split(";")[0].strip()
                    weight = language.split(";")[1].split("=")[1]
                    locale_q_pairs.append((locale, weight))
            except IndexError:
                pass

        return locale_q_pairs

    def _find_supported_language(accepted_languages):
        for lang_tuple in accepted_languages:
            lang = lang_tuple[0]
            if '-' in lang:
                lang = lang.split('-', 1)[0]
            if lang in SUPPORTED_LANGS:
                return lang
        return None

    lang = None
    hostname = request.headers['Host']
    if hostname != 'wttr.in' and hostname.endswith('.wttr.in'):
        lang = hostname[:-8]

    if 'lang' in request.args:
        lang = request.args.get('lang')

    header_accept_language = request.headers.get('Accept-Language', '')
    if lang is None and header_accept_language:
        lang = _find_supported_language(
            _parse_accept_language(header_accept_language))

    return lang

def get_output_format(request):
    """
    Return preferred output format: ansi, text, html or png
    based on arguments and headers in `request`.
    Return new location (can be rewritten)
    """

    # FIXME
    user_agent = request.headers.get('User-Agent', '').lower()
    html_output = not any(agent in user_agent for agent in PLAIN_TEXT_AGENTS)
    return html_output

def wttr(location, request):
    """
    Main rendering function, it processes incoming weather queries.
    Depending on user agent it returns output in HTML or ANSI format.

    Incoming data:
        request.args
        request.headers
        request.remote_addr
        request.referrer
        request.query_string
    """

    if is_location_blocked(location):
        return ""

    ip_addr = client_ip_address(request)

    try:
        LIMITS.check_ip(ip_addr)
    except RuntimeError, exception:
        return str(exception)

    png_filename = None
    if location is not None and location.lower().endswith(".png"):
        png_filename = location
        location = location[:-4]

    lang = get_answer_language(request)
    query = parse_query.parse_query(request.args)
    html_output = get_output_format(request)
    user_agent = request.headers.get('User-Agent', '').lower()

    if location in PLAIN_TEXT_PAGES:
        help_ = show_text_file(location, lang)
        if html_output:
            return render_template('index.html', body=help_)
        return help_

    orig_location = location

    location, override_location_name, full_address, country, query_source_location = \
            location_processing(location, ip_addr)

    us_ip = query_source_location[1] == 'United States' and 'slack' not in user_agent
    query = parse_query.metric_or_imperial(query, lang, us_ip=us_ip)

    # logging query
    orig_location_utf8 = (orig_location or "").encode('utf-8')
    location_utf8 = location.encode('utf-8')
    use_imperial = query.get('use_imperial', False)
    log(" ".join(map(str,
                     [ip_addr, user_agent, orig_location_utf8, location_utf8, use_imperial, lang])))

    if country and location != NOT_FOUND_LOCATION:
        location = "%s,%s" % (location, country)

    # We are ready to return the answer
    try:
        if 'format' in query:
            return wttr_line(location, query)

        if png_filename:
            options = {
                'lang': None,
                'location': location}
            options.update(query)

            cached_png_file = wttrin_png.make_wttr_in_png(png_filename, options=options)
            response = make_response(send_file(cached_png_file,
                                               attachment_filename=png_filename,
                                               mimetype='image/png'))
            for key, value in {
                    'Cache-Control': 'no-cache, no-store, must-revalidate',
                    'Pragma': 'no-cache',
                    'Expires': '0',
                }.items():
                response.headers[key] = value

            # Trying to disable github caching
            return response

        if location == 'moon' or location.startswith('moon@'):
            output = get_moon(location, html=html_output, lang=lang)
        else:
            output = get_wetter(location, ip_addr,
                                html=html_output,
                                lang=lang,
                                query=query,
                                location_name=override_location_name,
                                full_address=full_address,
                                url=request.url,
                               )

        if html_output:
            output = add_buttons(output)
        else:
            if query.get('days', '3') != '0':
                #output += '\n' + get_message('NEW_FEATURE', lang).encode('utf-8')
                output += '\n' + get_message('FOLLOW_ME', lang).encode('utf-8') + '\n'
        return output

    except RuntimeError, exception:
        if 'Malformed response' in str(exception) \
                or 'API key has reached calls per day allowed limit' in str(exception):
            if html_output:
                return MALFORMED_RESPONSE_HTML_PAGE
            return get_message('CAPACITY_LIMIT_REACHED', lang).encode('utf-8')
        logging.error("Exception has occured", exc_info=1)
        return "ERROR"
<commit_msg>cyclic location support<commit_after>#!/usr/bin/env python
# vim: set encoding=utf-8

"""
Main wttr.in rendering function implementation
"""

import logging
import os
from flask import render_template, send_file, make_response

import wttrin_png
import parse_query
from translations import get_message, FULL_TRANSLATION, PARTIAL_TRANSLATION, SUPPORTED_LANGS
from buttons import add_buttons
from globals import get_help_file, log, \
                    BASH_FUNCTION_FILE, TRANSLATION_FILE, LOG_FILE, \
                    NOT_FOUND_LOCATION, \
                    MALFORMED_RESPONSE_HTML_PAGE, \
                    PLAIN_TEXT_AGENTS, PLAIN_TEXT_PAGES, \
                    MY_EXTERNAL_IP, QUERY_LIMITS
from location import is_location_blocked, location_processing
from limits import Limits
from wttr import get_wetter, get_moon
from wttr_line import wttr_line

if not os.path.exists(os.path.dirname(LOG_FILE)):
    os.makedirs(os.path.dirname(LOG_FILE))
logging.basicConfig(filename=LOG_FILE, level=logging.DEBUG, format='%(asctime)s %(message)s')

LIMITS = Limits(whitelist=[MY_EXTERNAL_IP], limits=QUERY_LIMITS)

def show_text_file(name, lang):
    """
    show static file `name` for `lang`
    """
    text = ""
    if name == ":help":
        text = open(get_help_file(lang), 'r').read()
        text = text.replace('FULL_TRANSLATION', ' '.join(FULL_TRANSLATION))
        text = text.replace('PARTIAL_TRANSLATION', ' '.join(PARTIAL_TRANSLATION))
    elif name == ":bash.function":
        text = open(BASH_FUNCTION_FILE, 'r').read()
    elif name == ":translation":
        text = open(TRANSLATION_FILE, 'r').read()
        text = text\
                .replace('NUMBER_OF_LANGUAGES', str(len(SUPPORTED_LANGS)))\
                .replace('SUPPORTED_LANGUAGES', ' '.join(SUPPORTED_LANGS))
    return text.decode('utf-8')

def client_ip_address(request):
    """
    Return client ip address for `request`.
    Flask related
    """

    if request.headers.getlist("X-Forwarded-For"):
        ip_addr = request.headers.getlist("X-Forwarded-For")[0]
        if ip_addr.startswith('::ffff:'):
            ip_addr = ip_addr[7:]
    else:
        ip_addr = request.remote_addr

    return ip_addr

def get_answer_language(request):
    """
    Return preferred answer language based on
    domain name, query arguments and headers
    """

    def _parse_accept_language(accept_language):
        languages = accept_language.split(",")
        locale_q_pairs = []

        for language in languages:
            try:
                if language.split(";")[0] == language:
                    # no q => q = 1
                    locale_q_pairs.append((language.strip(), "1"))
                else:
                    locale = language.split(";")[0].strip()
                    weight = language.split(";")[1].split("=")[1]
                    locale_q_pairs.append((locale, weight))
            except IndexError:
                pass

        return locale_q_pairs

    def _find_supported_language(accepted_languages):
        for lang_tuple in accepted_languages:
            lang = lang_tuple[0]
            if '-' in lang:
                lang = lang.split('-', 1)[0]
            if lang in SUPPORTED_LANGS:
                return lang
        return None

    lang = None
    hostname = request.headers['Host']
    if hostname != 'wttr.in' and hostname.endswith('.wttr.in'):
        lang = hostname[:-8]

    if 'lang' in request.args:
        lang = request.args.get('lang')

    header_accept_language = request.headers.get('Accept-Language', '')
    if lang is None and header_accept_language:
        lang = _find_supported_language(
            _parse_accept_language(header_accept_language))

    return lang

def get_output_format(request):
    """
    Return preferred output format: ansi, text, html or png
    based on arguments and headers in `request`.
    Return new location (can be rewritten)
    """

    # FIXME
    user_agent = request.headers.get('User-Agent', '').lower()
    html_output = not any(agent in user_agent for agent in PLAIN_TEXT_AGENTS)
    return html_output

def cyclic_location_selection(locations, period):
    """
    Return one of `locations` (: separated list)
    basing on the current time and query interval `period`
    """

    locations = locations.split(':')
    max_len = max(len(x) for x in locations)
    locations = [x.rjust(max_len) for x in locations]

    try:
        period = int(period)
    except ValueError:
        period = 1

    index = int(time.time())/period % len(locations)
    return locations[index]

def wttr(location, request):
    """
    Main rendering function, it processes incoming weather queries.
    Depending on user agent it returns output in HTML or ANSI format.

    Incoming data:
        request.args
        request.headers
        request.remote_addr
        request.referrer
        request.query_string
    """

    if is_location_blocked(location):
        return ""

    ip_addr = client_ip_address(request)

    try:
        LIMITS.check_ip(ip_addr)
    except RuntimeError, exception:
        return str(exception)

    png_filename = None
    if location is not None and location.lower().endswith(".png"):
        png_filename = location
        location = location[:-4]

    lang = get_answer_language(request)
    query = parse_query.parse_query(request.args)
    html_output = get_output_format(request)
    user_agent = request.headers.get('User-Agent', '').lower()

    if location in PLAIN_TEXT_PAGES:
        help_ = show_text_file(location, lang)
        if html_output:
            return render_template('index.html', body=help_)
        return help_

    if location and ':' in location:
        location = cyclic_location_selection(location, query.get('period', 1))

    orig_location = location

    location, override_location_name, full_address, country, query_source_location = \
            location_processing(location, ip_addr)

    us_ip = query_source_location[1] == 'United States' and 'slack' not in user_agent
    query = parse_query.metric_or_imperial(query, lang, us_ip=us_ip)

    # logging query
    orig_location_utf8 = (orig_location or "").encode('utf-8')
    location_utf8 = location.encode('utf-8')
    use_imperial = query.get('use_imperial', False)
    log(" ".join(map(str,
                     [ip_addr, user_agent, orig_location_utf8, location_utf8, use_imperial, lang])))

    if country and location != NOT_FOUND_LOCATION:
        location = "%s,%s" % (location, country)

    # We are ready to return the answer
    try:
        if 'format' in query:
            return wttr_line(location, query)

        if png_filename:
            options = {
                'lang': None,
                'location': location}
            options.update(query)

            cached_png_file = wttrin_png.make_wttr_in_png(png_filename, options=options)
            response = make_response(send_file(cached_png_file,
                                               attachment_filename=png_filename,
                                               mimetype='image/png'))
            for key, value in {
                    'Cache-Control': 'no-cache, no-store, must-revalidate',
                    'Pragma': 'no-cache',
                    'Expires': '0',
                }.items():
                response.headers[key] = value

            # Trying to disable github caching
            return response

        if location == 'moon' or location.startswith('moon@'):
            output = get_moon(location, html=html_output, lang=lang)
        else:
            output = get_wetter(location, ip_addr,
                                html=html_output,
                                lang=lang,
                                query=query,
                                location_name=override_location_name,
                                full_address=full_address,
                                url=request.url,
                               )

        if html_output:
            output = add_buttons(output)
        else:
            if query.get('days', '3') != '0':
                #output += '\n' + get_message('NEW_FEATURE', lang).encode('utf-8')
                output += '\n' + get_message('FOLLOW_ME', lang).encode('utf-8') + '\n'
        return output

    except RuntimeError, exception:
        if 'Malformed response' in str(exception) \
                or 'API key has reached calls per day allowed limit' in str(exception):
            if html_output:
                return MALFORMED_RESPONSE_HTML_PAGE
            return get_message('CAPACITY_LIMIT_REACHED', lang).encode('utf-8')
        logging.error("Exception has occured", exc_info=1)
        return "ERROR"
<|endoftext|>