33Use Docker container to build an RPM.
44Using Docker approach to ensure a consistent and isolated build environment.
55
6- Requirement: The `toml` Python package
6+ Requirement:
7+ - toml
8+ - Docker
9+
10+ To install the required Python packages, run:
711
812 pip install toml
913
14+ To install Docker, follow the instructions at:
15+ https://docs.docker.com/get-docker/
16+
1017To run the script:
1118
1219 python build_rpm_docker.py
1320
1421This script will generate the RPM package files and place them in the
1522dist/rpmbuild/ directory.
1623
17- Once the RPM package is generated, you can install it using:
24+ Once the RPM package is generated, one can install it using:
1825
1926 sudo rpm -i /path/to/<dejacode>.rpm
2027 OR
2330 sudo yum install /path/to/<dejacode>.rpm
2431
2532Replace the above path with the actual path to the generated RPM file.
33+
34+ Run the binary directly
35+
36+ dejacode
2637"""
2738
2839import os
@@ -47,11 +58,10 @@ def build_rpm_with_docker():
4758 # Generate requirements for RPM - exclude packages installed from GitHub
4859 dependencies = project ["dependencies" ]
4960
50- # Exclude packages that will be installed from GitHub URLs
51- excluded_packages = {"django-rest-hooks" , "django_notifications_patched" }
52-
5361 filtered_dependencies = [
54- dep for dep in dependencies if not any (excluded in dep for excluded in excluded_packages )
62+ dep
63+ for dep in dependencies
64+ if "django-rest-hooks" not in dep and "django-notifications-patched" not in dep
5565 ]
5666
5767 # Create a requirements.txt content for installation
@@ -69,14 +79,12 @@ def build_rpm_with_docker():
6979 "/bin/bash" ,
7080 "-c" ,
7181 f"""set -ex
72- # Install All build dependencies including development tools
73- dnf install -y rpm-build python3-devel python3-setuptools python3-wheel \
74- python3-build python3-pip python3-virtualenv curl gcc openldap-devel
75-
76- # Clean up build directories to prevent recursive copying
77- rm -rf build
82+ # Install build dependencies
83+ dnf install -y rpm-build python3-devel python3-setuptools python3-wheel \\
84+ python3-build python3-pip python3-virtualenv curl gcc openldap-devel git
7885
79- # Build the wheel
86+ # Clean up and build wheel
87+ rm -rf build dist
8088python3 -m build --wheel
8189
8290# Get the wheel file name
@@ -99,13 +107,13 @@ def build_rpm_with_docker():
99107# Get the changelog date
100108CHANGELOG_DATE=$(date '+%a %b %d %Y')
101109
102- # Create source tarball with actual name
110+ # Create source tarball
103111tar czf dist/rpmbuild/SOURCES/{ rpm_name } -{ rpm_version } .tar.gz \\
104112 --transform "s,^,/{ rpm_name } -{ rpm_version } /," \\
105113 -C /workspace \\
106114 --exclude build --exclude=.git --exclude=dist --exclude=*.pyc --exclude=__pycache__ .
107115
108- # Generate spec file with virtualenv approach - using actual values instead of variables
116+ # Generate spec file
109117cat > dist/rpmbuild/SPECS/{ rpm_name } .spec << EOF
110118Name: { rpm_name }
111119Version: { rpm_version }
@@ -123,16 +131,38 @@ def build_rpm_with_docker():
123131 }
124132Source0: { rpm_name } -{ rpm_version } .tar.gz
125133Source1: requirements.txt
134+ Source2: $WHEEL_FILENAME
135+
136+ BuildArch: x86_64
137+ BuildRequires: python3-devel python3-virtualenv gcc openldap-devel git
138+
139+ # Runtime dependencies
140+ Requires: git
141+ Requires: python3
142+ Requires: postgresql
143+ Requires: postgresql-devel
144+ Requires: openldap
145+
146+ # Disable automatic debug package generation and file checking
147+ %global debug_package %{{nil}}
148+ %global __check_files %{{nil}}
149+ %global _enable_debug_package 0
150+
151+ # Only disable python bytecompilation which breaks virtualenvs
152+ %global __brp_python_bytecompile %{{nil}}
153+
154+ # Keep shebang mangling disabled for virtualenv
155+ %global __os_install_post %(echo '%{{__os_install_post}}' | \
156+ sed -e 's!/usr/lib/rpm/redhat/brp-mangle-shebangs!!g')
157+ %global __brp_mangle_shebangs %{{nil}}
126158
127- BuildArch: noarch
128- BuildRequires: python3-devel python3-virtualenv gcc openldap-devel
129159AutoReqProv: no
130160
131161%description
132162{
133163 project .get (
134164 "description" ,
135- "Automate open source license compliance and ensure supply chain integrity" ,
165+ "Automate open source license complianceand ensure supply chain integrity" ,
136166 )
137167 }
138168
@@ -142,93 +172,81 @@ def build_rpm_with_docker():
142172%build
143173
144174%install
175+ rm -rf %{{buildroot}}
145176# Create directories
146177mkdir -p %{{buildroot}}/opt/%{{name}}/venv
147178mkdir -p %{{buildroot}}/usr/bin
179+ mkdir -p %{{buildroot}}/opt/%{{name}}/src
148180
149181# Create virtual environment in a temporary location first
150182mkdir -p /tmp/venv_build
151- python3 -m venv /tmp/venv_build
152-
153- # Upgrade pip in the temporary virtual environment
154- /tmp/venv_build/bin/pip install --upgrade pip
155-
156- # funcparserlib Patch/Install
157- cd /tmp
158- curl -L -o funcparserlib-0.3.6.tar.gz https://files.pythonhosted.org/packages/source/f/funcparserlib/funcparserlib-0.3.6.tar.gz
159- tar -xzf funcparserlib-0.3.6.tar.gz
160- cd funcparserlib-0.3.6
161-
162- # rewrite setup.py to remove the "use_2to3" as this is not suported in Python3
163- cat > setup.py << 'SETUP_EOF'
164- from setuptools import setup
165-
166- setup(
167- name='funcparserlib',
168- version='0.3.6',
169- packages=['funcparserlib', 'funcparserlib.tests'],
170- author='Andrey Vlasovskikh',
171- 172- description='Recursive descent parsing library based on functional '
173- 'combinators',
174- license='MIT',
175- url='http://code.google.com/p/funcparserlib/',
176- )
177- SETUP_EOF
178-
179- # Install the patched funcparserlib
180- /tmp/venv_build/bin/pip install .
181-
182- # Clean up
183- cd /tmp
184- rm -rf funcparserlib-0.3.6 funcparserlib-0.3.6.tar.gz
185-
186- # Install all other dependencies including the main package
183+ python3 -m venv /tmp/venv_build --copies
184+
187185cd %{{_sourcedir}}
188- /tmp/venv_build/bin/pip install -r requirements.txt
186+ /tmp/venv_build/bin/python -m pip install --upgrade pip
187+
188+ # Install system dependencies for psycopg
189+ dnf install -y postgresql-devel
189190
190191# Install non-PyPI dependencies
191- /tmp/venv_build/bin/pip install \\
192+ /tmp/venv_build/bin/python -m pip install \\
192193 https://github.com/aboutcode-org/django-rest-hooks/releases/download/1.6.1/django_rest_hooks-1.6.1-py2.py3-none-any.whl
193-
194- /tmp/venv_build/bin/pip install \\
194+ /tmp/venv_build/bin/python -m pip install \\
195195 https://github.com/dejacode/django-notifications-patched/archive/refs/tags/2.0.0.tar.gz
196196
197- # Install the main package from the wheel
198- /tmp/venv_build/bin/pip install --no-deps $WHEEL_FILENAME
197+ # Install the main package
198+ /tmp/venv_build/bin/python -m pip install -r requirements.txt
199+
200+ # Install psycopg2-binary for compatibility
201+ /tmp/venv_build/bin/python -m pip install psycopg2-binary
202+
203+ # Install dejacode wheel
204+ /tmp/venv_build/bin/python -m pip install %{{_sourcedir}}/$WHEEL_FILENAME
205+
206+ # Extract source code for tests
207+ cd %{{_sourcedir}}
208+ tar xzf { rpm_name } -{ rpm_version } .tar.gz
209+ cp -r { rpm_name } -{ rpm_version } /* %{{buildroot}}/opt/%{{name}}/src/
210+
211+ # Clean up temporary virtualenv
212+ find /tmp/venv_build -name "*.pyc" -delete
213+ find /tmp/venv_build -name "__pycache__" -type d -exec rm -rf {{}} + 2>/dev/null || true
199214
200215# Copy the completed virtual environment to the final location
201216cp -r /tmp/venv_build/* %{{buildroot}}/opt/%{{name}}/venv/
202217
203218# Clean up temporary virtual environment
204219rm -rf /tmp/venv_build
205220
206- # Doing clean up to prevent the "Arch dependent binaries in noarch package" error.
207- # Remove arch-dependent shared object files (*.so)
208- find %{{buildroot}}/opt/%{{name}}/venv -name "*.so*" -type f -delete
221+ # Fix shebang
222+ for script in %{{buildroot}}/opt/%{{name}}/venv/bin/*; do
223+ if [ -f "\\ $script" ] && head -1 "\\ $script" | grep -q "^#!"; then
224+ # Use sed to safely replace only the first line
225+ sed -i '1s|.*|#!/opt/%{{name}}/venv/bin/python3|' "\\ $script"
226+ fi
227+ done
228+
229+ # Remove ONLY pip and wheel binaries
230+ rm -f %{{buildroot}}/opt/%{{name}}/venv/bin/pip*
231+ rm -f %{{buildroot}}/opt/%{{name}}/venv/bin/wheel
209232
210- # Remove any other potential binary files
211- find %{{buildroot}}/opt/%{{name}}/venv -type f -exec file {{}} \\ ; | grep -i \
212- "executable" | cut -d: -f1 | xargs -r rm -f
233+ # Ensure executables have proper permissions
234+ find %{{buildroot}}/opt/%{{name}}/venv/bin -type f -exec chmod 755 {{}} \\ ;
213235
214- # Create wrapper script for dejacode command
236+ # Create wrapper script with PYTHONPATH for tests
215237cat > %{{buildroot}}/usr/bin/dejacode << 'WRAPPER_EOF'
216238#!/bin/sh
217- export PYTHONPATH="/opt/{ rpm_name } /venv/lib/python3.13/site-packages"
218- exec /usr/bin/python3 -m dejacode "\\ $@"
239+ export PYTHONPATH="/opt/%{{name}}/src:/opt/%{{name}}/venv/lib/python3.13/site-packages"
240+ cd "/opt/%{{name}}/src"
241+ /opt/%{{name}}/venv/bin/dejacode "\\ $@"
219242WRAPPER_EOF
220243chmod 755 %{{buildroot}}/usr/bin/dejacode
221244
222- # Clean up any remaining build artifacts
223- find %{{buildroot}}/opt/%{{name}}/venv -name "*.pyc" -delete
224- find %{{buildroot}}/opt/%{{name}}/venv -name "__pycache__" -type d \
225- -exec rm -rf {{}} + 2>/dev/null || true
226- find %{{buildroot}}/opt/%{{name}}/venv -path "*/pip/_vendor/distlib/*.tmp" \
227- -delete 2>/dev/null || true
228-
229245%files
246+ %defattr(-,root,root,-)
230247%dir /opt/%{{name}}
231- /opt/%{{name}}/venv
248+ /opt/%{{name}}/venv/
249+ /opt/%{{name}}/src/
232250/usr/bin/dejacode
233251
234252%changelog
@@ -240,8 +258,13 @@ def build_rpm_with_docker():
240258 }
241259EOF
242260
243- # Build the RPM
244- cd dist/rpmbuild && rpmbuild --define "_topdir $(pwd)" -bb SPECS/{ rpm_name } .spec
261+ # Build RPM with only specific BRP processing disabled
262+ cd dist/rpmbuild && rpmbuild \\
263+ --define "_topdir $(pwd)" \\
264+ --define "__check_files /bin/true" \\
265+ --define "__brp_python_bytecompile /bin/true" \\
266+ -bb SPECS/{ rpm_name } .spec
267+
245268
246269# Fix permissions for Windows host
247270chmod -R u+rwX /workspace/dist/rpmbuild
@@ -251,11 +274,11 @@ def build_rpm_with_docker():
251274 try :
252275 subprocess .run (docker_cmd , check = True , shell = False ) # noqa: S603
253276 # Verify the existence of the .rpm
254- rpm_file = next (Path ("dist/rpmbuild/RPMS/noarch " ).glob ("*.rpm" ), None )
277+ rpm_file = next (Path ("dist/rpmbuild/RPMS/x86_64 " ).glob ("*.rpm" ), None )
255278 if rpm_file :
256279 print (f"\n Success! RPM built: { rpm_file } " )
257280 else :
258- print ("Error: RPM not found in dist/rpmbuild/RPMS/noarch /" , file = sys .stderr )
281+ print ("Error: RPM not found in dist/rpmbuild/RPMS/x86_64 /" , file = sys .stderr )
259282 sys .exit (1 )
260283 except subprocess .CalledProcessError as e :
261284 print (f"Build failed: { e } " , file = sys .stderr )
0 commit comments