| # 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 |