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/package-installs-v2
#!/usr/bin/env python3

# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# 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 locale
import os
import subprocess
import sys

from collections import defaultdict


# run a command, return output
#  if follow is set, output will be echoed to stdout
def process_output(cmdline, follow=False):
    proc = subprocess.Popen(cmdline, stdout=subprocess.PIPE,
                            stderr=subprocess.STDOUT)
    if follow:
        print("Running command: %s" % cmdline)
        out = ""
        with proc.stdout:
            for line in iter(proc.stdout.readline, b''):
                line = line.decode(encoding=locale.getpreferredencoding(False),
                                   errors='backslashreplace')
                out += line
                print("> %s" % line, end="")
        proc.wait()
        print("returncode: %d" % proc.returncode)
    else:
        out = proc.communicate()[0].decode(errors='backslashreplace')

    if proc.returncode:
        e = subprocess.CalledProcessError(proc.returncode, cmdline)
        e.output = out
        raise e

    return out


def main():
    dbg_level = int(os.getenv('DIB_DEBUG_TRACE', '0'))

    parser = argparse.ArgumentParser(
        description="Install or uninstall packages for a specific phase based"
                    " on package-installs files.")
    parser.add_argument('--phase', required=True,
                        help="Install phase to filter on. Valid options are"
                             " 'install.d' or pre-install.d")
    parser.add_argument('--uninstall', action="store_true",
                        help="Only show packages to uninstall. By default only"
                             " packages to install are shown")
    parser.add_argument('-n', '--noop', action="store_true",
                        help="Don't actually install, just print the command")
    parser.add_argument('infile', help="File to process")
    args = parser.parse_args()

    packages = json.load(open(args.infile))
    if args.uninstall:
        install = "uninstall"
    else:
        install = "install"

    pkgs = list()
    if args.phase in packages and install in packages[args.phase]:
        install_packages = packages[args.phase][install]
    else:
        print("Nothing to %s" % install)
        sys.exit(0)

    # sort the list by element, this way we only do one pkg-map call
    # per element
    by_element = defaultdict(list)
    for (pkg, element) in install_packages:
        by_element[element].append(pkg)

    for element, packages in by_element.items():
        print("Map %s for %s: %s" % (install, element, ', '.join(packages)))

        # Only trace pkg-map for higher levels of debugging.  Note
        # that pkg-map debug output comes out on stderr, which is
        # captured into the output by process_output.  We filter by
        # "prefix" so we don't think the debug lines are packages!
        pkg_map_args = ['pkg-map', '--prefix', '-',
                        '--missing-ok', '--element', element]
        if dbg_level > 1:
            pkg_map_args.append('--debug')
        pkg_map_args.extend(packages)

        try:
            follow = True if dbg_level > 1 else False
            map_output = process_output(pkg_map_args, follow=follow)
            map_output = map_output.strip().split('\n')
            map_output = [m[1:] for m in map_output if m.startswith('-')]
            pkgs.extend(map_output)
        except subprocess.CalledProcessError as e:
            if e.returncode == 1:
                if args.noop:
                    pkgs.append(pkg)
                    continue
                else:
                    print("pkg-map failed")
                    sys.exit(1)
            elif e.returncode == 2:
                pkgs.append(pkg)
                continue

    install_args = ["install-packages"]
    if args.uninstall:
        install_args.append("-e")
    install_args.extend(list(set(pkgs)))

    if args.noop:
        print(" ".join(install_args))
    else:
        try:
            process_output(install_args, follow=True)
        except subprocess.CalledProcessError as e:
            print("install-packages failed with returncode %d" % e.returncode)
            sys.exit(1)


if __name__ == '__main__':
    main()

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