#!/usr/bin/env python3 """ Remove one or more Perforce users and their associated clients and shelves using the P4Python API. This script accepts either a single username or a file containing a list of usernames (one per line). For each user, it uses the P4Python API to run ``p4 user -FDy``, which deletes the user along with any clients and shelves they own. The script respects a list of service accounts that should never be removed. """ import argparse import logging import sys from typing import Iterable from P4 import P4, P4Exception # type: ignore import sdputils # type: ignore def parse_arguments(argv: Iterable[str]) -> argparse.Namespace: parser = argparse.ArgumentParser( description="Remove Perforce users and their associated clients/shelves via P4Python", ) parser.add_argument( "instance", nargs="?", default="1", help="SDP instance identifier (defaults to '1')", ) parser.add_argument( "user_or_file", help="Username to remove or path to a file containing one username per line", ) parser.add_argument( "--simulate", action="store_true", help="Simulation mode: print actions without deleting users", ) return parser.parse_args(list(argv)) class P4UserRemoverAPI: """Helper to manage user deletion using the P4Python API.""" def __init__(self, instance: str) -> None: self.instance = instance self.utils = sdputils.SDPUtils(instance) self.p4: P4 | None = None def connect_and_login(self) -> None: try: self.p4 = self.utils.connect_p4() except P4Exception as exc: logging.error("Failed to connect/login: %s", exc) raise def delete_user(self, user: str, simulate: bool = False) -> None: if user.lower() in sdputils.PROTECTED_USERS: logging.info("Skipping protected user %s", user) return logging.info("Deleting user: %s", user) if simulate: logging.info("Simulation mode: would run 'user -FDy %s'", user) return try: # run('user', '-FDy', user) deletes the user and associated metadata self.p4.run("user", "-FDy", user) logging.debug("Successfully deleted user %s", user) except P4Exception as exc: logging.error("Failed to delete user %s: %s", user, exc) def main(argv: Iterable[str] | None = None) -> int: args = parse_arguments(argv or sys.argv[1:]) logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s") remover = P4UserRemoverAPI(args.instance) # Connect and login once at the beginning try: remover.connect_and_login() except P4Exception: return 1 # Determine user list user_list = sdputils.SDPUtils.load_items_or_single(args.user_or_file) # Delete each user for user in user_list: remover.delete_user(user, simulate=args.simulate) return 0 if __name__ == "__main__": sys.exit(main())