<commit_before>#!/bin/env python3
# eprl.py
# author: borysn | oxenfree
# license: MIT
#
# edit portage resume list
#
# usage: eprl.py [-h] [-l] [-r ITEMNUMS [ITEMNUMS ...]] [-a ITEMS [ITEMS ...]] [-b] [-v]
#
# optional arguments:
#   -h, --help            show this help message and exit
#   -l, --list            list portage resume items
#   -r ITEMNUMS [ITEMNUMS ...], --remove ITEMNUMS [ITEMNUMS ...]
#                         remove portage resume items
#   -a ITEMS [ITEMS ...], --add ITEMS [ITEMS ...]
#                         add resume item(s) to a resume list
#   -b, --backup          perform operations on backup list
#   -v, --version         show program's version number and exit
import sys
import util, vargs, dbstore, resolver
from colors import tcolor, bcolors
from util import status

# printResumeItems
# output resume item list to console
#
# @params items    dictionary containing 'resume' & 'resume_backup' matrices
def printResumeList(resumeList, target):
    # print collection name
    print('[{} list]'.format(tcolor.CTXT(tcolor.PURPLE, target)))
    # check list size
    if resumeList == None or len(resumeList) <= 0:
        print('\t{}: list is empty'.format(status.WARN))
    else:
        for i in range(len(resumeList)):
            print('\t{}: {}'.format(tcolor.CTXT(tcolor.BLUE, i), resumeList[i][2]))

# listPortageResumeItems
# list all ebuilds scheduled in resume & resume_backup
#
# @param db    mtimedb data store
def listPortageResumeItems(db):
        # print resume items
        printResumeList(db.getResumeList(), db.getTarget())
        # listing portage resume items was successful
        print('\n{}: fetch portage resume/resume_backup lists'.format(status.SUCCESS))

# removePortageResumeItem
# remove a portage resume item
#
# @param itemNum    valid portage resume item to be removed
def removePortageResumeItems(itemNums, db):
    # confirm delete
    # TODO resolve itemNums for proper input
    if util.userConfirmed(itemNums):
        # attempt to remove resume item
        db.removeItems(itemNums)
        print('{}: item "{}" removed from portage resume list'.format(status.SUCCESS, tcolor.CTXT(tcolor.PURPLE, itemNums)))

# addPortageResumeItems
# add item(s) to a portage resume list
#
# @param  items    list of possible item entries, just portage package names
# @param  db       portage mtimedb data store
def addPortageResumeItems(items, db):
    db.addItems(items)
    print('{}: item(s)\n{}\nadded to portage resume list'.format(status.SUCCESS, tcolor.CTXT(tcolor.PURPLE, items)))

# runScript
# run script as a function of args
#
# @param args       args should be validated before passed in
def runScript(args, db):
    # list all portage emerge items
    if args.list == True:
        listPortageResumeItems(db)
    # remove portage resume item(s)
    elif args.itemNums != None:
        removePortageResumeItems(args.itemNums, db)
    # add portage resume item(s)
    elif args.items != None:
        # resolve dependencies
        resolvedItems = resolver.resolveItems(args.items)
        # add to portage resume list
        addPortageResumeItems(resolvedItems, db)

# main
# root privilege check, parse & validate args, get mtimedb store, run script
def main():
    # check for correct privileges
    if util.userDoesNotHaveRootPrivileges():
        util.errorAndExit('eprl.py requires root privileges, try running with sudo')
    # get args
    args = vargs.parseArgs()
    # init db store for portage mtimedb
    db = dbstore.DBstore(args.backup)
    # validate args, exit if invalid
    if vargs.argsAreNotValid(args, db):
        util.errorAndExit('what to do, what to do...try {}'.format(tcolor.CTXT(tcolor.BLUE, '-h')))
    # execute script
    runScript(args, db)
    # exit succes
    sys.exit(0)

# exec main
if __name__ == '__main__':
    main()
<commit_msg>remove todo<commit_after>#!/bin/env python3
# eprl.py
# author: borysn | oxenfree
# license: MIT
#
# edit portage resume list
#
# usage: eprl.py [-h] [-l] [-r ITEMNUMS [ITEMNUMS ...]] [-a ITEMS [ITEMS ...]] [-b] [-v]
#
# optional arguments:
#   -h, --help            show this help message and exit
#   -l, --list            list portage resume items
#   -r ITEMNUMS [ITEMNUMS ...], --remove ITEMNUMS [ITEMNUMS ...]
#                         remove portage resume items
#   -a ITEMS [ITEMS ...], --add ITEMS [ITEMS ...]
#                         add resume item(s) to a resume list
#   -b, --backup          perform operations on backup list
#   -v, --version         show program's version number and exit
import sys
import util, vargs, dbstore, resolver
from colors import tcolor, bcolors
from util import status

# printResumeItems
# output resume item list to console
#
# @params items    dictionary containing 'resume' & 'resume_backup' matrices
def printResumeList(resumeList, target):
    # print collection name
    print('[{} list]'.format(tcolor.CTXT(tcolor.PURPLE, target)))
    # check list size
    if resumeList == None or len(resumeList) <= 0:
        print('\t{}: list is empty'.format(status.WARN))
    else:
        for i in range(len(resumeList)):
            print('\t{}: {}'.format(tcolor.CTXT(tcolor.BLUE, i), resumeList[i][2]))

# listPortageResumeItems
# list all ebuilds scheduled in resume & resume_backup
#
# @param db    mtimedb data store
def listPortageResumeItems(db):
        # print resume items
        printResumeList(db.getResumeList(), db.getTarget())
        # listing portage resume items was successful
        print('\n{}: fetch portage resume/resume_backup lists'.format(status.SUCCESS))

# removePortageResumeItem
# remove a portage resume item
#
# @param itemNum    valid portage resume item to be removed
def removePortageResumeItems(itemNums, db):
    # confirm delete
    if util.userConfirmed(itemNums):
        # attempt to remove resume item
        db.removeItems(itemNums)
        print('{}: item "{}" removed from portage resume list'.format(status.SUCCESS, tcolor.CTXT(tcolor.PURPLE, itemNums)))

# addPortageResumeItems
# add item(s) to a portage resume list
#
# @param  items    list of possible item entries, just portage package names
# @param  db       portage mtimedb data store
def addPortageResumeItems(items, db):
    db.addItems(items)
    print('{}: item(s)\n{}\nadded to portage resume list'.format(status.SUCCESS, tcolor.CTXT(tcolor.PURPLE, items)))

# runScript
# run script as a function of args
#
# @param args       args should be validated before passed in
def runScript(args, db):
    # list all portage emerge items
    if args.list == True:
        listPortageResumeItems(db)
    # remove portage resume item(s)
    elif args.itemNums != None:
        removePortageResumeItems(args.itemNums, db)
    # add portage resume item(s)
    elif args.items != None:
        # resolve dependencies
        resolvedItems = resolver.resolveItems(args.items)
        # add to portage resume list
        addPortageResumeItems(resolvedItems, db)

# main
# root privilege check, parse & validate args, get mtimedb store, run script
def main():
    # check for correct privileges
    if util.userDoesNotHaveRootPrivileges():
        util.errorAndExit('eprl.py requires root privileges, try running with sudo')
    # get args
    args = vargs.parseArgs()
    # init db store for portage mtimedb
    db = dbstore.DBstore(args.backup)
    # validate args, exit if invalid
    if vargs.argsAreNotValid(args, db):
        util.errorAndExit('what to do, what to do...try {}'.format(tcolor.CTXT(tcolor.BLUE, '-h')))
    # execute script
    runScript(args, db)
    # exit succes
    sys.exit(0)

# exec main
if __name__ == '__main__':
    main()
<|endoftext|>


<commit_before>"""
Data models for the licenses app.
"""

from django.db import models
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _

from apps.tools.utils import unique_slug
from apps.txtrender.fields import RenderTextField
from apps.txtrender.utils import render_html, strip_html
from apps.txtrender.signals import render_engine_changed

from .settings import LICENSE_LOGO_UPLOAD_DIR_NAME

class License(models.Model):
    """
    Content license data model.
    A license is made of:
    - a name (human readable),
    - a slug (unique and indexed in database),
    - an optional logo (only full size version),
    - a brief description (can be blank),
    - a full usage text (can be blank),
    - an optional source URL (for external license like CC).
    """

    name = models.CharField(_('Name'),
                            db_index=True,
                            max_length=255)

    # FIXME AutoSlugField
    slug = models.SlugField(_('Slug'),
                            max_length=255,
                            unique=True)

    logo = models.ImageField(_('Logo'),
                             upload_to=LICENSE_LOGO_UPLOAD_DIR_NAME,
                             default=None,
                             blank=True,
                             null=True)

    description = RenderTextField(_('Description'))

    description_html = models.TextField(_('Description (raw HTML)'))

    description_text = models.TextField(_('Description (raw text)'))

    usage = models.TextField(_('Usage'),
                             default='',
                             blank=True)

    source_url = models.URLField(_('Source URL'),
                                 default='',
                                 blank=True)

    last_modification_date = models.DateTimeField(_('Last modification date'),
                                                  auto_now=True)

    class Meta:
        verbose_name = _('License')
        verbose_name_plural = _('Licenses')
        ordering = ('name', )
        # FIXME Permissions for skcode

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        """
        Return the permalink to this license.
        """
        return reverse('licenses:license_detail', kwargs={'slug': self.slug})

    def save(self, *args, **kwargs):
        """
        Save the license.
        :param args: For super()
        :param kwargs: For super()
        """

        # Avoid duplicate slug
        # FIXME AutoSlugField
        self.slug = unique_slug(License, self, self.slug, 'slug', self.name)

        # Render the description text
        self.render_description()

        # Save the license
        super(License, self).save(*args, **kwargs)

    def render_description(self, save=False):
        """
        Render the description. Save the model only if ``save`` is True.
        """

        # Render HTML
        # FIXME Deploy skcode engine
        self.description_html = render_html(self.description, force_nofollow=False)
        self.description_text = 'TODO'

        # Save if required
        if save:
            # Avoid infinite loop by calling directly super.save
            super(License, self).save(update_fields=('description_html',))

