#!/usr/bin/python
# Copyright 1999-2007 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Id$

import errno, signal, sys, os
from itertools import izip

def quickpkg_main(options, args, eout):
	from portage import catsplit, dep_expand, flatten, isvalidatom, xpak
	from portage.dep import use_reduce, paren_reduce
	from portage.util import ConfigProtect, ensure_dirs
	from portage.exception import InvalidData, InvalidDependString
	from portage.dbapi.vartree import dblink, tar_contents
	from portage.checksum import perform_md5
	import tarfile
	import portage
	root = portage.settings["ROOT"]
	trees = portage.db[root]
	vartree = trees["vartree"]
	vardb = vartree.dbapi
	bintree = trees["bintree"]
	try:
		ensure_dirs(bintree.pkgdir)
	except portage.exception.PortageException:
		pass
	if not os.access(bintree.pkgdir, os.W_OK):
		eout.eerror("No write access to '%s'" % bintree.pkgdir)
		return errno.EACCES
	successes = []
	missing = []
	config_files_excluded = 0
	include_config = options.include_config == "y"
	include_unmodified_config = options.include_unmodified_config == "y"
	fix_metadata_keys = ["PF", "CATEGORY"]
	for arg in args:
		try:
			atom = dep_expand(arg, mydb=vardb, settings=vartree.settings)
		except ValueError, e:
			# Multiple matches thrown from cpv_expand
			eout.eerror("Please use a more specific atom: %s" % \
				" ".join(e.args[0]))
			del e
			missing.append(arg)
			continue
		except InvalidData, e:
			eout.eerror("Invalid atom: %s" % str(e))
			del e
			missing.append(arg)
			continue
		if not isvalidatom(atom):
			eout.eerror("Invalid atom: %s" % atom)
			missing.append(arg)
			continue
		matches = vardb.match(atom)
		pkgs_for_arg = 0
		for cpv in matches:
			excluded_config_files = []
			bintree.prevent_collision(cpv)
			cat, pkg = catsplit(cpv)
			dblnk = dblink(cat, pkg, root,
				vartree.settings, treetype="vartree",
				vartree=vartree)
			dblnk.lockdb()
			try:
				if not dblnk.exists():
					# unmerged by a concurrent process
					continue
				iuse, use, restrict = vardb.aux_get(cpv,
					["IUSE","USE","RESTRICT"])
				iuse = [ x.lstrip("+-") for x in iuse.split() ]
				use = use.split()
				try:
					restrict = flatten(use_reduce(
						paren_reduce(restrict), uselist=use))
				except InvalidDependString, e:
					eout.eerror("Invalid RESTRICT metadata " + \
						"for '%s': %s; skipping" % (cpv, str(e)))
					del e
					continue
				if "bindist" in iuse and "bindist" not in use:
					eout.ewarn("%s: package was emerged with USE=-bindist!" % cpv)
					eout.ewarn("%s: it may not be legal to redistribute this." % cpv)
				elif "bindist" in restrict:
					eout.ewarn("%s: package has RESTRICT=bindist!" % cpv)
					eout.ewarn("%s: it may not be legal to redistribute this." % cpv)
				eout.ebegin("Building package for %s" % cpv)
				pkgs_for_arg += 1
				contents = dblnk.getcontents()
				protect = None
				if not include_config:
					confprot = ConfigProtect(root,
						portage.settings.get("CONFIG_PROTECT","").split(),
						portage.settings.get("CONFIG_PROTECT_MASK","").split())
					def protect(filename):
						if not confprot.isprotected(filename):
							return False
						if include_unmodified_config:
							file_data = contents[filename]
							if file_data[0] == "obj":
								orig_md5 = file_data[2].lower()
								cur_md5 = perform_md5(filename, calc_prelink=1)
								if orig_md5 == cur_md5:
									return False
						excluded_config_files.append(filename)
						return True
				existing_metadata = dict(izip(fix_metadata_keys,
					vardb.aux_get(cpv, fix_metadata_keys)))
				category, pf = portage.catsplit(cpv)
				required_metadata = {}
				required_metadata["CATEGORY"] = category
				required_metadata["PF"] = pf
				update_metadata = {}
				for k, v in required_metadata.iteritems():
					if v != existing_metadata[k]:
						update_metadata[k] = v
				if update_metadata:
					vardb.aux_update(cpv, update_metadata)
				xpdata = xpak.xpak(dblnk.dbdir)
				binpkg_tmpfile = os.path.join(bintree.pkgdir,
					cpv + ".tbz2." + str(os.getpid()))
				ensure_dirs(os.path.dirname(binpkg_tmpfile))
				tar = tarfile.open(binpkg_tmpfile, "w:bz2")
				tar_contents(contents, root, tar, protect=protect)
				tar.close()
				xpak.tbz2(binpkg_tmpfile).recompose_mem(xpdata)
			finally:
				dblnk.unlockdb()
			bintree.inject(cpv, filename=binpkg_tmpfile)
			binpkg_path = bintree.getname(cpv)
			try:
				s = os.stat(binpkg_path)
			except OSError, e:
				# Sanity check, shouldn't happen normally.
				eout.eend(1)
				eout.eerror(str(e))
				del e
				eout.eerror("Failed to create package: '%s'" % binpkg_path)
			else:
				eout.eend(0)
				successes.append((cpv, s.st_size))
				config_files_excluded += len(excluded_config_files)
				for filename in excluded_config_files:
					eout.ewarn("Excluded config: '%s'" % filename)
		if not pkgs_for_arg:
			eout.eerror("Could not find anything " + \
				"to match '%s'; skipping" % arg)
			missing.append(arg)
	if not successes:
		eout.eerror("No packages found")
		return 1
	print
	eout.einfo("Packages now in '%s':" % bintree.pkgdir)
	import math
	units = {10:'K', 20:'M', 30:'G', 40:'T',
		50:'P', 60:'E', 70:'Z', 80:'Y'}
	for cpv, size in successes:
		if not size:
			# avoid OverflowError in math.log()
			size_str = "0"
		else:
			power_of_2 = math.log(size, 2)
			power_of_2 = 10*int(power_of_2/10)
			unit = units.get(power_of_2)
			if unit:
				size = float(size)/(2**power_of_2)
				size_str = "%.1f" % size
				if len(size_str) > 4:
					# emulate `du -h`, don't show too many sig figs
					size_str = str(int(size))
				size_str += unit
			else:
				size_str = str(size)
		eout.einfo("%s: %s" % (cpv, size_str))
	if config_files_excluded:
		print
		eout.ewarn("Excluded config files: %d" % config_files_excluded)
		eout.ewarn("See --help if you would like to include config files.")
	if missing:
		print
		eout.ewarn("The following packages could not be found:")
		eout.ewarn(" ".join(missing))
		return 2
	return os.EX_OK

