Ejemplo n.º 1
0
    def test_evaluate_conditionals(self):
        test_cases = (
            ("dev-libs/A[foo]", [], "dev-libs/A[foo]"),
            ("dev-libs/A[foo]", ["foo"], "dev-libs/A[foo]"),
            ("dev-libs/A:0[foo=]", ["foo"], "dev-libs/A:0[foo]"),
            ("dev-libs/A[foo,-bar]", [], "dev-libs/A[foo,-bar]"),
            ("dev-libs/A[-foo,bar]", [], "dev-libs/A[-foo,bar]"),
            ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", [], "dev-libs/A[a,-b,c,-e,-f]"),
            ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["a"],
             "dev-libs/A[a,-b,c,-e,-f]"),
            ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["b"],
             "dev-libs/A[a,b,c,-e,-f]"),
            ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["c"],
             "dev-libs/A[a,-b,-c,-e,-f]"),
            ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["d"],
             "dev-libs/A[a,-b,c,d,-e,-f]"),
            ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["e"], "dev-libs/A[a,-b,c,-f]"),
            ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["f"],
             "dev-libs/A[a,-b,c,-e,-f]"),
            ("dev-libs/A[a(-),b(+)=,!c(-)=,d(+)?,!e(-)?,-f(+)]", ["d"],
             "dev-libs/A[a(-),-b(+),c(-),d(+),-e(-),-f(+)]"),
            ("dev-libs/A[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]", ["f"],
             "dev-libs/A[a(+),-b(-),c(+),-e(+),-f(-)]"),
        )

        for atom, use, expected_atom in test_cases:
            a = Atom(atom)
            b = a.evaluate_conditionals(use)
            self.assertEqual(str(b), expected_atom)
            self.assertEqual(str(b.unevaluated_atom), atom)
