1616
1717Once the RPM package is generated, you can install it using:
1818
19+ sudo rpm -i /path/to/<dejacode>.rpm
20+ OR
1921 sudo dnf install /path/to/<dejacode>.rpm
22+ OR
23+ sudo yum install /path/to/<dejacode>.rpm
2024
21- ( Replace the above path with the actual path to the generated RPM file.)
25+ Replace the above path with the actual path to the generated RPM file.
2226"""
2327
2428import os
@@ -38,6 +42,20 @@ def build_rpm_with_docker():
3842 pkg_name = project ["name" ]
3943 # Insert "python3-"" prefix that follows a common convention for Python RPMs
4044 rpm_name = f"python3-{ pkg_name .lower ()} "
45+ rpm_version = project ["version" ].replace ("-dev" , "~dev" )
46+
47+ # Generate requirements for RPM - exclude packages installed from GitHub
48+ dependencies = project ["dependencies" ]
49+
50+ # Exclude packages that will be installed from GitHub URLs
51+ excluded_packages = {"django-rest-hooks" , "django_notifications_patched" }
52+
53+ filtered_dependencies = [
54+ dep for dep in dependencies if not any (excluded in dep for excluded in excluded_packages )
55+ ]
56+
57+ # Create a requirements.txt content for installation
58+ requirements_content = "\n " .join (filtered_dependencies )
4159
4260 docker_cmd = [
4361 "docker" ,
@@ -51,8 +69,12 @@ def build_rpm_with_docker():
5169 "/bin/bash" ,
5270 "-c" ,
5371 f"""set -ex
54- # Install All build dependencies
55- dnf install -y rpm-build python3-devel python3-setuptools python3-wheel python3-build python3-toml
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
5678
5779# Build the wheel
5880python3 -m build --wheel
@@ -65,58 +87,152 @@ def build_rpm_with_docker():
6587fi
6688WHEEL_FILENAME=$(basename "$WHEEL_FILE")
6789
68- # Keep RPM version as is for sorting
69- RPM_VERSION="{ project ["version" ].replace ("-dev" , "~dev" )} "
70-
7190# Creates the standard directory structure required by rpmbuild
7291mkdir -p dist/rpmbuild/{{BUILD,RPMS,SOURCES,SPECS,SRPMS}}
7392mv "$WHEEL_FILE" dist/rpmbuild/SOURCES/
7493
94+ # Create requirements.txt in SOURCES
95+ cat > dist/rpmbuild/SOURCES/requirements.txt << 'REQ_EOF'
96+ { requirements_content }
97+ REQ_EOF
98+
7599# Get the changelog date
76100CHANGELOG_DATE=$(date '+%a %b %d %Y')
77101
78- # Generate spec file with correct deps
102+ # Create source tarball with actual name
103+ tar czf dist/rpmbuild/SOURCES/{ rpm_name } -{ rpm_version } .tar.gz \\
104+ --transform "s,^,/{ rpm_name } -{ rpm_version } /," \\
105+ -C /workspace \\
106+ --exclude build --exclude=.git --exclude=dist --exclude=*.pyc --exclude=__pycache__ .
107+
108+ # Generate spec file with virtualenv approach - using actual values instead of variables
79109cat > dist/rpmbuild/SPECS/{ rpm_name } .spec << EOF
80110Name: { rpm_name }
81- Version: $RPM_VERSION
111+ Version: { rpm_version }
82112Release: 1%{{?dist}}
83113Summary: {
84114 project .get (
85115 "description" ,
86- "Automate open source license complianceand ensure supply chain integrity" ,
116+ "Automate open source license compliance and ensure supply chain integrity" ,
87117 )
88118 }
89119
90120License: { project .get ("license" , "AGPL-3.0-only" )}
91121URL: {
92122 project .get ("urls" , "" ).get ("Homepage" , "https://github.com/aboutcode-org/dejacode" )
93123 }
94- Source0: "$WHEEL_FILENAME"
124+ Source0: { rpm_name } -{ rpm_version } .tar.gz
125+ Source1: requirements.txt
95126
96127BuildArch: noarch
97- BuildRequires: python3-devel python3-setuptools python3-wheel python3-build python3-toml
128+ BuildRequires: python3-devel python3-virtualenv gcc openldap-devel
129+ AutoReqProv: no
98130
99131%description
100132{
101133 project .get (
102134 "description" ,
103- "Automate open source license compliance and ensuresupply chain integrity" ,
135+ "Automate open source license compliance and ensure supply chain integrity" ,
104136 )
105137 }
106138
107139%prep
140+ %setup -q
141+
142+ %build
108143
109144%install
110- mkdir -p %{{buildroot}}%{{python3_sitelib}}
111- # Use the actual filename for pip install, which %SOURCE0 resolves to
112- pip install --no-deps --ignore-installed --root %{{buildroot}} --prefix %{{_prefix}} %{{SOURCE0}}
145+ # Create directories
146+ mkdir -p %{{buildroot}}/opt/%{{name}}/venv
147+ mkdir -p %{{buildroot}}/usr/bin
148+
149+ # Create virtual environment in a temporary location first
150+ mkdir -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
187+ cd %{{_sourcedir}}
188+ /tmp/venv_build/bin/pip install -r requirements.txt
189+
190+ # Install non-PyPI dependencies
191+ /tmp/venv_build/bin/pip install \\
192+ 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 \\
195+ https://github.com/dejacode/django-notifications-patched/archive/refs/tags/2.0.0.tar.gz
196+
197+ # Install the main package from the wheel
198+ /tmp/venv_build/bin/pip install --no-deps $WHEEL_FILENAME
199+
200+ # Copy the completed virtual environment to the final location
201+ cp -r /tmp/venv_build/* %{{buildroot}}/opt/%{{name}}/venv/
202+
203+ # Clean up temporary virtual environment
204+ rm -rf /tmp/venv_build
205+
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
209+
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
213+
214+ # Create wrapper script for dejacode command
215+ cat > %{{buildroot}}/usr/bin/dejacode << 'WRAPPER_EOF'
216+ #!/bin/sh
217+ export PYTHONPATH="/opt/{ rpm_name } /venv/lib/python3.13/site-packages"
218+ exec /usr/bin/python3 -m dejacode "\\ $@"
219+ WRAPPER_EOF
220+ chmod 755 %{{buildroot}}/usr/bin/dejacode
221+
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
113228
114229%files
115- %{{_bindir}}/dejacode
116- %{{python3_sitelib}}/*
230+ %dir /opt/%{{name}}
231+ /opt/%{{name}}/venv
232+ /usr/bin/dejacode
117233
118234%changelog
119- * $CHANGELOG_DATE { project .get ("authors" , [{}])[0 ].get ("name" , "nexB Inc." )} - $RPM_VERSION -1
235+ * $CHANGELOG_DATE { project .get ("authors" , [{}])[0 ].get ("name" , "nexB Inc." )} - { rpm_version } -1
120236- {
121237 project .get ("urls" , "" ).get (
122238 "Changelog" , "https://github.com/aboutcode-org/dejacode/blob/main/CHANGELOG.rst"
@@ -125,16 +241,16 @@ def build_rpm_with_docker():
125241EOF
126242
127243# Build the RPM
128- rpmbuild --define "_topdir /workspace/dist/rpmbuild " -bb dist/rpmbuild/ SPECS/{ rpm_name } .spec
244+ cd dist/ rpmbuild && rpmbuild --define "_topdir $(pwd) " -bb SPECS/{ rpm_name } .spec
129245
130246# Fix permissions for Windows host
131- chmod -R u+rwX dist/rpmbuild
247+ chmod -R u+rwX /workspace/ dist/rpmbuild
132248""" ,
133249 ]
134250
135251 try :
136252 subprocess .run (docker_cmd , check = True , shell = False ) # noqa: S603
137- # Verify the existance of the .rpm
253+ # Verify the existence of the .rpm
138254 rpm_file = next (Path ("dist/rpmbuild/RPMS/noarch" ).glob ("*.rpm" ), None )
139255 if rpm_file :
140256 print (f"\n Success! RPM built: { rpm_file } " )
0 commit comments