#!/usr/bin/env python3

import os, sys, re
import getopt

re_head = re.compile("^binary-arch_(.*)_real::")
re_flav = re.compile("binary-arch-flavour")
re_item = re.compile("[A-Z_]*='[^']*'")

try:
	f = open("debian/rules.gen", "r")
except:
	print("Unable to open debian/rules.gen; can't continue.")
	sys.exit(1)
lines = f.readlines()
f.close()

line = 0

configlist = []
configdict = {}

# scan Debian rules.gen file and gather all variable data into a more useable format:

while line < len(lines):
	head_match = re_head.match(lines[line])
	if not head_match:
		line += 1
		continue
	config_name = head_match.group(1)
	line += 1
	if not re_flav.findall(lines[line]):
		continue
	lsplit = re_item.findall(lines[line])
	groovydict = {}
	for item in lsplit:
		kv = item.split("=", 1)
		if len(kv) < 2:
			continue
		groovydict[kv[0]] = kv[1][1:-1]
	configlist.append(config_name)
	configdict[config_name] = groovydict
	line += 1

# We will organize the arch, featureset and flavors into cascading lists so
# that we can present a nice clean chart of what's available to the user:

archdict = {}

for config in configlist:
	cs = config.split("_")
	if not cs[0] in archdict:
		archdict[cs[0]] = {}
	if cs[1] == "none":
		cs[1] = None
	if cs[1] not in archdict[cs[0]]:
		archdict[cs[0]][cs[1]] = []
	archdict[cs[0]][cs[1]].append(cs[2])

arches = list(archdict.keys())
arches.sort()

features = [None]
for arch in arches:
	for flav in archdict[arch]:
		if flav not in features:
			features.append(flav)

PROG = "config-extract"


def usage():
	print(
		"""This work is free software.

Copyright 2011 Funtoo Solutions. You can redistribute and/or modify it under
the terms of the GNU General Public License version 3 as published by the Free
Software Foundation. Alternatively you may (at your option) use any other
license that has been publicly approved for use with this program by Funtoo
Technologies (or its successors, if any.)

usage: %s [options] arch [featureset] [subarch]
  
  -h  --help        print this usage and exit
  -l  --list        list all available kernel configurations
  -o  --outfile     specify kernel config outfile --
                    defaults to .config in current directory
  [featureset]      defaults to "standard" if not specified
  [subarch]         defaults to the only one available; otherwise required

This program was written by Daniel Robbins for Funtoo Linux, for the purpose of
easily and conveniently extracting Debian kernel configurations. To see a nice
list of all available kernel configurations, use the --list option.

Debian's kernel configs are specified internally in arch_featureset_flavor
format, such as: "amd64_openvz_amd64". The featureset typically describes an
optional kernel configuration such as "xen" or "openvz", while the flavor in
Debian terminology typically refers to the sub-architecture of the CPU.

When using this command, you must specify an arch. A featureset of "standard" is
assumed unless you specify one, and by default this program will pick the only
available subarch if there is only one to choose from. If not, you will need to
pick one (and the program will remind you to do this.)

The kernel configuration will be written to ".config" in the current directory,
or the location you specified using the -o/--outfile option.
"""
		% PROG
	)
	sys.exit(2)


try:
	opts, args = getopt.getopt(sys.argv[1:], "o:hl", ["help", "list", "outfile="])
except getopt.GetoptError as err:
	print(str(err))
	usage()

mode = "run"
outfile = None
for o, a in opts:
	if o in ("-h", "--help"):
		usage()
	elif o in ("-l", "--list"):
		mode = "list"
	elif o in ("-o", "--outfile"):
		outfile = a
	else:
		assert False, "Unhandled option"
if mode == "run":
	if len(args) < 1 or len(args) > 3:
		if len(args) == 0:
			print("Please specify an arch - one of: " + ", ".join(arches))
			sys.exit(2)
		else:
			print("Too many arguments.")
			usage()
	arch = args[0]
	if outfile == None:
		outfile = os.path.join(os.getcwd(), ".config")
	featureset = None
	subarch = None
	if len(args) == 3:
		featureset = args[1]
		subarch = args[2]
	elif len(args) == 2:
		featureset = args[1]
	if featureset == "standard":
		featureset = None

# print out optimized list of available kernel configurations:

if mode == "list":
	print()
	for flav in features:
		label = flav
		if label == None:
			label = "standard"
		print("====== %s featureset ======" % label)
		print()
		for arch in arches:
			if flav in archdict[arch]:
				if len(archdict[arch][flav]) == 1:
					print(arch.rjust(12))
				else:
					flavlist = archdict[arch][flav]
					flavlist.sort()
					variants = ", ".join(flavlist)
					print(arch.rjust(12) + ":", variants)
		print()
	sys.exit(0)

# featureset defaults to None.

if featureset not in archdict[arch]:
	print("Error: There is no '%s' featureset kernel config for arch '%s'. Exiting." % (featureset, arch))
	print(archdict[arch])
	sys.exit(2)

# If a subarch is not specified (None), then we will auto-pick the subarch if only one is available.
# Debian often has an "amd64" subarch for the "amd64" arch, rather than "none" as I might expect:

if subarch == None:
	if len(archdict[arch][featureset]) == 1:
		subarch = archdict[arch][featureset][0]
	else:
		print("Error: there is more than one 'sub-architecture' for this arch.")
		print("Please specify [arch] [featureset] [subarch], with one of these subarches:")
		print(", ".join(archdict[arch][featureset]))
		sys.exit(2)
else:
	if subarch not in archdict[arch][featureset]:
		print("Error: specified sub-architecture '%s' is not available for this arch. Exiting." % subarch)
		sys.exit(2)

# We've done all our arg processing, now let's construct the master_key that we will use to look up the
# proper settings to pass to Debian's debian/bin/kconfig.py command:

master_key = arch
if featureset == None:
	master_key += "_none"
else:
	master_key += "_%s" % featureset
if subarch == None:
	master_key += "_none"
else:
	master_key += "_%s" % subarch
if master_key not in configdict:
	print("Master key lookup failed; can't continue. Please report this bug.")
	sys.exit(1)
if "KCONFIG" not in configdict[master_key]:
	print("Unable to find KCONFIG option; can't continue. Please report this bug.")
	sys.exit(1)
cmd = "python3 debian/bin/kconfig.py '%s' %s" % (outfile, configdict[master_key]["KCONFIG"])
if "KCONFIG_OPTIONS" in configdict[master_key]:
	cmd += " %s" % configdict[master_key]["KCONFIG_OPTIONS"]
os.environ["PYTHONPATH"] = "debian/lib/python"
retval = os.system(cmd)
if retval == 0:
	print("Wrote %s kernel configuration to %s." % (master_key, outfile))
	sys.exit(0)
else:
	print("There was an error extracting the Debian kernel config.")
	sys.exit(1)
