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