<commit_before>'''
Render the pillar data
'''

# Import python libs
import os
import collections
import logging

# Import salt libs
import salt.loader
import salt.fileclient
import salt.minion
import salt.crypt
from salt._compat import string_types
from salt.template import compile_template
from salt.utils.dictupdate import update

log = logging.getLogger(__name__)

def get_pillar(opts, grains, id_, env=None):
    '''
    Return the correct pillar driver based on the file_client option
    '''
    return {
            'remote': RemotePillar,
            'local': Pillar
            }.get(opts['file_client'], Pillar)(opts, grains, id_, env)

class RemotePillar(object):
    '''
    Get the pillar from the master
    '''
    def __init__(self, opts, grains, id_, env):
        self.opts = opts
        self.opts['environment'] = env
        self.grains = grains
        self.id_ = id_
        self.serial = salt.payload.Serial(self.opts)
        self.sreq = salt.payload.SREQ(self.opts['master_uri'])
        self.auth = salt.crypt.SAuth(opts)

    def compile_pillar(self):
        '''
        Return the pillar data from the master
        '''
        load = {'id': self.id_,
                'grains': self.grains,
                'env': self.opts['environment'],
                'ver': '2',
                'cmd': '_pillar'}
        ret = self.sreq.send('aes', self.auth.crypticle.dumps(load), 3, 7200)
        key = self.auth.get_keys()
        aes = key.private_decrypt(ret['key'], 4)
        pcrypt = salt.crypt.Crypticle(self.opts, aes)
        return pcrypt.loads(ret['pillar'])

class Pillar(object):
    '''
    Read over the pillar top files and render the pillar data
    '''
    def __init__(self, opts, grains, id_, env):
        # use the local file client
        self.opts = self.__gen_opts(opts, grains, id_, env)
        self.client = salt.fileclient.get_file_client(self.opts)
        if opts.get('file_client', '') == 'local':
            opts['grains'] = grains
            self.functions = salt.loader.minion_mods(opts)
        else:
            self.functions = salt.loader.minion_mods(self.opts)
        self.matcher = salt.minion.Matcher(self.opts, self.functions)
        self.rend = salt.loader.render(self.opts, self.functions)
        self.ext_pillars = salt.loader.pillars(self.opts, self.functions)

    def __gen_opts(self, opts_in, grains, id_, env=None):
        '''
        The options need to be altered to conform to the file client
        '''
        opts = dict(opts_in)
        opts['file_roots'] = opts['pillar_roots']
        opts['file_client'] = 'local'
        opts['grains'] = grains
        opts['id'] = id_
        if 'environment' not in opts:
            opts['environment'] = env
        if opts['state_top'].startswith('salt://'):
            opts['state_top'] = opts['state_top']
        elif opts['state_top'].startswith('/'):
            opts['state_top'] = os.path.join('salt://', opts['state_top'][1:])
        else:
            opts['state_top'] = os.path.join('salt://', opts['state_top'])
        return opts

    def _get_envs(self):
        '''
        Pull the file server environments out of the master options
        '''
        envs = set(['base'])
        if 'file_roots' in self.opts:
            envs.update(list(self.opts['file_roots']))
        return envs

    def get_tops(self):
        '''
        Gather the top files
        '''
        tops = collections.defaultdict(list)
        include = collections.defaultdict(list)
        done = collections.defaultdict(list)
        errors = []
        # Gather initial top files
        try:
            if self.opts['environment']:
                tops[self.opts['environment']] = [
                        compile_template(
                            self.client.cache_file(
                                self.opts['state_top'],
                                self.opts['environment']
                                ),
                            self.rend,
                            self.opts['renderer'],
                            self.opts['environment']
                            )
                        ]
            else:
                for env in self._get_envs():
                    tops[env].append(
                            compile_template(
                                self.client.cache_file(
                                    self.opts['state_top'],
                                    env
                                    ),
                                self.rend,
                                self.opts['renderer'],
                                env=env
                                )
                            )
        except Exception as exc:
            errors.append(
                    ('Rendering Primary Top file failed, render error:\n{0}'
                        .format(exc)))

        # Search initial top files for includes
        for env, ctops in tops.items():
            for ctop in ctops:
                if not 'include' in ctop:
                    continue
                for sls in ctop['include']:
                    include[env].append(sls)
                ctop.pop('include')
        # Go through the includes and pull out the extra tops and add them
        while include:
            pops = []
            for env, states in include.items():
                pops.append(env)
                if not states:
                    continue
                for sls in states:
                    if sls in done[env]:
                        continue
                    try:
                        tops[env].append(
                                compile_template(
                                    self.client.get_state(
                                        sls,
                                        env
                                        ),
                                    self.rend,
                                    self.opts['renderer'],
                                    env=env
                                    )
                                )
                    except Exception as exc:
                        errors.append(
                                ('Rendering Top file {0} failed, render error'
                                 ':\n{1}').format(sls, exc))
                    done[env].append(sls)
            for env in pops:
                if env in include:
                    include.pop(env)

        return tops, errors

    def merge_tops(self, tops):
        '''
        Cleanly merge the top files
        '''
        top = collections.defaultdict(dict)
        for sourceenv, ctops in tops.items():
            for ctop in ctops:
                for env, targets in ctop.items():
                    if env == 'include':
                        continue
                    for tgt in targets:
                        if not tgt in top[env]:
                            top[env][tgt] = ctop[env][tgt]
                            continue
                        matches = []
                        states = set()
                        for comp in top[env][tgt]:
                            if isinstance(comp, dict):
                                matches.append(comp)
                            if isinstance(comp, string_types):
                                states.add(comp)
                        top[env][tgt] = matches
                        top[env][tgt].extend(list(states))
        return top

    def get_top(self):
        '''
        Returns the high data derived from the top file
        '''
        tops, errors = self.get_tops()
        return self.merge_tops(tops), errors

    def top_matches(self, top):
        '''
        Search through the top high data for matches and return the states
        that this minion needs to execute.

        Returns:
        {'env': ['state1', 'state2', ...]}
        '''
        matches = {}
        for env, body in top.items():
            if self.opts['environment']:
                if not env == self.opts['environment']:
                    continue
            for match, data in body.items():
                if self.matcher.confirm_top(
                        match,
                        data,
                        self.opts.get('nodegroups', {}),
                        ):
                    if env not in matches:
                        matches[env] = []
                    for item in data:
                        if isinstance(item, string_types):
                            matches[env].append(item)
        return matches

    def render_pstate(self, sls, env, mods):
        '''
        Collect a single pillar sls file and render it
        '''
        err = ''
        errors = []
        fn_ = self.client.get_state(sls, env)
        if not fn_:
            errors.append(('Specified SLS {0} in environment {1} is not'
                           ' available on the salt master').format(sls, env))
        state = None
        try:
            state = compile_template(
                fn_, self.rend, self.opts['renderer'], env, sls)
        except Exception as exc:
            errors.append(('Rendering SLS {0} failed, render error:\n{1}'
                           .format(sls, exc)))
        mods.add(sls)
        nstate = None
        if state:
            if not isinstance(state, dict):
                errors.append(('SLS {0} does not render to a dictionary'
                               .format(sls)))
            else:
                if 'include' in state:
                    if not isinstance(state['include'], list):
                        err = ('Include Declaration in SLS {0} is not formed '
                               'as a list'.format(sls))
                        errors.append(err)
                    else:
                        for sub_sls in state.pop('include'):
                            if sub_sls not in mods:
                                nstate, mods, err = self.render_pstate(
                                        sub_sls,
                                        env,
                                        mods
                                        )
                            if nstate:
                                state.update(nstate)
                            if err:
                                errors += err
        return state, mods, errors

    def render_pillar(self, matches):
        '''
        Extract the sls pillar files from the matches and render them into the
        pillar
        '''
        pillar = {}
        errors = []
        for env, pstates in matches.items():
            mods = set()
            for sls in pstates:
                pstate, mods, err = self.render_pstate(sls, env, mods)
                if pstate:
                    pillar.update(pstate)
                if err:
                    errors += err
        return pillar, errors

    def ext_pillar(self, pillar):
        '''
        Render the external pillar data
        '''
        if not 'ext_pillar' in self.opts:
            return  {}
        if not isinstance(self.opts['ext_pillar'], list):
            log.critical('The "ext_pillar" option is malformed')
            return {}
        for run in self.opts['ext_pillar']:
            if not isinstance(run, dict):
                log.critical('The "ext_pillar" option is malformed')
                return {}
            for key, val in run.items():
                if key not in self.ext_pillars:
                    err = ('Specified ext_pillar interface {0} is '
                           'unavailable').format(key)
                    log.critical(err)
                    continue
                try:
                    if isinstance(val, dict):
                        ext = self.ext_pillars[key](pillar, **val)
                    elif isinstance(val, list):
                        ext = self.ext_pillars[key](pillar, *val)
                    else:
                        ext = self.ext_pillars[key](pillar, val)
                    update(pillar, ext)
                except Exception as exc:
                    log.exception('Failed to load ext_pillar {0}: {1}'.format(key, exc))
        return pillar

    def compile_pillar(self):
        '''
        Render the pillar dta and return
        '''
        top, terrors = self.get_top()
        matches = self.top_matches(top)
        pillar, errors = self.render_pillar(matches)
        self.ext_pillar(pillar)
        errors.extend(terrors)
        if self.opts.get('pillar_opts', True):
            mopts = dict(self.opts)
            if 'grains' in mopts:
                mopts.pop('grains')
            if 'aes' in mopts:
                mopts.pop('aes')
            pillar['master'] = mopts
        if errors:
            for error in errors:
                log.critical('Pillar render error: {0}'.format(error))
            return {}
        return pillar
