Source code for univention.appcenter.actions.get

#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Univention App Center
#  univention-app module for getting app meta information
#
# Copyright 2015-2022 Univention GmbH
#
# https://www.univention.de/
#
# All rights reserved.
#
# The source code of this program is made available
# under the terms of the GNU Affero General Public License version 3
# (GNU AGPL V3) as published by the Free Software Foundation.
#
# Binary versions of this program provided by Univention to you as
# well as other copyrighted, protected or trademarked materials like
# Logos, graphics, fonts, specific documentations and configurations,
# cryptographic keys etc. are subject to a license agreement between
# you and Univention and not subject to the GNU AGPL V3.
#
# In the case you use this program under the terms of the GNU AGPL V3,
# the program is provided in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# <https://www.gnu.org/licenses/>.
#

from pipes import quote
import re
from argparse import Action
from fnmatch import translate

from six.moves.configparser import NoOptionError, NoSectionError

from univention.appcenter.app import CaseSensitiveConfigParser
from univention.appcenter.app_cache import Apps
from univention.appcenter.utils import shell_safe
from univention.appcenter.actions import UniventionAppAction, StoreAppAction
from univention.appcenter.ucr import ucr_get


[docs]class StoreKeysAction(Action): def __call__(self, parser, namespace, value, option_string=None): keys = [] for val in value: try: section, key = val.rsplit(':', 1) except ValueError: section, key = None, val keys.append((section, key)) setattr(namespace, self.dest, keys)
def _match(value, pattern): regex = re.compile(translate(pattern), re.I) return regex.match(value)
[docs]class Get(UniventionAppAction): '''Fetches meta information about the app.''' help = 'Query an app'
[docs] def setup_parser(self, parser): parser.add_argument('app', action=StoreAppAction, help='The ID of the App that shall be queried') parser.add_argument('--shell', action='store_true', help='Print the information so that it can be evaluated in shell scripts. Example: %(prog)s app Vendor UseShop -> vendor="Vendor Inc."\\nuse_shop="1"') parser.add_argument('--values-only', action='store_true', help='Only print the value of KEY, not KEY itself') parser.add_argument('keys', action=StoreKeysAction, metavar='KEY', nargs='+', help='The key of the meta information')
[docs] def main(self, args): for section, key, value in self.get_values(args.app, args.keys): if args.shell: if isinstance(value, list): value = ' '.join(value) if isinstance(value, bool): value = int(value) if value is None: value = '' value = str(value) if args.values_only: self.log(value) else: if section is not None: key = '%s__%s' % (section, key) self.log('%s=%s' % (shell_safe(key), quote(value))) else: if isinstance(value, list): value = ', '.join(value) if section is not None: key = '%s/%s' % (section, key) if args.values_only: self.log(value) else: self.log('%s: %s' % (key, value))
[docs] @classmethod def to_dict(cls, app): ret = app.attrs_dict() ret['logo_name'] = app.logo_name ret['logo_detail_page_name'] = app.logo_detail_page_name ret['license_description'] = app.license_description ret['thumbnails'] = app.get_thumbnail_urls() ret['is_installed'] = app.is_installed() ret['is_current'] = app.without_repository or ucr_get('repository/online/component/%s' % app.component_id) == 'enabled' ret['local_role'] = ucr_get('server/role') ret['is_master'] = ret['local_role'] == 'domaincontroller_master' ret['host_master'] = ucr_get('ldap/master') ret['is_ucs_component'] = app.is_ucs_component() ret.update(cls._candidate_dict(app)) return ret
@classmethod def _candidate_dict(cls, app): ret = {} if app.is_installed(): candidate = Apps().find_candidate(app) else: candidate = None if candidate: ret['update_available'] = True ret['candidate_docker'] = candidate.docker ret['candidate_version'] = candidate.version ret['candidate_component_id'] = candidate.component_id ret['candidate_readme_update'] = candidate.readme_update ret['candidate_readme_post_update'] = candidate.readme_post_update ret['candidate_needs_install_permissions'] = not candidate.install_permissions_exist() ret['candidate_install_permissions_message'] = candidate.install_permissions_message else: ret['update_available'] = False # TODO: ucr.is_true(app.ucr_upgrade_key); Bug#39916 ret['candidate_needs_install_permissions'] = not app.install_permissions_exist() ret['candidate_install_permissions_message'] = app.install_permissions_message return ret
[docs] @classmethod def raw_value(cls, app, section, option): config_parser = CaseSensitiveConfigParser() with open(app.get_ini_file(), 'r') as f: config_parser.readfp(f) try: return config_parser.get(section, option) except (NoSectionError, NoOptionError): return None
[docs] def get_values(self, app, keys, warn=True): config_parser = CaseSensitiveConfigParser() with open(app.get_ini_file(), 'r') as f: config_parser.readfp(f) for section, key in keys: search_section = section or 'Application' found = False for config_section in config_parser.sections(): if _match(config_section, search_section): for name, value in config_parser.items(config_section): if _match(name, key): for attr in app._attrs: ini_attr_name = attr.name.replace('_', '') if ini_attr_name == name.lower(): value = attr.get(value, app.get_ini_file()) found = True result_section = section and config_section yield result_section, name, value if not found: try: value = getattr(app, key) if callable(value): raise AttributeError(key) except AttributeError: if warn: self.warn('Could not find option %s:%s' % (search_section, key)) else: yield None, key, value