source: PSPA/madxPSPA/testing/MadBuild.py @ 430

Last change on this file since 430 was 430, checked in by touze, 11 years ago

import madx-5.01.00

File size: 12.4 KB
Line 
1#!/usr/bin/python
2
3
4import datetime
5import optparse
6import os
7import stat
8import re
9import shutil
10
11
12from Notify import notify
13
14
15class Logger: # in more recent versions, Python features a logger
16    def __init__(self,name):
17        self.name = name
18        if os.path.exists(self.name):
19            os.remove(self.name)
20
21    def log(self,msg):
22        f = open(self.name,"a") # append
23        f.write(msg+'\n')
24        f.close() # close after each log message
25
26website =   "/afs/cern.ch/user/n/nougaret/www/mad"
27reportDir = "/afs/cern.ch/user/n/nougaret/scratch1/mad-automation"
28# 12 april 2009 fix the directory in which to extract MAD-X
29#currentDir = os.getcwd()
30currentDir = reportDir
31extractDir = currentDir+'/MadSvnExtract'
32
33notify('jean-luc','MadSvnExtract','MadSvnExtract will be created as ' + extractDir)
34
35class Repository:
36    def __init__(self):
37        pass
38    def checkout(self,releaseTag):
39#        command = "cvs -d " + Repository.repoDir + " checkout -r" + releaseTag + " madX"
40        command = "svn co svn+ssh://svn.cern.ch/reps/madx/tags/" + releaseTag + " " + extractDir
41        os.system(command)
42
43class Build:
44    builds = []
45    def __init__(self,name,command,outcome):
46        self.name = name # 'Makefile', 'Makefile_dev' or 'Makefile_nag'
47        self.command = command # the build command
48        self.outcome = outcome
49        Build.builds.append(self)
50
51# first set environment variables for lf95 and NAG compilers
52# this is necessary for the acron job which does not perform a login
53# that would set the variables transparently.
54
55# 27 september: this script is no longer called from an acron job, therefore
56# no longer need to reset the environment variables within the scripts.
57# instead we inherit everything from ~/.cshrc on pcslux99
58
59def main():
60
61# temporary: for the Intel compiler, lines split after the 80th character
62# unless we set up a specific environment variable to set the line length
63# note that this variable will be transmitted to the child processes
64# launched through os.sytem() calls.
65# all 'madx < input > output' calls where madx is compiled with the ifort
66# Intel compiler will take FORT_FMT_RECL into account.
67#    os.environ['FORT_FMT_RECL']='256' # lines split after 256 chars instead of
68# THIS DOES NOT SEEM TO WORK 13 april 2010 - force the variable when invoking the makefile instead
69# the default 80   
70         
71    LOG_FILENAME = reportDir + "/MadBuild_Report.txt"
72    logger = Logger(LOG_FILENAME)
73    logger.log('first logging message')   
74    logger.log('start logging at '+(datetime.datetime.now()).ctime())
75                 
76    compilationOK = True # default (assumes all the compilations proceed till completion)
77
78    globalStartTime =  (datetime.datetime.now()).ctime()
79    usage = "%prog [options]"
80    parser = optparse.OptionParser(usage)
81    parser.add_option('--release','-r',help="release tag",dest="releaseTag")
82    parser.add_option('--dev','-d',help="construct executable with Makefile_develop",action="store_true")
83    parser.add_option('--nag','-n',help="construct executable with Makefile_nag",action="store_true")
84    (options,args) = parser.parse_args()
85
86    if options.dev and not options.nag:
87        logger.log("option --dev selected")
88    elif options.nag and not options.dev:
89        logger.log("option --nag selected")
90    elif options.dev and options.nag:
91        logger.log("options --dev and --nag selected")
92    else:
93        logger.log("only compile madx_Makefile")
94
95    if not options.releaseTag:
96        raise("except a release tag to be specified")
97    else: # is the release tag well formed?
98        releasePattern = re.compile(r'^madX\-\d+_\d{2}_\d{2}(\_dev)?$')
99        if not releasePattern.match(options.releaseTag):
100            raise("release tag is ill-formed: it should be like 'madX-4_01_01' instead of '"+options.releaseTag+"'")
101
102    # 23 juin 2010
103    #os.environ['PATH'] = os.environ['PATH'] +\
104    #                     ":/afs/cern.ch/sw/fortran/nag/f95.5.361/bin:/afs/cern.ch/sw/fortran/lahey/lf9562/bin"
105    #
106    #if os.getenv('LD_LIBRARY_PATH')==None: # would cause a key error at runtime
107    #    os.environ['LD_LIBRARY_PATH'] = ":/afs/cern.ch/sw/fortran/lahey/lf9562/lib"
108    #else:
109    #    os.environ['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH'] + ":/afs/cern.ch/sw/fortran/lahey/lf9562/lib"
110
111    makefiles = ['Makefile']
112
113    if options.nag:
114        # 23 juin 2010
115        #        os.environ['NAG95_ROOT'] = "/afs/cern.ch/sw/fortran/nag/f95.5.361" # flexlm license manager for NAG compiler
116        #os.environ['LM_LICENSE_FILE'] = "/afs/cern.ch/sw/fortran/nag/f95.5.361/license.dat"
117        # 27 september 2010: rely on the path and env set in ~/.cshrc instead of setting environment variables
118        #os.environ['NAG95_ROOT'] = "/usr/local/lib/NAG_Fortran"
119        #os.environ['NAG_KUSARI_FILE'] = os.environ['NAG95_ROOT']+"/license.dat"
120        makefiles.append('Makefile_nag')
121
122        #os.environ['PATH'] = ".:/usr/local/lib/NAG_FORTRAN:"+os.environ['PATH']
123
124    if options.dev:
125        makefiles.append('Makefile_develop')
126
127    # if the directory in which to extract the CVS already exists, then delete it
128    if os.path.exists(extractDir):
129        shutil.rmtree(extractDir)
130    # now create the directory in which to extract the CVS   
131    #os.mkdir(extractDir)
132    #os.chdir(extractDir)
133    repo = Repository()
134    repo.checkout(options.releaseTag) # creates or overwrites extractDir
135    os.chdir(extractDir)
136    os.chdir('./madX')
137
138    for m in makefiles:
139
140        # do a make clean and remove any preexisting target
141        if os.path.exists('./madx'):
142            os.remove('./madx')
143            logger.log('remove preexisting ./madx executable')
144        else:
145            logger.log('no preexisting ./madx executable')
146        os.system('make clean')
147        logger.log("invoked 'make clean' at time "+(datetime.datetime.now()).ctime())
148
149        #print("now to compile "+m+" in " + os.getcwd())
150        if m == 'Makefile':
151            #invocation = "make f95=/opt/intel/Compiler/11.0/081/bin/ia32/ifort DEBUG=NO FORT_FMT_RECL=256 madx"
152            invocation = "make f95=ifort DEBUG=NO FORT_FMT_RECL=256 madx"
153        elif m == 'Makefile_develop':
154            invocation = "make f95=lf95 DEBUG=YES madx" # the Lahey Fortran compiler
155        elif m == 'Makefile_nag':
156            invocation = "make f95=f95 DEBUG=YES madx" # the NAG compiler
157        else:
158            raise("should never reach this point")
159        print "make invocation=",invocation
160        #notify('jean-luc','Point 3.2', 'makefile='+m)
161        output = "./makeResult"
162        #os.system(invocation)
163        startTime = (datetime.datetime.now()).ctime()
164        #notify('jean-luc','now in directory', 'os.getcwd()='+os.getcwd()+" at time"+(datetime.datetime.now()).ctime())             
165        #notify('jean-luc','Point 3.3', 'now to issue command='+invocation+">& "+output+" at time"+(datetime.datetime.now()).ctime())
166        logger.log('now located in '+os.getcwd())
167        logger.log('now to invoke command='+invocation+">& "+output+" at time "+(datetime.datetime.now()).ctime())
168
169        os.system(invocation+">& "+output)
170
171        endTime = (datetime.datetime.now()).ctime()
172
173        logger.log("compilation command completed at time : " + endTime)
174
175        f = open(output,'r')
176        lines = f.readlines()
177        f.close()
178        #notify('jean-luc','Point 4', '')
179        # if the target madx is absent, compilation failed
180        if os.path.exists('./madx'):
181            # success or warning
182            outcome = 'success' # for the time-being
183            outcome = lookForWarnings(lines)
184            executable = './madx_'+m # new name of the executable
185            shutil.copyfile('./madx',executable)
186            if os.path.exists(executable):
187                logger.log('.madx has been copied into '+executable+" under "+os.getcwd())
188            else:
189                logger.log("can't find executable "+executable+" which must have just been created")
190            os.chmod(executable,stat.S_IRWXU) # read, write, and execute permission by owner
191            logger.log("a ./madx executable was succesfully created at "+(datetime.datetime.now()).ctime())
192            # very important: grant execution rights to the script
193            #print("succesfully compiled for "+m)
194        else: # failure
195            outcome = 'failure'
196            compilationOK = False # overwrite
197            logger.log("missing ./madx executable")
198            #print("failed to compile for "+m)
199
200        b = Build(m,invocation,outcome)
201        #notify('jean-luc','Point 5', 'makefile='+m)
202        page = BuildWebPage(website+'/build_'+m+'_madx.htm',m,lines,outcome,startTime,endTime)
203        page.output()
204
205    #notify('jean-luc','Point 6', '')
206    globalEndTime = (datetime.datetime.now()).ctime()       
207    # create the main HTML page from which the three above HTML pages can be reached   
208    page = MainWebPage(website+'/build.htm',globalStartTime,globalEndTime,Build.builds)
209    page.output()
210
211    # Finally output the return status on stdout to be processed by the calling MadBuildAndTest.py
212    if not compilationOK:
213        notify('jean-luc','compilation failed','failed to compile release = '+options.releaseTag)
214    else:
215        notify('jean-luc','compilation succeeded','managed to compile last release = '+options.releaseTag)
216    print compilationOK
217
218    notify('jean-luc','reached the end of MadBuild.py','compilationOK=' + str(compilationOK))
219
220
221
222def lookForWarnings(lines): 
223    warningPattern = re.compile(r'[\s\t]*[\w\d_\-:]+[\s\t]+[Ww]arning(s?)')
224    for line in lines:
225        m = warningPattern.search(line)
226        if m:
227            if m.lastindex == 1:
228                return('warning')
229    return('success')
230       
231   
232
233class MainWebPage: # the main web page that lists all the outcomes for the successive builds
234   
235    def __init__(self,name,startTime,endTime,builds):
236        self.name = name
237        self.startTime = startTime
238        self.endTime = endTime
239        self.builds = builds # a list of Build objects
240
241    def header(self):
242        self.contents += '<DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">\n'
243        self.contents += '<html>\n'
244        self.contents += '<head>\n'
245        self.contents += '<title>MAD build result page</title>\n'
246        self.contents += '<link rel=stylesheet href="./MadTestWebStyle.css" type="text/css">\n'
247        self.contents += '</head>\n'
248       
249    def body(self):
250        self.contents += '<body>\n'
251        self.contents += 'Build started '+ self.startTime + ', ended  ' + self.endTime
252        self.contents += '<table>\n'     
253        for b in self.builds:
254            weblink = "build_"+b.name+"_madx.htm"
255            self.contents += '<tr class="'+b.outcome+'"><td>'+b.name+'</td><td>'+b.command+'</td><td><a href="'+weblink+'">'+b.outcome+'</a></td></tr>\n'
256        self.contents += '<table>\n'
257        self.contents += '<body>\n'
258
259    def footer(self):
260        self.contents += '</html>\n'
261
262    def output(self):
263        self.contents = ""
264        self.header()
265        self.body()
266        self.footer()
267        f = open(self.name,'w')
268        for c in self.contents:
269            f.write(c)
270        f.close()
271       
272    def display(self):
273        os.system('firefox ' + self.name+ '&')
274
275class BuildWebPage(MainWebPage):
276    def __init__(self,name,makefile,lines,returnStatus,startTime,endTime):
277        self.name = name
278        self.returnStatus = returnStatus
279        self.buildResult = lines
280        self.startTime = startTime
281        self.endTime = endTime
282        self.makefile = makefile
283
284    def header(self):
285        self.contents += '<DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">\n'
286        self.contents += '<html>\n'
287        self.contents += '<head>\n'
288        self.contents += '<title>MAD build main page</title>\n'
289        self.contents += '<link rel=stylesheet href="./MadTestWebStyle.css" type="text/css">\n'
290        self.contents += '</head>\n'
291
292    def body(self):
293        self.contents += '<body>\n'
294        self.contents += '<p>Build started '+self.startTime+', ended '+self.endTime+'</p>\n'
295        self.contents += '<table width="75%" border="0">\n'
296        # top coloured banner
297        self.contents += '<tr class='+self.returnStatus+'><td width="80%">Outcome of build process for \''+self.makefile+'\'</td><td width="20%">'+\
298                         self.returnStatus+"</td></tr>\n"
299        for l in self.buildResult:
300            self.contents += '<tr><td colspan="2">'+l.rstrip("\n")+'</td></tr>\n'
301        self.contents += "</table>\n"
302        self.contents += '</body>\n'       
303       
304if __name__ == "__main__":
305    main()
306
Note: See TracBrowser for help on using the repository browser.