mirror of
https://github.com/truenas/scale-build.git
synced 2025-12-20 02:49:28 +00:00
173 lines
6.4 KiB
Python
173 lines
6.4 KiB
Python
import json
|
|
import logging
|
|
import os
|
|
|
|
from scale_build.exceptions import CallError
|
|
from scale_build.utils.run import run
|
|
from scale_build.utils.paths import HASH_DIR, PKG_LOG_DIR, SOURCES_DIR
|
|
|
|
from .binary_package import BinaryPackage
|
|
from .bootstrap import BootstrapMixin
|
|
from .build import BuildPackageMixin
|
|
from .clean import BuildCleanMixin
|
|
from .git import GitPackageMixin
|
|
from .overlay import OverlayMixin
|
|
from .utils import (
|
|
DEPENDS_SCRIPT_PATH, gather_build_time_dependencies, get_normalized_build_constraint_value,
|
|
get_normalized_specified_build_constraint_value, normalize_build_depends, normalize_bin_packages_depends,
|
|
)
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class Package(BootstrapMixin, BuildPackageMixin, BuildCleanMixin, GitPackageMixin, OverlayMixin):
|
|
def __init__(
|
|
self, name, branch, repo, prebuildcmd=None, kernel_module=False, explicit_deps=None,
|
|
generate_version=True, predepscmd=None, deps_path=None, subdir=None, deoptions=None, jobs=None,
|
|
buildcmd=None, tmpfs=True, tmpfs_size=12, batch_priority=100, env=None, identity_file_path=None,
|
|
build_constraints=None, debian_fork=False,
|
|
):
|
|
self.name = name
|
|
self.branch = branch
|
|
self.origin = repo
|
|
self.prebuildcmd = prebuildcmd or []
|
|
self.buildcmd = buildcmd or []
|
|
self.build_constraints = build_constraints or []
|
|
self.kernel_module = kernel_module
|
|
self.explicit_deps = set(explicit_deps or set())
|
|
self.generate_version = generate_version
|
|
self.predepscmd = predepscmd or []
|
|
self.deps_path = deps_path
|
|
self.subdir = subdir
|
|
self.identity_file_path = identity_file_path
|
|
self.deoptions = deoptions
|
|
self.jobs = jobs
|
|
self.tmpfs = tmpfs
|
|
self.tmpfs_size = tmpfs_size
|
|
self.initialized_deps = False
|
|
self._binary_packages = []
|
|
self.build_depends = set()
|
|
self.source_package = None
|
|
self.parent_changed = False
|
|
self.force_build = False
|
|
self._build_time_dependencies = None
|
|
self.build_stage = None
|
|
self.logger = logger
|
|
self.children = set()
|
|
self.batch_priority = batch_priority
|
|
self.env = env or {}
|
|
self.debian_fork = debian_fork
|
|
|
|
def __eq__(self, other):
|
|
return other == self.name if isinstance(other, str) else self.name == other.name
|
|
|
|
@property
|
|
def log_file_path(self):
|
|
return os.path.join(PKG_LOG_DIR, f'{self.name}.log')
|
|
|
|
@property
|
|
def package_path(self):
|
|
pkg_path = self.source_path
|
|
if self.subdir:
|
|
pkg_path = os.path.join(pkg_path, self.subdir)
|
|
return pkg_path
|
|
|
|
@property
|
|
def debian_control_file_path(self):
|
|
if self.deps_path:
|
|
return os.path.join(self.package_path, self.deps_path, 'control')
|
|
else:
|
|
return os.path.join(self.package_path, 'debian/control')
|
|
|
|
@property
|
|
def source_path(self):
|
|
return os.path.join(SOURCES_DIR, self.name)
|
|
|
|
@property
|
|
def binary_packages(self):
|
|
if self._binary_packages:
|
|
return self._binary_packages
|
|
|
|
if self.name == 'kernel' or (self.predepscmd and not self.deps_path):
|
|
# We cannot determine dependency of this package because it does not probably have a control file
|
|
# in it's current state - the only example we have is grub right now. Let's improve this if there are
|
|
# more examples
|
|
self._binary_packages.append(BinaryPackage(self.name, self.build_depends, self.name, self.name, set()))
|
|
return self._binary_packages
|
|
|
|
cp = run([DEPENDS_SCRIPT_PATH, self.debian_control_file_path], log=False)
|
|
info = json.loads(cp.stdout)
|
|
default_dependencies = {'kernel'} if self.kernel_module else set()
|
|
self.build_depends = set(
|
|
normalize_build_depends(info['source_package']['build_depends'])
|
|
) | default_dependencies
|
|
self.source_package = info['source_package']['name']
|
|
for bin_package in info['binary_packages']:
|
|
self._binary_packages.append(BinaryPackage(
|
|
bin_package['name'], self.build_depends, self.source_package, self.name,
|
|
set(normalize_bin_packages_depends(bin_package['depends'] or ''))
|
|
))
|
|
if self.name == 'truenas':
|
|
self._binary_packages[-1].build_dependencies |= self._binary_packages[-1].install_dependencies
|
|
|
|
return self._binary_packages
|
|
|
|
def build_time_dependencies(self, all_binary_packages=None):
|
|
if self._build_time_dependencies is not None:
|
|
return self._build_time_dependencies
|
|
elif not all_binary_packages:
|
|
raise CallError('Binary packages must be specified when computing build time dependencies')
|
|
|
|
self._build_time_dependencies = gather_build_time_dependencies(
|
|
all_binary_packages, set(), self.build_depends
|
|
) | self.explicit_deps
|
|
return self._build_time_dependencies
|
|
|
|
@property
|
|
def hash_changed(self):
|
|
if self.name == 'truenas':
|
|
# truenas is special and we want to rebuild it always
|
|
# TODO: Do see why that is so
|
|
return True
|
|
|
|
source_hash = self.source_hash
|
|
existing_hash = None
|
|
if os.path.exists(self.hash_path):
|
|
with open(self.hash_path, 'r') as f:
|
|
existing_hash = f.read().strip()
|
|
if source_hash == existing_hash:
|
|
return run(
|
|
['git', '-C', self.source_path, 'diff-files', '--quiet', '--ignore-submodules'], check=False, log=False
|
|
).returncode != 0
|
|
else:
|
|
return True
|
|
|
|
@property
|
|
def source_hash(self):
|
|
return run(['git', '-C', self.source_path, 'rev-parse', '--verify', 'HEAD'], log=False).stdout.strip()
|
|
|
|
@property
|
|
def rebuild(self):
|
|
return self.hash_changed or self.parent_changed
|
|
|
|
@property
|
|
def hash_path(self):
|
|
return os.path.join(HASH_DIR, f'{self.name}.hash')
|
|
|
|
@property
|
|
def exists(self):
|
|
return os.path.exists(self.source_path)
|
|
|
|
@property
|
|
def pkglist_hash_file_path(self):
|
|
return os.path.join(HASH_DIR, f'{self.name}.pkglist')
|
|
|
|
@property
|
|
def to_build(self):
|
|
return all(
|
|
get_normalized_build_constraint_value(constraint) == get_normalized_specified_build_constraint_value(
|
|
constraint
|
|
) for constraint in self.build_constraints
|
|
) if self.build_constraints else True
|