1 | #!/usr/bin/env python |
---|
2 | # -*- coding: utf-8 -*- |
---|
3 | # __ _______ _____ |
---|
4 | # \ \ / / __ \| __ \ |
---|
5 | # \ V /| | | | |__) |_ __ _ _ |
---|
6 | # > < | | | | _ /| '_ \| | | | |
---|
7 | # / . \| |__| | | \ \| |_) | |_| | |
---|
8 | # /_/ \_\_____/|_| \_\ .__/ \__, | |
---|
9 | # | | __/ | |
---|
10 | # |_| |___/ |
---|
11 | |
---|
12 | """ |
---|
13 | |
---|
14 | XDR.py |
---|
15 | ------ |
---|
16 | |
---|
17 | Created by A. Dauptain and G Frichet |
---|
18 | |
---|
19 | Main generic tools for C3Sm interface |
---|
20 | Requires version 2.6.6 or later of python 2 |
---|
21 | Does not run with python 3 |
---|
22 | |
---|
23 | |
---|
24 | |
---|
25 | """ |
---|
26 | import sys |
---|
27 | if ((sys.hexversion < 0x020606F0) or |
---|
28 | (sys.hexversion > 0x030000A0)): |
---|
29 | raise Exception( |
---|
30 | "Must be run with python version at least 2.6.6, and not python 3\n" |
---|
31 | "Your version is %i.%i.%i" % sys.version_info[:3]) |
---|
32 | |
---|
33 | from xml.dom.minidom import * |
---|
34 | import xml.parsers.expat |
---|
35 | import time, os, subprocess, re, string,shutil |
---|
36 | import filecmp |
---|
37 | import fileinput |
---|
38 | import imp |
---|
39 | import codecs |
---|
40 | from itertools import izip |
---|
41 | import shlex |
---|
42 | |
---|
43 | import glob |
---|
44 | |
---|
45 | |
---|
46 | # Warnig cannot be importedblike this : |
---|
47 | #if we use xdrpy on distant locations, SAV will be missing |
---|
48 | #import SAV |
---|
49 | |
---|
50 | |
---|
51 | |
---|
52 | |
---|
53 | """ |
---|
54 | This library intends to provide methods to access and modify XML datasets read and written |
---|
55 | by C3Sm. |
---|
56 | Moreover, this library provides methods to deal with ascii files that might be read and written by external programs. |
---|
57 | |
---|
58 | There are two parts in this library : |
---|
59 | The first one is composed of high-level procedures. |
---|
60 | The second one is a set of classes used by the high-level procedures. |
---|
61 | Normal developers does not have to use them, even if they can !""" |
---|
62 | |
---|
63 | # _ _ _ _ _ _ |
---|
64 | #| | | (_) | | | | | | |
---|
65 | #| |__| |_ __ _| |__ | | _____ _____| | |
---|
66 | #| __ | |/ _` | '_ \ | |/ _ \ \ / / _ \ | |
---|
67 | #| | | | | (_| | | | | | | __/\ V / __/ | |
---|
68 | #|_| |_|_|\__, |_| |_| |_|\___| \_/ \___|_| |
---|
69 | # __/ | |
---|
70 | # |___/ |
---|
71 | |
---|
72 | def init(): |
---|
73 | """ |
---|
74 | This procedure initializes the XDR environment. |
---|
75 | It must be called at the beginning of every script using XDR. |
---|
76 | |
---|
77 | ==== Dev ===== |
---|
78 | This procedures creates an interface "dsin" for reading XML file "dataset.xml" produced by C3Sm |
---|
79 | It creates also a copy of this dataset "dsout", modifiable, to be read by C3Sm, "out_dataset.xml" |
---|
80 | It also stores useful paths (current directory at launch of the script (not to lose C3Sm) and script directory) |
---|
81 | """ |
---|
82 | |
---|
83 | global dsin |
---|
84 | global dsout |
---|
85 | global startingDir |
---|
86 | global scriptDir |
---|
87 | global verbose |
---|
88 | global OrigAppName |
---|
89 | global projectName |
---|
90 | |
---|
91 | global timestamp |
---|
92 | global COMMON_DIRECTORY,PREFIX,DIGIT_NUMBER |
---|
93 | |
---|
94 | |
---|
95 | verbose = 0 |
---|
96 | startingDir=os.getcwd() |
---|
97 | scriptDir=os.path.dirname(os.path.abspath(sys.modules['__main__'].__file__)) |
---|
98 | |
---|
99 | dsin=Dataset("dataset.xml") |
---|
100 | dsout=Dataset("dataset.xml") |
---|
101 | os.remove("dataset.xml") |
---|
102 | |
---|
103 | OrigAppName = dsout.getValue("name","solver","meta") |
---|
104 | projectName = dsout.getValue("name","project","meta") |
---|
105 | |
---|
106 | |
---|
107 | |
---|
108 | print "Local use of XDRpy for project ",projectName, "(",OrigAppName,")" |
---|
109 | |
---|
110 | |
---|
111 | print dsout.getValue("pluginsPath","engine","meta") |
---|
112 | # |
---|
113 | |
---|
114 | PREFIX = "RUN_" |
---|
115 | DIGIT_NUMBER = 3 |
---|
116 | COMMON_DIRECTORY = "COMMON" |
---|
117 | |
---|
118 | if OrigAppName == "none" : |
---|
119 | print "Warning : XDRpy unable to find the origin application" |
---|
120 | else : |
---|
121 | print "XDRpy running for application : ",OrigAppName |
---|
122 | COMMON_DIRECTORY = os.path.join(COMMON_DIRECTORY,OrigAppName.upper()) |
---|
123 | |
---|
124 | |
---|
125 | |
---|
126 | |
---|
127 | timestamp = time.time() |
---|
128 | |
---|
129 | return dsin,dsout |
---|
130 | |
---|
131 | def finish(a=0): |
---|
132 | """ |
---|
133 | This procedure closes the XDR environment. |
---|
134 | It must be called at the end of every script using XDR. |
---|
135 | |
---|
136 | ==== Dev ==== |
---|
137 | This procedure saves the output XML file and changes the directory to the initial one |
---|
138 | """ |
---|
139 | |
---|
140 | oldDir = os.getcwd() |
---|
141 | os.chdir(startingDir) |
---|
142 | if a != 0 : |
---|
143 | a.save2file("out_dataset.xml") |
---|
144 | else : |
---|
145 | try: |
---|
146 | dsout.save2file("out_dataset.xml") |
---|
147 | |
---|
148 | except NameError: |
---|
149 | pass |
---|
150 | |
---|
151 | def progress(percent,message): |
---|
152 | """ This function lets c3sm know progresse of the current script |
---|
153 | percent is the percentage of work done (0 < percent < 100) |
---|
154 | message is a little status written by the progressbar, it shouldn't be too long |
---|
155 | """ |
---|
156 | global timestamp |
---|
157 | |
---|
158 | time.sleep(0.1) |
---|
159 | newtime = time.time() |
---|
160 | |
---|
161 | print "%"+str(int(percent))+"%"+str(message) |
---|
162 | print '{0:2f}'.format(newtime-timestamp-0.1)+"s \n"+ str(int(percent))+"% "+str(message) |
---|
163 | sys.stdout.flush() |
---|
164 | timestamp=newtime |
---|
165 | |
---|
166 | |
---|
167 | def getDsin(): |
---|
168 | """ This procedure returns the Dataset object representing the input xml file """ |
---|
169 | try: |
---|
170 | return dsin |
---|
171 | except NameError: |
---|
172 | error("XDRError : XDR library must be initialized") |
---|
173 | |
---|
174 | |
---|
175 | def getDsout(): |
---|
176 | """ This procedure returns the Dataset object representing the current dataset """ |
---|
177 | try: |
---|
178 | return dsout |
---|
179 | except NameError: |
---|
180 | error("XDRError : XDR library must be initialized") |
---|
181 | |
---|
182 | |
---|
183 | def tryGetValue(default, key, *path): |
---|
184 | """ |
---|
185 | Search for the node "nodeName" with elements of "path" in its path and return its value |
---|
186 | If node doesn't exist, catch XDRnoNodeException end return the default value |
---|
187 | |
---|
188 | It would be cleaner to use "path" as a list, instead of "*path", but this would change all the geValue calls :( |
---|
189 | To be evaluated later |
---|
190 | """ |
---|
191 | return dsout.tryGetValue(default, key, *path) |
---|
192 | |
---|
193 | |
---|
194 | def getValue(key,*path): |
---|
195 | """ |
---|
196 | This procedure returns the value of a specified tag in the dataset. |
---|
197 | If more than one node have the same name, one or more parts of the path have to be specified. |
---|
198 | Ex : |
---|
199 | getValue("myParam") |
---|
200 | or |
---|
201 | getValue("myParam","parent","parent of parent") |
---|
202 | |
---|
203 | It would be cleaner to use "path" as a list, instead of "*path", but this would change all the geValue calls :( |
---|
204 | To be evaluated later |
---|
205 | """ |
---|
206 | return dsout.getValue(key,*path) |
---|
207 | |
---|
208 | |
---|
209 | def getListValue(key,*path): |
---|
210 | """ |
---|
211 | This procedure gets the asked value from the dataset and returns it as a list |
---|
212 | """ |
---|
213 | return dsout.getListValue(key,*path) |
---|
214 | |
---|
215 | |
---|
216 | def getIntegerValue(key,*path): |
---|
217 | """ |
---|
218 | This procedure returns an integer corresponding to the value of a specified tag in the dataset. |
---|
219 | If more than one node have the same name, one or more parts of the path have to be specified. |
---|
220 | """ |
---|
221 | return int(dsout.getValue(key,*path)) |
---|
222 | |
---|
223 | |
---|
224 | def getFloatValue(key,*path): |
---|
225 | """ |
---|
226 | This procedure returns a float corresponding to the value of a specified tag in the dataset. |
---|
227 | If more than one node have the same name, one or more parts of the path have to be specified. |
---|
228 | """ |
---|
229 | return float(dsout.getValue(key,*path)) |
---|
230 | |
---|
231 | |
---|
232 | def getChildrenName(nodeName,*path): |
---|
233 | """ |
---|
234 | This procedure returns a list of the name of all the children of the node named "nodeName". |
---|
235 | If more than one node has the same name, parts of its path can be specified as for the getValue method |
---|
236 | """ |
---|
237 | return dsout.getChildrenName(nodeName,*path) |
---|
238 | |
---|
239 | |
---|
240 | def setValue(value,nodeName,*path): |
---|
241 | """ |
---|
242 | This procedure modifies the node specify and set its value to "value" |
---|
243 | If more than one node has the same name, parts of its path can be specified as for the getValue method |
---|
244 | """ |
---|
245 | dsout.setValue(value,nodeName,*path) |
---|
246 | |
---|
247 | |
---|
248 | def nodeExists(nodeName,*path): |
---|
249 | """ |
---|
250 | This procedure checks if the node exists or not. It returns 1 if it exists, 0 if not |
---|
251 | """ |
---|
252 | return dsout.nodeExists(nodeName,*path) |
---|
253 | |
---|
254 | |
---|
255 | |
---|
256 | # |
---|
257 | # ______ _ |
---|
258 | #| ____| | | |
---|
259 | #| |__ __ _____ ___ _ _| |_ ___ |
---|
260 | #| __| \ \/ / _ \/ __| | | | __/ _ \ |
---|
261 | #| |____ > < __/ (__| |_| | || __/ |
---|
262 | #|______/_/\_\___|\___|\__,_|\__\___| |
---|
263 | # |
---|
264 | |
---|
265 | def execute(command, always_print_err=False, silent=True): |
---|
266 | """ |
---|
267 | This procedure searches for the specified executable in the script directory, if not, it tries to execute the command itself. |
---|
268 | The command is then executed and its output is printed in standard output |
---|
269 | """ |
---|
270 | ####### Need some work to handle long run and reading of the output on the fly ! |
---|
271 | if (os.path.exists(os.path.join(scriptDir,command))): |
---|
272 | command=os.path.join(scriptDir,command) |
---|
273 | print "command "+ command |
---|
274 | command=shlex.split(command) |
---|
275 | if silent == False : |
---|
276 | print "Executing " + repr(command) + ' in ' + repr(os.getcwd()) + ':\n' + 50*'-' + '\n' |
---|
277 | read_from = None |
---|
278 | if "<" in command : |
---|
279 | read_from = command[-1] |
---|
280 | command = command[:-2] |
---|
281 | p=subprocess.Popen(command,stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
---|
282 | if read_from: |
---|
283 | p.stdin.write(open(read_from, "r").read()) |
---|
284 | |
---|
285 | stdout_data = [] |
---|
286 | if silent == False : |
---|
287 | print "\nXDRExecute =============StdOut=================\n" |
---|
288 | while True: |
---|
289 | line = p.stdout.readline() |
---|
290 | if not line: |
---|
291 | break |
---|
292 | if silent == False : |
---|
293 | print 'XDRExecute ' + line.rstrip() |
---|
294 | sys.stdout.flush() |
---|
295 | stdout_data.append(line) |
---|
296 | returncode = p.wait() |
---|
297 | stderr_data = p.stderr.read() |
---|
298 | |
---|
299 | if ( always_print_err and not returncode ): |
---|
300 | if silent == False : |
---|
301 | print "\nXDRExecute =============StdErr=================\n" |
---|
302 | print 'XDRExecute ' + "\nXDRExecute ".join(stderr_data.split('\n')) |
---|
303 | # if traite "None" "0" False" "" Comme des retours negatif |
---|
304 | if returncode: |
---|
305 | error("Problem while running command :"+" ".join(command)+"\n=============StdErr=================\n"+stderr_data) |
---|
306 | return "".join(stdout_data) |
---|
307 | |
---|
308 | |
---|
309 | |
---|
310 | # |
---|
311 | # _____ _ |
---|
312 | # / ____| | | |
---|
313 | #| (___ ___| |__ |
---|
314 | # \___ \/ __| '_ \ |
---|
315 | # ____) \__ \ | | | |
---|
316 | #|_____/|___/_| |_| |
---|
317 | # |
---|
318 | |
---|
319 | def ssh_host(host, login): |
---|
320 | """reconstruct full host description""" |
---|
321 | full_host = host |
---|
322 | if host == None or host == "": |
---|
323 | error("SSH host unspecified") |
---|
324 | |
---|
325 | if login != None and login != "": |
---|
326 | full_host = login + '@' + host |
---|
327 | |
---|
328 | return full_host |
---|
329 | |
---|
330 | def ssh(host, login, command, options=""): |
---|
331 | """ Executes a command through SSH """ |
---|
332 | # TODO: check that we are on a platform were ssh actually exists |
---|
333 | full_host = ssh_host(host, login) |
---|
334 | |
---|
335 | output= execute("""ssh """ + options + """ """ + full_host + """ '"""+command+"""'""") |
---|
336 | return output |
---|
337 | |
---|
338 | def ssh_prepare_directory(host, login, distant_directory): |
---|
339 | """ Prepare (creates) a directory on a distant server """ |
---|
340 | # TODO: check that we are on a platform where ssh actually exists |
---|
341 | |
---|
342 | if len(distant_directory) == 0: |
---|
343 | error("Please specify a distant directory, for example : /home/toto/") |
---|
344 | |
---|
345 | if distant_directory[0] != '/' and distant_directory[0] != '~': |
---|
346 | error("Relative path given. Please specify an absolute path") |
---|
347 | |
---|
348 | print "Making sure distant directory is ready..." |
---|
349 | command = """mkdir -p """ + distant_directory |
---|
350 | ssh(host, login, command) |
---|
351 | |
---|
352 | def ssh_send(host, login, distant_directory, local_directories_list, options=""): |
---|
353 | """ Uploads files to a server using ssh. |
---|
354 | This creates a tar archive, and pipes it through ssh to a 'tar xf' on the distant side. |
---|
355 | In short, the command that we run is: |
---|
356 | tar cf - directory1 directory2 | ssh distant_server "tar xf - -C distant_directory" |
---|
357 | (with some additional safety) |
---|
358 | """ |
---|
359 | # TODO: check that we are on a platform where tar, scp, ssh actually exist |
---|
360 | |
---|
361 | # TODO: Check that local_directories_list is actually a list. |
---|
362 | # People will try with string, and it does bad things with strings. |
---|
363 | |
---|
364 | full_host = ssh_host(host, login) |
---|
365 | |
---|
366 | if (len(local_directories_list) == 0): |
---|
367 | print "No directories to be sent" |
---|
368 | return |
---|
369 | |
---|
370 | |
---|
371 | print "Sending and extracting archive..." |
---|
372 | |
---|
373 | # Decomposition |
---|
374 | # Bash : passage en bash |
---|
375 | # -c :(...) |
---|
376 | # tar cvf : compresse |
---|
377 | # local directoryes_list (liste de tous les rep a envoyer) |
---|
378 | # - : vers le pipe |
---|
379 | # | : pipe |
---|
380 | # ssh mylogin@host - |
---|
381 | # \:(...) |
---|
382 | # tarc xv : decompresse |
---|
383 | # - depuis le pipe |
---|
384 | # -C:(...) |
---|
385 | # distant directory : Dans la directory distante |
---|
386 | # \ :(...) |
---|
387 | |
---|
388 | command = """bash -c "tar cvf - """ + (" ".join(local_directories_list)) + """ | ssh """ + full_host + """ \\\"tar xf - -C """ + distant_directory + """\\\" " """ |
---|
389 | #print "ssh_send command ",command |
---|
390 | execute(command,always_print_err=True) |
---|
391 | |
---|
392 | def ssh_retrieve(host, login, distant_directory, directory, options=""): |
---|
393 | """ Transfers files from a server using ssh. |
---|
394 | This is the opposite of ssh_send, except it operates on a single directory. |
---|
395 | """ |
---|
396 | # TODO: check that we are on a platform where scp actually exists |
---|
397 | full_host = ssh_host(host, login) |
---|
398 | |
---|
399 | |
---|
400 | # M RIVIERE Solution -Deprecated- ( Il y a pb non resolu dedans) |
---|
401 | |
---|
402 | # Decomposition |
---|
403 | # Bash : passage en bash |
---|
404 | # -c : interprete la chaine de caractÚres suivante |
---|
405 | # ssh mylogin@host - |
---|
406 | # \:(...) |
---|
407 | # tar cvf : compresse |
---|
408 | # - : vers le pipe |
---|
409 | # -C:(...) |
---|
410 | # distant directory |
---|
411 | # local directory |
---|
412 | # \ :(...) |
---|
413 | # | : pipe |
---|
414 | # tarc xvf : decompresse |
---|
415 | # - depuis le pipe |
---|
416 | #command = """bash -c "ssh """ + full_host + """ \' tar cvf - -C """ + distant_directory + """ """ + directory + """\\\" | tar xvf -" """ |
---|
417 | |
---|
418 | # G DEJEAN Sokution |
---|
419 | # Decomposition |
---|
420 | # Bash : passage en bash |
---|
421 | # -c : interprete la chaine de caractÚres suivante |
---|
422 | # ssh mylogin@host |
---|
423 | # ' |
---|
424 | # cd distant directory: |
---|
425 | # tar cvf : compresse |
---|
426 | # - : vers le pipe |
---|
427 | # . : le repretoire courant |
---|
428 | # ' |
---|
429 | # | : pipe |
---|
430 | # tar -x vf : decompresse |
---|
431 | # -C local directory : en renommant le repertoire |
---|
432 | # -vf : |
---|
433 | # - :depuis le pipe |
---|
434 | command = """bash -c " ssh """ + full_host + """ 'cd """+ distant_directory + """; tar cvf - .'| tar -x -C """ +directory+""" -vf - " """ |
---|
435 | |
---|
436 | print "ssh_retrieve command ",command |
---|
437 | execute(command,always_print_err=True) |
---|
438 | |
---|
439 | |
---|
440 | def ssh_cleanup_directory(host, login, distant_directory, directory): |
---|
441 | """ Remove a directory on distant ssh server """ |
---|
442 | print "Cleaning up distant files..." |
---|
443 | command = """rm -rf """ + distant_directory + """/""" + directory |
---|
444 | ssh(host, login, command) |
---|
445 | |
---|
446 | def tar(file, filelist): |
---|
447 | """ Create an archive from a list of files """ |
---|
448 | # TODO: Windows support ? Use pkgfile.py or something ? |
---|
449 | execute("tar cvf " + file + " " + " ".join(filelist)) |
---|
450 | |
---|
451 | |
---|
452 | |
---|
453 | def error(txt): |
---|
454 | """ |
---|
455 | This procedure stops the script and make sure to say it to C3Sm |
---|
456 | """ |
---|
457 | try : |
---|
458 | dsout.setValue("0","scriptSuccess","meta") |
---|
459 | except NameError: |
---|
460 | pass |
---|
461 | print "Error : "+txt |
---|
462 | finish() |
---|
463 | exit() |
---|
464 | |
---|
465 | |
---|
466 | def verbose(): |
---|
467 | """ This procedure activates verbosing for the library""" |
---|
468 | global verbose |
---|
469 | verbose = 1 |
---|
470 | print "Verbose activated ... ("+str(verbose)+") " |
---|
471 | |
---|
472 | |
---|
473 | def getScriptDir(): |
---|
474 | """ This accessor returns the value of the script directory for the current solver""" |
---|
475 | global scriptDir |
---|
476 | return scriptDir |
---|
477 | |
---|
478 | def getCommonDir(): |
---|
479 | """ This accessor returns the value of the script directory for the current solver""" |
---|
480 | global COMMON_DIRECTORY |
---|
481 | return COMMON_DIRECTORY |
---|
482 | |
---|
483 | |
---|
484 | # |
---|
485 | # _____ _ _ |
---|
486 | #| __ \ | | | | |
---|
487 | #| | | | __ _| |_ __ _ ___ ___| |_ |
---|
488 | #| | | |/ _` | __/ _` / __|/ _ \ __| |
---|
489 | #| |__| | (_| | || (_| \__ \ __/ |_ |
---|
490 | #|_____/ \__,_|\__\__,_|___/\___|\__| |
---|
491 | # |
---|
492 | |
---|
493 | class Dataset: |
---|
494 | """ This class defines a reader for XML files written by C3Sm. |
---|
495 | Specifying a XML file, the XDR interface stores the dataset and |
---|
496 | implements several methods to access values and structures of the dataset""" |
---|
497 | |
---|
498 | def __init__(self,xmlfile): |
---|
499 | """ XDR constructor : it needs a XML file from C3Sm """ |
---|
500 | self._xmlFile=xmlfile |
---|
501 | try : |
---|
502 | self._dom=parse(self._xmlFile) |
---|
503 | except IOError: |
---|
504 | error("XDRError : Problem with file system, check that permissions and free space are ok.\n"+xmlfile+" couldn't be read") |
---|
505 | except xml.parsers.expat.ExpatError , err: |
---|
506 | print err |
---|
507 | XMLfile = open(self._xmlFile,"r").read().split("\n") |
---|
508 | print "--> "+XMLfile[err.lineno+1] |
---|
509 | print " "*(4+err.offset)+"^" |
---|
510 | |
---|
511 | |
---|
512 | error("XDRError : Xml file from c3sm wasn't correct xml, please check that you have enough free space and you have the last version of C3Sm. Otherwise, please send dataset.xml from your project directory to C3Sm team") |
---|
513 | self._root=self._dom.documentElement |
---|
514 | self._currentNode=self._root |
---|
515 | self._outputFile="" |
---|
516 | |
---|
517 | def __repr__(self): |
---|
518 | return self._printNode() |
---|
519 | |
---|
520 | def _printNode (self, sep=''): |
---|
521 | """ This private method is a recursive method to describe the content of the dataset for debugging purpose""" |
---|
522 | desc="" |
---|
523 | node=self._currentNode |
---|
524 | if node.nodeType == 1: |
---|
525 | desc+= sep+node.nodeName+ ' >> ' |
---|
526 | for cle,valeur in node.attributes.items(): |
---|
527 | desc+= ' '+valeur+' ' |
---|
528 | desc+="\n" |
---|
529 | for child in node.childNodes: |
---|
530 | self._currentNode=child |
---|
531 | desc+=self._printNode(sep+' ') |
---|
532 | self._currentNode=node |
---|
533 | return desc |
---|
534 | |
---|
535 | def _getTags(self,tagList): |
---|
536 | node=self._currentNode |
---|
537 | if node.nodeType == 1: |
---|
538 | tagList.append(node.nodeName) |
---|
539 | for child in node.childNodes: |
---|
540 | self._currentNode=child |
---|
541 | tagList = self._getTags(tagList) |
---|
542 | self._currentNode=node |
---|
543 | return tagList |
---|
544 | |
---|
545 | def _getNode(self,key,*path): |
---|
546 | try: |
---|
547 | return self._searchNode(key,*path) |
---|
548 | except XDRtooManyNodesException, e: |
---|
549 | solverNode = self.getValue("callingAddress","action","meta") |
---|
550 | solverNode= solverNode.split(".")[1] |
---|
551 | return self._searchNode(key,solverNode,*path) |
---|
552 | |
---|
553 | def _searchNode(self,key,*path): |
---|
554 | """ This private method needs a key to search a node with name=key |
---|
555 | If no node is found, an Exception is raisen |
---|
556 | If one node is found, an Element is returned |
---|
557 | If more than one node is, the most relevant one (according to path) is chosen and returned as an Element |
---|
558 | |
---|
559 | path is a list of keyword""" |
---|
560 | |
---|
561 | if not isinstance(key,basestring) : |
---|
562 | raise XDRillFormed("XDRError : the type of key ", key , "is ", type(key), "instead of a basestring") |
---|
563 | |
---|
564 | result=self._dom.getElementsByTagName(key) |
---|
565 | if result.length==0: |
---|
566 | raise XDRnoNodeException("XDRError : no node found with key "+str(key)+" and path containing "+str(path)) |
---|
567 | else : |
---|
568 | resultToDel=[] |
---|
569 | for i,elt in enumerate(result): |
---|
570 | address=self._getAddress(elt) |
---|
571 | for eltPath in path: |
---|
572 | if eltPath not in address: |
---|
573 | resultToDel.append(i) |
---|
574 | break |
---|
575 | #Now, the result should be one item long, if not there is a problem |
---|
576 | # Raising XDRnoNodeException or XDRtooManyNodesException |
---|
577 | resultToDel.sort(reverse=True) |
---|
578 | for i in resultToDel: |
---|
579 | del result[i] |
---|
580 | |
---|
581 | if result.length == 1: |
---|
582 | return result[0] |
---|
583 | elif result.length == 0: |
---|
584 | raise XDRnoNodeException("XDRError : no node found with key "+str(key)+" and path containing "+str(path)) |
---|
585 | else: |
---|
586 | |
---|
587 | errMsg = "XDRError :"+str(result.length)+" nodes found with key '"+str(key)+"' and path "+str(path)+" :\n" |
---|
588 | for elt in result: |
---|
589 | errMsg += str(self._getAddress(elt))+"\n" |
---|
590 | raise XDRtooManyNodesException(errMsg) |
---|
591 | |
---|
592 | def _getAddress(self,node): |
---|
593 | """ This private method constructs the address of a node in the DOM""" |
---|
594 | parents=list() |
---|
595 | |
---|
596 | security=100 |
---|
597 | while (node.nodeName != '#document'): |
---|
598 | security-=1 |
---|
599 | if security==0: |
---|
600 | raise Exception("Infinite loop while searching for all the parents ...") |
---|
601 | |
---|
602 | parents.insert(0,node.nodeName) |
---|
603 | node=node.parentNode |
---|
604 | return parents |
---|
605 | |
---|
606 | def addChild(self,nodeName,value,fatherName,*path): |
---|
607 | """ |
---|
608 | This method adds a child named nodeName to fatherName |
---|
609 | It also sets attribute "value" to value |
---|
610 | It returns the createdNode |
---|
611 | """ |
---|
612 | fatherNode = self._getNode(fatherName,*path) |
---|
613 | newNode = self._dom.createElement(nodeName) |
---|
614 | |
---|
615 | newNode = fatherNode.appendChild(newNode) |
---|
616 | if value != "": |
---|
617 | newNode.setAttribute("value", value) |
---|
618 | return newNode |
---|
619 | |
---|
620 | def addMultipleChild(self,value,fatherName,*path): |
---|
621 | """ |
---|
622 | This methods adds a child to a multiple node to fatherName |
---|
623 | It also sets attribute "value" to value |
---|
624 | It returns the createdNode name |
---|
625 | """ |
---|
626 | |
---|
627 | # Retrieve next "item" number |
---|
628 | tagList= [] |
---|
629 | tagList = self._getTags(tagList) |
---|
630 | itemList=[] |
---|
631 | |
---|
632 | for item in tagList: |
---|
633 | p=re.compile("^item_\d+$") |
---|
634 | if p.search(item): |
---|
635 | itemList.append(int(item.split("_")[1])) |
---|
636 | |
---|
637 | itemList.sort() |
---|
638 | try: |
---|
639 | nextItem = "item_"+str(itemList[-1]+1) |
---|
640 | except IndexError: |
---|
641 | nextItem = "item_1" |
---|
642 | |
---|
643 | self.addChild(nextItem,value,fatherName,*path) |
---|
644 | |
---|
645 | return nextItem |
---|
646 | |
---|
647 | def nodeExists(self,nodeName,*path): |
---|
648 | """ |
---|
649 | This method tests if the node exists |
---|
650 | """ |
---|
651 | try : |
---|
652 | self._getNode(nodeName,*path) |
---|
653 | except XDRnoNodeException: |
---|
654 | return 0 |
---|
655 | else: |
---|
656 | return 1 |
---|
657 | |
---|
658 | def tryGetValue(self, default, nodeName, *path): |
---|
659 | """ |
---|
660 | Search for the node "nodeName" with elements of "path" in its path and return its value |
---|
661 | If node doesn't exist, use "default" for value |
---|
662 | |
---|
663 | It would be cleaner to use "path" as a list, instead of "*path", but this would change all the geValue calls :( |
---|
664 | To be evaluated later |
---|
665 | """ |
---|
666 | |
---|
667 | if not isinstance(default,basestring) : |
---|
668 | raise XDRillFormed("XDRError : the type of default ", default , "is ", type(default), "instead of a basestring") |
---|
669 | |
---|
670 | try : |
---|
671 | result = self.getValue(nodeName,*path) |
---|
672 | except XDRnoNodeException: |
---|
673 | result = default |
---|
674 | print "Note : Could not find node \"", nodeName, " \" for path" , path ,". Using default value :", default |
---|
675 | return result |
---|
676 | |
---|
677 | def getValue(self,nodeName,*path): |
---|
678 | """ |
---|
679 | Search for the node "nodeName" with elements of "path" in its path and return its value |
---|
680 | If node doesn't exist, XDRnoNodeException will be raised |
---|
681 | |
---|
682 | It would be cleaner to use "path" as a list, instead of "*path", but this would change all the geValue calls :( |
---|
683 | To be evaluated later |
---|
684 | """ |
---|
685 | node = self._getNode(nodeName, *path) |
---|
686 | return node.getAttribute("value").encode("utf-8") |
---|
687 | |
---|
688 | def getListValue(self, key, *path): |
---|
689 | """ |
---|
690 | This procedure gets the asked value from the dataset and returns it as a list |
---|
691 | """ |
---|
692 | result = self.getValue(key, *path).split(';') |
---|
693 | |
---|
694 | return result |
---|
695 | |
---|
696 | def setValue(self,value,nodeName,*path): |
---|
697 | """ |
---|
698 | This method searches for the node "nodeName" with elements of "path" in its path and change its value to "value" |
---|
699 | If the value is a python list, it's converted into a Tcl list |
---|
700 | """ |
---|
701 | |
---|
702 | if isinstance(value,list): |
---|
703 | value2=[] |
---|
704 | for elt in value: |
---|
705 | value2.append(str(elt).strip()) |
---|
706 | value=";".join(value2) |
---|
707 | |
---|
708 | try : |
---|
709 | node=self._getNode(nodeName, *path) |
---|
710 | node.setAttribute("value",str(value)) |
---|
711 | except : |
---|
712 | print "Note : Could not find node \"", nodeName, " \" for path" , path ,". skipping setValue" |
---|
713 | |
---|
714 | |
---|
715 | def getChildrenName(self,nodeName,*path): |
---|
716 | """ |
---|
717 | This method returns a list of the name of all the children of the node named "nodeName". |
---|
718 | If more than one node has the same name, parts of its path can be specified as for the getValue method |
---|
719 | """ |
---|
720 | try: |
---|
721 | node=self._getNode(nodeName, *path) |
---|
722 | except XDRnoNodeException: |
---|
723 | return "" |
---|
724 | |
---|
725 | #result=list() |
---|
726 | result=[child.nodeName for child in node.childNodes if child.nodeType == 1] |
---|
727 | #result.append(child.nodeName) |
---|
728 | |
---|
729 | return result |
---|
730 | |
---|
731 | def removeNode(self,nodeName,*path): |
---|
732 | """ |
---|
733 | This method removes the node named "nodeName". |
---|
734 | If more than one node has the same name, parts of its path can be specified as for the getValue method |
---|
735 | """ |
---|
736 | node=self._getNode(nodeName,*path) |
---|
737 | parent = node.parentNode |
---|
738 | parent.removeChild(node) |
---|
739 | |
---|
740 | def save2file(self,fileName): |
---|
741 | """ |
---|
742 | This method save the dataset in C3Sm XML format |
---|
743 | """ |
---|
744 | try: |
---|
745 | f=codecs.open(fileName,"w","utf-8") |
---|
746 | self._dom.writexml(f,addindent=" ",encoding="utf-8") |
---|
747 | f.close() |
---|
748 | except IOError: |
---|
749 | error("XDRError : could not save XML content to file "+fileName+" from "+os.getcwd()+". Check path, permissions and disk space.") |
---|
750 | |
---|
751 | |
---|
752 | |
---|
753 | # |
---|
754 | # _ _ ______ _ _ |
---|
755 | # /\ (_|_) ____(_) | |
---|
756 | # / \ ___ ___ _ _| |__ _| | ___ ___ |
---|
757 | # / /\ \ / __|/ __| | | __| | | |/ _ \/ __| |
---|
758 | # / ____ \\__ \ (__| | | | | | | __/\__ \ |
---|
759 | #/_/ \_\___/\___|_|_|_| |_|_|\___||___/ |
---|
760 | # |
---|
761 | # |
---|
762 | |
---|
763 | |
---|
764 | class WriteAsciiFile: |
---|
765 | """ |
---|
766 | This class allows developers to easily write informations to ASCII files |
---|
767 | It provides writing methods |
---|
768 | """ |
---|
769 | def __init__(self,fileName): |
---|
770 | """ |
---|
771 | This constructor open "fileName" |
---|
772 | """ |
---|
773 | self._outputFile=open(fileName,"w") |
---|
774 | |
---|
775 | def write(self,str): |
---|
776 | """ |
---|
777 | This method write the string "str" in the file |
---|
778 | """ |
---|
779 | self._outputFile.write(str) |
---|
780 | def writeLine(self,line): |
---|
781 | """ |
---|
782 | This method write the string "str" followed by "\n" in the file |
---|
783 | """ |
---|
784 | self._outputFile.write(line+"\n") |
---|
785 | |
---|
786 | def close(self): |
---|
787 | self._outputFile.close() |
---|
788 | del self |
---|
789 | |
---|
790 | |
---|
791 | |
---|
792 | |
---|
793 | |
---|
794 | class ReadAsciiFile: |
---|
795 | """ This class provides methods to read and parse ascii files""" |
---|
796 | def __init__(self,fileName): |
---|
797 | try: |
---|
798 | self._inputFile=open(fileName,"r") |
---|
799 | except IOError: |
---|
800 | print "XDRError :\nThe file "+fileName+" has not been found\nPlease check that the command supposed to create it is working well\n===============" |
---|
801 | self._content=self._inputFile.read() |
---|
802 | self._contentList=self._content.split('\n') |
---|
803 | self._inputFile.close() |
---|
804 | |
---|
805 | |
---|
806 | def __iter__(self): |
---|
807 | return self._contentList.__iter__() |
---|
808 | |
---|
809 | def getContent(self): |
---|
810 | """ |
---|
811 | This method returns the content of the file |
---|
812 | """ |
---|
813 | return self._content |
---|
814 | |
---|
815 | |
---|
816 | # |
---|
817 | # _____ _ _ |
---|
818 | #| __ \ | | (_) |
---|
819 | #| |__) | _ _ __ ___ _ __ ___ _ __ __ _| |_ _ ___ _ __ ___ |
---|
820 | #| _ / | | | '_ \ / _ \| '_ \ / _ \ '__/ _` | __| |/ _ \| '_ \/ __| |
---|
821 | #| | \ \ |_| | | | | | (_) | |_) | __/ | | (_| | |_| | (_) | | | \__ \ |
---|
822 | #|_| \_\__,_|_| |_| \___/| .__/ \___|_| \__,_|\__|_|\___/|_| |_|___/ |
---|
823 | # | | |
---|
824 | # |_| |
---|
825 | # |
---|
826 | def getRunsList(): |
---|
827 | """ This function returns a list containing the directories which are considered as runs |
---|
828 | """ |
---|
829 | # Retrieve list of element in current directory |
---|
830 | listElt = os.listdir(".") |
---|
831 | listDir = [] |
---|
832 | for elt in listElt: |
---|
833 | if os.path.isdir(elt): |
---|
834 | # The element is a directory |
---|
835 | p=re.compile('^'+PREFIX+'\d{'+str(DIGIT_NUMBER)+'}$') |
---|
836 | if p.search(elt): |
---|
837 | # The directory is detected as a run |
---|
838 | listDir.append(elt) |
---|
839 | listDir.sort() |
---|
840 | return listDir |
---|
841 | |
---|
842 | def getCurrentRun(): |
---|
843 | """ This function analyses the directories in the current directory and return the name of the directory corresponding to the last "run" |
---|
844 | """ |
---|
845 | |
---|
846 | # Retrieve runs list |
---|
847 | listDir = getRunsList() |
---|
848 | |
---|
849 | |
---|
850 | # Sorting the list to get the last element |
---|
851 | listDir.sort() |
---|
852 | if len(listDir) == 0: |
---|
853 | return createNewRun() |
---|
854 | return listDir[-1] |
---|
855 | |
---|
856 | def goIntoCurrentRun(): |
---|
857 | """ This function changes directory to go into current run directory, if no run director is present, then it creates RUN001 and goes into it |
---|
858 | """ |
---|
859 | currentRun = getCurrentRun() |
---|
860 | |
---|
861 | if currentRun == "": |
---|
862 | currentRun = createNewRun() |
---|
863 | |
---|
864 | os.chdir(currentRun) |
---|
865 | |
---|
866 | |
---|
867 | def formatRunNumber(int): |
---|
868 | """ This function formats int to be correct towards the defined format for run number |
---|
869 | """ |
---|
870 | formatter ="%(#)0"+str(DIGIT_NUMBER)+"d" |
---|
871 | return formatter % {"#" : int} |
---|
872 | |
---|
873 | def createNewRun(): |
---|
874 | """ This function creates a new directory following the last detected run. |
---|
875 | It returns the name of the newly created folder |
---|
876 | """ |
---|
877 | # Retrieve runs list |
---|
878 | listDir = getRunsList() |
---|
879 | |
---|
880 | # Sorting the list to get the last element |
---|
881 | listDir.sort() |
---|
882 | if len(listDir) == 0: |
---|
883 | lastRun = "" |
---|
884 | else: |
---|
885 | lastRun = listDir[-1] |
---|
886 | |
---|
887 | |
---|
888 | #formatter = '{0:0='+str(DIGIT_NUMBER)+'d}' |
---|
889 | if lastRun == "" : |
---|
890 | #nextRunNumber = formatter.format(1) |
---|
891 | nextRunNumber = formatRunNumber(1) |
---|
892 | else: |
---|
893 | p=re.compile('^'+PREFIX+'(\d{'+str(DIGIT_NUMBER)+'})$') |
---|
894 | m = p.search(lastRun) |
---|
895 | if m: |
---|
896 | #nextRunNumber = formatter.format(int(m.group(1))+1) |
---|
897 | nextRunNumber = formatRunNumber(int(m.group(1))+1) |
---|
898 | else: |
---|
899 | print("XDRError : Return from getLastRun function is not well formatted, contact C3Sm team ...") |
---|
900 | |
---|
901 | nextRun = PREFIX+nextRunNumber |
---|
902 | os.mkdir(nextRun) |
---|
903 | return nextRun |
---|
904 | |
---|
905 | def createNewRunFromLastRun(): |
---|
906 | """ This function creates a new directory following the last detected run and duplicate its content |
---|
907 | It returns the name of the newly created folder |
---|
908 | """ |
---|
909 | # Retrieve runs list |
---|
910 | listDir = getRunsList() |
---|
911 | |
---|
912 | # Sorting the list to get the last element |
---|
913 | listDir.sort() |
---|
914 | if len(listDir) == 0: |
---|
915 | lastRun = "" |
---|
916 | else: |
---|
917 | lastRun = listDir[-1] |
---|
918 | |
---|
919 | |
---|
920 | #formatter = '{0:0='+str(DIGIT_NUMBER)+'d}' |
---|
921 | if lastRun == "" : |
---|
922 | #nextRunNumber = formatter.format(1) |
---|
923 | nextRunNumber = formatRunNumber(1) |
---|
924 | nextRun = PREFIX+nextRunNumber |
---|
925 | os.mkdir(nextRun) |
---|
926 | else: |
---|
927 | p=re.compile('^'+PREFIX+'(\d{'+str(DIGIT_NUMBER)+'})$') |
---|
928 | m = p.search(lastRun) |
---|
929 | if m: |
---|
930 | #nextRunNumber = formatter.format(int(m.group(1))+1) |
---|
931 | nextRunNumber = formatRunNumber(int(m.group(1))+1) |
---|
932 | nextRun = PREFIX+nextRunNumber |
---|
933 | shutil.copytree(lastRun, nextRun) |
---|
934 | else: |
---|
935 | print("XDRError : Return from getLastRun function is not well formatted, contact C3Sm team ...") |
---|
936 | |
---|
937 | |
---|
938 | return nextRun |
---|
939 | |
---|
940 | |
---|
941 | |
---|
942 | |
---|
943 | |
---|
944 | |
---|
945 | |
---|
946 | |
---|
947 | def saveDatasetInCurrentRun(): |
---|
948 | """ This function saves the current dataset in the last known run. |
---|
949 | In order to use this function, you must have initialized the XDR library |
---|
950 | """ |
---|
951 | if "XDR" not in sys.modules: |
---|
952 | raise Exception("XDRError : XDR library is not loaded") |
---|
953 | |
---|
954 | try : |
---|
955 | dsout = getDsout() |
---|
956 | except NameError: |
---|
957 | dsout = XDR.dsout() |
---|
958 | |
---|
959 | currentRun = getCurrentRun() |
---|
960 | dsout.save2file(os.path.join(".",currentRun,currentRun+".xml")) |
---|
961 | |
---|
962 | |
---|
963 | def copyFileInLocalProject(path,tgt_dir="COMMON"): |
---|
964 | """ This function copy the file path into the common directory. |
---|
965 | If the file already exists, it compares the two files and rename the new one if they are different |
---|
966 | It finally returns the new path |
---|
967 | """ |
---|
968 | global COMMON_DIRECTORY,OrigAppName |
---|
969 | |
---|
970 | |
---|
971 | |
---|
972 | if tgt_dir == "COMMON" : |
---|
973 | tgt_dir = COMMON_DIRECTORY |
---|
974 | ensureDirectory(COMMON_DIRECTORY,clean=False) |
---|
975 | else : |
---|
976 | ensureDirectory(tgt_dir,clean=False) |
---|
977 | |
---|
978 | tgt_dir = os.path.relpath(tgt_dir,os.getcwd()) |
---|
979 | |
---|
980 | |
---|
981 | |
---|
982 | |
---|
983 | # Checking if original path exists |
---|
984 | if not(os.path.exists(path) == True and os.path.isfile(path)): |
---|
985 | msgerr = "XDRError : the file "+path+" can't be accessed" |
---|
986 | error(msgerr) |
---|
987 | |
---|
988 | # Checking existence of file in COMMON |
---|
989 | dirName,fileName = os.path.split(path) |
---|
990 | |
---|
991 | |
---|
992 | newPath = os.path.join(tgt_dir,fileName) |
---|
993 | |
---|
994 | |
---|
995 | if fileName in os.listdir(tgt_dir): |
---|
996 | # The file already exists |
---|
997 | print "This file already exists in "+tgt_dir |
---|
998 | |
---|
999 | # Checking equality |
---|
1000 | if filecmp.cmp(path,newPath): |
---|
1001 | print "File equal, skipping copy..." |
---|
1002 | |
---|
1003 | else: |
---|
1004 | print "Warning : File differ, previous file will be ecrased (ha ha ha)..." |
---|
1005 | print "Copying "+path +" in "+newPath |
---|
1006 | shutil.copy(path,newPath) |
---|
1007 | else : |
---|
1008 | print "Copying "+path +" in "+newPath |
---|
1009 | shutil.copy(path,newPath) |
---|
1010 | return newPath |
---|
1011 | |
---|
1012 | |
---|
1013 | |
---|
1014 | def copyFileFromDatasetInLocalProject(key,*path): |
---|
1015 | """ This function retrieves the path from the field identified by key and path (see getValue() ) |
---|
1016 | It copies the file from the retrieved path into the common directory. |
---|
1017 | If the file already exists, it compares the two files and rename the new one if they are different |
---|
1018 | The function then update the field defined by key and path |
---|
1019 | """ |
---|
1020 | originalPath = getValue(key,*path) |
---|
1021 | |
---|
1022 | newPath = copyFileInLocalProject(originalPath) |
---|
1023 | |
---|
1024 | setValue(newPath,key,*path) |
---|
1025 | return newPath |
---|
1026 | |
---|
1027 | def createFileInCurrentRun(fileName,fileContent): |
---|
1028 | """ This function creates a new file named fileName in current run and writes fileContent into it |
---|
1029 | """ |
---|
1030 | |
---|
1031 | currentRun = getCurrentRun() |
---|
1032 | |
---|
1033 | if currentRun == "" : |
---|
1034 | currentRun = createNewRun() |
---|
1035 | |
---|
1036 | filePath = os.path.join(".",currentRun,fileName) |
---|
1037 | f = open(filePath,"w") |
---|
1038 | f.write(fileContent) |
---|
1039 | f.close() |
---|
1040 | |
---|
1041 | return filePath |
---|
1042 | |
---|
1043 | |
---|
1044 | # |
---|
1045 | #_____ _ _____ |
---|
1046 | #| __ \| | |_ _| |
---|
1047 | #| |__) | |_ _ __ _ ______| | _ __ ___ |
---|
1048 | #| ___/| | | | |/ _` |______| | | '_ \/ __| |
---|
1049 | #| | | | |_| | (_| | _| |_| | | \__ \ |
---|
1050 | #|_| |_|\__,_|\__, | |_____|_| |_|___/ |
---|
1051 | # __/ | |
---|
1052 | # |___/ |
---|
1053 | |
---|
1054 | |
---|
1055 | |
---|
1056 | class Plugin: |
---|
1057 | """ All the plugins inherit from this class |
---|
1058 | """ |
---|
1059 | def __init__(self,type): |
---|
1060 | """ |
---|
1061 | Initializes the plugin with type = (code|tool) |
---|
1062 | """ |
---|
1063 | if (type != "code") and (type != "tool"): |
---|
1064 | error("XDRError : Plugin type was "+type+", it has to be 'code' or 'tool'") |
---|
1065 | self.type = type |
---|
1066 | self.infos={} |
---|
1067 | self.infos['platform']="XDRError : Platform is not specified in current plugin" |
---|
1068 | self.infos['parallelCommand'] = "" |
---|
1069 | |
---|
1070 | self.dir2send = [] |
---|
1071 | self.plugin_name = self.__class__.__name__ |
---|
1072 | self.nbcores = 0 |
---|
1073 | self.enable_sav = False |
---|
1074 | |
---|
1075 | |
---|
1076 | def get_cores(self): |
---|
1077 | if self.nbcores == 0 : |
---|
1078 | msg_err = "Warning : 0 cores reserved for the present computation" |
---|
1079 | error(msg_err) |
---|
1080 | return self.nbcores |
---|
1081 | |
---|
1082 | |
---|
1083 | # def sendDirectory(self,directory): |
---|
1084 | # """ This method sends directory on a distant place """ |
---|
1085 | # error("Plugin : sendDirectory() is not implemented in current plugin ...") |
---|
1086 | |
---|
1087 | def executeDistantCommand(self,command,execDirectory,flags=[]): |
---|
1088 | """ This method goes into execDirectory and execute command """ |
---|
1089 | error("Plugin : executeDistantCommand() is not implemented in current plugin ...") |
---|
1090 | |
---|
1091 | def sendDirectory(self,directory): |
---|
1092 | """ This method adds a directory to the run archive. """ |
---|
1093 | # basename(abspath()) removes the trailing '/'s. |
---|
1094 | #local_directory = os.path.abspath(directory) |
---|
1095 | #directory_name = os.path.basename(local_directory) |
---|
1096 | |
---|
1097 | local_directory = os.path.relpath(directory) |
---|
1098 | |
---|
1099 | # We don't check that relpath doesn't contain some '../../../'. |
---|
1100 | # Might be an issue. |
---|
1101 | # tar removes them on its own, a plain scp might not. |
---|
1102 | |
---|
1103 | # Also, handling of symlinks is unknown. |
---|
1104 | |
---|
1105 | # Check that directory exists |
---|
1106 | if not os.path.exists(local_directory): |
---|
1107 | error("Error : " + directory + " doesn't exist") |
---|
1108 | |
---|
1109 | # Check that we didn't change working directory along the way. |
---|
1110 | if (len(self.dir2send) > 0): |
---|
1111 | if os.getcwd() != self._dir2send_curdir: |
---|
1112 | error("Current directory changed between calls to sendDirectory(). This is not supported !") |
---|
1113 | else: |
---|
1114 | self._dir2send_curdir = os.getcwd() |
---|
1115 | |
---|
1116 | # Add to the list of files to be sent |
---|
1117 | self.dir2send.append(local_directory) |
---|
1118 | |
---|
1119 | def retrieveDirectory(self,directory): |
---|
1120 | """ This method retrieves directory from the distant place """ |
---|
1121 | error("Plugin : retrieveDirectory is not implemented in current plugin ...") |
---|
1122 | |
---|
1123 | def removeDirectory(self,directory): |
---|
1124 | """ This method removes directory from the distant place """ |
---|
1125 | error("Plugin : removeDirectory is not implemented in current plugin ...") |
---|
1126 | |
---|
1127 | def getPlatform(self): |
---|
1128 | """ This method has to be deleted |
---|
1129 | """ |
---|
1130 | error("Plugin : getPlatform souldn't be called anymore") |
---|
1131 | |
---|
1132 | def getInfos(self): |
---|
1133 | """ This methods returns informations regarding the plugin as a dictionary. |
---|
1134 | This dictionary is instantiated in the constructor of mother class Plugin |
---|
1135 | This method has to be deleted |
---|
1136 | """ |
---|
1137 | error("Plugin : getInfos souldn't be called anymore") |
---|
1138 | |
---|
1139 | def getPluginParam(self,paramName): |
---|
1140 | """ This method searches for paramName where the plugin is configurated and return its value |
---|
1141 | """ |
---|
1142 | try: |
---|
1143 | return getValue(paramName,self.__class__.__name__,self.type+"_plugins") |
---|
1144 | except XDRtooManyNodesException: |
---|
1145 | #error("Your plugin "+self.__class__.__name__+" is configurated in multiple places ...\n Remove it from your config !") |
---|
1146 | return getValue(paramName,self.__class__.__name__,self.type+"_plugins",getValue("name","solver","meta")) |
---|
1147 | |
---|
1148 | def runSAV(self): |
---|
1149 | if not self.enable_sav: |
---|
1150 | print "SAV not available for current plugin" |
---|
1151 | return |
---|
1152 | |
---|
1153 | shutil.copy(os.path.join(os.path.dirname(os.path.abspath(__file__)), "SAV.py"), ".") |
---|
1154 | self.sendDirectory('SAV.py') |
---|
1155 | self.executeDistantCommand("python SAV.py", ".", "SAV") |
---|
1156 | self.retrieveDirectory('XDR-FileDB.csv') |
---|
1157 | |
---|
1158 | db = SAV.FileDB('XDR-FileDB.csv') |
---|
1159 | print db |
---|
1160 | |
---|
1161 | |
---|
1162 | |
---|
1163 | |
---|
1164 | |
---|
1165 | def loadPlugin(pluginName): |
---|
1166 | |
---|
1167 | callDir = os.path.split(scriptDir)[1] |
---|
1168 | #print callDir |
---|
1169 | #pluginPath = "" |
---|
1170 | #if callDir == "XDRpy" : |
---|
1171 | # pluginPath = os.path.join(scriptDir,"..","library","DATA","pluginscripts") |
---|
1172 | #if callDir == "scripts" : |
---|
1173 | # pluginPath = os.path.join(scriptDir,"..","..","DATA","pluginscripts") |
---|
1174 | # |
---|
1175 | #if pluginPath == "" : |
---|
1176 | # error("Problem, this case is not managed by load plugin") |
---|
1177 | pluginsPath = getValue("pluginsPath","engine","meta") |
---|
1178 | |
---|
1179 | print "Loading plugin : "+str(os.path.join(pluginsPath,pluginName+".py")) |
---|
1180 | |
---|
1181 | |
---|
1182 | try: |
---|
1183 | return imp.load_source(pluginName,os.path.join(pluginsPath,pluginName+".py")) |
---|
1184 | except IOError: |
---|
1185 | error("XDRError : plugin \""+pluginName+"\" couldn't be found") |
---|
1186 | |
---|
1187 | |
---|
1188 | |
---|
1189 | def loadCodePlugin(pluginName=""): |
---|
1190 | |
---|
1191 | if pluginName == "" : |
---|
1192 | try: |
---|
1193 | pluginName = getValue("code_plugins") |
---|
1194 | except XDRtooManyNodesException: |
---|
1195 | #error("Your plugin "+self.__class__.__name__+" is configurated in multiple places ...\n Remove it from your config !") |
---|
1196 | pluginName = getValue("code_plugins",getValue("name","solver","meta")) |
---|
1197 | |
---|
1198 | pluginLib = loadPlugin(pluginName) |
---|
1199 | pluginClass = getattr(pluginLib,pluginName) |
---|
1200 | plugin = pluginClass("code") |
---|
1201 | return plugin |
---|
1202 | |
---|
1203 | def loadToolPlugin(): |
---|
1204 | try: |
---|
1205 | pluginName = getValue("tool_plugins","config") |
---|
1206 | except XDRnoNodeException: |
---|
1207 | error("XDRError : Your config file is not up to date") |
---|
1208 | |
---|
1209 | |
---|
1210 | pluginLib = loadPlugin(pluginName) |
---|
1211 | pluginClass = getattr(pluginLib,pluginName) |
---|
1212 | plugin = pluginClass("tool") |
---|
1213 | return plugin |
---|
1214 | |
---|
1215 | |
---|
1216 | def executeTool(command,directory): |
---|
1217 | """ This command execute a tool on a distant service regarding the chosen plugin in config file |
---|
1218 | """ |
---|
1219 | |
---|
1220 | |
---|
1221 | plugin = loadToolPlugin() |
---|
1222 | |
---|
1223 | plugin.sendDirectory(directory) |
---|
1224 | |
---|
1225 | plugin.executeDistantCommand(command,directory) |
---|
1226 | |
---|
1227 | plugin.retrieveDirectory(directory) |
---|
1228 | |
---|
1229 | |
---|
1230 | # ______ _ |
---|
1231 | # ____ | ____| | | |
---|
1232 | # / __ \ | |__ __ _____ ___ ___ ___ _ __ ___ _ __ ___ __ _ _ __ __| | |
---|
1233 | # / / _` | | __| \ \/ / _ \/ __| / __/ _ \| '_ ` _ \| '_ ` _ \ / _` | '_ \ / _` | |
---|
1234 | #| | (_| | | |____ > < __/ (__ | (_| (_) | | | | | | | | | | | (_| | | | | (_| | |
---|
1235 | # \ \__,_| |______/_/\_\___|\___| \___\___/|_| |_| |_|_| |_| |_|\__,_|_| |_|\__,_| |
---|
1236 | # \____/ ______ |
---|
1237 | # |______| |
---|
1238 | |
---|
1239 | |
---|
1240 | def exec_command(fun): |
---|
1241 | """ This function defines the annotation @exec_command, to be used by all plugin scripts. |
---|
1242 | It defines self.command_exe (defaults to command), self.local_directory (the current directory) |
---|
1243 | that can then be accessed in executeDistantCommand """ |
---|
1244 | def wrapped_fun(self, command, execDirectory, appli, flags=[]): |
---|
1245 | print "Plugin : Running executeDistantCommand " + command + " (appli: " + appli + ") in " + execDirectory |
---|
1246 | |
---|
1247 | # Initialize some variables |
---|
1248 | self.command_exe = command |
---|
1249 | self.local_directory = os.getcwd() |
---|
1250 | |
---|
1251 | # Used only for testing deployment plugins |
---|
1252 | if appli == "-c3sm_auto_deployment_tests": |
---|
1253 | if command == "-c3sm_auto_deploy_test_write-": |
---|
1254 | self.command_exe = "cat my_input_file > my_new_file" |
---|
1255 | |
---|
1256 | # Check that execDirectory makes sense |
---|
1257 | if len(execDirectory) == 0: |
---|
1258 | print "No execDirectory given. Assuming '.'" |
---|
1259 | execDirectory = '.' |
---|
1260 | |
---|
1261 | if execDirectory[0] == '/' or execDirectory[0] == '~': |
---|
1262 | error("execDirectory should be relative to the project directory, not an absolute path") |
---|
1263 | |
---|
1264 | # Run the actual command |
---|
1265 | r = fun(self, command, execDirectory, appli, flags=[]) |
---|
1266 | |
---|
1267 | # The command is supposed to have uploaded pending files |
---|
1268 | # Empty the list, so they aren't sent again if we invoke executeDistantCommand another time. |
---|
1269 | self.dir2send = [] |
---|
1270 | |
---|
1271 | # Make sure we get back to the initial directory |
---|
1272 | os.chdir(self.local_directory) |
---|
1273 | return wrapped_fun |
---|
1274 | |
---|
1275 | # |
---|
1276 | # _____ _ _ _ _ _ _ |
---|
1277 | # ____ / ____| | | | | | (_) | | (_) |
---|
1278 | # / __ \ | (___ _ _ _ __ _ __ ___ _ __| |_ ___ __| | __ _ _ __ _ __ | |_ ___ __ _| |_ _ ___ _ __ ___ |
---|
1279 | # / / _` | \___ \| | | | '_ \| '_ \ / _ \| '__| __/ _ \/ _` | / _` | '_ \| '_ \| | |/ __/ _` | __| |/ _ \| '_ \/ __| |
---|
1280 | #| | (_| | ____) | |_| | |_) | |_) | (_) | | | || __/ (_| || (_| | |_) | |_) | | | (_| (_| | |_| | (_) | | | \__ \ |
---|
1281 | # \ \__,_| |_____/ \__,_| .__/| .__/ \___/|_| \__\___|\__,_| \__,_| .__/| .__/|_|_|\___\__,_|\__|_|\___/|_| |_|___/ |
---|
1282 | # \____/ | | | | ______ | | | | |
---|
1283 | # |_| |_| |______| |_| |_| |
---|
1284 | |
---|
1285 | def supported_applications(apps): |
---|
1286 | """ Annotation @supported_applications(['appli1', 'appli2']) automates checking that a passed application is supported """ |
---|
1287 | def wrapper(fun): |
---|
1288 | def wrapped_fun(self, command, execDirectory, appli, flags=[]): |
---|
1289 | # This is a list of apps that the user doesn't have to specifically accept. |
---|
1290 | # XDRpy will handle them internally, and developers of deployment plugins |
---|
1291 | # don't have to care about them. |
---|
1292 | apps_whitelist = ['-c3sm_auto_deployment_tests', 'SAV'] |
---|
1293 | |
---|
1294 | if (appli not in apps) and (appli not in apps_whitelist): |
---|
1295 | error("This application requires the application tag " + appli + ", which is not supported by the plugin " + self.plugin_name) |
---|
1296 | return fun(self, command, execDirectory, appli, flags=[]) |
---|
1297 | return wrapped_fun |
---|
1298 | return wrapper |
---|
1299 | |
---|
1300 | def check_command_exe(command_exe): |
---|
1301 | """ Checks that the command is valid. If it starts with -c3sm_auto-, the associated command hasn't been found """ |
---|
1302 | if command_exe.startswith("-c3sm_auto_"): |
---|
1303 | error("command was not understood: "+command_exe ) |
---|
1304 | |
---|
1305 | |
---|
1306 | def executeCode(command,currentRunDirectory="None"): |
---|
1307 | |
---|
1308 | |
---|
1309 | error("XDRError : executeCode is not managed anymore in XDR library, update your library") |
---|
1310 | |
---|
1311 | try: |
---|
1312 | pluginName = getValue("code_plugins","config") |
---|
1313 | except XDRnoNodeException: |
---|
1314 | error("XDRError : Your config file is not up to date") |
---|
1315 | return |
---|
1316 | |
---|
1317 | if currentRunDirectory=="None" : |
---|
1318 | currentRunDirectory = getCurrentRun() |
---|
1319 | |
---|
1320 | typeRun = "code" |
---|
1321 | |
---|
1322 | plugin = loadPlugin(pluginName) |
---|
1323 | |
---|
1324 | plugin.sendDirectory(os.path.join(".",COMMON_DIRECTORY),typeRun) |
---|
1325 | |
---|
1326 | plugin.sendDirectory(os.path.join(".",getCurrentRun()),typeRun) |
---|
1327 | |
---|
1328 | plugin.executeDistantCommand(command,currentRunDirectory,typeRun) |
---|
1329 | |
---|
1330 | def retrieveCodeDirectory(directory): |
---|
1331 | try: |
---|
1332 | pluginName = getValue("code_plugins","config") |
---|
1333 | except XDRnoNodeException: |
---|
1334 | print "XDRError : Your config file is not up to date" |
---|
1335 | return |
---|
1336 | |
---|
1337 | plugin = loadPlugin(pluginName) |
---|
1338 | |
---|
1339 | plugin.retrieveDirectory(directory,"code") |
---|
1340 | |
---|
1341 | |
---|
1342 | |
---|
1343 | |
---|
1344 | # |
---|
1345 | # |
---|
1346 | # ______ _ _ |
---|
1347 | #| ____| | | (_) |
---|
1348 | #| |__ __ _____ ___ _ __ | |_ _ ___ _ __ ___ |
---|
1349 | #| __| \ \/ / __/ _ \ '_ \| __| |/ _ \| '_ \/ __| |
---|
1350 | #| |____ > < (_| __/ |_) | |_| | (_) | | | \__ \ |
---|
1351 | #|______/_/\_\___\___| .__/ \__|_|\___/|_| |_|___/ |
---|
1352 | # | | |
---|
1353 | # |_| |
---|
1354 | # |
---|
1355 | |
---|
1356 | class XDRException(Exception): |
---|
1357 | """ All exceptions raisen by XDR library inherits from this one""" |
---|
1358 | |
---|
1359 | class XDRnoNodeException(XDRException): |
---|
1360 | """" No node found """ |
---|
1361 | |
---|
1362 | class XDRtooManyNodesException(XDRException): |
---|
1363 | """ Too many nodes have been found""" |
---|
1364 | |
---|
1365 | class XDRnoFileException(XDRException): |
---|
1366 | """ No file found """ |
---|
1367 | |
---|
1368 | class XDRillFormed(XDRException): |
---|
1369 | """ Ill formed XML address """ |
---|
1370 | |
---|
1371 | |
---|
1372 | |
---|
1373 | |
---|
1374 | def replace_pattern_in_file(file,searchExp,replaceExp): |
---|
1375 | """ serach and replace a pattern in a file |
---|
1376 | needs the fileinput package""" |
---|
1377 | |
---|
1378 | if not os.path.exists(file) : |
---|
1379 | print "Warning : file not found:"+file |
---|
1380 | return |
---|
1381 | |
---|
1382 | replace = 0 |
---|
1383 | for line in fileinput.input(file, inplace=1): |
---|
1384 | if searchExp in line: |
---|
1385 | line = line.replace(searchExp,replaceExp) |
---|
1386 | replace += 1 |
---|
1387 | sys.stdout.write(line) |
---|
1388 | |
---|
1389 | if replace == 0 : |
---|
1390 | print "Warning : no replacement made \n "+file+":"+ searchExp +">"+replaceExp |
---|
1391 | else : |
---|
1392 | print str(replace)+" replacement made \n"+file+":"+ searchExp +">"+replaceExp |
---|
1393 | return |
---|
1394 | |
---|
1395 | # |
---|
1396 | # ______ _ _ _ |
---|
1397 | #| ____| | | | | (_) |
---|
1398 | #| |__ _ __ ___ __ _ _ _ ___ _ __ | |_ __ _ ___| |_ _ ___ _ __ ___ |
---|
1399 | #| __| '__/ _ \/ _` | | | |/ _ \ '_ \| __| / _` |/ __| __| |/ _ \| '_ \/ __| |
---|
1400 | #| | | | | __/ (_| | |_| | __/ | | | |_ | (_| | (__| |_| | (_) | | | \__ \ |
---|
1401 | #|_| |_| \___|\__, |\__,_|\___|_| |_|\__| \__,_|\___|\__|_|\___/|_| |_|___/ |
---|
1402 | # | | |
---|
1403 | # |_| |
---|
1404 | |
---|
1405 | |
---|
1406 | def afterstring(text,pattern): |
---|
1407 | """ |
---|
1408 | This procedure searches for the first line beginning with "pattern" in "text" and return the rest of the line |
---|
1409 | """ |
---|
1410 | p= re.compile('^[ \t]*'+pattern+'[\t ]*(.*?)[ \t]*$', re.MULTILINE) |
---|
1411 | m=p.search(text) |
---|
1412 | if m: |
---|
1413 | return m.group(1) |
---|
1414 | else: |
---|
1415 | print "No result found for "+pattern+" ..." |
---|
1416 | return "Error" |
---|
1417 | |
---|
1418 | |
---|
1419 | def grep(text,pattern): |
---|
1420 | textLines=text.split("\n") |
---|
1421 | p= re.compile(pattern) |
---|
1422 | result=[] |
---|
1423 | for line in textLines: |
---|
1424 | m=p.search(line) |
---|
1425 | if m: |
---|
1426 | result.append(line) |
---|
1427 | return "\n".join(result) |
---|
1428 | |
---|
1429 | |
---|
1430 | def betweenlines(text,pattern1,pattern2): |
---|
1431 | """ |
---|
1432 | This procedure return the text between the lines "pattern1" and "pattern2" |
---|
1433 | """ |
---|
1434 | textLines=text.split("\n") |
---|
1435 | p=re.compile('^[ \t]*'+pattern1+'[ \t]*$') |
---|
1436 | position="out" |
---|
1437 | result=[] |
---|
1438 | for line in textLines: |
---|
1439 | m=p.search(line) |
---|
1440 | if m: |
---|
1441 | if position=="out": |
---|
1442 | p=re.compile('^[ \t]*'+pattern2+'[ \t]*$') |
---|
1443 | position="in" |
---|
1444 | else: |
---|
1445 | position="out" |
---|
1446 | else: |
---|
1447 | if position=="in": |
---|
1448 | result.append(line) |
---|
1449 | return "\n".join(result) |
---|
1450 | |
---|
1451 | |
---|
1452 | def getColumn(text,pos,sep=None): |
---|
1453 | """ This procedure reads the lines of "text" and return an array containing the pos-th element of each line |
---|
1454 | sep is the separator, if not specified, the separator is assumed to be any kind of whitespace (tab, space, etc ...) |
---|
1455 | """ |
---|
1456 | finalList = [] |
---|
1457 | result=text.split("\n") |
---|
1458 | for line in result: |
---|
1459 | toto=line.split(sep) |
---|
1460 | if len(toto)>=pos: |
---|
1461 | finalList.append(toto[pos-1].strip()) |
---|
1462 | return finalList |
---|
1463 | |
---|
1464 | |
---|
1465 | def readFile(filename): |
---|
1466 | """ This procedure returns the content of the file "filename" """ |
---|
1467 | # asciiIn = ReadAsciiFile(filename) |
---|
1468 | # result = asciiIn.getContent() |
---|
1469 | return ReadAsciiFile(filename).getContent() |
---|
1470 | |
---|
1471 | |
---|
1472 | |
---|
1473 | |
---|
1474 | def pairwise(iterable): |
---|
1475 | """ |
---|
1476 | This procedure allows to loop in a list in a pairwise fashion |
---|
1477 | need package izip |
---|
1478 | s -> (s0,s1), (s2,s3), (s4, s5), ... |
---|
1479 | """ |
---|
1480 | a = iter(iterable) |
---|
1481 | return izip(a, a) |
---|
1482 | |
---|
1483 | def ensureDirectory(list_strings,clean=False): |
---|
1484 | """ Check wether a directory exists in the current working directory |
---|
1485 | argument is a list of strings to be contcatenated. |
---|
1486 | Returns the directory path in absolute form |
---|
1487 | """ |
---|
1488 | |
---|
1489 | if isinstance(list_strings, basestring) : |
---|
1490 | dirlist = [list_strings] |
---|
1491 | else : |
---|
1492 | dirlist = list_strings |
---|
1493 | |
---|
1494 | |
---|
1495 | directory= os.path.join(os.getcwd(),*dirlist) |
---|
1496 | |
---|
1497 | |
---|
1498 | if os.path.exists(directory) : |
---|
1499 | if clean : |
---|
1500 | print "Ensure clean directory", directory |
---|
1501 | # directory exists, and need to clean it |
---|
1502 | shutil.rmtree(directory) |
---|
1503 | os.makedirs(directory) |
---|
1504 | else : |
---|
1505 | # directory exists, and no need to clean it |
---|
1506 | pass |
---|
1507 | |
---|
1508 | else : |
---|
1509 | #directory does not exists |
---|
1510 | print "Create directory", directory |
---|
1511 | os.makedirs(directory) |
---|
1512 | |
---|
1513 | |
---|
1514 | |
---|
1515 | return directory |
---|
1516 | |
---|
1517 | def readAsciiBound(asciiBoundFile): |
---|
1518 | asciiBound = readFile(asciiBoundFile) |
---|
1519 | asciiBound = asciiBound.split("\n") |
---|
1520 | |
---|
1521 | nbPatches = int(asciiBound[1].strip().split(" ")[0]) |
---|
1522 | |
---|
1523 | results= [] |
---|
1524 | for i,line in enumerate(asciiBound): |
---|
1525 | if re.compile("^\s*Patch: ").search(line): |
---|
1526 | results.append(asciiBound[i+1].strip()) |
---|
1527 | |
---|
1528 | if len(results) != nbPatches: |
---|
1529 | msg = "Mismatch between the number of patches and the patches read in file "+asciiBoundFile |
---|
1530 | error(msg) |
---|
1531 | |
---|
1532 | return results |
---|
1533 | |
---|
1534 | |
---|
1535 | def getFileList(path,filter_search="",output="listonly"): |
---|
1536 | """ return the list of files in a path (compulsory) matching a filter string (facultative). |
---|
1537 | output (facultative) can be : - listonly : a list of the files |
---|
1538 | - relative : a list relative pathes |
---|
1539 | - absolute : a list of absolute path |
---|
1540 | """ |
---|
1541 | |
---|
1542 | |
---|
1543 | lresult = [] |
---|
1544 | glob_arg = os.path.join(path,filter_search) |
---|
1545 | list_dir = glob.glob(glob_arg) |
---|
1546 | |
---|
1547 | |
---|
1548 | if output == "relative" : |
---|
1549 | for f in list_dir: |
---|
1550 | lresult.append(os.path.relpath(f)) |
---|
1551 | if output == "listonly" : |
---|
1552 | for f in list_dir: |
---|
1553 | lresult.append(os.path.relpath(f,path)) |
---|
1554 | if output == "absolute" : |
---|
1555 | lresult = list_dir |
---|
1556 | |
---|
1557 | #print "getFileList",lresult |
---|
1558 | |
---|
1559 | |
---|
1560 | return sorted(lresult) |
---|
1561 | |
---|
1562 | |
---|
1563 | |
---|
1564 | # |
---|
1565 | # _____ __ __ _ _ _ |
---|
1566 | #| __ \| \/ | | | (_) | |
---|
1567 | #| |__) | \ / | _ _| |_ _| |___ |
---|
1568 | #| ___/| |\/| | | | | | __| | / __| |
---|
1569 | #| | | | | | | |_| | |_| | \__ \ |
---|
1570 | #|_| |_| |_| \__,_|\__|_|_|___/ |
---|
1571 | # |
---|
1572 | |
---|
1573 | def SimToColor(simu) : |
---|
1574 | color = "black" |
---|
1575 | if simu == "1" : |
---|
1576 | color="black" |
---|
1577 | if simu == "2" : |
---|
1578 | color="red" |
---|
1579 | if simu == "3" : |
---|
1580 | color="blue" |
---|
1581 | if simu == "4" : |
---|
1582 | color="green4" |
---|
1583 | return color |
---|
1584 | |
---|
1585 | def SimToSymbol(simu) : |
---|
1586 | symbol = "" |
---|
1587 | if simu == "1" : |
---|
1588 | symbol="circle" |
---|
1589 | if simu == "2" : |
---|
1590 | symbol="square" |
---|
1591 | if simu == "3" : |
---|
1592 | symbol="triangle" |
---|
1593 | if simu == "4" : |
---|
1594 | symbol="diamond" |
---|
1595 | return symbol |
---|
1596 | |
---|