• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
4# Copyright (c) 2021-2025 Huawei Device Co., Ltd.
5# Licensed under the Apache License, Version 2.0 (the 'License');
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an 'AS IS' BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17import threading
18import platform
19from pathlib import Path
20from typing import Optional, Tuple
21from runner.code_coverage.coverage_dir import CoverageDir
22from runner.code_coverage.llvm_cov_tool import LlvmCovTool
23from runner.code_coverage.lcov_tool import LcovTool
24from runner.code_coverage.cmd_executor import CmdExecutor, LinuxCmdExecutor
25
26
27class CoverageManager:
28    _instance: Optional['CoverageManager'] = None
29    _lock: threading.Lock = threading.Lock()
30    _initialized: bool = False
31
32    def __new__(
33            cls,
34            build_dir_path: Optional[Path] = None,
35            coverage_dir: Optional[CoverageDir] = None
36        ) -> 'CoverageManager':
37        if cls._instance is not None:
38            return cls._instance
39        with cls._lock:
40            build_dir_path, coverage_dir = cls._validate_parameters(build_dir_path, coverage_dir)
41            if cls._instance is None:
42                instance = super().__new__(cls)
43                instance._initialize(build_dir_path, coverage_dir)
44                cls._instance = instance
45        return cls._instance
46
47    @property
48    def llvm_cov_tool(self) -> LlvmCovTool:
49        return self.llvm_cov
50
51    @property
52    def lcov_tool(self) -> LcovTool:
53        return self.lcov
54
55    @staticmethod
56    def _get_cmd_executor() -> CmdExecutor:
57        system = platform.system()
58        if system == "Linux":
59            return LinuxCmdExecutor()
60        raise NotImplementedError(f"Unsupported OS: {system}")
61
62    @classmethod
63    def _validate_parameters(
64            cls,
65            build_dir_path: Optional[Path] = None,
66            coverage_dir: Optional[CoverageDir] = None
67        ) -> Tuple[Path, CoverageDir]:
68        if build_dir_path is None:
69            raise ValueError("build_dir_path is not initialized")
70        if not build_dir_path.parts or str(build_dir_path) == ".":
71            raise ValueError("build_dir_path must not be '.' or empty")
72        if not build_dir_path.exists():
73            raise FileNotFoundError(f"Directory build_dir_path={build_dir_path} not found")
74
75        if coverage_dir is None:
76            raise ValueError("coverage_dir is not initialized")
77        if not coverage_dir.root.exists():
78            raise FileNotFoundError(f"Directory coverage_dir.root={coverage_dir.root} not found")
79
80        return build_dir_path, coverage_dir
81
82    def _initialize(self, build_dir_path: Path, coverage_dir: CoverageDir) -> None:
83        if self._initialized:
84            return
85        self.cmd_executor = self._get_cmd_executor()
86        self.llvm_cov = LlvmCovTool(build_dir_path, coverage_dir, self.cmd_executor)
87        self.lcov = LcovTool(build_dir_path, coverage_dir, self.cmd_executor)
88        self._initialized = True
89