1# -*- coding: utf-8 -*- 2# 3# Copyright 2013 Ingo Weinhold 4# Copyright 2014 Oliver Tappe 5# Distributed under the terms of the MIT License. 6 7# -- Modules ------------------------------------------------------------------ 8 9from . import BuildPlatform 10from .Configuration import Configuration 11from .Options import getOption 12from .PackageInfo import PackageInfo, Resolvable 13from .Utils import versionCompare 14 15# -- ProvidesInfo class ------------------------------------------------------- 16 17class ProvidesInfo(Resolvable): 18 def __init__(self, packageInfo, providesString): 19 super(ProvidesInfo, self).__init__(providesString) 20 self.packageInfo = packageInfo 21 22 @property 23 def packageID(self): 24 return self.packageInfo.versionedName 25 26 @property 27 def path(self): 28 return self.packageInfo.path 29 30# -- ProvidesManager class ---------------------------------------------------- 31 32class ProvidesManager(object): 33 def __init__(self): 34 self._providesMap = {} 35 self._providesSourceMap = {} 36 self.architectures = [BuildPlatform.buildPlatform.targetArchitecture, 37 'any', 'source'] 38 39 def addProvidesFromPackage(self, package): 40 for providesString in package.recipeKeys['PROVIDES']: 41 self._addPackageProvidesInfo(package.revisionedName, providesString) 42 43 def addProvidesFromPackageInfo(self, packageInfo): 44 if (packageInfo.architecture not in self.architectures 45 and not (Configuration.isCrossBuildRepository() 46 and '_cross_' in packageInfo.path)): 47 return 48 49 for provides in packageInfo.provides: 50 self._addPackageProvidesInfo(packageInfo, str(provides)) 51 52 def getMatchingProvides(self, resolvableExpression, anyHpkg=False, 53 ignoreBase=False): 54 name = resolvableExpression.name 55 operator = resolvableExpression.operator 56 version = resolvableExpression.version 57 base = resolvableExpression.base 58 59 if name not in self._providesMap: 60 return None 61 62 updateDependencies = getOption('updateDependencies') 63 missingDependencies = getOption('missingDependencies') 64 65 providesList = self._providesMap[name] 66 67 found = None 68 foundIsHpkg = False 69 for provides in providesList: 70 provideIsHpkg = (provides.packageInfo.path.endswith('.hpkg') 71 if isinstance(provides.packageInfo, PackageInfo) else False) 72 if not ignoreBase and base and provideIsHpkg: 73 continue 74 if not operator: 75 if not updateDependencies and not missingDependencies: 76 return provides 77 if (found is None or 78 (anyHpkg and provideIsHpkg) or 79 (provideIsHpkg and not foundIsHpkg and 80 (missingDependencies or found.version is None 81 or versionCompare(provides.version, found.version) >= 0))): 82 found = provides 83 foundIsHpkg = provideIsHpkg 84 continue 85 if not provides.version: 86 continue 87 matches = { 88 '<': lambda compareResult: compareResult < 0, 89 '<=': lambda compareResult: compareResult <= 0, 90 '==': lambda compareResult: compareResult == 0, 91 '!=': lambda compareResult: compareResult != 0, 92 '>=': lambda compareResult: compareResult >= 0, 93 '>': lambda compareResult: compareResult > 0, 94 }[operator](versionCompare(provides.version, version)) 95 if not matches: 96 continue 97 if (provides.compatibleVersion 98 and versionCompare(provides.compatibleVersion, version) > 0): 99 continue 100 if not updateDependencies and not missingDependencies: 101 return provides 102 if (found is None or 103 (anyHpkg and provideIsHpkg) or 104 (provideIsHpkg and not foundIsHpkg and 105 (missingDependencies or found.version is None 106 or versionCompare(provides.version, found.version) >= 0))): 107 found = provides 108 foundIsHpkg = provideIsHpkg 109 return found 110 111 @staticmethod 112 def _providesSource(packageInfo): 113 return packageInfo.path if isinstance(packageInfo, PackageInfo) \ 114 else packageInfo 115 116 117 def _addPackageProvidesInfo(self, packageInfo, providesString): 118 provides = ProvidesInfo(packageInfo, providesString.strip()) 119 120 source = self._providesSource(packageInfo) 121 if source in self._providesSourceMap: 122 self._providesSourceMap[source].append(provides) 123 else: 124 self._providesSourceMap[source] = [provides] 125 126 if provides.name in self._providesMap: 127 self._providesMap[provides.name].append(provides) 128 else: 129 self._providesMap[provides.name] = [provides] 130 131 def removeProvidesOfPackageInfo(self, packageInfo): 132 source = self._providesSource(packageInfo) 133 providesList = self._providesSourceMap.pop(source) 134 for provides in providesList: 135 self._providesMap[provides.name].remove(provides) 136