def _redo_licenses_text_rendering(sender, **kwargs):
    """
    Redo text rendering of all licenses.
    :param sender: Not used.
    :param kwargs: Not used.
    """
    for license in License.objects.all():
        license.render_description(save=True)

render_engine_changed.connect(_redo_licenses_text_rendering)
<commit_msg>PySkCode deployment done<commit_after>"""
Data models for the licenses app.
"""

from django.db import models
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _

from apps.tools.utils import unique_slug
from apps.txtrender.fields import RenderTextField
from apps.txtrender.utils import render_document
from apps.txtrender.signals import render_engine_changed

from .settings import LICENSE_LOGO_UPLOAD_DIR_NAME

class License(models.Model):
    """
    Content license data model.
    A license is made of:
    - a name (human readable),
    - a slug (unique and indexed in database),
    - an optional logo (only full size version),
    - a brief description (can be blank),
    - a full usage text (can be blank),
    - an optional source URL (for external license like CC).
    """

    name = models.CharField(_('Name'),
                            db_index=True,
                            max_length=255)

    # FIXME AutoSlugField
    slug = models.SlugField(_('Slug'),
                            max_length=255,
                            unique=True)

    logo = models.ImageField(_('Logo'),
                             upload_to=LICENSE_LOGO_UPLOAD_DIR_NAME,
                             default=None,
                             blank=True,
                             null=True)

    description = RenderTextField(_('Description'))

    description_html = models.TextField(_('Description (raw HTML)'))

    description_text = models.TextField(_('Description (raw text)'))

    usage = models.TextField(_('Usage'),
                             default='',
                             blank=True)

    source_url = models.URLField(_('Source URL'),
                                 default='',
                                 blank=True)

    last_modification_date = models.DateTimeField(_('Last modification date'),
                                                  auto_now=True)

    class Meta:
        verbose_name = _('License')
        verbose_name_plural = _('Licenses')
        ordering = ('name', )

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        """
        Return the permalink to this license.
        """
        return reverse('licenses:license_detail', kwargs={'slug': self.slug})

    def save(self, *args, **kwargs):
        """
        Save the license.
        :param args: For super()
        :param kwargs: For super()
        """

        # Avoid duplicate slug
        # FIXME AutoSlugField
        self.slug = unique_slug(License, self, self.slug, 'slug', self.name)

        # Render the description text
        self.render_description()

        # Save the license
        super(License, self).save(*args, **kwargs)

    def render_description(self, save=False):
        """
        Render the description. Save the model only if ``save`` is True.
        """

        # Render HTML
        content_html, content_text, _ = render_document(self.description,
                                                        allow_titles=True,
                                                        allow_alerts_box=True,
                                                        allow_text_formating=True,
                                                        allow_text_extra=True,
                                                        allow_text_alignments=True,
                                                        allow_text_directions=True,
                                                        allow_text_modifiers=True,
                                                        allow_text_colors=True,
                                                        allow_figures=True,
                                                        allow_lists=True,
                                                        allow_definition_lists=True,
                                                        allow_tables=True,
                                                        allow_quotes=True,
                                                        allow_footnotes=True,
                                                        allow_acronyms=True,
                                                        allow_links=True,
                                                        allow_medias=True,
                                                        allow_cdm_extra=True,
                                                        force_nofollow=False,
                                                        render_text_version=True,
                                                        merge_footnotes_html=True,
                                                        merge_footnotes_text=True)
        self.description_html = content_html
        self.description_text = content_text

        # Save if required
        if save:
            # Avoid infinite loop by calling directly super.save
            super(License, self).save(update_fields=('description_html',))

def _redo_licenses_text_rendering(sender, **kwargs):
    """
    Redo text rendering of all licenses.
    :param sender: Not used.
    :param kwargs: Not used.
    """
    for license in License.objects.all():
        license.render_description(save=True)

render_engine_changed.connect(_redo_licenses_text_rendering)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# khan
# https://github.com/topfreegames/khan
# Licensed under the MIT license:
# http://www.opensource.org/licenses/mit-license
# Copyright © 2016 Top Free Games <backend@tfgco.com>

import urllib
import urllib2
import json

def main():
    url = "https://auth.docker.io/token?service=registry.docker.io&scope=repository:tfgco/khan:pull,push"
    response = urllib.urlopen(url)
    token = json.loads(response.read())['token']

    url = "https://registry-1.docker.io/v2/tfgco/khan/tags/list"
    req = urllib2.Request(url, None, {
        "Authorization": "Bearer %s" % token,
    })
    response = urllib2.urlopen(req)
    tags = json.loads(response.read())
    last_tag = get_last_tag(tags['tags'])
    print last_tag

def get_tag_value(tag):
    if tag == "latest":
        return 0

    while len(tag) < 4:
        tag.append('0')

    total_value = 0
    for index, tag_part in enumerate(tag):
        power = pow(100, len(tag) - index)
        total_value += int(tag_part) * power

    return total_value

def get_last_tag(tags):
    return '.'.join(
        max([
            (get_tag_value(tag), tag) for tag in
                [t.split('.') for t in tags]
            ], key=lambda i: i[0]
        )[1]
    )

if __name__ == "__main__":
    main()
<commit_msg>Ignore latest tag<commit_after># -*- coding: utf-8 -*-
# khan
# https://github.com/topfreegames/khan
# Licensed under the MIT license:
# http://www.opensource.org/licenses/mit-license
# Copyright © 2016 Top Free Games <backend@tfgco.com>

import urllib
import urllib2
import json

def main():
    url = "https://auth.docker.io/token?service=registry.docker.io&scope=repository:tfgco/khan:pull,push"
    response = urllib.urlopen(url)
    token = json.loads(response.read())['token']

    url = "https://registry-1.docker.io/v2/tfgco/khan/tags/list"
    req = urllib2.Request(url, None, {
        "Authorization": "Bearer %s" % token,
    })
    response = urllib2.urlopen(req)
    tags = json.loads(response.read())
    last_tag = get_last_tag(tags['tags'])
    print last_tag

def get_tag_value(tag):
    if "latest" in tag:
        return 0

    while len(tag) < 4:
        tag.append('0')

    total_value = 0
    for index, tag_part in enumerate(tag):
        power = pow(100, len(tag) - index)
        total_value += int(tag_part) * power

    return total_value

def get_last_tag(tags):
    return '.'.join(
        max([
            (get_tag_value(tag), tag) for tag in
                [t.split('.') for t in tags]
            ], key=lambda i: i[0]
        )[1]
    )

if __name__ == "__main__":
    main()
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
'''
.. module:: wizard
   :synopsis: A Web based wizard to setup the core
   :noindex:
   :copyright: Copyright 2016 by Tiago Antao
   :license: GNU Affero, see LICENSE for details

.. moduleauthor:: Tiago Antao <tra@popgen.net>

'''
from collections import defaultdict
import glob
import os
import shutil

import yaml

__version__ = '0.0.1+'

config = None

descriptive_names = {}
dependencies = defaultdict(set)
# container dependencies extracted from links and dependencies.yml
role_containers = defaultdict(list)
container_role = defaultdict(str)
container_order = []  # A possible container order
requirements = defaultdict(dict)
descriptive_requirements = {
    'ca': 'Certificate Authority',
    'ssl': 'SSL key and ceritificate'
}

_config_exts = ['.sample', '.link']

def load_config():
    '''Loads configuration from a previous execution.
    '''
    global config
    try:
        config = yaml.load(open('virtual-core.yml'))
    except FileNotFoundError:
        config = {}

def load_requirements():
    '''Loads container requirements.
    '''
    global requirements
    requirements = defaultdict(dict, yaml.load(open('containers.yml')))

def save_config():
    '''Saves configuration.
    '''
    w = open('virtual-core.yml', 'wt')
    w.write(yaml.dump(config, default_flow_style=False))
    w.close()

def change_config(section, **kwargs):
    if section not in config:
        config[section] = {}
    for k, v in kwargs.items():
        config[section][k] = v
    save_config()

def get_server_dependencies():
    '''Checks dependencies and gets some metadata.'''
    with open('dependencies.yml') as explicit_dependencies:
        deps = yaml.load(explicit_dependencies)
        for docker_name, server_dependencies in deps.items():
            dependencies[docker_name] = set(server_dependencies)
    main_roles = glob.glob('ansible/roles/**/tasks/main.yml')
    for main_role in main_roles:
        role = main_role.split('/')[2]
        with open(main_role) as f:
            doc = yaml.load(f)
            for entry in doc:
                if 'docker' in entry:
                    descriptive_name = entry['name']
                    name = entry['docker']['name']
                    role_containers[role].append(name)
                    container_role[name] = role
                    descriptive_names[name] = descriptive_name
                    if 'links' in entry['docker']:
                        for link in entry['docker']['links']:
                            docker_name, internal_name = tuple(link.split(':'))
                            dependencies[name].add(docker_name)

