#!/usr/libexec/platform-python
# Script to check for known gotchas that occur between
# major versions of htcondor. This script will only check
# for gotchas to the next version.

# Imports Always needed
import os
import sys
import re
import subprocess
import textwrap
import argparse
from enum import Enum
from typing import List

# Temporary needed imports (for a check)
# End imports

try:
    import htcondor2 as htcondor
    import classad2 as classad
except ImportError:
    print(
        textwrap.dedent(
            """
            Failed to find HTCondor Python bindings.
            Please check your current Python environment or install the bindings if needed:
            https://htcondor.readthedocs.io/en/latest/apis/python-bindings/install.html
            """
        ),
        file=sys.stderr,
    )
    sys.exit(1)


class Debug(Enum):
    WARNING = 0
    BASE = 1
    DETAILED = 2
    DEBUGGING = 3
    MAX = 4

    def __gt__(self, other):
        if self.__class__ is other.__class__:
            return self.value > other.value
        return NotImplemented

    def __ge__(self, other):
        if self.__class__ is other.__class__:
            return self.value >= other.value
        return NotImplemented


class System(Enum):
    STANDARD = 0
    CE = 1
    BOTH = 2


MAX_TAG_LEN = 10


class Check:
    def __init__(self, **kwargs):
        self.version = kwargs["version"]
        self.test = kwargs["test"]
        self.name = kwargs["name"]
        self.tag = kwargs["tag"]
        self.synopsis = kwargs.get("synopsis", "No check synopsis provided.")
        self.desc = kwargs.get("desc", "No detailed check description provided.")
        self.is_warning = kwargs.get("warning", False)
        self.daemons = kwargs.get("daemons", [])
        self.needs_root = kwargs.get("root", False)
        self.system = kwargs.get("system", System.BOTH)

        assert len(self.tag) <= MAX_TAG_LEN and len(self.tag) > 0
        assert type(self.version) is tuple
        assert type(self.daemons) is list

        self.desc = textwrap.dedent(self.desc)
    def __lt__(self, other):
        return self.version > other.version


NEXT_MAJOR_VERSION = (26, 0, 0)
CURRENT_VERSION = tuple(int(x) for x in htcondor.param["CONDOR_VERSION"].split("."))
IS_WINDOWS = os.name == "nt"
VERBOSITY = Debug.BASE


def format_print(msg, offset=0, newline=False, err=False, debug=Debug.BASE):
    """Custom print function to help with output spacing"""
    if debug > VERBOSITY:
        return

    f = sys.stderr if err else sys.stdout
    if newline:
        print(file=f)

    for line in textwrap.dedent(msg).split("\n"):
        if line.strip() == "":
            continue
        if "$(<EMPTY_LINE>)" in line:
            print(file=f)
            continue
        line_offset = offset + len(line)
        print(f"{line:>{line_offset}s}", file=f)


def make_version_str(version):
    """Convert Version Tuple into period seperated string"""
    return ".".join([f"{n}" for n in version])


def iter_list(l: list):
    """Recursively yield each item in a list of lists"""
    for item in l:
        if type(item) is list:
            yield from iter_list(item)
        else:
            yield item


SPLIT_RE = re.compile(r"[\s,]+")
def split_config_line(option: str, default: str = "") -> List[str]:
    """Split a config line on whitespace and commas"""
    return list(filter(None, SPLIT_RE.split(htcondor.param.get(option, default))))


# ===============================Incompatibility Check Functions===============================
def warn_multi_q_deprecation(*args, **kwargs):
    """Warn about multi-queue statement deprecation"""
    format_print(
        """
        Warning:
            The use of multiple queue statements in a single submit
            description file is now deprecated. This functionality
            will be removed during the lifetime of the V25 feature
            series.
        """,
        offset=4,
        newline=True,
        debug=Debug.WARNING,
    )

