1+ import argparse
2+ from gamuLogger import Logger , LEVELS
3+
4+ import os , sys , shutil
5+
6+ from tempfile import mkdtemp
7+
8+ class BaseBuilder :
9+ def __init__ (self ):
10+ if self .__class__ == BaseBuilder :
11+ raise Exception ('BaseBuilder is an abstract class and cannot be instantiated' )
12+
13+ self .argumentParser = argparse .ArgumentParser (description = 'Builder tool' )
14+
15+ loggerOptions = self .argumentParser .add_argument_group ('Logger options' )
16+ loggerOptions .add_argument ('--debug' , action = 'store_true' , help = 'Enable debug messages' )
17+
18+ buildersOptions = self .argumentParser .add_argument_group ('Builder options' )
19+ buildersOptions .add_argument ('--no-tests' , action = 'store_true' , help = 'Do not run tests' )
20+ buildersOptions .add_argument ('--no-docs' , action = 'store_true' , help = 'Do not generate documentation' )
21+ buildersOptions .add_argument ('--no-build' , action = 'store_true' , help = 'Do not build the package' )
22+ buildersOptions .add_argument ('--publish' , action = 'store_true' , help = 'Publish the package' )
23+ buildersOptions .add_argument ('--no-clean' , action = 'store_true' , help = 'Do not clean temporary files' )
24+ buildersOptions .add_argument ('--temp-dir' , help = 'Temporary directory' , type = str , default = mkdtemp ())
25+ buildersOptions .add_argument ('--dist-dir' , help = 'Distribution directory' , type = str , default = 'dist' )
26+ buildersOptions .add_argument ('-pv' , '--package-version' , help = 'Package version' , type = str , default = '0.0.0' )
27+
28+ self .argumentParser .add_argument ('--version' , '-v' , action = 'version' , version = '%(prog)s 1.0' )
29+
30+ self .args = self .argumentParser .parse_args ()
31+
32+ if self .args .debug :
33+ Logger .setLevel ('stdout' , LEVELS .DEBUG )
34+
35+
36+ Logger .debug ('Using temporary directory: ' + os .path .abspath (self .args .temp_dir ))
37+ Logger .debug ('Using distribution directory: ' + os .path .abspath (self .args .dist_dir ))
38+
39+ if os .path .exists (self .args .temp_dir ):
40+ Logger .debug ('Removing temp directory for cleaning' )
41+ shutil .rmtree (self .args .temp_dir )
42+
43+ Logger .debug ('Creating temp directory' )
44+ os .makedirs (self .args .temp_dir )
45+
46+ @property
47+ def tempDir (self ):
48+ return os .path .abspath (self .args .temp_dir )
49+
50+ @property
51+ def packageVersion (self ):
52+ return self .args .package_version
53+
54+ @property
55+ def distDir (self ):
56+ return os .path .abspath (self .args .dist_dir )
57+
58+ def CopyAndReplaceByPackageVersion (self , src , dst , versionString = "{version}" ):
59+ with open (src , 'r' ) as file :
60+ content = file .read ()
61+ content = content .replace (versionString , self .packageVersion )
62+ with open (dst , 'w' ) as file :
63+ file .write (content )
64+
65+
66+
67+ # These methods should be overriden by the child class
68+ def Setup (self ):
69+ """Copy required file to the temporary directory and replace the version string by the package version, install dependencies, etc."""
70+ Logger .warning ('no setup configured' )
71+
72+ def Tests (self ):
73+ """Run the tests for the package"""
74+ Logger .debug ('no tests configured' )
75+
76+ def Docs (self ):
77+ """Generate the documentation for the package"""
78+ Logger .debug ('no docs configured' )
79+
80+ def Build (self ):
81+ """Build the package"""
82+ Logger .warning ('no build configured' )
83+
84+ def Publish (self ):
85+ """Publish the package"""
86+ Logger .error ('no publish configured' )
87+
88+
89+ def __clean (self ):
90+ shutil .rmtree (self .args .temp_dir )
91+
92+
93+ def __run (self ):
94+ """
95+ Order of execution:
96+ - Setup
97+ - Build
98+ - Tests
99+ - Docs
100+ - Publish
101+ - Clean
102+
103+ If any of this steps fails, the process should stop, and the clean method should be called
104+ """
105+
106+ Logger .info ('Running setup' )
107+ self .Setup ()
108+ Logger .debug ('Setup finished' )
109+
110+ if not self .args .no_build :
111+ Logger .info ('Building package' )
112+ self .Build ()
113+
114+ if self .args .no_tests :
115+ Logger .warning ('Skipping tests' )
116+ else :
117+ Logger .info ('Running tests' )
118+ self .Tests ()
119+
120+ if not self .args .no_docs :
121+ Logger .info ('Generating documentation' )
122+ self .Docs ()
123+
124+ if self .args .publish :
125+ Logger .info ('Publishing package' )
126+ self .Publish ()
127+ else :
128+ Logger .info ('Package not published' )
129+
130+ if self .args .no_clean :
131+ Logger .warning ('Skipping cleaning' )
132+ else :
133+ Logger .info ('Cleaning temporary files' )
134+ self .__clean ()
135+ Logger .debug ('Temporary files cleaned' )
136+
137+ Logger .info ('Process finished' )
138+
139+
140+ @staticmethod
141+ def execute ():
142+ subClasses = BaseBuilder .__subclasses__ ()
143+ if len (subClasses ) == 0 :
144+ Logger .critical ('No builders found' )
145+ sys .exit (1 )
146+ elif len (subClasses ) > 1 :
147+ Logger .critical ('Multiple builders found' )
148+ sys .exit (1 )
149+ subClasses [0 ]().__run ()
150+
151+
152+ # some useful constants
153+
154+ PYTHON = sys .executable
155+ NULL_TARGET = '/dev/null' if os .name == 'posix' else 'nul'
0 commit comments