def compute_container_order(done=set(['ldap'])):
    if len(done) == 1:
        container_order = ['ldap']
    else:
        container_order = []
    for container, deps in dependencies.items():
        if container in done:
            continue
        done.add(container)
        pre_containers = compute_container_order(done)
        container_order.append(container)
        container_order.extend(pre_containers)
    return container_order

def get_all_dependencies(container):
    '''Returns all containers that are required by a certain container
    '''
    my_dependencies = []
    check_containers = [container]
    while check_containers is not []:
        check_dependencies = dependencies[check]
        check_containers.extend(check_dependencies)
        my_dependencies.extend(check_containers)
        del check_containers[container]
    return my_dependencies

def get_configuration_file_samples(container):
    samples = glob.glob('docker/%s/**/*sample' % container, recursive=True)
    return samples

def is_file_configured(container, file_name):
    final_name = file_name[:-7]
    if os.path.exists(final_name):
        return True
    return False

def all_files_configured(container):
    for file_name in get_configuration_file_samples(container):
        if not is_file_configured(container, file_name):
            return False
    return True

def is_ssl_configured(container):
    if os.path.exists('etc/%s/ssl.key.pem' % container) and \
            os.path.exists('etc/%s/ssl.cert.pem' % container):
        return True
    return False

def is_requirement_fullfiled(container, req):
    if req == 'ca':
        return True
    elif req == 'ssl':
        return is_ssl_configured(container)
    return False

def all_requirements_done(container):
    for req in requirements[container]:
        if not is_requirement_fullfiled(container, req):
            return False
    return True

def is_configuration_complete(container):
    return all_files_configured(container) and all_requirements_done(container)

def all_containers_configured():
    for container in config['General']['containers']:
        if not is_configuration_complete(container):
            return False
    return True

def _copy(orig, container, fname, check):
    copy = 'docker/%s/copy/%s' % (container, fname[1:])
    named = 'docker/%s/named/%s' % (container, fname[1:])
    if check:
        return os.path.exists(copy) or os.path.exists(named)
    try:
        shutil.copy(orig, copy)
    except:
        shutil.copy(orig, named)

def _copy_ca_artefact(container, artefact, fname, check=False):
    if artefact == 'certificate':
        return _copy('etc/ca/cacert.pem', container, fname, check)
    raise Exception('Unknown artefact %s' % artefact)

def _copy_ssl_artefact(container, artefact, fname, check=False):
    if artefact == 'certificate':
        return _copy('etc/%s/ssl.cert.pem' % container,
                     container, fname, check)
    elif artefact == 'key':
        return _copy('etc/%s/ssl.key.pem' % container,
                     container, fname, check)
    raise Exception('Unknown artefact %s' % artefact)

def generate_configuration():
    for container, services in requirements.items():
        shutil.copy('etc/ssh/authorized_keys', 'docker/%s' % container)
        for service, artefacts in services.items():
            for artefact, files in artefacts.items():
                for fname in files:
                    if service == 'ssl':
                        _copy_ssl_artefact(container, str(artefact), fname)
                    elif service == 'ca':
                        _copy_ca_artefact(container, str(artefact), fname)

def all_configurations_copied():
    for container, services in requirements.items():
        print(container, services)
        if not os.path.exists('docker/%s' % container):
            return False
        for service, artefacts in services.items():
            for artefact, files in artefacts.items():
                for fname in files:
                    if service == 'ssl':
                        ret = _copy_ssl_artefact(
                            container, str(artefact), fname, True)
                    elif service == 'ca':
                        ret = _copy_ca_artefact(container,
                                                str(artefact), fname, True)
                    if not ret:
                        return False
    return True

def _get_link_path(link_redir):
    '''Get a link to another place for a config file.

    Currently only configuration for other containers is supported.'''
    info = yaml.load(open(link_redir))['container']
    my_fname = 'docker/%s/copy/%s' % (info['name'], info['file'])
    return my_fname

def check_copies(checkup):

    def check_cases(cases):
        for case in cases:
            machine = case.split('/')[1]
            root = case[:-7]
            checkup[machine].append((os.path.isfile(root), dest, 'copy'))
    samples = glob.glob('docker/**/*sample', recursive=True)
    check_cases(samples)
    links = glob.glob('docker/**/*link', recursive=True)
    check_cases(links)
    return checkup

def deploy(my_dir, check_instead=False):
    samples = glob.glob('ansible/roles/**/vars/main.yml')
    print(list(requirements.keys()), samples, os.getcwd())
    checkup = defaultdict(list)
    links = []
    for sample in samples:
        host = sample.split('/')[2]
        if host not in requirements:
            continue
        conf = yaml.load(open(sample))
        print(9999, sample, conf)
        for k, container_dir in conf.items():
            if not k.endswith('_dir'):
                continue
            machine = k[:-4]
            print(my_dir, machine)
            if not check_instead:
                try:
                    os.mkdir(my_dir + '/' + machine)
                except FileExistsError:
                    pass  # OK
            for sample_dir, dirs, fnames in os.walk(
                    'docker/%s/named' % machine):
                root = '/'.join([my_dir, machine] + sample_dir.split('/')[3:])
                if not check_instead:
                    for in_dir in dirs:
                        try:
                            print(root, in_dir)
                            os.mkdir(root + '/' + in_dir)
                        except FileExistsError:
                            pass  # OK
                for fname in fnames:
                    if fname.endswith('.sample') or \
                       fname.endswith('.sample.doc') or fname == '.gitignore':
                        continue
                    if fname.endswith('.link'):
                        links.append((
                            _get_link_path(sample_dir + '/' + fname),
                            root + '/' + fname[:-5]))
                        continue
                    print(sample_dir + '/' + fname, root)
                    dest = root + '/' + fname
                    if check_instead:
                        checkup[machine].append((os.path.isfile(dest),
                                                 dest, 'file'))
                    else:
                        shutil.copyfile(sample_dir + '/' + fname,
                                        root + '/' + fname)
    for source, dest in links:
        if check_instead:
            checkup[machine].append((os.path.isfile(dest), dest, 'link'))
        else:
            shutil.copyfile(source, dest)
    if check_instead:
        return check_copies(checkup)

def deploy_on_volumes():
    my_dir = config['General']['nameddirectoriesroot']
    deploy(my_dir)

def check_deployment():
    my_dir = config['General']['nameddirectoriesroot']
    return deploy(my_dir, check_instead=True)

def get_available_options():
    options = [('Basic options', '/')]
    if 'General' in config:
        options.append(('Choose containers', '/choose'))
        if 'containers' in config['General']:
            options.append(('Configure Containers', '/configure'))
            if all_containers_configured():
                options.append(('Generate configuration files', '/generate'))
                if all_configurations_copied():
                    options.append(('Deploy on volumes', '/deploy'))
                    options.append(('Check deployment', '/check_deployment'))
    return options

def make_instance_directory(file_name):
    instance_directory = file_name[:file_name.rfind('/')]
    try:
        os.makedirs(instance_directory)
    except OSError:
        pass  # OK, already exists

def link_existing_configuration(existing_conf=None):
    if existing_conf is None:
        existing_confs = glob.glob('_instance/docker/**', recursive=True)
    else:
        existing_confs = [existing_conf]
    for existing_conf in existing_confs:
        root_name = existing_conf[10:]
        is_config = False
        for ext in _config_exts:
            if os.path.exists(root_name + ext):
                is_config = True
                break
        if not is_config:
            continue
        try:
            os.remove(root_name)
        except OSError:
            pass  # This is OK, file does not exist yet
        os.link(existing_conf, root_name)
        # Docker does not allow symlinks

def link_ansible():
    try:
        os.mkdir('_instance/ansible')
    except OSError:
        pass  # Fine, already exists
    if not os.path.exists('_instance/ansible/main.yml'):
        shutil.copyfile('ansible/main.yml.example', '_instance/ansible/main.yml')
    if not os.path.islink('_instance/ansible/roles'):
        os.symlink('../../ansible/roles', '_instance/ansible/roles')

def prepare_instance():
    try:
        os.mkdir('_instance')
    except OSError:
        pass  # Fine, already exists
    link_ansible()
    link_existing_configuration()

load_config()
load_requirements()
get_server_dependencies()
container_order = compute_container_order()
prepare_instance()
<commit_msg>skip undesired containers<commit_after># -*- coding: utf-8 -*-
'''
.. module:: wizard
   :synopsis: A Web based wizard to setup the core
   :noindex:
   :copyright: Copyright 2016 by Tiago Antao
   :license: GNU Affero, see LICENSE for details

.. moduleauthor:: Tiago Antao <tra@popgen.net>

'''
from collections import defaultdict
import glob
import os
import shutil

import yaml

__version__ = '0.0.1+'

config = None

