|
| 1 | +#!/usr/bin/env python3 |
| 2 | +from collections import defaultdict |
| 3 | +import logging |
| 4 | +import argparse |
| 5 | + |
| 6 | +from qcrepocleaner import binUtils |
| 7 | +from qcrepocleaner.Ccdb import Ccdb |
| 8 | +import dryable |
| 9 | + |
| 10 | +def parse_args(): |
| 11 | + """Parse the arguments passed to the script.""" |
| 12 | + logging.info("Parsing arguments") |
| 13 | + parser = argparse.ArgumentParser(description='Remove all the versions in the given path that don\'t match the given list of periodNames or has no periodName.') |
| 14 | + parser.add_argument('--url', dest='url', action='store', help='URL of the CCDB, with http[s]://', required=True) |
| 15 | + parser.add_argument('--log-level', dest='log_level', action='store', default="20", |
| 16 | + help='Log level (CRITICAL->50, ERROR->40, WARNING->30, INFO->20,DEBUG->10)') |
| 17 | + parser.add_argument('--dry-run', action='store_true', |
| 18 | + help='Dry run, no actual deletion nor modification to the CCDB.') |
| 19 | + parser.add_argument('--path', dest='path', action='store', default="", |
| 20 | + help='The path to work with (without initial slash and without .* at the end, e.g. qc/TST/MO/Bob).', required=True) |
| 21 | + parser.add_argument('--one-by-one', action='store_true', help='Ask confirmation for each deletion') |
| 22 | + parser.add_argument('--yes', action='store_true', help='Answers yes to all. You should really not use that.') |
| 23 | + parser.add_argument('--periods-list', dest='periods_list', action='store', default="", |
| 24 | + help='The list of periods that will be spared, comma separated, no space.', required=True) |
| 25 | + |
| 26 | + args = parser.parse_args() |
| 27 | + dryable.set(args.dry_run) |
| 28 | + logging.info(args) |
| 29 | + return args |
| 30 | + |
| 31 | + |
| 32 | +def run(args): |
| 33 | + ccdb = Ccdb(args.url) |
| 34 | + ccdb.logger = logging.getLogger |
| 35 | + global_deleted = 0 |
| 36 | + global_skipped = 0 |
| 37 | + global_spared = 0 |
| 38 | + global_spared_dict = defaultdict(int) |
| 39 | + periods_list = args.periods_list.split(',') |
| 40 | + |
| 41 | + # retrieve all the objects |
| 42 | + path = args.path + ".*" |
| 43 | + objects = ccdb.getFullObjectsDetails(path=path) |
| 44 | + logging.debug(f"objects: {objects}") |
| 45 | + |
| 46 | + for o in objects: |
| 47 | + deleted = 0 |
| 48 | + skipped = 0 |
| 49 | + spared = 0 |
| 50 | + spared_dict = defaultdict(int) |
| 51 | + logging.info(f"object: {o}") |
| 52 | + # Retrieve the list of versions for this object |
| 53 | + versions = ccdb.getVersionsList(o['path']) |
| 54 | + logging.info(f" Number of versions: {len(versions)} - {periods_list}") |
| 55 | + for v in versions: |
| 56 | + if "PeriodName" not in v.metadata: |
| 57 | + ccdb.deleteVersion(v) |
| 58 | + deleted += 1 |
| 59 | + elif v.metadata["PeriodName"] not in periods_list: |
| 60 | + if args.one_by_one: |
| 61 | + answer = input(" Continue? y/n\n ") |
| 62 | + if answer.lower() in ["y", "yes"]: |
| 63 | + ccdb.deleteVersion(v) |
| 64 | + deleted += 1 |
| 65 | + elif answer.lower() in ["n", "no"]: |
| 66 | + logging.info(" skipping") |
| 67 | + skipped += 1 |
| 68 | + else: |
| 69 | + logging.error(" wrong input, skipping") |
| 70 | + skipped += 1 |
| 71 | + else: |
| 72 | + ccdb.deleteVersion(v) |
| 73 | + deleted += 1 |
| 74 | + else: |
| 75 | + logging.debug(f"Not deleting {v} as it is in the periods list") |
| 76 | + spared += 1 |
| 77 | + spared_dict[v.metadata["PeriodName"]] += 1 |
| 78 | + |
| 79 | + logging.info(f"Number of deleted: {deleted}") |
| 80 | + logging.info(f"Number of spared: {spared}") |
| 81 | + logging.info(f"Number of skipped: {skipped}") |
| 82 | + logging.info(f"Spared : {spared_dict}") |
| 83 | + global_deleted += deleted |
| 84 | + global_skipped += skipped |
| 85 | + global_spared += spared |
| 86 | + global_spared_dict = defaultdict(int, {key: spared_dict.get(key, 0) + global_spared_dict.get(key, 0) for key in |
| 87 | + set(spared_dict) | set(global_spared_dict)}) |
| 88 | + |
| 89 | + logging.info(f"Global results : ") |
| 90 | + logging.info(f" Number of deleted: {global_deleted}") |
| 91 | + logging.info(f" Number of spared: {global_spared}") |
| 92 | + logging.info(f" Number of skipped: {global_skipped}") |
| 93 | + logging.info(f" Spared : {global_spared_dict}") |
| 94 | + |
| 95 | + # **************** |
| 96 | + # We start here ! |
| 97 | + # **************** |
| 98 | + |
| 99 | +def main(): |
| 100 | + binUtils.prepare_main_logger() |
| 101 | + |
| 102 | + # Parse arguments |
| 103 | + args = parse_args() |
| 104 | + logging.getLogger().setLevel(int(args.log_level)) |
| 105 | + |
| 106 | + run(args) |
| 107 | + |
| 108 | +if __name__ == "__main__": |
| 109 | + main() |
0 commit comments