Esempio n. 1
0
def check_uses(ruse, uselist, sw, package):
    act = [] # check_required_use doesn't like -flag entries
    for pos in range(len(uselist)):
        if ((2**pos) & sw):
            act.append(uselist[pos])
    if bool(check_required_use(ruse, " ".join(act), all_valid_flags)):
        return True
    else:
        print("  " + package.packageString() + ": ignoring invalid USE flag combination", act)
        return False
Esempio n. 2
0
def check_uses(ruse, uselist, sw, package):
    act = []  # check_required_use doesn't like -flag entries
    for pos in range(len(uselist)):
        if ((2**pos) & sw):
            act.append(uselist[pos])
    if bool(check_required_use(ruse, " ".join(act), all_valid_flags)):
        return True
    else:
        print(
            "  " + package.packageString() +
            ": ignoring invalid USE flag combination", act)
        return False
Esempio n. 3
0
    def testCheckRequiredUseFilterSatisfied(self):
        """
		Test filtering of satisfied parts of REQUIRED_USE,
		in order to reduce noise for bug #353234.
		"""
        test_cases = (
            ("bindist? ( !amr !faac !win32codecs ) cdio? ( !cdparanoia !cddb ) dvdnav? ( dvd )",
             ("cdio", "cdparanoia"), "cdio? ( !cdparanoia )"),
            ("|| ( !amr !faac !win32codecs ) cdio? ( !cdparanoia !cddb ) ^^ ( foo bar )",
             ["cdio", "cdparanoia", "foo"], "cdio? ( !cdparanoia )"),
            ("^^ ( || ( a b ) c )", ("a", "b", "c"), "^^ ( || ( a b ) c )"),
            ("^^ ( || ( ( a b ) ) ( c ) )", ("a", "b", "c"),
             "^^ ( ( a b ) c )"),
            ("a? ( ( c e ) ( b d ) )", ("a", "c", "e"), "a? ( b d )"),
            ("a? ( ( c e ) ( b d ) )", ("a", "b", "c", "e"), "a? ( d )"),
            ("a? ( ( c e ) ( c e b c d e c ) )", ("a", "c", "e"),
             "a? ( b d )"),
            ("^^ ( || ( a b ) ^^ ( b c ) )", ("a", "b"),
             "^^ ( || ( a b ) ^^ ( b c ) )"),
            ("^^ ( || ( a b ) ^^ ( b c ) )", ["a", "c"],
             "^^ ( || ( a b ) ^^ ( b c ) )"),
            ("^^ ( || ( a b ) ^^ ( b c ) )", ["b", "c"], ""),
            ("^^ ( || ( a b ) ^^ ( b c ) )", ["a", "b", "c"], ""),
            ("^^ ( ( a b c ) ( b c d ) )", ["a", "b", "c"], ""),
            ("^^ ( ( a b c ) ( b c d ) )", ["a", "b", "c", "d"],
             "^^ ( ( a b c ) ( b c d ) )"),
            ("^^ ( ( a b c ) ( b c !d ) )", ["a", "b", "c"],
             "^^ ( ( a b c ) ( b c !d ) )"),
            ("^^ ( ( a b c ) ( b c !d ) )", ["a", "b", "c", "d"], ""),
            ("( ( ( a ) ) ( ( ( b c ) ) ) )", [""], "a b c"),
            ("|| ( ( ( ( a ) ) ( ( ( b c ) ) ) ) )", [""], "a b c"),
            ("|| ( ( a ( ( ) ( ) ) ( ( ) ) ( b ( ) c ) ) )", [""], "a b c"),
            ("|| ( ( a b c ) ) || ( ( d e f ) )", [""], "a b c d e f"),
        )
        for required_use, use, expected in test_cases:
            result = check_required_use(required_use, use,
                                        lambda k: True).tounicode()
            self.assertEqual(result, expected,
             "REQUIRED_USE = '%s', USE = '%s', '%s' != '%s'" % \
             (required_use, " ".join(use), result, expected))
