Michal Marek 7276a4
#!/usr/bin/env python
Michal Marek 7276a4
"""
Michal Marek 7276a4
xen-port-patches.py [git dir]
Michal Marek 7276a4
Create custom patches for xen from custom patches that affect x86.
Michal Marek 7276a4
Turned out to be a little functional programming exercise for the author.
Michal Marek 7276a4
(c) 2005-04-06, Kurt Garloff <garloff@suse.de>
Michal Marek 7276a4
"""
Michal Marek 7276a4
Michal Marek 7276a4
import re, glob, sys, os, filecmp
Michal Marek 7276a4
Michal Marek 7276a4
# List of replacement rules
Michal Marek 7276a4
replrules = [(r"(.*)-xen(\.[^/\s])", r"\1\2"),
Michal Marek 7276a4
	   (r"include/asm-([^/\s]+86[^/\s]*)/mach-xen/asm/", r"include/asm-\1/"),
Michal Marek 7276a4
	   (r"arch/([^/\s]+86[^/\s]*)/include/mach-xen/asm/", r"arch/\1/include/asm/")]
Michal Marek 7276a4
# List of compiled rules (speed reasons)
Michal Marek 7276a4
#comprules = map(lambda(x): (x[0], x[1], re.compile(x[0])), replrules)
Michal Marek 7276a4
comprules = [ (x[0], x[1], re.compile(x[0])) for x in replrules ]
Michal Marek 7276a4
Michal Marek 7276a4
def applCorrFwd(path):
Michal Marek 7276a4
	"Try to apply replrules, return void elem if none applied, otherwise \
Michal Marek 7276a4
	 corresponding old and new name"
Michal Marek 7276a4
	# Maximal functional programming obfusc^W elegance
Michal Marek 7276a4
		# Drop element 2 from each tupel
Michal Marek 7276a4
	return map(lambda(x): (x[0], x[1]), \
Michal Marek 7276a4
		# Filter out non-matched path combinations
Michal Marek 7276a4
		filter(lambda(x): x[2], \
Michal Marek 7276a4
		# Try all replacement rules
Michal Marek 7276a4
		map(lambda(x): (path, 
Michal Marek 7276a4
			re.sub(x[0], x[1], path), x[2].search(path)),
Michal Marek 7276a4
			comprules)))
Michal Marek 7276a4
Michal Marek 7276a4
Michal Marek 7276a4
def createReplList(patch):
Michal Marek 7276a4
	"Creates a list of files to watch and their corresp xen file names"
Michal Marek 7276a4
	pfile = open(patch, "r")
Michal Marek 7276a4
	srch = re.compile(r"^\+\+\+ [^/\s]+/([\S]*)")
Michal Marek 7276a4
	# Again illegi^W beautiful functional programming
Michal Marek 7276a4
	# return matched string no 1
Michal Marek 7276a4
	matches = map(lambda(m): m.group(1), \
Michal Marek 7276a4
		# filter out non-matches
Michal Marek 7276a4
		filter(lambda(m): m, \
Michal Marek 7276a4
		# find matches
Michal Marek 7276a4
		map(lambda(line): srch.search(line), pfile)))
Michal Marek 7276a4
	pfile.close()
Michal Marek 7276a4
	#print matches
Michal Marek 7276a4
	# Try path replacements, drop empty elements and one nesting level
Michal Marek 7276a4
	return map(lambda(x): (x[0][0], x[0][1]), \
Michal Marek 7276a4
			filter(lambda(x): x, map(applCorrFwd, matches)))
Michal Marek 7276a4
Michal Marek 7276a4
def findPatchFiles(kgit):
Michal Marek 7276a4
	"Returns a list of all files in patches.*/ on below kgit"
Michal Marek 7276a4
	list = glob.glob(kgit + "/patches.*/*")
Michal Marek 7276a4
	# Avoid patches in patches.xen, backup files
Michal Marek 7276a4
	filterout = re.compile("(patches\.xen|~$|\.#)")
Michal Marek 7276a4
	return filter(lambda(x): not filterout.search(x), list)
Michal Marek 7276a4
Michal Marek 7276a4
def writePatch(fname, hdr, body):
Michal Marek 7276a4
	"Create xen patch corresponding to other patch"
