summaryrefslogtreecommitdiff
path: root/tools/ng/utils.py
diff options
context:
space:
mode:
authorbernard <[email protected]>2025-08-01 21:33:50 +0800
committerR b b666 <[email protected]>2025-08-07 09:32:45 +0800
commita65efe648c7750bbd970c7f8d72fb164cde13835 (patch)
tree83b22b91c5faafd5ffd52cbe5d84bae55d900e55 /tools/ng/utils.py
parent5347500f3306a283d9c4c2be5b9454bf31dd514f (diff)
[Tools] Add documents for tools script; Add NG for tools
Diffstat (limited to 'tools/ng/utils.py')
-rw-r--r--tools/ng/utils.py339
1 files changed, 339 insertions, 0 deletions
diff --git a/tools/ng/utils.py b/tools/ng/utils.py
new file mode 100644
index 0000000000..a0503ea481
--- /dev/null
+++ b/tools/ng/utils.py
@@ -0,0 +1,339 @@
+# -*- 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 \ No newline at end of file