Esempio n. 4
0
	def _check_solution(self, config, all_involved_flags, all_conflict_atoms_by_slotatom):
		"""
		Given a configuartion and all involved flags, all possible settings for the involved
		flags are checked if they solve the slot conflict.
		"""
		_pkg_use_enabled = self.depgraph._pkg_use_enabled

		if self.debug:
			#The code is a bit verbose, because the states might not
			#be a string, but a _value_helper.
			msg = "Solution candidate: "
			msg += "["
			first = True
			for involved_flags in all_involved_flags:
				if first:
					first = False
				else:
					msg += ", "
				msg += "{"
				inner_first = True
				for flag, state in involved_flags.items():
					if inner_first:
						inner_first = False
					else:
						msg += ", "
					msg += flag + ": %s" % (state,)
				msg += "}"
			msg += "]\n"
			writemsg(msg, noiselevel=-1)
		
		required_changes = {}
		for id, pkg in enumerate(config):
			if not pkg.installed:
				#We can't change the USE of installed packages.
				for flag in all_involved_flags[id]:
					if not pkg.iuse.is_valid_flag(flag):
						continue
					state = all_involved_flags[id][flag]
					self._force_flag_for_package(required_changes, pkg, flag, state)

			#Go through all (parent, atom) pairs for the current slot conflict.
			for ppkg, atom in all_conflict_atoms_by_slotatom[id]:
				use = atom.unevaluated_atom.use
				if not use:
					#No need to force something for an atom without USE conditionals.
					#These atoms are already satisfied.
					continue
				for flag in all_involved_flags[id]:
					state = all_involved_flags[id][flag]
					
					if flag not in use.required or not use.conditional:
						continue
					if flag in use.conditional.enabled:
						#[flag?]
						if state == "enabled":
							#no need to change anything, the atom won't
							#force -flag on pkg
							pass
						elif state == "disabled":
							#if flag is enabled we get [flag] -> it must be disabled
							self._force_flag_for_package(required_changes, ppkg, flag, "disabled")
					elif flag in use.conditional.disabled:
						#[!flag?]
						if state == "enabled":
							#if flag is enabled we get [-flag] -> it must be disabled
							self._force_flag_for_package(required_changes, ppkg, flag, "disabled")
						elif state == "disabled":
							#no need to change anything, the atom won't
							#force +flag on pkg
							pass
					elif flag in use.conditional.equal:
						#[flag=]
						if state == "enabled":
							#if flag is disabled we get [-flag] -> it must be enabled
							self._force_flag_for_package(required_changes, ppkg, flag, "enabled")
						elif state == "disabled":
							#if flag is enabled we get [flag] -> it must be disabled
							self._force_flag_for_package(required_changes, ppkg, flag, "disabled")
					elif flag in use.conditional.not_equal:
						#[!flag=]
						if state == "enabled":
							#if flag is enabled we get [-flag] -> it must be disabled
							self._force_flag_for_package(required_changes, ppkg, flag, "disabled")
						elif state == "disabled":
							#if flag is disabled we get [flag] -> it must be enabled
							self._force_flag_for_package(required_changes, ppkg, flag, "enabled")

		is_valid_solution = True
		for pkg in required_changes:
			for state in required_changes[pkg].values():
				if not state in ("enabled", "disabled"):
					is_valid_solution = False
		
		if not is_valid_solution:
			return None

		#Check if all atoms are satisfied after the changes are applied.
		for id, pkg in enumerate(config):
			new_use = _pkg_use_enabled(pkg)
			if pkg in required_changes:
				old_use = pkg.use.enabled
				new_use = set(new_use)
				for flag, state in required_changes[pkg].items():
					if state == "enabled":
						new_use.add(flag)
					elif state == "disabled":
						new_use.discard(flag)
				if not new_use.symmetric_difference(old_use):
					#avoid copying the package in findAtomForPackage if possible
					new_use = old_use

			for ppkg, atom in all_conflict_atoms_by_slotatom[id]:
				if not hasattr(ppkg, "use"):
					#It's a SetArg or something like that.
					continue
				ppkg_new_use = set(_pkg_use_enabled(ppkg))
				if ppkg in required_changes:
					for flag, state in required_changes[ppkg].items():
						if state == "enabled":
							ppkg_new_use.add(flag)
						elif state == "disabled":
							ppkg_new_use.discard(flag)

				new_atom = atom.unevaluated_atom.evaluate_conditionals(ppkg_new_use)
				i = InternalPackageSet(initial_atoms=(new_atom,))
				if not i.findAtomForPackage(pkg, new_use):
					#We managed to create a new problem with our changes.
					is_valid_solution = False
					if self.debug:
						writemsg(("new conflict introduced: %s"
							" does not match %s from %s\n") %
							(pkg, new_atom, ppkg), noiselevel=-1)
					break

			if not is_valid_solution:
				break

		#Make sure the changes don't violate REQUIRED_USE
		for pkg in required_changes:
			required_use = pkg._metadata.get("REQUIRED_USE")
			if not required_use:
				continue

			use = set(_pkg_use_enabled(pkg))
			for flag, state in required_changes[pkg].items():
				if state == "enabled":
					use.add(flag)
				else:
					use.discard(flag)

			if not check_required_use(required_use, use, pkg.iuse.is_valid_flag):
				is_valid_solution = False
				break

		if is_valid_solution and required_changes:
			return required_changes
		else:
			return None
	def _find_suggestions(self):
		if not self.shortest_cycle:
			return None, None

		suggestions = []
		final_solutions = {}

		for pos, pkg in enumerate(self.shortest_cycle):
			parent = self.shortest_cycle[pos-1]
			priorities = self.graph.nodes[parent][0][pkg]
			parent_atoms = self.all_parent_atoms.get(pkg)

			if priorities[-1].buildtime:
				dep = parent.metadata["DEPEND"]
			elif priorities[-1].runtime:
				dep = parent.metadata["RDEPEND"]

			for ppkg, atom in parent_atoms:
				if ppkg == parent:
					changed_parent = ppkg
					parent_atom = atom.unevaluated_atom
					break

			try:
				affecting_use = extract_affecting_use(dep, parent_atom,
					eapi=parent.metadata["EAPI"])
			except InvalidDependString:
				if not parent.installed:
					raise
				affecting_use = set()

			# Make sure we don't want to change a flag that is 
			#	a) in use.mask or use.force
			#	b) changed by autounmask
			
			usemask, useforce = self._get_use_mask_and_force(parent)
			autounmask_changes = self._get_autounmask_changes(parent)
			untouchable_flags = frozenset(chain(usemask, useforce, autounmask_changes))

			affecting_use.difference_update(untouchable_flags)

			#If any of the flags we're going to touch is in REQUIRED_USE, add all
			#other flags in REQUIRED_USE to affecting_use, to not lose any solution.
			required_use_flags = get_required_use_flags(
				parent.metadata.get("REQUIRED_USE", ""))

			if affecting_use.intersection(required_use_flags):
				# TODO: Find out exactly which REQUIRED_USE flags are
				# entangled with affecting_use. We have to limit the
				# number of flags since the number of loops is
				# exponentially related (see bug #374397).
				total_flags = set()
				total_flags.update(affecting_use, required_use_flags)
				total_flags.difference_update(untouchable_flags)
				if len(total_flags) <= 10:
					affecting_use = total_flags

			affecting_use = tuple(affecting_use)

			if not affecting_use:
				continue

			#We iterate over all possible settings of these use flags and gather
			#a set of possible changes
			#TODO: Use the information encoded in REQUIRED_USE
			solutions = set()
			for use_state in product(("disabled", "enabled"),
				repeat=len(affecting_use)):
				current_use = set(self.depgraph._pkg_use_enabled(parent))
				for flag, state in zip(affecting_use, use_state):
					if state == "enabled":
						current_use.add(flag)
					else:
						current_use.discard(flag)
				try:
					reduced_dep = use_reduce(dep,
						uselist=current_use, flat=True)
				except InvalidDependString:
					if not parent.installed:
						raise
					reduced_dep = None

				if reduced_dep is not None and \
					parent_atom not in reduced_dep:
					#We found an assignment that removes the atom from 'dep'.
					#Make sure it doesn't conflict with REQUIRED_USE.
					required_use = parent.metadata.get("REQUIRED_USE", "")

					if check_required_use(required_use, current_use, parent.iuse.is_valid_flag):
						use = self.depgraph._pkg_use_enabled(parent)
						solution = set()
						for flag, state in zip(affecting_use, use_state):
							if state == "enabled" and \
								flag not in use:
								solution.add((flag, True))
							elif state == "disabled" and \
								flag in use:
								solution.add((flag, False))
						solutions.add(frozenset(solution))

			for solution in solutions:
				ignore_solution = False
				for other_solution in solutions:
					if solution is other_solution:
						continue
					if solution.issuperset(other_solution):
						ignore_solution = True
				if ignore_solution:
					continue

				#Check if a USE change conflicts with use requirements of the parents.
				#If a requiremnet is hard, ignore the suggestion.
				#If the requirment is conditional, warn the user that other changes might be needed.
				followup_change = False
				parent_parent_atoms = self.depgraph._dynamic_config._parent_atoms.get(changed_parent)
				for ppkg, atom in parent_parent_atoms:

					atom = atom.unevaluated_atom
					if not atom.use:
						continue

					for flag, state in solution:
						if flag in atom.use.enabled or flag in atom.use.disabled:
							ignore_solution = True
							break
						elif atom.use.conditional:
							for flags in atom.use.conditional.values():
								if flag in flags:
									followup_change = True
									break

					if ignore_solution:
						break

				if ignore_solution:
					continue

				changes = []
				for flag, state in solution:
					if state:
						changes.append(colorize("red", "+"+flag))
					else:
						changes.append(colorize("blue", "-"+flag))
				msg = "- %s (Change USE: %s)\n" \
					% (parent.cpv, " ".join(changes))
				if followup_change:
					msg += " (This change might require USE changes on parent packages.)"
				suggestions.append(msg)
				final_solutions.setdefault(pkg, set()).add(solution)

		return final_solutions, suggestions
Esempio n. 6
0
    def _find_suggestions(self):
        if not self.shortest_cycle:
            return None, None

        suggestions = []
        final_solutions = {}

        for pos, pkg in enumerate(self.shortest_cycle):
            parent = self.shortest_cycle[pos - 1]
            priorities = self.graph.nodes[parent][0][pkg]
            parent_atoms = self.all_parent_atoms.get(pkg)

            if priorities[-1].buildtime:
                dep = parent.metadata["DEPEND"]
            elif priorities[-1].runtime:
                dep = parent.metadata["RDEPEND"]

            for ppkg, atom in parent_atoms:
                if ppkg == parent:
                    changed_parent = ppkg
                    parent_atom = atom.unevaluated_atom
                    break

            try:
                affecting_use = extract_affecting_use(
                    dep, parent_atom, eapi=parent.metadata["EAPI"])
            except InvalidDependString:
                if not parent.installed:
                    raise
                affecting_use = set()

            # Make sure we don't want to change a flag that is
            #	a) in use.mask or use.force
            #	b) changed by autounmask

            usemask, useforce = self._get_use_mask_and_force(parent)
            autounmask_changes = self._get_autounmask_changes(parent)
            untouchable_flags = frozenset(
                chain(usemask, useforce, autounmask_changes))

            affecting_use.difference_update(untouchable_flags)

            #If any of the flags we're going to touch is in REQUIRED_USE, add all
            #other flags in REQUIRED_USE to affecting_use, to not lose any solution.
            required_use_flags = get_required_use_flags(
                parent.metadata.get("REQUIRED_USE", ""))

            if affecting_use.intersection(required_use_flags):
                # TODO: Find out exactly which REQUIRED_USE flags are
                # entangled with affecting_use. We have to limit the
                # number of flags since the number of loops is
                # exponentially related (see bug #374397).
                total_flags = set()
                total_flags.update(affecting_use, required_use_flags)
                total_flags.difference_update(untouchable_flags)
                if len(total_flags) <= 10:
                    affecting_use = total_flags

            affecting_use = tuple(affecting_use)

            if not affecting_use:
                continue

            #We iterate over all possible settings of these use flags and gather
            #a set of possible changes
            #TODO: Use the information encoded in REQUIRED_USE
            solutions = set()
            for use_state in product(("disabled", "enabled"),
                                     repeat=len(affecting_use)):
                current_use = set(self.depgraph._pkg_use_enabled(parent))
                for flag, state in zip(affecting_use, use_state):
                    if state == "enabled":
                        current_use.add(flag)
                    else:
                        current_use.discard(flag)
                try:
                    reduced_dep = use_reduce(dep,
                                             uselist=current_use,
                                             flat=True)
                except InvalidDependString:
                    if not parent.installed:
                        raise
                    reduced_dep = None

                if reduced_dep is not None and \
                 parent_atom not in reduced_dep:
                    #We found an assignment that removes the atom from 'dep'.
                    #Make sure it doesn't conflict with REQUIRED_USE.
                    required_use = parent.metadata.get("REQUIRED_USE", "")

                    if check_required_use(required_use, current_use,
                                          parent.iuse.is_valid_flag):
                        use = self.depgraph._pkg_use_enabled(parent)
                        solution = set()
                        for flag, state in zip(affecting_use, use_state):
                            if state == "enabled" and \
                             flag not in use:
                                solution.add((flag, True))
                            elif state == "disabled" and \
                             flag in use:
                                solution.add((flag, False))
                        solutions.add(frozenset(solution))

            for solution in solutions:
                ignore_solution = False
                for other_solution in solutions:
                    if solution is other_solution:
                        continue
                    if solution.issuperset(other_solution):
                        ignore_solution = True
                if ignore_solution:
                    continue

                #Check if a USE change conflicts with use requirements of the parents.
                #If a requiremnet is hard, ignore the suggestion.
                #If the requirment is conditional, warn the user that other changes might be needed.
                followup_change = False
                parent_parent_atoms = self.depgraph._dynamic_config._parent_atoms.get(
                    changed_parent)
                for ppkg, atom in parent_parent_atoms:

                    atom = atom.unevaluated_atom
                    if not atom.use:
                        continue

                    for flag, state in solution:
                        if flag in atom.use.enabled or flag in atom.use.disabled:
                            ignore_solution = True
                            break
                        elif atom.use.conditional:
                            for flags in atom.use.conditional.values():
                                if flag in flags:
                                    followup_change = True
                                    break

                    if ignore_solution:
                        break

                if ignore_solution:
                    continue

                changes = []
                for flag, state in solution:
                    if state:
                        changes.append(colorize("red", "+" + flag))
                    else:
                        changes.append(colorize("blue", "-" + flag))
                msg = "- %s (Change USE: %s)\n" \
                 % (parent.cpv, " ".join(changes))
                if followup_change:
                    msg += " (This change might require USE changes on parent packages.)"
                suggestions.append(msg)
                final_solutions.setdefault(pkg, set()).add(solution)

        return final_solutions, suggestions
