Add core modules: config and platform detection
Some checks failed
CI / test (push) Failing after 12s
Some checks failed
CI / test (push) Failing after 12s
This commit is contained in:
233
dev_env_sync/core/platform.py
Normal file
233
dev_env_sync/core/platform.py
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
"""Platform detection for Linux, macOS, and WSL environments."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import re
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from enum import Enum
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
class Platform(Enum):
|
||||||
|
"""Supported platforms."""
|
||||||
|
LINUX = "linux"
|
||||||
|
MACOS = "macos"
|
||||||
|
WSL = "wsl"
|
||||||
|
UNKNOWN = "unknown"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class PlatformInfo:
|
||||||
|
"""Information about the current platform."""
|
||||||
|
system: str
|
||||||
|
release: str
|
||||||
|
version: str
|
||||||
|
machine: str
|
||||||
|
platform: Platform
|
||||||
|
is_wsl: bool
|
||||||
|
wsl_version: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
|
class PlatformNotSupported(Exception):
|
||||||
|
"""Raised when the platform is not supported."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PlatformDetector:
|
||||||
|
"""Detects and provides information about the current platform."""
|
||||||
|
|
||||||
|
WSL_PATTERN = re.compile(r'(microsoft|wsl|WSL)', re.IGNORECASE)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def detect() -> PlatformInfo:
|
||||||
|
"""Detect the current platform and return detailed information."""
|
||||||
|
system = platform.system()
|
||||||
|
release = platform.release()
|
||||||
|
version = platform.version()
|
||||||
|
machine = platform.machine()
|
||||||
|
|
||||||
|
is_wsl, wsl_version = PlatformDetector._detect_wsl()
|
||||||
|
|
||||||
|
platform_enum = Platform.UNKNOWN
|
||||||
|
|
||||||
|
if system == "Darwin":
|
||||||
|
platform_enum = Platform.MACOS
|
||||||
|
elif system == "Linux":
|
||||||
|
if is_wsl:
|
||||||
|
platform_enum = Platform.WSL
|
||||||
|
else:
|
||||||
|
platform_enum = Platform.LINUX
|
||||||
|
|
||||||
|
return PlatformInfo(
|
||||||
|
system=system,
|
||||||
|
release=release,
|
||||||
|
version=version,
|
||||||
|
machine=machine,
|
||||||
|
platform=platform_enum,
|
||||||
|
is_wsl=is_wsl,
|
||||||
|
wsl_version=wsl_version,
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _detect_wsl() -> tuple[bool, Optional[str]]:
|
||||||
|
"""Detect if running in WSL and return version info."""
|
||||||
|
try:
|
||||||
|
os_release_path = Path("/proc/sys/kernel/osrelease")
|
||||||
|
if os_release_path.exists():
|
||||||
|
content = os_release_path.read_text().strip()
|
||||||
|
if PlatformDetector.WSL_PATTERN.search(content):
|
||||||
|
wsl_version = content
|
||||||
|
return True, wsl_version
|
||||||
|
except (IOError, PermissionError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
version_path = Path("/proc/version")
|
||||||
|
if version_path.exists():
|
||||||
|
content = version_path.read_text().strip()
|
||||||
|
if PlatformDetector.WSL_PATTERN.search(content):
|
||||||
|
return True, content
|
||||||
|
except (IOError, PermissionError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if "microsoft" in platform.release().lower():
|
||||||
|
return True, platform.release()
|
||||||
|
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_linux() -> bool:
|
||||||
|
"""Check if running on Linux."""
|
||||||
|
return platform.system() == "Linux" and not PlatformDetector._detect_wsl()[0]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_macos() -> bool:
|
||||||
|
"""Check if running on macOS."""
|
||||||
|
return platform.system() == "Darwin"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_wsl() -> bool:
|
||||||
|
"""Check if running on WSL."""
|
||||||
|
return PlatformDetector._detect_wsl()[0]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_supported() -> bool:
|
||||||
|
"""Check if the current platform is supported."""
|
||||||
|
return PlatformDetector.detect().platform != Platform.UNKNOWN
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_shell_config_dir() -> Path:
|
||||||
|
"""Get the platform-specific shell configuration directory."""
|
||||||
|
info = PlatformDetector.detect()
|
||||||
|
|
||||||
|
if info.platform == Platform.MACOS:
|
||||||
|
return Path.home() / ".config"
|
||||||
|
elif info.platform in (Platform.LINUX, Platform.WSL):
|
||||||
|
xdg_config = os.environ.get("XDG_CONFIG_HOME")
|
||||||
|
if xdg_config:
|
||||||
|
return Path(xdg_config)
|
||||||
|
return Path.home() / ".config"
|
||||||
|
else:
|
||||||
|
return Path.home()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_home_dir() -> Path:
|
||||||
|
"""Get the user's home directory."""
|
||||||
|
return Path.home()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_backup_dir() -> Path:
|
||||||
|
"""Get the default backup directory based on platform."""
|
||||||
|
return PlatformDetector.get_home_dir() / ".dev-env-sync-backups"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_editor_config_dir(editor: str) -> Path:
|
||||||
|
"""Get the platform-specific config directory for an editor."""
|
||||||
|
info = PlatformDetector.detect()
|
||||||
|
home = Path.home()
|
||||||
|
|
||||||
|
if editor == "vscode":
|
||||||
|
if info.platform == Platform.MACOS:
|
||||||
|
return home / "Library/Application Support/Code/User"
|
||||||
|
else:
|
||||||
|
xdg_config = os.environ.get("XDG_CONFIG_HOME")
|
||||||
|
if xdg_config:
|
||||||
|
return Path(xdg_config) / "Code/User"
|
||||||
|
return home / ".config/Code/User"
|
||||||
|
|
||||||
|
elif editor == "neovim":
|
||||||
|
if info.platform == Platform.MACOS:
|
||||||
|
return home / ".config/nvim"
|
||||||
|
else:
|
||||||
|
xdg_config = os.environ.get("XDG_CONFIG_HOME")
|
||||||
|
if xdg_config:
|
||||||
|
return Path(xdg_config) / "nvim"
|
||||||
|
return home / ".config/nvim"
|
||||||
|
|
||||||
|
elif editor == "vim":
|
||||||
|
if info.platform == Platform.MACOS:
|
||||||
|
return home
|
||||||
|
else:
|
||||||
|
return home
|
||||||
|
|
||||||
|
else:
|
||||||
|
return PlatformDetector.get_shell_config_dir()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_package_manager() -> str:
|
||||||
|
"""Get the appropriate package manager for the platform."""
|
||||||
|
info = PlatformDetector.detect()
|
||||||
|
|
||||||
|
if info.platform == Platform.MACOS:
|
||||||
|
return "brew"
|
||||||
|
elif info.platform == Platform.WSL:
|
||||||
|
if PlatformDetector._has_command("apt"):
|
||||||
|
return "apt"
|
||||||
|
elif PlatformDetector._has_command("dnf"):
|
||||||
|
return "dnf"
|
||||||
|
elif PlatformDetector._has_command("yum"):
|
||||||
|
return "yum"
|
||||||
|
elif info.platform == Platform.LINUX:
|
||||||
|
if PlatformDetector._has_command("apt"):
|
||||||
|
return "apt"
|
||||||
|
elif PlatformDetector._has_command("dnf"):
|
||||||
|
return "dnf"
|
||||||
|
elif PlatformDetector._has_command("yum"):
|
||||||
|
return "yum"
|
||||||
|
elif PlatformDetector._has_command("pacman"):
|
||||||
|
return "pacman"
|
||||||
|
|
||||||
|
return "unknown"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _has_command(cmd: str) -> bool:
|
||||||
|
"""Check if a command is available."""
|
||||||
|
import shutil
|
||||||
|
return shutil.which(cmd) is not None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def normalize_path(path: str) -> Path:
|
||||||
|
"""Normalize a path for the current platform."""
|
||||||
|
path_obj = Path(path).expanduser()
|
||||||
|
|
||||||
|
if not path_obj.is_absolute():
|
||||||
|
if path.startswith("~"):
|
||||||
|
path_obj = Path.home() / path[2:]
|
||||||
|
else:
|
||||||
|
path_obj = Path.cwd() / path_obj
|
||||||
|
|
||||||
|
return path_obj
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_path_separator() -> str:
|
||||||
|
"""Get the path separator for the current platform."""
|
||||||
|
return "/" if platform.system() != "Windows" else "\\"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_line_ending() -> str:
|
||||||
|
"""Get the appropriate line ending for the current platform."""
|
||||||
|
info = PlatformDetector.detect()
|
||||||
|
if info.platform == Platform.MACOS and platform.mac_ver()[0].startswith("10"):
|
||||||
|
return "\r"
|
||||||
|
return "\n"
|
||||||
Reference in New Issue
Block a user