def test_ordered_versop_expressions(self): """Given set of ranges, order them according to version/operator (most recent/specific first)""" # simple version ordering, all different versions ovop = OrderedVersionOperators() versop_exprs = [ '> 3.0.0', '>= 2.5.0', '> 2.0.0', '== 1.0.0', ] # add version expressions out of order intentionally ovop.add(versop_exprs[1]) ovop.add(versop_exprs[-1]) ovop.add(versop_exprs[0]) ovop.add(versop_exprs[2]) # verify whether order is what we expect it to be self.assertEqual(ovop.versops, [VersionOperator(x) for x in versop_exprs]) # more complex version ordering, identical/overlapping vesions ovop = OrderedVersionOperators() versop_exprs = [ '== 1.0.0', '> 1.0.0', '< 1.0.0', ] # add version expressions out of order intentionally ovop.add(versop_exprs[-1]) ovop.add(versop_exprs[1]) ovop.add(versop_exprs[0]) # verify whether order is what we expect it to be self.assertEqual(ovop.versops, [VersionOperator(x) for x in versop_exprs])
def __init__(self): """Initialise Squashed instance""" self.log = fancylogger.getLogger(self.__class__.__name__, fname=False) # OrderedVersionOperators instances to keep track of the data of the matching # version and toolchain version sections self.versions = OrderedVersionOperators() self.tcversions = OrderedVersionOperators() self.result = {}
def _squash_versop(self, key, value, squashed, sanity, vt_tuple): """ Squash VERSION_OPERATOR_VALUE_TYPES value return None or new Squashed instance :param key: section key :param nested_dict: the nested_dict instance :param squashed: Squashed instance :param sanity: the sanity dict :param vt_tuple: version, tc_name, tc_version tuple """ version, tcname, tcversion = vt_tuple if key == 'toolchains': # remove any other toolchain from list self.log.debug("Filtering 'toolchains' key") matching_toolchains = [] tmp_tc_oversops = {} # temporary, only for conflict checking for tcversop in value: tc_overops = tmp_tc_oversops.setdefault(tcversop.tc_name, OrderedVersionOperators()) self.log.debug("Add tcversop %s to tc_overops %s tcname %s tcversion %s", tcversop, tc_overops, tcname, tcversion) tc_overops.add(tcversop) # test non-conflicting list if tcversop.test(tcname, tcversion): matching_toolchains.append(tcversop) if matching_toolchains: # does this have any use? self.log.debug('Matching toolchains %s found (but data not needed)' % matching_toolchains) else: self.log.debug('No matching toolchains, removing the whole current key %s' % key) return Squashed() elif key == 'versions': self.log.debug("Adding all versions %s from versions key" % value) matching_versions = [] tmp_versops = OrderedVersionOperators() # temporary, only for conflict checking for versop in value: tmp_versops.add(versop) # test non-conflicting list if versop.test(version): matching_versions.append(versop) if matching_versions: # does this have any use? self.log.debug('Matching versions %s found (but data not needed)' % matching_versions) else: self.log.debug('No matching versions, removing the whole current key %s' % key) return Squashed() else: raise EasyBuildError('Unexpected VERSION_OPERATOR_VALUE_TYPES key %s value %s', key, value) return None
def test_ordered_versop_add_data(self): """Test the add and data handling""" ovop = OrderedVersionOperators() tests = [ ('> 1', '5'), ('> 2', { 'x': 3 }), ] for versop_txt, data in tests: versop = VersionOperator(versop_txt) ovop.add(versop) # no data was added, this is a new entry, mapper is initialised with None self.assertEqual(ovop.get_data(versop), None) ovop.add(versop, data) # test data self.assertEqual(ovop.get_data(versop), data) # new data for same versops tests = [ ('> 1', '6'), ('> 2', { 'x': 4 }), ] for versop_txt, data in tests: versop = VersionOperator(versop_txt) ovop.add(versop, data) # test updated data self.assertEqual(ovop.get_data(versop), data) # 'update' a value # the data for '> 1' has no .update() extra_data = {'y': 4} tests = [ ('> 2', extra_data), ] for versop_txt, data in tests: versop = VersionOperator(versop_txt) prevdata = copy.deepcopy(ovop.get_data(versop)) prevdata.update(extra_data) ovop.add(versop, data, update=True) # test updated data self.assertEqual(ovop.get_data(versop), prevdata) # use update=True on new element versop = VersionOperator('> 10000') new_data = {'new': 5} ovop.add(versop, new_data, update=True) # test updated data self.assertEqual(ovop.get_data(versop), new_data)
def _squash_netsed_dict(self, key, nested_dict, squashed, sanity, vt_tuple): """ Squash NestedDict instance, returns dict with already squashed data from possible higher sections @param key: section key @param nested_dict: the nested_dict instance @param squashed: Squashed instance @param sanity: the sanity dict @param vt_tuple: version, tc_name, tc_version tuple """ version, tcname, tcversion = vt_tuple res_sections = {} if isinstance(key, ToolchainVersionOperator): # perform sanity check for all toolchains, use .add to check for conflicts tc_overops = sanity['toolchains'].setdefault( key.tc_name, OrderedVersionOperators()) tc_overops.add(key) if key.test(tcname, tcversion): tup = (tcname, tcversion, key) self.log.debug( "Found matching marker for specified toolchain '%s, %s': %s" % tup) # TODO remove when unifying add_toolchina with .add() tmp_squashed = self._squash(vt_tuple, nested_dict, sanity) res_sections.update(tmp_squashed.result) squashed.add_toolchain(tmp_squashed) else: tmpl = "Found marker for other toolchain or version '%s', ignoring this (nested) section." self.log.debug(tmpl % key) elif isinstance(key, VersionOperator): # keep track of all version operators, and enforce conflict check sanity['versops'].add(key) if key.test(version): self.log.debug('Found matching version marker %s' % key) squashed.add_version( key, self._squash(vt_tuple, nested_dict, sanity)) else: self.log.debug( 'Found non-matching version marker %s. Ignoring this (nested) section.' % key) else: self.log.error("Unhandled section marker '%s' (type '%s')" % (key, type(key))) return res_sections
def squash(self, version, tcname, tcversion): """ Project the multidimensional easyconfig to single easyconfig It (tries to) detect conflicts in the easyconfig. @param version: version to keep @param tcname: toolchain name to keep @param tcversion: toolchain version to keep """ self.log.debug('Start squash with sections %s' % self.sections) # dictionary to keep track of all sections, to detect conflicts in the easyconfig sanity = { 'versops': OrderedVersionOperators(), 'toolchains': {}, } vt_tuple = (version, tcname, tcversion) squashed = self._squash(vt_tuple, self.sections, sanity) result = squashed.final() self.log.debug('End squash with result %s' % result) return result