1# -*- coding: utf-8 -*-
2#
3# Copyright 2013 Ingo Weinhold
4# Distributed under the terms of the MIT License.
5
6# -- Modules ------------------------------------------------------------------
7
8import os
9from subprocess import CalledProcessError
10
11from .PackageInfo import PackageInfo, Resolvable, ResolvableExpression
12from .ProvidesManager import ProvidesManager
13from .Utils import sysExit
14
15# -- ProvidesInfo class -------------------------------------------------------
16
17class ProvidesInfo(Resolvable):
18	def __init__(self, package, providesString):
19		super(ProvidesInfo, self).__init__(providesString)
20		self.package = package
21
22# -- RequiresUpdater class ----------------------------------------------------
23
24class RequiresUpdater(object):
25	def __init__(self, portPackages, requiredPackages):
26		self._providesManager = ProvidesManager()
27
28		# get the provides for the port packages
29		for package in portPackages:
30			self._providesManager.addProvidesFromPackage(package)
31
32		# get the provides for the required packages
33		for package in requiredPackages:
34			if package.endswith('.hpkg'):
35				self.addPackageFile(package)
36
37	def addPackageFile(self, package):
38		try:
39			packageInfo = PackageInfo(package)
40		except CalledProcessError:
41			sysExit('failed to get provides for package "%s"' % package)
42
43		self._providesManager.addProvidesFromPackageInfo(packageInfo)
44
45	def addPackages(self, directory):
46		for package in os.listdir(directory):
47			if package.endswith('.hpkg') or package.endswith('.PackageInfo'):
48				self.addPackageFile(directory + '/' + package)
49
50	def updateRequiresList(self, requiresList):
51		result = []
52		for requires in requiresList:
53			requires = requires.strip()
54			if not requires.startswith('#'):
55				result.append(self._updateRequires(requires))
56		return result
57
58	def getMatchingProvides(self, resolvableExpression):
59		return self._providesManager.getMatchingProvides(resolvableExpression)
60
61	def _updateRequires(self, requires):
62		# split the requires string
63		requires = requires.strip()
64		partialRequires = requires
65		isBase = requires.endswith('base')
66		if isBase:
67			partialRequires = requires[:-4].rstrip()
68
69		resolvableExpression = ResolvableExpression(partialRequires)
70		name = resolvableExpression.name
71		operator = resolvableExpression.operator
72
73		# check whether there's a matching provides and, if so, replace the
74		# given requires
75		matchingProvides = self.getMatchingProvides(resolvableExpression)
76		if not matchingProvides:
77			if self.getMatchingProvides(ResolvableExpression(name)):
78				sysExit('found provides for "%s", but none matching the '
79					'version requirement' % requires)
80			return requires
81
82		if not matchingProvides.version:
83			return requires
84		if operator in ['<', '<=', '!=']:
85			return requires
86
87		# Enforce the minimum found version, if the requires has no version
88		# requirement or also a minimum. Otherwise enforce the exact version
89		# found.
90		resultOperator = '>=' if operator in [None, '> ', '>='] else '=='
91		result = '%s %s %s' \
92			% (matchingProvides.name, resultOperator, matchingProvides.version)
93		if isBase:
94			result += ' base'
95		return result
96