descriptive_names = {}
dependencies = defaultdict(set)
# container dependencies extracted from links and dependencies.yml
role_containers = defaultdict(list)
container_role = defaultdict(str)
container_order = []  # A possible container order
requirements = defaultdict(dict)
descriptive_requirements = {
    'ca': 'Certificate Authority',
    'ssl': 'SSL key and certificate'
}

_config_exts = ['.sample', '.link']

def load_config():
    '''Loads configuration from a previous execution.
    '''
    global config
    try:
        config = yaml.load(open('virtual-core.yml'))
    except FileNotFoundError:
        config = {}

def load_requirements():
    '''Loads container requirements.
    '''
    global requirements
    requirements = defaultdict(dict, yaml.load(open('containers.yml')))

def save_config():
    '''Saves configuration.
    '''
    w = open('virtual-core.yml', 'wt')
    w.write(yaml.dump(config, default_flow_style=False))
    w.close()

def change_config(section, **kwargs):
    if section not in config:
        config[section] = {}
    for k, v in kwargs.items():
        config[section][k] = v
    save_config()

def get_server_dependencies():
    '''Checks dependencies and gets some metadata.'''
    with open('dependencies.yml') as explicit_dependencies:
        deps = yaml.load(explicit_dependencies)
        for docker_name, server_dependencies in deps.items():
            dependencies[docker_name] = set(server_dependencies)
    main_roles = glob.glob('ansible/roles/**/tasks/main.yml')
    for main_role in main_roles:
        role = main_role.split('/')[2]
        with open(main_role) as f:
            doc = yaml.load(f)
            for entry in doc:
                if 'docker' in entry:
                    descriptive_name = entry['name']
                    name = entry['docker']['name']
                    role_containers[role].append(name)
                    container_role[name] = role
                    descriptive_names[name] = descriptive_name
                    if 'links' in entry['docker']:
                        for link in entry['docker']['links']:
                            docker_name, internal_name = tuple(link.split(':'))
                            dependencies[name].add(docker_name)

def compute_container_order(done=set(['ldap'])):
    if len(done) == 1:
        container_order = ['ldap']
    else:
        container_order = []
    for container, deps in dependencies.items():
        if container in done:
            continue
        done.add(container)
        pre_containers = compute_container_order(done)
        container_order.append(container)
        container_order.extend(pre_containers)
    return container_order

def get_all_dependencies(container):
    '''Returns all containers that are required by a certain container
    '''
    my_dependencies = []
    check_containers = [container]
    while check_containers is not []:
        check_dependencies = dependencies[check]
        check_containers.extend(check_dependencies)
        my_dependencies.extend(check_containers)
        del check_containers[container]
    return my_dependencies

def get_configuration_file_samples(container):
    samples = glob.glob('docker/%s/**/*sample' % container, recursive=True)
    return samples

def is_file_configured(container, file_name):
    final_name = file_name[:-7]
    if os.path.exists(final_name):
        return True
    return False

def all_files_configured(container):
    for file_name in get_configuration_file_samples(container):
        if not is_file_configured(container, file_name):
            return False
    return True

def is_ssl_configured(container):
    if os.path.exists('etc/%s/ssl.key.pem' % container) and \
            os.path.exists('etc/%s/ssl.cert.pem' % container):
        return True
    return False

def is_requirement_fullfiled(container, req):
    if req == 'ca':
        return True
    elif req == 'ssl':
        return is_ssl_configured(container)
    return False

def all_requirements_done(container):
    for req in requirements[container]:
        if not is_requirement_fullfiled(container, req):
            return False
    return True

def is_configuration_complete(container):
    return all_files_configured(container) and all_requirements_done(container)

def all_containers_configured():
    for container in config['General']['containers']:
        if not is_configuration_complete(container):
            return False
    return True

def _copy(orig, container, fname, check):
    copy = 'docker/%s/copy/%s' % (container, fname[1:])
    named = 'docker/%s/named/%s' % (container, fname[1:])
    if check:
        return os.path.exists(copy) or os.path.exists(named)
    try:
        shutil.copy(orig, copy)
    except:
        shutil.copy(orig, named)

def _copy_ca_artefact(container, artefact, fname, check=False):
    if artefact == 'certificate':
        return _copy('etc/ca/cacert.pem', container, fname, check)
    raise Exception('Unknown artefact %s' % artefact)

def _copy_ssl_artefact(container, artefact, fname, check=False):
    if artefact == 'certificate':
        return _copy('etc/%s/ssl.cert.pem' % container,
                     container, fname, check)
    elif artefact == 'key':
        return _copy('etc/%s/ssl.key.pem' % container,
                     container, fname, check)
    raise Exception('Unknown artefact %s' % artefact)

def generate_configuration():
    my_containers = list(config['General']['containers'])
    for container, services in requirements.items():
        if container not in my_containers:
            continue
        shutil.copy('etc/ssh/authorized_keys', 'docker/%s' % container)
        for service, artefacts in services.items():
            for artefact, files in artefacts.items():
                for fname in files:
                    if service == 'ssl':
                        _copy_ssl_artefact(container, str(artefact), fname)
                    elif service == 'ca':
                        _copy_ca_artefact(container, str(artefact), fname)

def all_configurations_copied():
    for container, services in requirements.items():
        print(container, services)
        if not os.path.exists('docker/%s' % container):
            return False
        for service, artefacts in services.items():
            for artefact, files in artefacts.items():
                for fname in files:
                    if service == 'ssl':
                        ret = _copy_ssl_artefact(
                            container, str(artefact), fname, True)
                    elif service == 'ca':
                        ret = _copy_ca_artefact(container,
                                                str(artefact), fname, True)
                    if not ret:
                        return False
    return True

def _get_link_path(link_redir):
    '''Get a link to another place for a config file.

    Currently only configuration for other containers is supported.'''
    info = yaml.load(open(link_redir))['container']
    my_fname = 'docker/%s/copy/%s' % (info['name'], info['file'])
    return my_fname

def check_copies(checkup):

    def check_cases(cases):
        for case in cases:
            machine = case.split('/')[1]
            root = case[:-7]
            checkup[machine].append((os.path.isfile(root), dest, 'copy'))
    samples = glob.glob('docker/**/*sample', recursive=True)
    check_cases(samples)
    links = glob.glob('docker/**/*link', recursive=True)
    check_cases(links)
    return checkup

def deploy(my_dir, check_instead=False):
    samples = glob.glob('ansible/roles/**/vars/main.yml')
    print(list(requirements.keys()), samples, os.getcwd())
    checkup = defaultdict(list)
    links = []
    for sample in samples:
        host = sample.split('/')[2]
        if host not in requirements:
            continue
        conf = yaml.load(open(sample))
        print(9999, sample, conf)
        for k, container_dir in conf.items():
            if not k.endswith('_dir'):
                continue
            machine = k[:-4]
            print(my_dir, machine)
            if not check_instead:
                try:
                    os.mkdir(my_dir + '/' + machine)
                except FileExistsError:
                    pass  # OK
            for sample_dir, dirs, fnames in os.walk(
                    'docker/%s/named' % machine):
                root = '/'.join([my_dir, machine] + sample_dir.split('/')[3:])
                if not check_instead:
                    for in_dir in dirs:
                        try:
                            print(root, in_dir)
                            os.mkdir(root + '/' + in_dir)
                        except FileExistsError:
                            pass  # OK
                for fname in fnames:
                    if fname.endswith('.sample') or \
                       fname.endswith('.sample.doc') or fname == '.gitignore':
                        continue
                    if fname.endswith('.link'):
                        links.append((
                            _get_link_path(sample_dir + '/' + fname),
                            root + '/' + fname[:-5]))
                        continue
                    print(sample_dir + '/' + fname, root)
                    dest = root + '/' + fname
                    if check_instead:
                        checkup[machine].append((os.path.isfile(dest),
                                                 dest, 'file'))
                    else:
                        shutil.copyfile(sample_dir + '/' + fname,
                                        root + '/' + fname)
    for source, dest in links:
        if check_instead:
            checkup[machine].append((os.path.isfile(dest), dest, 'link'))
        else:
            shutil.copyfile(source, dest)
    if check_instead:
        return check_copies(checkup)

def deploy_on_volumes():
    my_dir = config['General']['nameddirectoriesroot']
    deploy(my_dir)

def check_deployment():
    my_dir = config['General']['nameddirectoriesroot']
    return deploy(my_dir, check_instead=True)

def get_available_options():
    options = [('Basic options', '/')]
    if 'General' in config:
        options.append(('Choose containers', '/choose'))
        if 'containers' in config['General']:
            options.append(('Configure Containers', '/configure'))
            if all_containers_configured():
                options.append(('Generate configuration files', '/generate'))
                if all_configurations_copied():
                    options.append(('Deploy on volumes', '/deploy'))
                    options.append(('Check deployment', '/check_deployment'))
    return options

def make_instance_directory(file_name):
    instance_directory = file_name[:file_name.rfind('/')]
    try:
        os.makedirs(instance_directory)
    except OSError:
        pass  # OK, already exists

def link_existing_configuration(existing_conf=None):
    if existing_conf is None:
        existing_confs = glob.glob('_instance/docker/**', recursive=True)
    else:
        existing_confs = [existing_conf]
    for existing_conf in existing_confs:
        root_name = existing_conf[10:]
        is_config = False
        for ext in _config_exts:
            if os.path.exists(root_name + ext):
                is_config = True
                break
        if not is_config:
            continue
        try:
            os.remove(root_name)
        except OSError:
            pass  # This is OK, file does not exist yet
        os.link(existing_conf, root_name)
        # Docker does not allow symlinks