def warn_python_api_v2(*args, **kwargs):
    """Warn about removal of V1 Python API"""
    format_print(
        """
        Warning:
            The original Python API is no longer supported.  The `htcondor`
            and `classad` modules have been removed from HTCondor 25, and
            replaced with the `htcondor2` and `classad2` modules.
        $(<EMPTY_LINE>)
            The modules are almost entirely compatible, but scripts using
            the original API will not work until switched to the new API;
            see the following URL for details.
        $(<EMPTY_LINE>)
            https://htcondor.readthedocs.io/en/latest/apis/python-bindings/api/version2/migration-guide.html
        """,
        offset=4,
        newline=True,
        debug=Debug.WARNING,
    )


def warn_new_dag_file_parser(*args, **kwargs):
    """Warn about removal of old DAG file parser"""
    format_print(
        """
        Warning:
            DAGMan now utilizes a new DAGMan file parser for reading DAG
            files. The old parser is deprecated and will be removed during
            the HTCondor V26 feature series.
        """,
        offset=4,
        newline=True,
        debug=Debug.WARNING,
    )

    if htcondor.param.get("DAGMAN_USE_OLD_FILE_PARSER", False):
        format_print(
            """This host is configured to use the old DAG file parser.""",
            offset=4,
            newline=True,
            debug=Debug.WARNING,
        )


def warn_dagman_full_rescue_file(*args, **kwargs):
    """Warn about removal of full rescue files in DAGMan"""
    format_print(
        """
        Warning:
            DAGMan now no longer supports 'Full Rescue Files' specified via
            `DAGMAN_WRITE_PARTIAL_RESCUE = False` in the configuration.
        """,
        offset=4,
        newline=True,
        debug=Debug.WARNING,
    )

    if not htcondor.param.get("DAGMAN_WRITE_PARTIAL_RESCUE", True):
        format_print(
            """This host is configured to have DAGMan write full rescue files""",
            offset=4,
            newline=True,
            debug=Debug.WARNING,
        )


def warn_dagman_admin_throttle_limiting(*args, **kwargs):
    """Warn about DAGMan throttle limiting from root configuration"""
    format_print(
        """
        Warning:
            DAGMan's configurable throttles set by the user are now limited
            to the values set in the root configuration. This can be disabled
            by setting `DAGMAN_DISABLE_ADMIN_THROTTLE_LIMITING = False` in
            your configuration.
        """,
        offset=4,
        newline=True,
        debug=Debug.WARNING,
    )

    THROTTLES = {
        "DAGMAN_MAX_JOBS_IDLE": 1000,
        "DAGMAN_MAX_JOBS_SUBMITTED": 0,
        "DAGMAN_MAX_PRE_SCRIPTS": 20,
        "DAGMAN_MAX_HOLD_SCRIPTS": 20,
        "DAGMAN_MAX_POST_SCRIPTS": 20,
        "DAGMAN_MAX_SUBMITS_PER_INTERVAL": 100,
    }

    warn = {}
    for key, default in THROTTLES.items():
        configed = htcondor.param.get(key, default)
        if configed != default and configed != 0 and (default == 0 or configed < default):
            warn[key] = configed

    if len(warn) > 0:
        format_print(
            """
            The following DAGMan throttle(s) have been modified smaller the
            default sizes thus limiting users more:
            """,
            offset=4,
            newline=True
        )

        for option, val in warn.items():
            format_print(
                f"""- {option}: {val}""",
                offset=8,
            )


def warn_condor_run_getenv_true(*args, **kwargs):
    """Warn about condor_run no longer setting `getenv = true`"""
    format_print(
        """
        Warning:
            condor_run no longer sets `getenv = true` within the submitted
            job. This will result in the job no longer having the entire
            environment from which user executed the command. To restore
            this behavior the user will have to provide the new `-getenv`
            option.
        """,
        offset=4,
        newline=True,
        debug=Debug.WARNING,
    )


