Exemple #1
0
def list_plugins():
    entry_point_names = [
        entry_point_name for entry_point_name in pkg_resources.get_entry_map(
            'cylc-flow').keys() if entry_point_name.startswith('cylc.')
    ]

    entry_point_groups = {
        entry_point_name: [
            entry_point for entry_point in iter_entry_points(entry_point_name)
            if not entry_point.module_name.startswith('cylc.flow')
        ]
        for entry_point_name in entry_point_names
    }

    dists = {
        entry_point.dist
        for entry_points in entry_point_groups.values()
        for entry_point in entry_points
    }

    lines = []
    if dists:
        lines.append('\nPlugins:')
        maxlen1 = max(len(dist.project_name) for dist in dists) + 2
        maxlen2 = max(len(dist.version) for dist in dists) + 2
        for dist in dists:
            lines.append(f'  {dist.project_name.ljust(maxlen1)}'
                         f' {dist.version.ljust(maxlen2)}'
                         f' {dist.module_path}')

        lines.append('\nEntry Points:')
        for entry_point_name, entry_points in entry_point_groups.items():
            if entry_points:
                lines.append(f'  {entry_point_name}:')
                for entry_point in entry_points:
                    lines.append(f'    {entry_point}')

    return '\n'.join(lines)
Exemple #2
0
def load(config, additional_plugins=None):
    additional_plugins = additional_plugins or []
    entry_points = {
        entry_point.name: entry_point
        for entry_point in iter_entry_points('cylc.main_loop')
    }
    plugins = {'state': {}, 'timings': {}}
    for plugin_name in config['plugins'] + additional_plugins:
        # get plugin
        try:
            module_name = entry_points[plugin_name.replace(' ', '_')]
        except KeyError:
            raise UserInputError(
                f'No main-loop plugin: "{plugin_name}"\n' +
                '    Available plugins:\n' +
                indent('\n'.join(sorted(entry_points)), '        '))
        # load plugin
        try:
            module = module_name.load()
        except Exception:
            raise CylcError(f'Could not load plugin: "{plugin_name}"')
        # load coroutines
        log = []
        for coro_name, coro in ((coro_name, coro)
                                for coro_name, coro in getmembers(module)
                                if isfunction(coro)
                                if hasattr(coro, 'main_loop')):
            log.append(coro_name)
            plugins.setdefault(coro.main_loop,
                               {})[(plugin_name, coro_name)] = coro
            plugins['timings'][(plugin_name, coro_name)] = deque(maxlen=1)
        LOG.debug('Loaded main loop plugin "%s": %s', plugin_name + '\n',
                  '\n'.join((f'* {x}' for x in log)))
        # set the initial state of the plugin
        plugins['state'][plugin_name] = {}
    # make a note of the config here for ease of reference
    plugins['config'] = config
    return plugins
Exemple #3
0
      workflow//*:running             # All running cycles in workflow
      workflow//cycle/*:running       # All running tasks in workflow//cycle
      workflow//cycle/task/*:running  # All running jobs in
                                      # workflow//cycle/task
'''

# because this command is not served from behind cli_function like the
# other cylc commands we have to manually patch in colour support
USAGE = format_shell_examples(USAGE)
USAGE = cparse(USAGE)

# all sub-commands
# {name: entry_point}
COMMANDS: dict = {
    entry_point.name: entry_point
    for entry_point in iter_entry_points('cylc.command')
}

# aliases for sub-commands
# {alias_name: command_name}
ALIASES = {
    'bcast': 'broadcast',
    'compare': 'diff',
    'cyclepoint': 'cycle-point',
    'cycletime': 'cycle-point',
    'datetime': 'cycle-point',
    'external-trigger': 'ext-trigger',
    'get-contact': 'get-workflow-contact',
    'get-cylc-version': 'get-workflow-version',
    'log': 'cat-log',
    'ls': 'list',
def process_plugins(fpath, opts):
    """Run a Cylc pre-configuration plugin.

    Plugins should return a dictionary containing:
        'env': A dictionary of environment variables.
        'template_variables': A dictionary of template variables.
        'templating_detected': Where the plugin identifies a templating
            language this is specified here. Expected values are ``jinja2``
            or ``empy``.

    args:
        fpath: Directory where the plugin will look for a config.
        opts: Command line options to be passed to the plugin.

    Returns: Dictionary in the form:
        extra_vars = {
            'env': {},
            'template_variables': {},
            'templating_detected': None
        }
    """
    # Set out blank dictionary for return:
    extra_vars = {
        'env': {},
        'template_variables': {},
        'templating_detected': None
    }

    # Run entry point pre_configure items, trying to merge values with each.:
    for entry_point in iter_entry_points(
        'cylc.pre_configure'
    ):
        try:
            # If you want it to work on sourcedirs you need to get the options
            # to here.
            plugin_result = entry_point.resolve()(
                srcdir=fpath, opts=opts
            )
        except Exception as exc:
            # NOTE: except Exception (purposefully vague)
            # this is to separate plugin from core Cylc errors
            raise PluginError(
                'cylc.pre_configure',
                entry_point.name,
                exc
            ) from None
        for section in ['env', 'template_variables']:
            if section in plugin_result and plugin_result[section] is not None:
                # Raise error if multiple plugins try to update the same keys.
                section_update = plugin_result.get(section, {})
                keys_collision = (
                    extra_vars[section].keys() & section_update.keys()
                )
                if keys_collision:
                    raise ParsecError(
                        f"{entry_point.name} is trying to alter "
                        f"[{section}]{', '.join(sorted(keys_collision))}."
                    )
                extra_vars[section].update(section_update)

        if (
            'templating_detected' in plugin_result and
            plugin_result['templating_detected'] is not None and
            extra_vars['templating_detected'] is not None and
            extra_vars['templating_detected'] !=
                plugin_result['templating_detected']
        ):
            # Don't allow subsequent plugins with different templating_detected
            raise ParsecError(
                "Can't merge templating languages "
                f"{extra_vars['templating_detected']} and "
                f"{plugin_result['templating_detected']}"
            )
        elif(
            'templating_detected' in plugin_result and
            plugin_result['templating_detected'] is not None
        ):
            extra_vars['templating_detected'] = plugin_result[
                'templating_detected'
            ]

    return extra_vars