mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-15 17:30:13 +08:00
* chore: add release preparation workflow * fix: address release workflow review feedback
185 lines
6.0 KiB
Python
185 lines
6.0 KiB
Python
"""Small TOML readers for bootstrapping paths without parser dependencies."""
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
def _read_quoted_value(value: str, field_name: str) -> tuple[str, str]:
|
|
"""Read one quoted TOML string value and return its tail.
|
|
|
|
Args:
|
|
value: Raw value text that starts with a quoted string.
|
|
field_name: Field name used in error messages.
|
|
|
|
Returns:
|
|
A tuple containing the unquoted string and the remaining text.
|
|
|
|
Raises:
|
|
ValueError: The value is not a supported quoted string.
|
|
"""
|
|
value = value.strip()
|
|
if len(value) < 2 or value[0] not in ("'", '"'):
|
|
raise ValueError(f"Unsupported {field_name} value")
|
|
|
|
quote = value[0]
|
|
end_index = value.find(quote, 1)
|
|
if end_index == -1:
|
|
raise ValueError(f"Unterminated {field_name} string")
|
|
|
|
result = value[1:end_index]
|
|
if not result:
|
|
raise ValueError(f"Empty {field_name} value")
|
|
return result, value[end_index + 1 :].strip()
|
|
|
|
|
|
def _read_dependency_array(raw_value: str) -> list[str]:
|
|
"""Read a simple inline TOML string array.
|
|
|
|
Args:
|
|
raw_value: Raw dependency array text, including the surrounding brackets.
|
|
|
|
Returns:
|
|
Parsed dependency strings.
|
|
|
|
Raises:
|
|
ValueError: The array is missing brackets or contains unsupported entries.
|
|
"""
|
|
value = raw_value.strip()
|
|
if not value.startswith("["):
|
|
raise ValueError("Unsupported project.dependencies value")
|
|
|
|
dependencies = []
|
|
value = value[1:].strip()
|
|
while value:
|
|
if value.startswith("]"):
|
|
tail = value[1:].strip()
|
|
if tail and not tail.startswith("#"):
|
|
raise ValueError("Unsupported content after project.dependencies")
|
|
return dependencies
|
|
|
|
dependency, tail = _read_quoted_value(value, "project.dependencies entry")
|
|
dependencies.append(dependency)
|
|
|
|
if tail.startswith(","):
|
|
value = tail[1:].strip()
|
|
continue
|
|
if tail.startswith("]"):
|
|
value = tail
|
|
continue
|
|
if tail:
|
|
raise ValueError("Unsupported content after project.dependencies entry")
|
|
raise ValueError("Unterminated project.dependencies array")
|
|
|
|
raise ValueError("Unterminated project.dependencies array")
|
|
|
|
|
|
def read_pyproject_project_version(pyproject_path: Path) -> str:
|
|
"""Read the project version from a pyproject.toml file.
|
|
|
|
Args:
|
|
pyproject_path: Path to the pyproject.toml file.
|
|
|
|
Returns:
|
|
The value of the project.version field.
|
|
|
|
Raises:
|
|
FileNotFoundError: The pyproject.toml file does not exist.
|
|
ValueError: The project.version field is missing or unsupported.
|
|
"""
|
|
in_project_section = False
|
|
for raw_line in pyproject_path.read_text(encoding="utf-8").splitlines():
|
|
line = raw_line.strip()
|
|
if not line or line.startswith("#"):
|
|
continue
|
|
|
|
if line.startswith("[") and line.endswith("]"):
|
|
in_project_section = line == "[project]"
|
|
continue
|
|
|
|
if not in_project_section:
|
|
continue
|
|
|
|
key, separator, raw_value = line.partition("=")
|
|
if key.strip() != "version":
|
|
continue
|
|
if not separator:
|
|
raise ValueError("Missing value separator for project.version")
|
|
|
|
version, tail = _read_quoted_value(raw_value, "project.version")
|
|
if tail and not tail.startswith("#"):
|
|
raise ValueError("Unsupported content after project.version")
|
|
return version
|
|
|
|
raise ValueError("Missing project.version")
|
|
|
|
|
|
def read_pyproject_project_dependencies(pyproject_path: Path) -> list[str]:
|
|
"""Read project dependencies from a pyproject.toml file.
|
|
|
|
Args:
|
|
pyproject_path: Path to the pyproject.toml file.
|
|
|
|
Returns:
|
|
The values in the project.dependencies array.
|
|
|
|
Raises:
|
|
FileNotFoundError: The pyproject.toml file does not exist.
|
|
ValueError: The project.dependencies field is missing or unsupported.
|
|
"""
|
|
dependencies = []
|
|
in_project_section = False
|
|
in_dependencies_array = False
|
|
|
|
for raw_line in pyproject_path.read_text(encoding="utf-8").splitlines():
|
|
line = raw_line.strip()
|
|
if not line or line.startswith("#"):
|
|
continue
|
|
|
|
if in_dependencies_array:
|
|
if line.startswith("]"):
|
|
tail = line[1:].strip()
|
|
if tail and not tail.startswith("#"):
|
|
raise ValueError("Unsupported content after project.dependencies")
|
|
return dependencies
|
|
|
|
dependency, tail = _read_quoted_value(
|
|
line,
|
|
"project.dependencies entry",
|
|
)
|
|
if tail.startswith(","):
|
|
tail = tail[1:].strip()
|
|
if tail.startswith("]"):
|
|
tail = tail[1:].strip()
|
|
dependencies.append(dependency)
|
|
if tail and not tail.startswith("#"):
|
|
raise ValueError("Unsupported content after project.dependencies")
|
|
return dependencies
|
|
if tail and not tail.startswith("#"):
|
|
raise ValueError("Unsupported content after project.dependencies entry")
|
|
|
|
dependencies.append(dependency)
|
|
continue
|
|
|
|
if line.startswith("[") and line.endswith("]"):
|
|
in_project_section = line == "[project]"
|
|
continue
|
|
|
|
if not in_project_section:
|
|
continue
|
|
|
|
key, separator, raw_value = line.partition("=")
|
|
if key.strip() != "dependencies":
|
|
continue
|
|
if not separator:
|
|
raise ValueError("Unsupported project.dependencies value")
|
|
raw_value = raw_value.strip()
|
|
if raw_value == "[" or raw_value.startswith("[ #"):
|
|
in_dependencies_array = True
|
|
continue
|
|
if raw_value.startswith("["):
|
|
return _read_dependency_array(raw_value)
|
|
raise ValueError("Unsupported project.dependencies value")
|
|
|
|
if in_dependencies_array:
|
|
raise ValueError("Unterminated project.dependencies array")
|
|
raise ValueError("Missing project.dependencies")
|