# ---------------------------------------------------------------------------------------------
def check_job_router_syntax(*args, **kwargs):
    """Check for old job router configuration syntax."""
    deprecated_knobs = ["DEFAULTS", "ENTRIES", "ENTRIES_CMD", "ENTRIES_FILE"]
    found_knobs = []

    for knob in deprecated_knobs:
        full_name = "JOB_ROUTER_" + knob
        if full_name in htcondor.param:
            found_knobs.append(full_name)

    if len(found_knobs) > 0:
        format_print(
            """
            Warning:
                The following configuration macro(s):
            """,
            offset=4,
            newline=True,
            debug=Debug.WARNING,
        )
        for knob in found_knobs:
            format_print(f"- {knob}", offset=12, debug=Debug.WARNING)
        format_print(
            """
            Are no longer supported due to use of old syntax.
            The new configuration syntax for the job router is defined
            using JOB_ROUTER_ROUTE_NAMES and JOB_ROUTER_ROUTE_<name>.
            For more information visit:
                https://htcondor.readthedocs.io/en/latest/grid-computing/job-router.html#the-htcondor-job-router
            For assistance converting from old to new syntax use:
                condor_transfrom_ads -help convert
            """,
            offset=8,
            debug=Debug.WARNING,
        )
        return False
    return True


def check_job_transform_old_syntax(*args, **kwargs):
    """Check for obsolete syntax in schedd job transforms"""
    transforms = htcondor.param.get("JOB_TRANSFORM_NAMES")
    if transforms is not None:
        bad_syntax_xforms = []
        for name in transforms.replace(" ", ",").split(","):
            name = name.strip()
            xform = htcondor.param.get(f"JOB_TRANSFORM_{name}")
            if xform is not None:
                if xform.strip().startswith("["):
                    bad_syntax_xforms.append(f"JOB_TRANSFORM_{name}")

        l = len(bad_syntax_xforms)
        if l != 0:
            s = "s" if l > 1 else ""
            format_print(
                f"""
                Found {l} job transform{s} using obsolete syntax that is no longer
                supported. Please convert the following transforms to use the
                proper syntax:
                """,
                offset=4,
                newline=True,
            )
            for xform in bad_syntax_xforms:
                format_print(f"- {xform}", offset=8)
            format_print(
                """
                $(<EMPTY_LINE>)
                Proper Syntax Documentation:
                https://htcondor.readthedocs.io/en/latest/admin-manual/ap-policy-configuration.html#schedd-job-transforms
                """,
                offset=4
            )
            return False

    return True


def check_credmon_disallowed_characters(*args, **kwargs):
    """Check configured token provider names are valid"""
    CONFIG_OPTIONS = [
        "LOCAL_CREDMON_PROVIDER_NAMES",
        "LOCAL_CREDMON_PROVIDER_NAME",
        "OAUTH2_CREDMON_PROVIDER_NAMES",
        "CLIENT_CREDMON_PROVIDER_NAMES",
        "VAULT_CREDMON_PROVIDER_NAMES",
    ]

    has_invalid = False
    invalid = { option: [] for option in CONFIG_OPTIONS }

    regex = re.compile(r"^[a-zA-Z0-9-]+$")

    for option in CONFIG_OPTIONS:
        providers = split_config_line(option)
        for name in providers:
            if name != "*" and not regex.match(name):
                has_invalid = True
                invalid[option].append(name)

    if has_invalid:
        format_print(
            """
            Unless CREDMON_ALLOW_SPECIAL_CHAR_NAMES is set to True,
            the following token provider names are invalid due to use of
            non-alphanumeric/hyphen characters:
            """,
            offset=4,
            newline=True,
        )

        for option, providers in invalid.items():
            if len(providers) == 0:
                continue

            names = ", ".join(providers)
            format_print(
                f"""- {option}: {names}""",
                offset=8,
            )

        if not htcondor.param.get("CREDMON_ALLOW_SPECIAL_CHAR_NAMES", False):
            format_print(
                """
                Note:
                    Underscores are considered invalid to work correctly with
                    token handles. If handles are in use replace underscores
                    with hyphens. Otherwise, if handles are not being used then
                    set `CREDMON_ALLOW_SPECIAL_CHAR_NAMES = True` in the configuration.
                """,
                offset=4,
                newline=True,
            )
        return False

    return True

