4
4
5
5
from dataclasses import dataclass
6
6
from importlib import metadata
7
- from typing import Callable , Optional , Type , TypeVar
7
+ from typing import Any , Type , TypeVar
8
8
from xmlrpc .client import Boolean
9
9
10
- from cppython_core .exceptions import ConfigError
11
- from cppython_core .schema import API , Generator , Interface , Plugin , PyProject
10
+ from cppython_core .schema import (
11
+ API ,
12
+ CPPythonData ,
13
+ Generator ,
14
+ Interface ,
15
+ Plugin ,
16
+ PyProject ,
17
+ ToolData ,
18
+ )
19
+ from pydantic import create_model
12
20
13
21
14
22
@dataclass
@@ -20,89 +28,138 @@ class ProjectConfiguration:
20
28
verbose : Boolean = False
21
29
22
30
31
+ class ProjectBuilder :
32
+ """
33
+ TODO
34
+ """
35
+
36
+ def __init__ (self , configuration : ProjectConfiguration ) -> None :
37
+ self .configuration = configuration
38
+
39
+ def gather_plugins (self , plugin_type : Type [Plugin ]) -> list [Type [Plugin ]]:
40
+ """
41
+ TODO
42
+ """
43
+ plugins = []
44
+ entry_points = metadata .entry_points (group = f"cppython.{ plugin_type .plugin_group ()} " )
45
+
46
+ for entry_point in entry_points :
47
+ loaded_plugin_type = entry_point .load ()
48
+ if issubclass (loaded_plugin_type , plugin_type ) & (loaded_plugin_type is not plugin_type ):
49
+ plugins .append (loaded_plugin_type )
50
+
51
+ return plugins
52
+
53
+ def generate_model (self , plugins : list [Type [Plugin ]]) -> Type [PyProject ]:
54
+ """
55
+ TODO
56
+ """
57
+ plugin_fields = {}
58
+ for plugin_type in plugins :
59
+ plugin_fields [plugin_type .name ()] = plugin_type .data_type ()
60
+
61
+ ExtendedCPPythonData = create_model (
62
+ "ExtendedCPPythonData" ,
63
+ ** plugin_fields ,
64
+ __base__ = CPPythonData ,
65
+ )
66
+
67
+ ExtendedToolData = create_model (
68
+ "ToolData" ,
69
+ cppython = ExtendedCPPythonData ,
70
+ __base__ = ToolData ,
71
+ )
72
+
73
+ return create_model (
74
+ "PyProject" ,
75
+ tool = ExtendedToolData ,
76
+ __base__ = PyProject ,
77
+ )
78
+
79
+
23
80
class Project (API ):
24
81
"""
25
82
The object constructed at each entry_point
26
83
"""
27
84
28
- def __init__ (self , configuration : ProjectConfiguration , interface : Interface , pyproject : PyProject ) -> None :
85
+ def __init__ (
86
+ self , configuration : ProjectConfiguration , interface : Interface , pyproject_data : dict [str , Any ]
87
+ ) -> None :
29
88
30
89
self .enabled = False
31
- self .verbose = configuration . verbose
90
+ self .configuration = configuration
32
91
33
- if self .verbose :
92
+ if self .configuration . verbose :
34
93
interface .print ("Starting CPPython project initialization" )
35
94
95
+ builder = ProjectBuilder (self .configuration )
96
+ plugins = builder .gather_plugins (Generator )
97
+
98
+ if not plugins :
99
+ if self .configuration .verbose :
100
+ interface .print ("No generator plugin was found." )
101
+ return
102
+
103
+ ExtendedPyProject = builder .generate_model (plugins )
104
+ pyproject = ExtendedPyProject (** pyproject_data )
105
+
36
106
if pyproject .tool is None :
37
- if self .verbose :
107
+ if self .configuration . verbose :
38
108
interface .print ("Table [tool] is not defined" )
39
109
return
40
110
41
111
if pyproject .tool .cppython is None :
42
- if self .verbose :
112
+ if self .configuration . verbose :
43
113
interface .print ("Table [tool.cppython] is not defined" )
44
114
return
45
115
46
116
self .enabled = True
47
117
48
118
self ._interface = interface
49
119
50
- PluginType = TypeVar ("PluginType" , bound = Type [Plugin ])
51
-
52
- def find_plugin_type (plugin_type : PluginType , condition : Callable [[str ], bool ]) -> Optional [PluginType ]:
53
- """
54
- Finds the first plugin that satisfies the given condition
55
- """
56
-
57
- entry_points = metadata .entry_points (group = f"cppython.{ plugin_type .plugin_group ()} " )
58
-
59
- for entry_point in entry_points :
60
- loaded_plugin_type = entry_point .load ()
61
- if issubclass (loaded_plugin_type , plugin_type ) & (loaded_plugin_type is not plugin_type ):
62
- if condition (loaded_plugin_type .name ()):
63
- return loaded_plugin_type
120
+ self ._generators = []
121
+ for plugin_type in plugins :
122
+ self ._generators .append (plugin_type (pyproject ))
64
123
65
- return None
66
-
67
- plugin_type = find_plugin_type (Generator , lambda name : name == pyproject .tool .cppython .generator )
68
-
69
- if plugin_type is None :
70
- raise ConfigError (f"No generator plugin with the name '{ pyproject .tool .cppython .generator } ' was found." )
71
-
72
- generator_data = interface .read_generator_data (plugin_type .data_type ())
73
- self ._generator = plugin_type (pyproject , generator_data )
74
-
75
- if self .verbose :
124
+ if self .configuration .verbose :
76
125
interface .print ("CPPython project initialized" )
77
126
78
127
def download (self ):
79
128
"""
80
129
Download the generator tooling if required
81
130
"""
82
- if not self ._generator .generator_downloaded ():
83
- self ._interface .print (f"Downloading the { self ._generator .name ()} tool" )
131
+ for generator in self ._generators :
84
132
85
- # TODO: Make async with progress bar
86
- self ._generator .download_generator ()
87
- self ._interface .print ("Download complete" )
133
+ if not generator .generator_downloaded ():
134
+ self ._interface .print (f"Downloading the { generator .name ()} tool" )
135
+
136
+ # TODO: Make async with progress bar
137
+ generator .download_generator ()
138
+ self ._interface .print ("Download complete" )
88
139
89
140
# API Contract
90
141
91
142
def install (self ) -> None :
92
143
if self .enabled :
93
- if self .verbose :
144
+ if self .configuration . verbose :
94
145
self ._interface .print ("CPPython: Installing..." )
95
146
self .download ()
96
- self ._generator .install ()
147
+
148
+ for generator in self ._generators :
149
+ generator .install ()
97
150
98
151
def update (self ) -> None :
99
152
if self .enabled :
100
- if self .verbose :
153
+ if self .configuration . verbose :
101
154
self ._interface .print ("CPPython: Updating..." )
102
- self ._generator .update ()
155
+
156
+ for generator in self ._generators :
157
+ generator .update ()
103
158
104
159
def build (self ) -> None :
105
160
if self .enabled :
106
- if self .verbose :
161
+ if self .configuration . verbose :
107
162
self ._interface .print ("CPPython: Building..." )
108
- self ._generator .build ()
163
+
164
+ for generator in self ._generators :
165
+ generator .build ()
0 commit comments