Source code for flexlate_dev.project_ops

from pathlib import Path
from typing import Optional

import jinja2
from flexlate import Flexlate
from flexlate import exc as flexlate_exc
from flexlate.config import FlexlateConfig
from flexlate.template_data import TemplateData
from git import Repo

from flexlate_dev.config import (
    DEFAULT_PROJECT_NAME,
    FlexlateDevConfig,
    FullRunConfiguration,
)
from flexlate_dev.dirutils import directory_has_files_or_directories
from flexlate_dev.ext_flexlate import get_template_path_from_project_path
from flexlate_dev.gitutils import stage_and_commit_all
from flexlate_dev.render import create_jinja_environment
from flexlate_dev.styles import ACTION_REQUIRED_STYLE, INFO_STYLE, print_styled
from flexlate_dev.user_runner import CommandContext, RunnerHookType, run_user_hook

fxt = Flexlate()


[docs]def update_or_initialize_project_get_folder( template_path: Path, out_root: Path, config: FlexlateDevConfig, run_config: FullRunConfiguration, no_input: bool = False, data: Optional[TemplateData] = None, save: bool = False, abort_on_conflict: bool = False, auto_commit: bool = True, known_folder_name: Optional[str] = None, default_folder_name: str = DEFAULT_PROJECT_NAME, ) -> str: # TODO: Allow passing options to Jinja environment jinja_env = create_jinja_environment() def init_project() -> str: return initialize_project_get_folder( template_path, out_root, config, run_config, jinja_env, no_input=no_input, data=data, save=save, default_folder_name=default_folder_name, ) folder = known_folder_name or ( run_config.data.use_folder_name if run_config.data else None ) if folder is None: print_styled( "No folder name in the config, defaulting to initializing the project", INFO_STYLE, ) return init_project() out_path = out_root / folder if not out_path.exists(): out_path.mkdir() context = CommandContext.create( template_root=template_path, out_root=out_root, no_input=no_input, save=save, abort_on_conflict=abort_on_conflict, auto_commit=auto_commit, ) run_user_hook( RunnerHookType.PRE_CHECK, out_path, run_config, config, jinja_env, context ) if out_path.exists() and directory_has_files_or_directories(out_path): print_styled(f"{out_path} exists, updating project", INFO_STYLE) update_project( out_path, config, run_config, jinja_env, data=data, no_input=no_input, abort_on_conflict=abort_on_conflict, auto_commit=auto_commit, save=save, ) return folder print_styled(f"{out_path} does not exist, initializing project", INFO_STYLE) # Clear the folder that was temporarily created to run the check hook. It will be # recreated by the init_project() function. out_path.rmdir() return init_project()
[docs]def initialize_project_get_folder( template_path: Path, out_root: Path, config: FlexlateDevConfig, run_config: FullRunConfiguration, jinja_env: jinja2.Environment, no_input: bool = False, data: Optional[TemplateData] = None, save: bool = True, default_folder_name: str = DEFAULT_PROJECT_NAME, ) -> str: folder = fxt.init_project_from( str(template_path), path=out_root, no_input=no_input, data=data, default_folder_name=default_folder_name, ) out_path = out_root / folder context = CommandContext.create( template_root=template_path, out_root=out_root, no_input=no_input, save=save, ) run_user_hook( RunnerHookType.POST_INIT, out_path, run_config, config, jinja_env, context ) if save: if run_config.data: run_config.data.folder_name = folder _save_config(out_path, config, run_config) return folder
[docs]def update_project( out_path: Path, config: FlexlateDevConfig, run_config: FullRunConfiguration, jinja_env: jinja2.Environment, data: Optional[TemplateData] = None, no_input: bool = False, abort_on_conflict: bool = False, auto_commit: bool = True, save: bool = True, ): def run_update_check_was_aborted() -> bool: try: fxt.update( data=[data] if data else None, no_input=no_input, abort_on_conflict=abort_on_conflict, project_path=out_path, ) return False except flexlate_exc.TriedToCommitButNoChangesException: print_styled("Update did not have any changes", INFO_STYLE) return True except flexlate_exc.MergeConflictsAndAbortException: print_styled( "User aborted resolving merge conflicts, skipping update", INFO_STYLE ) return True template_path = Path(get_template_path_from_project_path(out_path)) context = CommandContext.create( template_root=template_path, out_root=out_path, no_input=no_input, save=save, abort_on_conflict=abort_on_conflict, auto_commit=auto_commit, ) run_user_hook( RunnerHookType.PRE_UPDATE, out_path, run_config, config, jinja_env, context ) try: aborted = run_update_check_was_aborted() except flexlate_exc.GitRepoDirtyException: if auto_commit: repo = Repo(out_path) stage_and_commit_all(repo, run_config.config.commit_message) print_styled( "Detected manual changes to generated files and auto_commit=True, committing", INFO_STYLE, ) aborted = run_update_check_was_aborted() else: print_styled( "Detected manual changes to generated files and auto_commit=False. Please manually commit the changes to continue updating", ACTION_REQUIRED_STYLE, ) return if aborted: # If update was not successful, skip post update hook and saving config return run_user_hook( RunnerHookType.POST_UPDATE, out_path, run_config, config, jinja_env, context ) if save: _save_config(out_path, config, run_config)
def _save_config( out_path: Path, config: FlexlateDevConfig, run_config: FullRunConfiguration ): data = _get_data_from_flexlate_config(out_path) config.save_data_for_run_config(run_config, data) def _get_data_from_flexlate_config(folder: Path) -> TemplateData: config_path = folder / "flexlate.json" config = FlexlateConfig.load(config_path) assert len(config.applied_templates) == 1 at = config.applied_templates[0] return at.data