def link_ansible():
    try:
        os.mkdir('_instance/ansible')
    except OSError:
        pass  # Fine, already exists
    if not os.path.exists('_instance/ansible/main.yml'):
        shutil.copyfile('ansible/main.yml.example', '_instance/ansible/main.yml')
    if not os.path.islink('_instance/ansible/roles'):
        os.symlink('../../ansible/roles', '_instance/ansible/roles')

def prepare_instance():
    try:
        os.mkdir('_instance')
    except OSError:
        pass  # Fine, already exists
    link_ansible()
    link_existing_configuration()

load_config()
load_requirements()
get_server_dependencies()
container_order = compute_container_order()
prepare_instance()
<|endoftext|>


<commit_before>import webApp
import xmlDatabase
import actions
import sseListener
import callUrl
import os
import argparse
import besthostname
import time
import json
import web
import subprocess
import imp
from _version import VERSION

import sys
reload(sys)
sys.setdefaultencoding('utf8')

class IgorServer:
    def __init__(self, datadir, port=9333, advertise=False):
        #
        # Create the database, and tell the web application about it
        #
        self.port = port
        self.app = webApp.WEBAPP
        self.datadir = datadir
        self.database = xmlDatabase.DBImpl(os.path.join(self.datadir, 'database.xml'))
        webApp.DATABASE = self.database # Have to set in a module-global variable, to be fixed some time...
        webApp.SCRIPTDIR = os.path.join(datadir, 'scripts')
        webApp.PLUGINDIR = os.path.join(datadir, 'plugins')
        webApp.STATICDIR = os.path.join(datadir, 'static')
        webApp.COMMANDS = self

        #
        # Create and start the asynchronous URL accessor
        #
        self.urlCaller = callUrl.URLCaller(self.app)
        self.urlCaller.start()

        #
        # Fill self data
        #
        self.fillSelfData()
        #
        # Startup other components
        #
        self.actionHandler = None
        self.updateActions()
        self.eventSources = None
        self.updateEventSources()
        self.triggerHandler = None
        self.updateTriggers()
        #
        # Disable debug
        #
        web.config.debug = False
        #
        # Send start action to start any plugins
        #
        self.urlCaller.callURL(dict(method='GET', url='/action/start'))
        if advertise:
            self.advertise(port)

    def advertise(self, port):
        if sys.platform == 'darwin':
            cmd = ['dns-sd', '-R', 'igor', '_http._tcp', 'local', str(port)]
        elif sys.platform == 'linux2':
            cmd = ['avahi-publish', '-s', 'igor', '_http._tcp', str(port)]
        else:
            print >> sys.stderr, "Cannot do mdns-advertise on platform", sys.platform
            return
        try:
            self.advertiser = subprocess.Popen(cmd)
        except OSError:
            print >> sys.stderr, "advertisement command failed: %s" % (' '.join(cmd))

    def fillSelfData(self):
        """Put our details in the database"""
        hostName = besthostname.besthostname()
        url = 'http://%s:%d/data' % (hostName, self.port)
        data = dict(host=hostName, url=url, port=self.port, startTime=int(time.time()), version=VERSION)
        tocall = dict(method='PUT', url='/data/services/igor', mimetype='application/json', data=json.dumps(data))
        self.urlCaller.callURL(tocall)

    def run(self):
        self.app.run(port=self.port)

    def dump(self):
        rv = ''
        if self.urlCaller: rv += self.urlCaller.dump() + '\n'
        if self.actionHandler: rv += self.actionHandler.dump() + '\n'
        if self.eventSources: rv += self.eventSources.dump() + '\n'
        return rv

    def log(self):
        logfn = os.path.join(self.datadir, 'igor.log')
        if os.path.exists(logfn):
            return open(logfn).read()
        raise Web.HTTPError('404 Log file not available')

    def updateActions(self):
        """Create any (periodic) event handlers defined in the database"""
        startupActions = self.database.getElements('actions')
        if len(startupActions):
            if len(startupActions) > 1:
                raise web.HTTPError('401 only one <actions> element allowed')
            if not self.actionHandler:
                self.actionHandler = actions.ActionCollection(self.database, self.urlCaller.callURL)
            self.actionHandler.updateActions(startupActions[0])
        elif self.actionHandler:
            self.actionHandler.updateActions([])
        return 'OK'

    def updateEventSources(self):
        """Create any SSE event sources that are defined in the database"""
        eventSources = self.database.getElements('eventSources')
        if len(eventSources):
            if len(eventSources) > 1:
                raise web.HTTPError('401 only one <eventSources> element allowed')
            if not self.eventSources:
                self.eventSources = sseListener.EventSourceCollection(self.database, self.urlCaller.callURL)
            self.eventSources.updateEventSources(eventSources[0])
        elif self.eventSources:
            self.eventSources.updateEventSources([])
        return 'OK'

    def updateTriggers(self):
        pass

    def runAction(self, actionname):
        if not self.actionHandler:
            raise web.notfound()
        nodes = self.database.getElements('actions/action[name="%s"]'%actionname)
        if not nodes:
            raise web.notfound()
        for node in nodes:
            self.actionHandler.triggerAction(node)
        return 'OK'

    def runTrigger(self, triggername):
        raise web.HTTPError("502 triggers not yet implemented")
        if not self.triggerHandler:
            raise web.notfound()
        triggerNodes = self.database.getElements('triggers/%s' % triggername)
        if not triggerNodes:
            raise web.notfound()
        if len(triggerNodes) > 1:
            raise web.HTTPError("502 multiple triggers %s in database" % triggername)
        triggerNode = triggerNodes[0]
        self.triggerHandler.triggerTrigger(triggerNode)

    def save(self):
        self.database.saveFile()
        return 'OK'

    def started(self):
        return "IgorServer started"

    def stop(self):
        if self.actionHandler:
            self.actionHandler.stop()
            self.actionHandler = None
        if self.eventSources:
            self.eventSources.stop()
            self.eventSources = None
        if self.triggerHandler:
            self.triggerHandler.stop()
            self.triggerHandler = None
        if self.urlCaller:
            self.urlCaller.stop()
            self.urlCaller = None
        self.save()
        sys.exit(0)

    def restart(self):
        self.save()
        os.closerange(3, MAXFD)
        os.execl(sys.executable, sys.executable, *sys.argv)

    def command(self):
        rv = ''
        if 'IGORSERVER_DIR' in os.environ:
            rv = rv + 'export IGORSERVER_DIR=' + repr(os.environ['IGORSERVER_DIR']) + '\n'
        if 'IGORSERVER_PORT' in os.environ:
            rv = rv + 'export IGORSERVER_PORT=%d\n' % int(os.environ['IGORSERVER_PORT'])
        rv = rv + 'exec %s' % repr(sys.executable)
        for a in sys.argv:
            rv += ' ' + repr(a)
        rv += '\n'
        return rv

    def help(self):
        rv = 'Internal igor commands:\n'
        rv += 'help - this help\n'
        rv += 'version - return version number\n'
        rv += 'save - Make sure database is saved to disk\n'
        rv += 'restart - Save and restart this Igor (may appear to fail even when executed correctly)\n'
        rv += 'stop - Save and stop this Igor (may appear to fail even when executed correctly)\n'
        rv += 'command - Show command line that started this Igor instance\n'
        rv += 'dump - Show internal run queue of this Igor instance\n'
        rv += 'log - Show httpd-style log file of this Igor instance\n'
        return rv

    def version(self):
        return VERSION + '\n'

def main():
    DEFAULTDIR=os.path.join(os.path.expanduser('~'), '.igor')
    if 'IGORSERVER_DIR' in os.environ:
        DEFAULTDIR = os.environ['IGORSERVER_DIR']
    DEFAULTPORT=9333
    if 'IGORSERVER_PORT' in os.environ:
        DEFAULTDIR = int(os.environ['IGORSERVER_PORT'])

    parser = argparse.ArgumentParser(description="Run the Igor home automation server")
    parser.add_argument("-d", "--database", metavar="DIR", help="Database and scripts are stored in DIR (default: %s, environment IGORSERVER_DIR)" % DEFAULTDIR, default=DEFAULTDIR)
    parser.add_argument("-p", "--port", metavar="PORT", type=int, help="Port to serve on (default: 9333, environment IGORSERVER_PORT)", default=DEFAULTPORT)
    parser.add_argument("--debug", action="store_true", help="Enable debug output")
    parser.add_argument("--advertise", action="store_true", help="Advertise service through bonjour/zeroconf")
    parser.add_argument("--version", action="store_true", help="Print version and exit")
    args = parser.parse_args()

    if args.version:
        print VERSION
        sys.exit(0)
    if args.debug:
        callUrl.DEBUG = True
        sseListener.DEBUG = True
        actions.DEBUG = True
        xmlDatabase.DEBUG = True
        webApp.DEBUG = True
    datadir = args.database
    try:
        igorServer = IgorServer(datadir, args.port, args.advertise)
    except IOError, arg:
        print >>sys.stderr, '%s: Cannot open database: %s' % (sys.argv[0], arg)
        print >>sys.stderr, '%s: Use --help option to see command line arguments' % sys.argv[0]
        sys.exit(1)
    igorServer.run()

