Control: tags -1 patch
thanks

On Wed, Aug 19, 2020 at 02:46:47PM +0200, Marc Haber wrote:
> Please consider adding this as a feature. Unfortunately, I am not fluent
> enough in python to deliver a patch.

This has changed in the four years that this issue has rotted around in
the BTS. Please find attached a small patch that introduces an
extensible hook mechanism. At the moment, the hook script is only called
at the create stage, which allows me to solve the pressing issue at hand
(enable two foreign architectures inside the container).

A possible hook script is:

#!/usr/bin/python3

import argparse
import subprocess
import sys


def create():
        subprocess.run(["dpkg", "--add-architecture", "armhf"], check=True)
        subprocess.run(["dpkg", "--add-architecture", "arm64"], check=True)

        subprocess.run(["apt", "update"], check=True)
        print("System architecture added and package list updated.")


def main():
        parser = argparse.ArgumentParser(
                description="Setup system architecture and update package list."
        )
        parser.add_argument("command", help="Command to execute (e.g., 
'create')")

        args = parser.parse_args()

        if args.command == "create":
                create()
        else:
                print(f"Unknown command: {args.command}")
                sys.exit(1)


if __name__ == "__main__":
        main()

Greetigns
Marc

diff --git a/debspawn/cli.py b/debspawn/cli.py
index d7fe299..90e97bf 100644
--- a/debspawn/cli.py
+++ b/debspawn/cli.py
@@ -100,6 +100,7 @@ def command_create(options):
         variant=options.variant,
         base_suite=options.base_suite,
         custom_name=options.name,
+        hook_path=options.hook_path,
     )
     r = osbase.create(
         options.mirror,
@@ -450,6 +451,12 @@ def create_parser(formatter_class=None):
         dest='with_init',
         help='Include an init system in this image, so it is bootable.',
     )
+    sp.add_argument(
+        '--hook-path',
+        action='store',
+        dest='hook_path',
+        help='Path to hook script',
+    )
     sp.set_defaults(func=command_create)
 
     # 'delete' command
diff --git a/debspawn/dsrun b/debspawn/dsrun
index 8d6618d..d47d09c 100755
--- a/debspawn/dsrun
+++ b/debspawn/dsrun
@@ -357,6 +357,23 @@ def run_qatasks(qa_lintian=True):
     return True
 
 
+def run_hook(step):
+    ''' Run hook script'''
+    hook_path = "/usr/lib/debspawn/hook"
+    if not os.path.isfile(hook_path):
+        print('ERROR: No hook script here in container')
+        sys.exit(2)
+
+    cmd = [hook_path,
+           step,
+           ]
+    run_command(cmd)
+
+    # run_command will exit the whole program if the command failed,
+    # so we can return True here (everything went fine if we are here)
+    return True
+
+
 def setup_environment(builder_uid=None, use_color=True, use_unicode=True, *, 
is_update=False):
     os.environ['LANG'] = 'C.UTF-8' if use_unicode else 'C'
     os.environ['LC_ALL'] = 'C.UTF-8' if use_unicode else 'C'
@@ -414,6 +431,8 @@ def main():
                         help='Prepare container image for generic script run.')
     parser.add_argument('--run-qa', action='store_true', dest='run_qatasks',
                         help='Run QA tasks (only Lintian currently) against a 
package.')
+    parser.add_argument('--run-hook-create', action='store_true', 
dest='run_hook_create',
+                        help='Run Hook Script after creating container.')
 
     options = parser.parse_args(sys.argv[1:])
 
@@ -449,6 +468,10 @@ def main():
         r = run_qatasks(qa_lintian=options.qa_lintian)
         if not r:
             return 2
+    elif options.run_hook_create:
+        r = run_hook("create")
+        if not r:
+            return 2
     else:
         print('ERROR: No action specified.', file=sys.stderr)
         return 1
diff --git a/debspawn/osbase.py b/debspawn/osbase.py
index 3df261d..ca0044f 100644
--- a/debspawn/osbase.py
+++ b/debspawn/osbase.py
@@ -73,6 +73,7 @@ class OSBase:
         base_suite=None,
         custom_name=None,
         cachekey=None,
+        hook_path=None,
     ):
         self._gconf = gconf
         self._suite = suite
@@ -91,6 +92,7 @@ class OSBase:
         self._cachekey = cachekey
         if self._cachekey:
             self._cachekey = self._cachekey.replace(' ', '')
+        self.hook_path = hook_path
 
         self._parameters_checked = False
         self._aptcache = APTCache(self)
@@ -228,17 +230,23 @@ class OSBase:
         self._results_dir = path
         Path(self._results_dir).mkdir(exist_ok=True)
 
-    def _copy_helper_script(self, osroot_path):
+    def _copy_script(self, source_path, osroot_path, targetfname):
         script_location = os.path.join(osroot_path, 'usr', 'lib', 'debspawn')
         Path(script_location).mkdir(parents=True, exist_ok=True)
-        script_fname = os.path.join(script_location, 'dsrun')
+        script_fname = os.path.join(script_location, targetfname)
 
         if os.path.isfile(script_fname):
             os.remove(script_fname)
-        shutil.copy2(self._gconf.dsrun_path, script_fname)
+        shutil.copy2(source_path, script_fname)
 
         os.chmod(script_fname, 0o0755)
 
+    def _copy_helper_script(self, osroot_path):
+        self._copy_script(self._gconf.dsrun_path, osroot_path, 'dsrun')
+
+    def _copy_hook_script(self, osroot_path):
+        self._copy_script(self.hook_path, osroot_path, 'hook')
+
     def get_image_location(self):
         return os.path.join(self._gconf.osroots_dir, 
'{}.tar.zst'.format(self.name))
 
@@ -494,6 +502,8 @@ class OSBase:
             print('Variant: {}'.format(self.variant))
         if with_init:
             print('Includes init: yes')
+        if self.hook_path:
+            print('Hook Script: {}'.format(self.hook_path))
 
         include_pkgs = ['passwd', 'python3-minimal', 'eatmydata']
         if with_init:
@@ -527,6 +537,10 @@ class OSBase:
             # create helper script runner
             self._copy_helper_script(tdir)
 
+            # copy hook script
+            if self.hook_path:
+                self._copy_hook_script(tdir)
+
             # if we bootstrapped the base suite, add the primary suite to
             # sources.list. We also add any explicit extra suites and source 
lines
             if self.has_base_suite or extra_suites or extra_source_lines:
@@ -634,6 +648,16 @@ class OSBase:
             ):
                 return False
 
+            if self.hook_path:
+                print_section('Run Hook Create')
+                if (
+                    nspawn_run_helper_persist(
+                        self, tdir, self.new_nspawn_machine_name(), 
'--run-hook-create', build_uid=0,
+                    )
+                    != 0
+                ):
+                    return False
+
             # drop any unwanted files (again) before building the tarball
             self._remove_unwanted_files(tdir)
 

Reply via email to