|
24 | 24 |
|
25 | 25 | from __future__ import annotations |
26 | 26 |
|
| 27 | +import re |
27 | 28 | import string |
28 | 29 | from collections import namedtuple |
29 | 30 | from collections.abc import Mapping |
@@ -469,6 +470,40 @@ def to_string(self, encode: bool | None = True) -> str: |
469 | 470 |
|
470 | 471 | return "".join(purl) |
471 | 472 |
|
| 473 | + |
| 474 | + @classmethod |
| 475 | + def validate_alpm(cls): |
| 476 | + """Type-specific validation for ALPM PURLs.""" |
| 477 | + if cls.namespace.lower() != cls.namespace: |
| 478 | + return False, "Namespace must be lowercase." |
| 479 | + if cls.name.lower() != cls.name: |
| 480 | + return False, "Package name must be lowercase." |
| 481 | + if not re.match(r"^[0-9]*:?[\w\.\+\-]+$", cls.version): |
| 482 | + return False, f"Invalid version format '{cls.version}'." |
| 483 | + |
| 484 | + if cls.qualifiers: |
| 485 | + for key in cls.qualifiers: |
| 486 | + if key != "arch": |
| 487 | + return False, f"Unknown qualifier '{key}', only 'arch' is allowed." |
| 488 | + if not cls.qualifiers[key]: |
| 489 | + return False, "Qualifier 'arch' cannot be empty." |
| 490 | + |
| 491 | + |
| 492 | + @classmethod |
| 493 | + def validate(cls): |
| 494 | + """ |
| 495 | + Main validation function. |
| 496 | + Runs basic validation first, then dispatches to type-specific validators. |
| 497 | + Yields error messages only. |
| 498 | + """ |
| 499 | + yield from cls.validate_basic() |
| 500 | + |
| 501 | + validator_by_type: dict[str, Callable[[str], Iterable[str]]] = { |
| 502 | + "alpm": cls.validate_alpm, |
| 503 | + } |
| 504 | + |
| 505 | + yield from validator_by_type() |
| 506 | + |
472 | 507 | @classmethod |
473 | 508 | def from_string(cls, purl: str) -> Self: |
474 | 509 | """ |
|
0 commit comments