#
# We need to hack the import lock. In case we get here via the easy_install igorServer script
# we are inside an __import__(), and we hold the lock. This means other threads cannot import
# and we hang once a web request comes in. We "work around" this by releasing the lock.
#
hasImportLock = imp.lock_held()
if hasImportLock:
    imp.release_lock()
main()
if hasImportLock:
    imp.acquire_lock()

<commit_msg>Implemented a --profile option to enable profiling Igor<commit_after>import webApp
import xmlDatabase
import actions
import sseListener
import callUrl
import os
import argparse
import besthostname
import time
import json
import web
import subprocess
import imp
import threading
import cProfile
import pstats
from _version import VERSION

import sys
reload(sys)
sys.setdefaultencoding('utf8')

#
# Helper for profileing multiple threads
#
PROFILER_STATS = None
def enable_thread_profiling():
    '''Monkey-patch Thread.run to enable global profiling.

    Each thread creates a local profiler; statistics are pooled
    to the global stats object on run completion.'''
    global PROFILER_STATS
    import pstats
    PROFILER_STATS = None
    thread_run = threading.Thread.run

    def profile_run(self):
        print 'xxxjack profile_run'
        self._prof = cProfile.Profile()
        self._prof.enable()
        thread_run(self)
        self._prof.disable()

        if PROFILER_STATS is None:
            PROFILER_STATS = pstats.Stats(self._prof)
        else:
            PROFILER_STATS.add(self._prof)

    threading.Thread.run = profile_run
    print 'xxxjack inserted profiler'

class IgorServer:
    def __init__(self, datadir, port=9333, advertise=False, profile=False):
        #
        # Create the database, and tell the web application about it
        #
        self.profile = None
        if profile:
            enable_thread_profiling()
            self.profile = cProfile.Profile()
            self.profile.enable()
        self.port = port
        self.app = webApp.WEBAPP
        self.datadir = datadir
        self.database = xmlDatabase.DBImpl(os.path.join(self.datadir, 'database.xml'))
        webApp.DATABASE = self.database # Have to set in a module-global variable, to be fixed some time...
        webApp.SCRIPTDIR = os.path.join(datadir, 'scripts')
        webApp.PLUGINDIR = os.path.join(datadir, 'plugins')
        webApp.STATICDIR = os.path.join(datadir, 'static')
        webApp.COMMANDS = self

        #
        # Create and start the asynchronous URL accessor
        #
        self.urlCaller = callUrl.URLCaller(self.app)
        self.urlCaller.start()

        #
        # Fill self data
        #
        self.fillSelfData()
        #
        # Startup other components
        #
        self.actionHandler = None
        self.updateActions()
        self.eventSources = None
        self.updateEventSources()
        self.triggerHandler = None
        self.updateTriggers()
        #
        # Disable debug
        #
        web.config.debug = False
        #
        # Send start action to start any plugins
        #
        self.urlCaller.callURL(dict(method='GET', url='/action/start'))
        if advertise:
            self.advertise(port)

    def advertise(self, port):
        if sys.platform == 'darwin':
            cmd = ['dns-sd', '-R', 'igor', '_http._tcp', 'local', str(port)]
        elif sys.platform == 'linux2':
            cmd = ['avahi-publish', '-s', 'igor', '_http._tcp', str(port)]
        else:
            print >> sys.stderr, "Cannot do mdns-advertise on platform", sys.platform
            return
        try:
            self.advertiser = subprocess.Popen(cmd)
        except OSError:
            print >> sys.stderr, "advertisement command failed: %s" % (' '.join(cmd))

    def fillSelfData(self):
        """Put our details in the database"""
        hostName = besthostname.besthostname()
        url = 'http://%s:%d/data' % (hostName, self.port)
        data = dict(host=hostName, url=url, port=self.port, startTime=int(time.time()), version=VERSION)
        tocall = dict(method='PUT', url='/data/services/igor', mimetype='application/json', data=json.dumps(data))
        self.urlCaller.callURL(tocall)

    def run(self):
        self.app.run(port=self.port)

    def dump(self):
        rv = ''
        if self.urlCaller: rv += self.urlCaller.dump() + '\n'
        if self.actionHandler: rv += self.actionHandler.dump() + '\n'
        if self.eventSources: rv += self.eventSources.dump() + '\n'
        return rv

    def log(self):
        logfn = os.path.join(self.datadir, 'igor.log')
        if os.path.exists(logfn):
            return open(logfn).read()
        raise Web.HTTPError('404 Log file not available')

    def updateActions(self):
        """Create any (periodic) event handlers defined in the database"""
        startupActions = self.database.getElements('actions')
        if len(startupActions):
            if len(startupActions) > 1:
                raise web.HTTPError('401 only one <actions> element allowed')
            if not self.actionHandler:
                self.actionHandler = actions.ActionCollection(self.database, self.urlCaller.callURL)
            self.actionHandler.updateActions(startupActions[0])
        elif self.actionHandler:
            self.actionHandler.updateActions([])
        return 'OK'

    def updateEventSources(self):
        """Create any SSE event sources that are defined in the database"""
        eventSources = self.database.getElements('eventSources')
        if len(eventSources):
            if len(eventSources) > 1:
                raise web.HTTPError('401 only one <eventSources> element allowed')
            if not self.eventSources:
                self.eventSources = sseListener.EventSourceCollection(self.database, self.urlCaller.callURL)
            self.eventSources.updateEventSources(eventSources[0])
        elif self.eventSources:
            self.eventSources.updateEventSources([])
        return 'OK'

    def updateTriggers(self):
        pass

    def runAction(self, actionname):
        if not self.actionHandler:
            raise web.notfound()
        nodes = self.database.getElements('actions/action[name="%s"]'%actionname)
        if not nodes:
            raise web.notfound()
        for node in nodes:
            self.actionHandler.triggerAction(node)
        return 'OK'

    def runTrigger(self, triggername):
        raise web.HTTPError("502 triggers not yet implemented")
        if not self.triggerHandler:
            raise web.notfound()
        triggerNodes = self.database.getElements('triggers/%s' % triggername)
        if not triggerNodes:
            raise web.notfound()
        if len(triggerNodes) > 1:
            raise web.HTTPError("502 multiple triggers %s in database" % triggername)
        triggerNode = triggerNodes[0]
        self.triggerHandler.triggerTrigger(triggerNode)

    def save(self):
        self.database.saveFile()
        return 'OK'

    def started(self):
        return "IgorServer started"

    def stop(self):
        global PROFILER_STATS
        if self.actionHandler:
            self.actionHandler.stop()
            self.actionHandler = None
        if self.eventSources:
            self.eventSources.stop()
            self.eventSources = None
        if self.triggerHandler:
            self.triggerHandler.stop()
            self.triggerHandler = None
        if self.urlCaller:
            self.urlCaller.stop()
            self.urlCaller = None
        self.save()
        if self.profile:
            self.profile.disable()
            if PROFILER_STATS is None:
                PROFILER_STATS = pstats.Stats(self.profile)
            else:
                PROFILER_STATS.add(self.profile)
            PROFILER_STATS.dump_stats("igor.profile")
        sys.exit(0)

    def restart(self):
        self.save()
        os.closerange(3, MAXFD)
        os.execl(sys.executable, sys.executable, *sys.argv)

    def command(self):
        rv = ''
        if 'IGORSERVER_DIR' in os.environ:
            rv = rv + 'export IGORSERVER_DIR=' + repr(os.environ['IGORSERVER_DIR']) + '\n'
        if 'IGORSERVER_PORT' in os.environ:
            rv = rv + 'export IGORSERVER_PORT=%d\n' % int(os.environ['IGORSERVER_PORT'])
        rv = rv + 'exec %s' % repr(sys.executable)
        for a in sys.argv:
            rv += ' ' + repr(a)
        rv += '\n'
        return rv

    def help(self):
        rv = 'Internal igor commands:\n'
        rv += 'help - this help\n'
        rv += 'version - return version number\n'
        rv += 'save - Make sure database is saved to disk\n'
        rv += 'restart - Save and restart this Igor (may appear to fail even when executed correctly)\n'
        rv += 'stop - Save and stop this Igor (may appear to fail even when executed correctly)\n'
        rv += 'command - Show command line that started this Igor instance\n'
        rv += 'dump - Show internal run queue of this Igor instance\n'
        rv += 'log - Show httpd-style log file of this Igor instance\n'
        return rv

    def version(self):
        return VERSION + '\n'

