merge the formfield patch from ooo-build
[ooovba.git] / solenv / bin / pchdelta.py
blob52a0df4ecc5dccc967fbebb6f55ed72d1f609b35
1 #!/usr/bin/python
3 # ------------------------------------------------------------------------------
4 # Hacky little delta debug tool to figure out the proper includes for a pch file
6 # Usage:
7 #
8 # pchdelta.py <pch_target> <dir1> [<dir2> <dir3> ...]
10 # <pch_target> File to perform delta debugging on. The section to test
11 # is delimeted by '//---MARKER---' lines.
12 # <dir1> .. <dirn> Sequence of directories to run dmake in to test if the
13 # modification works
15 # Examples:
17 # pchdelta.py inc/pch/precompiled_sfx2.hxx inc source/dialog
19 # Run pchdelta inside sfx2 first building the pch files and then files in
20 # source/dialog
22 # ------------------------------------------------------------------------------
24 import os
25 import os.path
26 import sys
28 # C++
29 MARKER="//---MARKER---\n"
31 # dmake
32 #MARKER="#---MARKER---\n"
34 # ------------------------------------------------------------------------------
35 # Sequentially build all argument directories from scratch
37 def testSequenceBuild(dirlist):
38 cwd = os.path.abspath(os.getcwd())
39 for path in dirlist:
40 os.chdir(path)
41 buildcommand = "dmake -u"
42 buildcommand += " >>" + cwd + "/buildlog.txt 2>&1"
43 buildresult = os.system(buildcommand)
44 os.chdir(cwd)
45 if buildresult != 0:
46 return False
47 return True
49 # ------------------------------------------------------------------------------
50 # Dump out the delta file with corresponding markers
52 def writePch(pchname, header, footer, acceptedlines, testlines):
53 outputfile = file(pchname, "w")
54 outputfile.write(header)
55 outputfile.write(MARKER)
56 outputfile.write("\n".join(acceptedlines))
57 if len(testlines) > 0:
58 outputfile.write("\n\n//---Candidate marker---\n")
59 outputfile.write("\n".join(testlines) + "\n")
60 outputfile.write("//---Candidate marker end---\n")
61 outputfile.write(MARKER)
62 outputfile.write(footer)
63 outputfile.close()
66 # ------------------------------------------------------------------------------
67 # Recursive tester routine. Test the segment given and if an error is
68 # encountered splits the segment into <fanout> subsegment and recurses. Failing
69 # one liners are rejected. The set of accepted lines are built sequentially from
70 # the beginning.
72 def binaryTest(dirlist, lines, pchname, header, footer, acceptedlines, indent, startpoint):
73 linecount = len(lines)
74 if linecount == 0:
75 return
76 # Test if this slice passes the buildtest
77 writePch(pchname, header, footer, acceptedlines, lines)
78 if testSequenceBuild(dirlist):
79 return acceptedlines + lines
81 # Reject one liners
82 if linecount == 1:
83 print indent + "Rejected: " + lines[0]
84 return acceptedlines
86 # Recurse with multiline slices
87 fanout = 4
88 splits = []
89 for i in range(3):
90 splits.append(linecount * (i + 1) / fanout)
91 splits.append(linecount)
93 splitstart = 0
94 for splitend in splits:
95 # avoid splitting in case we have no resulting lines
96 if (splitend - splitstart) == 0:
97 continue
98 splitslice = lines[splitstart:splitend]
99 print indent + "[" + str(startpoint + splitstart) + ":" + str(startpoint + splitend) + "] (" + str(splitend - splitstart) + ")"
100 acceptedlines = binaryTest(dirlist, splitslice, pchname, header, footer, acceptedlines, indent + " ", startpoint + splitstart)
101 splitstart = splitend
103 return acceptedlines
105 # ------------------------------------------------------------------------------
106 # Main entry point
108 if len(sys.argv) < 3:
109 print "Usage: " + sys.argv[0] + " <pch_target> <dir1> [<dir2> <dir3> ...]"
110 sys.exit(1)
112 pchname = os.path.abspath(sys.argv[1])
113 dirlist = sys.argv[2:]
115 # remove old build log file
116 if os.path.exists("buildlog.txt"):
117 os.remove("buildlog.txt")
119 # test for corner case of everything working from the start
120 if testSequenceBuild(dirlist):
121 print "pch working, nothing to do."
122 sys.exit(0)
124 # Open the header file for reading
125 inputfile = file(pchname, "r+")
126 inputdata = inputfile.read()
127 inputfile.close()
129 segments = inputdata.split(MARKER)
130 header = segments[0]
131 footer = segments[2]
132 lines = segments[1].split("\n")
134 writePch(pchname + "_backup", header, footer, lines, [])
136 # test for corner case of no convergence possible
137 writePch(pchname, header, footer, [], [])
138 if not testSequenceBuild(dirlist):
139 writePch(pchname, header, footer, lines, [])
140 print "Building with no candidate lines failed. Convergence questionable, aborting."
141 sys.exit(0)
143 # Starting pruning
144 print "Starting evaluation of " + str(len(lines)) + " lines"
145 acceptedlines = binaryTest(dirlist, lines, pchname, header, footer, [], "", 0)
146 writePch(pchname, header, footer, acceptedlines, [])