# Copyright 2007 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Id: security.py 14052 2009-08-14 22:57:44Z zmedico $

import portage.glsa as glsa
from portage.sets.base import PackageSet
from portage.versions import catpkgsplit, pkgcmp
from portage.sets import get_boolean

__all__ = ["SecuritySet", "NewGlsaSet", "NewAffectedSet", "AffectedSet"]

class SecuritySet(PackageSet):
	_operations = ["merge"]
	_skip_applied = False
	
	description = "package set that includes all packages possibly affected by a GLSA"
		
	def __init__(self, settings, vardbapi, portdbapi, least_change=True):
		super(SecuritySet, self).__init__()
		self._settings = settings
		self._vardbapi = vardbapi
		self._portdbapi = portdbapi
		self._least_change = least_change

	def getGlsaList(self, skip_applied):
		glsaindexlist = glsa.get_glsa_list(self._settings)
		if skip_applied:
			applied_list = glsa.get_applied_glsas(self._settings)
			glsaindexlist = set(glsaindexlist).difference(applied_list)
			glsaindexlist = list(glsaindexlist)
		glsaindexlist.sort()
		return glsaindexlist
		
	def load(self):
		glsaindexlist = self.getGlsaList(self._skip_applied)
		atomlist = []
		for glsaid in glsaindexlist:
			myglsa = glsa.Glsa(glsaid, self._settings, self._vardbapi, self._portdbapi)
			#print glsaid, myglsa.isVulnerable(), myglsa.isApplied(), myglsa.getMergeList()
			if self.useGlsa(myglsa):
				atomlist += ["="+x for x in myglsa.getMergeList(least_change=self._least_change)]
		self._setAtoms(self._reduce(atomlist))
	
	def _reduce(self, atomlist):
		mydict = {}
		for atom in atomlist[:]:
			cpv = self._portdbapi.xmatch("match-all", atom)[0]
			slot = self._portdbapi.aux_get(cpv, ["SLOT"])[0]
			cps = "/".join(catpkgsplit(cpv)[0:2]) + ":" + slot
			if not cps in mydict:
				mydict[cps] = (atom, cpv)
			else:
				other_cpv = mydict[cps][1]
				if pkgcmp(catpkgsplit(cpv)[1:], catpkgsplit(other_cpv)[1:]) > 0:
					atomlist.remove(mydict[cps][0])
					mydict[cps] = (atom, cpv)
		return atomlist
	
	def useGlsa(self, myglsa):
		return True

	def updateAppliedList(self):
		glsaindexlist = self.getGlsaList(True)
		applied_list = glsa.get_applied_glsas(self._settings)
		for glsaid in glsaindexlist:
			myglsa = glsa.Glsa(glsaid, self._settings, self._vardbapi, self._portdbapi)
			if not myglsa.isVulnerable() and not myglsa.nr in applied_list:
				myglsa.inject()
	
	def singleBuilder(cls, options, settings, trees):
		least_change = not get_boolean(options, "use_emerge_resolver", False)
		return cls(settings, trees["vartree"].dbapi, trees["porttree"].dbapi, least_change=least_change)
	singleBuilder = classmethod(singleBuilder)
	
class NewGlsaSet(SecuritySet):
	_skip_applied = True
	description = "Package set that includes all packages possibly affected by an unapplied GLSA"

class AffectedSet(SecuritySet):
	description = "Package set that includes all packages affected by an unapplied GLSA"

	def useGlsa(self, myglsa):
		return myglsa.isVulnerable()

class NewAffectedSet(AffectedSet):
	_skip_applied = True
	description = "Package set that includes all packages affected by an unapplied GLSA"
