Coverage for src / mafw / devtools / cli / documentation / prune.py: 96%

61 statements  

« prev     ^ index     » next       coverage.py v7.14.0, created at 2026-06-28 13:34 +0000

1# Copyright 2025–2026 European Union 

2# Author: Bulgheroni Antonio (antonio.bulgheroni@ec.europa.eu) 

3# SPDX-License-Identifier: EUPL-1.2 

4"""CLI commands for pruning and cleaning documentation builds.""" 

5 

6from __future__ import annotations 

7 

8import shutil 

9from pathlib import Path 

10 

11import click 

12 

13from mafw.devtools.documentation.versions import ( 

14 format_size, 

15 prune_old_versions, 

16 regenerate_versions_json_after_pruning, 

17) 

18 

19 

20@click.command() 

21@click.option('--outdir', '-o', default='docs/build/doc', help='Output directory to check') 

22@click.option('--max-size', '-s', default=100, help='Maximum size in MB (default: 100)') 

23@click.option('--dry-run/--no-dry-run', default=False, help='Show what would be removed without actually removing') 

24@click.option('--auto-prune/--no-auto-prune', default=False, help='Automatically prune without confirmation') 

25def prune(outdir: Path, max_size: int, dry_run: bool, auto_prune: bool) -> None: 

26 """Prune old documentation versions to stay within size limit.""" 

27 outdir = Path(outdir).resolve() 

28 

29 if not outdir.exists(): 

30 print(f'❌ Directory does not exist: {outdir}') 

31 return 

32 

33 print(f'🔍 Analyzing {outdir}...\n') 

34 

35 removed_versions, final_size = prune_old_versions(outdir, max_size, dry_run=True) 

36 

37 if not removed_versions: 

38 return 

39 

40 if dry_run: 

41 print('\n📋 Summary:') 

42 print(f' Versions to remove: {", ".join(removed_versions)}') 

43 print(f' Final size: {format_size(final_size)}') 

44 print('\n💡 Run without --dry-run to actually remove these versions') 

45 return 

46 

47 if not auto_prune: 

48 print(f'\n⚠️ This will permanently delete {len(removed_versions)} version(s): {", ".join(removed_versions)}') 

49 response = input('Continue? [y/N]: ') 

50 if response.lower() not in ('y', 'yes'): 50 ↛ 54line 50 didn't jump to line 54 because the condition on line 50 was always true

51 print('❌ Aborted') 

52 return 

53 

54 print('\n🔨 Pruning versions...') 

55 removed_versions, final_size = prune_old_versions(outdir, max_size, dry_run=False) 

56 

57 regenerate_versions_json_after_pruning(outdir, removed_versions) 

58 

59 print('\n✅ Pruning complete!') 

60 print(f' Removed: {", ".join(removed_versions)}') 

61 print(f' Final size: {format_size(final_size)} (target: {max_size} MB)') 

62 

63 

64@click.command() 

65@click.argument('target', type=click.Choice(['all', 'latest'], case_sensitive=False), default='all') 

66@click.option('--outdir', '-o', default='docs/build/doc', help='Output directory to clean') 

67def clean(target: str, outdir: Path) -> None: 

68 """Clean the output directory. 

69 

70 TARGET can be 'all' (remove everything) or 'latest' (remove only latest folder). 

71 """ 

72 outdir = Path(outdir).resolve() 

73 

74 if not outdir.exists(): 

75 print(f'ℹ️ Output directory does not exist: {outdir}') 

76 return 

77 

78 if target == 'latest': 

79 latest_dir = outdir / 'latest' 

80 if latest_dir.exists(): 

81 try: 

82 if latest_dir.is_symlink(): 

83 latest_dir.unlink() 

84 else: 

85 shutil.rmtree(latest_dir) 

86 print(f'🧹 Cleaned latest directory: {latest_dir}') 

87 except Exception as e: 

88 print(f'❌ Failed to clean directory {latest_dir}: {e}') 

89 else: 

90 print(f'ℹ️ Latest directory does not exist: {latest_dir}') 

91 else: 

92 try: 

93 shutil.rmtree(outdir) 

94 print(f'🧹 Cleaned all output: {outdir}') 

95 except Exception as e: 

96 print(f'❌ Failed to clean directory {outdir}: {e}')