Mercurial > farol > farolluz
view farolluz/producttree.py @ 27:934c510f8077
Fix the imports
author | Benoît Allard <benoit.allard@greenbone.net> |
---|---|
date | Fri, 24 Oct 2014 17:06:34 +0200 |
parents | 809db989cac5 |
children | b87f2a6e613a |
line wrap: on
line source
# -*- coding: utf-8 -*- # # Authors: # BenoƮt Allard <benoit.allard@greenbone.net> # # Copyright: # Copyright (C) 2014 Greenbone Networks GmbH # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. """\ Product Tree Objects related to CVRF Documents """ from .common import ValidationError class CVRFProductTree(object): def __init__(self): # All the branches, they can be order with their `parent` attribute self._branches = [] self._groups = [] self._relationships = [] self._products = [] self._groups = [] def addProduct(self, product): """ Add to the product list """ self._products.append(product) def addRelationship(self, rel): self._relationships.append(rel) def addGroup(self, group): self._groups.append(group) def getProductForID(self, productid): for product in self._products: if product._productid == productid: return product raise KeyError(productid) def getGroupForID(self, groupid): for group in self._groups: if group._groupid == groupid: return group raise KeyError(groupid) def decomposeProduct(self, productid): """ In case of product defined as a relationship (product X installed on OS Y), this gives us the following tuple: (OS, product). """ product = self.getProductForID(productid) parent = product._parent if parent is None: return (None, None) if not isinstance(parent, CVRFRelationship): return (None, None) relationtype = parent._relationtype.replace(' ', '').lower() if relationtype not in ('defaultcomponentof', 'installedon'): return (None, None) return ( self.getProductForID(parent._relatestoproductreference), self.getProductForID(parent._productreference) ) def getBranch(self, path): if len(path) == 0: return self branches = self._branches node = None for idx in path: node = branches[idx] branches = node._childs return node def getBranches(self): for branch in self._branches: yield branch for sub_branch in branch.getBranches(): yield sub_branch def getPath(self): return () def getNameOfRelationship(self, relationship): if relationship is None: return '' return ' '.join((self.getProductForID(relationship._productreference)._name, 'as', relationship._relationtype.lower(), self.getProductForID(relationship._relatestoproductreference)._name)) def getOrphanedBranches(self, product=None): """ The branches that could accept `product` as Product Definition """ white_list = [] if product is not None: white_list = [product._parent] for branch in self.getBranches(): if (branch in white_list) or branch.isOrphaned(): yield branch def getNotTerminalBranches(self, b2=None): """\ The branches that could accept `b2` as new sub-branches Note that b2 and all its sub-branches cannot be listed """ black_list = [] if b2 is not None: black_list = [b2] + list(b2.getBranches()) for branch in self.getBranches(): if branch in black_list: continue if branch._product is None: yield branch def getOrphanedRelationships(self, product=None): """ The relationships that need a product defninition """ white_list = [] if product is not None: white_list = [product.getCurrentRelationship()] for i, relationship in enumerate(self._relationships): if (relationship in white_list) or relationship.isOrphaned(): yield (i, relationship) def nbProducts(self): """ Amount of 'raw' Products """ return len([p for p in self._products if p._parent is self]) def validate(self): for branch in self._branches: branch.validate() productids = set() for product in self._products: product.validate() if product._productid in productids: raise ValidationError('Each ProductID must be unique (%s)' % product._productid) productids.add(product._productid) for relationship in self._relationships: relationship.validate() for productid in (relationship._productreference, relationship._relatestoproductreference): if productid not in productids: raise ValidationError('ProductID %s is unknown' % productid) groupids = set() for group in self._groups: group.validate() if group._groupid in groupids: raise ValidationError('Duplicated GroupID: %s' % group._groupid) groupids.add(group._groupid) for productid in group._productids: if productid not in productids: raise ValidationError('ProductID %s is unknown' % productid) return productids, groupids def __str__(self): return 'Products: %s' % '\n'.join(str(p) for p in self._products) class CVRFProductBranch(object): TYPES = ('Vendor', 'Product Family', 'Product Name', 'Product Version', 'Patch Level', 'Service Pack', 'Architecture', 'Language', 'Legacy', 'Specification') def __init__(self, _type, name, parentbranch): self._type = _type self._name = name self._childs = [] self._product = None self.link(parentbranch) def getParent(self): return self._parentbranch def getPath(self, string=False): """ return the path to that branch element as a tuple """ if self.isRoot(): for i, b in enumerate(self._parentbranch._branches): if b is self: if string: return '%d' % i return (i, ) else: for i, b in enumerate(self._parentbranch._childs): if b is self: if string: return '/'.join([self._parentbranch.getPath(string), '%d' % i]) return self._parentbranch.getPath(string) + (i,) if string: return '' return () def getTree(self): """ this returns a list of tuples (type, name) leading to here""" if self.isRoot(): return [(self._type, self._name)] return self._parentbranch.getTree() + [(self._type, self._name)] def getName(self): return ' / '.join("%s: %s" % (type_, name) for type_, name in self.getTree()) def getParentPath(self): """ return as string the path to the parent """ return '/'.join('%s' % p for p in self.getPath()[:-1]) def isRoot(self): return isinstance(self._parentbranch, CVRFProductTree) def isOrphaned(self): """ Has no childs and no product """ return len(self._childs) == 0 and (self._product is None) def getBranches(self): for branch in self._childs: yield branch for sub_branch in branch.getBranches(): yield sub_branch def unlink(self): """ Unset our _parent, and remove us from the _parent._childs """ if self.isRoot(): self.getParent()._branches.remove(self) else: self.getParent()._childs.remove(self) self._parentbranch = None def link(self, parent): """ Actually, only set the parent """ self._parentbranch = parent if self.isRoot(): parent._branches.append(self) else: parent._childs.append(self) def validate(self): if not self._type: raise ValidationError('A Branch must have a Type') if self._type not in self.TYPES: raise ValidationError('A Branch Type must be one of %s' % ', '.join(self.TYPES)) if not self._name: raise ValidationError('A Branch must have a Name') for branch in self._childs: branch.validate() if self.isOrphaned(): raise ValidationError('A Branch must have at least a sub-product or sub-branches') def __str__(self): return "%s: %s" % (self._type, self._name) class CVRFFullProductName(object): def __init__(self, productid, name, parent, cpe=None): self._productid = productid self._name = name self._cpe = cpe # Can be None (directly under the tree), a ProductBranch, or a # Relationship self.link(parent) def isRoot(self): return isinstance(self._parent, CVRFProductTree) def isRelationship(self): return isinstance(self._parent, CVRFRelationship) def getTree(self): if not isinstance(self._parent, CVRFProductBranch): return [] return self._parent.getTree() def getParentPath(self): if self.isRoot() or self.isRelationship(): return '' return self._parent.getPath(True) def getCurrentRelationship(self): if self.isRelationship(): return self._parent return None def unlink(self): """ Unset our _parent, and remove us from the _parent._childs We are still in the product list. """ if not self.isRoot(): self._parent._product = None self._parent = None def link(self, parent): self._parent = parent if not self.isRoot(): parent._product = self def validate(self): if not self._productid: raise ValidationError('A Product must have a ProductID') if not self._name: raise ValidationError('A Product must have a Name') def __str__(self): return "%s (%s)" % (self._productid, self._name) class CVRFRelationship(object): TYPES = ('Default Component Of', 'Optional Component Of', 'External Component Of', 'Installed On', 'Installed With') def __init__(self, productref, reltype, relatestoproductref): self._productreference = productref self._relationtype = reltype self._relatestoproductreference = relatestoproductref self._product = None def getParent(self): """ All parent element of a FullProductName should implement that method """ return None def isOrphaned(self): return self._product is None def validate(self): if not self._productreference: raise ValidationError('A Relationship must have a Product Reference') if not self._relationtype: raise ValidationError('A Relationship must have a Relation Type') if self._relationtype not in self.TYPES: raise ValidationError('Relation Type must be one of %s' % ', '.join(self.TYPES)) if not self._relatestoproductreference: raise ValidationError('A Relationship must have a "Relates To product Reference"') if self._productreference == self._relatestoproductreference: raise ValidationError('A Relationship cannot reference twice the same Product') class CVRFGroup(object): def __init__(self, groupid): self._groupid = groupid self._description = None self._productids = [] def setDescription(self, description): self._description = description def addProductID(self, productid): self._productids.append(productid) def getTitle(self): if self._description: return "%s (%d products)" % (self._description, len(self._productids)) return "#%s (%d products)" % (self._groupid, len(self._productids)) def validate(self): if not self._groupid: raise ValidationError('A Group must have a GroupID') if not self._productids or len(self._productids) < 2: raise ValidationError('A Group must contain at least two products')