2022-08-14 04:14:47 +02:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
from . import logging
|
2022-02-17 05:55:35 +01:00
|
|
|
import os
|
|
|
|
import subprocess
|
|
|
|
|
2022-08-14 04:14:47 +02:00
|
|
|
from typing import Optional, Sequence
|
2022-02-17 05:55:35 +01:00
|
|
|
|
2022-08-14 04:14:47 +02:00
|
|
|
from chroot import Chroot
|
|
|
|
from constants import Arch, CHROOT_PATHS, MAKEPKG_CMD
|
2022-02-20 20:20:34 +01:00
|
|
|
from distro.package import PackageInfo
|
2022-02-17 05:55:35 +01:00
|
|
|
|
|
|
|
|
|
|
|
class Pkgbuild(PackageInfo):
|
2022-08-14 04:14:47 +02:00
|
|
|
name: str
|
|
|
|
version: str
|
|
|
|
arches: list[Arch]
|
2022-02-17 19:34:58 +01:00
|
|
|
depends: list[str]
|
|
|
|
provides: list[str]
|
|
|
|
replaces: list[str]
|
|
|
|
local_depends: list[str]
|
2022-08-14 04:14:47 +02:00
|
|
|
repo: str
|
|
|
|
mode: str
|
|
|
|
path: str
|
|
|
|
pkgver: str
|
|
|
|
pkgrel: str
|
2022-02-17 05:55:35 +01:00
|
|
|
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
relative_path: str,
|
2022-08-14 04:14:47 +02:00
|
|
|
arches: list[Arch] = [],
|
2022-02-17 05:55:35 +01:00
|
|
|
depends: list[str] = [],
|
|
|
|
provides: list[str] = [],
|
2022-02-17 06:08:31 +01:00
|
|
|
replaces: list[str] = [],
|
2022-08-14 04:14:47 +02:00
|
|
|
repo: Optional[str] = None,
|
2022-02-17 05:55:35 +01:00
|
|
|
) -> None:
|
2022-08-14 04:14:47 +02:00
|
|
|
"""
|
|
|
|
Create new Pkgbuild representation for file located at `{relative_path}/PKGBUILD`.
|
|
|
|
`relative_path` will be stored in `self.path`.
|
|
|
|
"""
|
|
|
|
self.name = os.path.basename(relative_path)
|
2022-02-17 19:34:58 +01:00
|
|
|
self.version = ''
|
2022-08-14 04:14:47 +02:00
|
|
|
self.arches = list(arches)
|
|
|
|
self.depends = list(depends)
|
|
|
|
self.provides = list(provides)
|
|
|
|
self.replaces = list(replaces)
|
|
|
|
self.local_depends = []
|
|
|
|
self.repo = repo or ''
|
|
|
|
self.mode = ''
|
2022-02-17 05:55:35 +01:00
|
|
|
self.path = relative_path
|
2022-08-14 04:14:47 +02:00
|
|
|
self.pkgver = ''
|
|
|
|
self.pkgrel = ''
|
2022-02-17 05:55:35 +01:00
|
|
|
|
|
|
|
def __repr__(self):
|
2022-02-20 19:23:28 +01:00
|
|
|
return f'Pkgbuild({self.name},{repr(self.path)},{self.version},{self.mode})'
|
2022-02-17 05:55:35 +01:00
|
|
|
|
|
|
|
def names(self):
|
2022-02-17 06:42:15 +01:00
|
|
|
return list(set([self.name] + self.provides + self.replaces))
|
2022-02-17 05:55:35 +01:00
|
|
|
|
2022-08-14 04:14:47 +02:00
|
|
|
def update_version(self):
|
|
|
|
"""updates `self.version` from `self.pkgver` and `self.pkgrel`"""
|
|
|
|
self.version = f'{self.pkgver}-{self.pkgrel}'
|
|
|
|
|
2022-02-17 05:55:35 +01:00
|
|
|
|
2022-02-17 19:34:58 +01:00
|
|
|
class Pkgbase(Pkgbuild):
|
2022-08-14 04:14:47 +02:00
|
|
|
subpackages: Sequence[SubPkgbuild]
|
2022-02-17 19:34:58 +01:00
|
|
|
|
2022-08-14 04:14:47 +02:00
|
|
|
def __init__(self, relative_path: str, subpackages: Sequence[SubPkgbuild] = [], **args):
|
|
|
|
self.subpackages = list(subpackages)
|
2022-02-17 19:34:58 +01:00
|
|
|
super().__init__(relative_path, **args)
|
|
|
|
|
|
|
|
|
2022-08-14 04:14:47 +02:00
|
|
|
class SubPkgbuild(Pkgbuild):
|
|
|
|
pkgbase: Pkgbase
|
|
|
|
|
|
|
|
def __init__(self, name: str, pkgbase: Pkgbase):
|
|
|
|
|
|
|
|
self.name = name
|
|
|
|
self.pkgbase = pkgbase
|
|
|
|
|
|
|
|
self.version = pkgbase.version
|
|
|
|
self.arches = pkgbase.arches
|
|
|
|
self.depends = list(pkgbase.depends)
|
|
|
|
self.provides = []
|
|
|
|
self.replaces = []
|
|
|
|
self.local_depends = list(pkgbase.local_depends)
|
|
|
|
self.repo = pkgbase.repo
|
|
|
|
self.mode = pkgbase.mode
|
|
|
|
self.path = pkgbase.path
|
|
|
|
self.pkgver = pkgbase.pkgver
|
|
|
|
self.pkgrel = pkgbase.pkgrel
|
|
|
|
|
|
|
|
|
|
|
|
def parse_pkgbuild(relative_pkg_dir: str, native_chroot: Chroot) -> Sequence[Pkgbuild]:
|
|
|
|
filename = os.path.join(native_chroot.get_path(CHROOT_PATHS['pkgbuilds']), relative_pkg_dir, 'PKGBUILD')
|
|
|
|
logging.debug(f"Parsing {filename}")
|
2022-02-17 05:55:35 +01:00
|
|
|
mode = None
|
2022-08-14 04:14:47 +02:00
|
|
|
with open(filename, 'r') as file:
|
2022-02-17 05:55:35 +01:00
|
|
|
for line in file.read().split('\n'):
|
|
|
|
if line.startswith('_mode='):
|
|
|
|
mode = line.split('=')[1]
|
|
|
|
break
|
|
|
|
if mode not in ['host', 'cross']:
|
|
|
|
raise Exception((f'{relative_pkg_dir}/PKGBUILD has {"no" if mode is None else "an invalid"} mode configured') +
|
|
|
|
(f': "{mode}"' if mode is not None else ''))
|
|
|
|
|
2022-02-17 19:34:58 +01:00
|
|
|
base_package = Pkgbase(relative_pkg_dir)
|
2022-02-17 05:55:35 +01:00
|
|
|
base_package.mode = mode
|
|
|
|
base_package.repo = relative_pkg_dir.split('/')[0]
|
|
|
|
srcinfo = native_chroot.run_cmd(
|
|
|
|
MAKEPKG_CMD + ['--printsrcinfo'],
|
|
|
|
cwd=os.path.join(CHROOT_PATHS['pkgbuilds'], base_package.path),
|
|
|
|
stdout=subprocess.PIPE,
|
|
|
|
)
|
2022-02-18 06:32:04 +01:00
|
|
|
assert (isinstance(srcinfo, subprocess.CompletedProcess))
|
2022-02-17 05:55:35 +01:00
|
|
|
lines = srcinfo.stdout.decode('utf-8').split('\n')
|
|
|
|
|
2022-08-14 04:14:47 +02:00
|
|
|
current: Pkgbuild = base_package
|
2022-02-17 05:55:35 +01:00
|
|
|
multi_pkgs = False
|
|
|
|
for line_raw in lines:
|
|
|
|
line = line_raw.strip()
|
|
|
|
if not line:
|
|
|
|
continue
|
|
|
|
splits = line.split(' = ')
|
|
|
|
if line.startswith('pkgbase'):
|
|
|
|
base_package.name = splits[1]
|
|
|
|
multi_pkgs = True
|
|
|
|
elif line.startswith('pkgname'):
|
|
|
|
if multi_pkgs:
|
2022-08-14 04:14:47 +02:00
|
|
|
current = SubPkgbuild(splits[1], base_package)
|
|
|
|
assert isinstance(base_package.subpackages, list)
|
2022-08-08 23:52:55 +02:00
|
|
|
base_package.subpackages.append(current)
|
2022-08-14 04:14:47 +02:00
|
|
|
else:
|
|
|
|
current.name = splits[1]
|
2022-02-17 05:55:35 +01:00
|
|
|
elif line.startswith('pkgver'):
|
|
|
|
current.pkgver = splits[1]
|
|
|
|
elif line.startswith('pkgrel'):
|
|
|
|
current.pkgrel = splits[1]
|
2022-08-14 04:14:47 +02:00
|
|
|
elif line.startswith('arch'):
|
|
|
|
current.arches.append(splits[1])
|
2022-02-17 05:55:35 +01:00
|
|
|
elif line.startswith('provides'):
|
|
|
|
current.provides.append(splits[1])
|
2022-02-17 06:08:31 +01:00
|
|
|
elif line.startswith('replaces'):
|
|
|
|
current.replaces.append(splits[1])
|
2022-02-17 05:55:35 +01:00
|
|
|
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])
|
|
|
|
|
2022-08-14 04:14:47 +02:00
|
|
|
results: Sequence[Pkgbuild] = list(base_package.subpackages)
|
|
|
|
if len(results) > 1:
|
|
|
|
logging.debug(f" Split package detected: {base_package.name}: {results}")
|
|
|
|
base_package.update_version()
|
|
|
|
else:
|
|
|
|
results = [base_package]
|
2022-02-17 05:55:35 +01:00
|
|
|
|
2022-08-14 04:14:47 +02:00
|
|
|
for pkg in results:
|
|
|
|
assert isinstance(pkg, Pkgbuild)
|
|
|
|
pkg.depends = list(set(pkg.depends)) # deduplicate dependencies
|
|
|
|
pkg.update_version()
|
|
|
|
if not (pkg.version == base_package.version):
|
|
|
|
raise Exception(f'Subpackage malformed! Versions differ! base: {base_package}, subpackage: {pkg}')
|
2022-02-17 05:55:35 +01:00
|
|
|
return results
|