1 | #!/usr/bin/python |
---|
2 | |
---|
3 | import re |
---|
4 | import os |
---|
5 | import sys |
---|
6 | import traceback |
---|
7 | import shutil |
---|
8 | import time |
---|
9 | |
---|
10 | import socket |
---|
11 | |
---|
12 | # public: |
---|
13 | |
---|
14 | def releaseForWindows(tag): # to be called by MadTrigRelease.pl |
---|
15 | try: |
---|
16 | client = windowsReleaseClient() |
---|
17 | client.release(tag) |
---|
18 | return 'success' |
---|
19 | except: |
---|
20 | exceptionType, exceptionValue, exceptionTraceback = sys.exc_info() |
---|
21 | traceback.print_tb(exceptionTraceback) |
---|
22 | return 'failure' |
---|
23 | |
---|
24 | # private: |
---|
25 | |
---|
26 | def getMonthAsString(monthInt): |
---|
27 | monthStrs = ['Jan','Fev','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'] |
---|
28 | monthStr = monthStrs[monthInt-1] |
---|
29 | return monthStr |
---|
30 | |
---|
31 | class windowsReleaseClient: |
---|
32 | |
---|
33 | def __init__(self): |
---|
34 | self.megabytes = 0 # the size of the binary |
---|
35 | self.version = 'undefined' # defined in release |
---|
36 | self.startTimeStr = '' # defined in remoteCompile() |
---|
37 | self.endTimeStr = ''# defined in remoteCompile() |
---|
38 | pass |
---|
39 | |
---|
40 | def extractSVN(self,tag): # populate /user/nougaret/MAD-X-WINDOWS |
---|
41 | |
---|
42 | currentDir = os.getcwd() |
---|
43 | |
---|
44 | os.chdir('/user/nougaret/MAD-X-WINDOWS') |
---|
45 | |
---|
46 | shutil.rmtree('madX',ignore_errors=True) # clean-up |
---|
47 | #cmd = 'cvs -d :gserver:isscvs.cern.ch:/local/reps/madx '+\ |
---|
48 | # 'checkout -r '+tag+' '+\ |
---|
49 | # 'madX' |
---|
50 | cmd = 'svn co svn+ssh://svn.cern.ch/reps/madx/tags/' +\ |
---|
51 | tag +'/madX'+ ' madX' |
---|
52 | print cmd |
---|
53 | os.system(cmd) |
---|
54 | os.chdir(currentDir) # back to initial location |
---|
55 | |
---|
56 | def remoteCompile(self): |
---|
57 | thisLinuxHost = socket.gethostname() |
---|
58 | windowsHost = 'abpc10788' # The remote host |
---|
59 | toWindowsHostPort = 7070 # The same port as used by the server |
---|
60 | #fromWindowsHostPort = 7071 |
---|
61 | s = None |
---|
62 | for res in socket.getaddrinfo(windowsHost, toWindowsHostPort,\ |
---|
63 | socket.AF_INET, socket.SOCK_STREAM): |
---|
64 | af, socktype, proto, canonname, sa = res |
---|
65 | try: |
---|
66 | s = socket.socket(af, socktype, proto) |
---|
67 | except socket.error, msg: |
---|
68 | s = None |
---|
69 | continue |
---|
70 | try: |
---|
71 | s.connect(sa) |
---|
72 | except socket.error, msg: |
---|
73 | s.close() |
---|
74 | s = None |
---|
75 | continue |
---|
76 | break |
---|
77 | if s is None: |
---|
78 | print 'could not open socket' |
---|
79 | sys.exit(1) |
---|
80 | s.send(thisLinuxHost+' asks: Compile MAD for Windows!') |
---|
81 | print('send compilation request to the Windows host...') |
---|
82 | startTime = time.localtime() |
---|
83 | self.startTimeStr = str(startTime.tm_mday)+' '+getMonthAsString(startTime.tm_mon)+\ |
---|
84 | ' '+str(startTime.tm_year)+ ' '+str(startTime.tm_hour)+':'+str(startTime.tm_min) |
---|
85 | data = s.recv(1024) # blocking on reception (what about the time out???) |
---|
86 | s.close() |
---|
87 | endTime = time.localtime() |
---|
88 | self.endTimeStr = str(endTime.tm_mday)+' '+getMonthAsString(endTime.tm_mon)+\ |
---|
89 | ' '+str(endTime.tm_year)+ ' '+str(endTime.tm_hour)+':'+str(endTime.tm_min) |
---|
90 | print 'Received', repr(data) |
---|
91 | |
---|
92 | def checkCompileOutcome(self): |
---|
93 | # look into MAD-X-WINDOWS and check whether a fresh madx.exe is present |
---|
94 | try: |
---|
95 | os.system('rm ./outfile') # if any |
---|
96 | except: |
---|
97 | pass |
---|
98 | os.system('ls -l /user/nougaret/MAD-X-WINDOWS/madX/madx.exe > ./outfile') |
---|
99 | f = open('./outfile','r') |
---|
100 | lines = f.readlines() |
---|
101 | f.close() |
---|
102 | os.system('rm ./outfile') |
---|
103 | if len(lines) != 1: |
---|
104 | raise('error trying to access ./outfile for checking madx.exe') |
---|
105 | else: |
---|
106 | singleLine = lines[0] |
---|
107 | pattern = re.compile(r'(\d+)[\s\t]+([\w\W]{3})[\s\t]+(\d{1,2})[\s\t]+(\d{2}):(\d{2})') |
---|
108 | m = pattern.search(singleLine) |
---|
109 | if m: |
---|
110 | size = float(m.group(1)) |
---|
111 | month = m.group(2) |
---|
112 | day = m.group(3) |
---|
113 | hour = m.group(4) # can be year if from last year, in which case 200X instead of xx:yy |
---|
114 | min = m.group(5) |
---|
115 | self.megabytes = size/1000000.0 # for subsequent use when generating HTML page |
---|
116 | print("size="+str(self.megabytes)+", month="+month+", day="+day+",hour="+hour+", min="+min) |
---|
117 | # compare with local time - should not be older than 5 minutes |
---|
118 | now = time.localtime() |
---|
119 | #monthStrs = ['Jan','Fev','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'] |
---|
120 | #monthStr = monthStrs[now.tm_mon-1] |
---|
121 | monthStr = getMonthAsString(now.tm_mon) |
---|
122 | print("now.tm_mon="+monthStr+", now.tm_day="+str(now.tm_mday)+\ |
---|
123 | ",now.tm_hour="+str(now.tm_hour)+", min="+str(now.tm_min)) |
---|
124 | print('monthStr='+monthStr+', month='+month+', now.tm_mday='+str(now.tm_mday)+', day='+day) |
---|
125 | if (monthStr==month) and (now.tm_mday==int(day)): |
---|
126 | # check if generated less than 5 minutes ago |
---|
127 | nowTotalMinutes = 60*(now.tm_hour) + now.tm_min # minutes elapsed since now |
---|
128 | totalMinutes = 60*int(hour) + int(min) # minutes elapsed since madx.exe created |
---|
129 | print("nowTotalMinutes="+str(nowTotalMinutes)+", totalMinutes="+str(totalMinutes)) |
---|
130 | print("differences in minutes="+str(nowTotalMinutes-totalMinutes)) |
---|
131 | if (nowTotalMinutes - totalMinutes)>5: |
---|
132 | raise('madx.exe is older than 5 minutes old. abort.') |
---|
133 | else: |
---|
134 | # done |
---|
135 | pass |
---|
136 | else: |
---|
137 | raise('madx.exe is too old. abort.') |
---|
138 | print("now year="+str(now.tm_year)+", month="+str(now.tm_mon)+\ |
---|
139 | ", day="+str(now.tm_mday)+", hour="+str(now.tm_hour)+", min="+str(now.tm_min)) |
---|
140 | else: |
---|
141 | raise('fail to match the date') |
---|
142 | pass |
---|
143 | print("completed checkCompileOutcome") |
---|
144 | # could also gather the executable size here |
---|
145 | |
---|
146 | |
---|
147 | def generateHtmlOutput(self): |
---|
148 | # move MAD-X fresh executable to the AFS web folder |
---|
149 | executablesAfsWebFolder = '/afs/cern.ch/user/n/nougaret/www/mad/windows-binaries' |
---|
150 | # (it has already been put into MAD-X-WINDOWS/madX by the Windows host) |
---|
151 | os.system('cp /user/nougaret/MAD-X-WINDOWS/madX/madx.exe '+\ |
---|
152 | executablesAfsWebFolder + '/madx.exe' ) # hard-coded! |
---|
153 | # now produce the HTML page (may be static actually) |
---|
154 | htmlFile = executablesAfsWebFolder + '/executables.htm' |
---|
155 | contents ='' |
---|
156 | contents += "<p>Version "+ self.version+" compiled with Intel ifort and Microsoft Visual C++:</p>\n"; |
---|
157 | contents += "<table width=\"75%\" border=\"0\">\n"; |
---|
158 | oddOrEven = 'even' # to colorize successive lines differently |
---|
159 | |
---|
160 | contents += "<tr class=\"odd\"><td>Download</td><td><a href=\"./madx.exe\">madx.exe</a></td><td>("+\ |
---|
161 | str(self.megabytes)+" Megabytes)</td><td>for the latest version.</td></tr>\n"; |
---|
162 | |
---|
163 | contents += "</table>\n" |
---|
164 | contents += "<p>Version 3.04.53 compiled with Lahey Fortran and accepting sequences with BV flag, as until March 2009:</p>\n" |
---|
165 | contents += "<table width=\"75%\" border=\"0\">\n" |
---|
166 | contents += "<tr class=\"even\"><td>Download</td><td><a href=\"./madx-old.exe\">madx-old.exe</a></td><td>(2.6132 Megabytes)</td><td>for the archived version, without PTC.</td></tr>\n" |
---|
167 | contents += "<tr class=\"odd\"><td>Download</td><td><a href=\"./madxp-old.exe\">madxp-old.exe</a></td><td>(6.7554 Megabytes)</td><td>for the archived version, including PTC.</td></tr>\n" |
---|
168 | contents += "</table>\n" |
---|
169 | |
---|
170 | # create web page in the correct AFS web folder location |
---|
171 | html = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">' |
---|
172 | html += "<html>\n" |
---|
173 | html += "<head>\n" |
---|
174 | html += "<title>MAD-X downloadable executables</title>\n" |
---|
175 | html += "<link rel=stylesheet href=\"../MadTestWebStyle.css\" type=\"text/css\">" # CSS one level up |
---|
176 | html += "</head>\n" |
---|
177 | html += "<!-- generated by Windows compilation script -->\n" |
---|
178 | html += "<body>\n" |
---|
179 | html += "<p>Windows compilation started "+self.startTimeStr+", ended "+self.endTimeStr+"</p>\n" |
---|
180 | html += contents |
---|
181 | html += "</body>\n" |
---|
182 | html += "</html>\n" |
---|
183 | |
---|
184 | htmlFile = executablesAfsWebFolder + '/executables.htm' |
---|
185 | f = open(htmlFile,'w') |
---|
186 | f.write(html) |
---|
187 | f.close() |
---|
188 | |
---|
189 | |
---|
190 | def release(self,tag): |
---|
191 | pattern = re.compile(r'^madX\-(\d+)_(\d+)_(\d+).*$') # pro, dev ok |
---|
192 | m = pattern.match(tag) |
---|
193 | if m: |
---|
194 | major = m.group(1) |
---|
195 | medium = m.group(2) |
---|
196 | minor = m.group(3) |
---|
197 | self.version = major + '.' + medium + '.' + minor |
---|
198 | else: |
---|
199 | raise('ill-formed release tag') |
---|
200 | # first extract the SVN on NFS |
---|
201 | self.extractSVN(tag) |
---|
202 | # then remote invoke compilation on the Windows machine |
---|
203 | self.remoteCompile() |
---|
204 | # control the outcome of the compilation |
---|
205 | self.checkCompileOutcome() |
---|
206 | # generate HTML information and link to the executable |
---|
207 | self.generateHtmlOutput() |
---|
208 | |
---|
209 | |
---|
210 | if __name__ == '__main__': |
---|
211 | |
---|
212 | if len(sys.argv) != 2: |
---|
213 | raise('expect exactly one argument: release tag') |
---|
214 | else: |
---|
215 | tag = sys.argv[1] |
---|
216 | print "/"+tag+"/" |
---|
217 | pattern = re.compile(r'^madX\-(\d+)_(\d+)_(\d+).+$') # pro, dev ok |
---|
218 | m = pattern.match(tag) |
---|
219 | if not m: |
---|
220 | raise('argument release-tag is ill-formed') |
---|
221 | |
---|
222 | outcome = releaseForWindows(tag) # the main function |
---|
223 | print outcome |
---|