def main():
    DEFAULTDIR=os.path.join(os.path.expanduser('~'), '.igor')
    if 'IGORSERVER_DIR' in os.environ:
        DEFAULTDIR = os.environ['IGORSERVER_DIR']
    DEFAULTPORT=9333
    if 'IGORSERVER_PORT' in os.environ:
        DEFAULTDIR = int(os.environ['IGORSERVER_PORT'])

    parser = argparse.ArgumentParser(description="Run the Igor home automation server")
    parser.add_argument("-d", "--database", metavar="DIR", help="Database and scripts are stored in DIR (default: %s, environment IGORSERVER_DIR)" % DEFAULTDIR, default=DEFAULTDIR)
    parser.add_argument("-p", "--port", metavar="PORT", type=int, help="Port to serve on (default: 9333, environment IGORSERVER_PORT)", default=DEFAULTPORT)
    parser.add_argument("--debug", action="store_true", help="Enable debug output")
    parser.add_argument("--advertise", action="store_true", help="Advertise service through bonjour/zeroconf")
    parser.add_argument("--version", action="store_true", help="Print version and exit")
    parser.add_argument("--profile", action="store_true", help="Enable Python profiler (debugging Igor only)")
    args = parser.parse_args()

    if args.version:
        print VERSION
        sys.exit(0)
    if args.debug:
        callUrl.DEBUG = True
        sseListener.DEBUG = True
        actions.DEBUG = True
        xmlDatabase.DEBUG = True
        webApp.DEBUG = True
    datadir = args.database
    try:
        igorServer = IgorServer(datadir, args.port, args.advertise, profile=args.profile)
    except IOError, arg:
        print >>sys.stderr, '%s: Cannot open database: %s' % (sys.argv[0], arg)
        print >>sys.stderr, '%s: Use --help option to see command line arguments' % sys.argv[0]
        sys.exit(1)
    igorServer.run()

#
# We need to hack the import lock. In case we get here via the easy_install igorServer script
# we are inside an __import__(), and we hold the lock. This means other threads cannot import
# and we hang once a web request comes in. We "work around" this by releasing the lock.
#
hasImportLock = imp.lock_held()
if hasImportLock:
    imp.release_lock()
main()
if hasImportLock:
    imp.acquire_lock()

<|endoftext|>


<commit_before>#!/usr/bin/env python

import optparse
import os
import random
import time
import urlparse

from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler

from main import WKhtmlToPdf

HOST = '127.0.0.1'
PORT = 8888

def run_server(handler, host, port):
    server = HTTPServer((host, port), handler)
    try:
        server.serve_forever()
        print time.asctime(), 'Starting server (http://%s:%s), use <Ctrl-C> to stop' % (host, port)
        return True
    except KeyboardInterrupt:
        server.server_close()
        print time.asctime(), 'Stopping server (http://%s:%s)' % (host, port)
        return True

class RequestHandler(BaseHTTPRequestHandler):
    """
    Simple request class to serve json response back to ajax application.
    """
    def handle_headers(self, status_code):
        self.send_response(status_code)
        self.send_header('Content-Type', 'application/json')
        self.send_header('Access-Control-Allow-Origin', host)
        self.end_headers()

    def handle_404(self, message):
        self.handle_headers(404)
        self.wfile.write('{"error": "%s"}"' % message)
        self.end_headers()

    def handle_500(self, message):
        self.handle_headers(500)
        self.wfile.write('{"error": "%s"}"' % message)

    def handle_200(self, message, file_path=None):
        self.handle_headers(200)
        if file_path:
            self.wfile.write('{"success": "%s", "file_path": %s}"' % (message, file_path))
        else:
            self.wfile.write('{"success": "%s"}"' % message)

    def do_GET(self):
        # get the query string variables
        self.urlparser = urlparse.urlparse(self.path)
        self.query_string = self.urlparser.query
        self.query_dict = urlparse.parse_qs(self.query_string)

        # get the url and output_file
        self.url = self.query_dict.get('url', [None, ])[0]
        self.output_file = self.query_dict.get('output_file', [None, ])[0]

        if not self.url or not self.output_file:
            self.handle_404("url and output_file params are required")
            return None

        wkhtp = WKhtmlToPdf(self.url, self.output_file)
        output_file = wkhtp.render()

        # send json response
        if output_file[0]:
            self.handle_200("the file has been saved", output_file[1])
        else:
            self.handle_500("%s - the file could not be created" % output_file[1])
        return None

if __name__ == '__main__':

    # parse through the system argumants
    usage = "usage: %prog [options]"
    parser = optparse.OptionParser()
    parser.add_option("-H", "--host", dest="host", default=HOST, help="server host name")
    parser.add_option("-p", "--port", dest="port", default=PORT, help="port to run the api on")
    options, args = parser.parse_args()

    # set host and port
    host = options.host
    port = int(options.port)

    # handle the server
    run_server(RequestHandler, host, port)
<commit_msg>added support for optional argumants to api<commit_after>#!/usr/bin/env python

import optparse
import os
import random
import time
import urlparse

from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler

from main import WKhtmlToPdf

HOST = '127.0.0.1'
PORT = 8888

def run_server(handler, host, port):
    server = HTTPServer((host, port), handler)
    try:
        server.serve_forever()
        print time.asctime(), 'Starting server (http://%s:%s), use <Ctrl-C> to stop' % (host, port)
        return True
    except KeyboardInterrupt:
        server.server_close()
        print time.asctime(), 'Stopping server (http://%s:%s)' % (host, port)
        return True

class RequestHandler(BaseHTTPRequestHandler):
    """
    Simple request class to serve json response back to ajax application.
    """
    def handle_headers(self, status_code):
        self.send_response(status_code)
        self.send_header('Content-Type', 'application/json')
        self.send_header('Access-Control-Allow-Origin', host)
        self.end_headers()

    def handle_404(self, message):
        self.handle_headers(404)
        self.wfile.write('{"error": "%s"}"' % message)
        self.end_headers()

    def handle_500(self, message):
        self.handle_headers(500)
        self.wfile.write('{"error": "%s"}"' % message)

    def handle_200(self, message, file_path=None):
        self.handle_headers(200)
        if file_path:
            self.wfile.write('{"success": "%s", "file_path": %s}"' % (message, file_path))
        else:
            self.wfile.write('{"success": "%s"}"' % message)

    def do_GET(self):
        # get the query string variables
        self.urlparser = urlparse.urlparse(self.path)
        self.query_string = self.urlparser.query
        self.query_dict = urlparse.parse_qs(self.query_string)

        # get the url and output_file
        self.url = self.query_dict.get('url', [None, ])[0]
        self.output_file = self.query_dict.get('output_file', [None, ])[0]

        # return error if url or output_file are missing
        if not self.url or not self.output_file:
            self.handle_404("url and output_file params are required")
            return None

        wkhtp = WKhtmlToPdf(self.url, self.output_file, **self.query_dict)
        output_file = wkhtp.render()

        # send json response
        if output_file[0]:
            self.handle_200("the file has been saved", output_file[1])
        else:
            self.handle_500("%s - the file could not be created" % output_file[1])
        return None

if __name__ == '__main__':

    # parse through the system argumants
    usage = "usage: %prog [options]"
    parser = optparse.OptionParser()
    parser.add_option("-H", "--host", dest="host", default=HOST, help="server host name")
    parser.add_option("-p", "--port", dest="port", default=PORT, help="port to run the api on")
    options, args = parser.parse_args()

    # set host and port
    host = options.host
    port = int(options.port)

    # handle the server
    run_server(RequestHandler, host, port)
<|endoftext|>


<commit_before># Licensed to the StackStorm, Inc ('StackStorm') under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.

import os
import sys

from st2common import log as logging
from st2common.persistence.reactor import Trigger
from st2reactor.container.process_container import ProcessSensorContainer

LOG = logging.getLogger(__name__)

class SensorContainerManager(object):
    # TODO: Load balancing for sensors.
    def __init__(self, max_containers=10):
        self._max_containers = max_containers

    def run_sensors(self, sensors):
        """
        :param sensors: A list of DB models of sensors to run.
        :type sensors: ``list``
        """
        LOG.info('Setting up container to run %d sensors.', len(sensors))

        sensors_to_run = []
        for sensor in sensors:
            # TODO: Directly pass DB object to the ProcessContainer
            file_path = sensor.artifact_uri.replace('file://', '')
            class_name = sensor.entry_point.split('.')[-1]

            sensor_obj = {
                'pack': sensor.pack,
                'file_path': file_path,
                'class_name': class_name,
                'trigger_types': sensor.trigger_types,
                'poll_interval': sensor.poll_interval
            }
            sensors_to_run.append(sensor_obj)

        for trigger in Trigger.get_all():
            # TODO: Dispatch event to be consumed by the wrapper
            #self._create_handler(trigger=trigger)
            pass

        LOG.info('(PID:%s) SensorContainer started.', os.getpid())
        sensor_container = ProcessSensorContainer(sensors=sensors_to_run)
        try:
            exit_code = sensor_container.run()
            LOG.info('(PID:%s) SensorContainer stopped. Reason - run ended.', os.getpid())
            return exit_code
        except (KeyboardInterrupt, SystemExit):
            LOG.info('(PID:%s) SensorContainer stopped. Reason - %s', os.getpid(),
                     sys.exc_info()[0].__name__)
            return 0
<commit_msg>Update ContainerManager to publish "trigger create" Trigger CUD events for all the existing Trigger objects in the database.<commit_after># Licensed to the StackStorm, Inc ('StackStorm') under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.

import os
import sys

from oslo.config import cfg

from st2common import log as logging
from st2common.persistence.reactor import Trigger
from st2common.transport.reactor import TriggerCUDPublisher
from st2reactor.container.process_container import ProcessSensorContainer

LOG = logging.getLogger(__name__)