Esempio n. 7
0
	def testCheckRequiredUse(self):
		test_cases = (
			( "|| ( a b )", [], ["a", "b"], False),
			( "|| ( a b )", ["a"], ["a", "b"], True),
			( "|| ( a b )", ["b"], ["a", "b"], True),
			( "|| ( a b )", ["a", "b"], ["a", "b"], True),

			( "^^ ( a b )", [], ["a", "b"], False),
			( "^^ ( a b )", ["a"], ["a", "b"], True),
			( "^^ ( a b )", ["b"], ["a", "b"], True),
			( "^^ ( a b )", ["a", "b"], ["a", "b"], False),

			( "^^ ( || ( a b ) c )", [], ["a", "b", "c"], False),
			( "^^ ( || ( a b ) c )", ["a"], ["a", "b", "c"], True),

			( "^^ ( || ( ( a b ) ) ( c ) )", [], ["a", "b", "c"], False),
			( "( ^^ ( ( || ( ( a ) ( b ) ) ) ( ( c ) ) ) )", ["a"], ["a", "b", "c"], True),

			( "a || ( b c )", ["a"], ["a", "b", "c"], False),
			( "|| ( b c ) a", ["a"], ["a", "b", "c"], False),

			( "|| ( a b c )", ["a"], ["a", "b", "c"], True),
			( "|| ( a b c )", ["b"], ["a", "b", "c"], True),
			( "|| ( a b c )", ["c"], ["a", "b", "c"], True),

			( "^^ ( a b c )", ["a"], ["a", "b", "c"], True),
			( "^^ ( a b c )", ["b"], ["a", "b", "c"], True),
			( "^^ ( a b c )", ["c"], ["a", "b", "c"], True),
			( "^^ ( a b c )", ["a", "b"], ["a", "b", "c"], False),
			( "^^ ( a b c )", ["b", "c"], ["a", "b", "c"], False),
			( "^^ ( a b c )", ["a", "c"], ["a", "b", "c"], False),
			( "^^ ( a b c )", ["a", "b", "c"], ["a", "b", "c"], False),

			( "a? ( ^^ ( b c ) )", [], ["a", "b", "c"], True),
			( "a? ( ^^ ( b c ) )", ["a"], ["a", "b", "c"], False),
			( "a? ( ^^ ( b c ) )", ["b"], ["a", "b", "c"], True),
			( "a? ( ^^ ( b c ) )", ["c"], ["a", "b", "c"], True),
			( "a? ( ^^ ( b c ) )", ["a", "b"], ["a", "b", "c"], True),
			( "a? ( ^^ ( b c ) )", ["a", "b", "c"], ["a", "b", "c"], False),

			( "^^ ( a? ( !b ) !c? ( d ) )", [], ["a", "b", "c", "d"], False),
			( "^^ ( a? ( !b ) !c? ( d ) )", ["a"], ["a", "b", "c", "d"], True),
			( "^^ ( a? ( !b ) !c? ( d ) )", ["c"], ["a", "b", "c", "d"], True),
			( "^^ ( a? ( !b ) !c? ( d ) )", ["a", "c"], ["a", "b", "c", "d"], True),
			( "^^ ( a? ( !b ) !c? ( d ) )", ["a", "b", "c"], ["a", "b", "c", "d"], False),
			( "^^ ( a? ( !b ) !c? ( d ) )", ["a", "b", "d"], ["a", "b", "c", "d"], True),
			( "^^ ( a? ( !b ) !c? ( d ) )", ["a", "b", "d"], ["a", "b", "c", "d"], True),
			( "^^ ( a? ( !b ) !c? ( d ) )", ["a", "d"], ["a", "b", "c", "d"], False),

			( "|| ( ^^ ( a b ) ^^ ( b c ) )", [], ["a", "b", "c"], False),
			( "|| ( ^^ ( a b ) ^^ ( b c ) )", ["a"], ["a", "b", "c"], True),
			( "|| ( ^^ ( a b ) ^^ ( b c ) )", ["b"], ["a", "b", "c"], True),
			( "|| ( ^^ ( a b ) ^^ ( b c ) )", ["c"], ["a", "b", "c"], True),
			( "|| ( ^^ ( a b ) ^^ ( b c ) )", ["a", "b"], ["a", "b", "c"], True),
			( "|| ( ^^ ( a b ) ^^ ( b c ) )", ["a", "c"], ["a", "b", "c"], True),
			( "|| ( ^^ ( a b ) ^^ ( b c ) )", ["b", "c"], ["a", "b", "c"], True),
			( "|| ( ^^ ( a b ) ^^ ( b c ) )", ["a", "b", "c"], ["a", "b", "c"], False),

			( "^^ ( || ( a b ) ^^ ( b c ) )", [], ["a", "b", "c"], False),
			( "^^ ( || ( a b ) ^^ ( b c ) )", ["a"], ["a", "b", "c"], True),
			( "^^ ( || ( a b ) ^^ ( b c ) )", ["b"], ["a", "b", "c"], False),
			( "^^ ( || ( a b ) ^^ ( b c ) )", ["c"], ["a", "b", "c"], True),
			( "^^ ( || ( a b ) ^^ ( b c ) )", ["a", "b"], ["a", "b", "c"], False),
			( "^^ ( || ( a b ) ^^ ( b c ) )", ["a", "c"], ["a", "b", "c"], False),
			( "^^ ( || ( a b ) ^^ ( b c ) )", ["b", "c"], ["a", "b", "c"], True),
			( "^^ ( || ( a b ) ^^ ( b c ) )", ["a", "b", "c"], ["a", "b", "c"], True),

			( "|| ( ( a b ) c )", ["a", "b", "c"], ["a", "b", "c"], True),
			( "|| ( ( a b ) c )", ["b", "c"], ["a", "b", "c"], True),
			( "|| ( ( a b ) c )", ["a", "c"], ["a", "b", "c"], True),
			( "|| ( ( a b ) c )", ["a", "b"], ["a", "b", "c"], True),
			( "|| ( ( a b ) c )", ["a"], ["a", "b", "c"], False),
			( "|| ( ( a b ) c )", ["b"], ["a", "b", "c"], False),
			( "|| ( ( a b ) c )", ["c"], ["a", "b", "c"], True),
			( "|| ( ( a b ) c )", [], ["a", "b", "c"], False),

			( "^^ ( ( a b ) c )", ["a", "b", "c"], ["a", "b", "c"], False),
			( "^^ ( ( a b ) c )", ["b", "c"], ["a", "b", "c"], True),
			( "^^ ( ( a b ) c )", ["a", "c"], ["a", "b", "c"], True),
			( "^^ ( ( a b ) c )", ["a", "b"], ["a", "b", "c"], True),
			( "^^ ( ( a b ) c )", ["a"], ["a", "b", "c"], False),
			( "^^ ( ( a b ) c )", ["b"], ["a", "b", "c"], False),
			( "^^ ( ( a b ) c )", ["c"], ["a", "b", "c"], True),
			( "^^ ( ( a b ) c )", [], ["a", "b", "c"], False),
		)

		test_cases_xfail = (
			( "^^ ( || ( a b ) ^^ ( b c ) )", [], ["a", "b"]),
			( "^^ ( || ( a b ) ^^ ( b c )", [], ["a", "b", "c"]),
			( "^^( || ( a b ) ^^ ( b c ) )", [], ["a", "b", "c"]),
			( "^^ || ( a b ) ^^ ( b c )", [], ["a", "b", "c"]),
			( "^^ ( ( || ) ( a b ) ^^ ( b c ) )", [], ["a", "b", "c"]),
			( "^^ ( || ( a b ) ) ^^ ( b c ) )", [], ["a", "b", "c"]),
		)

		for required_use, use, iuse, expected in test_cases:
			self.assertEqual(check_required_use(required_use, use, iuse.__contains__), \
				expected, required_use + ", USE = " + " ".join(use))

		for required_use, use, iuse in test_cases_xfail:
			self.assertRaisesMsg(required_use + ", USE = " + " ".join(use), \
				InvalidDependString, check_required_use, required_use, use, iuse.__contains__)
	def testCheckRequiredUseFilterSatisfied(self):
		"""
		Test filtering of satisfied parts of REQUIRED_USE,
		in order to reduce noise for bug #353234.
		"""
		test_cases = (
			(
				"bindist? ( !amr !faac !win32codecs ) cdio? ( !cdparanoia !cddb ) dvdnav? ( dvd )",
				("cdio", "cdparanoia"),
				"cdio? ( !cdparanoia )"
			),
			(
				"|| ( !amr !faac !win32codecs ) cdio? ( !cdparanoia !cddb ) ^^ ( foo bar )",
				["cdio", "cdparanoia", "foo"],
				"cdio? ( !cdparanoia )"
			),
			(
				"^^ ( || ( a b ) c )",
				("a", "b", "c"),
				"^^ ( || ( a b ) c )"
			),
			(
				"^^ ( || ( ( a b ) ) ( c ) )",
				("a", "b", "c"),
				"^^ ( ( a b ) c )"
			),
			(
				"a? ( ( c e ) ( b d ) )",
				("a", "c", "e"),
				"a? ( b d )"
			),
			(
				"a? ( ( c e ) ( b d ) )",
				("a", "b", "c", "e"),
				"a? ( d )"
			),
			(
				"a? ( ( c e ) ( c e b c d e c ) )",
				("a", "c", "e"),
				"a? ( b d )"
			),
			(
				"^^ ( || ( a b ) ^^ ( b c ) )",
				("a", "b"),
				"^^ ( || ( a b ) ^^ ( b c ) )"
			),
			(
				"^^ ( || ( a b ) ^^ ( b c ) )",
				["a", "c"],
				"^^ ( || ( a b ) ^^ ( b c ) )"
			),
			(
				"^^ ( || ( a b ) ^^ ( b c ) )",
				["b", "c"],
				""
			),
			(
				"^^ ( || ( a b ) ^^ ( b c ) )",
				["a", "b", "c"],
				""
			),
			(
				"^^ ( ( a b c ) ( b c d ) )",
				["a", "b", "c"],
				""
			),
			(
				"^^ ( ( a b c ) ( b c d ) )",
				["a", "b", "c", "d"],
				"^^ ( ( a b c ) ( b c d ) )"
			),
			(
				"^^ ( ( a b c ) ( b c !d ) )",
				["a", "b", "c"],
				"^^ ( ( a b c ) ( b c !d ) )"
			),
			(
				"^^ ( ( a b c ) ( b c !d ) )",
				["a", "b", "c", "d"],
				""
			),
			(
				"( ( ( a ) ) ( ( ( b c ) ) ) )",
				[""],
				"a b c"
			),
			(
				"|| ( ( ( ( a ) ) ( ( ( b c ) ) ) ) )",
				[""],
				"a b c"
			),
			(
				"|| ( ( a ( ( ) ( ) ) ( ( ) ) ( b ( ) c ) ) )",
				[""],
				"a b c"
			),
			(
				"|| ( ( a b c ) ) || ( ( d e f ) )",
				[""],
				"a b c d e f"
			),
		)
		for required_use, use, expected in test_cases:
			result = check_required_use(required_use, use, lambda k: True).tounicode()
			self.assertEqual(result, expected,
				"REQUIRED_USE = '%s', USE = '%s', '%s' != '%s'" % \
				(required_use, " ".join(use), result, expected))