Ejemplo n.º 2
0
	def test_evaluate_conditionals(self):
		test_cases = (
			("dev-libs/A[foo]", [], "dev-libs/A[foo]"),
			("dev-libs/A[foo]", ["foo"], "dev-libs/A[foo]"),

			("dev-libs/A:0[foo=]", ["foo"], "dev-libs/A:0[foo]"),

			("dev-libs/A[foo,-bar]", [], "dev-libs/A[foo,-bar]"),
			("dev-libs/A[-foo,bar]", [], "dev-libs/A[-foo,bar]"),

			("dev-libs/A[a,b=,!c=,d?,!e?,-f]", [], "dev-libs/A[a,-b,c,-e,-f]"),
			("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["a"], "dev-libs/A[a,-b,c,-e,-f]"),
			("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["b"], "dev-libs/A[a,b,c,-e,-f]"),
			("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["c"], "dev-libs/A[a,-b,-c,-e,-f]"),
			("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["d"], "dev-libs/A[a,-b,c,d,-e,-f]"),
			("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["e"], "dev-libs/A[a,-b,c,-f]"),
			("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["f"], "dev-libs/A[a,-b,c,-e,-f]"),
			("dev-libs/A[a(-),b(+)=,!c(-)=,d(+)?,!e(-)?,-f(+)]", ["d"], "dev-libs/A[a(-),-b(+),c(-),d(+),-e(-),-f(+)]"),
			("dev-libs/A[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]", ["f"], "dev-libs/A[a(+),-b(-),c(+),-e(+),-f(-)]"),
		)

		for atom, use, expected_atom in test_cases:
			a = Atom(atom)
			b = a.evaluate_conditionals(use)
			self.assertEqual(str(b), expected_atom)
			self.assertEqual(str(b.unevaluated_atom), atom)
Ejemplo n.º 3
0
	def __call__(self, argv):
		"""
		@return: tuple of (stdout, stderr, returncode)
		"""

		# Python 3:
		# cmd, root, *args = argv
		cmd = argv[0]
		root = argv[1]
		args = argv[2:]

		warnings = []
		warnings_str = ''

		db = self.get_db()
		eapi = self.settings.get('EAPI')

		root = normalize_path(root or os.sep).rstrip(os.sep) + os.sep
		if root not in db:
			return ('', '%s: Invalid ROOT: %s\n' % (cmd, root), 3)

		portdb = db[root]["porttree"].dbapi
		vardb = db[root]["vartree"].dbapi

		if cmd in ('best_version', 'has_version'):
			try:
				atom = Atom(args[0], allow_repo=False)
			except InvalidAtom:
				return ('', '%s: Invalid atom: %s\n' % (cmd, args[0]), 2)

			try:
				atom = Atom(args[0], allow_repo=False, eapi=eapi)
			except InvalidAtom as e:
				warnings.append("QA Notice: %s: %s" % (cmd, e))

			use = self.settings.get('PORTAGE_BUILT_USE')
			if use is None:
				use = self.settings['PORTAGE_USE']

			use = frozenset(use.split())
			atom = atom.evaluate_conditionals(use)

		if warnings:
			warnings_str = self._elog('eqawarn', warnings)

		if cmd == 'has_version':
			if vardb.match(atom):
				returncode = 0
			else:
				returncode = 1
			return ('', warnings_str, returncode)
		elif cmd == 'best_version':
			m = best(vardb.match(atom))
			return ('%s\n' % m, warnings_str, 0)
		else:
			return ('', 'Invalid command: %s\n' % cmd, 3)
Ejemplo n.º 4
0
	def __call__(self, argv):
		"""
		@returns: tuple of (stdout, stderr, returncode)
		"""

		cmd, root, atom_str = argv

		eapi = self.settings.get('EAPI')
		allow_repo = eapi_has_repo_deps(eapi)
		try:
			atom = Atom(atom_str, allow_repo=allow_repo)
		except InvalidAtom:
			return ('', 'invalid atom: %s\n' % atom_str, 2)

		warnings = []
		try:
			atom = Atom(atom_str, allow_repo=allow_repo, eapi=eapi)
		except InvalidAtom as e:
			warnings.append(_unicode_decode("QA Notice: %s: %s") % (cmd, e))

		use = self.settings.get('PORTAGE_BUILT_USE')
		if use is None:
			use = self.settings['PORTAGE_USE']

		use = frozenset(use.split())
		atom = atom.evaluate_conditionals(use)

		db = self._db
		if db is None:
			db = portage.db

		warnings_str = ''
		if warnings:
			warnings_str = self._elog('eqawarn', warnings)

		root = normalize_path(root).rstrip(os.path.sep) + os.path.sep
		if root not in db:
			return ('', 'invalid ROOT: %s\n' % root, 2)

		vardb = db[root]["vartree"].dbapi

		if cmd == 'has_version':
			if vardb.match(atom):
				returncode = 0
			else:
				returncode = 1
			return ('', warnings_str, returncode)
		elif cmd == 'best_version':
			m = best(vardb.match(atom))
			return ('%s\n' % m, warnings_str, 0)
		else:
			return ('', 'invalid command: %s\n' % cmd, 2)
Ejemplo n.º 5
0
	def __call__(self, argv):
		"""
		@returns: tuple of (stdout, stderr, returncode)
		"""

		# Note that $USE is passed via IPC in order to ensure that
		# we have the correct value for built/installed packages,
		# since the config class doesn't currently provide a way
		# to access built/installed $USE that would work in all
		# possible scenarios.
		cmd, root, atom, use = argv

		try:
			atom = Atom(atom)
		except InvalidAtom:
			return ('', 'invalid atom: %s\n' % atom, 2)

		use = frozenset(use.split())
		atom = atom.evaluate_conditionals(use)

		db = self._db
		if db is None:
			db = portage.db

		root = normalize_path(root).rstrip(os.path.sep) + os.path.sep
		if root not in db:
			return ('', 'invalid ROOT: %s\n' % root, 2)

		vardb = db[root]["vartree"].dbapi

		if cmd == 'has_version':
			if vardb.match(atom):
				returncode = 0
			else:
				returncode = 1
			return ('', '', returncode)
		elif cmd == 'best_version':
			m = best(vardb.match(atom))
			return ('%s\n' % m, '', 0)
		else:
			return ('', 'invalid command: %s\n' % cmd, 2)
Ejemplo n.º 6
0
            def clean_subslots(depatom, usel=None):
                if isinstance(depatom, list):
                    # process the nested list.
                    return [clean_subslots(x, usel) for x in depatom]

                try:
                    # this can be either an atom or some special operator.
                    # in the latter case, we get InvalidAtom and pass it as-is.
                    a = Atom(depatom)
                except InvalidAtom:
                    return depatom
                # if we're processing portdb, we need to evaluate USE flag
                # dependency conditionals to make them match vdb. this
                # requires passing the list of USE flags, so we reuse it
                # as conditional for the operation as well.
                if usel is not None:
                    a = a.evaluate_conditionals(usel)

                # replace slot operator := dependencies with plain :=
                # since we can't properly compare expanded slots
                # in vardb to abstract slots in portdb.
                return subslot_repl_re.sub(':=', a)
Ejemplo n.º 7
0
			def clean_subslots(depatom, usel=None):
				if isinstance(depatom, list):
					# process the nested list.
					return [clean_subslots(x, usel) for x in depatom]
				else:
					try:
						# this can be either an atom or some special operator.
						# in the latter case, we get InvalidAtom and pass it as-is.
						a = Atom(depatom)
					except InvalidAtom:
						return depatom
					else:
						# if we're processing portdb, we need to evaluate USE flag
						# dependency conditionals to make them match vdb. this
						# requires passing the list of USE flags, so we reuse it
						# as conditional for the operation as well.
						if usel is not None:
							a = a.evaluate_conditionals(usel)

						# replace slot operator := dependencies with plain :=
						# since we can't properly compare expanded slots
						# in vardb to abstract slots in portdb.
						return subslot_repl_re.sub(':=', a)
Ejemplo n.º 8
0
    def __call__(self, argv):
        """
		@return: tuple of (stdout, stderr, returncode)
		"""

        # Python 3:
        # cmd, root, *args = argv
        cmd = argv[0]
        root = argv[1]
        args = argv[2:]

        warnings = []
        warnings_str = ''

        db = self.get_db()
        eapi = self.settings.get('EAPI')

        root = normalize_path(root or os.sep).rstrip(os.sep) + os.sep
        if root not in db:
            return ('', '%s: Invalid ROOT: %s\n' % (cmd, root), 3)

        portdb = db[root]["porttree"].dbapi
        vardb = db[root]["vartree"].dbapi

        if cmd in ('best_version', 'has_version'):
            allow_repo = eapi_has_repo_deps(eapi)
            try:
                atom = Atom(args[0], allow_repo=allow_repo)
            except InvalidAtom:
                return ('', '%s: Invalid atom: %s\n' % (cmd, args[0]), 2)

            try:
                atom = Atom(args[0], allow_repo=allow_repo, eapi=eapi)
            except InvalidAtom as e:
                warnings.append("QA Notice: %s: %s" % (cmd, e))

            use = self.settings.get('PORTAGE_BUILT_USE')
            if use is None:
                use = self.settings['PORTAGE_USE']

            use = frozenset(use.split())
            atom = atom.evaluate_conditionals(use)

        if warnings:
            warnings_str = self._elog('eqawarn', warnings)

        if cmd == 'has_version':
            if vardb.match(atom):
                returncode = 0
            else:
                returncode = 1
            return ('', warnings_str, returncode)
        elif cmd == 'best_version':
            m = best(vardb.match(atom))
            return ('%s\n' % m, warnings_str, 0)
        elif cmd in ('master_repositories', 'repository_path',
                     'available_eclasses', 'eclass_path', 'license_path'):
            repo = _repo_name_re.match(args[0])
            if repo is None:
                return ('', '%s: Invalid repository: %s\n' % (cmd, args[0]), 2)
            try:
                repo = portdb.repositories[args[0]]
            except KeyError:
                return ('', warnings_str, 1)

            if cmd == 'master_repositories':
                return ('%s\n' % ' '.join(x.name for x in repo.masters),
                        warnings_str, 0)
            elif cmd == 'repository_path':
                return ('%s\n' % repo.location, warnings_str, 0)
            elif cmd == 'available_eclasses':
                return ('%s\n' % ' '.join(sorted(repo.eclass_db.eclasses)),
                        warnings_str, 0)
            elif cmd == 'eclass_path':
                try:
                    eclass = repo.eclass_db.eclasses[args[1]]
                except KeyError:
                    return ('', warnings_str, 1)
                return ('%s\n' % eclass.location, warnings_str, 0)
            elif cmd == 'license_path':
                paths = reversed([
                    os.path.join(x.location, 'licenses', args[1])
                    for x in list(repo.masters) + [repo]
                ])
                for path in paths:
                    if os.path.exists(path):
                        return ('%s\n' % path, warnings_str, 0)
                return ('', warnings_str, 1)
        else:
            return ('', 'Invalid command: %s\n' % cmd, 3)
Ejemplo n.º 9
0
def _expand_new_virtuals(
    mysplit, edebug, mydbapi, mysettings, myroot="/", trees=None, use_mask=None, use_force=None, **kwargs
):
    """
	In order to solve bug #141118, recursively expand new-style virtuals so
	as to collapse one or more levels of indirection, generating an expanded
	search space. In dep_zapdeps, new-style virtuals will be assigned
	zero cost regardless of whether or not they are currently installed. Virtual
	blockers are supported but only when the virtual expands to a single
	atom because it wouldn't necessarily make sense to block all the components
	of a compound virtual.  When more than one new-style virtual is matched,
	the matches are sorted from highest to lowest versions and the atom is
	expanded to || ( highest match ... lowest match )."""
    newsplit = []
    mytrees = trees[myroot]
    portdb = mytrees["porttree"].dbapi
    pkg_use_enabled = mytrees.get("pkg_use_enabled")
    # Atoms are stored in the graph as (atom, id(atom)) tuples
    # since each atom is considered to be a unique entity. For
    # example, atoms that appear identical may behave differently
    # in USE matching, depending on their unevaluated form. Also,
    # specially generated virtual atoms may appear identical while
    # having different _orig_atom attributes.
    atom_graph = mytrees.get("atom_graph")
    parent = mytrees.get("parent")
    virt_parent = mytrees.get("virt_parent")
    graph_parent = None
    if parent is not None:
        if virt_parent is not None:
            graph_parent = virt_parent
            parent = virt_parent
        else:
            graph_parent = parent
    repoman = not mysettings.local_config
    if kwargs["use_binaries"]:
        portdb = trees[myroot]["bintree"].dbapi
    pprovideddict = mysettings.pprovideddict
    myuse = kwargs["myuse"]
    for x in mysplit:
        if x == "||":
            newsplit.append(x)
            continue
        elif isinstance(x, list):
            newsplit.append(
                _expand_new_virtuals(
                    x,
                    edebug,
                    mydbapi,
                    mysettings,
                    myroot=myroot,
                    trees=trees,
                    use_mask=use_mask,
                    use_force=use_force,
                    **kwargs
                )
            )
            continue

        if not isinstance(x, Atom):
            raise ParseError(_("invalid token: '%s'") % x)

        if repoman:
            x = x._eval_qa_conditionals(use_mask, use_force)

        mykey = x.cp
        if not mykey.startswith("virtual/"):
            newsplit.append(x)
            if atom_graph is not None:
                atom_graph.add((x, id(x)), graph_parent)
            continue

        if x.blocker:
            # Virtual blockers are no longer expanded here since
            # the un-expanded virtual atom is more useful for
            # maintaining a cache of blocker atoms.
            newsplit.append(x)
            if atom_graph is not None:
                atom_graph.add((x, id(x)), graph_parent)
            continue

        if repoman or not hasattr(portdb, "match_pkgs") or pkg_use_enabled is None:
            if portdb.cp_list(x.cp):
                newsplit.append(x)
            else:
                a = []
                myvartree = mytrees.get("vartree")
                if myvartree is not None:
                    mysettings._populate_treeVirtuals_if_needed(myvartree)
                mychoices = mysettings.getvirtuals().get(mykey, [])
                for y in mychoices:
                    a.append(Atom(x.replace(x.cp, y.cp, 1)))
                if not a:
                    newsplit.append(x)
                elif len(a) == 1:
                    newsplit.append(a[0])
                else:
                    newsplit.append(["||"] + a)
            continue

        pkgs = []
        # Ignore USE deps here, since otherwise we might not
        # get any matches. Choices with correct USE settings
        # will be preferred in dep_zapdeps().
        matches = portdb.match_pkgs(x.without_use)
        # Use descending order to prefer higher versions.
        matches.reverse()
        for pkg in matches:
            # only use new-style matches
            if pkg.cp.startswith("virtual/"):
                pkgs.append(pkg)

        mychoices = []
        if not pkgs and not portdb.cp_list(x.cp):
            myvartree = mytrees.get("vartree")
            if myvartree is not None:
                mysettings._populate_treeVirtuals_if_needed(myvartree)
            mychoices = mysettings.getvirtuals().get(mykey, [])

        if not (pkgs or mychoices):
            # This one couldn't be expanded as a new-style virtual.  Old-style
            # virtuals have already been expanded by dep_virtual, so this one
            # is unavailable and dep_zapdeps will identify it as such.  The
            # atom is not eliminated here since it may still represent a
            # dependency that needs to be satisfied.
            newsplit.append(x)
            if atom_graph is not None:
                atom_graph.add((x, id(x)), graph_parent)
            continue

        a = []
        for pkg in pkgs:
            virt_atom = "=" + pkg.cpv
            if x.unevaluated_atom.use:
                virt_atom += str(x.unevaluated_atom.use)
                virt_atom = Atom(virt_atom)
                if parent is None:
                    if myuse is None:
                        virt_atom = virt_atom.evaluate_conditionals(mysettings.get("PORTAGE_USE", "").split())
                    else:
                        virt_atom = virt_atom.evaluate_conditionals(myuse)
                else:
                    virt_atom = virt_atom.evaluate_conditionals(pkg_use_enabled(parent))
            else:
                virt_atom = Atom(virt_atom)

                # Allow the depgraph to map this atom back to the
                # original, in order to avoid distortion in places
                # like display or conflict resolution code.
            virt_atom.__dict__["_orig_atom"] = x

            # According to GLEP 37, RDEPEND is the only dependency
            # type that is valid for new-style virtuals. Repoman
            # should enforce this.
            depstring = pkg._metadata["RDEPEND"]
            pkg_kwargs = kwargs.copy()
            pkg_kwargs["myuse"] = pkg_use_enabled(pkg)
            if edebug:
                writemsg_level(_("Virtual Parent:      %s\n") % (pkg,), noiselevel=-1, level=logging.DEBUG)
                writemsg_level(_("Virtual Depstring:   %s\n") % (depstring,), noiselevel=-1, level=logging.DEBUG)

                # Set EAPI used for validation in dep_check() recursion.
            mytrees["virt_parent"] = pkg

            try:
                mycheck = dep_check(depstring, mydbapi, mysettings, myroot=myroot, trees=trees, **pkg_kwargs)
            finally:
                # Restore previous EAPI after recursion.
                if virt_parent is not None:
                    mytrees["virt_parent"] = virt_parent
                else:
                    del mytrees["virt_parent"]

            if not mycheck[0]:
                raise ParseError("%s: %s '%s'" % (pkg, mycheck[1], depstring))

                # pull in the new-style virtual
            mycheck[1].append(virt_atom)
            a.append(mycheck[1])
            if atom_graph is not None:
                virt_atom_node = (virt_atom, id(virt_atom))
                atom_graph.add(virt_atom_node, graph_parent)
                atom_graph.add(pkg, virt_atom_node)

        if not a and mychoices:
            # Check for a virtual package.provided match.
            for y in mychoices:
                new_atom = Atom(x.replace(x.cp, y.cp, 1))
                if match_from_list(new_atom, pprovideddict.get(new_atom.cp, [])):
                    a.append(new_atom)
                    if atom_graph is not None:
                        atom_graph.add((new_atom, id(new_atom)), graph_parent)

        if not a:
            newsplit.append(x)
            if atom_graph is not None:
                atom_graph.add((x, id(x)), graph_parent)
        elif len(a) == 1:
            newsplit.append(a[0])
        else:
            newsplit.append(["||"] + a)

    return newsplit
Ejemplo n.º 10
0
def _expand_new_virtuals(mysplit, edebug, mydbapi, mysettings, myroot="/",
	trees=None, use_mask=None, use_force=None, **kwargs):
	"""
	In order to solve bug #141118, recursively expand new-style virtuals so
	as to collapse one or more levels of indirection, generating an expanded
	search space. In dep_zapdeps, new-style virtuals will be assigned
	zero cost regardless of whether or not they are currently installed. Virtual
	blockers are supported but only when the virtual expands to a single
	atom because it wouldn't necessarily make sense to block all the components
	of a compound virtual.  When more than one new-style virtual is matched,
	the matches are sorted from highest to lowest versions and the atom is
	expanded to || ( highest match ... lowest match )."""
	newsplit = []
	mytrees = trees[myroot]
	portdb = mytrees["porttree"].dbapi
	atom_graph = mytrees.get("atom_graph")
	parent = mytrees.get("parent")
	virt_parent = mytrees.get("virt_parent")
	graph_parent = None
	eapi = None
	if parent is not None:
		if virt_parent is not None:
			graph_parent = virt_parent
			eapi = virt_parent[0].metadata['EAPI']
		else:
			graph_parent = parent
			eapi = parent.metadata["EAPI"]
	repoman = not mysettings.local_config
	if kwargs["use_binaries"]:
		portdb = trees[myroot]["bintree"].dbapi
	myvirtuals = mysettings.getvirtuals()
	pprovideddict = mysettings.pprovideddict
	myuse = kwargs["myuse"]
	for x in mysplit:
		if x == "||":
			newsplit.append(x)
			continue
		elif isinstance(x, list):
			newsplit.append(_expand_new_virtuals(x, edebug, mydbapi,
				mysettings, myroot=myroot, trees=trees, use_mask=use_mask,
				use_force=use_force, **kwargs))
			continue

		if not isinstance(x, Atom):
			try:
				x = Atom(x)
			except InvalidAtom:
				if portage.dep._dep_check_strict:
					raise ParseError(
						_("invalid atom: '%s'") % x)
				else:
					# Only real Atom instances are allowed past this point.
					continue
			else:
				if x.blocker and x.blocker.overlap.forbid and \
					eapi in ("0", "1") and portage.dep._dep_check_strict:
					raise ParseError(
						_("invalid atom: '%s'") % (x,))
				if x.use and eapi in ("0", "1") and \
					portage.dep._dep_check_strict:
					raise ParseError(
						_("invalid atom: '%s'") % (x,))

		if repoman and x.use and x.use.conditional:
			evaluated_atom = remove_slot(x)
			if x.slot:
				evaluated_atom += ":%s" % x.slot
			evaluated_atom += str(x.use._eval_qa_conditionals(
				use_mask, use_force))
			x = Atom(evaluated_atom)

		if not repoman :
			if 'lib32' not in x and portage.dep_getkey(x) not in mysettings.get("NO_AUTO_FLAG", None):
				if ']' in x:
					x = str(x).replace(']',',lib32?]')
				else:
					x = str(x) + '[lib32?]'
				try:
					x = portage.dep.Atom(x)
				except portage.exception.InvalidAtom:
					if portage.dep._dep_check_strict:
						raise portage.exception.ParseError(
							"invalid atom: '%s'" % x)

			if myuse is not None and isinstance(x, Atom) and x.use:
				if x.use.conditional:
					x = x.evaluate_conditionals(myuse)

		mykey = x.cp
		if not mykey.startswith("virtual/"):
			newsplit.append(x)
			if atom_graph is not None:
				atom_graph.add(x, graph_parent)
			continue
		mychoices = myvirtuals.get(mykey, [])
		if x.blocker:
			# Virtual blockers are no longer expanded here since
			# the un-expanded virtual atom is more useful for
			# maintaining a cache of blocker atoms.
			newsplit.append(x)
			if atom_graph is not None:
				atom_graph.add(x, graph_parent)
			continue

		if repoman or not hasattr(portdb, 'match_pkgs'):
			if portdb.cp_list(x.cp):
				newsplit.append(x)
			else:
				# TODO: Add PROVIDE check for repoman.
				a = []
				for y in mychoices:
					a.append(Atom(x.replace(x.cp, y.cp, 1)))
				if not a:
					newsplit.append(x)
				elif len(a) == 1:
					newsplit.append(a[0])
				else:
					newsplit.append(['||'] + a)
			continue

		pkgs = []
		# Ignore USE deps here, since otherwise we might not
		# get any matches. Choices with correct USE settings
		# will be preferred in dep_zapdeps().
		matches = portdb.match_pkgs(x.without_use)
		# Use descending order to prefer higher versions.
		matches.reverse()
		for pkg in matches:
			# only use new-style matches
			if pkg.cp.startswith("virtual/"):
				pkgs.append(pkg)
		if not (pkgs or mychoices):
			# This one couldn't be expanded as a new-style virtual.  Old-style
			# virtuals have already been expanded by dep_virtual, so this one
			# is unavailable and dep_zapdeps will identify it as such.  The
			# atom is not eliminated here since it may still represent a
			# dependency that needs to be satisfied.
			newsplit.append(x)
			if atom_graph is not None:
				atom_graph.add(x, graph_parent)
			continue

		a = []
		for pkg in pkgs:
			virt_atom = '=' + pkg.cpv
			if x.use:
				virt_atom += str(x.use)
			virt_atom = Atom(virt_atom)
			# According to GLEP 37, RDEPEND is the only dependency
			# type that is valid for new-style virtuals. Repoman
			# should enforce this.
			depstring = pkg.metadata['RDEPEND']
			pkg_kwargs = kwargs.copy()
			pkg_kwargs["myuse"] = pkg.use.enabled
			if edebug:
				writemsg_level(_("Virtual Parent:      %s\n") \
					% (pkg,), noiselevel=-1, level=logging.DEBUG)
				writemsg_level(_("Virtual Depstring:   %s\n") \
					% (depstring,), noiselevel=-1, level=logging.DEBUG)

			# Set EAPI used for validation in dep_check() recursion.
			mytrees["virt_parent"] = (pkg, virt_atom)

			try:
				mycheck = dep_check(depstring, mydbapi, mysettings,
					myroot=myroot, trees=trees, **pkg_kwargs)
			finally:
				# Restore previous EAPI after recursion.
				if virt_parent is not None:
					mytrees["virt_parent"] = virt_parent
				else:
					del mytrees["virt_parent"]

			if not mycheck[0]:
				raise ParseError(
					"%s: %s '%s'" % (y[0], mycheck[1], depstring))

			# pull in the new-style virtual
			mycheck[1].append(virt_atom)
			a.append(mycheck[1])
			if atom_graph is not None:
				atom_graph.add(virt_atom, graph_parent)
		# Plain old-style virtuals.  New-style virtuals are preferred.
		if not pkgs:
				for y in mychoices:
					new_atom = Atom(x.replace(x.cp, y.cp, 1))
					matches = portdb.match(new_atom)
					# portdb is an instance of depgraph._dep_check_composite_db, so
					# USE conditionals are already evaluated.
					if matches and mykey in \
						portdb.aux_get(matches[-1], ['PROVIDE'])[0].split():
						a.append(new_atom)
						if atom_graph is not None:
							atom_graph.add(new_atom, graph_parent)

		if not a and mychoices:
			# Check for a virtual package.provided match.
			for y in mychoices:
				new_atom = Atom(x.replace(x.cp, y.cp, 1))
				if match_from_list(new_atom,
					pprovideddict.get(new_atom.cp, [])):
					a.append(new_atom)
					if atom_graph is not None:
						atom_graph.add(new_atom, graph_parent)

		if not a:
			newsplit.append(x)
			if atom_graph is not None:
				atom_graph.add(x, graph_parent)
		elif len(a) == 1:
			newsplit.append(a[0])
		else:
			newsplit.append(['||'] + a)

	return newsplit
Ejemplo n.º 11
0
def _expand_new_virtuals(mysplit,
                         edebug,
                         mydbapi,
                         mysettings,
                         myroot="/",
                         trees=None,
                         use_mask=None,
                         use_force=None,
                         **kwargs):
    """
	In order to solve bug #141118, recursively expand new-style virtuals so
	as to collapse one or more levels of indirection, generating an expanded
	search space. In dep_zapdeps, new-style virtuals will be assigned
	zero cost regardless of whether or not they are currently installed. Virtual
	blockers are supported but only when the virtual expands to a single
	atom because it wouldn't necessarily make sense to block all the components
	of a compound virtual.  When more than one new-style virtual is matched,
	the matches are sorted from highest to lowest versions and the atom is
	expanded to || ( highest match ... lowest match ).

	The result is normalized in the same way as use_reduce, having a top-level
	conjuction, and no redundant nested lists.
	"""
    newsplit = []
    mytrees = trees[myroot]
    portdb = mytrees["porttree"].dbapi
    pkg_use_enabled = mytrees.get("pkg_use_enabled")
    # Atoms are stored in the graph as (atom, id(atom)) tuples
    # since each atom is considered to be a unique entity. For
    # example, atoms that appear identical may behave differently
    # in USE matching, depending on their unevaluated form. Also,
    # specially generated virtual atoms may appear identical while
    # having different _orig_atom attributes.
    atom_graph = mytrees.get("atom_graph")
    parent = mytrees.get("parent")
    virt_parent = mytrees.get("virt_parent")
    graph_parent = None
    if parent is not None:
        if virt_parent is not None:
            graph_parent = virt_parent
            parent = virt_parent
        else:
            graph_parent = parent
    repoman = not mysettings.local_config
    if kwargs["use_binaries"]:
        portdb = trees[myroot]["bintree"].dbapi
    pprovideddict = mysettings.pprovideddict
    myuse = kwargs["myuse"]
    is_disjunction = mysplit and mysplit[0] == '||'
    for x in mysplit:
        if x == "||":
            newsplit.append(x)
            continue
        elif isinstance(x, list):
            assert x, 'Normalization error, empty conjunction found in %s' % (
                mysplit, )
            if is_disjunction:
                assert x[0] != '||', \
                 'Normalization error, nested disjunction found in %s' % (mysplit,)
            else:
                assert x[0] == '||', \
                 'Normalization error, nested conjunction found in %s' % (mysplit,)
            x_exp = _expand_new_virtuals(x,
                                         edebug,
                                         mydbapi,
                                         mysettings,
                                         myroot=myroot,
                                         trees=trees,
                                         use_mask=use_mask,
                                         use_force=use_force,
                                         **kwargs)
            if is_disjunction:
                if len(x_exp) == 1:
                    x = x_exp[0]
                    if isinstance(x, list):
                        # Due to normalization, a conjunction must not be
                        # nested directly in another conjunction, so this
                        # must be a disjunction.
                        assert x and x[0] == '||', \
                         'Normalization error, nested conjunction found in %s' % (x_exp,)
                        newsplit.extend(x[1:])
                    else:
                        newsplit.append(x)
                else:
                    newsplit.append(x_exp)
            else:
                newsplit.extend(x_exp)
            continue

        if not isinstance(x, Atom):
            raise ParseError(_("invalid token: '%s'") % x)

        if repoman:
            x = x._eval_qa_conditionals(use_mask, use_force)

        mykey = x.cp
        if not mykey.startswith("virtual/"):
            newsplit.append(x)
            if atom_graph is not None:
                atom_graph.add((x, id(x)), graph_parent)
            continue

        if x.blocker:
            # Virtual blockers are no longer expanded here since
            # the un-expanded virtual atom is more useful for
            # maintaining a cache of blocker atoms.
            newsplit.append(x)
            if atom_graph is not None:
                atom_graph.add((x, id(x)), graph_parent)
            continue

        if repoman or not hasattr(portdb, 'match_pkgs') or \
         pkg_use_enabled is None:
            if portdb.cp_list(x.cp):
                newsplit.append(x)
            else:
                a = []
                myvartree = mytrees.get("vartree")
                if myvartree is not None:
                    mysettings._populate_treeVirtuals_if_needed(myvartree)
                mychoices = mysettings.getvirtuals().get(mykey, [])
                for y in mychoices:
                    a.append(Atom(x.replace(x.cp, y.cp, 1)))
                if not a:
                    newsplit.append(x)
                elif is_disjunction:
                    newsplit.extend(a)
                elif len(a) == 1:
                    newsplit.append(a[0])
                else:
                    newsplit.append(['||'] + a)
            continue

        pkgs = []
        # Ignore USE deps here, since otherwise we might not
        # get any matches. Choices with correct USE settings
        # will be preferred in dep_zapdeps().
        matches = portdb.match_pkgs(x.without_use)
        # Use descending order to prefer higher versions.
        matches.reverse()
        for pkg in matches:
            # only use new-style matches
            if pkg.cp.startswith("virtual/"):
                pkgs.append(pkg)

        mychoices = []
        if not pkgs and not portdb.cp_list(x.cp):
            myvartree = mytrees.get("vartree")
            if myvartree is not None:
                mysettings._populate_treeVirtuals_if_needed(myvartree)
            mychoices = mysettings.getvirtuals().get(mykey, [])

        if not (pkgs or mychoices):
            # This one couldn't be expanded as a new-style virtual.  Old-style
            # virtuals have already been expanded by dep_virtual, so this one
            # is unavailable and dep_zapdeps will identify it as such.  The
            # atom is not eliminated here since it may still represent a
            # dependency that needs to be satisfied.
            newsplit.append(x)
            if atom_graph is not None:
                atom_graph.add((x, id(x)), graph_parent)
            continue

        a = []
        for pkg in pkgs:
            virt_atom = '=' + pkg.cpv
            if x.unevaluated_atom.use:
                virt_atom += str(x.unevaluated_atom.use)
                virt_atom = Atom(virt_atom)
                if parent is None:
                    if myuse is None:
                        virt_atom = virt_atom.evaluate_conditionals(
                            mysettings.get("PORTAGE_USE", "").split())
                    else:
                        virt_atom = virt_atom.evaluate_conditionals(myuse)
                else:
                    virt_atom = virt_atom.evaluate_conditionals(
                        pkg_use_enabled(parent))
            else:
                virt_atom = Atom(virt_atom)

            # Allow the depgraph to map this atom back to the
            # original, in order to avoid distortion in places
            # like display or conflict resolution code.
            virt_atom.__dict__['_orig_atom'] = x

            # According to GLEP 37, RDEPEND is the only dependency
            # type that is valid for new-style virtuals. Repoman
            # should enforce this.
            depstring = pkg._metadata['RDEPEND']
            pkg_kwargs = kwargs.copy()
            pkg_kwargs["myuse"] = pkg_use_enabled(pkg)
            if edebug:
                writemsg_level(_("Virtual Parent:      %s\n") \
                 % (pkg,), noiselevel=-1, level=logging.DEBUG)
                writemsg_level(_("Virtual Depstring:   %s\n") \
                 % (depstring,), noiselevel=-1, level=logging.DEBUG)

            # Set EAPI used for validation in dep_check() recursion.
            mytrees["virt_parent"] = pkg

            try:
                mycheck = dep_check(depstring,
                                    mydbapi,
                                    mysettings,
                                    myroot=myroot,
                                    trees=trees,
                                    **pkg_kwargs)
            finally:
                # Restore previous EAPI after recursion.
                if virt_parent is not None:
                    mytrees["virt_parent"] = virt_parent
                else:
                    del mytrees["virt_parent"]

            if not mycheck[0]:
                raise ParseError("%s: %s '%s'" % \
                 (pkg, mycheck[1], depstring))

            # Replace the original atom "x" with "virt_atom" which refers
            # to the specific version of the virtual whose deps we're
            # expanding. The virt_atom._orig_atom attribute is used
            # by depgraph to map virt_atom back to the original atom.
            # We specifically exclude the original atom "x" from the
            # the expanded output here, since otherwise it could trigger
            # incorrect dep_zapdeps behavior (see bug #597752).
            mycheck[1].append(virt_atom)
            a.append(mycheck[1])
            if atom_graph is not None:
                virt_atom_node = (virt_atom, id(virt_atom))
                atom_graph.add(virt_atom_node, graph_parent)
                atom_graph.add(pkg, virt_atom_node)
                atom_graph.add((x, id(x)), graph_parent)

        if not a and mychoices:
            # Check for a virtual package.provided match.
            for y in mychoices:
                new_atom = Atom(x.replace(x.cp, y.cp, 1))
                if match_from_list(new_atom,
                                   pprovideddict.get(new_atom.cp, [])):
                    a.append(new_atom)
                    if atom_graph is not None:
                        atom_graph.add((new_atom, id(new_atom)), graph_parent)

        if not a:
            newsplit.append(x)
            if atom_graph is not None:
                atom_graph.add((x, id(x)), graph_parent)
        elif is_disjunction:
            newsplit.extend(a)
        elif len(a) == 1:
            newsplit.extend(a[0])
        else:
            newsplit.append(['||'] + a)

    # For consistency with related functions like use_reduce, always
    # normalize the result to have a top-level conjunction.
    if is_disjunction:
        newsplit = [newsplit]

    return newsplit
Ejemplo n.º 12
0
	def __call__(self, argv):
		"""
		@return: tuple of (stdout, stderr, returncode)
		"""

		# Python 3:
		# cmd, root, *args = argv
		cmd = argv[0]
		root = argv[1]
		args = argv[2:]

		warnings = []
		warnings_str = ''

		db = self.get_db()
		eapi = self.settings.get('EAPI')

		root = normalize_path(root or os.sep).rstrip(os.sep) + os.sep
		if root not in db:
			return ('', '%s: Invalid ROOT: %s\n' % (cmd, root), 3)

		portdb = db[root]["porttree"].dbapi
		vardb = db[root]["vartree"].dbapi

		if cmd in ('best_version', 'has_version'):
			allow_repo = eapi_has_repo_deps(eapi)
			try:
				atom = Atom(args[0], allow_repo=allow_repo)
			except InvalidAtom:
				return ('', '%s: Invalid atom: %s\n' % (cmd, args[0]), 2)

			try:
				atom = Atom(args[0], allow_repo=allow_repo, eapi=eapi)
			except InvalidAtom as e:
				warnings.append("QA Notice: %s: %s" % (cmd, e))

			use = self.settings.get('PORTAGE_BUILT_USE')
			if use is None:
				use = self.settings['PORTAGE_USE']

			use = frozenset(use.split())
			atom = atom.evaluate_conditionals(use)

		if warnings:
			warnings_str = self._elog('eqawarn', warnings)

		if cmd == 'has_version':
			if vardb.match(atom):
				returncode = 0
			else:
				returncode = 1
			return ('', warnings_str, returncode)
		elif cmd == 'best_version':
			m = best(vardb.match(atom))
			return ('%s\n' % m, warnings_str, 0)
		elif cmd in ('master_repositories', 'repository_path', 'available_eclasses', 'eclass_path', 'license_path'):
			repo = _repo_name_re.match(args[0])
			if repo is None:
				return ('', '%s: Invalid repository: %s\n' % (cmd, args[0]), 2)
			try:
				repo = portdb.repositories[args[0]]
			except KeyError:
				return ('', warnings_str, 1)

			if cmd == 'master_repositories':
				return ('%s\n' % ' '.join(x.name for x in repo.masters), warnings_str, 0)
			elif cmd == 'repository_path':
				return ('%s\n' % repo.location, warnings_str, 0)
			elif cmd == 'available_eclasses':
				return ('%s\n' % ' '.join(sorted(repo.eclass_db.eclasses)), warnings_str, 0)
			elif cmd == 'eclass_path':
				try:
					eclass = repo.eclass_db.eclasses[args[1]]
				except KeyError:
					return ('', warnings_str, 1)
				return ('%s\n' % eclass.location, warnings_str, 0)
			elif cmd == 'license_path':
				paths = reversed([os.path.join(x.location, 'licenses', args[1]) for x in list(repo.masters) + [repo]])
				for path in paths:
					if os.path.exists(path):
						return ('%s\n' % path, warnings_str, 0)
				return ('', warnings_str, 1)
		else:
			return ('', 'Invalid command: %s\n' % cmd, 3)
Ejemplo n.º 13
0
    def __call__(self, argv):
        """
        @return: tuple of (stdout, stderr, returncode)
        """

        # Python 3:
        # cmd, root, *args = argv
        cmd = argv[0]
        root = argv[1]
        args = argv[2:]

        warnings = []
        warnings_str = ""

        db = self.get_db()
        eapi = self.settings.get("EAPI")

        root = normalize_path(root or os.sep).rstrip(os.sep) + os.sep
        if root not in db:
            return ("", "%s: Invalid ROOT: %s\n" % (cmd, root), 3)

        portdb = db[root]["porttree"].dbapi
        vardb = db[root]["vartree"].dbapi

        if cmd in ("best_version", "has_version"):
            allow_repo = eapi_has_repo_deps(eapi)
            try:
                atom = Atom(args[0], allow_repo=allow_repo)
            except InvalidAtom:
                return ("", "%s: Invalid atom: %s\n" % (cmd, args[0]), 2)

            try:
                atom = Atom(args[0], allow_repo=allow_repo, eapi=eapi)
            except InvalidAtom as e:
                warnings.append("QA Notice: %s: %s" % (cmd, e))

            use = self.settings.get("PORTAGE_BUILT_USE")
            if use is None:
                use = self.settings["PORTAGE_USE"]

            use = frozenset(use.split())
            atom = atom.evaluate_conditionals(use)

        if warnings:
            warnings_str = self._elog("eqawarn", warnings)

        if cmd == "has_version":
            if vardb.match(atom):
                returncode = 0
            else:
                returncode = 1
            return ("", warnings_str, returncode)
        if cmd == "best_version":
            m = best(vardb.match(atom))
            return ("%s\n" % m, warnings_str, 0)
        if cmd in (
                "master_repositories",
                "repository_path",
                "available_eclasses",
                "eclass_path",
                "license_path",
        ):
            repo = _repo_name_re.match(args[0])
            if repo is None:
                return ("", "%s: Invalid repository: %s\n" % (cmd, args[0]), 2)
            try:
                repo = portdb.repositories[args[0]]
            except KeyError:
                return ("", warnings_str, 1)

            if cmd == "master_repositories":
                return (
                    "%s\n" % " ".join(x.name for x in repo.masters),
                    warnings_str,
                    0,
                )
            if cmd == "repository_path":
                return ("%s\n" % repo.location, warnings_str, 0)
            if cmd == "available_eclasses":
                return (
                    "%s\n" % " ".join(sorted(repo.eclass_db.eclasses)),
                    warnings_str,
                    0,
                )
            if cmd == "eclass_path":
                try:
                    eclass = repo.eclass_db.eclasses[args[1]]
                except KeyError:
                    return ("", warnings_str, 1)
                return ("%s\n" % eclass.location, warnings_str, 0)
            if cmd == "license_path":
                paths = reversed([
                    os.path.join(x.location, "licenses", args[1])
                    for x in list(repo.masters) + [repo]
                ])
                for path in paths:
                    if os.path.exists(path):
                        return ("%s\n" % path, warnings_str, 0)
                return ("", warnings_str, 1)
        return ("", "Invalid command: %s\n" % cmd, 3)
Ejemplo n.º 14
0
def _expand_new_virtuals(mysplit,
                         edebug,
                         mydbapi,
                         mysettings,
                         myroot="/",
                         trees=None,
                         use_mask=None,
                         use_force=None,
                         **kwargs):
    """
	In order to solve bug #141118, recursively expand new-style virtuals so
	as to collapse one or more levels of indirection, generating an expanded
	search space. In dep_zapdeps, new-style virtuals will be assigned
	zero cost regardless of whether or not they are currently installed. Virtual
	blockers are supported but only when the virtual expands to a single
	atom because it wouldn't necessarily make sense to block all the components
	of a compound virtual.  When more than one new-style virtual is matched,
	the matches are sorted from highest to lowest versions and the atom is
	expanded to || ( highest match ... lowest match )."""
    newsplit = []
    mytrees = trees[myroot]
    portdb = mytrees["porttree"].dbapi
    atom_graph = mytrees.get("atom_graph")
    parent = mytrees.get("parent")
    virt_parent = mytrees.get("virt_parent")
    graph_parent = None
    eapi = None
    if parent is not None:
        if virt_parent is not None:
            graph_parent = virt_parent
            eapi = virt_parent[0].metadata['EAPI']
        else:
            graph_parent = parent
            eapi = parent.metadata["EAPI"]
    repoman = not mysettings.local_config
    if kwargs["use_binaries"]:
        portdb = trees[myroot]["bintree"].dbapi
    myvirtuals = mysettings.getvirtuals()
    pprovideddict = mysettings.pprovideddict
    myuse = kwargs["myuse"]
    for x in mysplit:
        if x == "||":
            newsplit.append(x)
            continue
        elif isinstance(x, list):
            newsplit.append(
                _expand_new_virtuals(x,
                                     edebug,
                                     mydbapi,
                                     mysettings,
                                     myroot=myroot,
                                     trees=trees,
                                     use_mask=use_mask,
                                     use_force=use_force,
                                     **kwargs))
            continue

        if not isinstance(x, Atom):
            try:
                x = Atom(x)
            except InvalidAtom:
                if portage.dep._dep_check_strict:
                    raise ParseError(_("invalid atom: '%s'") % x)
                else:
                    # Only real Atom instances are allowed past this point.
                    continue
            else:
                if x.blocker and x.blocker.overlap.forbid and \
                 eapi in ("0", "1") and portage.dep._dep_check_strict:
                    raise ParseError(_("invalid atom: '%s'") % (x, ))
                if x.use and eapi in ("0", "1") and \
                 portage.dep._dep_check_strict:
                    raise ParseError(_("invalid atom: '%s'") % (x, ))

        if repoman and x.use and x.use.conditional:
            evaluated_atom = remove_slot(x)
            if x.slot:
                evaluated_atom += ":%s" % x.slot
            evaluated_atom += str(
                x.use._eval_qa_conditionals(use_mask, use_force))
            x = Atom(evaluated_atom)

        if not repoman and \
         myuse is not None and isinstance(x, Atom) and x.use:
            if x.use.conditional:
                x = x.evaluate_conditionals(myuse)

        mykey = x.cp
        if not mykey.startswith("virtual/"):
            newsplit.append(x)
            if atom_graph is not None:
                atom_graph.add(x, graph_parent)
            continue
        mychoices = myvirtuals.get(mykey, [])
        if x.blocker:
            # Virtual blockers are no longer expanded here since
            # the un-expanded virtual atom is more useful for
            # maintaining a cache of blocker atoms.
            newsplit.append(x)
            if atom_graph is not None:
                atom_graph.add(x, graph_parent)
            continue

        if repoman or not hasattr(portdb, 'match_pkgs'):
            if portdb.cp_list(x.cp):
                newsplit.append(x)
            else:
                # TODO: Add PROVIDE check for repoman.
                a = []
                for y in mychoices:
                    a.append(Atom(x.replace(x.cp, y.cp, 1)))
                if not a:
                    newsplit.append(x)
                elif len(a) == 1:
                    newsplit.append(a[0])
                else:
                    newsplit.append(['||'] + a)
            continue

        pkgs = []
        # Ignore USE deps here, since otherwise we might not
        # get any matches. Choices with correct USE settings
        # will be preferred in dep_zapdeps().
        matches = portdb.match_pkgs(x.without_use)
        # Use descending order to prefer higher versions.
        matches.reverse()
        for pkg in matches:
            # only use new-style matches
            if pkg.cp.startswith("virtual/"):
                pkgs.append(pkg)
        if not (pkgs or mychoices):
            # This one couldn't be expanded as a new-style virtual.  Old-style
            # virtuals have already been expanded by dep_virtual, so this one
            # is unavailable and dep_zapdeps will identify it as such.  The
            # atom is not eliminated here since it may still represent a
            # dependency that needs to be satisfied.
            newsplit.append(x)
            if atom_graph is not None:
                atom_graph.add(x, graph_parent)
            continue

        a = []
        for pkg in pkgs:
            virt_atom = '=' + pkg.cpv
            if x.use:
                virt_atom += str(x.use)
            virt_atom = Atom(virt_atom)
            # According to GLEP 37, RDEPEND is the only dependency
            # type that is valid for new-style virtuals. Repoman
            # should enforce this.
            depstring = pkg.metadata['RDEPEND']
            pkg_kwargs = kwargs.copy()
            pkg_kwargs["myuse"] = pkg.use.enabled
            if edebug:
                writemsg_level(_("Virtual Parent:      %s\n") \
                 % (pkg,), noiselevel=-1, level=logging.DEBUG)
                writemsg_level(_("Virtual Depstring:   %s\n") \
                 % (depstring,), noiselevel=-1, level=logging.DEBUG)

            # Set EAPI used for validation in dep_check() recursion.
            mytrees["virt_parent"] = (pkg, virt_atom)

            try:
                mycheck = dep_check(depstring,
                                    mydbapi,
                                    mysettings,
                                    myroot=myroot,
                                    trees=trees,
                                    **pkg_kwargs)
            finally:
                # Restore previous EAPI after recursion.
                if virt_parent is not None:
                    mytrees["virt_parent"] = virt_parent
                else:
                    del mytrees["virt_parent"]

            if not mycheck[0]:
                raise ParseError("%s: %s '%s'" % (y[0], mycheck[1], depstring))

            # pull in the new-style virtual
            mycheck[1].append(virt_atom)
            a.append(mycheck[1])
            if atom_graph is not None:
                atom_graph.add(virt_atom, graph_parent)
        # Plain old-style virtuals.  New-style virtuals are preferred.
        if not pkgs:
            for y in mychoices:
                new_atom = Atom(x.replace(x.cp, y.cp, 1))
                matches = portdb.match(new_atom)
                # portdb is an instance of depgraph._dep_check_composite_db, so
                # USE conditionals are already evaluated.
                if matches and mykey in \
                 portdb.aux_get(matches[-1], ['PROVIDE'])[0].split():
                    a.append(new_atom)
                    if atom_graph is not None:
                        atom_graph.add(new_atom, graph_parent)

        if not a and mychoices:
            # Check for a virtual package.provided match.
            for y in mychoices:
                new_atom = Atom(x.replace(x.cp, y.cp, 1))
                if match_from_list(new_atom,
                                   pprovideddict.get(new_atom.cp, [])):
                    a.append(new_atom)
                    if atom_graph is not None:
                        atom_graph.add(new_atom, graph_parent)

        if not a:
            newsplit.append(x)
            if atom_graph is not None:
                atom_graph.add(x, graph_parent)
        elif len(a) == 1:
            newsplit.append(a[0])
        else:
            newsplit.append(['||'] + a)

    return newsplit
Ejemplo n.º 15
0
    def __call__(self, argv):
        """
		@return: tuple of (stdout, stderr, returncode)
		"""

        # Python 3:
        # cmd, root, *args = argv
        cmd = argv[0]
        root = argv[1]
        args = argv[2:]

        warnings = []
        warnings_str = ""

        db = self.get_db()
        eapi = self.settings.get("EAPI")

        root = normalize_path(root).rstrip(os.path.sep) + os.path.sep
        if root not in db:
            return ("", "%s: Invalid ROOT: %s\n" % (cmd, root), 3)

        portdb = db[root]["porttree"].dbapi
        vardb = db[root]["vartree"].dbapi

        if cmd in ("best_version", "has_version"):
            allow_repo = eapi_has_repo_deps(eapi)
            try:
                atom = Atom(args[0], allow_repo=allow_repo)
            except InvalidAtom:
                return ("", "%s: Invalid atom: %s\n" % (cmd, args[0]), 2)

            try:
                atom = Atom(args[0], allow_repo=allow_repo, eapi=eapi)
            except InvalidAtom as e:
                warnings.append(_unicode_decode("QA Notice: %s: %s") % (cmd, e))

            use = self.settings.get("PORTAGE_BUILT_USE")
            if use is None:
                use = self.settings["PORTAGE_USE"]

            use = frozenset(use.split())
            atom = atom.evaluate_conditionals(use)

        if warnings:
            warnings_str = self._elog("eqawarn", warnings)

        if cmd == "has_version":
            if vardb.match(atom):
                returncode = 0
            else:
                returncode = 1
            return ("", warnings_str, returncode)
        elif cmd == "best_version":
            m = best(vardb.match(atom))
            return ("%s\n" % m, warnings_str, 0)
        elif cmd in ("master_repositories", "repository_path", "available_eclasses", "eclass_path", "license_path"):
            repo = _repo_name_re.match(args[0])
            if repo is None:
                return ("", "%s: Invalid repository: %s\n" % (cmd, args[0]), 2)
            try:
                repo = portdb.repositories[args[0]]
            except KeyError:
                return ("", warnings_str, 1)

            if cmd == "master_repositories":
                return ("%s\n" % " ".join(x.name for x in repo.masters), warnings_str, 0)
            elif cmd == "repository_path":
                return ("%s\n" % repo.location, warnings_str, 0)
            elif cmd == "available_eclasses":
                return ("%s\n" % " ".join(sorted(repo.eclass_db.eclasses)), warnings_str, 0)
            elif cmd == "eclass_path":
                try:
                    eclass = repo.eclass_db.eclasses[args[1]]
                except KeyError:
                    return ("", warnings_str, 1)
                return ("%s\n" % eclass.location, warnings_str, 0)
            elif cmd == "license_path":
                paths = reversed([os.path.join(x.location, "licenses", args[1]) for x in list(repo.masters) + [repo]])
                for path in paths:
                    if os.path.exists(path):
                        return ("%s\n" % path, warnings_str, 0)
                return ("", warnings_str, 1)
        else:
            return ("", "Invalid command: %s\n" % cmd, 3)