1515 os .system (f'{ sys .executable } -m pip install https://github.com/GamuNetwork/logger/releases/download/2.0.0-alpha.4/gamu_logger-2.0.0a4-py3-none-any.whl > { NULL_TARGET } 2> { NULL_TARGET } ' )
1616 print ("done" )
1717 from gamuLogger import Logger , LEVELS , debugFunc
18+
19+ Logger .setModule ('Builder' )
1820
1921class BaseBuilder :
2022 """
@@ -49,20 +51,27 @@ class Status(Enum):
4951
5052 def __str__ (self ):
5153 return self .name
54+
55+ class RequireMode (Enum ):
56+ OPTIONAL = 0
57+ REQUIRED = 1
58+
59+ def __str__ (self ):
60+ return self .name
5261
5362 def __init__ (self ):
5463 if self .__class__ == BaseBuilder :
5564 raise Exception ('BaseBuilder is an abstract class and cannot be instantiated' )
5665
5766 self .argumentParser = argparse .ArgumentParser (description = 'Builder tool' )
5867
59- loggerOptions = self .argumentParser .add_argument_group ( 'Logger options' )
68+ loggerOptions = self .argumentParser .add_mutually_exclusive_group ( )
6069 loggerOptions .add_argument ('--debug' , action = 'store_true' , help = 'Enable debug messages' )
70+ loggerOptions .add_argument ('--deep-debug' , action = 'store_true' , help = 'Enable deep debug messages' )
6171
6272 buildersOptions = self .argumentParser .add_argument_group ('Builder options' )
6373 buildersOptions .add_argument ('--no-tests' , action = 'store_true' , help = 'Do not run tests' )
6474 buildersOptions .add_argument ('--no-docs' , action = 'store_true' , help = 'Do not generate documentation' )
65- buildersOptions .add_argument ('--no-build' , action = 'store_true' , help = 'Do not build the package' )
6675 buildersOptions .add_argument ('--publish' , action = 'store_true' , help = 'Publish the package' )
6776 buildersOptions .add_argument ('--no-clean' , action = 'store_true' , help = 'Do not clean temporary files' )
6877 buildersOptions .add_argument ('--temp-dir' , help = 'Temporary directory (used to generate the package)' , type = str , default = mkdtemp ())
@@ -74,27 +83,45 @@ def __init__(self):
7483 self .args = self .argumentParser .parse_args ()
7584
7685 self .__steps = {
77- "Setup" : self .Status .WAITING ,
78- "Build" : self .Status .DISABLED if self .args .no_build else self .Status .WAITING ,
79- "Tests" : self .Status .DISABLED if self .args .no_tests else self .Status .WAITING ,
80- "Docs" : self .Status .DISABLED if self .args .no_docs else self .Status .WAITING ,
81- "Publish" : self .Status .WAITING if self .args .publish else self .Status .DISABLED
86+ "Setup" : self .Status .WAITING ,
87+ "Build" : self .Status .WAITING ,
88+ "Tests" : self .Status .DISABLED if self .args .no_tests else self .Status .WAITING ,
89+ "BuildTests" : self .Status .DISABLED if self .args .no_tests else self .Status .WAITING ,
90+ "Docs" : self .Status .DISABLED if self .args .no_docs else self .Status .WAITING ,
91+ "Publish" : self .Status .WAITING if self .args .publish else self .Status .DISABLED
8292 }
8393
8494 self .clean = not self .args .no_clean
8595
8696 self .__remainingSteps = len ([step for step in self .__steps if self .__steps [step ] != self .Status .DISABLED ])
8797
8898 self .__stepDependencies = {
89- "Setup" : [],
90- "Build" : ["Setup" ],
91- "Docs" : ["Setup" ],
92- "Tests" : ["Setup" , "Build" ],
93- "Publish" : ["Setup" , "Build" , "Tests" , "Docs" ]
94- }
99+ "Setup" : {},
100+ "Build" : {
101+ "Setup" : self .RequireMode .REQUIRED ,
102+ "Tests" : self .RequireMode .OPTIONAL
103+ },
104+ "Docs" : {
105+ "Setup" : self .RequireMode .REQUIRED
106+ },
107+ "Tests" : {
108+ "Setup" : self .RequireMode .REQUIRED
109+ },
110+ "BuildTests" : {
111+ "Setup" : self .RequireMode .REQUIRED ,
112+ "Build" : self .RequireMode .REQUIRED
113+ },
114+ "Publish" : {
115+ "Build" : self .RequireMode .REQUIRED ,
116+ "BuildTests" : self .RequireMode .OPTIONAL ,
117+ "Docs" : self .RequireMode .OPTIONAL
118+ }
119+ } #type: dict[str, dict[str, BaseBuilder.RequireMode]]
95120
96121 if self .args .debug :
97122 Logger .setLevel ('stdout' , LEVELS .DEBUG )
123+ elif self .args .deep_debug :
124+ Logger .setLevel ('stdout' , LEVELS .DEEP_DEBUG )
98125
99126
100127 Logger .debug ('Using temporary directory: ' + os .path .abspath (self .args .temp_dir ))
@@ -112,7 +139,8 @@ def packageVersion(self):
112139 def distDir (self ):
113140 return os .path .abspath (self .args .dist_dir )
114141
115- def CopyAndReplaceByPackageVersion (self , src , dst , versionString = "{version}" ):
142+ def addAndReplaceByPackageVersion (self , src , dst , versionString = "{version}" ):
143+ Logger .debug ('Adding file: ' + src + ' and replacing version string by ' + self .packageVersion )
116144 with open (src , 'r' ) as file :
117145 content = file .read ()
118146 content = content .replace (versionString , self .packageVersion )
@@ -140,6 +168,18 @@ def runCommand(self, command) -> bool:
140168 os .remove (stderrPath )
141169 return True
142170
171+ def addFile (self , path , dest = None ):
172+ Logger .debug ('Adding file: ' + path )
173+ if dest is None :
174+ dest = path
175+ shutil .copy (path , self .tempDir + '/' + dest )
176+
177+ def addDirectory (self , path , dest = None ):
178+ Logger .debug ('Adding directory: ' + path )
179+ if dest is None :
180+ dest = path
181+ shutil .copytree (path , self .tempDir + '/' + dest , ignore = shutil .ignore_patterns ('*.pyc' , '*.pyo' , '__pycache__' ))
182+
143183
144184 def __clean (self ) -> bool :
145185 Logger .info ('Cleaning temporary directory' )
@@ -152,13 +192,32 @@ def __clean(self) -> bool:
152192 Logger .debug ('Temporary directory cleaned' )
153193 return True
154194
155-
195+
156196 def __canStepBeStarted (self , step ):
157- for dependency in self .__stepDependencies [step ]:
158- if self .__steps [dependency ] != self .Status .FINISHED :
159- return False
197+ # a better version of the previous function
198+ for dependency , requireMode in self .__stepDependencies [step ].items ():
199+ match self .__steps [dependency ]:
200+ case self .Status .WAITING :
201+ Logger .deepDebug (f"The step '{ step } ' cannot be started because the dependency '{ dependency } ' is not started yet" )
202+ return False
203+ case self .Status .RUNNING :
204+ Logger .deepDebug (f"The step '{ step } ' cannot be started because the dependency '{ dependency } ' is running and need to finish first" )
205+ return False
206+ case self .Status .FAILED :
207+ Logger .deepDebug (f"The step '{ step } ' cannot be started because the dependency '{ dependency } ' has failed" )
208+ return False
209+ case self .Status .DISABLED :
210+ if requireMode == self .RequireMode .REQUIRED :
211+ Logger .deepDebug (f"The step '{ step } ' cannot be started because the dependency '{ dependency } ' is disabled but required" )
212+ return False
213+ else :
214+ Logger .deepDebug (f"The step '{ step } ' will run without the optional dependency '{ dependency } '" )
215+ continue
216+ case self .Status .FINISHED :
217+ continue
160218 return True
161219
220+
162221 def __runStep (self , step : str ):
163222 '''
164223 A step is considered failed if it raises an exception, or if it returns False
@@ -177,20 +236,22 @@ def __runStep(self, step : str):
177236
178237 def __run (self , configuredSteps : list [str ]):
179238 for step in self .__steps :
180- if step not in configuredSteps and step != '__clean' :
239+ if step not in configuredSteps :
181240 self .__steps [step ] = self .Status .DISABLED
182241 self .__remainingSteps -= 1
183242 Logger .debug ('Step "' + step + '" disabled' )
184243
185244
186245 HasFailed = False
187246 while self .__remainingSteps > 0 and not HasFailed :
247+ Logger .deepDebug ("Remaining steps: " + str (self .__remainingSteps ))
188248 for step in self .__steps :
189249 if self .__steps [step ] == self .Status .WAITING and self .__canStepBeStarted (step ):
190250 Logger .info ('Starting step "' + step + '"' )
191251 self .__steps [step ] = self .Status .RUNNING
192252
193253 hasSucceeded = self .__runStep (step )
254+ Logger .deepDebug ('Step "' + step + '" returned ' + str (hasSucceeded ))
194255
195256 if hasSucceeded :
196257 self .__steps [step ] = self .Status .FINISHED
@@ -221,7 +282,7 @@ def execute():
221282 Logger .critical ('Multiple builders found' )
222283 sys .exit (1 )
223284
224- possibleSteps = ['Setup' , 'Tests' , 'Docs' , 'Build' , 'Publish' ]
285+ possibleSteps = ['Setup' , 'Tests' , 'BuildTests' , ' Docs' , 'Build' , 'Publish' ]
225286 steps = [step for step in subClasses [0 ].__dict__ if step in possibleSteps ]
226287 subClasses [0 ]().__run (steps )
227288
0 commit comments