if __name__ == "__main__":
	usage = "quickpkg [options] <list of package atoms>"
	from optparse import OptionParser
	parser = OptionParser(usage=usage)
	parser.add_option("--umask",
		default="0077",
		help="umask used during package creation (default is 0077)")
	parser.add_option("--ignore-default-opts",
		action="store_true",
		help="do not use the QUICKPKG_DEFAULT_OPTS environment variable")
	parser.add_option("--include-config",
		type="choice",
		choices=["y","n"],
		default="n",
		metavar="<y|n>",
		help="include all files protected by CONFIG_PROTECT (as a security precaution, default is 'n')")
	parser.add_option("--include-unmodified-config",
		type="choice",
		choices=["y","n"],
		default="n",
		metavar="<y|n>",
		help="include files protected by CONFIG_PROTECT that have not been modified since installation (as a security precaution, default is 'n')")
	options, args = parser.parse_args(sys.argv[1:])
	if not options.ignore_default_opts:
		from portage import settings
		default_opts = settings.get("QUICKPKG_DEFAULT_OPTS","").split()
		options, args = parser.parse_args(default_opts + sys.argv[1:])
	if not args:
		parser.error("no packages atoms given")
	try:
		umask = int(options.umask, 8)
	except ValueError:
		parser.error("invalid umask: %s" % options.umask)
	# We need to ensure a sane umask for the packages that will be created.
	old_umask = os.umask(umask)
	from portage.output import get_term_size, EOutput
	eout = EOutput()
	def sigwinch_handler(signum, frame):
		lines, eout.term_columns = get_term_size()
	signal.signal(signal.SIGWINCH, sigwinch_handler)
	try:
		retval = quickpkg_main(options, args, eout)
	finally:
		os.umask(old_umask)
		signal.signal(signal.SIGWINCH, signal.SIG_DFL)
	sys.exit(retval)
