From 72ac6c2b4f6174ab4b2f772713017f398785dc8b Mon Sep 17 00:00:00 2001 From: twi-devel Date: Tue, 18 Aug 2026 17:57:06 +0200 Subject: [PATCH] Adds ubuntu2604 build --- make_rpm_ubuntu26.py | 295 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 295 insertions(+) create mode 100644 make_rpm_ubuntu26.py diff --git a/make_rpm_ubuntu26.py b/make_rpm_ubuntu26.py new file mode 100644 index 0000000..2f24e2f --- /dev/null +++ b/make_rpm_ubuntu26.py @@ -0,0 +1,295 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +""" +DEB package builder for Ubuntu 26.04 +Migrated from make_rpm.py (openSUSE) to Ubuntu/DEB ecosystem +""" + +import argparse +import configparser +import getpass +import os +import re +import shutil +import stat +import subprocess +import sys +from datetime import datetime +from pathlib import Path + + +def verbose(): + verb = os.getenv("EMERGE_VERBOSE") + if verb is not None and verb.isdigit() and int(verb) > 0: + return int(verb) + return 0 + + +def debug(message): + if verbose() >= 1: + print(f"debug: {message}") + return True + + +def info(message): + if verbose() >= 0: + print(f"info: {message}") + return True + + +def warning(message): + print(f"warning: {message}") + return True + + +def error(message): + die(message) + + +def die(message): + print(f"emerge fatal error: {message}", file=sys.stderr) + sys.exit(1) + + +def system(cmdstring, file=None): + debug(f"Executing '{cmdstring}'") + stdout = subprocess.PIPE + if file is not None: + stdout = file + p = subprocess.Popen(cmdstring, shell=True, stdout=stdout, stderr=sys.stderr) + ret = p.wait() + if ret != 0: + die(f"Error executing {cmdstring} ({ret})") + ret = "" + if file is None: + ret = p.stdout.read().strip() + return ret + + +def get_os_name(): + """Return Ubuntu version name""" + if os.path.exists("/etc/os-release"): + with open("/etc/os-release", "r") as f: + for line in f.readlines(): + if line.startswith("PRETTY_NAME="): + name = line.split("=")[1].strip().strip('"') + return name.replace(" ", "_") + return "Ubuntu_unknown" + + +def remove_directory(dest_dir): + info("--------------------------------") + info(f"Removing {dest_dir}") + info("--------------------------------") + if os.path.exists(dest_dir) and os.path.isdir(dest_dir): + shutil.rmtree(dest_dir) + + +def copy_src_dir_to_dest_dir(srcdir, dstdir, perm=None, with_subdirs=True): + info("--------------------------------") + info(f"Copying {srcdir} to {dstdir}") + info("--------------------------------") + + while srcdir.endswith("/"): + srcdir = srcdir[:-1] + + if with_subdirs: + for root, dirs, files in os.walk(srcdir): + tmpdir = root.replace(srcdir, dstdir) + debug(f"dstdir = '{tmpdir}'") + if not os.path.exists(tmpdir): + debug(f"Creating dir '{tmpdir}'") + os.makedirs(tmpdir) + if perm: + os.chmod(tmpdir, perm | stat.S_IREAD | stat.S_IRGRP | stat.S_IROTH) + for file in files: + if os.path.isfile(tmpdir) and os.path.exists(tmpdir): + os.remove(tmpdir) + shutil.copy(os.path.join(root, file), tmpdir) + if perm: + f = os.path.join(tmpdir, file) + add_perm = 0 + if os.path.isdir(f): + add_perm = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH + else: + mode = os.stat(f).st_mode + if (stat.S_IXUSR & mode) == stat.S_IXUSR: + add_perm = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH + os.chmod(f, perm | add_perm) + else: + for f in os.listdir(srcdir): + if os.path.isdir(f): + continue + shutil.copy(os.path.join(srcdir, f), os.path.join(dstdir, f)) + + +def create_debian_control(deb_dir, project_name, version, build_number, cmake_flags): + """Create debian/control file for DEB package""" + control_content = f"""Source: legatus-{project_name.lower()} +Section: devel +Priority: optional +Maintainer: Legatus Team +Build-Depends: debhelper (>= 13), cmake, ninja-build, qt6-base-dev, qt6-tools-dev, + libboost-all-dev, libjson-glib-dev, libgeographic-dev + +Package: legatus-{project_name.lower()} +Architecture: any +Depends: ${{shlibs:Depends}}, ${{misc:Depends}} +Description: Legatus {project_name} LTS package + Legatus {project_name} component built with Qt6/C++23 + Version: {version}-{build_number} + Build flags: {cmake_flags} +""" + + control_file = os.path.join(deb_dir, "control") + with open(control_file, "w") as f: + f.write(control_content) + info(f"Created {control_file}") + + +def create_debian_changelog(deb_dir, project_name, version, build_number): + """Create debian/changelog file""" + timestamp = datetime.now().strftime("%a, %d %b %Y %H:%M:%S +0000") + changelog_content = f"""legatus-{project_name.lower()} ({version}-{build_number}) unstable; urgency=medium + + * Automated build for Ubuntu 26.04 + * Qt6/C++23 migration + + -- Legatus Team {timestamp} +""" + + changelog_file = os.path.join(deb_dir, "changelog") + with open(changelog_file, "w") as f: + f.write(changelog_content) + info(f"Created {changelog_file}") + + +def create_debian_rules(deb_dir): + """Create debian/rules file""" + rules_content = """#!/usr/bin/make -f +%: + dh $@ --buildsystem=cmake --builddirectory=build + +override_dh_auto_configure: + dh_auto_configure -- -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr + +override_dh_auto_build: + dh_auto_build --parallel + +override_dh_auto_install: + dh_auto_install +""" + + rules_file = os.path.join(deb_dir, "rules") + with open(rules_file, "w") as f: + f.write(rules_content) + os.chmod(rules_file, stat.S_IREAD | stat.S_IWRITE | stat.S_IXUSR | stat.S_IRGRP | stat.S_IROTH | stat.S_IXGRP | stat.S_IXOTH) + info(f"Created {rules_file}") + + +def build_deb(source_dir, output_dir, project_name, version, build_number, cmake_flags): + """Build DEB package using debuild""" + info("--------------------------------") + info(f"Building DEB package for {project_name} {version}-{build_number}") + info("--------------------------------") + + # Create output directory + os.makedirs(output_dir, exist_ok=True) + + # Create temporary build directory + build_base = os.path.join(source_dir, "deb_build_tmp") + remove_directory(build_base) + os.makedirs(build_base) + + # Copy source to build directory + pkg_name = f"legatus-{project_name.lower()}" + pkg_dir = os.path.join(build_base, f"{pkg_name}-{version}") + copy_src_dir_to_dest_dir(source_dir, pkg_dir) + + # Create debian directory + deb_dir = os.path.join(pkg_dir, "debian") + os.makedirs(deb_dir) + + # Create debian control files + create_debian_control(deb_dir, project_name, version, build_number, cmake_flags) + create_debian_changelog(deb_dir, project_name, version, build_number) + create_debian_rules(deb_dir) + + # Create debian/source/format + source_dir_path = os.path.join(deb_dir, "source") + os.makedirs(source_dir_path) + with open(os.path.join(source_dir_path, "format"), "w") as f: + f.write("3.0 (quilt)\n") + + # Create debian/compat (for older debhelper compatibility) + with open(os.path.join(deb_dir, "compat"), "w") as f: + f.write("13\n") + + # Build the package + info("Running debuild...") + os.chdir(pkg_dir) + + # Set environment for debuild + env = os.environ.copy() + env["DEB_BUILD_OPTIONS"] = "parallel=$(nproc)" + + cmd = f"debuild -us -uc -b" + debug(f"Executing: {cmd}") + ret = subprocess.run(cmd, shell=True, env=env) + + if ret.returncode != 0: + die(f"debuild failed with code {ret.returncode}") + + # Move generated packages to output directory + parent_dir = os.path.dirname(pkg_dir) + for f in os.listdir(parent_dir): + if f.endswith(".deb") or f.endswith(".dsc") or f.endswith(".changes") or f.endswith(".buildinfo"): + src = os.path.join(parent_dir, f) + dst = os.path.join(output_dir, f) + if os.path.exists(dst): + os.remove(dst) + shutil.move(src, output_dir) + info(f"Moved {f} to {output_dir}") + + # Cleanup + os.chdir(source_dir) + remove_directory(build_base) + + info(f"DEB package build completed: {output_dir}") + + +def main(): + parser = argparse.ArgumentParser(description="Build DEB packages for Legatus LTS") + parser.add_argument("-c", "--config", required=True, help="Config type (LTS)") + parser.add_argument("--project_name", required=True, help="Project name (qatar|ahtc|guez)") + parser.add_argument("--version", required=True, help="Version (Major.minor)") + parser.add_argument("--output_dir", required=True, help="Output directory for packages") + parser.add_argument("--cmake_build_flags", default="", help="CMake build flags") + parser.add_argument("--build_number", default="1", help="Build number") + + args = parser.parse_args() + + info(f"Building {args.config} package for {args.project_name} v{args.version}") + info(f"Output directory: {args.output_dir}") + info(f"CMake flags: {args.cmake_build_flags}") + + # Determine source directory (parent of rpmbuild folder) + script_dir = os.path.dirname(os.path.abspath(__file__)) + source_dir = os.path.dirname(script_dir) + + info(f"Source directory: {source_dir}") + + build_deb( + source_dir=source_dir, + output_dir=args.output_dir, + project_name=args.project_name, + version=args.version, + build_number=args.build_number, + cmake_flags=args.cmake_build_flags + ) + + info("Build completed successfully!") + + +if __name__ == "__main__": + main() \ No newline at end of file