11"""Everything needed to build a CPPython project
22"""
33
4+ import logging
45from importlib import metadata
56from inspect import getmodule
67from logging import Logger
7- from pathlib import Path
88from typing import Any
99
10- from cppython_core .exceptions import ConfigError , PluginError
10+ from cppython_core .exceptions import PluginError
1111from cppython_core .plugin_schema .generator import Generator
1212from cppython_core .plugin_schema .provider import Provider
1313from cppython_core .plugin_schema .scm import SCM
2020 resolve_pep621 ,
2121 resolve_project_configuration ,
2222 resolve_provider ,
23+ resolve_scm ,
2324)
2425from cppython_core .schema import (
2526 CoreData ,
2627 CorePluginData ,
2728 CPPythonGlobalConfiguration ,
28- CPPythonLocalConfiguration ,
2929 DataPluginT ,
30- PEP621Configuration ,
30+ PEP621Data ,
3131 ProjectConfiguration ,
32+ ProjectData ,
33+ PyProject ,
3234)
3335
3436
@@ -38,90 +40,104 @@ class Builder:
3840 def __init__ (self , logger : Logger ) -> None :
3941 self .logger = logger
4042
41- def generate_core_data (
42- self ,
43- configuration : ProjectConfiguration ,
44- pep621_configuration : PEP621Configuration ,
45- cppython_configuration : CPPythonLocalConfiguration ,
46- plugin_build_date : PluginBuildData ,
47- ) -> CoreData :
48- """Parses and returns resolved data from all configuration sources
43+ def setup_logger (self , project_configuration : ProjectConfiguration ) -> None :
44+ """_summary_
4945
5046 Args:
51- configuration: Input configuration
52- pep621_configuration: Project table configuration
53- cppython_configuration: Tool configuration
54- plugin_build_date: Build data
47+ project_configuration: _description_
48+ """
49+ # Default logging levels
50+ levels = [ logging . WARNING , logging . INFO , logging . DEBUG ]
5551
56- Raises:
57- ConfigError: Raised if data cannot be parsed
52+ # Add default output stream
53+ self .logger .addHandler (logging .StreamHandler ())
54+ self .logger .setLevel (levels [project_configuration .verbosity ])
55+
56+ self .logger .info ("Logging setup complete" )
57+
58+ def generate_project_data (self , project_configuration : ProjectConfiguration ) -> ProjectData :
59+ """_summary_
60+
61+ Args:
62+ project_configuration: _description_
5863
5964 Returns:
60- The resolved core object
65+ _description_
6166 """
6267
63- global_configuration = CPPythonGlobalConfiguration ( )
68+ return resolve_project_configuration ( project_configuration )
6469
65- project_data = resolve_project_configuration (configuration )
70+ def generate_data_plugins (self , pyproject : PyProject ) -> PluginBuildData :
71+ """_summary_
6672
67- try :
68- pep621_data = resolve_pep621 ( pep621_configuration , configuration )
73+ Args :
74+ pyproject: _description_
6975
70- except ConfigError :
71- configuration . version = self . extract_scm_version ( configuration . pyproject_file . parent )
72- pep621_data = resolve_pep621 ( pep621_configuration , configuration )
76+ Returns :
77+ _description_
78+ """
7379
74- cppython_data = resolve_cppython (cppython_configuration , global_configuration , project_data , plugin_build_date )
80+ raw_generator_plugins = self .find_generators ()
81+ generator_plugins = self .filter_plugins (
82+ raw_generator_plugins ,
83+ pyproject .tool .cppython .generator_name ,
84+ "Generator" ,
85+ )
7586
76- return CoreData (project_data = project_data , pep621_data = pep621_data , cppython_data = cppython_data )
87+ raw_provider_plugins = self .find_providers ()
88+ provider_plugins = self .filter_plugins (
89+ raw_provider_plugins ,
90+ pyproject .tool .cppython .provider_name ,
91+ "Provider" ,
92+ )
7793
78- def extract_scm_version ( self , path : Path ) -> str :
79- """Locates an available SCM plugin that can report version information about the given path
94+ # Solve the messy interactions between plugins
95+ generator_type , provider_type = self . solve ( generator_plugins , provider_plugins )
8096
81- Args:
82- path: The directory to query
97+ return PluginBuildData (generator_type = generator_type , provider_type = provider_type )
8398
84- Raises:
85- PluginError: If no SCM plugin can be found
99+ def generate_pep621_data (
100+ self , pyproject : PyProject , project_configuration : ProjectConfiguration , scm : SCM | None
101+ ) -> PEP621Data :
102+ """_summary_
103+
104+ Args:
105+ pyproject: _description_
106+ project_configuration: _description_
107+ scm: _description_
86108
87109 Returns:
88- A version token
110+ _description_
89111 """
112+ return resolve_pep621 (pyproject .project , project_configuration , scm )
90113
91- group = "SCM"
92- group_lower = group .lower ()
93-
94- scm_types : list [type [SCM ]] = []
114+ def generate_core_data (
115+ self ,
116+ project_data : ProjectData ,
117+ pyproject : PyProject ,
118+ pep621_data : PEP621Data ,
119+ plugin_build_date : PluginBuildData ,
120+ ) -> CoreData :
121+ """Parses and returns resolved data from all configuration sources
95122
96- if not (entries := list (metadata .entry_points (group = f"cppython.{ group_lower } " ))):
97- raise PluginError ("No SCM plugin found" )
123+ Args:
124+ project_data: Project data
125+ pyproject: TODO
126+ pep621_data: TODO
127+ plugin_build_date: TODO
98128
99- # Filter entries
100- for entry_point in entries :
101- plugin_type = entry_point .load ()
102- if not issubclass (plugin_type , SCM ):
103- self .logger .warning (
104- f"Found incompatible plugin. The '{ resolve_name (plugin_type )} ' plugin must be an instance of"
105- f" '{ group_lower } '"
106- )
107- else :
108- scm_types .append (plugin_type )
129+ Raises:
130+ ConfigError: Raised if data cannot be parsed
109131
110- # Deduce the SCM repository
111- plugin = None
112- for scm_type in scm_types :
113- scm = scm_type ()
114- if scm .supported (path ):
115- plugin = scm
116- break
132+ Returns:
133+ The resolved core object
134+ """
117135
118- if not plugin :
119- raise PluginError ("No applicable SCM plugin found for the given path" )
136+ global_configuration = CPPythonGlobalConfiguration ()
120137
121- if (version := plugin .version (path )) is None :
122- raise PluginError ("Project has no version information" )
138+ cppython_data = resolve_cppython (pyproject .tool .cppython , global_configuration , project_data , plugin_build_date )
123139
124- return version
140+ return CoreData ( project_data = project_data , pep621_data = pep621_data , cppython_data = cppython_data )
125141
126142 def find_generators (self ) -> list [type [Generator ]]:
127143 """_summary_
@@ -188,13 +204,12 @@ def find_providers(self) -> list[type[Provider]]:
188204 return plugin_types
189205
190206 def filter_plugins (
191- self , plugin_types : list [type [DataPluginT ]], directory : Path , pinned_name : str | None , group_name : str
207+ self , plugin_types : list [type [DataPluginT ]], pinned_name : str | None , group_name : str
192208 ) -> list [type [DataPluginT ]]:
193209 """Finds and filters data plugins
194210
195211 Args:
196212 plugin_types: The plugin type to lookup
197- directory: The data to query support for the filtered plugins
198213 pinned_name: The configuration name
199214 group_name: The group name
200215
@@ -220,11 +235,10 @@ def filter_plugins(
220235
221236 # Deduce types
222237 for loaded_type in plugin_types :
223- if loaded_type .supported (directory ):
224- self .logger .warning (
225- f"A { group_name } plugin is supported: { resolve_name (loaded_type )} from { getmodule (loaded_type )} "
226- )
227- supported_types .append (loaded_type )
238+ self .logger .warning (
239+ f"A { group_name } plugin is supported: { resolve_name (loaded_type )} from { getmodule (loaded_type )} "
240+ )
241+ supported_types .append (loaded_type )
228242
229243 # Fail
230244 if supported_types is None :
@@ -263,6 +277,53 @@ def solve(
263277
264278 return combos [0 ]
265279
280+ def create_scm (
281+ self ,
282+ project_data : ProjectData ,
283+ ) -> SCM | None :
284+ """_summary_
285+
286+ Args:
287+ project_data: _description_
288+
289+ Raises:
290+ PluginError: Ya
291+
292+ Returns:
293+ _description_
294+ """
295+ group = "scm"
296+ path = project_data .pyproject_file .parent
297+
298+ scm_types : list [type [SCM ]] = []
299+
300+ if not (entries := list (metadata .entry_points (group = f"cppython.{ group } " ))):
301+ raise PluginError ("No SCM plugin found" )
302+
303+ # Filter entries
304+ for entry_point in entries :
305+ plugin_type = entry_point .load ()
306+ if not issubclass (plugin_type , SCM ):
307+ self .logger .warning (
308+ f"Found incompatible plugin. The '{ resolve_name (plugin_type )} ' plugin must be an instance of"
309+ f" '{ group } '"
310+ )
311+ else :
312+ scm_types .append (plugin_type )
313+
314+ # Deduce the SCM repository
315+ plugin = None
316+ for scm_type in scm_types :
317+ if scm_type .features (path ).repository :
318+ scm_data = resolve_scm (project_data )
319+ plugin = scm_type (scm_data )
320+ break
321+
322+ if not plugin :
323+ self .logger .error ("No applicable SCM plugin found for the given path" )
324+
325+ return plugin
326+
266327 def create_generator (
267328 self , core_data : CoreData , generator_configuration : dict [str , Any ], generator_type : type [Generator ]
268329 ) -> Generator :
0 commit comments