Exemple #1
0
def test_retrieving_triggers_from_action_block():
    """All trigger instructions should be returned."""
    action_block_dict = {
        'trigger': [
            {
                'block': 'on_startup'
            },
            {
                'block': 'on_modified',
                'path': 'test.template'
            },
        ],
    }
    action_block = ActionBlock(
        action_block=action_block_dict,
        directory=Path('/'),
        replacer=lambda x: x,
        context_store=Context(),
    )

    startup_trigger, on_modified_trigger = action_block.triggers()

    assert startup_trigger.block == 'on_startup'
    assert on_modified_trigger.block == 'on_modified'
    assert on_modified_trigger.specified_path == 'test.template'
    assert on_modified_trigger.relative_path == Path('test.template')
    assert on_modified_trigger.absolute_path == Path('/test.template')
Exemple #2
0
def test_executing_action_block_with_one_action(
    global_modules_config,
    test_config_directory,
    tmpdir,
):
    """Action block behaviour with only one action specified."""
    temp_dir = Path(tmpdir)
    touched = temp_dir / 'touched.tmp'

    action_block_dict = {
        'run': [{
            'shell': 'touch ' + str(touched)
        }],
    }

    action_block = ActionBlock(
        action_block=action_block_dict,
        directory=test_config_directory,
        replacer=lambda x: x,
        context_store=Context(),
        global_modules_config=global_modules_config,
        module_name='test',
    )

    action_block.execute(default_timeout=1)
    assert touched.is_file()
Exemple #3
0
def test_executing_several_action_blocks(test_config_directory, tmpdir):
    """Invoking execute() should execute all actions."""
    temp_dir = Path(tmpdir)
    target = temp_dir / 'target.tmp'
    touched = temp_dir / 'touched.tmp'

    action_block_dict = {
        'import_context': {
            'from_path': 'context/mercedes.yml'
        },
        'compile': [{
            'content': 'templates/a_car.template',
            'target': str(target),
        }],
        'run': {
            'shell': 'touch ' + str(touched)
        },
        'trigger': {
            'block': 'on_startup'
        },
    }
    context_store = Context()

    action_block = ActionBlock(
        action_block=action_block_dict,
        directory=test_config_directory,
        replacer=lambda x: x,
        context_store=context_store,
    )

    action_block.execute(default_timeout=1)
    assert context_store == {'car': {'manufacturer': 'Mercedes'}}
    assert target.read_text() == 'My car is a Mercedes'
    assert touched.is_file()
Exemple #4
0
def test_null_object_pattern():
    """An empty action block should have no behaviour."""
    action_block = ActionBlock(
        action_block={},
        directory=Path('/'),
        replacer=lambda x: x,
        context_store=Context(),
    )
    action_block.execute(default_timeout=1)
Exemple #5
0
def test_retrieving_triggers_from_action_block_without_triggers():
    """Action block with no triggers should return empty tuple."""
    action_block = ActionBlock(
        action_block={},
        directory=Path('/'),
        replacer=lambda x: x,
        context_store=Context(),
    )

    assert action_block.triggers() == tuple()
Exemple #6
0
def test_null_object_pattern(global_modules_config):
    """An empty action block should have no behaviour."""
    action_block = ActionBlock(
        action_block={},
        directory=Path('/'),
        replacer=lambda x: x,
        context_store=Context(),
        global_modules_config=global_modules_config,
        module_name='test',
    )
    action_block.execute(default_timeout=1)
Exemple #7
0
    def _action_block_factory(
            import_context={},
            compile={},
            copy={},
            run={},
            stow={},
            symlink={},
            directory=test_config_directory,
            replacer=lambda x: x,
            context_store=Context(),
    ):
        """Return module with given parameters."""
        config = {
            'import_context': import_context,
            'compile': compile,
            'copy': copy,
            'run': run,
            'stow': stow,
            'symlink': symlink,
        }

        return ActionBlock(
            action_block=config,
            directory=directory,
            replacer=replacer,
            context_store=context_store,
        )
Exemple #8
0
def test_retrieving_all_compiled_templates(template_directory, tmpdir):
    """All earlier compilations should be retrievable."""
    template1 = template_directory / 'empty.template'
    template2 = template_directory / 'no_context.template'

    temp_dir = Path(tmpdir)
    target1 = temp_dir / 'target1.tmp'
    target2 = temp_dir / 'target2.tmp'
    target3 = temp_dir / 'target3.tmp'

    action_block_dict = {
        'compile': [
            {'source': str(template1), 'target': str(target1)},
            {'source': str(template1), 'target': str(target2)},
            {'source': str(template2), 'target': str(target3)},
        ],
    }

    action_block = ActionBlock(
        action_block=action_block_dict,
        directory=template_directory,
        replacer=lambda x: x,
        context_store={},
    )

    assert action_block.performed_compilations() == {}

    action_block.execute(default_timeout=1)
    assert action_block.performed_compilations() == {
        template1: {target1, target2},
        template2: {target3},
    }