Michal Marek 7276a4
	xenrepl = re.compile(r"^.*\/([^\/]*)$")
Michal Marek 7276a4
	xenfname = re.sub(xenrepl, r"xen3-\1", fname)
Michal Marek 7276a4
	shortrepl = re.compile(r"^.*\/([^\/]*\/[^\/]*)$")
Michal Marek 7276a4
	shortname = re.sub(shortrepl, r"\1", fname)
Michal Marek 7276a4
	origname = ".".join([xenfname, "orig"])
Michal Marek 7276a4
	print "%s -> %s" % (shortname, xenfname)
Michal Marek 7276a4
	if os.access(xenfname, os.F_OK):
Michal Marek 7276a4
		os.rename(xenfname, origname)
Michal Marek 7276a4
	pfile = open(xenfname, "w")
Michal Marek 7276a4
	pfile.write(hdr)
Michal Marek 7276a4
	pfile.write("Automatically created from \"%s\" by " \
Michal Marek 7276a4
			"xen-port-patches.py\n\n" % shortname)
Michal Marek 7276a4
	pfile.write(body)
Michal Marek 7276a4
	pfile.close()
Michal Marek 7276a4
	if os.access(origname, os.F_OK):
Michal Marek 7276a4
		if filecmp.cmp(xenfname, origname):
Michal Marek 7276a4
			os.remove(xenfname)
Michal Marek 7276a4
	else:
Michal Marek 7276a4
		ser = open("xen3-series.conf", "a")
Michal Marek 7276a4
		ser.write("\t\t%s\n" % xenfname)
Michal Marek 7276a4
		ser.close()
Michal Marek 7276a4
Michal Marek f771f0
def decorateSubject(subject):
Michal Marek f771f0
	m = re.search(r"^(Subject:\s*(?:\[.*\])?\s*)(.*)", subject);
Michal Marek f771f0
	if not m:
Michal Marek f771f0
		return subject
Michal Marek f771f0
	if re.search(r"^[^\s]*:[^:]*$", m.group(2)):
Michal Marek f771f0
		# subsystem: text -> xen/subsystem: text
Michal Marek f771f0
		tag = "xen/"
Michal Marek f771f0
	else:
Michal Marek f771f0
		# text -> xen: text
Michal Marek f771f0
		tag = "xen: "
Michal Marek f771f0
	return m.group(1) + tag + m.group(2) + "\n"
Michal Marek f771f0
Michal Marek 7276a4
def mayCreatePatch(fname, repls):
Michal Marek 7276a4
	"Try to apply the replacement rules to fname"
Michal Marek 7276a4
	if fname.endswith(".gz"):
Michal Marek 7276a4
		decomp ="gzip"
Michal Marek 7276a4
	elif fname.endswith(".bz2"):
Michal Marek 7276a4
		decomp = "bzip2"
Michal Marek 7276a4
	elif fname.endswith(".xz"):
Michal Marek 7276a4
		decomp = "xz"
Michal Marek 7276a4
	else:
Michal Marek 7276a4
		decomp = ""
Michal Marek 7276a4
	if decomp == "":
Michal Marek 7276a4
		pfile = open(fname, "r")
Michal Marek 7276a4
	else:
Michal Marek 7276a4
		pfile = os.popen(" ".join([decomp, "-dc", fname]), "r")
Michal Marek 7276a4
		parts = fname.split(".")
Michal Marek 7276a4
		del parts[-1]
Michal Marek 7276a4
		fname = ".".join(parts)
Michal Marek 7276a4
	# Again an unelegant loop with an ugly state machine
Michal Marek 7276a4
	active = 0; header = 0
Michal Marek 7276a4
	patch = ""; rule = ()
Michal Marek 7276a4
	patchheader = ""; pheaderactive = 1
Michal Marek 7276a4
	endmarker = re.compile(r"^(Index|diff|CVS|RCS|\-\-\-|\+\+\+|===)")
Michal Marek f771f0
	subj = re.compile(r"^Subject:\s")
Michal Marek 34eaba
	commit = re.compile(r"^Git-[Cc]ommit:\s")
Michal Marek 34eaba
	mainline = re.compile(r"^Patch-[Mm]ainline:\s")
Michal Marek 7276a4
	for line in pfile:
