generated from coulomb/repo-seed
87 lines
3.1 KiB
Python
87 lines
3.1 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
import tomllib
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
from urllib.parse import urlparse
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class RepositoryMetadata:
|
|
name: str
|
|
description: str | None
|
|
|
|
|
|
class RepositoryMetadataExtractor:
|
|
def extract(self, source_path: str | Path, url: str) -> RepositoryMetadata:
|
|
root = Path(source_path)
|
|
pyproject = self._from_pyproject(root)
|
|
package = self._from_package_json(root)
|
|
readme = self._from_readme(root)
|
|
fallback_name = self._name_from_url_or_path(url)
|
|
|
|
return RepositoryMetadata(
|
|
name=pyproject.name or package.name or readme.name or fallback_name,
|
|
description=(
|
|
pyproject.description
|
|
or package.description
|
|
or readme.description
|
|
),
|
|
)
|
|
|
|
def _from_pyproject(self, root: Path) -> RepositoryMetadata:
|
|
path = root / "pyproject.toml"
|
|
if not path.exists():
|
|
return RepositoryMetadata(name="", description=None)
|
|
try:
|
|
project = tomllib.loads(path.read_text(encoding="utf-8")).get("project", {})
|
|
except (OSError, tomllib.TOMLDecodeError):
|
|
return RepositoryMetadata(name="", description=None)
|
|
return RepositoryMetadata(
|
|
name=str(project.get("name") or ""),
|
|
description=project.get("description"),
|
|
)
|
|
|
|
def _from_package_json(self, root: Path) -> RepositoryMetadata:
|
|
path = root / "package.json"
|
|
if not path.exists():
|
|
return RepositoryMetadata(name="", description=None)
|
|
try:
|
|
package = json.loads(path.read_text(encoding="utf-8"))
|
|
except (OSError, json.JSONDecodeError):
|
|
return RepositoryMetadata(name="", description=None)
|
|
return RepositoryMetadata(
|
|
name=str(package.get("name") or ""),
|
|
description=package.get("description"),
|
|
)
|
|
|
|
def _from_readme(self, root: Path) -> RepositoryMetadata:
|
|
for readme in sorted(root.glob("README*")):
|
|
if not readme.is_file():
|
|
continue
|
|
try:
|
|
lines = readme.read_text(encoding="utf-8", errors="ignore").splitlines()
|
|
except OSError:
|
|
continue
|
|
title = ""
|
|
for line in lines:
|
|
stripped = line.strip()
|
|
cleaned = stripped.strip("#").strip()
|
|
if stripped.startswith("#") and cleaned and not title:
|
|
title = cleaned
|
|
continue
|
|
if cleaned:
|
|
return RepositoryMetadata(name=title, description=cleaned)
|
|
if title:
|
|
return RepositoryMetadata(name=title, description=None)
|
|
return RepositoryMetadata(name="", description=None)
|
|
|
|
def _name_from_url_or_path(self, value: str) -> str:
|
|
parsed = urlparse(value)
|
|
path = parsed.path if parsed.scheme else value
|
|
name = Path(path.rstrip("/")).name or "repository"
|
|
if name.endswith(".git"):
|
|
name = name[:-4]
|
|
return name or "repository"
|