|
9 | 9 | # SPDX-License-Identifier: MIT |
10 | 10 | # |
11 | 11 |
|
| 12 | +import json |
12 | 13 | from typer import Typer |
13 | 14 | from itertools import product |
14 | 15 | from quantcrypt.internal import utils, constants as const |
|
24 | 25 | ) |
25 | 26 |
|
26 | 27 |
|
| 28 | +def remove_spec_variants( |
| 29 | + spec_variants: dict[const.AlgoSpec, list[const.PQAVariant]] |
| 30 | +) -> tuple[dict, dict]: |
| 31 | + removed_variants: dict[const.AlgoSpec, list[const.PQAVariant]] = dict() |
| 32 | + already_removed: dict[const.AlgoSpec, list[const.PQAVariant]] = dict() |
| 33 | + bin_path = utils.search_upwards("bin") |
| 34 | + bin_contents = list(bin_path.iterdir()) |
| 35 | + |
| 36 | + for spec, variants in spec_variants.items(): # type: const.AlgoSpec, list[const.PQAVariant] |
| 37 | + for variant in variants: |
| 38 | + did_remove = False |
| 39 | + |
| 40 | + for item in bin_contents: |
| 41 | + if spec.module_name(variant) in item.name and item.exists(): |
| 42 | + item.unlink() |
| 43 | + x = removed_variants.get(spec, list()) |
| 44 | + x.append(variant) |
| 45 | + removed_variants[spec] = x |
| 46 | + did_remove = True |
| 47 | + |
| 48 | + if not did_remove: |
| 49 | + y = already_removed.get(spec, list()) |
| 50 | + y.append(variant) |
| 51 | + already_removed[spec] = y |
| 52 | + |
| 53 | + return removed_variants, already_removed |
| 54 | + |
| 55 | + |
| 56 | +def report_spec_variants( |
| 57 | + spec_variants: dict[const.AlgoSpec, list[const.PQAVariant]] |
| 58 | +) -> None: |
| 59 | + armor_names = [s.armor_name() for s in spec_variants.keys()] |
| 60 | + longest_name_len = max(len(n) for n in armor_names) if armor_names else 0 |
| 61 | + |
| 62 | + for spec, variants in spec_variants.items(): |
| 63 | + variants_fmt = json.dumps([v.value for v in variants]) |
| 64 | + arna_fmt = spec.armor_name().rjust(longest_name_len) |
| 65 | + console.styled_print(f"{arna_fmt}: {variants_fmt}") |
| 66 | + |
| 67 | + |
27 | 68 | @remove_app.callback() |
28 | 69 | def command_remove( |
29 | 70 | algorithms: ats.RemoveAlgos, |
30 | 71 | keep_algos: ats.KeepAlgos = False, |
| 72 | + only_ref: ats.OnlyRef = False, |
31 | 73 | dry_run: ats.DryRun = False, |
32 | 74 | non_interactive: ats.NonInteractive = False |
33 | 75 | ) -> None: |
| 76 | + if only_ref and not keep_algos: |
| 77 | + console.raise_error("Cannot use --only-ref without --keep") |
| 78 | + |
| 79 | + chosen_algos = const.SupportedAlgos.filter(algorithms) |
| 80 | + if len(chosen_algos) != len(algorithms): |
| 81 | + algo_names = [s.armor_name() for s in chosen_algos] |
| 82 | + bad_names = [a for a in algorithms if a.upper() not in algo_names] |
| 83 | + if bad_names: # pragma: no branch |
| 84 | + console.raise_error( |
| 85 | + f"Unknown algorithm name(s): {json.dumps(bad_names)}. " + |
| 86 | + "Please choose algorithm names from the following list:\n" + |
| 87 | + ' | '.join(const.SupportedAlgos.armor_names()) |
| 88 | + ) |
| 89 | + |
34 | 90 | console.notify_dry_run(dry_run) |
35 | 91 | console.styled_print("QuantCrypt is about to remove compiled PQA binaries from itself.") |
36 | 92 |
|
37 | 93 | if not non_interactive: |
38 | 94 | console.ask_continue(exit_on_false=True) |
39 | 95 |
|
40 | | - algos = const.SupportedAlgos.filter(algorithms, invert=keep_algos) |
41 | 96 | variants = const.PQAVariant.members() |
| 97 | + if only_ref: |
| 98 | + algorithms = [a.upper() for a in algorithms] |
| 99 | + algos = const.SupportedAlgos |
| 100 | + else: |
| 101 | + algos = const.SupportedAlgos.filter(algorithms, invert=keep_algos) |
| 102 | + |
| 103 | + to_remove: dict[const.AlgoSpec, list[const.PQAVariant]] = dict() |
| 104 | + for spec, variant in product(algos, variants): # type: const.AlgoSpec, const.PQAVariant |
| 105 | + if only_ref and spec.armor_name() in algorithms and variant == const.PQAVariant.REF: |
| 106 | + continue |
| 107 | + variants = to_remove.get(spec, list()) |
| 108 | + variants.append(variant) |
| 109 | + to_remove[spec] = variants |
42 | 110 |
|
43 | 111 | if dry_run: |
44 | | - console.styled_print("QuantCrypt would have removed the following algorithms:") |
45 | | - console.pretty_print(', '.join(s.armor_name() for s in algos)) |
| 112 | + console.styled_print("\nQuantCrypt would have removed the following algorithms and their variants:") |
| 113 | + report_spec_variants(to_remove) |
46 | 114 | return |
47 | 115 |
|
48 | | - print() |
49 | | - bin_path = utils.search_upwards("bin") |
50 | | - bin_contents = list(bin_path.iterdir()) |
51 | | - |
52 | | - for spec, variant in product(algos, variants): # type: const.AlgoSpec, const.PQAVariant |
53 | | - module_name = spec.module_name(variant) |
54 | | - did_remove = False |
| 116 | + removed_variants, already_removed = remove_spec_variants(to_remove) |
55 | 117 |
|
56 | | - for item in bin_contents: |
57 | | - if spec.module_name(variant) in item.name and item.exists(): |
58 | | - item.unlink() |
59 | | - did_remove = True |
60 | | - console.styled_print(f"Successfully removed binaries - {module_name}") |
| 118 | + console.styled_print("\nSuccessfully removed binaries: ") |
| 119 | + report_spec_variants(removed_variants) |
61 | 120 |
|
62 | | - if not did_remove: |
63 | | - console.styled_print(f"Binaries already removed - {module_name}") |
| 121 | + console.styled_print("\nAlready removed binaries: ") |
| 122 | + report_spec_variants(already_removed) |
64 | 123 |
|
65 | 124 | print() |
66 | 125 | console.print_success() |
0 commit comments