Michal Marek 7276a4
		hmark = endmarker.search(line)
Michal Marek 7276a4
		if pheaderactive:
Michal Marek 7276a4
			if hmark:
Michal Marek 7276a4
				pheaderactive = 0
Michal Marek 7276a4
			else:
Michal Marek f771f0
				if subj and subj.search(line):
Michal Marek f771f0
					subj = None
Michal Marek f771f0
					line = decorateSubject(line)
Michal Marek 34eaba
				elif commit.search(line):
Michal Marek 34eaba
					continue
Michal Marek 34eaba
				elif mainline.search(line):
Michal Marek 34eaba
					line = "Patch-mainline: Never, SUSE-Xen specific\n"
Michal Marek 7276a4
				patchheader += line
Michal Marek 7276a4
				continue
Michal Marek 7276a4
		# If we get here, we're past the patch file header
Michal Marek 7276a4
		if active:
Michal Marek 7276a4
			if header:
Michal Marek 7276a4
				if not hmark:
Michal Marek 7276a4
					header = 0
Michal Marek 7276a4
				#else:
Michal Marek 7276a4
				patch += re.sub(rule[1], rule[0], line)
Michal Marek 7276a4
			else:
Michal Marek 7276a4
				if hmark:
Michal Marek 7276a4
					active = 0
Michal Marek 7276a4
				else:
Michal Marek 7276a4
					patch += line
Michal Marek 7276a4
		# else is no good, need to test again
Michal Marek 7276a4
		if not active and hmark:
Michal Marek 7276a4
			matches = filter(lambda(x): x[2],
Michal Marek 7276a4
				map(lambda(x): (x[0], x[1], x[2].search(line)), repls))
Michal Marek 7276a4
			if matches:
Michal Marek 7276a4
				active = 1; header = 1
Michal Marek 7276a4
				# There should never be more than one match ...
Michal Marek 7276a4
				rule = (matches[0][0], matches[0][1])
Michal Marek 7276a4
				patch += re.sub(rule[1], rule[0], line)
Michal Marek 7276a4
	pfile.close()
Michal Marek 7276a4
	if patch:
Michal Marek 7276a4
		writePatch(fname, patchheader, patch)
Michal Marek 7276a4
Michal Marek 7276a4
def createXenPatches(filelist, repls):
Michal Marek 7276a4
	"For each file in the list, find hunks that may be needed for Xen"
Michal Marek 7276a4
	# We could do this again with functional programming, but the
Michal Marek 7276a4
	# memory requirements may be significant, so let's create a
Michal Marek 7276a4
	# loop on the per patchfile level.
Michal Marek 7276a4
	for pfile in filelist:
Michal Marek 7276a4
		mayCreatePatch(pfile, repls)
Michal Marek 7276a4
Michal Marek 7276a4
def main(args):
Michal Marek 7276a4
	"Main program"
Michal Marek 7276a4
	# Allow overriding kernel git dir
Michal Marek 7276a4
	if len(args) > 1 and args[1] != ".":
Michal Marek 7276a4
		kerngit = args[1]
Michal Marek 7276a4
	else:
Michal Marek 7276a4
		kerngit = re.sub(r"^(.*)/[^/]+/[^/]+$", r"\1", os.path.abspath(args[0]))
Michal Marek 7276a4
	print "Using kernel git at '%s'" % (kerngit)
Michal Marek 7276a4
	# Create list of replacements
Michal Marek 7276a4
	repllist = createReplList(kerngit + "/patches.xen/xen3-auto-xen-arch.diff")
Michal Marek 7276a4
	#print repllist
Michal Marek 7276a4
	# ... and compile
Michal Marek 7276a4
	complrepl = map(lambda(x): (x[0], x[1], re.compile(x[1])), repllist)
Michal Marek 7276a4
	# Create a list of patch files
Michal Marek 7276a4
	patchfiles = findPatchFiles(kerngit)
Michal Marek 7276a4
	#print patchfiles
Michal Marek 7276a4
	createXenPatches(patchfiles + args[2:], complrepl)
Michal Marek 7276a4
Michal Marek 7276a4
# Entry point
Michal Marek 7276a4
if __name__ == '__main__':
Michal Marek 7276a4
	main(sys.argv)
Michal Marek 7276a4