Exemple #9
0
    def __init__(
        self,
        name: str,
        module_config: ModuleConfigDict,
        module_directory: Path,
        replacer: Callable[[str], str] = lambda string: string,
        context_store: Context = Context(),
        global_modules_config: Optional[GlobalModulesConfig] = None,
        dry_run: bool = False,
    ) -> None:
        """
        Initialize Module object with a section from a config dictionary.

        Section name must be [module/*], where * is the module name.
        In addition, the enabled option must be set to "true", or not set at
        all.

        module_config example:
        {'name':
            'enabled': True,
            'event_listener': {'type': 'weekday'},
            'on_startup': {'run': ['echo weekday is {event}']},
        }
        """
        self.name = name

        # The source directory for the module, determining how to interpret
        # relative paths in the module config
        self.directory = module_directory

        # All user string options should be processed by the replacer
        self.replace = replacer

        # Use static event_listener if no event_listener is specified
        self.event_listener: EventListener = \
            event_listener_factory(
                module_config.get(
                    'event_listener',
                    {'type': 'static'},
                ),
            )

        self.context_store = context_store

        # Move root actions to 'on_startup' block
        module_config = self.prepare_on_startup_block(
            module_name=self.name,
            module_config=module_config,
        )

        # Create action block object for each available action block type
        action_blocks: ModuleActionBlocks = {'on_modified': {}}  # type: ignore
        params = {
            'module_name': self.name,
            'directory': self.directory,
            'replacer': self.interpolate_string,
            'context_store': self.context_store,
            'global_modules_config': global_modules_config,
        }

        # Create special case setup action block, it removes any action already
        # performed.
        action_blocks['on_setup'] = SetupActionBlock(
            action_block=module_config.get('on_setup', {}),
            **params,
        )

        # Create normal action blocks
        for block_name in ('on_startup', 'on_event', 'on_exit'):
            action_blocks[block_name] = ActionBlock(  # type: ignore
                action_block=module_config.get(  # type: ignore
                    block_name,
                    {},
                ),
                **params,
            )

        for path_string, action_block_dict in module_config.get(
            'on_modified',
            {},
        ).items():
            modified_path = expand_path(
                path=Path(path_string),
                config_directory=self.directory,
            )
            action_blocks['on_modified'][modified_path] = \
                ActionBlock(
                    action_block=action_block_dict,
                    **params,
            )

        self.action_blocks = action_blocks

        requirements = cast_to_list(module_config.get('requires', []))
        self.depends_on = tuple(  # type: ignore
            requirement['module']
            for requirement
            in requirements
            if 'module' in requirement
        )
Exemple #10
0
    def __init__(
        self,
        module_config: ModuleConfig,
        module_directory: Path,
        replacer: Callable[[str], str] = lambda string: string,
        context_store: compiler.Context = {},
    ) -> None:
        """
        Initialize Module object with a section from a config dictionary.

        Section name must be [module/*], where * is the module name.
        In addition, the enabled option must be set to "true", or not set at
        all.

        module_config example:
        {'module/name':
            'enabled': True,
            'event_listener': {'type': 'weekday'},
            'on_startup': {'run': ['echo weekday is {event}']},
        }
        """
        # Can only initialize one module at a time
        assert len(module_config) == 1

        section: str = next(iter(module_config.keys()))
        self.name: str = section[7:]

        # The source directory for the module, determining how to interpret
        # relative paths in the module config
        self.directory = module_directory

        # All user string options should be processed by the replacer
        self.replace = replacer

        # Extract configuration content
        module_config_content: ModuleConfigDict = module_config[section]

        # Use static event_listener if no event_listener is specified
        self.event_listener: EventListener = \
            event_listener_factory(
                module_config_content.get(
                    'event_listener',
                    {'type': 'static'},
                ),
            )

        self.context_store = context_store

        # Create action block object for each available action block type
        action_blocks: ModuleActionBlocks = {'on_modified': {}}  # type: ignore
        for block_name in ('on_startup', 'on_event', 'on_exit'):
            action_blocks[block_name] = ActionBlock(  # type: ignore
                action_block=module_config_content.get(  # type: ignore
                    block_name,
                    {},
                ),
                directory=self.directory,
                replacer=self.interpolate_string,
                context_store=self.context_store,
            )
        for path_string, action_block_dict \
                in module_config_content.get('on_modified', {}).items():
            modified_path = expand_path(
                path=Path(path_string),
                config_directory=self.directory,
            )
            action_blocks['on_modified'][modified_path] = \
                ActionBlock(
                    action_block=action_block_dict,
                    directory=self.directory,
                    replacer=self.interpolate_string,
                    context_store=self.context_store,
            )
        self.action_blocks = action_blocks