<commit_msg>Provide the master's version in pillar.data<commit_after>'''
Render the pillar data
'''

# Import python libs
import os
import collections
import logging

# Import salt libs
import salt.loader
import salt.fileclient
import salt.minion
import salt.crypt
from salt._compat import string_types
from salt.template import compile_template
from salt.utils.dictupdate import update
from salt.version import __version__

log = logging.getLogger(__name__)

def get_pillar(opts, grains, id_, env=None):
    '''
    Return the correct pillar driver based on the file_client option
    '''
    return {
            'remote': RemotePillar,
            'local': Pillar
            }.get(opts['file_client'], Pillar)(opts, grains, id_, env)

class RemotePillar(object):
    '''
    Get the pillar from the master
    '''
    def __init__(self, opts, grains, id_, env):
        self.opts = opts
        self.opts['environment'] = env
        self.grains = grains
        self.id_ = id_
        self.serial = salt.payload.Serial(self.opts)
        self.sreq = salt.payload.SREQ(self.opts['master_uri'])
        self.auth = salt.crypt.SAuth(opts)

    def compile_pillar(self):
        '''
        Return the pillar data from the master
        '''
        load = {'id': self.id_,
                'grains': self.grains,
                'env': self.opts['environment'],
                'ver': '2',
                'cmd': '_pillar'}
        ret = self.sreq.send('aes', self.auth.crypticle.dumps(load), 3, 7200)
        key = self.auth.get_keys()
        aes = key.private_decrypt(ret['key'], 4)
        pcrypt = salt.crypt.Crypticle(self.opts, aes)
        return pcrypt.loads(ret['pillar'])

class Pillar(object):
    '''
    Read over the pillar top files and render the pillar data
    '''
    def __init__(self, opts, grains, id_, env):
        # use the local file client
        self.opts = self.__gen_opts(opts, grains, id_, env)
        self.client = salt.fileclient.get_file_client(self.opts)
        if opts.get('file_client', '') == 'local':
            opts['grains'] = grains
            self.functions = salt.loader.minion_mods(opts)
        else:
            self.functions = salt.loader.minion_mods(self.opts)
        self.matcher = salt.minion.Matcher(self.opts, self.functions)
        self.rend = salt.loader.render(self.opts, self.functions)
        self.ext_pillars = salt.loader.pillars(self.opts, self.functions)

    def __gen_opts(self, opts_in, grains, id_, env=None):
        '''
        The options need to be altered to conform to the file client
        '''
        opts = dict(opts_in)
        opts['file_roots'] = opts['pillar_roots']
        opts['file_client'] = 'local'
        opts['grains'] = grains
        opts['id'] = id_
        if 'environment' not in opts:
            opts['environment'] = env
        if opts['state_top'].startswith('salt://'):
            opts['state_top'] = opts['state_top']
        elif opts['state_top'].startswith('/'):
            opts['state_top'] = os.path.join('salt://', opts['state_top'][1:])
        else:
            opts['state_top'] = os.path.join('salt://', opts['state_top'])
        return opts

    def _get_envs(self):
        '''
        Pull the file server environments out of the master options
        '''
        envs = set(['base'])
        if 'file_roots' in self.opts:
            envs.update(list(self.opts['file_roots']))
        return envs

    def get_tops(self):
        '''
        Gather the top files
        '''
        tops = collections.defaultdict(list)
        include = collections.defaultdict(list)
        done = collections.defaultdict(list)
        errors = []
        # Gather initial top files
        try:
            if self.opts['environment']:
                tops[self.opts['environment']] = [
                        compile_template(
                            self.client.cache_file(
                                self.opts['state_top'],
                                self.opts['environment']
                                ),
                            self.rend,
                            self.opts['renderer'],
                            self.opts['environment']
                            )
                        ]
            else:
                for env in self._get_envs():
                    tops[env].append(
                            compile_template(
                                self.client.cache_file(
                                    self.opts['state_top'],
                                    env
                                    ),
                                self.rend,
                                self.opts['renderer'],
                                env=env
                                )
                            )
        except Exception as exc:
            errors.append(
                    ('Rendering Primary Top file failed, render error:\n{0}'
                        .format(exc)))

        # Search initial top files for includes
        for env, ctops in tops.items():
            for ctop in ctops:
                if not 'include' in ctop:
                    continue
                for sls in ctop['include']:
                    include[env].append(sls)
                ctop.pop('include')
        # Go through the includes and pull out the extra tops and add them
        while include:
            pops = []
            for env, states in include.items():
                pops.append(env)
                if not states:
                    continue
                for sls in states:
                    if sls in done[env]:
                        continue
                    try:
                        tops[env].append(
                                compile_template(
                                    self.client.get_state(
                                        sls,
                                        env
                                        ),
                                    self.rend,
                                    self.opts['renderer'],
                                    env=env
                                    )
                                )
                    except Exception as exc:
                        errors.append(
                                ('Rendering Top file {0} failed, render error'
                                 ':\n{1}').format(sls, exc))
                    done[env].append(sls)
            for env in pops:
                if env in include:
                    include.pop(env)

        return tops, errors

    def merge_tops(self, tops):
        '''
        Cleanly merge the top files
        '''
        top = collections.defaultdict(dict)
        for sourceenv, ctops in tops.items():
            for ctop in ctops:
                for env, targets in ctop.items():
                    if env == 'include':
                        continue
                    for tgt in targets:
                        if not tgt in top[env]:
                            top[env][tgt] = ctop[env][tgt]
                            continue
                        matches = []
                        states = set()
                        for comp in top[env][tgt]:
                            if isinstance(comp, dict):
                                matches.append(comp)
                            if isinstance(comp, string_types):
                                states.add(comp)
                        top[env][tgt] = matches
                        top[env][tgt].extend(list(states))
        return top

    def get_top(self):
        '''
        Returns the high data derived from the top file
        '''
        tops, errors = self.get_tops()
        return self.merge_tops(tops), errors

    def top_matches(self, top):
        '''
        Search through the top high data for matches and return the states
        that this minion needs to execute.

        Returns:
        {'env': ['state1', 'state2', ...]}
        '''
        matches = {}
        for env, body in top.items():
            if self.opts['environment']:
                if not env == self.opts['environment']:
                    continue
            for match, data in body.items():
                if self.matcher.confirm_top(
                        match,
                        data,
                        self.opts.get('nodegroups', {}),
                        ):
                    if env not in matches:
                        matches[env] = []
                    for item in data:
                        if isinstance(item, string_types):
                            matches[env].append(item)
        return matches

    def render_pstate(self, sls, env, mods):
        '''
        Collect a single pillar sls file and render it
        '''
        err = ''
        errors = []
        fn_ = self.client.get_state(sls, env)
        if not fn_:
            errors.append(('Specified SLS {0} in environment {1} is not'
                           ' available on the salt master').format(sls, env))
        state = None
        try:
            state = compile_template(
                fn_, self.rend, self.opts['renderer'], env, sls)
        except Exception as exc:
            errors.append(('Rendering SLS {0} failed, render error:\n{1}'
                           .format(sls, exc)))
        mods.add(sls)
        nstate = None
        if state:
            if not isinstance(state, dict):
                errors.append(('SLS {0} does not render to a dictionary'
                               .format(sls)))
            else:
                if 'include' in state:
                    if not isinstance(state['include'], list):
                        err = ('Include Declaration in SLS {0} is not formed '
                               'as a list'.format(sls))
                        errors.append(err)
                    else:
                        for sub_sls in state.pop('include'):
                            if sub_sls not in mods:
                                nstate, mods, err = self.render_pstate(
                                        sub_sls,
                                        env,
                                        mods
                                        )
                            if nstate:
                                state.update(nstate)
                            if err:
                                errors += err
        return state, mods, errors

    def render_pillar(self, matches):
        '''
        Extract the sls pillar files from the matches and render them into the
        pillar
        '''
        pillar = {}
        errors = []
        for env, pstates in matches.items():
            mods = set()
            for sls in pstates:
                pstate, mods, err = self.render_pstate(sls, env, mods)
                if pstate:
                    pillar.update(pstate)
                if err:
                    errors += err
        return pillar, errors

    def ext_pillar(self, pillar):
        '''
        Render the external pillar data
        '''
        if not 'ext_pillar' in self.opts:
            return  {}
        if not isinstance(self.opts['ext_pillar'], list):
            log.critical('The "ext_pillar" option is malformed')
            return {}
        for run in self.opts['ext_pillar']:
            if not isinstance(run, dict):
                log.critical('The "ext_pillar" option is malformed')
                return {}
            for key, val in run.items():
                if key not in self.ext_pillars:
                    err = ('Specified ext_pillar interface {0} is '
                           'unavailable').format(key)
                    log.critical(err)
                    continue
                try:
                    if isinstance(val, dict):
                        ext = self.ext_pillars[key](pillar, **val)
                    elif isinstance(val, list):
                        ext = self.ext_pillars[key](pillar, *val)
                    else:
                        ext = self.ext_pillars[key](pillar, val)
                    update(pillar, ext)
                except Exception as exc:
                    log.exception('Failed to load ext_pillar {0}: {1}'.format(key, exc))
        return pillar

    def compile_pillar(self):
        '''
        Render the pillar dta and return
        '''
        top, terrors = self.get_top()
        matches = self.top_matches(top)
        pillar, errors = self.render_pillar(matches)
        self.ext_pillar(pillar)
        errors.extend(terrors)
        if self.opts.get('pillar_opts', True):
            mopts = dict(self.opts)
            if 'grains' in mopts:
                mopts.pop('grains')
            if 'aes' in mopts:
                mopts.pop('aes')
            mopts['saltversion'] = __version__
            pillar['master'] = mopts
        if errors:
            for error in errors:
                log.critical('Pillar render error: {0}'.format(error))
            return {}
        return pillar
<|endoftext|>


<commit_before>from marnadi import Header, descriptors
from marnadi.utils import to_bytes

class HttpError(Exception):

    __slots__ = '__weakref__',

    headers = descriptors.Headers(
        ('Content-Type', Header('text/plain', charset='utf-8')),
    )

    def __init__(self, status='500 Internal Server Error',
                 data=None, headers=None):
        self.status = status
        self.data = data
        if headers:
            self.headers.extend(headers)

    def __len__(self):
        return 1

    def __iter__(self):
        yield to_bytes(self.data)
<commit_msg>removed unnecessary __slots__<commit_after>from marnadi import Header, descriptors
from marnadi.utils import to_bytes

class HttpError(Exception):

    headers = descriptors.Headers(
        ('Content-Type', Header('text/plain', charset='utf-8')),
    )

    def __init__(self, status='500 Internal Server Error',
                 data=None, headers=None):
        self.status = status
        self.data = data
        if headers:
            self.headers.extend(headers)

    def __len__(self):
        return 1

    def __iter__(self):
        yield to_bytes(self.data)
<|endoftext|>


<commit_before>""" Version info for objbrowser
"""
import os

DEBUGGING = False # TODO: False

PROGRAM_NAME = 'objbrowser'
PROGRAM_VERSION = '0.9.3a'
PROGRAM_DIRECTORY = os.path.abspath(os.path.dirname(__file__))
#IMAGE_DIRECTORY = PROGRAM_DIRECTORY + '/images/'
<commit_msg>Version 0.9.4<commit_after>""" Version info for objbrowser
"""
import os

DEBUGGING = False # TODO: False

PROGRAM_NAME = 'objbrowser'
PROGRAM_VERSION = '0.9.4'
PROGRAM_DIRECTORY = os.path.abspath(os.path.dirname(__file__))
#IMAGE_DIRECTORY = PROGRAM_DIRECTORY + '/images/'
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
'''
Installation of Composer Packages
=================================

