[RFC,5/5] isar: Add external builder

Message ID 20220225074040.20975-6-amikan@ilbers.de
State RFC
Headers show
Series Debian dependencies investigation | expand

Commit Message

Anton Mikanovich Feb. 24, 2022, 9:40 p.m. UTC
Build Isar with external tool to parce all Debian package dependencies.
Support only one target build for now,
mc:qemuamd64-bullseye:isar-image-base is used by default.

Usage (inside build dir):
$ ../isar_builder.py

Signed-off-by: Anton Mikanovich <amikan@ilbers.de>
---
 isar_builder.py | 142 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 142 insertions(+)
 create mode 100755 isar_builder.py

Patch

diff --git a/isar_builder.py b/isar_builder.py
new file mode 100755
index 0000000..cf99c52
--- /dev/null
+++ b/isar_builder.py
@@ -0,0 +1,142 @@ 
+#!/usr/bin/env python3
+
+import os
+import sys
+import apt_pkg
+import apt.progress.base
+
+sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)) + '/bitbake/lib')
+
+import bb.tinfoil
+
+class IsarBuilder:
+    def __init__(self):
+        self.tinfoil = bb.tinfoil.Tinfoil()
+        self.tinfoil.prepare()
+
+    def create_apt_rootfs(self, rootfs):
+        repo_isar_dir = '%s/tmp/deploy/isar-apt/%s-%s/apt' % (os.path.abspath(os.getcwd()), self.distro, self.arch)
+        mirror = 'file://%s/%s' % (repo_isar_dir, self.distro)
+        codename = 'isar'
+
+        if not os.path.exists(rootfs + '/var/lib/dpkg'):
+            os.makedirs(rootfs + '/var/lib/dpkg')
+        open(rootfs + '/var/lib/dpkg/status', 'w').close()
+
+        if not os.path.exists(rootfs + '/etc/apt/preferences.d'):
+            os.makedirs(rootfs + '/etc/apt/preferences.d')
+        with open(rootfs + '/etc/apt/sources.list', 'w') as f:
+            f.write('deb [arch=%s] %s %s main\n' % (self.arch, mirror, codename))
+            f.write('deb-src [arch=%s] %s %s main\n' % (self.arch, mirror, codename))
+
+        if not os.path.exists(rootfs + '/var/cache/apt/archives/partial'):
+            os.makedirs(rootfs + '/var/cache/apt/archives/partial')
+
+    def apt_config(self):
+        apt_pkg.init()
+
+        rootfs = os.path.abspath(os.getcwd()) + '/tmp/deps_poc_rootfs/%s-%s' % (self.distro, self.arch)
+
+        if not os.path.isdir(rootfs):
+            self.create_apt_rootfs(rootfs)
+
+        apt_pkg.config.set('APT::Architecture', self.arch)
+        apt_pkg.config.set('Dir', rootfs)
+        apt_pkg.config.set('Dir::Cache', rootfs + '/var/cache/apt')
+        apt_pkg.config.set('Dir::State::status', rootfs + '/var/lib/dpkg/status')
+
+        apt_pkg.config.set("Acquire::AllowInsecureRepositories", "1")
+
+    def isar_apt_update(self):
+        sources = apt_pkg.SourceList()
+        sources.read_main_list()
+
+        progress = apt.progress.text.AcquireProgress()
+
+        self.cache = apt_pkg.Cache()
+        self.cache.update(progress, sources)
+        self.cache = apt_pkg.Cache()
+
+    def srcpackage_lookup(self, pkg):
+        if pkg in self.cache:
+            return
+        if self.tinfoil.find_best_provider(pkg)[3] is None:
+            return
+        if pkg not in self.target_deps:
+            self.need_deb.append(pkg)
+        self.sr.restart()
+        if self.sr.lookup(pkg) is None:
+            self.need_source.append(pkg)
+            return
+        if 'Build-Depends' not in self.sr.build_depends:
+            return
+        for dep in self.sr.build_depends['Build-Depends']:
+            child = str(dep[0][0])
+            if child not in self.checkdeps:
+                self.checkdeps.append(child)
+                self.srcpackage_lookup(child)
+
+    def bitbake(self, mc, targets, task='', justbuild=[]):
+        targets = [targets] if isinstance(targets, str) else targets
+        target_str = ''
+        for pn in targets:
+            target_str += 'mc:%s:%s ' % (mc, pn if not task else ':'.join([pn, task]))
+        targets.clear()
+        for pn in justbuild:
+            target_str += 'mc:%s:%s ' % (mc, pn)
+        justbuild.clear()
+        if target_str != '':
+            print('Building %s' % target_str)
+            self.tinfoil.build_targets(target_str)
+
+    def build(self, mc, target):
+        d = self.tinfoil.parse_recipe('multiconfig:%s:%s' % (mc, target))
+        self.distro = d.getVar('DISTRO', expand=True)
+        self.arch = d.getVar('DISTRO_ARCH', expand=True)
+
+        recipecache = self.tinfoil.cooker.recipecaches[mc]
+        provider = self.tinfoil.find_best_provider('multiconfig:%s:%s' % (mc, target))
+        self.target_deps = recipecache.deps[provider[3]]
+
+        kernel_image = d.getVar('KERNEL_IMAGE_PKG', expand=True) or ''
+        if kernel_image in self.target_deps:
+            kernel = self.tinfoil.find_best_provider('multiconfig:%s:%s' % (mc, kernel_image))
+            if kernel[3].endswith('linux-distro.bb'):
+                self.target_deps.remove(kernel_image)
+                print('Remove %s from checking' % kernel_image)
+
+        self.need_source = self.target_deps.copy()
+        self.need_deb = []
+
+        self.apt_config()
+
+        maxdepth = 3
+        while maxdepth > 0:
+            maxdepth -= 1
+
+            self.bitbake(mc, self.need_source, 'do_deploy_source', self.need_deb)
+
+            self.isar_apt_update()
+            self.sr = apt_pkg.SourceRecords()
+
+            self.checkdeps = []
+            for dep in self.target_deps:
+                if dep not in self.checkdeps:
+                    self.checkdeps.append(dep)
+                    self.srcpackage_lookup(dep)
+
+            if not self.need_source:
+                break
+
+        if self.need_source:
+            print('Following packages still left unchecked: ' + str(self.need_source))
+
+        if self.need_deb:
+            print('Additional Debian dependencies found:' + str(self.need_deb))
+            self.bitbake(mc, self.need_deb)
+
+        # start final build
+        self.bitbake(mc, target)
+
+ib = IsarBuilder()
+ib.build('qemuamd64-bullseye', 'isar-image-base')