Esempio n. 9
0
	def _validate_deps(self):
		"""
		Validate deps. This does not trigger USE calculation since that
		is expensive for ebuilds and therefore we want to avoid doing
		it unnecessarily (like for masked packages).
		"""
		eapi = self.eapi
		dep_eapi = eapi
		dep_valid_flag = self.iuse.is_valid_flag
		if self.installed:
			# Ignore EAPI.incompatible and conditionals missing
			# from IUSE for installed packages since these issues
			# aren't relevant now (re-evaluate when new EAPIs are
			# deployed).
			dep_eapi = None
			dep_valid_flag = None

		validated_atoms = []
		for k in self._dep_keys:
			v = self._metadata.get(k)
			if not v:
				continue
			try:
				atoms = use_reduce(v, eapi=dep_eapi,
					matchall=True, is_valid_flag=dep_valid_flag,
					token_class=Atom, flat=True)
			except InvalidDependString as e:
				self._metadata_exception(k, e)
			else:
				validated_atoms.extend(atoms)
				if not self.built:
					for atom in atoms:
						if not isinstance(atom, Atom):
							continue
						if atom.slot_operator_built:
							e = InvalidDependString(
								_("Improper context for slot-operator "
								"\"built\" atom syntax: %s") %
								(atom.unevaluated_atom,))
							self._metadata_exception(k, e)

		self._validated_atoms = tuple(set(atom for atom in
			validated_atoms if isinstance(atom, Atom)))

		for k in self._use_conditional_misc_keys:
			v = self._metadata.get(k)
			if not v:
				continue
			try:
				use_reduce(v, eapi=dep_eapi, matchall=True,
					is_valid_flag=dep_valid_flag)
			except InvalidDependString as e:
				self._metadata_exception(k, e)

		k = 'REQUIRED_USE'
		v = self._metadata.get(k)
		if v and not self.built:
			if not _get_eapi_attrs(eapi).required_use:
				self._invalid_metadata('EAPI.incompatible',
					"REQUIRED_USE set, but EAPI='%s' doesn't allow it" % eapi)
			else:
				try:
					check_required_use(v, (),
						self.iuse.is_valid_flag, eapi=eapi)
				except InvalidDependString as e:
					self._invalid_metadata(k + ".syntax", "%s: %s" % (k, e))

		k = 'SRC_URI'
		v = self._metadata.get(k)
		if v:
			try:
				use_reduce(v, is_src_uri=True, eapi=eapi, matchall=True,
					is_valid_flag=self.iuse.is_valid_flag)
			except InvalidDependString as e:
				if not self.installed:
					self._metadata_exception(k, e)

		if self.built:
			k = 'PROVIDES'
			try:
				self._provides = frozenset(
					parse_soname_deps(self._metadata[k]))
			except InvalidData as e:
				self._invalid_metadata(k + ".syntax", "%s: %s" % (k, e))

			k = 'REQUIRES'
			try:
				self._requires = frozenset(
					parse_soname_deps(self._metadata[k]))
			except InvalidData as e:
				self._invalid_metadata(k + ".syntax", "%s: %s" % (k, e))
