From acf6801088461c458b6991923a76d643efd2ae59 Mon Sep 17 00:00:00 2001 From: Chin Yeung Li Date: Tue, 22 Jul 2025 14:07:06 +0800 Subject: [PATCH 1/6] create script to build rpm with docker #340 Signed-off-by: Chin Yeung Li --- build_rpm_docker.py | 129 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 build_rpm_docker.py diff --git a/build_rpm_docker.py b/build_rpm_docker.py new file mode 100644 index 00000000..1e781185 --- /dev/null +++ b/build_rpm_docker.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 +""" +Use Docker container to build an RPM. +Using Docker approach to ensure a consistent and isolated build environment. + +Requirement: The `toml` Python package + + pip install toml + +To run the script: + + python build_rpm_docker.py + +This script will generate the RPM package files and place them in the +rpmbuild/ directory. +""" + +import os +import shutil +import subprocess +import sys +from pathlib import Path + +import toml + + +def build_rpm_with_docker(): + # Load the pyproject.toml file + with open('pyproject.toml') as f: + project = toml.load(f)['project'] + + pkg_name = project['name'] + # Insert "python3-"" prefix that follows a common convention for Python RPMs + # rpm_name = f"python3-{pkg_name.lower().replace('-', '_')}" + rpm_name = f"python3-{pkg_name.lower()}" + + docker_cmd = [ + 'docker', 'run', '--rm', + '-v', f"{os.getcwd()}:/workspace", + '-w', '/workspace', + 'fedora:42', + '/bin/bash', '-c', + f"""set -ex + # Install All build dependencies + dnf install -y rpm-build python3-devel python3-setuptools python3-wheel python3-build python3-toml + + # Build the wheel + python3 -m build --wheel + + # Get the wheel file name + WHEEL_FILE=$(ls dist/*.whl) + if [ -z "$WHEEL_FILE" ]; then + echo "Error: No wheel file found in dist/." >&2 + exit 1 + fi + WHEEL_FILENAME=$(basename "$WHEEL_FILE") + + # Keep RPM version as is for sorting + RPM_VERSION="{project['version'].replace("-dev", "~dev")}" + + # Creates the standard directory structure required by rpmbuild + mkdir -p rpmbuild/{{BUILD,RPMS,SOURCES,SPECS,SRPMS}} + cp "$WHEEL_FILE" rpmbuild/SOURCES/ + + # Get the changelog date + CHANGELOG_DATE=$(date '+%a %b %d %Y') + + # Generate spec file with correct deps + cat > rpmbuild/SPECS/{rpm_name}.spec << EOF +Name: {rpm_name} +Version: $RPM_VERSION +Release: 1%{{?dist}} +Summary: {project.get('description', 'Automate open source license compliance and ensure supply chain integrity')} + +License: {project.get('license', 'AGPL-3.0-only')} +URL: {project.get('urls', '').get('Homepage', 'https://github.com/aboutcode-org/dejacode')} +Source0: "$WHEEL_FILENAME" + +BuildArch: noarch +BuildRequires: python3-devel python3-setuptools python3-wheel python3-build python3-toml + +%description +{project.get('description', 'Automate open source license compliance and ensure supply chain integrity')} + +%prep + +%install +mkdir -p %{{buildroot}}%{{python3_sitelib}} +# Use the actual filename for pip install, which %SOURCE0 resolves to +pip install --no-deps --ignore-installed --root %{{buildroot}} --prefix %{{_prefix}} %{{SOURCE0}} + +%files +%{{_bindir}}/dejacode +%{{python3_sitelib}}/* + +%changelog +* $CHANGELOG_DATE {project.get('authors', [{}])[0].get('name', 'nexB Inc.')} - $RPM_VERSION-1 +- {project.get('urls', '').get('Changelog', 'https://github.com/aboutcode-org/dejacode/blob/main/CHANGELOG.rst')} +EOF + + # Build the RPM + rpmbuild --define "_topdir /workspace/rpmbuild" -bb rpmbuild/SPECS/{rpm_name}.spec + + # Fix permissions for Windows host + chmod -R u+rwX rpmbuild + """ + ] + + try: + subprocess.run(docker_cmd, check=True) + # Verify the existance of the .rpm + rpm_file = next(Path('rpmbuild/RPMS/noarch').glob('*.rpm'), None) + if rpm_file: + print(f"\nSuccess! RPM built: {rpm_file}") + else: + print("Error: RPM not found in rpmbuild/RPMS/noarch/", file=sys.stderr) + sys.exit(1) + except subprocess.CalledProcessError as e: + print(f"Build failed: {e}", file=sys.stderr) + sys.exit(1) + + +if __name__ == '__main__': + # Check if "docker" is available + if not shutil.which('docker'): + print("Error: Docker not found. Please install Docker first.", file=sys.stderr) + sys.exit(1) + + build_rpm_with_docker() From 99f38dd8b7979f2c38842f56b7f64befe646894d Mon Sep 17 00:00:00 2001 From: Chin Yeung Li Date: Tue, 22 Jul 2025 17:23:34 +0800 Subject: [PATCH 2/6] remove the hyphen replacement #340 Signed-off-by: Chin Yeung Li --- build_rpm_docker.py | 1 - 1 file changed, 1 deletion(-) diff --git a/build_rpm_docker.py b/build_rpm_docker.py index 1e781185..a6c86ed4 100644 --- a/build_rpm_docker.py +++ b/build_rpm_docker.py @@ -31,7 +31,6 @@ def build_rpm_with_docker(): pkg_name = project['name'] # Insert "python3-"" prefix that follows a common convention for Python RPMs - # rpm_name = f"python3-{pkg_name.lower().replace('-', '_')}" rpm_name = f"python3-{pkg_name.lower()}" docker_cmd = [ From e1e54e13e3241bc390b48ad954672af524513a48 Mon Sep 17 00:00:00 2001 From: Chin Yeung Li Date: Fri, 19 Sep 2025 09:44:28 +0800 Subject: [PATCH 3/6] Update script to put generated package under dist/rpmbuild/ #340 Signed-off-by: Chin Yeung Li --- build_rpm_docker.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/build_rpm_docker.py b/build_rpm_docker.py index a6c86ed4..2d5cb638 100644 --- a/build_rpm_docker.py +++ b/build_rpm_docker.py @@ -12,7 +12,7 @@ python build_rpm_docker.py This script will generate the RPM package files and place them in the -rpmbuild/ directory. +dist/rpmbuild/ directory. """ import os @@ -58,14 +58,14 @@ def build_rpm_with_docker(): RPM_VERSION="{project['version'].replace("-dev", "~dev")}" # Creates the standard directory structure required by rpmbuild - mkdir -p rpmbuild/{{BUILD,RPMS,SOURCES,SPECS,SRPMS}} - cp "$WHEEL_FILE" rpmbuild/SOURCES/ + mkdir -p dist/rpmbuild/{{BUILD,RPMS,SOURCES,SPECS,SRPMS}} + mv "$WHEEL_FILE" dist/rpmbuild/SOURCES/ # Get the changelog date CHANGELOG_DATE=$(date '+%a %b %d %Y') # Generate spec file with correct deps - cat > rpmbuild/SPECS/{rpm_name}.spec << EOF + cat > dist/rpmbuild/SPECS/{rpm_name}.spec << EOF Name: {rpm_name} Version: $RPM_VERSION Release: 1%{{?dist}} @@ -98,21 +98,21 @@ def build_rpm_with_docker(): EOF # Build the RPM - rpmbuild --define "_topdir /workspace/rpmbuild" -bb rpmbuild/SPECS/{rpm_name}.spec + rpmbuild --define "_topdir /workspace/dist/rpmbuild" -bb dist/rpmbuild/SPECS/{rpm_name}.spec # Fix permissions for Windows host - chmod -R u+rwX rpmbuild + chmod -R u+rwX dist/rpmbuild """ ] try: subprocess.run(docker_cmd, check=True) # Verify the existance of the .rpm - rpm_file = next(Path('rpmbuild/RPMS/noarch').glob('*.rpm'), None) + rpm_file = next(Path('dist/rpmbuild/RPMS/noarch').glob('*.rpm'), None) if rpm_file: print(f"\nSuccess! RPM built: {rpm_file}") else: - print("Error: RPM not found in rpmbuild/RPMS/noarch/", file=sys.stderr) + print("Error: RPM not found in dist/rpmbuild/RPMS/noarch/", file=sys.stderr) sys.exit(1) except subprocess.CalledProcessError as e: print(f"Build failed: {e}", file=sys.stderr) From b98640ec2f19330562ce118ae28c88d19c674a44 Mon Sep 17 00:00:00 2001 From: Chin Yeung Li Date: Tue, 14 Oct 2025 15:16:50 +0800 Subject: [PATCH 4/6] Reformat the code to comply with Ruff's check #340 Signed-off-by: Chin Yeung Li --- build_rpm_docker.py | 109 ++++++++++++++++++++++++++------------------ 1 file changed, 65 insertions(+), 44 deletions(-) diff --git a/build_rpm_docker.py b/build_rpm_docker.py index 2d5cb638..6e35e1f9 100644 --- a/build_rpm_docker.py +++ b/build_rpm_docker.py @@ -26,60 +26,77 @@ def build_rpm_with_docker(): # Load the pyproject.toml file - with open('pyproject.toml') as f: - project = toml.load(f)['project'] + with open("pyproject.toml") as f: + project = toml.load(f)["project"] - pkg_name = project['name'] + pkg_name = project["name"] # Insert "python3-"" prefix that follows a common convention for Python RPMs rpm_name = f"python3-{pkg_name.lower()}" docker_cmd = [ - 'docker', 'run', '--rm', - '-v', f"{os.getcwd()}:/workspace", - '-w', '/workspace', - 'fedora:42', - '/bin/bash', '-c', + "docker", + "run", + "--rm", + "-v", + f"{os.getcwd()}:/workspace", + "-w", + "/workspace", + "fedora:42", + "/bin/bash", + "-c", f"""set -ex - # Install All build dependencies - dnf install -y rpm-build python3-devel python3-setuptools python3-wheel python3-build python3-toml +# Install All build dependencies +dnf install -y rpm-build python3-devel python3-setuptools python3-wheel python3-build python3-toml - # Build the wheel - python3 -m build --wheel +# Build the wheel +python3 -m build --wheel - # Get the wheel file name - WHEEL_FILE=$(ls dist/*.whl) - if [ -z "$WHEEL_FILE" ]; then - echo "Error: No wheel file found in dist/." >&2 - exit 1 - fi - WHEEL_FILENAME=$(basename "$WHEEL_FILE") +# Get the wheel file name +WHEEL_FILE=$(ls dist/*.whl) +if [ -z "$WHEEL_FILE" ]; then + echo "Error: No wheel file found in dist/." >&2 + exit 1 +fi +WHEEL_FILENAME=$(basename "$WHEEL_FILE") - # Keep RPM version as is for sorting - RPM_VERSION="{project['version'].replace("-dev", "~dev")}" +# Keep RPM version as is for sorting +RPM_VERSION="{project["version"].replace("-dev", "~dev")}" - # Creates the standard directory structure required by rpmbuild - mkdir -p dist/rpmbuild/{{BUILD,RPMS,SOURCES,SPECS,SRPMS}} - mv "$WHEEL_FILE" dist/rpmbuild/SOURCES/ +# Creates the standard directory structure required by rpmbuild +mkdir -p dist/rpmbuild/{{BUILD,RPMS,SOURCES,SPECS,SRPMS}} +mv "$WHEEL_FILE" dist/rpmbuild/SOURCES/ - # Get the changelog date - CHANGELOG_DATE=$(date '+%a %b %d %Y') +# Get the changelog date +CHANGELOG_DATE=$(date '+%a %b %d %Y') - # Generate spec file with correct deps - cat > dist/rpmbuild/SPECS/{rpm_name}.spec << EOF +# Generate spec file with correct deps +cat > dist/rpmbuild/SPECS/{rpm_name}.spec << EOF Name: {rpm_name} Version: $RPM_VERSION Release: 1%{{?dist}} -Summary: {project.get('description', 'Automate open source license compliance and ensure supply chain integrity')} - -License: {project.get('license', 'AGPL-3.0-only')} -URL: {project.get('urls', '').get('Homepage', 'https://github.com/aboutcode-org/dejacode')} +Summary: { + project.get( + "description", + "Automate open source license complianceand ensure supply chain integrity", + ) + } + +License: {project.get("license", "AGPL-3.0-only")} +URL: { + project.get("urls", "").get("Homepage", "https://github.com/aboutcode-org/dejacode") + } Source0: "$WHEEL_FILENAME" BuildArch: noarch BuildRequires: python3-devel python3-setuptools python3-wheel python3-build python3-toml %description -{project.get('description', 'Automate open source license compliance and ensure supply chain integrity')} +{ + project.get( + "description", + "Automate open source license compliance and ensuresupply chain integrity", + ) + } %prep @@ -93,22 +110,26 @@ def build_rpm_with_docker(): %{{python3_sitelib}}/* %changelog -* $CHANGELOG_DATE {project.get('authors', [{}])[0].get('name', 'nexB Inc.')} - $RPM_VERSION-1 -- {project.get('urls', '').get('Changelog', 'https://github.com/aboutcode-org/dejacode/blob/main/CHANGELOG.rst')} +* $CHANGELOG_DATE {project.get("authors", [{}])[0].get("name", "nexB Inc.")} - $RPM_VERSION-1 +- { + project.get("urls", "").get( + "Changelog", "https://github.com/aboutcode-org/dejacode/blob/main/CHANGELOG.rst" + ) + } EOF - # Build the RPM - rpmbuild --define "_topdir /workspace/dist/rpmbuild" -bb dist/rpmbuild/SPECS/{rpm_name}.spec +# Build the RPM +rpmbuild --define "_topdir /workspace/dist/rpmbuild" -bb dist/rpmbuild/SPECS/{rpm_name}.spec - # Fix permissions for Windows host - chmod -R u+rwX dist/rpmbuild - """ +# Fix permissions for Windows host +chmod -R u+rwX dist/rpmbuild +""", ] try: - subprocess.run(docker_cmd, check=True) + subprocess.run(docker_cmd, check=True, shell=False) # noqa: S603 # Verify the existance of the .rpm - rpm_file = next(Path('dist/rpmbuild/RPMS/noarch').glob('*.rpm'), None) + rpm_file = next(Path("dist/rpmbuild/RPMS/noarch").glob("*.rpm"), None) if rpm_file: print(f"\nSuccess! RPM built: {rpm_file}") else: @@ -119,9 +140,9 @@ def build_rpm_with_docker(): sys.exit(1) -if __name__ == '__main__': +if __name__ == "__main__": # Check if "docker" is available - if not shutil.which('docker'): + if not shutil.which("docker"): print("Error: Docker not found. Please install Docker first.", file=sys.stderr) sys.exit(1) From f94b2558e00617b040d5a2d0031155bb34288591 Mon Sep 17 00:00:00 2001 From: Chin Yeung Li Date: Tue, 14 Oct 2025 17:51:03 +0800 Subject: [PATCH 5/6] Moved the build_rpm_docker.py to etc/scripts #340 Signed-off-by: Chin Yeung Li --- build_rpm_docker.py => etc/scripts/build_rpm_docker.py | 5 +++++ 1 file changed, 5 insertions(+) rename build_rpm_docker.py => etc/scripts/build_rpm_docker.py (94%) diff --git a/build_rpm_docker.py b/etc/scripts/build_rpm_docker.py similarity index 94% rename from build_rpm_docker.py rename to etc/scripts/build_rpm_docker.py index 6e35e1f9..05cfae47 100644 --- a/build_rpm_docker.py +++ b/etc/scripts/build_rpm_docker.py @@ -146,4 +146,9 @@ def build_rpm_with_docker(): print("Error: Docker not found. Please install Docker first.", file=sys.stderr) sys.exit(1) + # Get the directory where the current script is located (which is located in etc/scripts) + script_dir = Path(__file__).parent.resolve() + # Go up two levels from etc/scripts/ + project_root = script_dir.parent.parent + os.chdir(project_root) build_rpm_with_docker() From dd9f0bfbcd28e9805f4ae97b926e60bfe89081dd Mon Sep 17 00:00:00 2001 From: Chin Yeung Li Date: Tue, 14 Oct 2025 18:04:43 +0800 Subject: [PATCH 6/6] Update comment on how to install the generated RPM #340 Signed-off-by: Chin Yeung Li --- etc/scripts/build_rpm_docker.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/etc/scripts/build_rpm_docker.py b/etc/scripts/build_rpm_docker.py index 05cfae47..01da2ea5 100644 --- a/etc/scripts/build_rpm_docker.py +++ b/etc/scripts/build_rpm_docker.py @@ -13,6 +13,12 @@ This script will generate the RPM package files and place them in the dist/rpmbuild/ directory. + +Once the RPM package is generated, you can install it using: + + sudo dnf install /path/to/.rpm + +(Replace the above path with the actual path to the generated RPM file.) """ import os