def check_for_unsupported_platforms(*args, **kwargs):
    """Check for platforms no longer supported: Debian-12, Ubuntu-22, & openSUSE-15"""
    # Note: not using platform.freedesktop_os_release() due to python 3.10 dependency
    if sys.platform == "linux":
        got_details = False
        for path in ["/etc/os-release", "/usr/lib/os-release"]:
            try:
                release = None
                version = None

                with open(path, "r") as f:
                    for line in f:
                        key, val = line.strip().split("=", 1)
                        val = val.strip('"')

                        if key == "ID":
                            release = val.strip().lower()
                        elif key == "VERSION_ID":
                            version = val.strip().lower()
                            if "." in version:
                                version = version.split(".")[0]

                        if release is not None and version is not None:
                            got_details = True
                            break

                UNSUPPORTED = {
                    "debian": "12",
                    "ubuntu": "22",
                    "opensuse-leap": "15",
                }

                if release in UNSUPPORTED and UNSUPPORTED[release] == version:
                    format_print(
                        f"""
                        HTCondor V26 does not support this platform: {release}-{version}.
                        """,
                        offset=4,
                        newline=True,
                    )
                    return False

                break

            except Exception as e:
                format_print(
                    f"""ERROR: Failed to read release information from {path}: {e}""",
                    offset=4,
                    debug=Debug.DETAILED,
                )

        if not got_details:
            format_print(
                """Warning: Failed to locate platform information for unsupported OS check""",
                offset=4,
                newline=True,
                debug=Debug.WARNING,
            )
            return False

    return True


# =============================================================================================
INCOMPATIBILITY_CHECKS = [
    Check(
        test=warn_multi_q_deprecation,
        name="Multiple Queue Statment Deprecation",
        tag="MULTI-Q",
        synopsis="The use of multiple queue statements in one submit file is deprecated",
        version=(25, 14, 0),
        daemons=["SCHEDD"],
        warning=True,
    ),
    Check(
        test=check_job_router_syntax,
        name="Old Job Router Syntax",
        tag="OLD-JRC",
        synopsis="Old Job Router Configuration Syntax has been removed",
        version=(24, 10, 2),
        daemons=["JOB_ROUTER"],
    ),
    Check(
        test=check_job_transform_old_syntax,
        name="Obsolete Syntax For Schedd Job Transforms",
        tag="JOB-XFORM",
        synopsis="""
                 This check will verify Schedd job transforms are not
                 using obsolete configuration syntax. This syntax is
                 the same as the old job router syntax.
                 """,
        version=(25, 8, 0),
        daemons=["SCHEDD"]
    ),
    Check(
        test=warn_python_api_v2,
        name="Python API Deprecation",
        tag="PY-API",
        synopsis="HTCondor Python API is no longer available",
        version=(25, 0, 0),
    ),
    Check(
        test=warn_new_dag_file_parser,
        name="New DAG File Parser",
        tag="DAG-PARSER",
        synopsis="The old DAG file parser in DAGMan is officially deprecated",
        daemons=["SCHEDD"],
        version=(25, 5, 0),
        warning=True,
    ),
    Check(
        test=warn_condor_run_getenv_true,
        name="condor_run Environment Change",
        tag="CONDOR-RUN",
        synopsis="condor_run no longer sets 'getenv = true'",
        daemons=["SCHEDD"],
        version=(25, 8 , 0),
        warning=True,
    ),
    Check(
        test=warn_dagman_full_rescue_file,
        name="DAGMan Full Rescue Files",
        tag="DAG-RESCUE",
        synopsis="DAGMan no longer supports full rescue files",
        daemons=["SCHEDD"],
        version=(25, 8 ,0),
        warning=True,
    ),
    Check(
        test=warn_dagman_admin_throttle_limiting,
        name="Admin Limiting of DAGMan Throttles",
        tag="THROTTLES",
        synopsis="DAGMan throttles are now limited to the value in the root configuration",
        daemons=["SCHEDD"],
        version=(25, 10, 0),
        warning=True,
    ),
    Check(
        test=check_credmon_disallowed_characters,
        name="Disallowed CREDMon Characters",
        tag="CREDMON",
        synopsis="""
                 Check for use of underscores and special characters
                 in token provider names for use in tandem with token
                 handles.
                 """,
        version=(25, 13, 0),
    ),
    Check(
        test=check_for_unsupported_platforms,
        name="Unsupported Platforms",
        tag="OS-SUPPORT",
        synopsis="Debian-12, Ubuntu-22, & openSUSE-15 are no longer supported",
        version=(26, 0, 0),
    )
]

