224 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			224 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import importlib
 | |
| import os
 | |
| import sys
 | |
| import textwrap
 | |
| import traceback
 | |
| 
 | |
| from cpl_cli.abc.generate_schematic_abc import GenerateSchematicABC
 | |
| from cpl_cli.command_abc import CommandABC
 | |
| from cpl_cli.configuration import WorkspaceSettings
 | |
| from cpl_cli.configuration.schematic_collection import SchematicCollection
 | |
| from cpl_cli.helper.dependencies import Dependencies
 | |
| from cpl_core.configuration.configuration_abc import ConfigurationABC
 | |
| from cpl_core.console.console import Console
 | |
| from cpl_core.console.foreground_color_enum import ForegroundColorEnum
 | |
| from cpl_core.utils.string import String
 | |
| 
 | |
| 
 | |
| class GenerateService(CommandABC):
 | |
|     def __init__(
 | |
|         self,
 | |
|         configuration: ConfigurationABC,
 | |
|         workspace: WorkspaceSettings,
 | |
|     ):
 | |
|         """
 | |
|         Service for the CLI command generate
 | |
|         :param configuration:
 | |
|         """
 | |
|         CommandABC.__init__(self)
 | |
| 
 | |
|         self._config = configuration
 | |
|         self._workspace = workspace
 | |
| 
 | |
|         self._config = configuration
 | |
|         self._env = self._config.environment
 | |
|         self._schematics = {}
 | |
|         self._schematic_classes = set()
 | |
| 
 | |
|         for package_name, version in Dependencies.get_cpl_packages():
 | |
|             if package_name == "cpl-cli":
 | |
|                 continue
 | |
|             package = importlib.import_module(String.convert_to_snake_case(package_name))
 | |
|             self._read_custom_schematics_from_path(os.path.dirname(package.__file__))
 | |
| 
 | |
|         self._read_custom_schematics_from_path(self._env.working_directory)
 | |
|         self._read_custom_schematics_from_path(self._env.runtime_directory)
 | |
| 
 | |
|         if len(self._schematic_classes) == 0:
 | |
|             Console.error(f"No schematics found in template directory: .cpl")
 | |
|             sys.exit()
 | |
| 
 | |
|         known_schematics = []
 | |
|         for schematic in self._schematic_classes:
 | |
|             known_schematics.append(schematic.__name__)
 | |
|             schematic.register()
 | |
| 
 | |
|         self._schematics = SchematicCollection.get_schematics()
 | |
| 
 | |
|     @property
 | |
|     def help_message(self) -> str:
 | |
|         schematics = []
 | |
|         for schematic in self._schematics:
 | |
|             aliases = "|".join(self._schematics[schematic]["Aliases"])
 | |
|             schematic_str = schematic
 | |
|             if len(aliases) > 0:
 | |
|                 schematic_str = f"{schematic} ({aliases})"
 | |
| 
 | |
|             schematics.append(schematic_str)
 | |
|         help_msg = textwrap.dedent(
 | |
|             """\
 | |
|         Generate a file based on schematic.
 | |
|         Usage: cpl generate <schematic> <name>
 | |
|         
 | |
|         Arguments:
 | |
|             schematic:  The schematic to generate.
 | |
|             name:       The name of the generated file
 | |
|             
 | |
|         Schematics:"""
 | |
|         )
 | |
| 
 | |
|         for schematic in schematics:
 | |
|             help_msg += f"\n    {schematic}"
 | |
|         return help_msg
 | |
| 
 | |
|     def _read_custom_schematics_from_path(self, path: str):
 | |
|         if not os.path.exists(os.path.join(path, ".cpl")):
 | |
|             return
 | |
| 
 | |
|         sys.path.insert(0, os.path.join(path, ".cpl"))
 | |
|         for r, d, f in os.walk(os.path.join(path, ".cpl")):
 | |
|             for file in f:
 | |
|                 if not file.startswith("schematic_") or not file.endswith(".py"):
 | |
|                     continue
 | |
| 
 | |
|                 try:
 | |
|                     exec(open(os.path.join(r, file), "r").read())
 | |
|                     self._schematic_classes.update(GenerateSchematicABC.__subclasses__())
 | |
|                 except Exception as e:
 | |
|                     Console.error(str(e), traceback.format_exc())
 | |
|                     sys.exit(-1)
 | |
| 
 | |
|     @staticmethod
 | |
|     def _create_file(file_path: str, value: str):
 | |
|         """
 | |
|         Creates the given file with content
 | |
|         :param file_path:
 | |
|         :param value:
 | |
|         :return:
 | |
|         """
 | |
|         with open(file_path, "w") as template:
 | |
|             template.write(value)
 | |
|             template.close()
 | |
| 
 | |
