mirror of
https://gitlab.com/kupfer/kupferbootstrap.git
synced 2025-02-23 05:35:44 -05:00
packages/pkgbuild: parse version specs from dependencies, provides, etc.
handles e.g. "git>=1.0" properly
This commit is contained in:
parent
f16ea1684b
commit
e91a8c796c
1 changed files with 51 additions and 16 deletions
|
@ -6,7 +6,7 @@ import multiprocessing
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from joblib import Parallel, delayed
|
from joblib import Parallel, delayed
|
||||||
from typing import Iterable, Optional
|
from typing import Iterable, Optional, TypeAlias
|
||||||
|
|
||||||
from config import config, ConfigStateHolder
|
from config import config, ConfigStateHolder
|
||||||
from constants import REPOSITORIES
|
from constants import REPOSITORIES
|
||||||
|
@ -62,12 +62,42 @@ def init_pkgbuilds(interactive=False, lazy: bool = True, update: bool = False, s
|
||||||
_pkgbuilds_initialised = True
|
_pkgbuilds_initialised = True
|
||||||
|
|
||||||
|
|
||||||
|
VersionSpec: TypeAlias = Optional[str]
|
||||||
|
VersionSpecs: TypeAlias = dict[str, Optional[list[VersionSpec]]]
|
||||||
|
|
||||||
|
|
||||||
|
def parse_version_spec(spec: str) -> tuple[str, VersionSpec]:
|
||||||
|
for op in ['<', '>', '=']:
|
||||||
|
if op in spec:
|
||||||
|
name, ver = spec.split(op, 1)
|
||||||
|
assert name and ver
|
||||||
|
ver = op + ver
|
||||||
|
if name[-1] == '=':
|
||||||
|
assert op != '='
|
||||||
|
name = name[:-1]
|
||||||
|
ver = '=' + ver
|
||||||
|
return name, ver
|
||||||
|
return spec.strip(), None
|
||||||
|
|
||||||
|
|
||||||
|
def get_version_specs(spec: str, existing_specs: Optional[VersionSpecs] = None) -> VersionSpecs:
|
||||||
|
specs = existing_specs or {}
|
||||||
|
name, ver = parse_version_spec(spec)
|
||||||
|
_specs = specs.get(name, None)
|
||||||
|
if ver:
|
||||||
|
_specs = _specs or []
|
||||||
|
if ver not in _specs:
|
||||||
|
_specs.append(ver)
|
||||||
|
specs[name] = _specs
|
||||||
|
return specs
|
||||||
|
|
||||||
|
|
||||||
class Pkgbuild(PackageInfo):
|
class Pkgbuild(PackageInfo):
|
||||||
name: str
|
name: str
|
||||||
version: str
|
version: str
|
||||||
arches: list[Arch]
|
arches: list[Arch]
|
||||||
depends: list[str]
|
depends: VersionSpecs
|
||||||
provides: list[str]
|
provides: VersionSpecs
|
||||||
replaces: list[str]
|
replaces: list[str]
|
||||||
local_depends: list[str]
|
local_depends: list[str]
|
||||||
repo: str
|
repo: str
|
||||||
|
@ -84,8 +114,8 @@ class Pkgbuild(PackageInfo):
|
||||||
self,
|
self,
|
||||||
relative_path: str,
|
relative_path: str,
|
||||||
arches: list[Arch] = [],
|
arches: list[Arch] = [],
|
||||||
depends: list[str] = [],
|
depends: VersionSpecs = {},
|
||||||
provides: list[str] = [],
|
provides: VersionSpecs = {},
|
||||||
replaces: list[str] = [],
|
replaces: list[str] = [],
|
||||||
repo: Optional[str] = None,
|
repo: Optional[str] = None,
|
||||||
sources_refreshed: bool = False,
|
sources_refreshed: bool = False,
|
||||||
|
@ -98,8 +128,8 @@ class Pkgbuild(PackageInfo):
|
||||||
self.name = os.path.basename(relative_path)
|
self.name = os.path.basename(relative_path)
|
||||||
self.version = ''
|
self.version = ''
|
||||||
self.arches = list(arches)
|
self.arches = list(arches)
|
||||||
self.depends = list(depends)
|
self.depends = dict(depends)
|
||||||
self.provides = list(provides)
|
self.provides = dict(provides)
|
||||||
self.replaces = list(replaces)
|
self.replaces = list(replaces)
|
||||||
self.local_depends = []
|
self.local_depends = []
|
||||||
self.repo = repo or ''
|
self.repo = repo or ''
|
||||||
|
@ -120,8 +150,8 @@ class Pkgbuild(PackageInfo):
|
||||||
self.mode + ')',
|
self.mode + ')',
|
||||||
])
|
])
|
||||||
|
|
||||||
def names(self):
|
def names(self) -> list[str]:
|
||||||
return list(set([self.name] + self.provides + self.replaces))
|
return list({self.name, *self.provides, *self.replaces})
|
||||||
|
|
||||||
def update_version(self):
|
def update_version(self):
|
||||||
"""updates `self.version` from `self.pkgver` and `self.pkgrel`"""
|
"""updates `self.version` from `self.pkgver` and `self.pkgrel`"""
|
||||||
|
@ -130,8 +160,8 @@ class Pkgbuild(PackageInfo):
|
||||||
def update(self, pkg: Pkgbuild):
|
def update(self, pkg: Pkgbuild):
|
||||||
self.version = pkg.version
|
self.version = pkg.version
|
||||||
self.arches = list(pkg.arches)
|
self.arches = list(pkg.arches)
|
||||||
self.depends = list(pkg.depends)
|
self.depends = dict(pkg.depends)
|
||||||
self.provides = list(pkg.provides)
|
self.provides = dict(pkg.provides)
|
||||||
self.replaces = list(pkg.replaces)
|
self.replaces = list(pkg.replaces)
|
||||||
self.local_depends = list(pkg.local_depends)
|
self.local_depends = list(pkg.local_depends)
|
||||||
self.repo = pkg.repo
|
self.repo = pkg.repo
|
||||||
|
@ -193,6 +223,12 @@ class Pkgbase(Pkgbuild):
|
||||||
self.sources_refreshed = True
|
self.sources_refreshed = True
|
||||||
self.update(basepkg)
|
self.update(basepkg)
|
||||||
|
|
||||||
|
def names(self) -> list[str]:
|
||||||
|
names = set(Pkgbuild.names(self))
|
||||||
|
for pkg in self.subpackages:
|
||||||
|
names.update(pkg.names())
|
||||||
|
return list(names)
|
||||||
|
|
||||||
|
|
||||||
class SubPkgbuild(Pkgbuild):
|
class SubPkgbuild(Pkgbuild):
|
||||||
pkgbase: Pkgbase
|
pkgbase: Pkgbase
|
||||||
|
@ -206,7 +242,7 @@ class SubPkgbuild(Pkgbuild):
|
||||||
self.sources_refreshed = False
|
self.sources_refreshed = False
|
||||||
self.update(pkgbase)
|
self.update(pkgbase)
|
||||||
|
|
||||||
self.provides = []
|
self.provides = {}
|
||||||
self.replaces = []
|
self.replaces = []
|
||||||
|
|
||||||
def refresh_sources(self, lazy: bool = True):
|
def refresh_sources(self, lazy: bool = True):
|
||||||
|
@ -272,11 +308,11 @@ def parse_pkgbuild(
|
||||||
elif line.startswith('arch'):
|
elif line.startswith('arch'):
|
||||||
current.arches.append(splits[1])
|
current.arches.append(splits[1])
|
||||||
elif line.startswith('provides'):
|
elif line.startswith('provides'):
|
||||||
current.provides.append(splits[1])
|
current.provides = get_version_specs(splits[1], current.provides)
|
||||||
elif line.startswith('replaces'):
|
elif line.startswith('replaces'):
|
||||||
current.replaces.append(splits[1])
|
current.replaces.append(splits[1])
|
||||||
elif line.startswith('depends') or line.startswith('makedepends') or line.startswith('checkdepends') or line.startswith('optdepends'):
|
elif line.startswith('depends') or line.startswith('makedepends') or line.startswith('checkdepends') or line.startswith('optdepends'):
|
||||||
current.depends.append(splits[1].split('=')[0].split(': ')[0])
|
current.depends = get_version_specs(splits[1].split(': ', 1)[0], current.depends)
|
||||||
|
|
||||||
results: list[Pkgbuild] = list(base_package.subpackages)
|
results: list[Pkgbuild] = list(base_package.subpackages)
|
||||||
if multi_pkgs:
|
if multi_pkgs:
|
||||||
|
@ -285,7 +321,6 @@ def parse_pkgbuild(
|
||||||
base_package.update_version()
|
base_package.update_version()
|
||||||
for pkg in results:
|
for pkg in results:
|
||||||
assert isinstance(pkg, Pkgbuild)
|
assert isinstance(pkg, Pkgbuild)
|
||||||
pkg.depends = list(set(pkg.depends)) # deduplicate dependencies
|
|
||||||
pkg.update_version()
|
pkg.update_version()
|
||||||
if not (pkg.version == base_package.version):
|
if not (pkg.version == base_package.version):
|
||||||
raise Exception(f'Subpackage malformed! Versions differ! base: {base_package}, subpackage: {pkg}')
|
raise Exception(f'Subpackage malformed! Versions differ! base: {base_package}, subpackage: {pkg}')
|
||||||
|
@ -376,7 +411,7 @@ def discover_pkgbuilds(parallel: bool = True, lazy: bool = True, repositories: O
|
||||||
# This filters local_depends to only include the ones that are provided by local PKGBUILDs
|
# This filters local_depends to only include the ones that are provided by local PKGBUILDs
|
||||||
# we need to iterate over the entire cache in case partial scans happened
|
# we need to iterate over the entire cache in case partial scans happened
|
||||||
for package in _pkgbuilds_cache.values():
|
for package in _pkgbuilds_cache.values():
|
||||||
package.local_depends = package.depends.copy()
|
package.local_depends = list(package.depends.keys())
|
||||||
for dep in package.depends.copy():
|
for dep in package.depends.copy():
|
||||||
found = dep in _pkgbuilds_cache
|
found = dep in _pkgbuilds_cache
|
||||||
for pkg in _pkgbuilds_cache.values():
|
for pkg in _pkgbuilds_cache.values():
|
||||||
|
|
Loading…
Add table
Reference in a new issue