# Sort checks by version
INCOMPATIBILITY_CHECKS = sorted(INCOMPATIBILITY_CHECKS)

def list_tags():
    """Function to list all available check TAGs for filtering purposes"""
    format_print(
        """
        Incompatibility Check Tags:
               TAGS   |  Check
            ====================
        """,
        newline=True,
    )
    for check in INCOMPATIBILITY_CHECKS:
        format_print(f"{check.tag.upper():<{MAX_TAG_LEN}}| '{check.name}'", offset=4)


def list_checks(is_ce, ignore_list, only_list):
    format_print(
        f"""
        Incompatibility Checks for upgrading to HTCondor V{NEXT_MAJOR_VERSION[0]}:
            (For detailed descriptions use -v/--verbose)
        """,
        newline=True,
    )

    i = 0
    total = len(INCOMPATIBILITY_CHECKS)
    cnt_fmt = len(str(total))
    pad_len = (2 * cnt_fmt) + 4

    for check in INCOMPATIBILITY_CHECKS:
        i += 1
        if check.tag.upper() in ignore_list:
            continue

        if len(only_list) > 0:
            check_tag = True
            if "WARNINGS" in only_list and check.is_warning:
                check_tag = False
            if check_tag and check.tag.upper() not in only_list:
                continue

        if is_ce and check.system == System.STANDARD:
            continue
        elif not is_ce and check.system == System.CE:
            continue

        if IS_WINDOWS and check.needs_root:
            continue

        root = "Requires ROOT" if check.needs_root else ""
        ver = make_version_str(check.version)
        padding = " " * pad_len

        format_print(
            f"""
            ({i:>{cnt_fmt}}/{total}) [{check.tag:<{MAX_TAG_LEN}s}] '{check.name}'
            {padding}{root}
            {padding}Version : V{ver}
            {padding}Synopsis: {check.synopsis}
            """,
            offset=4,
            newline=(i == 1),
        )

        format_print(
            check.desc, offset=(4 + pad_len), newline=True, debug=Debug.DETAILED
        )
        format_print("", newline=True, debug=Debug.DETAILED)