Esempio n. 10
0
    def _validate_deps(self):
        """
		Validate deps. This does not trigger USE calculation since that
		is expensive for ebuilds and therefore we want to avoid doing
		in unnecessarily (like for masked packages).
		"""
        eapi = self.metadata['EAPI']
        dep_eapi = eapi
        dep_valid_flag = self.iuse.is_valid_flag
        if self.installed:
            # Ignore EAPI.incompatible and conditionals missing
            # from IUSE for installed packages since these issues
            # aren't relevant now (re-evaluate when new EAPIs are
            # deployed).
            dep_eapi = None
            dep_valid_flag = None

        for k in self._dep_keys:
            v = self.metadata.get(k)
            if not v:
                continue
            try:
                use_reduce(v,
                           eapi=dep_eapi,
                           matchall=True,
                           is_valid_flag=dep_valid_flag,
                           token_class=Atom)
            except InvalidDependString as e:
                self._metadata_exception(k, e)

        k = 'PROVIDE'
        v = self.metadata.get(k)
        if v:
            try:
                use_reduce(v,
                           eapi=dep_eapi,
                           matchall=True,
                           is_valid_flag=dep_valid_flag,
                           token_class=Atom)
            except InvalidDependString as e:
                self._invalid_metadata("PROVIDE.syntax",
                                       _unicode_decode("%s: %s") % (k, e))

        for k in self._use_conditional_misc_keys:
            v = self.metadata.get(k)
            if not v:
                continue
            try:
                use_reduce(v,
                           eapi=dep_eapi,
                           matchall=True,
                           is_valid_flag=dep_valid_flag)
            except InvalidDependString as e:
                self._metadata_exception(k, e)

        k = 'REQUIRED_USE'
        v = self.metadata.get(k)
        if v:
            if not eapi_has_required_use(eapi):
                self._invalid_metadata(
                    'EAPI.incompatible',
                    "REQUIRED_USE set, but EAPI='%s' doesn't allow it" % eapi)
            else:
                try:
                    check_required_use(v, (), self.iuse.is_valid_flag)
                except InvalidDependString as e:
                    # Force unicode format string for python-2.x safety,
                    # ensuring that PortageException.__unicode__() is used
                    # when necessary.
                    self._invalid_metadata(k + ".syntax",
                                           _unicode_decode("%s: %s") % (k, e))

        k = 'SRC_URI'
        v = self.metadata.get(k)
        if v:
            try:
                use_reduce(v,
                           is_src_uri=True,
                           eapi=eapi,
                           matchall=True,
                           is_valid_flag=self.iuse.is_valid_flag)
            except InvalidDependString as e:
                if not self.installed:
                    self._metadata_exception(k, e)
Esempio n. 11
0
	def _validate_deps(self):
		"""
		Validate deps. This does not trigger USE calculation since that
		is expensive for ebuilds and therefore we want to avoid doing
		it unnecessarily (like for masked packages).
		"""
		eapi = self.eapi
		dep_eapi = eapi
		dep_valid_flag = self.iuse.is_valid_flag
		if self.installed:
			# Ignore EAPI.incompatible and conditionals missing
			# from IUSE for installed packages since these issues
			# aren't relevant now (re-evaluate when new EAPIs are
			# deployed).
			dep_eapi = None
			dep_valid_flag = None

		validated_atoms = []
		for k in self._dep_keys:
			v = self._metadata.get(k)
			if not v:
				continue
			try:
				atoms = use_reduce(v, eapi=dep_eapi,
					matchall=True, is_valid_flag=dep_valid_flag,
					token_class=Atom, flat=True)
			except InvalidDependString as e:
				self._metadata_exception(k, e)
			else:
				validated_atoms.extend(atoms)
				if not self.built:
					for atom in atoms:
						if not isinstance(atom, Atom):
							continue
						if atom.slot_operator_built:
							e = InvalidDependString(
								_("Improper context for slot-operator "
								"\"built\" atom syntax: %s") %
								(atom.unevaluated_atom,))
							self._metadata_exception(k, e)

		self._validated_atoms = tuple(set(atom for atom in
			validated_atoms if isinstance(atom, Atom)))

		k = 'PROVIDE'
		v = self._metadata.get(k)
		if v:
			try:
				use_reduce(v, eapi=dep_eapi, matchall=True,
					is_valid_flag=dep_valid_flag, token_class=Atom)
			except InvalidDependString as e:
				self._invalid_metadata("PROVIDE.syntax", "%s: %s" % (k, e))

		for k in self._use_conditional_misc_keys:
			v = self._metadata.get(k)
			if not v:
				continue
			try:
				use_reduce(v, eapi=dep_eapi, matchall=True,
					is_valid_flag=dep_valid_flag)
			except InvalidDependString as e:
				self._metadata_exception(k, e)

		k = 'REQUIRED_USE'
		v = self._metadata.get(k)
		if v and not self.built:
			if not _get_eapi_attrs(eapi).required_use:
				self._invalid_metadata('EAPI.incompatible',
					"REQUIRED_USE set, but EAPI='%s' doesn't allow it" % eapi)
			else:
				try:
					check_required_use(v, (),
						self.iuse.is_valid_flag, eapi=eapi)
				except InvalidDependString as e:
					self._invalid_metadata(k + ".syntax", "%s: %s" % (k, e))

		k = 'SRC_URI'
		v = self._metadata.get(k)
		if v:
			try:
				use_reduce(v, is_src_uri=True, eapi=eapi, matchall=True,
					is_valid_flag=self.iuse.is_valid_flag)
			except InvalidDependString as e:
				if not self.installed:
					self._metadata_exception(k, e)

		if self.built:
			k = 'PROVIDES'
			try:
				self._provides = frozenset(
					parse_soname_deps(self._metadata[k]))
			except InvalidData as e:
				self._invalid_metadata(k + ".syntax", "%s: %s" % (k, e))

			k = 'REQUIRES'
			try:
				self._requires = frozenset(
					parse_soname_deps(self._metadata[k]))
			except InvalidData as e:
				self._invalid_metadata(k + ".syntax", "%s: %s" % (k, e))
Esempio n. 12
0
	def _validate_deps(self):
		"""
		Validate deps. This does not trigger USE calculation since that
		is expensive for ebuilds and therefore we want to avoid doing
		in unnecessarily (like for masked packages).
		"""
		eapi = self.metadata['EAPI']
		dep_eapi = eapi
		dep_valid_flag = self.iuse.is_valid_flag
		if self.installed:
			# Ignore EAPI.incompatible and conditionals missing
			# from IUSE for installed packages since these issues
			# aren't relevant now (re-evaluate when new EAPIs are
			# deployed).
			dep_eapi = None
			dep_valid_flag = None

		for k in self._dep_keys:
			v = self.metadata.get(k)
			if not v:
				continue
			try:
				use_reduce(v, eapi=dep_eapi, matchall=True,
					is_valid_flag=dep_valid_flag, token_class=Atom)
			except InvalidDependString as e:
				self._metadata_exception(k, e)

		k = 'PROVIDE'
		v = self.metadata.get(k)
		if v:
			try:
				use_reduce(v, eapi=dep_eapi, matchall=True,
					is_valid_flag=dep_valid_flag, token_class=Atom)
			except InvalidDependString as e:
				self._invalid_metadata("PROVIDE.syntax",
					_unicode_decode("%s: %s") % (k, e))

		for k in self._use_conditional_misc_keys:
			v = self.metadata.get(k)
			if not v:
				continue
			try:
				use_reduce(v, eapi=dep_eapi, matchall=True,
					is_valid_flag=dep_valid_flag)
			except InvalidDependString as e:
				self._metadata_exception(k, e)

		k = 'REQUIRED_USE'
		v = self.metadata.get(k)
		if v:
			if not eapi_has_required_use(eapi):
				self._invalid_metadata('EAPI.incompatible',
					"REQUIRED_USE set, but EAPI='%s' doesn't allow it" % eapi)
			else:
				try:
					check_required_use(v, (),
						self.iuse.is_valid_flag)
				except InvalidDependString as e:
					# Force unicode format string for python-2.x safety,
					# ensuring that PortageException.__unicode__() is used
					# when necessary.
					self._invalid_metadata(k + ".syntax",
						_unicode_decode("%s: %s") % (k, e))

		k = 'SRC_URI'
		v = self.metadata.get(k)
		if v:
			try:
				use_reduce(v, is_src_uri=True, eapi=eapi, matchall=True,
					is_valid_flag=self.iuse.is_valid_flag)
			except InvalidDependString as e:
				if not self.installed:
					self._metadata_exception(k, e)
