171 lines
6.5 KiB
Python
171 lines
6.5 KiB
Python
# Copyright 2022 Oliver Smith
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
import glob
|
|
import logging
|
|
import os
|
|
import shlex
|
|
import datetime
|
|
|
|
import pmb.chroot
|
|
import pmb.helpers.file
|
|
import pmb.helpers.git
|
|
import pmb.helpers.pmaports
|
|
import pmb.helpers.run
|
|
import pmb.parse.apkindex
|
|
import pmb.parse.version
|
|
|
|
|
|
def copy_to_buildpath(args, package, suffix="native"):
|
|
# Sanity check
|
|
aport = pmb.helpers.pmaports.find(args, package)
|
|
if not os.path.exists(aport + "/APKBUILD"):
|
|
raise ValueError("Path does not contain an APKBUILD file:" +
|
|
aport)
|
|
|
|
# Clean up folder
|
|
build = args.work + "/chroot_" + suffix + "/home/pmos/build"
|
|
if os.path.exists(build):
|
|
pmb.chroot.root(args, ["rm", "-rf", "/home/pmos/build"], suffix)
|
|
|
|
# Copy aport contents with resolved symlinks
|
|
pmb.helpers.run.root(args, ["cp", "-rL", aport + "/", build])
|
|
pmb.chroot.root(args, ["chown", "-R", "pmos:pmos",
|
|
"/home/pmos/build"], suffix)
|
|
|
|
|
|
def is_necessary(args, arch, apkbuild, indexes=None):
|
|
"""
|
|
Check if the package has already been built. Compared to abuild's check,
|
|
this check also works for different architectures.
|
|
|
|
:param arch: package target architecture
|
|
:param apkbuild: from pmb.parse.apkbuild()
|
|
:param indexes: list of APKINDEX.tar.gz paths
|
|
:returns: boolean
|
|
"""
|
|
# Get package name, version, define start of debug message
|
|
package = apkbuild["pkgname"]
|
|
version_new = apkbuild["pkgver"] + "-r" + apkbuild["pkgrel"]
|
|
msg = "Build is necessary for package '" + package + "': "
|
|
|
|
# Get old version from APKINDEX
|
|
index_data = pmb.parse.apkindex.package(args, package, arch, False,
|
|
indexes)
|
|
if not index_data:
|
|
logging.debug(msg + "No binary package available")
|
|
return True
|
|
|
|
# Can't build pmaport for arch: use Alpine's package (#1897)
|
|
if arch and not pmb.helpers.pmaports.check_arches(apkbuild["arch"], arch):
|
|
logging.verbose(f"{package}: build is not necessary, because pmaport"
|
|
" can't be built for {arch}. Using Alpine's binary"
|
|
" package.")
|
|
return False
|
|
|
|
# a) Binary repo has a newer version
|
|
version_old = index_data["version"]
|
|
if pmb.parse.version.compare(version_old, version_new) == 1:
|
|
logging.warning("WARNING: package {}: aport version {} is lower than"
|
|
" {} from the binary repository. {} will be used when"
|
|
" installing {}. See also:"
|
|
" <https://postmarketos.org/warning-repo2>"
|
|
"".format(package, version_new, version_old,
|
|
version_old, package))
|
|
return False
|
|
|
|
# b) Aports folder has a newer version
|
|
if version_new != version_old:
|
|
logging.debug(f"{msg}Binary package out of date (binary: "
|
|
f"{version_old}, aport: {version_new})")
|
|
return True
|
|
|
|
# Aports and binary repo have the same version.
|
|
return False
|
|
|
|
|
|
def index_repo(args, arch=None):
|
|
"""
|
|
Recreate the APKINDEX.tar.gz for a specific repo, and clear the parsing
|
|
cache for that file for the current pmbootstrap session (to prevent
|
|
rebuilding packages twice, in case the rebuild takes less than a second).
|
|
|
|
:param arch: when not defined, re-index all repos
|
|
"""
|
|
pmb.build.init(args)
|
|
|
|
channel = pmb.config.pmaports.read_config(args)["channel"]
|
|
if arch:
|
|
paths = [f"{args.work}/packages/{channel}/{arch}"]
|
|
else:
|
|
paths = glob.glob(f"{args.work}/packages/{channel}/*")
|
|
|
|
for path in paths:
|
|
if os.path.isdir(path):
|
|
path_arch = os.path.basename(path)
|
|
path_repo_chroot = "/home/pmos/packages/pmos/" + path_arch
|
|
logging.debug("(native) index " + path_arch + " repository")
|
|
description = str(datetime.datetime.now())
|
|
commands = [
|
|
# Wrap the index command with sh so we can use '*.apk'
|
|
["sh", "-c", "apk -q index --output APKINDEX.tar.gz_"
|
|
" --description " + shlex.quote(description) + ""
|
|
" --rewrite-arch " + shlex.quote(path_arch) + " *.apk"],
|
|
["abuild-sign", "APKINDEX.tar.gz_"],
|
|
["mv", "APKINDEX.tar.gz_", "APKINDEX.tar.gz"]
|
|
]
|
|
for command in commands:
|
|
pmb.chroot.user(args, command, working_dir=path_repo_chroot)
|
|
else:
|
|
logging.debug("NOTE: Can't build index for: " + path)
|
|
pmb.parse.apkindex.clear_cache(f"{path}/APKINDEX.tar.gz")
|
|
|
|
|
|
def configure_abuild(args, suffix, verify=False):
|
|
"""
|
|
Set the correct JOBS count in abuild.conf
|
|
|
|
:param verify: internally used to test if changing the config has worked.
|
|
"""
|
|
path = args.work + "/chroot_" + suffix + "/etc/abuild.conf"
|
|
prefix = "export JOBS="
|
|
with open(path, encoding="utf-8") as handle:
|
|
for line in handle:
|
|
if not line.startswith(prefix):
|
|
continue
|
|
if line != (prefix + args.jobs + "\n"):
|
|
if verify:
|
|
raise RuntimeError(f"Failed to configure abuild: {path}"
|
|
"\nTry to delete the file"
|
|
"(or zap the chroot).")
|
|
pmb.chroot.root(args, ["sed", "-i", "-e",
|
|
f"s/^{prefix}.*/{prefix}{args.jobs}/",
|
|
"/etc/abuild.conf"],
|
|
suffix)
|
|
configure_abuild(args, suffix, True)
|
|
return
|
|
raise RuntimeError("Could not find " + prefix + " line in " + path)
|
|
|
|
|
|
def configure_ccache(args, suffix="native", verify=False):
|
|
"""
|
|
Set the maximum ccache size
|
|
|
|
:param verify: internally used to test if changing the config has worked.
|
|
"""
|
|
# Check if the settings have been set already
|
|
arch = pmb.parse.arch.from_chroot_suffix(args, suffix)
|
|
path = args.work + "/cache_ccache_" + arch + "/ccache.conf"
|
|
if os.path.exists(path):
|
|
with open(path, encoding="utf-8") as handle:
|
|
for line in handle:
|
|
if line == ("max_size = " + args.ccache_size + "\n"):
|
|
return
|
|
if verify:
|
|
raise RuntimeError("Failed to configure ccache: " + path + "\nTry to"
|
|
" delete the file (or zap the chroot).")
|
|
|
|
# Set the size and verify
|
|
pmb.chroot.user(args, ["ccache", "--max-size", args.ccache_size],
|
|
suffix)
|
|
configure_ccache(args, suffix, True)
|