HEX
Server: Apache
System: Linux pdx1-shared-a1-38 6.6.104-grsec-jammy+ #3 SMP Tue Sep 16 00:28:11 UTC 2025 x86_64
User: mmickelson (3396398)
PHP: 8.1.31
Disabled: NONE
Upload Files
File: //usr/local/bin/pkg-map
#!/usr/bin/env python3

# Copyright 2014 Red Hat Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import argparse
import json
import logging
import os
import sys


log = logging.getLogger()


def os_family(distro):
    family = None
    if distro in ['fedora', 'rhel', 'rhel7', 'centos', 'centos7', 'openeuler',
                    'rocky']:
        family = 'redhat'
    elif distro in ['debian', 'ubuntu']:
        family = 'debian'
    elif distro == 'opensuse':
        family = 'suse'
    elif distro == 'gentoo':
        family = 'gentoo'

    return family


def os_major_release(release):
    if release in ['8-stream']:
        return '8'
    return release


def main():
    parser = argparse.ArgumentParser(
        description="Translate package name to distro specific name."
                    " Exits with 1 if error is encountered, 2 if no pkg-map"
                    " file is found. Otherwise exits with 0.")
    parser.add_argument('--element', default='',
                        help='The element (namespace) to use for translation.')
    parser.add_argument('--pkg-map', default='',
                        help='Path to specific pkg-map file.  '
                        '(Useful for testing)')
    parser.add_argument('--distro', default=os.environ.get('DISTRO_NAME'),
                        help='The distro name to use for translation.'
                        ' Defaults to DISTRO_NAME')
    parser.add_argument('--release', default=os.environ.get('DIB_RELEASE'),
                        help='A more specfic name for distribution release')
    parser.add_argument('--missing-ok', action="store_true",
                        help='Do not consider missing mappings an error.'
                             ' Causes packages where no mapping is set to be'
                             ' printed.')
    # This tool has traditionally output status and debug messages on
    # stderr.  The problem is if a caller has stderr > stdout then
    # actual output gets messed in with the logs.  This allows callers
    # to disambiguate actual output by specifying a unique prefix.
    parser.add_argument('--prefix', default='',
                        help='Output mapped packages with this prefix')
    parser.add_argument('--debug', dest='debug', action="store_true",
                        help="Enable debugging output")

    args, extra = parser.parse_known_args()

    # Logs have traditionally gone to stderr with this tool.  Maintain
    # compatibility
    level = logging.DEBUG if args.debug else logging.INFO
    logging.basicConfig(stream=sys.stderr, level=level)

    if not args.element and not args.pkg_map:
        log.error('Please specify an --element argument.')
        sys.exit(1)

    if args.element and args.pkg_map:
        log.error('Specify either --element or --pkg-map')
        sys.exit(1)

    if not args.distro:
        log.error('Please specify a --distro argument or set DISTRO_NAME.')
        sys.exit(1)

    if args.pkg_map:
        # specifying the pkg-map by hand is just for manual testing
        element = "<%s>" % args.pkg_map
        map_file = args.pkg_map
    else:
        element = args.element
        map_file = '/usr/share/pkg-map/%s' % element

    log.info("Mapping for %s : %s" % (element, ' '.join(extra)))

    if not os.path.exists(map_file):
        if args.missing_ok:
            log.info("No package map for %s, done" % element)
            for name in extra:
                print('%s%s' % (args.prefix, name))
            sys.exit(0)
        else:
            log.error('Required pkg-map for %s element does not exist.'
                      % args.element)
            sys.exit(2)

    with open(map_file) as fd:
        try:
            package_names = json.loads(fd.read())
            # log.debug(pprint.pformat(package_names))
        except ValueError:
            log.error('Unable to parse %s' % map_file)
            raise

    # Parse mapping data in this form using release/distro/family/default
    # Most specific takes priority; order is
    #  - release
    #  - distro
    #  - family
    #  - default
    # An empty package list can be provided.
    #
    # Example for Nova and Glance (using fictitious name for Fedora and SUSE
    # and package mapping for SUSE family)
    # {
    #   "release": {
    #     "fedora" : {
    #       "23" : {
    #         "nova_package": "openstack-compute-foo"
    #       }
    #     }
    #   }
    #   "distro": {
    #     "fedora": {
    #       "nova_package": "openstack-compute",
    #       "glance_package": "openstack-image"
    #     }
    #   },
    #   "family": {
    #     "redhat": {
    #       "nova_package": "openstack-nova",
    #       "glance_package": "openstack-glance"
    #     },
    #     "suse": {
    #       "nova_package": ""
    #    }
    #   },
    #   "default": {
    #     "nova_package": "nova",
    #     "glance_package": "glance"
    #   }
    # }
    name_map = package_names.get('default', {})
    if 'family' in package_names:
        family_map = package_names['family'].get(os_family(args.distro))
        if family_map:
            name_map.update(family_map)
    if 'distro' in package_names:
        distro_map = package_names['distro'].get(args.distro)
        if distro_map:
            name_map.update(distro_map)
    if 'release' in package_names:
        try:
            # release is a sub-concept of distro
            release = os_major_release(args.release)
            release_map = package_names['release'][args.distro][release]
            name_map.update(release_map)
        except KeyError:
            pass

    # log.debug(pprint.pformat(name_map))

    for name in extra:
        pkg_name = name_map.get(name)
        if pkg_name:
            log.debug("map %s -> %s" % (name, pkg_name))
            print('%s%s' % (args.prefix, pkg_name))
        elif name in name_map:
            log.debug("map %s -> <skip>" % (name))
            continue
        else:
            if args.missing_ok:
                log.debug("pass -> %s" % (name))
                print('%s%s' % (args.prefix, name))
            else:
                log.error("%s has no valid mapping for package %s" %
                          (element, name))
                sys.exit(1)

    sys.exit(0)


if __name__ == '__main__':
    main()

# Tell emacs to use python-mode
# Local variables:
# mode: python
# End: