diff --git a/stages/org.osbuild.debian.source b/stages/org.osbuild.debian.source new file mode 100644 index 00000000..8033b407 --- /dev/null +++ b/stages/org.osbuild.debian.source @@ -0,0 +1,132 @@ +#!/usr/bin/python3 +import os +import sys +import subprocess +import json +import tempfile +import shutil + +import osbuild.api + + +def download_source_package(package_name, suite, mirror, output_dir): + """Download Debian source package""" + + # Create temporary directory for download + with tempfile.TemporaryDirectory() as temp_dir: + os.chdir(temp_dir) + + # Use apt-get source to download package + cmd = ["apt-get", "source", package_name] + + print(f"Downloading source package: {' '.join(cmd)}") + + result = subprocess.run(cmd, capture_output=True, text=True) + if result.returncode != 0: + print(f"Error downloading source package:") + print(f"stdout: {result.stdout}") + print(f"stderr: {result.stderr}") + return False + + # Copy downloaded files to output directory + for file in os.listdir("."): + src = os.path.join(temp_dir, file) + dst = os.path.join(output_dir, file) + + if os.path.isdir(file): + shutil.copytree(src, dst) + else: + shutil.copy2(src, dst) + + print(f"Copied: {file}") + + return True + + +def setup_apt_sources(tree, suite, mirror, components=None): + """Set up apt sources for the specified suite""" + + if components is None: + components = ["main", "contrib", "non-free"] + + sources_content = f"""deb {mirror} {suite} {' '.join(components)} +deb {mirror} {suite}-updates {' '.join(components)} +deb {mirror} {suite}-security {' '.join(components)} +""" + + sources_path = os.path.join(tree, "etc/apt/sources.list") + os.makedirs(os.path.dirname(sources_path), exist_ok=True) + + with open(sources_path, "w") as f: + f.write(sources_content) + + print(f"Created sources.list for {suite}") + + +def update_package_lists(tree): + """Update package lists""" + + cmd = ["chroot", tree, "apt-get", "update"] + + print("Updating package lists...") + + result = subprocess.run(cmd, capture_output=True, text=True) + if result.returncode != 0: + print(f"Error updating package lists:") + print(f"stdout: {result.stdout}") + print(f"stderr: {result.stderr}") + return False + + print("Package lists updated successfully") + return True + + +def main(tree, options): + """Main function for debian source stage""" + + # Get options + package_name = options.get("package") + suite = options.get("suite", "bookworm") + mirror = options.get("mirror", "http://deb.debian.org/debian") + components = options.get("components", ["main", "contrib", "non-free"]) + output_dir = options.get("output_dir", ".") + + if not package_name: + print("No package name specified") + return 1 + + # Create output directory + os.makedirs(output_dir, exist_ok=True) + + # Set up apt sources + setup_apt_sources(tree, suite, mirror, components) + + # Update package lists + if not update_package_lists(tree): + return 1 + + # Download source package + if not download_source_package(package_name, suite, mirror, output_dir): + return 1 + + # Write source info + source_info = { + "package": package_name, + "suite": suite, + "mirror": mirror, + "components": components, + "output_dir": output_dir + } + + info_file = os.path.join(output_dir, "debian-source.json") + with open(info_file, "w") as f: + json.dump(source_info, f, indent=2) + + print(f"Source package {package_name} downloaded successfully") + return 0 + + +if __name__ == '__main__': + args = osbuild.api.arguments() + r = main(args["tree"], args["options"]) + sys.exit(r) diff --git a/stages/org.osbuild.debian.source.meta.json b/stages/org.osbuild.debian.source.meta.json new file mode 100644 index 00000000..a01e3334 --- /dev/null +++ b/stages/org.osbuild.debian.source.meta.json @@ -0,0 +1,57 @@ +{ + "name": "org.osbuild.debian.source", + "version": "1", + "description": "Download and manage Debian source packages", + "options": { + "type": "object", + "properties": { + "package": { + "type": "string", + "description": "Name of the Debian source package to download" + }, + "suite": { + "type": "string", + "default": "bookworm", + "description": "Debian suite for the package" + }, + "mirror": { + "type": "string", + "default": "http://deb.debian.org/debian", + "description": "Debian mirror for package sources" + }, + "components": { + "type": "array", + "items": { + "type": "string" + }, + "default": ["main", "contrib", "non-free"], + "description": "Debian repository components to use" + }, + "output_dir": { + "type": "string", + "default": ".", + "description": "Directory for downloaded source packages" + } + }, + "required": ["package"] + }, + "inputs": { + "type": "object", + "additionalProperties": false + }, + "devices": { + "type": "object", + "additionalProperties": false + }, + "mounts": { + "type": "object", + "additionalProperties": false + }, + "capabilities": { + "type": "array", + "items": { + "type": "string" + }, + "default": ["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_FOWNER", "CAP_FSETID", "CAP_MKNOD", "CAP_SETGID", "CAP_SETUID"] + } +} diff --git a/stages/org.osbuild.sbuild b/stages/org.osbuild.sbuild new file mode 100644 index 00000000..502d1102 --- /dev/null +++ b/stages/org.osbuild.sbuild @@ -0,0 +1,144 @@ +#!/usr/bin/python3 +import os +import sys +import subprocess +import tempfile +import shutil +import json + +import osbuild.api + + +def run_sbuild_command(cmd, cwd=None, env=None): + """Run sbuild command and return result""" + if env is None: + env = {} + + result = subprocess.run(cmd, cwd=cwd, env=env, capture_output=True, text=True) + + if result.returncode != 0: + print(f"Error running sbuild command: {' '.join(cmd)}") + print(f"stdout: {result.stdout}") + print(f"stderr: {result.stderr}") + return False, result.stderr + + return True, result.stdout + + +def create_sbuild_chroot(tree, suite, arch, mirror): + """Create sbuild chroot for building packages""" + + chroot_name = f"{suite}-{arch}-sbuild" + + # Create sbuild chroot + cmd = ["sbuild-createchroot", "--arch", arch, suite, chroot_name, mirror] + + print(f"Creating sbuild chroot: {' '.join(cmd)}") + + success, output = run_sbuild_command(cmd) + if not success: + return False, None + + print(f"Created sbuild chroot: {chroot_name}") + return True, chroot_name + + +def build_package_with_sbuild(chroot_name, source_dir, output_dir): + """Build package using sbuild""" + + # Change to source directory + os.chdir(source_dir) + + # Run sbuild + cmd = ["sbuild", "--arch", "amd64", "--dist", chroot_name.split("-")[0], "."] + + print(f"Building package with sbuild: {' '.join(cmd)}") + + success, output = run_sbuild_command(cmd) + if not success: + return False + + # Copy built packages to output directory + for file in os.listdir("."): + if file.endswith(".deb") or file.endswith(".dsc") or file.endswith(".tar.gz"): + src = os.path.join(source_dir, file) + dst = os.path.join(output_dir, file) + shutil.copy2(src, dst) + print(f"Copied: {file}") + + return True + + +def setup_sbuild_config(tree, chroot_name): + """Set up sbuild configuration for the chroot""" + + sbuild_conf_dir = f"{tree}/etc/sbuild" + os.makedirs(sbuild_conf_dir, exist_ok=True) + + # Create sbuild configuration + sbuild_conf = f"""# sbuild configuration for {chroot_name} +$build_environment = 'chroot'; +$build_arch_all = 1; +$build_source = 1; +$build_binary = 1; +$build_arch_any = 1; +$build_indep = 1; +$build_dep = 1; +$build_conf = 1; +$build_progress = 1; +$build_verbose = 1; +""" + + conf_file = os.path.join(sbuild_conf_dir, "sbuild.conf") + with open(conf_file, "w") as f: + f.write(sbuild_conf) + + print(f"Created sbuild configuration: {conf_file}") + + +def main(tree, options): + """Main function for sbuild stage""" + + # Get options + suite = options.get("suite", "bookworm") + arch = options.get("arch", "amd64") + mirror = options.get("mirror", "http://deb.debian.org/debian") + source_dir = options.get("source_dir", ".") + output_dir = options.get("output_dir", ".") + + # Create output directory + os.makedirs(output_dir, exist_ok=True) + + # Create sbuild chroot + success, chroot_name = create_sbuild_chroot(tree, suite, arch, mirror) + if not success: + return 1 + + # Set up sbuild configuration + setup_sbuild_config(tree, chroot_name) + + # Build package + if not build_package_with_sbuild(chroot_name, source_dir, output_dir): + return 1 + + # Write build info + build_info = { + "chroot": chroot_name, + "suite": suite, + "arch": arch, + "mirror": mirror, + "output_dir": output_dir + } + + info_file = os.path.join(output_dir, "sbuild-build.json") + with open(info_file, "w") as f: + json.dump(build_info, f, indent=2) + + print("sbuild package building completed successfully") + return 0 + + +if __name__ == '__main__': + args = osbuild.api.arguments() + r = main(args["tree"], args["options"]) + sys.exit(r) diff --git a/stages/org.osbuild.sbuild.meta.json b/stages/org.osbuild.sbuild.meta.json new file mode 100644 index 00000000..ec59d0d9 --- /dev/null +++ b/stages/org.osbuild.sbuild.meta.json @@ -0,0 +1,54 @@ +{ + "name": "org.osbuild.sbuild", + "version": "1", + "description": "Build Debian packages using sbuild chroot environments", + "options": { + "type": "object", + "properties": { + "suite": { + "type": "string", + "default": "bookworm", + "description": "Debian suite for the build environment" + }, + "arch": { + "type": "string", + "default": "amd64", + "description": "Target architecture for building" + }, + "mirror": { + "type": "string", + "default": "http://deb.debian.org/debian", + "description": "Debian mirror for chroot creation" + }, + "source_dir": { + "type": "string", + "default": ".", + "description": "Directory containing package source" + }, + "output_dir": { + "type": "string", + "default": ".", + "description": "Directory for built packages" + } + } + }, + "inputs": { + "type": "object", + "additionalProperties": false + }, + "devices": { + "type": "object", + "additionalProperties": false + }, + "mounts": { + "type": "object", + "additionalProperties": false + }, + "capabilities": { + "type": "array", + "items": { + "type": "string" + }, + "default": ["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_FOWNER", "CAP_FSETID", "CAP_MKNOD", "CAP_SETGID", "CAP_SETUID", "CAP_SYS_CHROOT"] + } +}