These states manage the installed packages for composer for PHP. Note that
either composer is installed and accessible via a bin directory or you can pass
the location of composer in the state.

.. code-block:: yaml

    get-composer:
      cmd.run:
        - name: 'CURL=`which curl`; $CURL -sS https://getcomposer.org/installer | php'
        - unless: test -f /usr/local/bin/composer
        - cwd: /root/

    install-composer:
      cmd.wait:
        - name: mv /root/composer.phar /usr/local/bin/composer
        - cwd: /root/
        - watch:
          - cmd: get-composer

    /path/to/project:
      composer.installed:
        - no_dev: true
        - require:
          - cmd: install-composer

    # Without composer installed in your PATH
    # Note: composer.phar must be executable for state to work properly
    /path/to/project:
      composer.installed:
        - composer: /path/to/composer.phar
        - php: /usr/local/bin/php
        - no_dev: true
'''

# Import salt libs
from salt.exceptions import CommandExecutionError, CommandNotFoundError

def __virtual__():
    '''
    Only load if the composer module is available in __salt__
    '''
    return 'composer.install' in __salt__

def installed(name,
              composer=None,
              php=None,
              user=None,
              prefer_source=None,
              prefer_dist=None,
              no_scripts=None,
              no_plugins=None,
              optimize=None,
              no_dev=None,
              composer_home='/root'):
    '''
    Verify that composer has installed the latest packages give a
    ``composer.json`` and ``composer.lock`` file in a directory.

    dir
        Directory location of the composer.json file.

    composer
        Location of the composer.phar file. If not set composer will
        just execute "composer" as if it is installed globally.
        (i.e. /path/to/composer.phar)

    php
        Location of the php executable to use with composer.
        (i.e. /usr/bin/php)

    user
        Which system user to run composer as.

        .. versionadded:: 2014.1.4

    prefer_source
        --prefer-source option of composer.

    prefer_dist
        --prefer-dist option of composer.

    no_scripts
        --no-scripts option of composer.

    no_plugins
        --no-plugins option of composer.

    optimize
        --optimize-autoloader option of composer. Recommended for production.

    no_dev
        --no-dev option for composer. Recommended for production.

    quiet
        --quiet option for composer. Whether or not to return output from composer.

    composer_home
        $COMPOSER_HOME environment variable
    '''
    ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}

    try:
        call = __salt__['composer.install'](
            name,
            composer=composer,
            php=php,
            runas=user,
            prefer_source=prefer_source,
            prefer_dist=prefer_dist,
            no_scripts=no_scripts,
            no_plugins=no_plugins,
            optimize=optimize,
            no_dev=no_dev,
            quiet=False,
            composer_home=composer_home
        )
    except (CommandNotFoundError, CommandExecutionError) as err:
        ret['result'] = False
        ret['comment'] = 'Error executing composer in \'{0!r}\': {1!r}'.format(name, err)
        return ret

    if call or isinstance(call, list) or isinstance(call, dict):
        ret['result'] = True
        if call.find('Nothing to install or update') < 0:
            ret['changes']['stdout'] = call

        ret['comment'] = 'Composer ran, nothing changed in {0!r}'.format(name)
    else:
        ret['result'] = False
        ret['comment'] = 'Could not run composer'

    return ret
<commit_msg>Making salt.states.composer python3 compatible<commit_after># -*- coding: utf-8 -*-
'''
Installation of Composer Packages
=================================

These states manage the installed packages for composer for PHP. Note that
either composer is installed and accessible via a bin directory or you can pass
the location of composer in the state.

.. code-block:: yaml

    get-composer:
      cmd.run:
        - name: 'CURL=`which curl`; $CURL -sS https://getcomposer.org/installer | php'
        - unless: test -f /usr/local/bin/composer
        - cwd: /root/

    install-composer:
      cmd.wait:
        - name: mv /root/composer.phar /usr/local/bin/composer
        - cwd: /root/
        - watch:
          - cmd: get-composer

    /path/to/project:
      composer.installed:
        - no_dev: true
        - require:
          - cmd: install-composer

    # Without composer installed in your PATH
    # Note: composer.phar must be executable for state to work properly
    /path/to/project:
      composer.installed:
        - composer: /path/to/composer.phar
        - php: /usr/local/bin/php
        - no_dev: true
