# Path: makeapp/appconfig.py
# class Config(metaclass=ConfigMeta):
#     """Base for application template configuration."""
# 
#     parent_template: List[str] = None
#     """Parent template names."""
# 
#     cleanup: List[str] = None
#     """Paths to cleanup after rollout."""
# 
#     def __init__(self, app_template: 'AppTemplate'):
#         """
# 
#         :param app_template:
# 
#         """
#         self.app_template = app_template
#         self.logger = app_template.maker.logger
# 
#         settings = {}
# 
#         for key, val in self.__class__.__dict__.items():
# 
#             if isinstance(val, ConfigSetting):
#                 settings[f'{app_template.name}_{key}'] = val
# 
#         self.settings = settings
# 
#     def hook_configure(self):
#         """Executed on rollout configuration."""
# 
#         settings_conf = self.settings
# 
#         if not settings_conf:
#             return
# 
#         app_template = self.app_template
#         settings_current = app_template.maker.settings
#         settings_gathered = {}
#         advertise_template = True
# 
#         for setting_name, settings_obj in settings_conf.items():
# 
#             current_value = settings_current.get(setting_name)
# 
#             if current_value is None:
# 
#                 if advertise_template:
#                     click.secho(
#                         f"Gathering settings for '{app_template.name}' application template ...",
#                         fg='blue'
#                     )
#                     advertise_template = False
# 
#                 current_value = click.prompt(
#                     f'{settings_obj.title} ({setting_name})',
#                     default=settings_obj.default,
#                     type=settings_obj.type,
#                 )
# 
#                 settings_gathered[setting_name] = current_value
# 
#         app_template.maker.update_settings(settings_gathered)
# 
#     def print_banner(self, text: str):
#         """Prints out a banner with the given text.
# 
#         :param text:
# 
#         """
#         max_line_len = max(map(len, text.splitlines()))
#         text = text + '\n' + '=' * max_line_len + '\n'
# 
#         self.logger.warning(text)
#         sleep(1)
# 
#     def hook_rollout_init(self):
#         """Executed on skeleton rollout initialization."""
# 
#     def hook_rollout_pre(self):
#         """Executed before application skeleton rollout."""
# 
#     def hook_rollout_post(self):
#         """Executed after application skeleton rollout."""
#         cleanup = self.cleanup or []
# 
#         for path in cleanup:
#             path = Path(path).absolute()
#             self.logger.info(f'Cleanup {path} ...')
#             rmtree(path, ignore_errors=True)
# 
# Path: makeapp/exceptions.py
# class AppMakerException(MakeappException):
#     """Basic AppMaker related exception."""


import importlib.util
import os
from typing import Type, Dict, Tuple
from .appconfig import Config
from .exceptions import AppMakerException
    from .appmaker import AppMaker
        self.parent = parent
        self.config = self._read_config()
        self._process_config()

    def __str__(self):
        return f'{self.name}: {self.path}'

    @property
    def is_default(self):
        """Whether current template is default (root)."""
        return self.name == self.maker.template_default_name

    def _read_config(self) -> Config:
        """Reads template's config.

        If not found, dummy config object is returned.

        """
        module_fake_name = f'makeapp.config.{self.name}'

        config_path = os.path.join(self.path, self.config_filename)

        if os.path.exists(config_path):

            spec = importlib.util.spec_from_file_location(module_fake_name, config_path)
            module = importlib.util.module_from_spec(spec)
            spec.loader.exec_module(module)

            config: Type[Config] = getattr(module, self.config_attr, None)


# Path: makeapp/appconfig.py
# class Config(metaclass=ConfigMeta):
#     """Base for application template configuration."""
# 
#     parent_template: List[str] = None
#     """Parent template names."""
# 
#     cleanup: List[str] = None
#     """Paths to cleanup after rollout."""
# 
#     def __init__(self, app_template: 'AppTemplate'):
#         """
# 
#         :param app_template:
# 
#         """
#         self.app_template = app_template
#         self.logger = app_template.maker.logger
# 
#         settings = {}
# 
#         for key, val in self.__class__.__dict__.items():
# 
#             if isinstance(val, ConfigSetting):
#                 settings[f'{app_template.name}_{key}'] = val
# 
#         self.settings = settings
# 
#     def hook_configure(self):
#         """Executed on rollout configuration."""
# 
#         settings_conf = self.settings
# 
#         if not settings_conf:
#             return
# 
#         app_template = self.app_template
#         settings_current = app_template.maker.settings
#         settings_gathered = {}
#         advertise_template = True
# 
#         for setting_name, settings_obj in settings_conf.items():
# 
#             current_value = settings_current.get(setting_name)
# 
#             if current_value is None:
# 
#                 if advertise_template:
#                     click.secho(
#                         f"Gathering settings for '{app_template.name}' application template ...",
#                         fg='blue'
#                     )
#                     advertise_template = False
# 
#                 current_value = click.prompt(
#                     f'{settings_obj.title} ({setting_name})',
#                     default=settings_obj.default,
#                     type=settings_obj.type,
#                 )
# 
#                 settings_gathered[setting_name] = current_value
# 
#         app_template.maker.update_settings(settings_gathered)
# 
#     def print_banner(self, text: str):
#         """Prints out a banner with the given text.
# 
#         :param text:
# 
#         """
#         max_line_len = max(map(len, text.splitlines()))
#         text = text + '\n' + '=' * max_line_len + '\n'
# 
#         self.logger.warning(text)
#         sleep(1)
# 
#     def hook_rollout_init(self):
#         """Executed on skeleton rollout initialization."""
# 
#     def hook_rollout_pre(self):
#         """Executed before application skeleton rollout."""
# 
#     def hook_rollout_post(self):
#         """Executed after application skeleton rollout."""
#         cleanup = self.cleanup or []
# 
#         for path in cleanup:
#             path = Path(path).absolute()
#             self.logger.info(f'Cleanup {path} ...')
#             rmtree(path, ignore_errors=True)
# 
# Path: makeapp/exceptions.py
# class AppMakerException(MakeappException):
#     """Basic AppMaker related exception."""


# Path: makeapp/apptemplate.py
import importlib.util
import os
from typing import Type, Dict, Tuple
from .appconfig import Config
from .exceptions import AppMakerException
    from .appmaker import AppMaker

        self.parent = parent
        self.config = self._read_config()
        self._process_config()

    def __str__(self):
        return f'{self.name}: {self.path}'

    @property
    def is_default(self):
        """Whether current template is default (root)."""
        return self.name == self.maker.template_default_name

    def _read_config(self) -> Config:
        """Reads template's config.

        If not found, dummy config object is returned.

        """
        module_fake_name = f'makeapp.config.{self.name}'

        config_path = os.path.join(self.path, self.config_filename)

        if os.path.exists(config_path):

            spec = importlib.util.spec_from_file_location(module_fake_name, config_path)
            module = importlib.util.module_from_spec(spec)
            spec.loader.exec_module(module)

            config: Type[Config] = getattr(module, self.config_attr, None)


            if not issubclass(config, Config):