def run_checks(args, ignore_list, only_list, daemons):
    """Function that runs all checks make it through filtering"""
    num_failed_checks = 0
    num_checks_ran = 0

    for check in INCOMPATIBILITY_CHECKS:
        if check.tag.upper() in ignore_list:
            format_print(f"Skipping {check.tag}: Specified in ignore list", newline=True, debug=Debug.DEBUGGING)
            continue

        if len(only_list) > 0:
            check_tag = True
            if "WARNINGS" in only_list and check.is_warning:
                check_tag = False
            if check_tag and check.tag.upper() not in only_list:
                format_print(f"Skipping {check.tag}: Not specified in only list", newline=True, debug=Debug.DEBUGGING)
                continue

        if args.ce and check.system == System.STANDARD:
            format_print(f"Skipping {check.tag}: Check only applies to standard installations", newline=True, debug=Debug.DEBUGGING)
            continue
        elif not args.ce and check.system == System.CE:
            format_print(f"Skipping {check.tag}: Check only applies to CE installations", newline=True, debug=Debug.DEBUGGING)
            continue

        if IS_WINDOWS and check.needs_root:
            format_print(f"Skipping {check.tag}: Linux root check", newline=True, debug=Debug.DEBUGGING)
            continue

        if check.needs_root and os.geteuid() != 0:
            format_print(
                f"Warning: Skipping check '{check.name}' because it requires root.",
            )
            continue

        if not args.all and check.version <= CURRENT_VERSION:
            format_print(f"Skipping {check.tag}: Check applies for versions older than current installation", newline=True, debug=Debug.DEBUGGING)
            continue

        if args.target_version is not None and check.version > args.target_version:
            format_print(f"Skipping {check.tag}: Check is for version newer than specified target version", newline=True, debug=Debug.DEBUGGING)
            continue

        if not args.warnings and check.is_warning:
            format_print(f"Skipping {check.tag}: Ignoring warnings", newline=True, debug=Debug.DEBUGGING)
            continue

        missing_daemon = False
        for daemon in check.daemons:
            if daemon.upper() not in daemons:
                missing_daemon = True
                format_print(f"Skipping {check.tag}: Required {daemon} not specified in daemon list", newline=True, debug=Debug.DEBUGGING)
                break
        if missing_daemon:
            continue

        num_checks_ran += 1

        format_print(
            f"Checking {check.name} [{check.tag}]:", newline=True, debug=Debug.DETAILED
        )

        if not check.test(args):
            num_failed_checks += 1
            format_print(f"Check {check.name} [{check.tag}] failed", offset=8, debug=Debug.DETAILED)
        else:
            format_print("No issue found with check", offset=8, debug=Debug.DETAILED)

    return (num_failed_checks, num_checks_ran)


class NegateAction(argparse.Action):
    def __call__(self, parser, args, values, option_string=None):
        setattr(args, self.dest, option_string.strip("-").startswith("no") != True)


class SpecifyVersionAction(argparse.Action):
    def __call__(self, parser, args, values, option_string=None):
        if not isinstance(values, str):
            parser.error("Invalid argparse value (expects string)")

        try:
            major, minor, patch = values.split(".")
            major = int(major)
            minor = int(minor)
            patch = int(patch)
        except Exception as e:
            parser.error(f"Invalid version string ({values}) provided: {e}")

        setattr(args, self.dest, (major, minor, patch))

def parse_args(has_extend_action: bool):
    """Function to parse tool command line arguments"""

    list_action = "extend" if has_extend_action else "append"

    parser = argparse.ArgumentParser(
        prog="condor_upgrade_check",
        description=textwrap.dedent(
            """
            Tool to help check for known incompatabilites with a current
            HTCondor install when upgrading to a new major version.

            This should be ran on a host with HTCondor installed prior
            to upgrading to new major version (V23 -> V24) to check current
            installation for potential issues that may occur during an
            upgrade.

            Examples:
                condor_upgrade_check
                condor_upgrade_check --tags
                condor_upgrade_check --dump
                condor_upgrade_check -i BAR -vv
                condor_upgrade_check -ce --only FOO BAR BAZ --no-warnings
            """
        ),
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )

    parser.add_argument(
        "-ce",
        "--ce",
        "-CE",
        "--CE",
        dest="ce",
        action="store_true",
        help="Do checks for HTCondor-CE environment.",
    )

    parser.add_argument(
        "-a",
        "--all",
        action="store_true",
        help="Run all available checks including ones for issues introduced in versions older than the installed system.",
    )

    parser.add_argument(
        "-i",
        "--ignore",
        nargs="+",
        action=list_action,
        metavar="TAG",
        default=[],
        help="Skip the provided TAGs. This option takes precedence over the --only option.",
    )

    parser.add_argument(
        "-o",
        "--only",
        nargs="+",
        action=list_action,
        metavar="TAG",
        default=[],
        help="Check only the provided TAGs. Use the tag WARNINGS to only check warnings",
    )

    parser.add_argument(
        "-w",
        "--warnings",
        "--no-warnings",
        dest="warnings",
        action=NegateAction,
        nargs=0,
        default=True,
        help="Enable or disable persistent upgrade warnings (i.e. issues that can't be tested).",
    )

    parser.add_argument(
        "-d",
        "--dump",
        action="store_true",
        help="Display available incompatibility checks.",
    )

    parser.add_argument(
        "-v",
        "--verbose",
        action="count",
        default=1,
        help="Increase tool output verbosity.",
    )

    parser.add_argument(
        "-t",
        "--tags",
        action="store_true",
        help="Display the incompatibility check TAGs which can be used with --only & --ignore",
    )

    parser.add_argument(
        "--version",
        type=str,
        dest="version",
        metavar="XX.YY.ZZ",
        action=SpecifyVersionAction,
        default=None,
        help="Specific version to test regardless of discovered installed version",
    )

    parser.add_argument(
        "--target",
        type=str,
        dest="target_version",
        metavar="XX.YY.ZZ",
        action=SpecifyVersionAction,
        default=None,
        help="Specify targeted update version",
    )

    return parser.parse_args()