'''
from __future__ import absolute_import

# Import salt libs
from salt.exceptions import CommandExecutionError, CommandNotFoundError

def __virtual__():
    '''
    Only load if the composer module is available in __salt__
    '''
    return 'composer.install' in __salt__

def installed(name,
              composer=None,
              php=None,
              user=None,
              prefer_source=None,
              prefer_dist=None,
              no_scripts=None,
              no_plugins=None,
              optimize=None,
              no_dev=None,
              composer_home='/root'):
    '''
    Verify that composer has installed the latest packages give a
    ``composer.json`` and ``composer.lock`` file in a directory.

    dir
        Directory location of the composer.json file.

    composer
        Location of the composer.phar file. If not set composer will
        just execute "composer" as if it is installed globally.
        (i.e. /path/to/composer.phar)

    php
        Location of the php executable to use with composer.
        (i.e. /usr/bin/php)

    user
        Which system user to run composer as.

        .. versionadded:: 2014.1.4

    prefer_source
        --prefer-source option of composer.

    prefer_dist
        --prefer-dist option of composer.

    no_scripts
        --no-scripts option of composer.

    no_plugins
        --no-plugins option of composer.

    optimize
        --optimize-autoloader option of composer. Recommended for production.

    no_dev
        --no-dev option for composer. Recommended for production.

    quiet
        --quiet option for composer. Whether or not to return output from composer.

    composer_home
        $COMPOSER_HOME environment variable
    '''
    ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}

    try:
        call = __salt__['composer.install'](
            name,
            composer=composer,
            php=php,
            runas=user,
            prefer_source=prefer_source,
            prefer_dist=prefer_dist,
            no_scripts=no_scripts,
            no_plugins=no_plugins,
            optimize=optimize,
            no_dev=no_dev,
            quiet=False,
            composer_home=composer_home
        )
    except (CommandNotFoundError, CommandExecutionError) as err:
        ret['result'] = False
        ret['comment'] = 'Error executing composer in \'{0!r}\': {1!r}'.format(name, err)
        return ret

    if call or isinstance(call, list) or isinstance(call, dict):
        ret['result'] = True
        if call.find('Nothing to install or update') < 0:
            ret['changes']['stdout'] = call

        ret['comment'] = 'Composer ran, nothing changed in {0!r}'.format(name)
    else:
        ret['result'] = False
        ret['comment'] = 'Could not run composer'

    return ret
<|endoftext|>


<commit_before>from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.db.models import get_models

class AlreadyRegistered(Exception):
    pass

class ObjectTools(object):
    """
    An ObjectTools object providing various object tools for various model
    classes. Models are registered with the ObjectTools using the
    register() method.
    """
    name = 'object-tools'
    app_name = 'object-tools'

    def __init__(self):
        self._registry = {}  # model class -> object_tools instance

    def register(self, object_tool_class, model_class=None):
        """
        Registers the given model(s) with the given object tool class.

        The model(s) should be Model classes, not instances.

        If a model class isn't given the object tool class will be registered
        for all models.

        If a model is already registered, this will raise AlreadyRegistered.

        If a model is abstract, this will raise ImproperlyConfigured.
        """
        if not object_tool_class:
            return None

        # Don't validate unless required.
        if object_tool_class and settings.DEBUG:
            from object_tools.validation import validate
            validate(object_tool_class, model_class)
            #= lambda model, adminclass: None

        if not model_class:
            models = get_models()
        else:
            models = [model_class, ]

        for model in models:
            if model._meta.abstract:
                raise ImproperlyConfigured(
                    'The model %s is abstract, so it \
                    cannot be registered with object tools.' % model.__name__)

            # Instantiate the object_tools class to save in the registry
            if model in self._registry:
                self._registry[model].append(object_tool_class(model))
            else:
                self._registry[model] = [object_tool_class(model), ]

    def get_urls(self):
        try:
            from django.conf.urls.defaults import patterns, url, include
        except ImportError:
            from django.conf.urls import patterns, url, include

        urlpatterns = patterns('',)

        # Add in each object_tool's views.
        for model, object_tools in self._registry.iteritems():
            for object_tool in object_tools:
                urlpatterns += patterns('',
                    url(r'^%s/%s/' % (model._meta.app_label,
                        model._meta.module_name),
                        include(object_tool.urls))
                )

        return urlpatterns

    @property
    def urls(self):
        return self.get_urls(), self.app_name, self.name

# This global object represents the default object tools, for the common case.
# You can instantiate ObjectTools in your own code to create a
# custom object tools object.
tools = ObjectTools()
<commit_msg>fixed for Django 1.8 -- module_name to model_name<commit_after>from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.db.models import get_models

class AlreadyRegistered(Exception):
    pass

class ObjectTools(object):
    """
    An ObjectTools object providing various object tools for various model
    classes. Models are registered with the ObjectTools using the
    register() method.
    """
    name = 'object-tools'
    app_name = 'object-tools'

    def __init__(self):
        self._registry = {}  # model class -> object_tools instance

    def register(self, object_tool_class, model_class=None):
        """
        Registers the given model(s) with the given object tool class.

        The model(s) should be Model classes, not instances.

        If a model class isn't given the object tool class will be registered
        for all models.

        If a model is already registered, this will raise AlreadyRegistered.

        If a model is abstract, this will raise ImproperlyConfigured.
        """
        if not object_tool_class:
            return None

        # Don't validate unless required.
        if object_tool_class and settings.DEBUG:
            from object_tools.validation import validate
            validate(object_tool_class, model_class)
            #= lambda model, adminclass: None

        if not model_class:
            models = get_models()
        else:
            models = [model_class, ]

        for model in models:
            if model._meta.abstract:
                raise ImproperlyConfigured(
                    'The model %s is abstract, so it \
                    cannot be registered with object tools.' % model.__name__)

            # Instantiate the object_tools class to save in the registry
            if model in self._registry:
                self._registry[model].append(object_tool_class(model))
            else:
                self._registry[model] = [object_tool_class(model), ]

    def get_urls(self):
        try:
            from django.conf.urls.defaults import patterns, url, include
        except ImportError:
            from django.conf.urls import patterns, url, include

        urlpatterns = patterns('',)

        # Add in each object_tool's views.
        for model, object_tools in self._registry.iteritems():
            for object_tool in object_tools:
                urlpatterns += patterns('',
                    url(r'^%s/%s/' % (model._meta.app_label,
                        model._meta.model_name),
                        include(object_tool.urls))
                )
        return urlpatterns

    @property
    def urls(self):
        return self.get_urls(), self.app_name, self.name

# This global object represents the default object tools, for the common case.
# You can instantiate ObjectTools in your own code to create a
# custom object tools object.
tools = ObjectTools()
<|endoftext|>


<commit_before>julia_package_env = {
    'CFLAGS':None,
    'CPPFLAGS': None,
    'LLVM_CMAKE': util.Property('llvm_cmake', default=None),
}

# Steps to build a `make binary-dist` tarball that should work on just about every linux ever
julia_package_factory = util.BuildFactory()
julia_package_factory.useProgress = True
julia_package_factory.addSteps([
    # Fetch first (allowing failure if no existing clone is present)
    steps.ShellCommand(
        name="git fetch",
        command=["git", "fetch"],
        flunkOnFailure=False
    ),

    # Clone julia
    steps.Git(
        name="Julia checkout",
        repourl=util.Property('repository', default='git://github.com/JuliaLang/julia.git'),
        mode='incremental',
        method='clean',
        submodules=True,
        clobberOnFailure=True,
        progress=True
    ),

    # Ensure gcc and cmake are installed on OSX
    steps.ShellCommand(
        name="Install necessary brew dependencies",
        command=["brew", "install", "gcc", "cmake"],
        doStepIf=is_mac,
        flunkOnFailure=False
    ),

    # make clean first
    steps.ShellCommand(
        name="make cleanall",
        command=["/bin/bash", "-c", util.Interpolate("make %(prop:flags)s %(prop:extra_make_flags)s cleanall")],
        env=julia_package_env,
    ),

    # Windows has a nasty habit of leaving julia-<gitsha> folders lying around....
    steps.ShellCommand(
        name="Clean out temporary windows cruft",
        command=["/bin/bash", "-c", "rm -rf julia-*"],
        doStepIf=is_windows,
        flunkOnFailure=False,
    ),

    # Make, forcing some degree of parallelism to cut down compile times
    # Also build `debug` and `release` in parallel, we should have enough RAM for that now
    steps.ShellCommand(
        name="make",
        command=["/bin/bash", "-c", util.Interpolate("make -j3 %(prop:flags)s %(prop:extra_make_flags)s debug release")],
        haltOnFailure = True,
        timeout=3600,
        env=julia_package_env,
    ),

    # Test this build
    steps.ShellCommand(
        name="make testall",
        command=["/bin/bash", "-c", util.Interpolate("make %(prop:flags)s %(prop:extra_make_flags)s testall")],
        haltOnFailure = True,
        timeout=3600,
        env=julia_package_env,
    ),

    # Make win-extras on windows
    steps.ShellCommand(
        name="make win-extras",
        command=["/bin/bash", "-c", util.Interpolate("make %(prop:flags)s %(prop:extra_make_flags)s win-extras")],
        haltOnFailure = True,
        doStepIf=is_windows,
        env=julia_package_env,
    ),

    # Set a bunch of properties that are useful down the line
    steps.SetPropertyFromCommand(
        name="Get commitmessage",
        command=["git", "log", "-1", "--pretty=format:%s%n%cN%n%cE%n%aN%n%aE"],
        extract_fn=parse_git_log,
        want_stderr=False
    ),
    steps.SetPropertyFromCommand(
        name="Get julia version/shortcommit",
        command=make_julia_version_command,
        extract_fn=parse_julia_version,
        want_stderr=False
    ),
    steps.SetPropertyFromCommand(
        name="Get build artifact filename",
        command=["make", "print-JULIA_BINARYDIST_FILENAME"],
        property="artifact_filename",
    ),
    steps.SetPropertyFromCommand(
        name="Munge artifact filename",
        command=munge_artifact_filename,
        property="dummy",
    ),

    # Make binary-dist to package it up
    steps.ShellCommand(
        name="make binary-dist",
        command=["/bin/bash", "-c", util.Interpolate("make %(prop:flags)s %(prop:extra_make_flags)s binary-dist")],
        haltOnFailure = True,
        timeout=3600,
        env=julia_package_env,
    ),

    # On OSX, deal with non-sf/consistent_distnames makefile nonsense by wrapping up all
    # the complexity into `render_make_app`.
    steps.ShellCommand(
        name="make .app",
        command=render_make_app,
        haltOnFailure = True,
        doStepIf=is_mac,
        env=julia_package_env,
    ),

    # Transfer the result to the buildmaster for uploading to AWS
    steps.MasterShellCommand(
        name="mkdir julia_package",
        command=["mkdir", "-p", "/tmp/julia_package"]
    ),

    steps.FileUpload(
        workersrc=util.Interpolate("%(prop:local_filename)s"),
        masterdest=util.Interpolate("/tmp/julia_package/%(prop:upload_filename)s")
    ),

    # Upload it to AWS and cleanup the master!
    steps.MasterShellCommand(
        name="Upload to AWS",
        command=render_upload_command,
        doStepIf=should_upload,
        haltOnFailure=True
    ),
    steps.MasterShellCommand(
        name="Upload to AWS (latest)",
        command=render_latest_upload_command,
        doStepIf=should_upload_latest,
        haltOnFailure=True
    ),

    steps.MasterShellCommand(
        name="Cleanup Master",
        command=["rm", "-f", util.Interpolate("/tmp/julia_package/%(prop:upload_filename)s")],
        doStepIf=should_upload
    ),

    # Trigger a download of this file onto another worker for coverage purposes
    steps.Trigger(schedulerNames=["Julia Coverage Testing"],
        set_properties={
            'url': render_download_url,
            'commitmessage': util.Property('commitmessage'),
            'commitname': util.Property('commitname'),
            'commitemail': util.Property('commitemail'),
            'authorname': util.Property('authorname'),
            'authoremail': util.Property('authoremail'),
            'shortcommit': util.Property('shortcommit'),
        },
        waitForFinish=False,
        doStepIf=should_run_coverage
    )
])

# Build a builder-worker mapping based off of the parent mapping in inventory.py
packager_mapping = {("package_" + k): v for k, v in builder_mapping.iteritems()}

# Add a few builders that don't exist in the typical mapping
packager_mapping["build_ubuntu32"] = "ubuntu16_04-x86"
packager_mapping["build_ubuntu64"] = "ubuntu16_04-x64"
packager_mapping["build_centos64"] = "centos7_3-x64"

packager_scheduler = schedulers.AnyBranchScheduler(
    name="Julia binary packaging",
    change_filter=util.ChangeFilter(
        project=['JuliaLang/julia','staticfloat/julia'],
        # Only build `master` or `release-*`
        branch_fn=lambda b: b == "master" or b.startswith("release-")
    ),
    builderNames=packager_mapping.keys(),
    treeStableTimer=1
)
c['schedulers'].append(packager_scheduler)

for packager, worker in packager_mapping.iteritems():
    c['builders'].append(util.BuilderConfig(
        name=packager,
        workernames=[worker],
        collapseRequests=False,
        tags=["Packaging"],
        factory=julia_package_factory
    ))

# Add a scheduler for building release candidates/triggering builds manually
force_build_scheduler = schedulers.ForceScheduler(
    name="package",
    label="Force Julia build/packaging",
    builderNames=packager_mapping.keys(),
    reason=util.FixedParameter(name="reason", default=""),
    codebases=[
        util.CodebaseParameter(
            "",
            name="",
            branch=util.FixedParameter(name="branch", default=""),
            repository=util.FixedParameter(name="repository", default=""),
            project=util.FixedParameter(name="project", default="Packaging"),
        )
    ],
    properties=[
        util.StringParameter(name="extra_make_flags", label="Extra Make Flags", size=30, default=""),
    ]
)
c['schedulers'].append(force_build_scheduler)
<commit_msg>Remove old `.cov` and `.mem` files (#63)<commit_after>julia_package_env = {
    'CFLAGS':None,
    'CPPFLAGS': None,
    'LLVM_CMAKE': util.Property('llvm_cmake', default=None),
}

# Steps to build a `make binary-dist` tarball that should work on just about every linux ever
julia_package_factory = util.BuildFactory()
julia_package_factory.useProgress = True
julia_package_factory.addSteps([
    # Fetch first (allowing failure if no existing clone is present)
    steps.ShellCommand(
        name="git fetch",
        command=["git", "fetch"],
        flunkOnFailure=False
    ),

    # Clone julia
    steps.Git(
        name="Julia checkout",
        repourl=util.Property('repository', default='git://github.com/JuliaLang/julia.git'),
        mode='incremental',
        method='clean',
        submodules=True,
        clobberOnFailure=True,
        progress=True
    ),

    # Ensure gcc and cmake are installed on OSX
    steps.ShellCommand(
        name="Install necessary brew dependencies",
        command=["brew", "install", "gcc", "cmake"],
        doStepIf=is_mac,
        flunkOnFailure=False
    ),

    # make clean first
    steps.ShellCommand(
        name="make cleanall",
        command=["/bin/bash", "-c", util.Interpolate("make %(prop:flags)s %(prop:extra_make_flags)s cleanall")],
        env=julia_package_env,
    ),

    # Windows has a nasty habit of leaving julia-<gitsha> folders lying around....
    steps.ShellCommand(
        name="Clean out temporary windows cruft",
        command=["/bin/bash", "-c", "rm -rf julia-*"],
        doStepIf=is_windows,
        flunkOnFailure=False,
    ),

    # Clear out old .cov and .mem files.  Note that this should be removed once we always start from scratch.
    steps.ShellCommand(
        name="Clear out usr",
        command=["/bin/bash", "-c", "find . \(-name *.jl.*.cov -o -name *.jl.mem \) -print -delete"],
        env=julia_package_env,
    ),

    # Make, forcing some degree of parallelism to cut down compile times
    # Also build `debug` and `release` in parallel, we should have enough RAM for that now
    steps.ShellCommand(
        name="make",
        command=["/bin/bash", "-c", util.Interpolate("make -j3 %(prop:flags)s %(prop:extra_make_flags)s debug release")],
        haltOnFailure = True,
        timeout=3600,
        env=julia_package_env,
    ),

    # Test this build
    steps.ShellCommand(
        name="make testall",
        command=["/bin/bash", "-c", util.Interpolate("make %(prop:flags)s %(prop:extra_make_flags)s testall")],
        haltOnFailure = True,
        timeout=3600,
        env=julia_package_env,
    ),

    # Make win-extras on windows
    steps.ShellCommand(
        name="make win-extras",
        command=["/bin/bash", "-c", util.Interpolate("make %(prop:flags)s %(prop:extra_make_flags)s win-extras")],
        haltOnFailure = True,
        doStepIf=is_windows,
        env=julia_package_env,
    ),

    # Set a bunch of properties that are useful down the line
    steps.SetPropertyFromCommand(
        name="Get commitmessage",
        command=["git", "log", "-1", "--pretty=format:%s%n%cN%n%cE%n%aN%n%aE"],
        extract_fn=parse_git_log,
        want_stderr=False
    ),
    steps.SetPropertyFromCommand(
        name="Get julia version/shortcommit",
        command=make_julia_version_command,
        extract_fn=parse_julia_version,
        want_stderr=False
    ),
    steps.SetPropertyFromCommand(
        name="Get build artifact filename",
        command=["make", "print-JULIA_BINARYDIST_FILENAME"],
        property="artifact_filename",
    ),
    steps.SetPropertyFromCommand(
        name="Munge artifact filename",
        command=munge_artifact_filename,
        property="dummy",
    ),

    # Make binary-dist to package it up
    steps.ShellCommand(
        name="make binary-dist",
        command=["/bin/bash", "-c", util.Interpolate("make %(prop:flags)s %(prop:extra_make_flags)s binary-dist")],
        haltOnFailure = True,
        timeout=3600,
        env=julia_package_env,
    ),

    # On OSX, deal with non-sf/consistent_distnames makefile nonsense by wrapping up all
    # the complexity into `render_make_app`.
    steps.ShellCommand(
        name="make .app",
        command=render_make_app,
        haltOnFailure = True,
        doStepIf=is_mac,
        env=julia_package_env,
    ),

    # Transfer the result to the buildmaster for uploading to AWS
    steps.MasterShellCommand(
        name="mkdir julia_package",
        command=["mkdir", "-p", "/tmp/julia_package"]
    ),

    steps.FileUpload(
        workersrc=util.Interpolate("%(prop:local_filename)s"),
        masterdest=util.Interpolate("/tmp/julia_package/%(prop:upload_filename)s")
    ),

    # Upload it to AWS and cleanup the master!
    steps.MasterShellCommand(
        name="Upload to AWS",
        command=render_upload_command,
        doStepIf=should_upload,
        haltOnFailure=True
    ),
    steps.MasterShellCommand(
        name="Upload to AWS (latest)",
        command=render_latest_upload_command,
        doStepIf=should_upload_latest,
        haltOnFailure=True
    ),

    steps.MasterShellCommand(
        name="Cleanup Master",
        command=["rm", "-f", util.Interpolate("/tmp/julia_package/%(prop:upload_filename)s")],
        doStepIf=should_upload
    ),

    # Trigger a download of this file onto another worker for coverage purposes
    steps.Trigger(schedulerNames=["Julia Coverage Testing"],
        set_properties={
            'url': render_download_url,
            'commitmessage': util.Property('commitmessage'),
            'commitname': util.Property('commitname'),
            'commitemail': util.Property('commitemail'),
            'authorname': util.Property('authorname'),
            'authoremail': util.Property('authoremail'),
            'shortcommit': util.Property('shortcommit'),
        },
        waitForFinish=False,
        doStepIf=should_run_coverage
    )
])

# Build a builder-worker mapping based off of the parent mapping in inventory.py
packager_mapping = {("package_" + k): v for k, v in builder_mapping.iteritems()}

# Add a few builders that don't exist in the typical mapping
packager_mapping["build_ubuntu32"] = "ubuntu16_04-x86"
packager_mapping["build_ubuntu64"] = "ubuntu16_04-x64"
packager_mapping["build_centos64"] = "centos7_3-x64"

packager_scheduler = schedulers.AnyBranchScheduler(
    name="Julia binary packaging",
    change_filter=util.ChangeFilter(
        project=['JuliaLang/julia','staticfloat/julia'],
        # Only build `master` or `release-*`
        branch_fn=lambda b: b == "master" or b.startswith("release-")
    ),
    builderNames=packager_mapping.keys(),
    treeStableTimer=1
)
c['schedulers'].append(packager_scheduler)

for packager, worker in packager_mapping.iteritems():
    c['builders'].append(util.BuilderConfig(
        name=packager,
        workernames=[worker],
        collapseRequests=False,
        tags=["Packaging"],
        factory=julia_package_factory
    ))

# Add a scheduler for building release candidates/triggering builds manually
force_build_scheduler = schedulers.ForceScheduler(
    name="package",
    label="Force Julia build/packaging",
    builderNames=packager_mapping.keys(),
    reason=util.FixedParameter(name="reason", default=""),
    codebases=[
        util.CodebaseParameter(
            "",
            name="",
            branch=util.FixedParameter(name="branch", default=""),
            repository=util.FixedParameter(name="repository", default=""),
            project=util.FixedParameter(name="project", default="Packaging"),
        )
    ],
    properties=[
        util.StringParameter(name="extra_make_flags", label="Extra Make Flags", size=30, default=""),
    ]
)
c['schedulers'].append(force_build_scheduler)
<|endoftext|>


<commit_before># Add our packagers on various platforms
julia_packagers  = ["package_osx64"] + ["package_win32", "package_win64"]
julia_packagers += ["package_linux%s"%(arch) for arch in ["32", "64", "armv7l", "ppc64le", "aarch64"]]

# Also add builders for Ubuntu and Centos builders, that won't upload anything at the end
julia_packagers += ["build_ubuntu32", "build_ubuntu64", "build_centos64"]

def should_build_branch(branch):
    if branch in ["master", "sf/buildbot_testing"]:
        return True
    if branch.startswith("release-"):
        return True
    return False
packager_scheduler = schedulers.AnyBranchScheduler(name="Julia binary packaging", change_filter=util.ChangeFilter(project=['JuliaLang/julia','staticfloat/julia'], branch_fn=should_build_branch), builderNames=julia_packagers, treeStableTimer=1)
c['schedulers'].append(packager_scheduler)

# Helper function to generate the necessary julia invocation to get metadata
# about this build such as major/minor versions
@util.renderer
def make_julia_version_command(props):
    command = [
        "usr/bin/julia",
        "-e",
        "println(\"$(VERSION.major).$(VERSION.minor).$(VERSION.patch)\\n$(Base.GIT_VERSION_INFO.commit[1:10])\")"
    ]

    if is_windows(props):
        command[0] += '.exe'
    return command

# Parse out the full julia version generated by make_julia_version_command's command
def parse_julia_version(return_code, stdout, stderr):
    lines = stdout.split('\n')
    return {
        "majmin": lines[0][:lines[0].rfind('.')],
        "version": lines[0].strip(),
        "shortcommit": lines[1].strip(),
    }

def parse_git_log(return_code, stdout, stderr):
    lines = stdout.split('\n')
    return {
        "commitmessage": lines[0],
        "commitname": lines[1],
        "commitemail": lines[2],
        "authorname": lines[3],
        "authoremail": lines[4],
    }

def gen_local_filename(props_obj):
    props = props_obj.getProperties().asDict()
    props = {k: props[k][0] for k in props}
    # Get the output of the `make print-JULIA_BINARYDIST_FILENAME` step
    artifact = "{artifact_filename}".format(**props).strip()

    # First, see if we got a JULIA_BINARYDIST_FILENAME output
    if artifact[:26] == "JULIA_BINARYDIST_FILENAME=" and len(artifact) > 26:
        return artifact[26:] + "{os_pkg_ext}".format(**props)
    else:
        # If not, use non-sf/consistent_distnames naming
        if is_mac(props_obj):
            return "contrib/mac/app/Julia-{version}-{shortcommit}.{os_pkg_ext}".format(**props)
        elif is_windows(props_obj):
            return "julia-{version}-{tar_arch}.{os_pkg_ext}".format(**props)
        else:
            return "julia-{shortcommit}-Linux-{tar_arch}.{os_pkg_ext}".format(**props)

def gen_upload_filename(props_obj):
    props = props_obj.getProperties().asDict()
    props = {k: props[k][0] for k in props}
    return "julia-{shortcommit}-{os_name}{bits}.{os_pkg_ext}".format(**props)

def gen_upload_path(props_obj):
    up_arch = props_obj.getProperty("up_arch")
    majmin = props_obj.getProperty("majmin")
    upload_fname = props_obj.getProperty("upload_filename")
    os = get_os_name(props_obj)
    return "%s/%s/%s/%s"%(os, up_arch, majmin, upload_fname)

def gen_latest_upload_path(props_obj):
    up_arch = props_obj.getProperty("up_arch")
    upload_filename = props_obj.getProperty("upload_filename")
    if upload_filename[:6] == "julia-":
        upload_filename = "julia-latest-%s"%(upload_filename[6:])
    os = get_os_name(props_obj)
    return "%s/%s/%s"%(os, up_arch, upload_filename)

def gen_download_url(props_obj):
    base = 'https://s3.amazonaws.com/julianightlies/test/bin'
    return '%s/%s'%(base, gen_upload_path(props))

# This is a weird buildbot hack where we really want to parse the output of our
# make command, but we also need access to our properties, which we can't get
# from within an `extract_fn`.  So we save the output from a previous
# SetPropertyFromCommand invocation, then invoke a new command through this
# @util.renderer nonsense.  This function is supposed to return a new command
# to be executed, but it has full access to all our properties, so we do all our
# artifact filename parsing/munging here, then return ["/bin/true"] as the step
# to be executed.
@util.renderer
def munge_artifact_filename(props_obj):
    # Generate our local and upload filenames
    local_filename = gen_local_filename(props_obj)
    upload_filename = gen_upload_filename(props_obj)

    props_obj.setProperty("local_filename", local_filename, "munge_artifact_filename")
    props_obj.setProperty("upload_filename", upload_filename, "munge_artifact_filename")
    return ["/bin/true"]

@util.renderer
def render_upload_command(props):
    upload_path = gen_upload_path(props)
    upload_filename = props.getProperty("upload_filename")
    return ["/bin/bash", "-c", "~/bin/try_thrice ~/bin/aws put --fail --public %s /tmp/julia_package/%s"%(upload_path, upload_filename)]

@util.renderer
def render_latest_upload_command(props):
    latest_upload_path = gen_latest_upload_path(props)
    upload_filename = props.getProperty("upload_filename")
    return ["/bin/bash", "-c", "~/bin/try_thrice ~/bin/aws put --fail --public %s /tmp/julia_package/%s"%(latest_upload_path, upload_filename)]

@util.renderer
def render_download_url(props_obj):
    return gen_download_url(props_obj)

julia_package_env = {
    'CFLAGS':None,
    'CPPFLAGS': None,
    'LLVM_CMAKE': util.Property('llvm_cmake', default=None),
    'JULIA_CPU_CORES': '6',
}

# Steps to build a `make binary-dist` tarball that should work on just about every linux ever
julia_package_factory = util.BuildFactory()
julia_package_factory.useProgress = True
julia_package_factory.addSteps([
    # Fetch first (allowing failure if no existing clone is present)
    steps.ShellCommand(
        name="git fetch",
        command=["git", "fetch"],
        flunkOnFailure=False
    ),

    # Clone julia
    steps.Git(
        name="Julia checkout",
        repourl=util.Property('repository', default='git://github.com/JuliaLang/julia.git'),
        mode='incremental',
        method='clean',
        submodules=True,
        clobberOnFailure=True,
        progress=True
    ),

    # Ensure gcc and cmake are installed on OSX
    steps.ShellCommand(
        name="Install necessary brew dependencies",
        command=["brew", "install", "gcc", "cmake"],
        doStepIf=is_mac,
        flunkOnFailure=False
    ),

    # make clean first
    steps.ShellCommand(
        name="make cleanall",
        command=["/bin/bash", "-c", util.Interpolate("make %(prop:flags)s cleanall")],
        env=julia_package_env,
    ),

    # Make, forcing some degree of parallelism to cut down compile times
    # Also build `debug` and `release` in parallel, we should have enough RAM for that now
    steps.ShellCommand(
        name="make",
        command=["/bin/bash", "-c", util.Interpolate("make -j3 %(prop:flags)s debug release")],
        haltOnFailure = True,
        timeout=3600,
        env=julia_package_env,
    ),

    # Test this build
    steps.ShellCommand(
        name="make testall",
        command=["/bin/bash", "-c", util.Interpolate("make %(prop:flags)s testall")],
        haltOnFailure = True,
        timeout=3600,
        env=julia_package_env,
    ),

    # Make win-extras on windows
    steps.ShellCommand(
        name="make win-extras",
        command=["/bin/bash", "-c", util.Interpolate("make %(prop:flags)s win-extras")],
        haltOnFailure = True,
        doStepIf=is_windows,
        env=julia_package_env,
    ),

    # Make binary-dist to package it up
    steps.ShellCommand(
        name="make binary-dist",
        command=["/bin/bash", "-c", util.Interpolate("make %(prop:flags)s binary-dist")],
        haltOnFailure = True,
        timeout=3600,
        env=julia_package_env,
    ),

    steps.ShellCommand(
        name="make .app",
        command=["/bin/bash", "-c", util.Interpolate("~/unlock_keychain.sh && make %(prop:flags)s app")],
        haltOnFailure = True,
        doStepIf=is_mac,
        env=julia_package_env,
    ),

    # Set a bunch of properties that are useful down the line
    steps.SetPropertyFromCommand(
        name="Get commitmessage",
        command=["git", "log", "-1", "--pretty=format:%s%n%cN%n%cE%n%aN%n%aE"],
        extract_fn=parse_git_log,
        want_stderr=False
    ),
    steps.SetPropertyFromCommand(
        name="Get julia version/shortcommit",
        command=make_julia_version_command,
        extract_fn=parse_julia_version,
        want_stderr=False
    ),
    steps.SetPropertyFromCommand(
        name="Get build artifact filename",
        command=["make", "print-JULIA_BINARYDIST_FILENAME"],
        property="artifact_filename",
    ),
    steps.SetPropertyFromCommand(
        name="Munge artifact filename",
        command=munge_artifact_filename,
        property="dummy",
    ),

    # Transfer the result to the buildmaster for uploading to AWS
    steps.MasterShellCommand(
        name="mkdir julia_package",
        command=["mkdir", "-p", "/tmp/julia_package"]
    ),

    steps.FileUpload(
        workersrc=util.Interpolate("%(prop:local_filename)s"),
        masterdest=util.Interpolate("/tmp/julia_package/%(prop:upload_filename)s")
    ),

    # Upload it to AWS and cleanup the master!
    steps.MasterShellCommand(
        name="Upload to AWS",
        command=render_upload_command,
        doStepIf=should_upload,
        haltOnFailure=True
    ),
    steps.MasterShellCommand(
        name="Upload to AWS (latest)",
        command=render_latest_upload_command,
        doStepIf=should_upload_latest,
        haltOnFailure=True
    ),

    steps.MasterShellCommand(
        name="Cleanup Master",
        command=["rm", "-f", util.Interpolate("/tmp/julia_package/%(prop:upload_filename)s")],
        doStepIf=should_upload
    ),

    # Trigger a download of this file onto another slave for coverage purposes
    steps.Trigger(schedulerNames=["Julia Coverage Testing"],
        set_properties={
            'url': render_download_url,
            'commitmessage': util.Property('commitmessage'),
            'commitname': util.Property('commitname'),
            'commitemail': util.Property('commitemail'),
            'authorname': util.Property('authorname'),
            'authoremail': util.Property('authoremail'),
            'shortcommit': util.Property('shortcommit'),
        },
        waitForFinish=False,
        doStepIf=should_run_coverage
    )
])

# Map each builder to each worker
mapping = {
    "package_osx64": "osx10_10-x64",
    "package_win32": "win6_2-x86",
    "package_win64": "win6_2-x64",
    "package_linux32": "centos5_11-x86",
    "package_linux64": "centos5_11-x64",
    "package_linuxarmv7l": "debian7_11-armv7l",
    "package_linuxppc64le": "debian8_6-ppc64le",
    "package_linuxaarch64": "debian8_6-aarch64",

    # These builders don't get uploaded
    "build_ubuntu32": "ubuntu16_04-x86",
    "build_ubuntu64": "ubuntu16_04-x64",
    "build_centos64": "centos7_3-x64",
}
for packager, slave in mapping.iteritems():
    c['builders'].append(util.BuilderConfig(
        name=packager,
        workernames=[slave],
        tags=["Packaging"],
        factory=julia_package_factory
    ))

# Add a scheduler for building release candidates/triggering builds manually
force_build_scheduler = schedulers.ForceScheduler(
    name="force_julia_package",
    label="Force Julia build/packaging",
    builderNames=julia_packagers,
    reason=util.FixedParameter(name="reason", default=""),
    codebases=[
        util.CodebaseParameter(
            "",
            name="",
            branch=util.FixedParameter(name="branch", default=""),
            repository=util.FixedParameter(name="repository", default=""),
            project=util.FixedParameter(name="project", default="Packaging"),
        )
    ],
    properties=[]
)
c['schedulers'].append(force_build_scheduler)
<commit_msg>`props` -> `props_obj`<commit_after># Add our packagers on various platforms
julia_packagers  = ["package_osx64"] + ["package_win32", "package_win64"]
julia_packagers += ["package_linux%s"%(arch) for arch in ["32", "64", "armv7l", "ppc64le", "aarch64"]]

# Also add builders for Ubuntu and Centos builders, that won't upload anything at the end
julia_packagers += ["build_ubuntu32", "build_ubuntu64", "build_centos64"]

def should_build_branch(branch):
    if branch in ["master", "sf/buildbot_testing"]:
        return True
    if branch.startswith("release-"):
        return True
    return False
packager_scheduler = schedulers.AnyBranchScheduler(name="Julia binary packaging", change_filter=util.ChangeFilter(project=['JuliaLang/julia','staticfloat/julia'], branch_fn=should_build_branch), builderNames=julia_packagers, treeStableTimer=1)
c['schedulers'].append(packager_scheduler)

# Helper function to generate the necessary julia invocation to get metadata
# about this build such as major/minor versions
@util.renderer
def make_julia_version_command(props_obj):
    command = [
        "usr/bin/julia",
        "-e",
        "println(\"$(VERSION.major).$(VERSION.minor).$(VERSION.patch)\\n$(Base.GIT_VERSION_INFO.commit[1:10])\")"
    ]

    if is_windows(props_obj):
        command[0] += '.exe'
    return command

# Parse out the full julia version generated by make_julia_version_command's command
def parse_julia_version(return_code, stdout, stderr):
    lines = stdout.split('\n')
    return {
        "majmin": lines[0][:lines[0].rfind('.')],
        "version": lines[0].strip(),
        "shortcommit": lines[1].strip(),
    }

def parse_git_log(return_code, stdout, stderr):
    lines = stdout.split('\n')
    return {
        "commitmessage": lines[0],
        "commitname": lines[1],
        "commitemail": lines[2],
        "authorname": lines[3],
        "authoremail": lines[4],
    }

def gen_local_filename(props_obj):
    props = props_obj.getProperties().asDict()
    props = {k: props[k][0] for k in props}
    # Get the output of the `make print-JULIA_BINARYDIST_FILENAME` step
    artifact = "{artifact_filename}".format(**props).strip()

    # First, see if we got a JULIA_BINARYDIST_FILENAME output
    if artifact[:26] == "JULIA_BINARYDIST_FILENAME=" and len(artifact) > 26:
        return artifact[26:] + "{os_pkg_ext}".format(**props)
    else:
        # If not, use non-sf/consistent_distnames naming
        if is_mac(props_obj):
            return "contrib/mac/app/Julia-{version}-{shortcommit}.{os_pkg_ext}".format(**props)
        elif is_windows(props_obj):
            return "julia-{version}-{tar_arch}.{os_pkg_ext}".format(**props)
        else:
            return "julia-{shortcommit}-Linux-{tar_arch}.{os_pkg_ext}".format(**props)

def gen_upload_filename(props_obj):
    props = props_obj.getProperties().asDict()
    props = {k: props[k][0] for k in props}
    return "julia-{shortcommit}-{os_name}{bits}.{os_pkg_ext}".format(**props)

def gen_upload_path(props_obj):
    up_arch = props_obj.getProperty("up_arch")
    majmin = props_obj.getProperty("majmin")
    upload_fname = props_obj.getProperty("upload_filename")
    os = get_os_name(props_obj)
    return "%s/%s/%s/%s"%(os, up_arch, majmin, upload_fname)

def gen_latest_upload_path(props_obj):
    up_arch = props_obj.getProperty("up_arch")
    upload_filename = props_obj.getProperty("upload_filename")
    if upload_filename[:6] == "julia-":
        upload_filename = "julia-latest-%s"%(upload_filename[6:])
    os = get_os_name(props_obj)
    return "%s/%s/%s"%(os, up_arch, upload_filename)

def gen_download_url(props_obj):
    base = 'https://s3.amazonaws.com/julianightlies/test/bin'
    return '%s/%s'%(base, gen_upload_path(props_obj))

# This is a weird buildbot hack where we really want to parse the output of our
# make command, but we also need access to our properties, which we can't get
# from within an `extract_fn`.  So we save the output from a previous
# SetPropertyFromCommand invocation, then invoke a new command through this
# @util.renderer nonsense.  This function is supposed to return a new command
# to be executed, but it has full access to all our properties, so we do all our
# artifact filename parsing/munging here, then return ["/bin/true"] as the step
# to be executed.
@util.renderer
def munge_artifact_filename(props_obj):
    # Generate our local and upload filenames
    local_filename = gen_local_filename(props_obj)
    upload_filename = gen_upload_filename(props_obj)

    props_obj.setProperty("local_filename", local_filename, "munge_artifact_filename")
    props_obj.setProperty("upload_filename", upload_filename, "munge_artifact_filename")
    return ["/bin/true"]

@util.renderer
def render_upload_command(props_obj):
    upload_path = gen_upload_path(props_obj)
    upload_filename = props_obj.getProperty("upload_filename")
    return ["/bin/bash", "-c", "~/bin/try_thrice ~/bin/aws put --fail --public %s /tmp/julia_package/%s"%(upload_path, upload_filename)]

@util.renderer
def render_latest_upload_command(props_obj):
    latest_upload_path = gen_latest_upload_path(props_obj)
    upload_filename = props_obj.getProperty("upload_filename")
    return ["/bin/bash", "-c", "~/bin/try_thrice ~/bin/aws put --fail --public %s /tmp/julia_package/%s"%(latest_upload_path, upload_filename)]

@util.renderer
def render_download_url(props_obj):
    return gen_download_url(props_obj)

julia_package_env = {
    'CFLAGS':None,
    'CPPFLAGS': None,
    'LLVM_CMAKE': util.Property('llvm_cmake', default=None),
    'JULIA_CPU_CORES': '6',
}

# Steps to build a `make binary-dist` tarball that should work on just about every linux ever
julia_package_factory = util.BuildFactory()
julia_package_factory.useProgress = True
julia_package_factory.addSteps([
    # Fetch first (allowing failure if no existing clone is present)
    steps.ShellCommand(
        name="git fetch",
        command=["git", "fetch"],
        flunkOnFailure=False
    ),

    # Clone julia
    steps.Git(
        name="Julia checkout",
        repourl=util.Property('repository', default='git://github.com/JuliaLang/julia.git'),
        mode='incremental',
        method='clean',
        submodules=True,
        clobberOnFailure=True,
        progress=True
    ),

    # Ensure gcc and cmake are installed on OSX
    steps.ShellCommand(
        name="Install necessary brew dependencies",
        command=["brew", "install", "gcc", "cmake"],
        doStepIf=is_mac,
        flunkOnFailure=False
    ),

    # make clean first
    steps.ShellCommand(
        name="make cleanall",
        command=["/bin/bash", "-c", util.Interpolate("make %(prop:flags)s cleanall")],
        env=julia_package_env,
    ),

    # Make, forcing some degree of parallelism to cut down compile times
    # Also build `debug` and `release` in parallel, we should have enough RAM for that now
    steps.ShellCommand(
        name="make",
        command=["/bin/bash", "-c", util.Interpolate("make -j3 %(prop:flags)s debug release")],
        haltOnFailure = True,
        timeout=3600,
        env=julia_package_env,
    ),

    # Test this build
    steps.ShellCommand(
        name="make testall",
        command=["/bin/bash", "-c", util.Interpolate("make %(prop:flags)s testall")],
        haltOnFailure = True,
        timeout=3600,
        env=julia_package_env,
    ),

    # Make win-extras on windows
    steps.ShellCommand(
        name="make win-extras",
        command=["/bin/bash", "-c", util.Interpolate("make %(prop:flags)s win-extras")],
        haltOnFailure = True,
        doStepIf=is_windows,
        env=julia_package_env,
    ),

    # Make binary-dist to package it up
    steps.ShellCommand(
        name="make binary-dist",
        command=["/bin/bash", "-c", util.Interpolate("make %(prop:flags)s binary-dist")],
        haltOnFailure = True,
        timeout=3600,
        env=julia_package_env,
    ),

    steps.ShellCommand(
        name="make .app",
        command=["/bin/bash", "-c", util.Interpolate("~/unlock_keychain.sh && make %(prop:flags)s app")],
        haltOnFailure = True,
        doStepIf=is_mac,
        env=julia_package_env,
    ),

    # Set a bunch of properties that are useful down the line
    steps.SetPropertyFromCommand(
        name="Get commitmessage",
        command=["git", "log", "-1", "--pretty=format:%s%n%cN%n%cE%n%aN%n%aE"],
        extract_fn=parse_git_log,
        want_stderr=False
    ),
    steps.SetPropertyFromCommand(
        name="Get julia version/shortcommit",
        command=make_julia_version_command,
        extract_fn=parse_julia_version,
        want_stderr=False
    ),
    steps.SetPropertyFromCommand(
        name="Get build artifact filename",
        command=["make", "print-JULIA_BINARYDIST_FILENAME"],
        property="artifact_filename",
    ),
    steps.SetPropertyFromCommand(
        name="Munge artifact filename",
        command=munge_artifact_filename,
        property="dummy",
    ),

    # Transfer the result to the buildmaster for uploading to AWS
    steps.MasterShellCommand(
        name="mkdir julia_package",
        command=["mkdir", "-p", "/tmp/julia_package"]
    ),

    steps.FileUpload(
        workersrc=util.Interpolate("%(prop:local_filename)s"),
        masterdest=util.Interpolate("/tmp/julia_package/%(prop:upload_filename)s")
    ),

    # Upload it to AWS and cleanup the master!
    steps.MasterShellCommand(
        name="Upload to AWS",
        command=render_upload_command,
        doStepIf=should_upload,
        haltOnFailure=True
    ),
    steps.MasterShellCommand(
        name="Upload to AWS (latest)",
        command=render_latest_upload_command,
        doStepIf=should_upload_latest,
        haltOnFailure=True
    ),

    steps.MasterShellCommand(
        name="Cleanup Master",
        command=["rm", "-f", util.Interpolate("/tmp/julia_package/%(prop:upload_filename)s")],
        doStepIf=should_upload
    ),

    # Trigger a download of this file onto another slave for coverage purposes
    steps.Trigger(schedulerNames=["Julia Coverage Testing"],
        set_properties={
            'url': render_download_url,
            'commitmessage': util.Property('commitmessage'),
            'commitname': util.Property('commitname'),
            'commitemail': util.Property('commitemail'),
            'authorname': util.Property('authorname'),
            'authoremail': util.Property('authoremail'),
            'shortcommit': util.Property('shortcommit'),
        },
        waitForFinish=False,
        doStepIf=should_run_coverage
    )
])

# Map each builder to each worker
mapping = {
    "package_osx64": "osx10_10-x64",
    "package_win32": "win6_2-x86",
    "package_win64": "win6_2-x64",
    "package_linux32": "centos5_11-x86",
    "package_linux64": "centos5_11-x64",
    "package_linuxarmv7l": "debian7_11-armv7l",
    "package_linuxppc64le": "debian8_6-ppc64le",
    "package_linuxaarch64": "debian8_6-aarch64",

    # These builders don't get uploaded
    "build_ubuntu32": "ubuntu16_04-x86",
    "build_ubuntu64": "ubuntu16_04-x64",
    "build_centos64": "centos7_3-x64",
}
for packager, slave in mapping.iteritems():
    c['builders'].append(util.BuilderConfig(
        name=packager,
        workernames=[slave],
        tags=["Packaging"],
        factory=julia_package_factory
    ))

# Add a scheduler for building release candidates/triggering builds manually
force_build_scheduler = schedulers.ForceScheduler(
    name="force_julia_package",
    label="Force Julia build/packaging",
    builderNames=julia_packagers,
    reason=util.FixedParameter(name="reason", default=""),
    codebases=[
        util.CodebaseParameter(
            "",
            name="",
            branch=util.FixedParameter(name="branch", default=""),
            repository=util.FixedParameter(name="repository", default=""),
            project=util.FixedParameter(name="project", default="Packaging"),
        )
    ],
    properties=[]
)
c['schedulers'].append(force_build_scheduler)
<|endoftext|>


<commit_before>from __future__ import unicode_literals
from django.db import models
from django.contrib.auth.models import User
from leagues.models import League

class Match(models.Model):
	COUNTRY_CHOICES = (
		('AL', "Albania"),
		('AT', "Austria"),
		('BE', "Belgium"),
		('HR', "Croatia"),
		('CZ', "Czech"),
		('EN', "England"),
		('FR', "France"),
		('DE', "Germany"),
		('HU', "Hungary"),
		('IS', "Iceland"),
		('IT', "Italy"),
		('NI', "Northern Ireland"),
		('PL', "Poland"),
		('PT', "Portugal"),
		('RI', "Republic of Ireland"),
		('RO', "Romania"),
		('RU', "Russia"),
		('SK', "Slovakia"),
		('SP', "Spain"),
		('SE', "Sweden"),
		('SW', "Switzerland"),
		('TK', "Turkey"),
		('UK', "Ukraine"),
		('WA', "Wales"),
	)
	home_team = models.CharField(max_length = 2, choices = COUNTRY_CHOICES)
	away_team = models.CharField(max_length = 2, choices = COUNTRY_CHOICES)
	home_score = models.IntegerField(default = 0)
	away_score = models.IntegerField(default = 0)
	start_date = models.DateTimeField()
	is_finished = models.BooleanField(default = False)

	def __str__(self):
		return self.get_home_team_display() + "-" + self.get_away_team_display() + ": " + str(self.home_score) + "-" + str(self.away_score) + "___" + str(self.start_date)

class Tip(models.Model):
	user = models.ForeignKey(User, models.CASCADE)
	league = models.ForeignKey(League, models.CASCADE, null = True)
	match = models.ForeignKey(Match, models.CASCADE)
	home_score_tip = models.IntegerField()
	away_score_tip = models.IntegerField()

	def __str__(self):
		return self.user.username + " - " + self.league.league_name + ": " + self.match.home_team + " - " + self.match.away_team + ": " + str(self.home_score_tip) + " - " + str(self.away_score_tip)

<commit_msg>Add group to match<commit_after>from __future__ import unicode_literals
from django.db import models
from django.contrib.auth.models import User
from leagues.models import League

class Match(models.Model):
	COUNTRY_CHOICES = (
		('AL', "Albania"),
		('AT', "Austria"),
		('BE', "Belgium"),
		('HR', "Croatia"),
		('CZ', "Czech"),
		('EN', "England"),
		('FR', "France"),
		('DE', "Germany"),
		('HU', "Hungary"),
		('IS', "Iceland"),
		('IT', "Italy"),
		('NI', "Northern Ireland"),
		('PL', "Poland"),
		('PT', "Portugal"),
		('RI', "Republic of Ireland"),
		('RO', "Romania"),
		('RU', "Russia"),
		('SK', "Slovakia"),
		('SP', "Spain"),
		('SE', "Sweden"),
		('SW', "Switzerland"),
		('TK', "Turkey"),
		('UK', "Ukraine"),
		('WA', "Wales"),
	)
	home_team = models.CharField(max_length = 2, choices = COUNTRY_CHOICES)
	away_team = models.CharField(max_length = 2, choices = COUNTRY_CHOICES)
	home_score = models.IntegerField(default = 0)
	away_score = models.IntegerField(default = 0)
	start_date = models.DateTimeField()
	is_finished = models.BooleanField(default = False)
	group = models.CharField(max_length = 20, null = True)

	def __str__(self):
		return self.get_home_team_display() + "-" + self.get_away_team_display() + ": " + str(self.home_score) + "-" + str(self.away_score) + "___" + str(self.start_date)

class Tip(models.Model):
	user = models.ForeignKey(User, models.CASCADE)
	league = models.ForeignKey(League, models.CASCADE, null = True)
	match = models.ForeignKey(Match, models.CASCADE)
	home_score_tip = models.IntegerField()
	away_score_tip = models.IntegerField()

	def __str__(self):
		return self.user.username + " - " + self.league.league_name + ": " + self.match.home_team + " - " + self.match.away_team + ": " + str(self.home_score_tip) + " - " + str(self.away_score_tip)

<|endoftext|>