| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- # -*- coding: utf-8 -*-
- """
- Utility functions for RT-Thread build system.
- This module provides common utility functions used throughout the build system.
- """
- import os
- import sys
- import platform
- from typing import List, Tuple, Optional
- class PathService:
- """Service for path manipulation and normalization."""
-
- def __init__(self, base_path: str = None):
- self.base_path = base_path or os.getcwd()
-
- def normalize_path(self, path: str) -> str:
- """
- Normalize path for cross-platform compatibility.
-
- Args:
- path: Path to normalize
-
- Returns:
- Normalized path
- """
- # Convert to absolute path if relative
- if not os.path.isabs(path):
- path = os.path.abspath(os.path.join(self.base_path, path))
-
- # Normalize separators
- path = os.path.normpath(path)
-
- # Convert to forward slashes for consistency
- if platform.system() == 'Windows':
- path = path.replace('\\', '/')
-
- return path
-
- def make_relative(self, path: str, base: str = None) -> str:
- """
- Make path relative to base.
-
- Args:
- path: Path to make relative
- base: Base path (defaults to self.base_path)
-
- Returns:
- Relative path
- """
- if base is None:
- base = self.base_path
-
- path = self.normalize_path(path)
- base = self.normalize_path(base)
-
- try:
- rel_path = os.path.relpath(path, base)
- # Convert to forward slashes
- if platform.system() == 'Windows':
- rel_path = rel_path.replace('\\', '/')
- return rel_path
- except ValueError:
- # Different drives on Windows
- return path
-
- def split_path(self, path: str) -> List[str]:
- """
- Split path into components.
-
- Args:
- path: Path to split
-
- Returns:
- List of path components
- """
- path = self.normalize_path(path)
- parts = []
-
- while True:
- head, tail = os.path.split(path)
- if tail:
- parts.insert(0, tail)
- if head == path: # Reached root
- if head:
- parts.insert(0, head)
- break
- path = head
-
- return parts
-
- def common_prefix(self, paths: List[str]) -> str:
- """
- Find common prefix of multiple paths.
-
- Args:
- paths: List of paths
-
- Returns:
- Common prefix path
- """
- if not paths:
- return ""
-
- # Normalize all paths
- normalized = [self.normalize_path(p) for p in paths]
-
- # Find common prefix
- prefix = os.path.commonpath(normalized)
-
- return self.normalize_path(prefix)
- class PlatformInfo:
- """Platform and system information."""
-
- @staticmethod
- def get_platform() -> str:
- """Get platform name (Windows, Linux, Darwin)."""
- return platform.system()
-
- @staticmethod
- def get_architecture() -> str:
- """Get system architecture."""
- return platform.machine()
-
- @staticmethod
- def is_windows() -> bool:
- """Check if running on Windows."""
- return platform.system() == 'Windows'
-
- @staticmethod
- def is_linux() -> bool:
- """Check if running on Linux."""
- return platform.system() == 'Linux'
-
- @staticmethod
- def is_macos() -> bool:
- """Check if running on macOS."""
- return platform.system() == 'Darwin'
-
- @staticmethod
- def get_python_version() -> Tuple[int, int, int]:
- """Get Python version tuple."""
- return sys.version_info[:3]
-
- @staticmethod
- def check_python_version(min_version: Tuple[int, int]) -> bool:
- """
- Check if Python version meets minimum requirement.
-
- Args:
- min_version: Minimum version tuple (major, minor)
-
- Returns:
- True if version is sufficient
- """
- current = sys.version_info[:2]
- return current >= min_version
- class FileUtils:
- """File operation utilities."""
-
- @staticmethod
- def read_file(filepath: str, encoding: str = 'utf-8') -> str:
- """
- Read file content.
-
- Args:
- filepath: File path
- encoding: File encoding
-
- Returns:
- File content
- """
- with open(filepath, 'r', encoding=encoding) as f:
- return f.read()
-
- @staticmethod
- def write_file(filepath: str, content: str, encoding: str = 'utf-8') -> None:
- """
- Write content to file.
-
- Args:
- filepath: File path
- content: Content to write
- encoding: File encoding
- """
- # Ensure directory exists
- directory = os.path.dirname(filepath)
- if directory:
- os.makedirs(directory, exist_ok=True)
-
- with open(filepath, 'w', encoding=encoding) as f:
- f.write(content)
-
- @staticmethod
- def copy_file(src: str, dst: str) -> None:
- """
- Copy file from src to dst.
-
- Args:
- src: Source file path
- dst: Destination file path
- """
- import shutil
-
- # Ensure destination directory exists
- dst_dir = os.path.dirname(dst)
- if dst_dir:
- os.makedirs(dst_dir, exist_ok=True)
-
- shutil.copy2(src, dst)
-
- @staticmethod
- def find_files(directory: str, pattern: str, recursive: bool = True) -> List[str]:
- """
- Find files matching pattern.
-
- Args:
- directory: Directory to search
- pattern: File pattern (supports wildcards)
- recursive: Search recursively
-
- Returns:
- List of matching file paths
- """
- import fnmatch
-
- matches = []
-
- if recursive:
- for root, dirnames, filenames in os.walk(directory):
- for filename in filenames:
- if fnmatch.fnmatch(filename, pattern):
- matches.append(os.path.join(root, filename))
- else:
- try:
- filenames = os.listdir(directory)
- for filename in filenames:
- if fnmatch.fnmatch(filename, pattern):
- filepath = os.path.join(directory, filename)
- if os.path.isfile(filepath):
- matches.append(filepath)
- except OSError:
- pass
-
- return sorted(matches)
- class VersionUtils:
- """Version comparison utilities."""
-
- @staticmethod
- def parse_version(version_str: str) -> Tuple[int, ...]:
- """
- Parse version string to tuple.
-
- Args:
- version_str: Version string (e.g., "1.2.3")
-
- Returns:
- Version tuple
- """
- try:
- parts = version_str.split('.')
- return tuple(int(p) for p in parts if p.isdigit())
- except (ValueError, AttributeError):
- return (0,)
-
- @staticmethod
- def compare_versions(v1: str, v2: str) -> int:
- """
- Compare two version strings.
-
- Args:
- v1: First version
- v2: Second version
-
- Returns:
- -1 if v1 < v2, 0 if equal, 1 if v1 > v2
- """
- t1 = VersionUtils.parse_version(v1)
- t2 = VersionUtils.parse_version(v2)
-
- # Pad shorter version with zeros
- if len(t1) < len(t2):
- t1 = t1 + (0,) * (len(t2) - len(t1))
- elif len(t2) < len(t1):
- t2 = t2 + (0,) * (len(t1) - len(t2))
-
- if t1 < t2:
- return -1
- elif t1 > t2:
- return 1
- else:
- return 0
-
- @staticmethod
- def version_satisfies(version: str, requirement: str) -> bool:
- """
- Check if version satisfies requirement.
-
- Args:
- version: Version string
- requirement: Requirement string (e.g., ">=1.2.0")
-
- Returns:
- True if satisfied
- """
- import re
-
- # Parse requirement
- match = re.match(r'([<>=]+)\s*(.+)', requirement)
- if not match:
- # Exact match required
- return version == requirement
-
- op, req_version = match.groups()
- cmp = VersionUtils.compare_versions(version, req_version)
-
- if op == '>=':
- return cmp >= 0
- elif op == '<=':
- return cmp <= 0
- elif op == '>':
- return cmp > 0
- elif op == '<':
- return cmp < 0
- elif op == '==':
- return cmp == 0
- elif op == '!=':
- return cmp != 0
- else:
- return False
|