def main():
    if len(INCOMPATIBILITY_CHECKS) == 0:
        ver = make_version_str(NEXT_MAJOR_VERSION)
        format_print(
            f"Currently no known incompatibilities to check for in preparation for V{ver}",
            newline=True,
            offset=4,
        )
        sys.exit(0)

    has_extend_action = sys.version_info[0] >= 3 and sys.version_info[1] >= 8
    args = parse_args(has_extend_action)

    global VERBOSITY
    try:
        VERBOSITY = Debug(args.verbose)
    except ValueError:
        VERBOSITY = Debug.MAX

    ignore_list = (
        [tag.upper() for tag in args.ignore]
        if has_extend_action
        else [tag.upper() for tag in iter_list(args.ignore)]
    )
    only_list = (
        [tag.upper() for tag in args.only]
        if has_extend_action
        else [tag.upper() for tag in iter_list(args.only)]
    )

    if args.tags:
        list_tags()
    elif args.dump:
        list_checks(args.ce, ignore_list, only_list)
    else:
        global CURRENT_VERSION
        system = "HTCondor"

        if args.ce:
            system += "-CE"
            config = "/etc/condor-ce/condor_config"
            if not os.path.exists(config):
                format_print(
                    f"""Error: {system} Specified but failed to locate {config}""",
                    err=True,
                    newline=True,
                )
                sys.exit(1)
            os.environ["CONDOR_CONFIG"] = config
            htcondor.reload_config()
            CURRENT_VERSION = tuple(
                int(x) for x in htcondor.param["CONDOR_VERSION"].split(".")
            )

        if args.version:
            format_print(
                f"Overriding current version {make_version_str(CURRENT_VERSION)} to {make_version_str(args.version)}",
                debug=Debug.DEBUGGING,
            )
            CURRENT_VERSION = args.version

        format_print(
            f"Checking {system} for possible issues with known incompatibilities upgrading to V{NEXT_MAJOR_VERSION[0]}",
            newline=True,
        )

        daemons = htcondor.param["DAEMON_LIST"].upper()

        num_failed, num_ran = run_checks(args, ignore_list, only_list, daemons)
        format_print(
            f"""
            Final Report:
                {num_ran} checks tested against currently installed {system}.
            """,
            newline=True,
            debug=Debug.DETAILED,
        )
        if num_failed == 0:
            format_print(
                f"""
                No issues found with installed {system} for known incompatibilities.
                Upgrade to V{NEXT_MAJOR_VERSION[0]} should be safe.
                """,
                newline=(Debug.DETAILED > VERBOSITY),
                offset=4,
            )
        else:
            format_print(
                f"Current install failed {num_failed} checks.",
                offset=4,
                debug=Debug.DETAILED,
            )

    format_print(
        """
        To ask any questions regarding incompatibilities email:
            htcondor-users@g-groups.wisc.edu
        """,
        newline=True,
    )


if __name__ == "__main__":
    main()