class SensorContainerManager(object):
    # TODO: Load balancing for sensors.
    def __init__(self, max_containers=10):
        self._max_containers = max_containers

    def run_sensors(self, sensors):
        """
        :param sensors: A list of DB models of sensors to run.
        :type sensors: ``list``
        """
        LOG.info('Setting up container to run %d sensors.', len(sensors))

        sensors_to_run = []
        for sensor in sensors:
            # TODO: Directly pass DB object to the ProcessContainer
            file_path = sensor.artifact_uri.replace('file://', '')
            class_name = sensor.entry_point.split('.')[-1]

            sensor_obj = {
                'pack': sensor.pack,
                'file_path': file_path,
                'class_name': class_name,
                'trigger_types': sensor.trigger_types,
                'poll_interval': sensor.poll_interval
            }
            sensors_to_run.append(sensor_obj)

        trigger_cud_publisher = TriggerCUDPublisher(url=cfg.CONF.messaging.url)
        for trigger in Trigger.get_all():
            # Dispatch create Trigger CUD events for all the existing Triggers
            # in the DB. Those events are consumer by the sensor wrapper
            trigger_cud_publisher.publish_create(payload=trigger)

        LOG.info('(PID:%s) SensorContainer started.', os.getpid())
        sensor_container = ProcessSensorContainer(sensors=sensors_to_run)
        try:
            exit_code = sensor_container.run()
            LOG.info('(PID:%s) SensorContainer stopped. Reason - run ended.', os.getpid())
            return exit_code
        except (KeyboardInterrupt, SystemExit):
            LOG.info('(PID:%s) SensorContainer stopped. Reason - %s', os.getpid(),
                     sys.exc_info()[0].__name__)
            return 0
<|endoftext|>


<commit_before>##########################################################################
#
#  Copyright (c) 2011-2012, John Haddon. All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are
#  met:
#
#      * Redistributions of source code must retain the above
#        copyright notice, this list of conditions and the following
#        disclaimer.
#
#      * Redistributions in binary form must reproduce the above
#        copyright notice, this list of conditions and the following
#        disclaimer in the documentation and/or other materials provided with
#        the distribution.
#
#      * Neither the name of John Haddon nor the names of
#        any other contributors to this software may be used to endorse or
#        promote products derived from this software without specific prior
#        written permission.
#
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
#  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
#  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
#  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
##########################################################################

import traceback
import sys

import IECore
import Gaffer

class python( Gaffer.Application ) :

	def __init__( self ) :

		Gaffer.Application.__init__(
			self,
			"""
			Runs python scripts in an environment where all the
			Gaffer modules are available.

			> Caution : This application is deprecated.
			> Use `gaffer env python` instead.
			"""
		)

		self.parameters().addParameters(

			[

				IECore.FileNameParameter(
					name = "file",
					description = "The python script to execute",
					defaultValue = "",
					allowEmptyString = False,
					check = IECore.FileNameParameter.CheckType.MustExist,
				),

				IECore.StringVectorParameter(
					name = "arguments",
					description = "An arbitrary list of arguments which will be provided to "
						"the python script in a variable called argv.",
					defaultValue = IECore.StringVectorData(),
					userData = {
						"parser" : {
							"acceptFlags" : IECore.BoolData( True ),
						},
					},
				),

			]

		)

		self.parameters().userData()["parser"] = IECore.CompoundObject(
			{
				"flagless" : IECore.StringVectorData( [ "file", "arguments" ] )
			}
		)

	def _run( self, args ) :

		# trying to set the sys.argv to the same values as we would expect from a python call
		#
		# the gaffer python command line syntax is expected to be:
		# gaffer python -file <script path> [-arguments <arguments>]
		#
		# given the limitations of the gaffer python app command line syntax, we can assume that the equivalent python command syntax would be:
		# python <script path> [<arguments>]
		#
		# python removes the "python" command from the start of the sys.argv list, making the first argument the script path
		# sys.argv should therefore be:
		# [<script path>] + [<arguments>]
		#
		# sys.argv is assumed to be the source of information for python argument parsing methods (argparse, getopt, ...)
		#
		# NOTE: this is not thread-safe
		# we could make it thread safe by using a mechanism similar to the one used by gaffer/python/Gaffer/OutputRedirection.py
		# but using that method, a generic python code could break if it was actually trying to alter a global sys.argv from a thread
		# however, since changing sys.argv is quite rare, and calling "gaffer python app" from a Thread is also a very unlikely scenario
		# we'll just leave it thread-unsafe for the moment

		origSysArgv = sys.argv
		try:
			sys.argv = [ args[ "file" ].value ] + list( args[ "arguments" ] )
			try :
				execfile(
					args["file"].value,
					{
						"argv" : args["arguments"],
						"__name__" : "__main__",
					}
				)
				return 0
			except SystemExit as e :
				# don't print traceback when a sys.exit was called, but return the exit code as the result
				return e.code
			except :
				traceback.print_exc()
				return 1
		finally:
			# restore sys.argv
			sys.argv = origSysArgv

IECore.registerRunTimeTyped( python )
<commit_msg>Python app : Avoid `execfile()`<commit_after>##########################################################################
#
#  Copyright (c) 2011-2012, John Haddon. All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are
#  met:
#
#      * Redistributions of source code must retain the above
#        copyright notice, this list of conditions and the following
#        disclaimer.
#
#      * Redistributions in binary form must reproduce the above
#        copyright notice, this list of conditions and the following
#        disclaimer in the documentation and/or other materials provided with
#        the distribution.
#
#      * Neither the name of John Haddon nor the names of
#        any other contributors to this software may be used to endorse or
#        promote products derived from this software without specific prior
#        written permission.
#
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
#  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
#  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
#  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
##########################################################################

import traceback
import sys
import six

import IECore
import Gaffer

class python( Gaffer.Application ) :

	def __init__( self ) :

		Gaffer.Application.__init__(
			self,
			"""
			Runs python scripts in an environment where all the
			Gaffer modules are available.

			> Caution : This application is deprecated.
			> Use `gaffer env python` instead.
			"""
		)

		self.parameters().addParameters(

			[

				IECore.FileNameParameter(
					name = "file",
					description = "The python script to execute",
					defaultValue = "",
					allowEmptyString = False,
					check = IECore.FileNameParameter.CheckType.MustExist,
				),

				IECore.StringVectorParameter(
					name = "arguments",
					description = "An arbitrary list of arguments which will be provided to "
						"the python script in a variable called argv.",
					defaultValue = IECore.StringVectorData(),
					userData = {
						"parser" : {
							"acceptFlags" : IECore.BoolData( True ),
						},
					},
				),

			]

		)

		self.parameters().userData()["parser"] = IECore.CompoundObject(
			{
				"flagless" : IECore.StringVectorData( [ "file", "arguments" ] )
			}
		)

	def _run( self, args ) :

		# trying to set the sys.argv to the same values as we would expect from a python call
		#
		# the gaffer python command line syntax is expected to be:
		# gaffer python -file <script path> [-arguments <arguments>]
		#
		# given the limitations of the gaffer python app command line syntax, we can assume that the equivalent python command syntax would be:
		# python <script path> [<arguments>]
		#
		# python removes the "python" command from the start of the sys.argv list, making the first argument the script path
		# sys.argv should therefore be:
		# [<script path>] + [<arguments>]
		#
		# sys.argv is assumed to be the source of information for python argument parsing methods (argparse, getopt, ...)
		#
		# NOTE: this is not thread-safe
		# we could make it thread safe by using a mechanism similar to the one used by gaffer/python/Gaffer/OutputRedirection.py
		# but using that method, a generic python code could break if it was actually trying to alter a global sys.argv from a thread
		# however, since changing sys.argv is quite rare, and calling "gaffer python app" from a Thread is also a very unlikely scenario
		# we'll just leave it thread-unsafe for the moment

		origSysArgv = sys.argv
		try:
			sys.argv = [ args[ "file" ].value ] + list( args[ "arguments" ] )
			try :
				with open( args["file"].value ) as f :
					six.exec_(
						compile( f.read(), args["file"].value, "exec" ),
						{
							"argv" : args["arguments"],
							"__name__" : "__main__",
						}
					)
				return 0
			except SystemExit as e :
				# don't print traceback when a sys.exit was called, but return the exit code as the result
				return e.code
			except :
				traceback.print_exc()
				return 1
		finally:
			# restore sys.argv
			sys.argv = origSysArgv

IECore.registerRunTimeTyped( python )
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""Utility functionality."""

from datetime import datetime

import dateutil

def datetime_to_timestamp(datetime_obj):
    """Return a timestamp for the given datetime object.

      :param datetime_obj: datetime object to be converted
    :type datetime_obj: datetime.datetime
    :return: timestamp from the passed datetime object
    :rtype: int

    """
    reference = datetime(1970, 1, 1)
    if datetime_obj.tzinfo:
        reference = reference.replace(tzinfo=dateutil.tz.tzutc())

    return int((datetime_obj - reference).total_seconds())
<commit_msg>Fix indentation in docstring<commit_after># -*- coding: utf-8 -*-
"""Utility functionality."""

from datetime import datetime

import dateutil

def datetime_to_timestamp(datetime_obj):
    """Return a timestamp for the given datetime object.

    :param datetime_obj: datetime object to be converted
    :type datetime_obj: datetime.datetime
    :return: timestamp from the passed datetime object
    :rtype: int

    """
    reference = datetime(1970, 1, 1)
    if datetime_obj.tzinfo:
        reference = reference.replace(tzinfo=dateutil.tz.tzutc())

    return int((datetime_obj - reference).total_seconds())
<|endoftext|>