xref: /trunk/main/solenv/bin/pchdelta.py (revision b0ad9294)
186f29464SPedro Giffuni#!/usr/bin/env python
29f22d7c2SAndrew Rist# *************************************************************
39f22d7c2SAndrew Rist#
49f22d7c2SAndrew Rist#  Licensed to the Apache Software Foundation (ASF) under one
59f22d7c2SAndrew Rist#  or more contributor license agreements.  See the NOTICE file
69f22d7c2SAndrew Rist#  distributed with this work for additional information
79f22d7c2SAndrew Rist#  regarding copyright ownership.  The ASF licenses this file
89f22d7c2SAndrew Rist#  to you under the Apache License, Version 2.0 (the
99f22d7c2SAndrew Rist#  "License"); you may not use this file except in compliance
109f22d7c2SAndrew Rist#  with the License.  You may obtain a copy of the License at
119f22d7c2SAndrew Rist#
129f22d7c2SAndrew Rist#    http://www.apache.org/licenses/LICENSE-2.0
139f22d7c2SAndrew Rist#
149f22d7c2SAndrew Rist#  Unless required by applicable law or agreed to in writing,
159f22d7c2SAndrew Rist#  software distributed under the License is distributed on an
169f22d7c2SAndrew Rist#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
179f22d7c2SAndrew Rist#  KIND, either express or implied.  See the License for the
189f22d7c2SAndrew Rist#  specific language governing permissions and limitations
199f22d7c2SAndrew Rist#  under the License.
209f22d7c2SAndrew Rist#
219f22d7c2SAndrew Rist# *************************************************************
229f22d7c2SAndrew Rist
23cdf0e10cSrcweir
24cdf0e10cSrcweir# ------------------------------------------------------------------------------
25cdf0e10cSrcweir# Hacky little delta debug tool to figure out the proper includes for a pch file
26cdf0e10cSrcweir#
27cdf0e10cSrcweir# Usage:
2886f29464SPedro Giffuni#
29cdf0e10cSrcweir# pchdelta.py <pch_target> <dir1> [<dir2> <dir3> ...]
30cdf0e10cSrcweir#
31cdf0e10cSrcweir# <pch_target>      File to perform delta debugging on. The section to test
32cdf0e10cSrcweir#                   is delimeted by '//---MARKER---' lines.
33cdf0e10cSrcweir# <dir1> .. <dirn>  Sequence of directories to run dmake in to test if the
34cdf0e10cSrcweir#                   modification works
35cdf0e10cSrcweir#
36cdf0e10cSrcweir# Examples:
37cdf0e10cSrcweir#
38cdf0e10cSrcweir# pchdelta.py inc/pch/precompiled_sfx2.hxx inc source/dialog
39cdf0e10cSrcweir#
40cdf0e10cSrcweir#  Run pchdelta inside sfx2 first building the pch files and then files in
41cdf0e10cSrcweir# source/dialog
42cdf0e10cSrcweir#
43cdf0e10cSrcweir# ------------------------------------------------------------------------------
44cdf0e10cSrcweir
45cdf0e10cSrcweirimport os
46cdf0e10cSrcweirimport os.path
47cdf0e10cSrcweirimport sys
48cdf0e10cSrcweir
49cdf0e10cSrcweir# C++
50cdf0e10cSrcweirMARKER="//---MARKER---\n"
51cdf0e10cSrcweir
52cdf0e10cSrcweir# dmake
53cdf0e10cSrcweir#MARKER="#---MARKER---\n"
54cdf0e10cSrcweir
55cdf0e10cSrcweir# ------------------------------------------------------------------------------
56cdf0e10cSrcweir# Sequentially build all argument directories from scratch
57cdf0e10cSrcweir
58cdf0e10cSrcweirdef testSequenceBuild(dirlist):
59cdf0e10cSrcweir    cwd = os.path.abspath(os.getcwd())
60cdf0e10cSrcweir    for path in dirlist:
61cdf0e10cSrcweir        os.chdir(path)
62cdf0e10cSrcweir        buildcommand = "dmake -u"
63cdf0e10cSrcweir        buildcommand += " >>" + cwd + "/buildlog.txt 2>&1"
64cdf0e10cSrcweir        buildresult = os.system(buildcommand)
65cdf0e10cSrcweir        os.chdir(cwd)
66cdf0e10cSrcweir        if buildresult != 0:
67cdf0e10cSrcweir            return False
68cdf0e10cSrcweir    return True
69cdf0e10cSrcweir
70cdf0e10cSrcweir# ------------------------------------------------------------------------------
71cdf0e10cSrcweir# Dump out the delta file with corresponding markers
72cdf0e10cSrcweir
73cdf0e10cSrcweirdef writePch(pchname, header, footer, acceptedlines, testlines):
74cdf0e10cSrcweir    outputfile = file(pchname, "w")
75cdf0e10cSrcweir    outputfile.write(header)
76cdf0e10cSrcweir    outputfile.write(MARKER)
77cdf0e10cSrcweir    outputfile.write("\n".join(acceptedlines))
78cdf0e10cSrcweir    if len(testlines) > 0:
79cdf0e10cSrcweir        outputfile.write("\n\n//---Candidate marker---\n")
80cdf0e10cSrcweir        outputfile.write("\n".join(testlines) + "\n")
81cdf0e10cSrcweir        outputfile.write("//---Candidate marker end---\n")
82cdf0e10cSrcweir    outputfile.write(MARKER)
83cdf0e10cSrcweir    outputfile.write(footer)
84cdf0e10cSrcweir    outputfile.close()
8586f29464SPedro Giffuni
86cdf0e10cSrcweir
87cdf0e10cSrcweir# ------------------------------------------------------------------------------
88cdf0e10cSrcweir# Recursive tester routine. Test the segment given and if an error is
89cdf0e10cSrcweir# encountered splits the segment into <fanout> subsegment and recurses. Failing
90cdf0e10cSrcweir# one liners are rejected. The set of accepted lines are built sequentially from
91cdf0e10cSrcweir# the beginning.
92cdf0e10cSrcweir
93cdf0e10cSrcweirdef binaryTest(dirlist, lines, pchname, header, footer, acceptedlines, indent, startpoint):
94cdf0e10cSrcweir    linecount = len(lines)
95cdf0e10cSrcweir    if linecount == 0:
96cdf0e10cSrcweir        return
97cdf0e10cSrcweir    # Test if this slice passes the buildtest
98cdf0e10cSrcweir    writePch(pchname, header, footer, acceptedlines, lines)
99cdf0e10cSrcweir    if testSequenceBuild(dirlist):
100cdf0e10cSrcweir        return acceptedlines + lines
101cdf0e10cSrcweir
102cdf0e10cSrcweir    # Reject one liners
103cdf0e10cSrcweir    if linecount == 1:
104*b0ad9294SPedro Giffuni        print(indent + "Rejected: " + lines[0])
105cdf0e10cSrcweir        return acceptedlines
106cdf0e10cSrcweir
107cdf0e10cSrcweir    # Recurse with multiline slices
108cdf0e10cSrcweir    fanout = 4
109cdf0e10cSrcweir    splits = []
110cdf0e10cSrcweir    for i in range(3):
111cdf0e10cSrcweir        splits.append(linecount * (i + 1) / fanout)
112cdf0e10cSrcweir    splits.append(linecount)
113cdf0e10cSrcweir
114cdf0e10cSrcweir    splitstart = 0
115cdf0e10cSrcweir    for splitend in splits:
116cdf0e10cSrcweir        # avoid splitting in case we have no resulting lines
117cdf0e10cSrcweir        if (splitend - splitstart) == 0:
118cdf0e10cSrcweir            continue
119cdf0e10cSrcweir        splitslice = lines[splitstart:splitend]
120*b0ad9294SPedro Giffuni        print(indent + "[" + str(startpoint + splitstart) + ":" + str(startpoint + splitend) + "] (" + str(splitend - splitstart) + ")")
121cdf0e10cSrcweir        acceptedlines = binaryTest(dirlist, splitslice, pchname, header, footer, acceptedlines, indent + " ", startpoint + splitstart)
122cdf0e10cSrcweir        splitstart = splitend
123cdf0e10cSrcweir
124cdf0e10cSrcweir    return acceptedlines
125cdf0e10cSrcweir
126cdf0e10cSrcweir# ------------------------------------------------------------------------------
127cdf0e10cSrcweir# Main entry point
128cdf0e10cSrcweir
129cdf0e10cSrcweirif len(sys.argv) < 3:
130*b0ad9294SPedro Giffuni    print("Usage: " + sys.argv[0] + " <pch_target> <dir1> [<dir2> <dir3> ...]")
131cdf0e10cSrcweir    sys.exit(1)
132cdf0e10cSrcweir
133cdf0e10cSrcweirpchname = os.path.abspath(sys.argv[1])
134cdf0e10cSrcweirdirlist = sys.argv[2:]
135cdf0e10cSrcweir
136cdf0e10cSrcweir# remove old build log file
137cdf0e10cSrcweirif os.path.exists("buildlog.txt"):
138cdf0e10cSrcweir    os.remove("buildlog.txt")
139cdf0e10cSrcweir
140cdf0e10cSrcweir# test for corner case of everything working from the start
141cdf0e10cSrcweirif testSequenceBuild(dirlist):
142*b0ad9294SPedro Giffuni    print("pch working, nothing to do.")
143cdf0e10cSrcweir    sys.exit(0)
144cdf0e10cSrcweir
145cdf0e10cSrcweir# Open the header file for reading
146cdf0e10cSrcweirinputfile = file(pchname, "r+")
147cdf0e10cSrcweirinputdata = inputfile.read()
148cdf0e10cSrcweirinputfile.close()
149cdf0e10cSrcweir
150cdf0e10cSrcweirsegments = inputdata.split(MARKER)
151cdf0e10cSrcweirheader = segments[0]
152cdf0e10cSrcweirfooter = segments[2]
153cdf0e10cSrcweirlines = segments[1].split("\n")
154cdf0e10cSrcweir
155cdf0e10cSrcweirwritePch(pchname + "_backup", header, footer, lines, [])
156cdf0e10cSrcweir
157cdf0e10cSrcweir# test for corner case of no convergence possible
158cdf0e10cSrcweirwritePch(pchname, header, footer, [], [])
159cdf0e10cSrcweirif not testSequenceBuild(dirlist):
160cdf0e10cSrcweir    writePch(pchname, header, footer, lines, [])
161*b0ad9294SPedro Giffuni    print("Building with no candidate lines failed. Convergence questionable, aborting.")
162cdf0e10cSrcweir    sys.exit(0)
163cdf0e10cSrcweir
164cdf0e10cSrcweir# Starting pruning
165*b0ad9294SPedro Giffuniprint("Starting evaluation of " + str(len(lines)) + " lines")
166cdf0e10cSrcweiracceptedlines = binaryTest(dirlist, lines, pchname, header, footer, [], "", 0)
167cdf0e10cSrcweirwritePch(pchname, header, footer, acceptedlines, [])
168