Esempio n. 13
0
    def testCheckRequiredUse(self):
        test_cases = (
            ("|| ( a b )", [], ["a", "b"], False),
            ("|| ( a b )", ["a"], ["a", "b"], True),
            ("|| ( a b )", ["b"], ["a", "b"], True),
            ("|| ( a b )", ["a", "b"], ["a", "b"], True),
            ("^^ ( a b )", [], ["a", "b"], False),
            ("^^ ( a b )", ["a"], ["a", "b"], True),
            ("^^ ( a b )", ["b"], ["a", "b"], True),
            ("^^ ( a b )", ["a", "b"], ["a", "b"], False),
            ("?? ( a b )", ["a", "b"], ["a", "b"], False),
            ("?? ( a b )", ["a"], ["a", "b"], True),
            ("?? ( a b )", ["b"], ["a", "b"], True),
            ("?? ( a b )", [], ["a", "b"], True),
            ("?? ( )", [], [], True),
            ("^^ ( || ( a b ) c )", [], ["a", "b", "c"], False),
            ("^^ ( || ( a b ) c )", ["a"], ["a", "b", "c"], True),
            ("^^ ( || ( ( a b ) ) ( c ) )", [], ["a", "b", "c"], False),
            ("( ^^ ( ( || ( ( a ) ( b ) ) ) ( ( c ) ) ) )", ["a"],
             ["a", "b", "c"], True),
            ("a || ( b c )", ["a"], ["a", "b", "c"], False),
            ("|| ( b c ) a", ["a"], ["a", "b", "c"], False),
            ("|| ( a b c )", ["a"], ["a", "b", "c"], True),
            ("|| ( a b c )", ["b"], ["a", "b", "c"], True),
            ("|| ( a b c )", ["c"], ["a", "b", "c"], True),
            ("^^ ( a b c )", ["a"], ["a", "b", "c"], True),
            ("^^ ( a b c )", ["b"], ["a", "b", "c"], True),
            ("^^ ( a b c )", ["c"], ["a", "b", "c"], True),
            ("^^ ( a b c )", ["a", "b"], ["a", "b", "c"], False),
            ("^^ ( a b c )", ["b", "c"], ["a", "b", "c"], False),
            ("^^ ( a b c )", ["a", "c"], ["a", "b", "c"], False),
            ("^^ ( a b c )", ["a", "b", "c"], ["a", "b", "c"], False),
            ("a? ( ^^ ( b c ) )", [], ["a", "b", "c"], True),
            ("a? ( ^^ ( b c ) )", ["a"], ["a", "b", "c"], False),
            ("a? ( ^^ ( b c ) )", ["b"], ["a", "b", "c"], True),
            ("a? ( ^^ ( b c ) )", ["c"], ["a", "b", "c"], True),
            ("a? ( ^^ ( b c ) )", ["a", "b"], ["a", "b", "c"], True),
            ("a? ( ^^ ( b c ) )", ["a", "b", "c"], ["a", "b", "c"], False),
            ("^^ ( a? ( !b ) !c? ( d ) )", [], ["a", "b", "c", "d"], False),
            ("^^ ( a? ( !b ) !c? ( d ) )", ["a"], ["a", "b", "c", "d"], True),
            # note: this one is EAPI-dependent, it used to be True for EAPI <7
            ("^^ ( a? ( !b ) !c? ( d ) )", ["c"], ["a", "b", "c", "d"], False),
            ("^^ ( a? ( !b ) !c? ( d ) )", ["a", "c"], ["a", "b", "c",
                                                        "d"], True),
            ("^^ ( a? ( !b ) !c? ( d ) )", ["a", "b",
                                            "c"], ["a", "b", "c", "d"], False),
            ("^^ ( a? ( !b ) !c? ( d ) )", ["a", "b",
                                            "d"], ["a", "b", "c", "d"], True),
            ("^^ ( a? ( !b ) !c? ( d ) )", ["a", "b",
                                            "d"], ["a", "b", "c", "d"], True),
            ("^^ ( a? ( !b ) !c? ( d ) )", ["a", "d"], ["a", "b", "c",
                                                        "d"], False),
            ("|| ( ^^ ( a b ) ^^ ( b c ) )", [], ["a", "b", "c"], False),
            ("|| ( ^^ ( a b ) ^^ ( b c ) )", ["a"], ["a", "b", "c"], True),
            ("|| ( ^^ ( a b ) ^^ ( b c ) )", ["b"], ["a", "b", "c"], True),
            ("|| ( ^^ ( a b ) ^^ ( b c ) )", ["c"], ["a", "b", "c"], True),
            ("|| ( ^^ ( a b ) ^^ ( b c ) )", ["a", "b"], ["a", "b",
                                                          "c"], True),
            ("|| ( ^^ ( a b ) ^^ ( b c ) )", ["a", "c"], ["a", "b",
                                                          "c"], True),
            ("|| ( ^^ ( a b ) ^^ ( b c ) )", ["b", "c"], ["a", "b",
                                                          "c"], True),
            ("|| ( ^^ ( a b ) ^^ ( b c ) )", ["a", "b", "c"], ["a", "b",
                                                               "c"], False),
            ("^^ ( || ( a b ) ^^ ( b c ) )", [], ["a", "b", "c"], False),
            ("^^ ( || ( a b ) ^^ ( b c ) )", ["a"], ["a", "b", "c"], True),
            ("^^ ( || ( a b ) ^^ ( b c ) )", ["b"], ["a", "b", "c"], False),
            ("^^ ( || ( a b ) ^^ ( b c ) )", ["c"], ["a", "b", "c"], True),
            ("^^ ( || ( a b ) ^^ ( b c ) )", ["a", "b"], ["a", "b",
                                                          "c"], False),
            ("^^ ( || ( a b ) ^^ ( b c ) )", ["a", "c"], ["a", "b",
                                                          "c"], False),
            ("^^ ( || ( a b ) ^^ ( b c ) )", ["b", "c"], ["a", "b",
                                                          "c"], True),
            ("^^ ( || ( a b ) ^^ ( b c ) )", ["a", "b", "c"], ["a", "b",
                                                               "c"], True),
            ("|| ( ( a b ) c )", ["a", "b", "c"], ["a", "b", "c"], True),
            ("|| ( ( a b ) c )", ["b", "c"], ["a", "b", "c"], True),
            ("|| ( ( a b ) c )", ["a", "c"], ["a", "b", "c"], True),
            ("|| ( ( a b ) c )", ["a", "b"], ["a", "b", "c"], True),
            ("|| ( ( a b ) c )", ["a"], ["a", "b", "c"], False),
            ("|| ( ( a b ) c )", ["b"], ["a", "b", "c"], False),
            ("|| ( ( a b ) c )", ["c"], ["a", "b", "c"], True),
            ("|| ( ( a b ) c )", [], ["a", "b", "c"], False),
            ("^^ ( ( a b ) c )", ["a", "b", "c"], ["a", "b", "c"], False),
            ("^^ ( ( a b ) c )", ["b", "c"], ["a", "b", "c"], True),
            ("^^ ( ( a b ) c )", ["a", "c"], ["a", "b", "c"], True),
            ("^^ ( ( a b ) c )", ["a", "b"], ["a", "b", "c"], True),
            ("^^ ( ( a b ) c )", ["a"], ["a", "b", "c"], False),
            ("^^ ( ( a b ) c )", ["b"], ["a", "b", "c"], False),
            ("^^ ( ( a b ) c )", ["c"], ["a", "b", "c"], True),
            ("^^ ( ( a b ) c )", [], ["a", "b", "c"], False),
        )

        test_cases_xfail = (
            ("^^ ( || ( a b ) ^^ ( b c ) )", [], ["a", "b"]),
            ("^^ ( || ( a b ) ^^ ( b c )", [], ["a", "b", "c"]),
            ("^^( || ( a b ) ^^ ( b c ) )", [], ["a", "b", "c"]),
            ("^^ || ( a b ) ^^ ( b c )", [], ["a", "b", "c"]),
            ("^^ ( ( || ) ( a b ) ^^ ( b c ) )", [], ["a", "b", "c"]),
            ("^^ ( || ( a b ) ) ^^ ( b c ) )", [], ["a", "b", "c"]),
        )

        test_cases_xfail_eapi = (("?? ( a b )", [], ["a", "b"], "4"), )

        for required_use, use, iuse, expected in test_cases:
            self.assertEqual(bool(check_required_use(required_use, use, iuse.__contains__)), \
             expected, required_use + ", USE = " + " ".join(use))

        for required_use, use, iuse in test_cases_xfail:
            self.assertRaisesMsg(required_use + ", USE = " + " ".join(use), \
             InvalidDependString, check_required_use, required_use, use, iuse.__contains__)

        for required_use, use, iuse, eapi in test_cases_xfail_eapi:
            self.assertRaisesMsg(required_use + ", USE = " + " ".join(use), \
             InvalidDependString, check_required_use, required_use, use,
             iuse.__contains__, eapi=eapi)
