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