# Copyright 2010-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 from __future__ import unicode_literals import io import portage from portage import os from portage.dep import Atom, _repo_name_re from portage.eapi import eapi_has_repo_deps from portage.elog import messages as elog_messages from portage.exception import InvalidAtom from portage.package.ebuild._ipc.IpcCommand import IpcCommand from portage.util import normalize_path from portage.versions import best class QueryCommand(IpcCommand): __slots__ = ('phase', 'settings',) _db = None @classmethod def get_db(cls): if cls._db is not None: return cls._db return portage.db def __init__(self, settings, phase): IpcCommand.__init__(self) self.settings = settings self.phase = phase 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("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) def _elog(self, elog_funcname, lines): """ This returns a string, to be returned via ipc and displayed at the appropriate place in the build output. We wouldn't want to open the log here since it is already opened by AbstractEbuildProcess and we don't want to corrupt it, especially if it is being written with compression. """ out = io.StringIO() phase = self.phase elog_func = getattr(elog_messages, elog_funcname) global_havecolor = portage.output.havecolor try: portage.output.havecolor = \ self.settings.get('NOCOLOR', 'false').lower() in ('no', 'false') for line in lines: elog_func(line, phase=phase, key=self.settings.mycpv, out=out) finally: portage.output.havecolor = global_havecolor msg = out.getvalue() return msg