|     def _create_init_files(
 | |
|         self, file_path: str, template: GenerateSchematicABC, class_name: str, schematic: str, rel_path: str
 | |
|     ):
 | |
|         if not os.path.isdir(os.path.dirname(file_path)):
 | |
|             os.makedirs(os.path.dirname(file_path))
 | |
|             directory = ""
 | |
|             for subdir in template.path.split("/"):
 | |
|                 directory = os.path.join(directory, subdir)
 | |
|                 if subdir == "src":
 | |
|                     continue
 | |
| 
 | |
|                 file = self._schematics["init"]["Template"](class_name, "init", rel_path)
 | |
|                 if os.path.exists(os.path.join(os.path.abspath(directory), file.name)):
 | |
|                     continue
 | |
| 
 | |
|                 Console.spinner(
 | |
|                     f"Creating {os.path.abspath(directory)}/{file.name}",
 | |
|                     self._create_file,
 | |
|                     os.path.join(os.path.abspath(directory), file.name),
 | |
|                     file.get_code(),
 | |
|                     text_foreground_color=ForegroundColorEnum.green,
 | |
|                     spinner_foreground_color=ForegroundColorEnum.cyan,
 | |
|                 )
 | |
| 
 | |
|     def _generate(self, schematic: str, name: str, template: type):
 | |
|         """
 | |
|         Generates files by given schematic, name and template
 | |
|         :param schematic:
 | |
|         :param name:
 | |
|         :param template:
 | |
|         :return:
 | |
|         """
 | |
|         class_name = name
 | |
|         rel_path = ""
 | |
|         if "/" in name:
 | |
|             parts = name.split("/")
 | |
|             rel_path = "/".join(parts[:-1])
 | |
|             class_name = parts[len(parts) - 1]
 | |
| 
 | |
|             if self._workspace is not None and parts[0] in self._workspace.projects:
 | |
|                 rel_path = os.path.join(os.path.dirname(self._workspace.projects[parts[0]]), *parts[1:-1])
 | |
| 
 | |
|         template = template(class_name, String.convert_to_snake_case(schematic), rel_path)
 | |
| 
 | |
|         file_path = os.path.join(self._env.working_directory, template.path, template.name)
 | |
|         self._create_init_files(file_path, template, class_name, schematic, rel_path)
 | |
| 
 | |
|         if os.path.isfile(file_path):
 | |
|             Console.error(f"{String.first_to_upper(schematic)} already exists!\n")
 | |
|             sys.exit()
 | |
| 
 | |
|         message = f"Creating {self._env.working_directory}/{template.path}/{template.name}"
 | |
|         if template.path == "":
 | |
|             message = f"Creating {self._env.working_directory}/{template.name}"
 | |
| 
 | |
|         Console.spinner(
 | |
|             message,
 | |
|             self._create_file,
 | |
|             file_path,
 | |
|             template.get_code(),
 | |
|             text_foreground_color=ForegroundColorEnum.green,
 | |
|             spinner_foreground_color=ForegroundColorEnum.cyan,
 | |
|         )
 | |
| 
 | |
|     def _get_schematic_by_alias(self, schematic: str) -> str:
 | |
|         for key in self._schematics:
 | |
|             if schematic in self._schematics[key]["Aliases"]:
 | |
|                 return key
 | |
| 
 | |
|         return schematic
 | |
| 
 | |
|     def execute(self, args: list[str]):
 | |
|         """
 | |
|         Entry point of command
 | |
|         :param args:
 | |
|         :return:
 | |
|         """
 | |
|         schematic = None
 | |
|         value = None
 | |
|         for s in self._schematics:
 | |
|             value = self._config.get_configuration(s)
 | |
|             if value is not None:
 | |
|                 schematic = s
 | |
|                 break
 | |
| 
 | |
|         if (
 | |
|             schematic is None
 | |
|             and len(args) >= 1
 | |
|             and (args[0] in self._schematics or self._get_schematic_by_alias(args[0]) != args[0])
 | |
|         ):
 | |
|             schematic = self._get_schematic_by_alias(args[0])
 | |
|             self._config.add_configuration(schematic, args[1])
 | |
|             value = args[1]
 | |
| 
 | |
|         if schematic is None:
 | |
|             Console.error(f"Schematic not found")
 | |
|             Console.write_line(self.help_message)
 | |
|             sys.exit()
 | |
| 
 | |
|         name = value
 | |
|         if name is None:
 | |
|             name = Console.read(f"Name for the {args[0]}: ")
 | |
| 
 | |
|         if schematic in self._schematics:
 | |
|             s = self._schematics[schematic]
 | |
|             self._generate(schematic, name, s["Template"])
 | |
| 
 | |
|         else:
 | |
|             self._help("Usage: cpl generate <schematic> [options]")
 | |
|             Console.write_line()
 | |
|             sys.exit()
 |