34 |
34 |
35 |
35 |
36 class BadMakeEngineException(Exception): |
36 class BadMakeEngineException(Exception): |
37 pass |
37 pass |
38 |
38 |
|
39 def XMLEscapeLog(stream): |
|
40 inRecipe = False |
|
41 |
|
42 for line in stream: |
|
43 if line.startswith("<recipe"): |
|
44 inRecipe = True |
|
45 elif line.startswith("</recipe"): |
|
46 inRecipe = False |
|
47 |
|
48 # unless we are inside a "recipe", any line not starting |
|
49 # with "<" is free text that must be escaped. |
|
50 if inRecipe or line.startswith("<"): |
|
51 yield line |
|
52 else: |
|
53 yield escape(line) |
|
54 |
|
55 def AnnoFileParseOutput(annofile): |
|
56 af = open(annofile, "r") |
|
57 |
|
58 inOutput = False |
|
59 inParseJob = False |
|
60 for line in af: |
|
61 line = line.rstrip("\n\r") |
|
62 |
|
63 if not inOutput: |
|
64 if line.startswith("<output>"): |
|
65 inOutput = True |
|
66 yield unescape(line[8:])+'\n' |
|
67 # This is make output so don't unescape it. |
|
68 elif line.startswith('<output src="prog">'): |
|
69 line = line[19:] |
|
70 inOutput = True |
|
71 yield unescape(line)+'\n' |
|
72 else: |
|
73 end_output = line.find("</output>") |
|
74 |
|
75 if end_output != -1: |
|
76 line = line[:end_output] |
|
77 inOutput = False |
|
78 |
|
79 yield unescape(line)+'\n' |
|
80 |
|
81 af.close() |
|
82 |
|
83 |
|
84 |
39 # raptor_make module classes |
85 # raptor_make module classes |
40 |
86 |
41 class MakeEngine(object): |
87 class MakeEngine(object): |
42 |
88 |
43 def __init__(self, Raptor, engine="make_engine"): |
89 def __init__(self, Raptor, engine="make_engine"): |
79 # options |
125 # options |
80 self.makefileOption = evaluator.Get("makefile") |
126 self.makefileOption = evaluator.Get("makefile") |
81 self.keepGoingOption = evaluator.Get("keep_going") |
127 self.keepGoingOption = evaluator.Get("keep_going") |
82 self.jobsOption = evaluator.Get("jobs") |
128 self.jobsOption = evaluator.Get("jobs") |
83 self.defaultMakeOptions = evaluator.Get("defaultoptions") |
129 self.defaultMakeOptions = evaluator.Get("defaultoptions") |
|
130 |
|
131 # Logging |
|
132 # copylogfromannofile means, for emake, that we should ignore |
|
133 # emake's console output and instead extract output from its annotation |
|
134 # file. This is a workaround for a problem where some emake |
|
135 # console output is lost. The annotation file has a copy of this |
|
136 # output in the "parse" job and it turns out to be uncorrupted. |
|
137 self.copyLogFromAnnoFile = (evaluator.Get("copylogfromannofile") == "true") |
|
138 self.annoFileName = None |
|
139 |
|
140 if self.copyLogFromAnnoFile: |
|
141 for o in self.raptor.makeOptions: |
|
142 if o.startswith("--mo=--emake-annofile="): |
|
143 self.annoFileName = o[22:] |
|
144 |
|
145 if not self.annoFileName: |
|
146 self.raptor.Info("Cannot copy log from annotation file as no annotation filename was specified via the option --mo=--emake-annofile=<filename>") |
|
147 self.copyLogFromAnnoFile = False |
84 |
148 |
85 # buffering |
149 # buffering |
86 self.scrambled = (evaluator.Get("scrambled") == "true") |
150 self.scrambled = (evaluator.Get("scrambled") == "true") |
87 |
151 |
88 # check tool versions |
152 # check tool versions |
479 # clock skew messages from some build engines scatter their |
543 # clock skew messages from some build engines scatter their |
480 # output across our xml. |
544 # output across our xml. |
481 stderrfilename = makefile+'.stderr' |
545 stderrfilename = makefile+'.stderr' |
482 stdoutfilename = makefile+'.stdout' |
546 stdoutfilename = makefile+'.stdout' |
483 command += " 2>'%s' " % stderrfilename |
547 command += " 2>'%s' " % stderrfilename |
484 command += " >'%s' " % stdoutfilename |
548 |
|
549 # Keep a copy of the stdout too in the case of using the |
|
550 # annofile - so that we can trap the problem that |
|
551 # makes the copy-log-from-annofile workaround necessary |
|
552 # and perhaps determine when we can remove it. |
|
553 if self.copyLogFromAnnoFile: |
|
554 command += " >'%s' " % stdoutfilename |
485 |
555 |
486 # Substitute the makefile name for any occurrence of #MAKEFILE# |
556 # Substitute the makefile name for any occurrence of #MAKEFILE# |
487 command = command.replace("#MAKEFILE#", str(makefile)) |
557 command = command.replace("#MAKEFILE#", str(makefile)) |
488 |
558 |
489 self.raptor.Info("Executing '%s'", command) |
559 self.raptor.Info("Executing '%s'", command) |
517 stderr=subprocess.STDOUT, |
587 stderr=subprocess.STDOUT, |
518 shell = False, |
588 shell = False, |
519 universal_newlines=True, env=makeenv) |
589 universal_newlines=True, env=makeenv) |
520 stream = p.stdout |
590 stream = p.stdout |
521 |
591 |
522 line = " " |
592 inRecipe = False |
523 while line: |
593 |
524 line = stream.readline() |
594 if not self.copyLogFromAnnoFile: |
525 |
595 for l in XMLEscapeLog(stream): |
526 # should be done now |
596 self.raptor.out.write(l) |
527 returncode = p.wait() |
597 |
528 |
598 returncode = p.wait() |
529 # Report end-time of the build |
599 else: |
530 self.raptor.InfoEndTime(object_type = "makefile", |
600 returncode = p.wait() |
531 task = "build", key = str(makefile)) |
601 |
532 |
602 annofilename = self.annoFileName.replace("#MAKEFILE#",makefile) |
533 try: |
603 try: |
534 e = open(stdoutfilename,"r") |
604 for l in XMLEscapeLog(AnnoFileParseOutput(annofilename)): |
535 inRecipe = False |
605 self.raptor.out.write(l) |
536 for line in e: |
606 except Exception,e: |
537 if line.startswith("<recipe"): |
607 self.raptor.Error("Couldn't complete stdout output from annofile %s for %s - '%s'", annofile, command, str(e)) |
538 inRecipe = True |
|
539 elif line.startswith("</recipe"): |
|
540 inRecipe = False |
|
541 |
|
542 # unless we are inside a "recipe", any line not starting |
|
543 # with "<" is free text that must be escaped. |
|
544 if inRecipe or line.startswith("<"): |
|
545 self.raptor.out.write(line) |
|
546 else: |
|
547 self.raptor.out.write(escape(line)) |
|
548 e.close() |
|
549 except Exception,e: |
|
550 self.raptor.Error("Couldn't complete stdout output for %s - '%s'", command, str(e)) |
|
551 |
|
552 if returncode != 0 and not self.raptor.keepGoing: |
|
553 self.Tidy() |
|
554 return False |
|
555 |
608 |
556 |
609 |
557 # Take all the stderr output that went into the .stderr file |
610 # Take all the stderr output that went into the .stderr file |
558 # and put it back into the log, but safely so it can't mess up |
611 # and put it back into the log, but safely so it can't mess up |
559 # xml parsers. |
612 # xml parsers. |
562 for line in e: |
615 for line in e: |
563 self.raptor.out.write(escape(line)) |
616 self.raptor.out.write(escape(line)) |
564 e.close() |
617 e.close() |
565 except Exception,e: |
618 except Exception,e: |
566 self.raptor.Error("Couldn't complete stderr output for %s - '%s'", command, str(e)) |
619 self.raptor.Error("Couldn't complete stderr output for %s - '%s'", command, str(e)) |
|
620 # Report end-time of the build |
|
621 self.raptor.InfoEndTime(object_type = "makefile", |
|
622 task = "build", key = str(makefile)) |
567 |
623 |
568 if returncode != 0 and not self.raptor.keepGoing: |
624 if returncode != 0 and not self.raptor.keepGoing: |
569 self.Tidy() |
625 self.Tidy() |
570 return False |
626 return False |
571 |
627 |