generated from coulomb/repo-seed
first usable curator UI
This commit is contained in:
86
src/repo_registry/repo_ingestion/metadata.py
Normal file
86
src/repo_registry/repo_ingestion/metadata.py
Normal file
@@ -0,0 +1,86 @@
|
||||
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"
|
||||
Reference in New Issue
Block a user