Coverage for src/ezcompiler/adapters/base_installer.py: 100.00%

13 statements  

« prev     ^ index     » next       coverage.py v7.14.3, created at 2026-07-04 11:22 +0000

1# /////////////////////////////////////////////////////////////// 

2# BASE_INSTALLER - Abstract base installer interface 

3# Project: ezcompiler 

4# /////////////////////////////////////////////////////////////// 

5 

6""" 

7Base installer - Abstract base class for first-deployment installer builders. 

8 

9Defines the interface (conforming to ``types.InstallerPort``) and shared 

10validation. The structural contract is the Port; this base factors common 

11behaviour. Boundaries are typed via the Port, not this base. 

12""" 

13 

14from __future__ import annotations 

15 

16# /////////////////////////////////////////////////////////////// 

17# IMPORTS 

18# /////////////////////////////////////////////////////////////// 

19from abc import ABC, abstractmethod 

20from pathlib import Path 

21from typing import Any 

22 

23from ..shared.exceptions import InstallerConfigError 

24 

25# /////////////////////////////////////////////////////////////// 

26# CLASSES 

27# /////////////////////////////////////////////////////////////// 

28 

29 

30class BaseInstaller(ABC): 

31 """Abstract base class for first-deployment installer builders.""" 

32 

33 # //////////////////////////////////////////////// 

34 # INITIALIZATION 

35 # //////////////////////////////////////////////// 

36 

37 def __init__(self, config: dict[str, Any] | None = None) -> None: 

38 self._config = config or {} 

39 

40 # //////////////////////////////////////////////// 

41 # ABSTRACT METHODS 

42 # //////////////////////////////////////////////// 

43 

44 @abstractmethod 

45 def build( 

46 self, bundle_dir: Path, app_name: str, version: str, output_dir: Path 

47 ) -> Path: 

48 """Build the installer executable. Raises InstallerError on failure.""" 

49 

50 @abstractmethod 

51 def get_installer_name(self) -> str: 

52 """Human-readable installer backend name.""" 

53 

54 # //////////////////////////////////////////////// 

55 # VALIDATION METHODS 

56 # //////////////////////////////////////////////// 

57 

58 def _validate_bundle_dir(self, bundle_dir: Path) -> None: 

59 """Ensure the bundle directory exists and is non-empty.""" 

60 if not bundle_dir.is_dir(): 

61 raise InstallerConfigError(f"Bundle directory does not exist: {bundle_dir}") 

62 if not any(bundle_dir.iterdir()): 

63 raise InstallerConfigError(f"Bundle directory is empty: {bundle_dir}")