47 lines
1.8 KiB
Python
47 lines
1.8 KiB
Python
"""
|
|
Zip File Parser
|
|
ZIP 文件解析器
|
|
"""
|
|
import zipfile
|
|
import os
|
|
from typing import Optional
|
|
|
|
from app.module.operator.parsers.abstract_parser import AbstractParser
|
|
from app.module.operator.schema import OperatorDto
|
|
|
|
|
|
class ZipParser(AbstractParser):
|
|
"""ZIP 压缩包解析器"""
|
|
|
|
def parse_yaml_from_archive(
|
|
self,
|
|
archive_path: str,
|
|
entry_path: str,
|
|
file_name: Optional[str] = None,
|
|
file_size: Optional[int] = None
|
|
) -> OperatorDto:
|
|
"""从 ZIP 文件中解析 YAML"""
|
|
try:
|
|
with zipfile.ZipFile(archive_path, 'r') as zf:
|
|
for name in zf.namelist():
|
|
if name == entry_path or name.endswith(f"/{entry_path}"):
|
|
with zf.open(name) as file:
|
|
content = file.read().decode('utf-8')
|
|
return self.parse_yaml(content, file_name, file_size)
|
|
raise FileNotFoundError(f"File '{entry_path}' not found in archive")
|
|
except (zipfile.BadZipFile, zipfile.LargeZipFile) as e:
|
|
raise ValueError(f"Failed to parse ZIP file: {e}")
|
|
|
|
def extract_to(self, archive_path: str, target_dir: str) -> None:
|
|
"""解压 ZIP 文件到目标目录"""
|
|
try:
|
|
os.makedirs(target_dir, exist_ok=True)
|
|
with zipfile.ZipFile(archive_path, 'r') as zf:
|
|
# Safety check: prevent path traversal
|
|
for name in zf.namelist():
|
|
if os.path.isabs(name) or ".." in name.split("/"):
|
|
raise ValueError(f"Unsafe path in archive: {name}")
|
|
zf.extractall(target_dir)
|
|
except (zipfile.BadZipFile, zipfile.LargeZipFile) as e:
|
|
raise ValueError(f"Failed to extract ZIP file: {e}")
|