Esempio n. 14
0
	def _find_suggestions(self):
		if not self.shortest_cycle:
			return None, None

		suggestions = []
		final_solutions = {}

		for pos, pkg in enumerate(self.shortest_cycle):
			parent = self.shortest_cycle[pos-1]
			priorities = self.graph.nodes[parent][0][pkg]
			parent_atoms = self.all_parent_atoms.get(pkg)

			if priorities[-1].buildtime:
				dep = parent.metadata["DEPEND"]
			elif priorities[-1].runtime:
				dep = parent.metadata["RDEPEND"]

			for ppkg, atom in parent_atoms:
				if ppkg == parent:
					changed_parent = ppkg
					parent_atom = atom.unevaluated_atom
					break

			affecting_use = extract_affecting_use(dep, parent_atom)

			# Make sure we don't want to change a flag that is 
			#	a) in use.mask or use.force
			#	b) changed by autounmask
			
			usemask, useforce = self._get_use_mask_and_force(parent)
			autounmask_changes = self._get_autounmask_changes(parent)
			untouchable_flags = frozenset(chain(usemask, useforce, autounmask_changes))

			affecting_use.difference_update(untouchable_flags)

			#If any of the flags we're going to touch is in REQUIRED_USE, add all
			#other flags in REQUIRED_USE to affecting_use, to not lose any solution.
			required_use_flags = get_required_use_flags(parent.metadata["REQUIRED_USE"])

			if affecting_use.intersection(required_use_flags):
				affecting_use.update(required_use_flags)
				affecting_use.difference_update(untouchable_flags)

			affecting_use = tuple(affecting_use)

			if not affecting_use:
				continue

			#We iterate over all possible settings of these use flags and gather
			#a set of possible changes
			#TODO: Use the information encoded in REQUIRED_USE
			use_state = []
			for flag in affecting_use:
				use_state.append("disabled")

			def _next_use_state(state, id=None):
				if id is None:
					id = len(state)-1

				if id == 0 and state[0] == "enabled":
					return False

				if state[id] == "disabled":
					state[id] = "enabled"
					for i in range(id+1,len(state)):
						state[i] = "disabled"
					return True
				else:
					return _next_use_state(state, id-1)

			solutions = set()
			while(True):
				current_use = set(self.depgraph._pkg_use_enabled(parent))
				for flag, state in zip(affecting_use, use_state):
					if state == "enabled":
						current_use.add(flag)
					else:
						current_use.discard(flag)
				reduced_dep = use_reduce(dep,
					uselist=current_use, flat=True)

				if parent_atom not in reduced_dep:
					#We found an assignment that removes the atom from 'dep'.
					#Make sure it doesn't conflict with REQUIRED_USE.
					required_use = parent.metadata["REQUIRED_USE"]

					if check_required_use(required_use, current_use, parent.iuse.is_valid_flag):
						use = self.depgraph._pkg_use_enabled(parent)
						solution = set()
						for flag, state in zip(affecting_use, use_state):
							if state == "enabled" and \
								flag not in use:
								solution.add((flag, True))
							elif state == "disabled" and \
								flag in use:
								solution.add((flag, False))
						solutions.add(frozenset(solution))

				if not _next_use_state(use_state):
					break

			for solution in solutions:
				ignore_solution = False
				for other_solution in solutions:
					if solution is other_solution:
						continue
					if solution.issuperset(other_solution):
						ignore_solution = True
				if ignore_solution:
					continue

				#Check if a USE change conflicts with use requirements of the parents.
				#If a requiremnet is hard, ignore the suggestion.
				#If the requirment is conditional, warn the user that other changes might be needed.
				followup_change = False
				parent_parent_atoms = self.depgraph._dynamic_config._parent_atoms.get(changed_parent)
				for ppkg, atom in parent_parent_atoms:

					atom = atom.unevaluated_atom
					if not atom.use:
						continue

					for flag, state in solution:
						if flag in atom.use.enabled or flag in atom.use.disabled:
							ignore_solution = True
							break
						elif atom.use.conditional:
							for flags in atom.use.conditional.values():
								if flag in flags:
									followup_change = True
									break

					if ignore_solution:
						break

				if ignore_solution:
					continue

				changes = []
				for flag, state in solution:
					if state:
						changes.append(colorize("red", "+"+flag))
					else:
						changes.append(colorize("blue", "-"+flag))
				msg = "- %s (Change USE: %s)\n" \
					% (parent.cpv, " ".join(changes))
				if followup_change:
					msg += " (This change might require USE changes on parent packages.)"
				suggestions.append(msg)
				final_solutions.setdefault(pkg, set()).add(solution)

		return final_solutions, suggestions
Esempio n. 15
0
	def testCheckRequiredUse(self):
		test_cases = (
			("|| ( a b )", [], ["a", "b"], False),
			("|| ( a b )", ["a"], ["a", "b"], True),
			("|| ( a b )", ["b"], ["a", "b"], True),
			("|| ( a b )", ["a", "b"], ["a", "b"], True),

			("^^ ( a b )", [], ["a", "b"], False),
			("^^ ( a b )", ["a"], ["a", "b"], True),
			("^^ ( a b )", ["b"], ["a", "b"], True),
			("^^ ( a b )", ["a", "b"], ["a", "b"], False),
			("?? ( a b )", ["a", "b"], ["a", "b"], False),
			("?? ( a b )", ["a"], ["a", "b"], True),
			("?? ( a b )", ["b"], ["a", "b"], True),
			("?? ( a b )", [], ["a", "b"], True),
			("?? ( )", [], [], True),

			("^^ ( || ( a b ) c )", [], ["a", "b", "c"], False),
			("^^ ( || ( a b ) c )", ["a"], ["a", "b", "c"], True),

			("^^ ( || ( ( a b ) ) ( c ) )", [], ["a", "b", "c"], False),
			("( ^^ ( ( || ( ( a ) ( b ) ) ) ( ( c ) ) ) )", ["a"], ["a", "b", "c"], True),

			("a || ( b c )", ["a"], ["a", "b", "c"], False),
			("|| ( b c ) a", ["a"], ["a", "b", "c"], False),

			("|| ( a b c )", ["a"], ["a", "b", "c"], True),
			("|| ( a b c )", ["b"], ["a", "b", "c"], True),
			("|| ( a b c )", ["c"], ["a", "b", "c"], True),

			("^^ ( a b c )", ["a"], ["a", "b", "c"], True),
			("^^ ( a b c )", ["b"], ["a", "b", "c"], True),
			("^^ ( a b c )", ["c"], ["a", "b", "c"], True),
			("^^ ( a b c )", ["a", "b"], ["a", "b", "c"], False),
			("^^ ( a b c )", ["b", "c"], ["a", "b", "c"], False),
			("^^ ( a b c )", ["a", "c"], ["a", "b", "c"], False),
			("^^ ( a b c )", ["a", "b", "c"], ["a", "b", "c"], False),

			("a? ( ^^ ( b c ) )", [], ["a", "b", "c"], True),
			("a? ( ^^ ( b c ) )", ["a"], ["a", "b", "c"], False),
			("a? ( ^^ ( b c ) )", ["b"], ["a", "b", "c"], True),
			("a? ( ^^ ( b c ) )", ["c"], ["a", "b", "c"], True),
			("a? ( ^^ ( b c ) )", ["a", "b"], ["a", "b", "c"], True),
			("a? ( ^^ ( b c ) )", ["a", "b", "c"], ["a", "b", "c"], False),

			("^^ ( a? ( !b ) !c? ( d ) )", [], ["a", "b", "c", "d"], False),
			("^^ ( a? ( !b ) !c? ( d ) )", ["a"], ["a", "b", "c", "d"], True),
			# note: this one is EAPI-dependent, it used to be True for EAPI <7
			("^^ ( a? ( !b ) !c? ( d ) )", ["c"], ["a", "b", "c", "d"], False),
			("^^ ( a? ( !b ) !c? ( d ) )", ["a", "c"], ["a", "b", "c", "d"], True),
			("^^ ( a? ( !b ) !c? ( d ) )", ["a", "b", "c"], ["a", "b", "c", "d"], False),
			("^^ ( a? ( !b ) !c? ( d ) )", ["a", "b", "d"], ["a", "b", "c", "d"], True),
			("^^ ( a? ( !b ) !c? ( d ) )", ["a", "b", "d"], ["a", "b", "c", "d"], True),
			("^^ ( a? ( !b ) !c? ( d ) )", ["a", "d"], ["a", "b", "c", "d"], False),

			("|| ( ^^ ( a b ) ^^ ( b c ) )", [], ["a", "b", "c"], False),
			("|| ( ^^ ( a b ) ^^ ( b c ) )", ["a"], ["a", "b", "c"], True),
			("|| ( ^^ ( a b ) ^^ ( b c ) )", ["b"], ["a", "b", "c"], True),
			("|| ( ^^ ( a b ) ^^ ( b c ) )", ["c"], ["a", "b", "c"], True),
			("|| ( ^^ ( a b ) ^^ ( b c ) )", ["a", "b"], ["a", "b", "c"], True),
			("|| ( ^^ ( a b ) ^^ ( b c ) )", ["a", "c"], ["a", "b", "c"], True),
			("|| ( ^^ ( a b ) ^^ ( b c ) )", ["b", "c"], ["a", "b", "c"], True),
			("|| ( ^^ ( a b ) ^^ ( b c ) )", ["a", "b", "c"], ["a", "b", "c"], False),

			("^^ ( || ( a b ) ^^ ( b c ) )", [], ["a", "b", "c"], False),
			("^^ ( || ( a b ) ^^ ( b c ) )", ["a"], ["a", "b", "c"], True),
			("^^ ( || ( a b ) ^^ ( b c ) )", ["b"], ["a", "b", "c"], False),
			("^^ ( || ( a b ) ^^ ( b c ) )", ["c"], ["a", "b", "c"], True),
			("^^ ( || ( a b ) ^^ ( b c ) )", ["a", "b"], ["a", "b", "c"], False),
			("^^ ( || ( a b ) ^^ ( b c ) )", ["a", "c"], ["a", "b", "c"], False),
			("^^ ( || ( a b ) ^^ ( b c ) )", ["b", "c"], ["a", "b", "c"], True),
			("^^ ( || ( a b ) ^^ ( b c ) )", ["a", "b", "c"], ["a", "b", "c"], True),

			("|| ( ( a b ) c )", ["a", "b", "c"], ["a", "b", "c"], True),
			("|| ( ( a b ) c )", ["b", "c"], ["a", "b", "c"], True),
			("|| ( ( a b ) c )", ["a", "c"], ["a", "b", "c"], True),
			("|| ( ( a b ) c )", ["a", "b"], ["a", "b", "c"], True),
			("|| ( ( a b ) c )", ["a"], ["a", "b", "c"], False),
			("|| ( ( a b ) c )", ["b"], ["a", "b", "c"], False),
			("|| ( ( a b ) c )", ["c"], ["a", "b", "c"], True),
			("|| ( ( a b ) c )", [], ["a", "b", "c"], False),

			("^^ ( ( a b ) c )", ["a", "b", "c"], ["a", "b", "c"], False),
			("^^ ( ( a b ) c )", ["b", "c"], ["a", "b", "c"], True),
			("^^ ( ( a b ) c )", ["a", "c"], ["a", "b", "c"], True),
			("^^ ( ( a b ) c )", ["a", "b"], ["a", "b", "c"], True),
			("^^ ( ( a b ) c )", ["a"], ["a", "b", "c"], False),
			("^^ ( ( a b ) c )", ["b"], ["a", "b", "c"], False),
			("^^ ( ( a b ) c )", ["c"], ["a", "b", "c"], True),
			("^^ ( ( a b ) c )", [], ["a", "b", "c"], False),
		)

		test_cases_xfail = (
			("^^ ( || ( a b ) ^^ ( b c ) )", [], ["a", "b"]),
			("^^ ( || ( a b ) ^^ ( b c )", [], ["a", "b", "c"]),
			("^^( || ( a b ) ^^ ( b c ) )", [], ["a", "b", "c"]),
			("^^ || ( a b ) ^^ ( b c )", [], ["a", "b", "c"]),
			("^^ ( ( || ) ( a b ) ^^ ( b c ) )", [], ["a", "b", "c"]),
			("^^ ( || ( a b ) ) ^^ ( b c ) )", [], ["a", "b", "c"]),
		)

		test_cases_xfail_eapi = (
			("?? ( a b )", [], ["a", "b"], "4"),
		)

		for required_use, use, iuse, expected in test_cases:
			self.assertEqual(bool(check_required_use(required_use, use, iuse.__contains__)), \
				expected, required_use + ", USE = " + " ".join(use))

		for required_use, use, iuse in test_cases_xfail:
			self.assertRaisesMsg(required_use + ", USE = " + " ".join(use), \
				InvalidDependString, check_required_use, required_use, use, iuse.__contains__)

		for required_use, use, iuse, eapi in test_cases_xfail_eapi:
			self.assertRaisesMsg(required_use + ", USE = " + " ".join(use), \
				InvalidDependString, check_required_use, required_use, use,
				iuse.__contains__, eapi=eapi)
Esempio n. 16
0
    def _find_suggestions(self):
        if not self.shortest_cycle:
            return None, None

        suggestions = []
        final_solutions = {}

        for pos, pkg in enumerate(self.shortest_cycle):
            parent = self.shortest_cycle[pos - 1]
            priorities = self.graph.nodes[parent][0][pkg]
            parent_atoms = self.all_parent_atoms.get(pkg)

            if priorities[-1].buildtime:
                dep = parent.metadata["DEPEND"]
            elif priorities[-1].runtime:
                dep = parent.metadata["RDEPEND"]

            for ppkg, atom in parent_atoms:
                if ppkg == parent:
                    changed_parent = ppkg
                    parent_atom = atom.unevaluated_atom
                    break

            affecting_use = extract_affecting_use(dep, parent_atom)

            # Make sure we don't want to change a flag that is
            #	a) in use.mask or use.force
            #	b) changed by autounmask

            usemask, useforce = self._get_use_mask_and_force(parent)
            autounmask_changes = self._get_autounmask_changes(parent)
            untouchable_flags = frozenset(
                chain(usemask, useforce, autounmask_changes))

            affecting_use.difference_update(untouchable_flags)

            #If any of the flags we're going to touch is in REQUIRED_USE, add all
            #other flags in REQUIRED_USE to affecting_use, to not lose any solution.
            required_use_flags = get_required_use_flags(
                parent.metadata["REQUIRED_USE"])

            if affecting_use.intersection(required_use_flags):
                affecting_use.update(required_use_flags)
                affecting_use.difference_update(untouchable_flags)

            affecting_use = tuple(affecting_use)

            if not affecting_use:
                continue

            #We iterate over all possible settings of these use flags and gather
            #a set of possible changes
            #TODO: Use the information encoded in REQUIRED_USE
            use_state = []
            for flag in affecting_use:
                use_state.append("disabled")

            def _next_use_state(state, id=None):
                if id is None:
                    id = len(state) - 1

                if id == 0 and state[0] == "enabled":
                    return False

                if state[id] == "disabled":
                    state[id] = "enabled"
                    for i in range(id + 1, len(state)):
                        state[i] = "disabled"
                    return True
                else:
                    return _next_use_state(state, id - 1)

            solutions = set()
            while (True):
                current_use = set(self.depgraph._pkg_use_enabled(parent))
                for flag, state in zip(affecting_use, use_state):
                    if state == "enabled":
                        current_use.add(flag)
                    else:
                        current_use.discard(flag)
                reduced_dep = use_reduce(dep, uselist=current_use, flat=True)

                if parent_atom not in reduced_dep:
                    #We found an assignment that removes the atom from 'dep'.
                    #Make sure it doesn't conflict with REQUIRED_USE.
                    required_use = parent.metadata["REQUIRED_USE"]

                    if check_required_use(required_use, current_use,
                                          parent.iuse.is_valid_flag):
                        use = self.depgraph._pkg_use_enabled(parent)
                        solution = set()
                        for flag, state in zip(affecting_use, use_state):
                            if state == "enabled" and \
                             flag not in use:
                                solution.add((flag, True))
                            elif state == "disabled" and \
                             flag in use:
                                solution.add((flag, False))
                        solutions.add(frozenset(solution))

                if not _next_use_state(use_state):
                    break

            for solution in solutions:
                ignore_solution = False
                for other_solution in solutions:
                    if solution is other_solution:
                        continue
                    if solution.issuperset(other_solution):
                        ignore_solution = True
                if ignore_solution:
                    continue

                #Check if a USE change conflicts with use requirements of the parents.
                #If a requiremnet is hard, ignore the suggestion.
                #If the requirment is conditional, warn the user that other changes might be needed.
                followup_change = False
                parent_parent_atoms = self.depgraph._dynamic_config._parent_atoms.get(
                    changed_parent)
                for ppkg, atom in parent_parent_atoms:

                    atom = atom.unevaluated_atom
                    if not atom.use:
                        continue

                    for flag, state in solution:
                        if flag in atom.use.enabled or flag in atom.use.disabled:
                            ignore_solution = True
                            break
                        elif atom.use.conditional:
                            for flags in atom.use.conditional.values():
                                if flag in flags:
                                    followup_change = True
                                    break

                    if ignore_solution:
                        break

                if ignore_solution:
                    continue

                changes = []
                for flag, state in solution:
                    if state:
                        changes.append(colorize("red", "+" + flag))
                    else:
                        changes.append(colorize("blue", "-" + flag))
                msg = "- %s (Change USE: %s)\n" \
                 % (parent.cpv, " ".join(changes))
                if followup_change:
                    msg += " (This change might require USE changes on parent packages.)"
                suggestions.append(msg)
                final_solutions.setdefault(pkg, set()).add(solution)

        return final_solutions, suggestions