%prepare_alternative(t:) \ %define alternative_target %{-t:%{-t*}}%{!-t:%{_bindir}/%1} \ rm -f %{buildroot}%{alternative_target} \ alternative_target="%{alternative_target}" \ if [[ "$alternative_target" == %{_mandir}* ]]; then \ rm -f %{buildroot}${alternative_target%%%%%{ext_man}} \ rm -f %{buildroot}%{alternative_target}%{ext_man} \ fi \ if [ %{with libalternatives} -eq 1 ] ; then \ mkdir -p %{buildroot}%{_datadir}/libalternatives \ if [[ "$alternative_target" != %{_mandir}* ]]; then \ ln -sf %{_bindir}/alts %{buildroot}%{alternative_target} \ fi \ else \ mkdir -p %{buildroot}%{_sysconfdir}/alternatives \ touch %{buildroot}%{_sysconfdir}/alternatives/%1 \ ln -sf %{_sysconfdir}/alternatives/%1 %{buildroot}%{alternative_target} \ fi \ %{nil} %install_alternative(s:t:p:n:) \ %define alternative_name %{-n:%{-n*}}%{!-n:%1} \ %define alternative_source %{-s:%{-s*}}%{!-s:%{_bindir}/%{alternative_name}} \ %define alternative_target %{-t:%{-t*}}%{!-t:%2} \ %define alternative_priority %{-p:%{-p*}}%{!-p:%3} \ update-alternatives --install \\\ %{alternative_source} \\\ %{alternative_name} \\\ %{alternative_target} \\\ %{alternative_priority} %uninstall_alternative(n:t:) \ %define alternative_name %{-n:%{-n*}}%{!-n:%1} \ %define alternative_target %{-t:%{-t*}}%{!-t:%2} \ if [ ! -e "%{alternative_target}" ]; then \ update-alternatives --quiet --remove "%{alternative_name}" "%{alternative_target}" \ fi \ %{nil} %reset_alternative(n:t:) \ %define alternative_name %{-n:%{-n*}}%{!-n:%1} \ %define alternative_target %{-t:%{-t*}}%{!-t:%2} \ if [ "$1" -gt 0 ] && [ -f %{_sbindir}/update-alternatives ]; then \ update-alternatives --quiet --remove "%{alternative_name}" "%{alternative_target}" \ fi \ %{nil} %alternative_for() \ %1 \ %ghost %{_sysconfdir}/alternatives/%{basename:%1} %python_flavored_alternatives(v:) \ %{!-v:set +x} \ %{python_expand # provide libalternatives and update-alternatives in the current flavor version when shuffling the build dir \ mkdir -p build/xdgflavorconfig \ export XDG_CONFIG_HOME=$PWD/build/xdgflavorconfig \ if [ -d /usr/share/libalternatives/ ]; then \ for b in /usr/share/libalternatives/*; do \ if [ -e "${b}/%{$python_version_nodots}.conf" ]; then \ baseb=$(basename ${b}) \ alts -n ${baseb} -p %{$python_version_nodots} \ echo "Using libalternatives variant %{$python_version_nodots} for ${baseb} in XDG_CONFIG_HOME during Python %{$python_version} expansions." \ fi \ done \ fi \ mkdir -p build/flavorbin \ for bin in %{_bindir}/*-%{$python_bin_suffix} %{buildroot}%{_bindir}/*-%{$python_bin_suffix}; do \ if [ -x "${bin}" ]; then \ # four percent into 1 by rpm/python expansions \ mainbin="${bin%%%%-%{$python_bin_suffix}}" \ basemain="$(basename ${mainbin})" \ if [ "$(readlink ${mainbin})" = "/etc/alternatives/${basemain}" ]; then \ ln -sf "${bin}" "build/flavorbin/${basemain}" \ echo "Using alternative $(basename ${bin}) for ${basemain} in ./build/flavorbin during Python %{$python_version} expansions." \ fi \ fi \ done \ } \ %{!-v:set -x} \ export PATH=$PWD/build/flavorbin:$PATH \ %{nil} %python_group_libalternatives() \ if [ %{with libalternatives} -eq 1 ] ; then \ group="%{**}" \ for f in %{buildroot}%{_datadir}/libalternatives/%1/*.conf; do \ for name in %{**}; do \ sed -n -i -e '/^group=/!p' -e '$'"a group=${group// /, }" ${f/\\/%{1}\\//\\/$name\\/} \ done \ done \ fi \ %{nil} %system_python python2 %python_for_executables python3 ##### common functionality ##### %_python_sysconfig_path() %([ -x %1 ] && RPM_BUILD_ROOT="%{buildroot}" %1 -c "import sysconfig as s; print(s.get_paths().get('%2'))" || echo "!!_{%1}_not_installed_!!") %_python_sysconfig_var() %([ -x %1 ] && RPM_BUILD_ROOT="%{buildroot}" %1 -c "import sysconfig as s; print(s.get_config_var('%2'))" || echo "!!_{%1}_not_installed_!!") %_rec_macro_helper %{lua: rpm.define("_rec_macro_helper %{nil}") function expand_macro(name, args) local pflavor = rpm.expand("%python_flavor") local args = args and rpm.expand(args) or "" print(rpm.expand("%{" .. pflavor .. "_" .. name .. " " .. args .."}")) end } # put wheels into python_expand shuffled wheeldir by default %_pyproject_wheeldir ./build # put flavor-agnostic wheels into a common dir. Dist is the default destination of pytnon -m build %_pyproject_anywheeldir ./dist %pyproject_wheel_args \\\ --verbose --progress-bar off --disable-pip-version-check \\\ %{?py_setup_args:--build-option %{py_setup_args}} \\\ --use-pep517 --no-build-isolation \\\ --no-deps \\\ --wheel-dir %{_pyproject_wheeldir} %pyproject_install_args \\\ --verbose --progress-bar off --disable-pip-version-check \\\ --root %{buildroot} \\\ --no-compile \\\ --ignore-installed --no-deps \\\ --no-index --find-links %{_pyproject_wheeldir} ##### fedora compatibility ##### %py_setup setup.py %py_shbang_opts -s ##### non-standard binary suffixes for flavors ##### %_pypy3_bin_suffix pp%{pypy3_version} ##### preferred configuration ##### %python_sitelib %{_python_sysconfig_path %{expand:%__%{python_flavor}} purelib} %python_sitearch %{_python_sysconfig_path %{expand:%__%{python_flavor}} platlib} %python_version %{_python_sysconfig_var %{expand:%__%{python_flavor}} py_version_short} %python_version_nodots %{_python_sysconfig_var %{expand:%__%{python_flavor}} py_version_nodot} %python_sysconfig_path() %{_python_sysconfig_path %{expand:%__%{python_flavor}} %1} %python_sysconfig_var() %{_python_sysconfig_var %{expand:%__%{python_flavor}} %1} %python_prefix %{_rec_macro_helper}%{lua:expand_macro("prefix")} %python_bin_suffix %{_rec_macro_helper}%{lua:expand_macro("bin_suffix")} %python_provides %{_rec_macro_helper}%{lua:expand_macro("provides")} %python_alternative() %{_rec_macro_helper}%{lua:expand_macro("alternative", "%**")} %python_install_alternative() %{_rec_macro_helper}%{lua:expand_macro("install_alternative", "%**")} %python_uninstall_alternative() %{_rec_macro_helper}%{lua:expand_macro("uninstall_alternative", "%**")} %python_libalternatives_reset_alternative() %{_rec_macro_helper}%{lua:expand_macro("reset_alternative", "%**")} # this is by convention hardcoded python2 %py_ver %(python -c "import sys; v=sys.version_info[:2]; print '%%d.%%d'%%v" 2>/dev/null || echo PYTHON-NOT-FOUND) ##### Python dependency generator macros ##### # === Macros for Build/Requires tags using Python dist tags === # - https://fedoraproject.org/wiki/Changes/Automatic_Provides_for_Python_RPM_Packages # Converts Python dist name to a canonical format %python_dist_name() %{lua:\ name = rpm.expand("%{?1:%{1}}");\ canonical = string.gsub(string.lower(name), "[^%w%.]+", "-");\ print(canonical);\ } # Creates Python 2 dist tag(s) after converting names to canonical format # Needs to first put all arguments into a list, because invoking a different # macro (%python_dist_name) overwrites them %python2_dist() %{lua:\ args = {}\ arg = 1\ while (true) do\ name = rpm.expand("%{?" .. arg .. ":%{" .. arg .. "}}");\ if (name == nil or name == '') then\ break\ end\ args[arg] = name\ arg = arg + 1\ end\ for arg, name in ipairs(args) do\ canonical = rpm.expand("%python_dist_name " .. name);\ print("python" .. rpm.expand("%python2_version") .. "dist(" .. canonical .. ") ");\ end\ } # Creates Python 3 dist tag(s) after converting names to canonical format # Needs to first put all arguments into a list, because invoking a different # macro (%python_dist_name) overwrites them %python3_dist() %{lua:\ args = {}\ arg = 1\ while (true) do\ name = rpm.expand("%{?" .. arg .. ":%{" .. arg .. "}}");\ if (name == nil or name == '') then\ break\ end\ args[arg] = name\ arg = arg + 1\ end\ for arg, name in ipairs(args) do\ canonical = rpm.expand("%python_dist_name " .. name);\ print("python" .. rpm.expand("%python3_version") .. "dist(" .. canonical .. ") ");\ end\ } # === Macros to control dependency generator === # - https://fedoraproject.org/wiki/Changes/EnablingPythonGenerators %python_enable_dependency_generator() \ %global __pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires \ %{nil} ##### Python Unittest macros ##### %pyunittest(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %python_flavored_alternatives \ %{lua:\ local args = rpm.expand("%**"); \ local broot = rpm.expand("%buildroot"); \ local intro = "%{python_expand PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}" .. broot .. "%{$python_sitelib} PYTHONDONTWRITEBYTECODE=1 $python -m unittest "; \ print(rpm.expand(intro .. args .. "}")) \ } %pyunittest_arch(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %python_flavored_alternatives \ %{lua:\ local args = rpm.expand("%**"); \ local broot = rpm.expand("%buildroot"); \ local intro = "%{python_expand PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}" .. broot .. "%{$python_sitearch} PYTHONDONTWRITEBYTECODE=1 $python -m unittest "; \ print(rpm.expand(intro .. args .. "}")) \ } ##### Pytest macros ##### %pytest(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %python_flavored_alternatives \ %{lua:\ local args = rpm.expand("%**"); \ local broot = rpm.expand("%buildroot"); \ local intro = "%{python_expand PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}" .. broot .. "%{$python_sitelib} PYTHONDONTWRITEBYTECODE=1 "; \ local ignore_build = "--ignore=_build." .. rpm.expand("%pythons"):gsub("%s+", " --ignore=_build."); \ intro = intro .. "pytest-%{$python_bin_suffix} " .. ignore_build .. " -v "; \ print(rpm.expand(intro .. args .. "}")) \ } %pytest_arch(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %python_flavored_alternatives \ %{lua:\ local args = rpm.expand("%**"); \ local broot = rpm.expand("%buildroot"); \ local intro = "%{python_expand PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}" .. broot .. "%{$python_sitearch} PYTHONDONTWRITEBYTECODE=1 "; \ local ignore_build = "--ignore=_build." .. rpm.expand("%pythons"):gsub("%s+", " --ignore=_build."); \ intro = intro .. "pytest-%{$python_bin_suffix} " .. ignore_build .. " -v "; \ print(rpm.expand(intro .. args .. "}")) \ } ##### Find language files ##### %python_find_lang() \ %find_lang %{**} \ langfile=%{?2}%{!?2:%1.lang} \ %{python_expand # \ grep -v 'python.*site-packages' ${langfile} > %{$python_prefix}-${langfile} \ grep -F %{$python_sitelib} ${langfile} >> %{$python_prefix}-${langfile} \ } \ %{nil} ##### macro definitions for flavor "pypy3" ##### %pypy3_shbang_opts %py_shbang_opts %__pypy3 %{_bindir}/%{lua: print((string.gsub("pypy3", "(%a+%d)(%d+)", "%1.%2")))} %pypy3_prefix pypy3 %pypy3_sitelib %{_python_sysconfig_path %__pypy3 purelib} %pypy3_sitearch %{_python_sysconfig_path %__pypy3 platlib} %pypy3_version %{_python_sysconfig_var %__pypy3 py_version_short} %pypy3_version_nodots %{_python_sysconfig_var %__pypy3 py_version_nodot} %pypy3_sysconfig_path() %{_python_sysconfig_path %__pypy3 %1} %pypy3_sysconfig_var() %{_python_sysconfig_var %__pypy3 %1} %pypy3_bin_suffix %{?!_pypy3_bin_suffix:%pypy3_version}%{?_pypy3_bin_suffix} # Check if there is a major version symlink to our flavor in the current build system. If so, we are the primary provider. %pypy3_provides %(provides=""; \ for flavorbin in %{_bindir}/python?; do \ if [ $flavorbin != %__pypy3 -a $(realpath $flavorbin) = %__pypy3 ]; then \ provides="$provides $(basename $flavorbin)"; \ fi; \ done; \ echo ${provides# }; \ ) %ifpypy3 %if "%{python_flavor}" == "pypy3" %pypy3_only() %if "%{python_flavor}" == "pypy3" \ %** \ %endif %pypy3_build \ %{_python_use_flavor pypy3} \ %__pypy3 %{py_setup} %{?py_setup_args} build \\\ --executable="%__pypy3 %pypy3_shbang_opts" %pypy3_install(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor pypy3} \ myargs="%{**}" \ %__pypy3 %{py_setup} %{?py_setup_args} install \\\ -O1 --skip-build --force --root %{buildroot} --prefix %{_prefix} $myargs \ %pypy3_compile \ %pypy3_fix_shebang %pypy3_pytest(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor pypy3} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{pypy3_sitelib} PYTHONDONTWRITEBYTECODE=1 %__pypy3 -m pytest -v $myargs %pypy3_pytest_arch(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor pypy3} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{pypy3_sitearch} PYTHONDONTWRITEBYTECODE=1 %__pypy3 -m pytest -v $myargs %pypy3_pyunittest(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor pypy3} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{pypy3_sitelib} PYTHONDONTWRITEBYTECODE=1 %__pypy3 -m unittest $myargs %pypy3_pyunittest_arch(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor pypy3} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{pypy3_sitearch} PYTHONDONTWRITEBYTECODE=1 %__pypy3 -m unittest $myargs ##### PEP517/PEP518 macros ##### %pypy3_pyproject_wheel(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor pypy3} \ myargs="%{**}" \ if [ -f %{_pyproject_anywheeldir}/*-none-any.whl ]; then \ echo "Already found a compatible wheel in %{_pyproject_anywheeldir}" \ mkdir -p %{_pyproject_wheeldir} \ cp %{_pyproject_anywheeldir}/*-none-any.whl %{_pyproject_wheeldir}/ \ else \ %__pypy3 -mpip wheel %{pyproject_wheel_args} ${myargs:-.}\ if [ -f %{_pyproject_wheeldir}/*-none-any.whl ]; then \ mkdir -p %{_pyproject_anywheeldir} \ cp %{_pyproject_wheeldir}/*-none-any.whl %{_pyproject_anywheeldir}/ \ fi \ fi %pypy3_pyproject_install(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor pypy3} \ myargs="%{**}" \ havereq=0 \ if [ -n "${myargs}" ]; then \ for a in ${myargs}; do \ pep440req=$(echo $(basename -- ${a}) | sed -E 's/([^-]+)-([^-]+)-.+\\.whl/\\1==\\2/') \ if [ -f ${a} -a $(basename -- ${a}) != "${pep440req}" ]; then \ myargs=$(echo ${myargs} | sed "s|${a}|${pep440req}|") \ mkdir -p %{_pyproject_wheeldir} \ cp $a %{_pyproject_wheeldir} \ havereq=1 \ fi \ done \ fi \ if [ $havereq -eq 0 ]; then \ # Fallback for old macro usages which expect a wheel in the current directory \ ls %{_pyproject_wheeldir}/*.whl || (mkdir -p %{_pyproject_wheeldir}/; cp *.whl %{_pyproject_wheeldir}/) \ for w in %{_pyproject_wheeldir}/*.whl; do \ myargs="$myargs $(echo $(basename ${w}) | sed -E 's/([^-]+)-([^-]+)-.+\\.whl/\\1==\\2/')" \ done \ fi \ %__pypy3 -mpip install %{pyproject_install_args} $myargs \ %pypy3_compile \ %pypy3_fix_shebang %pypy3_compile \ for d in %{buildroot}%{pypy3_sitelib} %{buildroot}%{pypy3_sitearch}; do \ if [ -d $d ]; then \ find $d -iname '*.pyc' -delete \ find $d -iname '*.py' -print0 | xargs -0 %__pypy3 -c ' \ import sys, py_compile \ for f in sys.argv[1:]: \ fp=f[len("%{buildroot}"):] \ print("Generating cached byte-code for " + str(fp)) \ if sys.version[0] == "2": \ py_compile.compile(f, dfile=fp) \ else: \ for o in [0, 1]: \ py_compile.compile(f, dfile=fp, optimize=o) \ ' \ fi \ done %pypy3_fix_shebang \ %pypy3_fix_shebang_path %{buildroot}%{_bindir}/* %{buildroot}%{_sbindir}/* %pypy3_fix_shebang_path(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ myargs="%{**}" \ for f in ${myargs}; do \ if [ -f "$f" -a -x "$f" -a -w "$f" ] \ then \ # in i586 sed fails when following symlinks to long paths, so \ # changing to the target directory avoid this problem \ pushd $(dirname $f) \ sed -i --follow-symlinks "1s@#\\!.*python\\S*@#\\!$(realpath %__pypy3)@" "$(basename $f)" \ popd \ fi \ done # Alternative entries in file section %pypy3_alternative() %{_python_macro_init} \ %{lua:local link, name, path = python_alternative_names(rpm.expand("%1"), rpm.expand("%pypy3_bin_suffix")) \ local libalternatives = rpm.expand("%{with libalternatives}") \ if libalternatives == "1" then \ if not link:startswith(rpm.expand("%{_mandir}")) then \ local prio = alternative_prio("pypy3") \ print(rpm.expand("%dir %{_datadir}/libalternatives/" .. name .. "\\\n")) \ print(rpm.expand("%{_datadir}/libalternatives/" .. name .. "/" .. prio .. ".conf\\\n")) \ print(link .. "\\\n") \ end \ print(path .. "\\\n") \ else \ print(rpm.expand("%ghost %{_sysconfdir}/alternatives/" .. name .. "\\\n")) \ print(link .. "\\\n") \ print(path .. "\\\n") \ end \ } # Commands for RPM scriptlets: These must not be empty even if there is no operation for # either update-alternatives or libalternatives. %pypy3_install_alternative() \# pypy3_install_alternative: \ %{?!with_libalternatives:%{_python_macro_init}%{lua:python_install_ualternative("pypy3") \ }}%{?with_libalternatives:\: \# no install scriptlet action for libalternatives} %pypy3_uninstall_alternative() \# pypy3_uninstall_alternative: \ %{?!with_libalternatives:%{uninstall_alternative -n %1 -t %{_bindir}/%1-%{pypy3_bin_suffix} \ }}%{?with_libalternatives:\: \# no uninstall scriptlet action for libalternatives} %pypy3_reset_alternative() \# pypy3_reset_alternative: \ %{?!with_libalternatives:\: \# reset action only for libalternatives \ }%{?with_libalternatives:%{reset_alternative -n %1 -t %{_bindir}/%1-%{pypy3_bin_suffix}}} ##### macro definitions for flavor "python2" ##### %python2_shbang_opts %py_shbang_opts %__python2 %{_bindir}/%{lua: print((string.gsub("python2", "(%a+%d)(%d+)", "%1.%2")))} %python2_prefix python2 %python2_sitelib %{_python_sysconfig_path %__python2 purelib} %python2_sitearch %{_python_sysconfig_path %__python2 platlib} %python2_version %{_python_sysconfig_var %__python2 py_version_short} %python2_version_nodots %{_python_sysconfig_var %__python2 py_version_nodot} %python2_sysconfig_path() %{_python_sysconfig_path %__python2 %1} %python2_sysconfig_var() %{_python_sysconfig_var %__python2 %1} %python2_bin_suffix %{?!_python2_bin_suffix:%python2_version}%{?_python2_bin_suffix} # Check if there is a major version symlink to our flavor in the current build system. If so, we are the primary provider. %python2_provides %(provides=""; \ for flavorbin in %{_bindir}/python?; do \ if [ $flavorbin != %__python2 -a $(realpath $flavorbin) = %__python2 ]; then \ provides="$provides $(basename $flavorbin)"; \ fi; \ done; \ echo ${provides# }; \ ) %ifpython2 %if "%{python_flavor}" == "python2" %python2_only() %if "%{python_flavor}" == "python2" \ %** \ %endif %python2_build \ %{_python_use_flavor python2} \ %__python2 %{py_setup} %{?py_setup_args} build \\\ --executable="%__python2 %python2_shbang_opts" %python2_install(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python2} \ myargs="%{**}" \ %__python2 %{py_setup} %{?py_setup_args} install \\\ -O1 --skip-build --force --root %{buildroot} --prefix %{_prefix} $myargs \ %python2_compile \ %python2_fix_shebang %python2_pytest(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python2} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python2_sitelib} PYTHONDONTWRITEBYTECODE=1 %__python2 -m pytest -v $myargs %python2_pytest_arch(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python2} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python2_sitearch} PYTHONDONTWRITEBYTECODE=1 %__python2 -m pytest -v $myargs %python2_pyunittest(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python2} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python2_sitelib} PYTHONDONTWRITEBYTECODE=1 %__python2 -m unittest $myargs %python2_pyunittest_arch(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python2} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python2_sitearch} PYTHONDONTWRITEBYTECODE=1 %__python2 -m unittest $myargs ##### PEP517/PEP518 macros ##### %python2_pyproject_wheel(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python2} \ myargs="%{**}" \ if [ -f %{_pyproject_anywheeldir}/*-none-any.whl ]; then \ echo "Already found a compatible wheel in %{_pyproject_anywheeldir}" \ mkdir -p %{_pyproject_wheeldir} \ cp %{_pyproject_anywheeldir}/*-none-any.whl %{_pyproject_wheeldir}/ \ else \ %__python2 -mpip wheel %{pyproject_wheel_args} ${myargs:-.}\ if [ -f %{_pyproject_wheeldir}/*-none-any.whl ]; then \ mkdir -p %{_pyproject_anywheeldir} \ cp %{_pyproject_wheeldir}/*-none-any.whl %{_pyproject_anywheeldir}/ \ fi \ fi %python2_pyproject_install(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python2} \ myargs="%{**}" \ havereq=0 \ if [ -n "${myargs}" ]; then \ for a in ${myargs}; do \ pep440req=$(echo $(basename -- ${a}) | sed -E 's/([^-]+)-([^-]+)-.+\\.whl/\\1==\\2/') \ if [ -f ${a} -a $(basename -- ${a}) != "${pep440req}" ]; then \ myargs=$(echo ${myargs} | sed "s|${a}|${pep440req}|") \ mkdir -p %{_pyproject_wheeldir} \ cp $a %{_pyproject_wheeldir} \ havereq=1 \ fi \ done \ fi \ if [ $havereq -eq 0 ]; then \ # Fallback for old macro usages which expect a wheel in the current directory \ ls %{_pyproject_wheeldir}/*.whl || (mkdir -p %{_pyproject_wheeldir}/; cp *.whl %{_pyproject_wheeldir}/) \ for w in %{_pyproject_wheeldir}/*.whl; do \ myargs="$myargs $(echo $(basename ${w}) | sed -E 's/([^-]+)-([^-]+)-.+\\.whl/\\1==\\2/')" \ done \ fi \ %__python2 -mpip install %{pyproject_install_args} $myargs \ %python2_compile \ %python2_fix_shebang %python2_compile \ for d in %{buildroot}%{python2_sitelib} %{buildroot}%{python2_sitearch}; do \ if [ -d $d ]; then \ find $d -iname '*.pyc' -delete \ find $d -iname '*.py' -print0 | xargs -0 %__python2 -c ' \ import sys, py_compile \ for f in sys.argv[1:]: \ fp=f[len("%{buildroot}"):] \ print("Generating cached byte-code for " + str(fp)) \ if sys.version[0] == "2": \ py_compile.compile(f, dfile=fp) \ else: \ for o in [0, 1]: \ py_compile.compile(f, dfile=fp, optimize=o) \ ' \ fi \ done %python2_fix_shebang \ %python2_fix_shebang_path %{buildroot}%{_bindir}/* %{buildroot}%{_sbindir}/* %python2_fix_shebang_path(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ myargs="%{**}" \ for f in ${myargs}; do \ if [ -f "$f" -a -x "$f" -a -w "$f" ] \ then \ # in i586 sed fails when following symlinks to long paths, so \ # changing to the target directory avoid this problem \ pushd $(dirname $f) \ sed -i --follow-symlinks "1s@#\\!.*python\\S*@#\\!$(realpath %__python2)@" "$(basename $f)" \ popd \ fi \ done # Alternative entries in file section %python2_alternative() %{_python_macro_init} \ %{lua:local link, name, path = python_alternative_names(rpm.expand("%1"), rpm.expand("%python2_bin_suffix")) \ local libalternatives = rpm.expand("%{with libalternatives}") \ if libalternatives == "1" then \ if not link:startswith(rpm.expand("%{_mandir}")) then \ local prio = alternative_prio("python2") \ print(rpm.expand("%dir %{_datadir}/libalternatives/" .. name .. "\\\n")) \ print(rpm.expand("%{_datadir}/libalternatives/" .. name .. "/" .. prio .. ".conf\\\n")) \ print(link .. "\\\n") \ end \ print(path .. "\\\n") \ else \ print(rpm.expand("%ghost %{_sysconfdir}/alternatives/" .. name .. "\\\n")) \ print(link .. "\\\n") \ print(path .. "\\\n") \ end \ } # Commands for RPM scriptlets: These must not be empty even if there is no operation for # either update-alternatives or libalternatives. %python2_install_alternative() \# python2_install_alternative: \ %{?!with_libalternatives:%{_python_macro_init}%{lua:python_install_ualternative("python2") \ }}%{?with_libalternatives:\: \# no install scriptlet action for libalternatives} %python2_uninstall_alternative() \# python2_uninstall_alternative: \ %{?!with_libalternatives:%{uninstall_alternative -n %1 -t %{_bindir}/%1-%{python2_bin_suffix} \ }}%{?with_libalternatives:\: \# no uninstall scriptlet action for libalternatives} %python2_reset_alternative() \# python2_reset_alternative: \ %{?!with_libalternatives:\: \# reset action only for libalternatives \ }%{?with_libalternatives:%{reset_alternative -n %1 -t %{_bindir}/%1-%{python2_bin_suffix}}} %python2_provides python ##### macro definitions for flavor "python3" ##### %python3_shbang_opts %py_shbang_opts %__python3 %{_bindir}/%{lua: print((string.gsub("python3", "(%a+%d)(%d+)", "%1.%2")))} %python3_prefix python3 %python3_sitelib %{_python_sysconfig_path %__python3 purelib} %python3_sitearch %{_python_sysconfig_path %__python3 platlib} %python3_version %{_python_sysconfig_var %__python3 py_version_short} %python3_version_nodots %{_python_sysconfig_var %__python3 py_version_nodot} %python3_sysconfig_path() %{_python_sysconfig_path %__python3 %1} %python3_sysconfig_var() %{_python_sysconfig_var %__python3 %1} %python3_bin_suffix %{?!_python3_bin_suffix:%python3_version}%{?_python3_bin_suffix} # Check if there is a major version symlink to our flavor in the current build system. If so, we are the primary provider. %python3_provides %(provides=""; \ for flavorbin in %{_bindir}/python?; do \ if [ $flavorbin != %__python3 -a $(realpath $flavorbin) = %__python3 ]; then \ provides="$provides $(basename $flavorbin)"; \ fi; \ done; \ echo ${provides# }; \ ) %ifpython3 %if "%{python_flavor}" == "python3" %python3_only() %if "%{python_flavor}" == "python3" \ %** \ %endif %python3_build \ %{_python_use_flavor python3} \ %__python3 %{py_setup} %{?py_setup_args} build \\\ --executable="%__python3 %python3_shbang_opts" %python3_install(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python3} \ myargs="%{**}" \ %__python3 %{py_setup} %{?py_setup_args} install \\\ -O1 --skip-build --force --root %{buildroot} --prefix %{_prefix} $myargs \ %python3_compile \ %python3_fix_shebang %python3_pytest(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python3} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python3_sitelib} PYTHONDONTWRITEBYTECODE=1 %__python3 -m pytest -v $myargs %python3_pytest_arch(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python3} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python3_sitearch} PYTHONDONTWRITEBYTECODE=1 %__python3 -m pytest -v $myargs %python3_pyunittest(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python3} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python3_sitelib} PYTHONDONTWRITEBYTECODE=1 %__python3 -m unittest $myargs %python3_pyunittest_arch(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python3} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python3_sitearch} PYTHONDONTWRITEBYTECODE=1 %__python3 -m unittest $myargs ##### PEP517/PEP518 macros ##### %python3_pyproject_wheel(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python3} \ myargs="%{**}" \ if [ -f %{_pyproject_anywheeldir}/*-none-any.whl ]; then \ echo "Already found a compatible wheel in %{_pyproject_anywheeldir}" \ mkdir -p %{_pyproject_wheeldir} \ cp %{_pyproject_anywheeldir}/*-none-any.whl %{_pyproject_wheeldir}/ \ else \ %__python3 -mpip wheel %{pyproject_wheel_args} ${myargs:-.}\ if [ -f %{_pyproject_wheeldir}/*-none-any.whl ]; then \ mkdir -p %{_pyproject_anywheeldir} \ cp %{_pyproject_wheeldir}/*-none-any.whl %{_pyproject_anywheeldir}/ \ fi \ fi %python3_pyproject_install(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python3} \ myargs="%{**}" \ havereq=0 \ if [ -n "${myargs}" ]; then \ for a in ${myargs}; do \ pep440req=$(echo $(basename -- ${a}) | sed -E 's/([^-]+)-([^-]+)-.+\\.whl/\\1==\\2/') \ if [ -f ${a} -a $(basename -- ${a}) != "${pep440req}" ]; then \ myargs=$(echo ${myargs} | sed "s|${a}|${pep440req}|") \ mkdir -p %{_pyproject_wheeldir} \ cp $a %{_pyproject_wheeldir} \ havereq=1 \ fi \ done \ fi \ if [ $havereq -eq 0 ]; then \ # Fallback for old macro usages which expect a wheel in the current directory \ ls %{_pyproject_wheeldir}/*.whl || (mkdir -p %{_pyproject_wheeldir}/; cp *.whl %{_pyproject_wheeldir}/) \ for w in %{_pyproject_wheeldir}/*.whl; do \ myargs="$myargs $(echo $(basename ${w}) | sed -E 's/([^-]+)-([^-]+)-.+\\.whl/\\1==\\2/')" \ done \ fi \ %__python3 -mpip install %{pyproject_install_args} $myargs \ %python3_compile \ %python3_fix_shebang %python3_compile \ for d in %{buildroot}%{python3_sitelib} %{buildroot}%{python3_sitearch}; do \ if [ -d $d ]; then \ find $d -iname '*.pyc' -delete \ find $d -iname '*.py' -print0 | xargs -0 %__python3 -c ' \ import sys, py_compile \ for f in sys.argv[1:]: \ fp=f[len("%{buildroot}"):] \ print("Generating cached byte-code for " + str(fp)) \ if sys.version[0] == "2": \ py_compile.compile(f, dfile=fp) \ else: \ for o in [0, 1]: \ py_compile.compile(f, dfile=fp, optimize=o) \ ' \ fi \ done %python3_fix_shebang \ %python3_fix_shebang_path %{buildroot}%{_bindir}/* %{buildroot}%{_sbindir}/* %python3_fix_shebang_path(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ myargs="%{**}" \ for f in ${myargs}; do \ if [ -f "$f" -a -x "$f" -a -w "$f" ] \ then \ # in i586 sed fails when following symlinks to long paths, so \ # changing to the target directory avoid this problem \ pushd $(dirname $f) \ sed -i --follow-symlinks "1s@#\\!.*python\\S*@#\\!$(realpath %__python3)@" "$(basename $f)" \ popd \ fi \ done # Alternative entries in file section %python3_alternative() %{_python_macro_init} \ %{lua:local link, name, path = python_alternative_names(rpm.expand("%1"), rpm.expand("%python3_bin_suffix")) \ local libalternatives = rpm.expand("%{with libalternatives}") \ if libalternatives == "1" then \ if not link:startswith(rpm.expand("%{_mandir}")) then \ local prio = alternative_prio("python3") \ print(rpm.expand("%dir %{_datadir}/libalternatives/" .. name .. "\\\n")) \ print(rpm.expand("%{_datadir}/libalternatives/" .. name .. "/" .. prio .. ".conf\\\n")) \ print(link .. "\\\n") \ end \ print(path .. "\\\n") \ else \ print(rpm.expand("%ghost %{_sysconfdir}/alternatives/" .. name .. "\\\n")) \ print(link .. "\\\n") \ print(path .. "\\\n") \ end \ } # Commands for RPM scriptlets: These must not be empty even if there is no operation for # either update-alternatives or libalternatives. %python3_install_alternative() \# python3_install_alternative: \ %{?!with_libalternatives:%{_python_macro_init}%{lua:python_install_ualternative("python3") \ }}%{?with_libalternatives:\: \# no install scriptlet action for libalternatives} %python3_uninstall_alternative() \# python3_uninstall_alternative: \ %{?!with_libalternatives:%{uninstall_alternative -n %1 -t %{_bindir}/%1-%{python3_bin_suffix} \ }}%{?with_libalternatives:\: \# no uninstall scriptlet action for libalternatives} %python3_reset_alternative() \# python3_reset_alternative: \ %{?!with_libalternatives:\: \# reset action only for libalternatives \ }%{?with_libalternatives:%{reset_alternative -n %1 -t %{_bindir}/%1-%{python3_bin_suffix}}} ##### macro definitions for flavor "python310" ##### %python310_shbang_opts %py_shbang_opts %__python310 %{_bindir}/%{lua: print((string.gsub("python310", "(%a+%d)(%d+)", "%1.%2")))} %python310_prefix python310 %python310_sitelib %{_python_sysconfig_path %__python310 purelib} %python310_sitearch %{_python_sysconfig_path %__python310 platlib} %python310_version %{_python_sysconfig_var %__python310 py_version_short} %python310_version_nodots %{_python_sysconfig_var %__python310 py_version_nodot} %python310_sysconfig_path() %{_python_sysconfig_path %__python310 %1} %python310_sysconfig_var() %{_python_sysconfig_var %__python310 %1} %python310_bin_suffix %{?!_python310_bin_suffix:%python310_version}%{?_python310_bin_suffix} # Check if there is a major version symlink to our flavor in the current build system. If so, we are the primary provider. %python310_provides %(provides=""; \ for flavorbin in %{_bindir}/python?; do \ if [ $flavorbin != %__python310 -a $(realpath $flavorbin) = %__python310 ]; then \ provides="$provides $(basename $flavorbin)"; \ fi; \ done; \ echo ${provides# }; \ ) %ifpython310 %if "%{python_flavor}" == "python310" %python310_only() %if "%{python_flavor}" == "python310" \ %** \ %endif %python310_build \ %{_python_use_flavor python310} \ %__python310 %{py_setup} %{?py_setup_args} build \\\ --executable="%__python310 %python310_shbang_opts" %python310_install(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python310} \ myargs="%{**}" \ %__python310 %{py_setup} %{?py_setup_args} install \\\ -O1 --skip-build --force --root %{buildroot} --prefix %{_prefix} $myargs \ %python310_compile \ %python310_fix_shebang %python310_pytest(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python310} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python310_sitelib} PYTHONDONTWRITEBYTECODE=1 %__python310 -m pytest -v $myargs %python310_pytest_arch(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python310} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python310_sitearch} PYTHONDONTWRITEBYTECODE=1 %__python310 -m pytest -v $myargs %python310_pyunittest(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python310} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python310_sitelib} PYTHONDONTWRITEBYTECODE=1 %__python310 -m unittest $myargs %python310_pyunittest_arch(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python310} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python310_sitearch} PYTHONDONTWRITEBYTECODE=1 %__python310 -m unittest $myargs ##### PEP517/PEP518 macros ##### %python310_pyproject_wheel(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python310} \ myargs="%{**}" \ if [ -f %{_pyproject_anywheeldir}/*-none-any.whl ]; then \ echo "Already found a compatible wheel in %{_pyproject_anywheeldir}" \ mkdir -p %{_pyproject_wheeldir} \ cp %{_pyproject_anywheeldir}/*-none-any.whl %{_pyproject_wheeldir}/ \ else \ %__python310 -mpip wheel %{pyproject_wheel_args} ${myargs:-.}\ if [ -f %{_pyproject_wheeldir}/*-none-any.whl ]; then \ mkdir -p %{_pyproject_anywheeldir} \ cp %{_pyproject_wheeldir}/*-none-any.whl %{_pyproject_anywheeldir}/ \ fi \ fi %python310_pyproject_install(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python310} \ myargs="%{**}" \ havereq=0 \ if [ -n "${myargs}" ]; then \ for a in ${myargs}; do \ pep440req=$(echo $(basename -- ${a}) | sed -E 's/([^-]+)-([^-]+)-.+\\.whl/\\1==\\2/') \ if [ -f ${a} -a $(basename -- ${a}) != "${pep440req}" ]; then \ myargs=$(echo ${myargs} | sed "s|${a}|${pep440req}|") \ mkdir -p %{_pyproject_wheeldir} \ cp $a %{_pyproject_wheeldir} \ havereq=1 \ fi \ done \ fi \ if [ $havereq -eq 0 ]; then \ # Fallback for old macro usages which expect a wheel in the current directory \ ls %{_pyproject_wheeldir}/*.whl || (mkdir -p %{_pyproject_wheeldir}/; cp *.whl %{_pyproject_wheeldir}/) \ for w in %{_pyproject_wheeldir}/*.whl; do \ myargs="$myargs $(echo $(basename ${w}) | sed -E 's/([^-]+)-([^-]+)-.+\\.whl/\\1==\\2/')" \ done \ fi \ %__python310 -mpip install %{pyproject_install_args} $myargs \ %python310_compile \ %python310_fix_shebang %python310_compile \ for d in %{buildroot}%{python310_sitelib} %{buildroot}%{python310_sitearch}; do \ if [ -d $d ]; then \ find $d -iname '*.pyc' -delete \ find $d -iname '*.py' -print0 | xargs -0 %__python310 -c ' \ import sys, py_compile \ for f in sys.argv[1:]: \ fp=f[len("%{buildroot}"):] \ print("Generating cached byte-code for " + str(fp)) \ if sys.version[0] == "2": \ py_compile.compile(f, dfile=fp) \ else: \ for o in [0, 1]: \ py_compile.compile(f, dfile=fp, optimize=o) \ ' \ fi \ done %python310_fix_shebang \ %python310_fix_shebang_path %{buildroot}%{_bindir}/* %{buildroot}%{_sbindir}/* %python310_fix_shebang_path(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ myargs="%{**}" \ for f in ${myargs}; do \ if [ -f "$f" -a -x "$f" -a -w "$f" ] \ then \ # in i586 sed fails when following symlinks to long paths, so \ # changing to the target directory avoid this problem \ pushd $(dirname $f) \ sed -i --follow-symlinks "1s@#\\!.*python\\S*@#\\!$(realpath %__python310)@" "$(basename $f)" \ popd \ fi \ done # Alternative entries in file section %python310_alternative() %{_python_macro_init} \ %{lua:local link, name, path = python_alternative_names(rpm.expand("%1"), rpm.expand("%python310_bin_suffix")) \ local libalternatives = rpm.expand("%{with libalternatives}") \ if libalternatives == "1" then \ if not link:startswith(rpm.expand("%{_mandir}")) then \ local prio = alternative_prio("python310") \ print(rpm.expand("%dir %{_datadir}/libalternatives/" .. name .. "\\\n")) \ print(rpm.expand("%{_datadir}/libalternatives/" .. name .. "/" .. prio .. ".conf\\\n")) \ print(link .. "\\\n") \ end \ print(path .. "\\\n") \ else \ print(rpm.expand("%ghost %{_sysconfdir}/alternatives/" .. name .. "\\\n")) \ print(link .. "\\\n") \ print(path .. "\\\n") \ end \ } # Commands for RPM scriptlets: These must not be empty even if there is no operation for # either update-alternatives or libalternatives. %python310_install_alternative() \# python310_install_alternative: \ %{?!with_libalternatives:%{_python_macro_init}%{lua:python_install_ualternative("python310") \ }}%{?with_libalternatives:\: \# no install scriptlet action for libalternatives} %python310_uninstall_alternative() \# python310_uninstall_alternative: \ %{?!with_libalternatives:%{uninstall_alternative -n %1 -t %{_bindir}/%1-%{python310_bin_suffix} \ }}%{?with_libalternatives:\: \# no uninstall scriptlet action for libalternatives} %python310_reset_alternative() \# python310_reset_alternative: \ %{?!with_libalternatives:\: \# reset action only for libalternatives \ }%{?with_libalternatives:%{reset_alternative -n %1 -t %{_bindir}/%1-%{python310_bin_suffix}}} ##### macro definitions for flavor "python311" ##### %python311_shbang_opts %py_shbang_opts %__python311 %{_bindir}/%{lua: print((string.gsub("python311", "(%a+%d)(%d+)", "%1.%2")))} %python311_prefix python311 %python311_sitelib %{_python_sysconfig_path %__python311 purelib} %python311_sitearch %{_python_sysconfig_path %__python311 platlib} %python311_version %{_python_sysconfig_var %__python311 py_version_short} %python311_version_nodots %{_python_sysconfig_var %__python311 py_version_nodot} %python311_sysconfig_path() %{_python_sysconfig_path %__python311 %1} %python311_sysconfig_var() %{_python_sysconfig_var %__python311 %1} %python311_bin_suffix %{?!_python311_bin_suffix:%python311_version}%{?_python311_bin_suffix} # Check if there is a major version symlink to our flavor in the current build system. If so, we are the primary provider. %python311_provides %(provides=""; \ for flavorbin in %{_bindir}/python?; do \ if [ $flavorbin != %__python311 -a $(realpath $flavorbin) = %__python311 ]; then \ provides="$provides $(basename $flavorbin)"; \ fi; \ done; \ echo ${provides# }; \ ) %ifpython311 %if "%{python_flavor}" == "python311" %python311_only() %if "%{python_flavor}" == "python311" \ %** \ %endif %python311_build \ %{_python_use_flavor python311} \ %__python311 %{py_setup} %{?py_setup_args} build \\\ --executable="%__python311 %python311_shbang_opts" %python311_install(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python311} \ myargs="%{**}" \ %__python311 %{py_setup} %{?py_setup_args} install \\\ -O1 --skip-build --force --root %{buildroot} --prefix %{_prefix} $myargs \ %python311_compile \ %python311_fix_shebang %python311_pytest(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python311} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python311_sitelib} PYTHONDONTWRITEBYTECODE=1 %__python311 -m pytest -v $myargs %python311_pytest_arch(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python311} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python311_sitearch} PYTHONDONTWRITEBYTECODE=1 %__python311 -m pytest -v $myargs %python311_pyunittest(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python311} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python311_sitelib} PYTHONDONTWRITEBYTECODE=1 %__python311 -m unittest $myargs %python311_pyunittest_arch(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python311} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python311_sitearch} PYTHONDONTWRITEBYTECODE=1 %__python311 -m unittest $myargs ##### PEP517/PEP518 macros ##### %python311_pyproject_wheel(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python311} \ myargs="%{**}" \ if [ -f %{_pyproject_anywheeldir}/*-none-any.whl ]; then \ echo "Already found a compatible wheel in %{_pyproject_anywheeldir}" \ mkdir -p %{_pyproject_wheeldir} \ cp %{_pyproject_anywheeldir}/*-none-any.whl %{_pyproject_wheeldir}/ \ else \ %__python311 -mpip wheel %{pyproject_wheel_args} ${myargs:-.}\ if [ -f %{_pyproject_wheeldir}/*-none-any.whl ]; then \ mkdir -p %{_pyproject_anywheeldir} \ cp %{_pyproject_wheeldir}/*-none-any.whl %{_pyproject_anywheeldir}/ \ fi \ fi %python311_pyproject_install(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python311} \ myargs="%{**}" \ havereq=0 \ if [ -n "${myargs}" ]; then \ for a in ${myargs}; do \ pep440req=$(echo $(basename -- ${a}) | sed -E 's/([^-]+)-([^-]+)-.+\\.whl/\\1==\\2/') \ if [ -f ${a} -a $(basename -- ${a}) != "${pep440req}" ]; then \ myargs=$(echo ${myargs} | sed "s|${a}|${pep440req}|") \ mkdir -p %{_pyproject_wheeldir} \ cp $a %{_pyproject_wheeldir} \ havereq=1 \ fi \ done \ fi \ if [ $havereq -eq 0 ]; then \ # Fallback for old macro usages which expect a wheel in the current directory \ ls %{_pyproject_wheeldir}/*.whl || (mkdir -p %{_pyproject_wheeldir}/; cp *.whl %{_pyproject_wheeldir}/) \ for w in %{_pyproject_wheeldir}/*.whl; do \ myargs="$myargs $(echo $(basename ${w}) | sed -E 's/([^-]+)-([^-]+)-.+\\.whl/\\1==\\2/')" \ done \ fi \ %__python311 -mpip install %{pyproject_install_args} $myargs \ %python311_compile \ %python311_fix_shebang %python311_compile \ for d in %{buildroot}%{python311_sitelib} %{buildroot}%{python311_sitearch}; do \ if [ -d $d ]; then \ find $d -iname '*.pyc' -delete \ find $d -iname '*.py' -print0 | xargs -0 %__python311 -c ' \ import sys, py_compile \ for f in sys.argv[1:]: \ fp=f[len("%{buildroot}"):] \ print("Generating cached byte-code for " + str(fp)) \ if sys.version[0] == "2": \ py_compile.compile(f, dfile=fp) \ else: \ for o in [0, 1]: \ py_compile.compile(f, dfile=fp, optimize=o) \ ' \ fi \ done %python311_fix_shebang \ %python311_fix_shebang_path %{buildroot}%{_bindir}/* %{buildroot}%{_sbindir}/* %python311_fix_shebang_path(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ myargs="%{**}" \ for f in ${myargs}; do \ if [ -f "$f" -a -x "$f" -a -w "$f" ] \ then \ # in i586 sed fails when following symlinks to long paths, so \ # changing to the target directory avoid this problem \ pushd $(dirname $f) \ sed -i --follow-symlinks "1s@#\\!.*python\\S*@#\\!$(realpath %__python311)@" "$(basename $f)" \ popd \ fi \ done # Alternative entries in file section %python311_alternative() %{_python_macro_init} \ %{lua:local link, name, path = python_alternative_names(rpm.expand("%1"), rpm.expand("%python311_bin_suffix")) \ local libalternatives = rpm.expand("%{with libalternatives}") \ if libalternatives == "1" then \ if not link:startswith(rpm.expand("%{_mandir}")) then \ local prio = alternative_prio("python311") \ print(rpm.expand("%dir %{_datadir}/libalternatives/" .. name .. "\\\n")) \ print(rpm.expand("%{_datadir}/libalternatives/" .. name .. "/" .. prio .. ".conf\\\n")) \ print(link .. "\\\n") \ end \ print(path .. "\\\n") \ else \ print(rpm.expand("%ghost %{_sysconfdir}/alternatives/" .. name .. "\\\n")) \ print(link .. "\\\n") \ print(path .. "\\\n") \ end \ } # Commands for RPM scriptlets: These must not be empty even if there is no operation for # either update-alternatives or libalternatives. %python311_install_alternative() \# python311_install_alternative: \ %{?!with_libalternatives:%{_python_macro_init}%{lua:python_install_ualternative("python311") \ }}%{?with_libalternatives:\: \# no install scriptlet action for libalternatives} %python311_uninstall_alternative() \# python311_uninstall_alternative: \ %{?!with_libalternatives:%{uninstall_alternative -n %1 -t %{_bindir}/%1-%{python311_bin_suffix} \ }}%{?with_libalternatives:\: \# no uninstall scriptlet action for libalternatives} %python311_reset_alternative() \# python311_reset_alternative: \ %{?!with_libalternatives:\: \# reset action only for libalternatives \ }%{?with_libalternatives:%{reset_alternative -n %1 -t %{_bindir}/%1-%{python311_bin_suffix}}} ##### macro definitions for flavor "python312" ##### %python312_shbang_opts %py_shbang_opts %__python312 %{_bindir}/%{lua: print((string.gsub("python312", "(%a+%d)(%d+)", "%1.%2")))} %python312_prefix python312 %python312_sitelib %{_python_sysconfig_path %__python312 purelib} %python312_sitearch %{_python_sysconfig_path %__python312 platlib} %python312_version %{_python_sysconfig_var %__python312 py_version_short} %python312_version_nodots %{_python_sysconfig_var %__python312 py_version_nodot} %python312_sysconfig_path() %{_python_sysconfig_path %__python312 %1} %python312_sysconfig_var() %{_python_sysconfig_var %__python312 %1} %python312_bin_suffix %{?!_python312_bin_suffix:%python312_version}%{?_python312_bin_suffix} # Check if there is a major version symlink to our flavor in the current build system. If so, we are the primary provider. %python312_provides %(provides=""; \ for flavorbin in %{_bindir}/python?; do \ if [ $flavorbin != %__python312 -a $(realpath $flavorbin) = %__python312 ]; then \ provides="$provides $(basename $flavorbin)"; \ fi; \ done; \ echo ${provides# }; \ ) %ifpython312 %if "%{python_flavor}" == "python312" %python312_only() %if "%{python_flavor}" == "python312" \ %** \ %endif %python312_build \ %{_python_use_flavor python312} \ %__python312 %{py_setup} %{?py_setup_args} build \\\ --executable="%__python312 %python312_shbang_opts" %python312_install(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python312} \ myargs="%{**}" \ %__python312 %{py_setup} %{?py_setup_args} install \\\ -O1 --skip-build --force --root %{buildroot} --prefix %{_prefix} $myargs \ %python312_compile \ %python312_fix_shebang %python312_pytest(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python312} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python312_sitelib} PYTHONDONTWRITEBYTECODE=1 %__python312 -m pytest -v $myargs %python312_pytest_arch(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python312} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python312_sitearch} PYTHONDONTWRITEBYTECODE=1 %__python312 -m pytest -v $myargs %python312_pyunittest(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python312} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python312_sitelib} PYTHONDONTWRITEBYTECODE=1 %__python312 -m unittest $myargs %python312_pyunittest_arch(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python312} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python312_sitearch} PYTHONDONTWRITEBYTECODE=1 %__python312 -m unittest $myargs ##### PEP517/PEP518 macros ##### %python312_pyproject_wheel(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python312} \ myargs="%{**}" \ if [ -f %{_pyproject_anywheeldir}/*-none-any.whl ]; then \ echo "Already found a compatible wheel in %{_pyproject_anywheeldir}" \ mkdir -p %{_pyproject_wheeldir} \ cp %{_pyproject_anywheeldir}/*-none-any.whl %{_pyproject_wheeldir}/ \ else \ %__python312 -mpip wheel %{pyproject_wheel_args} ${myargs:-.}\ if [ -f %{_pyproject_wheeldir}/*-none-any.whl ]; then \ mkdir -p %{_pyproject_anywheeldir} \ cp %{_pyproject_wheeldir}/*-none-any.whl %{_pyproject_anywheeldir}/ \ fi \ fi %python312_pyproject_install(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python312} \ myargs="%{**}" \ havereq=0 \ if [ -n "${myargs}" ]; then \ for a in ${myargs}; do \ pep440req=$(echo $(basename -- ${a}) | sed -E 's/([^-]+)-([^-]+)-.+\\.whl/\\1==\\2/') \ if [ -f ${a} -a $(basename -- ${a}) != "${pep440req}" ]; then \ myargs=$(echo ${myargs} | sed "s|${a}|${pep440req}|") \ mkdir -p %{_pyproject_wheeldir} \ cp $a %{_pyproject_wheeldir} \ havereq=1 \ fi \ done \ fi \ if [ $havereq -eq 0 ]; then \ # Fallback for old macro usages which expect a wheel in the current directory \ ls %{_pyproject_wheeldir}/*.whl || (mkdir -p %{_pyproject_wheeldir}/; cp *.whl %{_pyproject_wheeldir}/) \ for w in %{_pyproject_wheeldir}/*.whl; do \ myargs="$myargs $(echo $(basename ${w}) | sed -E 's/([^-]+)-([^-]+)-.+\\.whl/\\1==\\2/')" \ done \ fi \ %__python312 -mpip install %{pyproject_install_args} $myargs \ %python312_compile \ %python312_fix_shebang %python312_compile \ for d in %{buildroot}%{python312_sitelib} %{buildroot}%{python312_sitearch}; do \ if [ -d $d ]; then \ find $d -iname '*.pyc' -delete \ find $d -iname '*.py' -print0 | xargs -0 %__python312 -c ' \ import sys, py_compile \ for f in sys.argv[1:]: \ fp=f[len("%{buildroot}"):] \ print("Generating cached byte-code for " + str(fp)) \ if sys.version[0] == "2": \ py_compile.compile(f, dfile=fp) \ else: \ for o in [0, 1]: \ py_compile.compile(f, dfile=fp, optimize=o) \ ' \ fi \ done %python312_fix_shebang \ %python312_fix_shebang_path %{buildroot}%{_bindir}/* %{buildroot}%{_sbindir}/* %python312_fix_shebang_path(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ myargs="%{**}" \ for f in ${myargs}; do \ if [ -f "$f" -a -x "$f" -a -w "$f" ] \ then \ # in i586 sed fails when following symlinks to long paths, so \ # changing to the target directory avoid this problem \ pushd $(dirname $f) \ sed -i --follow-symlinks "1s@#\\!.*python\\S*@#\\!$(realpath %__python312)@" "$(basename $f)" \ popd \ fi \ done # Alternative entries in file section %python312_alternative() %{_python_macro_init} \ %{lua:local link, name, path = python_alternative_names(rpm.expand("%1"), rpm.expand("%python312_bin_suffix")) \ local libalternatives = rpm.expand("%{with libalternatives}") \ if libalternatives == "1" then \ if not link:startswith(rpm.expand("%{_mandir}")) then \ local prio = alternative_prio("python312") \ print(rpm.expand("%dir %{_datadir}/libalternatives/" .. name .. "\\\n")) \ print(rpm.expand("%{_datadir}/libalternatives/" .. name .. "/" .. prio .. ".conf\\\n")) \ print(link .. "\\\n") \ end \ print(path .. "\\\n") \ else \ print(rpm.expand("%ghost %{_sysconfdir}/alternatives/" .. name .. "\\\n")) \ print(link .. "\\\n") \ print(path .. "\\\n") \ end \ } # Commands for RPM scriptlets: These must not be empty even if there is no operation for # either update-alternatives or libalternatives. %python312_install_alternative() \# python312_install_alternative: \ %{?!with_libalternatives:%{_python_macro_init}%{lua:python_install_ualternative("python312") \ }}%{?with_libalternatives:\: \# no install scriptlet action for libalternatives} %python312_uninstall_alternative() \# python312_uninstall_alternative: \ %{?!with_libalternatives:%{uninstall_alternative -n %1 -t %{_bindir}/%1-%{python312_bin_suffix} \ }}%{?with_libalternatives:\: \# no uninstall scriptlet action for libalternatives} %python312_reset_alternative() \# python312_reset_alternative: \ %{?!with_libalternatives:\: \# reset action only for libalternatives \ }%{?with_libalternatives:%{reset_alternative -n %1 -t %{_bindir}/%1-%{python312_bin_suffix}}} ##### macro definitions for flavor "python313" ##### %python313_shbang_opts %py_shbang_opts %__python313 %{_bindir}/%{lua: print((string.gsub("python313", "(%a+%d)(%d+)", "%1.%2")))} %python313_prefix python313 %python313_sitelib %{_python_sysconfig_path %__python313 purelib} %python313_sitearch %{_python_sysconfig_path %__python313 platlib} %python313_version %{_python_sysconfig_var %__python313 py_version_short} %python313_version_nodots %{_python_sysconfig_var %__python313 py_version_nodot} %python313_sysconfig_path() %{_python_sysconfig_path %__python313 %1} %python313_sysconfig_var() %{_python_sysconfig_var %__python313 %1} %python313_bin_suffix %{?!_python313_bin_suffix:%python313_version}%{?_python313_bin_suffix} # Check if there is a major version symlink to our flavor in the current build system. If so, we are the primary provider. %python313_provides %(provides=""; \ for flavorbin in %{_bindir}/python?; do \ if [ $flavorbin != %__python313 -a $(realpath $flavorbin) = %__python313 ]; then \ provides="$provides $(basename $flavorbin)"; \ fi; \ done; \ echo ${provides# }; \ ) %ifpython313 %if "%{python_flavor}" == "python313" %python313_only() %if "%{python_flavor}" == "python313" \ %** \ %endif %python313_build \ %{_python_use_flavor python313} \ %__python313 %{py_setup} %{?py_setup_args} build \\\ --executable="%__python313 %python313_shbang_opts" %python313_install(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python313} \ myargs="%{**}" \ %__python313 %{py_setup} %{?py_setup_args} install \\\ -O1 --skip-build --force --root %{buildroot} --prefix %{_prefix} $myargs \ %python313_compile \ %python313_fix_shebang %python313_pytest(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python313} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python313_sitelib} PYTHONDONTWRITEBYTECODE=1 %__python313 -m pytest -v $myargs %python313_pytest_arch(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python313} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python313_sitearch} PYTHONDONTWRITEBYTECODE=1 %__python313 -m pytest -v $myargs %python313_pyunittest(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python313} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python313_sitelib} PYTHONDONTWRITEBYTECODE=1 %__python313 -m unittest $myargs %python313_pyunittest_arch(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python313} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python313_sitearch} PYTHONDONTWRITEBYTECODE=1 %__python313 -m unittest $myargs ##### PEP517/PEP518 macros ##### %python313_pyproject_wheel(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python313} \ myargs="%{**}" \ if [ -f %{_pyproject_anywheeldir}/*-none-any.whl ]; then \ echo "Already found a compatible wheel in %{_pyproject_anywheeldir}" \ mkdir -p %{_pyproject_wheeldir} \ cp %{_pyproject_anywheeldir}/*-none-any.whl %{_pyproject_wheeldir}/ \ else \ %__python313 -mpip wheel %{pyproject_wheel_args} ${myargs:-.}\ if [ -f %{_pyproject_wheeldir}/*-none-any.whl ]; then \ mkdir -p %{_pyproject_anywheeldir} \ cp %{_pyproject_wheeldir}/*-none-any.whl %{_pyproject_anywheeldir}/ \ fi \ fi %python313_pyproject_install(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python313} \ myargs="%{**}" \ havereq=0 \ if [ -n "${myargs}" ]; then \ for a in ${myargs}; do \ pep440req=$(echo $(basename -- ${a}) | sed -E 's/([^-]+)-([^-]+)-.+\\.whl/\\1==\\2/') \ if [ -f ${a} -a $(basename -- ${a}) != "${pep440req}" ]; then \ myargs=$(echo ${myargs} | sed "s|${a}|${pep440req}|") \ mkdir -p %{_pyproject_wheeldir} \ cp $a %{_pyproject_wheeldir} \ havereq=1 \ fi \ done \ fi \ if [ $havereq -eq 0 ]; then \ # Fallback for old macro usages which expect a wheel in the current directory \ ls %{_pyproject_wheeldir}/*.whl || (mkdir -p %{_pyproject_wheeldir}/; cp *.whl %{_pyproject_wheeldir}/) \ for w in %{_pyproject_wheeldir}/*.whl; do \ myargs="$myargs $(echo $(basename ${w}) | sed -E 's/([^-]+)-([^-]+)-.+\\.whl/\\1==\\2/')" \ done \ fi \ %__python313 -mpip install %{pyproject_install_args} $myargs \ %python313_compile \ %python313_fix_shebang %python313_compile \ for d in %{buildroot}%{python313_sitelib} %{buildroot}%{python313_sitearch}; do \ if [ -d $d ]; then \ find $d -iname '*.pyc' -delete \ find $d -iname '*.py' -print0 | xargs -0 %__python313 -c ' \ import sys, py_compile \ for f in sys.argv[1:]: \ fp=f[len("%{buildroot}"):] \ print("Generating cached byte-code for " + str(fp)) \ if sys.version[0] == "2": \ py_compile.compile(f, dfile=fp) \ else: \ for o in [0, 1]: \ py_compile.compile(f, dfile=fp, optimize=o) \ ' \ fi \ done %python313_fix_shebang \ %python313_fix_shebang_path %{buildroot}%{_bindir}/* %{buildroot}%{_sbindir}/* %python313_fix_shebang_path(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ myargs="%{**}" \ for f in ${myargs}; do \ if [ -f "$f" -a -x "$f" -a -w "$f" ] \ then \ # in i586 sed fails when following symlinks to long paths, so \ # changing to the target directory avoid this problem \ pushd $(dirname $f) \ sed -i --follow-symlinks "1s@#\\!.*python\\S*@#\\!$(realpath %__python313)@" "$(basename $f)" \ popd \ fi \ done # Alternative entries in file section %python313_alternative() %{_python_macro_init} \ %{lua:local link, name, path = python_alternative_names(rpm.expand("%1"), rpm.expand("%python313_bin_suffix")) \ local libalternatives = rpm.expand("%{with libalternatives}") \ if libalternatives == "1" then \ if not link:startswith(rpm.expand("%{_mandir}")) then \ local prio = alternative_prio("python313") \ print(rpm.expand("%dir %{_datadir}/libalternatives/" .. name .. "\\\n")) \ print(rpm.expand("%{_datadir}/libalternatives/" .. name .. "/" .. prio .. ".conf\\\n")) \ print(link .. "\\\n") \ end \ print(path .. "\\\n") \ else \ print(rpm.expand("%ghost %{_sysconfdir}/alternatives/" .. name .. "\\\n")) \ print(link .. "\\\n") \ print(path .. "\\\n") \ end \ } # Commands for RPM scriptlets: These must not be empty even if there is no operation for # either update-alternatives or libalternatives. %python313_install_alternative() \# python313_install_alternative: \ %{?!with_libalternatives:%{_python_macro_init}%{lua:python_install_ualternative("python313") \ }}%{?with_libalternatives:\: \# no install scriptlet action for libalternatives} %python313_uninstall_alternative() \# python313_uninstall_alternative: \ %{?!with_libalternatives:%{uninstall_alternative -n %1 -t %{_bindir}/%1-%{python313_bin_suffix} \ }}%{?with_libalternatives:\: \# no uninstall scriptlet action for libalternatives} %python313_reset_alternative() \# python313_reset_alternative: \ %{?!with_libalternatives:\: \# reset action only for libalternatives \ }%{?with_libalternatives:%{reset_alternative -n %1 -t %{_bindir}/%1-%{python313_bin_suffix}}} ##### macro definitions for flavor "python38" ##### %python38_shbang_opts %py_shbang_opts %__python38 %{_bindir}/%{lua: print((string.gsub("python38", "(%a+%d)(%d+)", "%1.%2")))} %python38_prefix python38 %python38_sitelib %{_python_sysconfig_path %__python38 purelib} %python38_sitearch %{_python_sysconfig_path %__python38 platlib} %python38_version %{_python_sysconfig_var %__python38 py_version_short} %python38_version_nodots %{_python_sysconfig_var %__python38 py_version_nodot} %python38_sysconfig_path() %{_python_sysconfig_path %__python38 %1} %python38_sysconfig_var() %{_python_sysconfig_var %__python38 %1} %python38_bin_suffix %{?!_python38_bin_suffix:%python38_version}%{?_python38_bin_suffix} # Check if there is a major version symlink to our flavor in the current build system. If so, we are the primary provider. %python38_provides %(provides=""; \ for flavorbin in %{_bindir}/python?; do \ if [ $flavorbin != %__python38 -a $(realpath $flavorbin) = %__python38 ]; then \ provides="$provides $(basename $flavorbin)"; \ fi; \ done; \ echo ${provides# }; \ ) %ifpython38 %if "%{python_flavor}" == "python38" %python38_only() %if "%{python_flavor}" == "python38" \ %** \ %endif %python38_build \ %{_python_use_flavor python38} \ %__python38 %{py_setup} %{?py_setup_args} build \\\ --executable="%__python38 %python38_shbang_opts" %python38_install(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python38} \ myargs="%{**}" \ %__python38 %{py_setup} %{?py_setup_args} install \\\ -O1 --skip-build --force --root %{buildroot} --prefix %{_prefix} $myargs \ %python38_compile \ %python38_fix_shebang %python38_pytest(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python38} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python38_sitelib} PYTHONDONTWRITEBYTECODE=1 %__python38 -m pytest -v $myargs %python38_pytest_arch(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python38} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python38_sitearch} PYTHONDONTWRITEBYTECODE=1 %__python38 -m pytest -v $myargs %python38_pyunittest(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python38} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python38_sitelib} PYTHONDONTWRITEBYTECODE=1 %__python38 -m unittest $myargs %python38_pyunittest_arch(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python38} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python38_sitearch} PYTHONDONTWRITEBYTECODE=1 %__python38 -m unittest $myargs ##### PEP517/PEP518 macros ##### %python38_pyproject_wheel(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python38} \ myargs="%{**}" \ if [ -f %{_pyproject_anywheeldir}/*-none-any.whl ]; then \ echo "Already found a compatible wheel in %{_pyproject_anywheeldir}" \ mkdir -p %{_pyproject_wheeldir} \ cp %{_pyproject_anywheeldir}/*-none-any.whl %{_pyproject_wheeldir}/ \ else \ %__python38 -mpip wheel %{pyproject_wheel_args} ${myargs:-.}\ if [ -f %{_pyproject_wheeldir}/*-none-any.whl ]; then \ mkdir -p %{_pyproject_anywheeldir} \ cp %{_pyproject_wheeldir}/*-none-any.whl %{_pyproject_anywheeldir}/ \ fi \ fi %python38_pyproject_install(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python38} \ myargs="%{**}" \ havereq=0 \ if [ -n "${myargs}" ]; then \ for a in ${myargs}; do \ pep440req=$(echo $(basename -- ${a}) | sed -E 's/([^-]+)-([^-]+)-.+\\.whl/\\1==\\2/') \ if [ -f ${a} -a $(basename -- ${a}) != "${pep440req}" ]; then \ myargs=$(echo ${myargs} | sed "s|${a}|${pep440req}|") \ mkdir -p %{_pyproject_wheeldir} \ cp $a %{_pyproject_wheeldir} \ havereq=1 \ fi \ done \ fi \ if [ $havereq -eq 0 ]; then \ # Fallback for old macro usages which expect a wheel in the current directory \ ls %{_pyproject_wheeldir}/*.whl || (mkdir -p %{_pyproject_wheeldir}/; cp *.whl %{_pyproject_wheeldir}/) \ for w in %{_pyproject_wheeldir}/*.whl; do \ myargs="$myargs $(echo $(basename ${w}) | sed -E 's/([^-]+)-([^-]+)-.+\\.whl/\\1==\\2/')" \ done \ fi \ %__python38 -mpip install %{pyproject_install_args} $myargs \ %python38_compile \ %python38_fix_shebang %python38_compile \ for d in %{buildroot}%{python38_sitelib} %{buildroot}%{python38_sitearch}; do \ if [ -d $d ]; then \ find $d -iname '*.pyc' -delete \ find $d -iname '*.py' -print0 | xargs -0 %__python38 -c ' \ import sys, py_compile \ for f in sys.argv[1:]: \ fp=f[len("%{buildroot}"):] \ print("Generating cached byte-code for " + str(fp)) \ if sys.version[0] == "2": \ py_compile.compile(f, dfile=fp) \ else: \ for o in [0, 1]: \ py_compile.compile(f, dfile=fp, optimize=o) \ ' \ fi \ done %python38_fix_shebang \ %python38_fix_shebang_path %{buildroot}%{_bindir}/* %{buildroot}%{_sbindir}/* %python38_fix_shebang_path(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ myargs="%{**}" \ for f in ${myargs}; do \ if [ -f "$f" -a -x "$f" -a -w "$f" ] \ then \ # in i586 sed fails when following symlinks to long paths, so \ # changing to the target directory avoid this problem \ pushd $(dirname $f) \ sed -i --follow-symlinks "1s@#\\!.*python\\S*@#\\!$(realpath %__python38)@" "$(basename $f)" \ popd \ fi \ done # Alternative entries in file section %python38_alternative() %{_python_macro_init} \ %{lua:local link, name, path = python_alternative_names(rpm.expand("%1"), rpm.expand("%python38_bin_suffix")) \ local libalternatives = rpm.expand("%{with libalternatives}") \ if libalternatives == "1" then \ if not link:startswith(rpm.expand("%{_mandir}")) then \ local prio = alternative_prio("python38") \ print(rpm.expand("%dir %{_datadir}/libalternatives/" .. name .. "\\\n")) \ print(rpm.expand("%{_datadir}/libalternatives/" .. name .. "/" .. prio .. ".conf\\\n")) \ print(link .. "\\\n") \ end \ print(path .. "\\\n") \ else \ print(rpm.expand("%ghost %{_sysconfdir}/alternatives/" .. name .. "\\\n")) \ print(link .. "\\\n") \ print(path .. "\\\n") \ end \ } # Commands for RPM scriptlets: These must not be empty even if there is no operation for # either update-alternatives or libalternatives. %python38_install_alternative() \# python38_install_alternative: \ %{?!with_libalternatives:%{_python_macro_init}%{lua:python_install_ualternative("python38") \ }}%{?with_libalternatives:\: \# no install scriptlet action for libalternatives} %python38_uninstall_alternative() \# python38_uninstall_alternative: \ %{?!with_libalternatives:%{uninstall_alternative -n %1 -t %{_bindir}/%1-%{python38_bin_suffix} \ }}%{?with_libalternatives:\: \# no uninstall scriptlet action for libalternatives} %python38_reset_alternative() \# python38_reset_alternative: \ %{?!with_libalternatives:\: \# reset action only for libalternatives \ }%{?with_libalternatives:%{reset_alternative -n %1 -t %{_bindir}/%1-%{python38_bin_suffix}}} ##### macro definitions for flavor "python39" ##### %python39_shbang_opts %py_shbang_opts %__python39 %{_bindir}/%{lua: print((string.gsub("python39", "(%a+%d)(%d+)", "%1.%2")))} %python39_prefix python39 %python39_sitelib %{_python_sysconfig_path %__python39 purelib} %python39_sitearch %{_python_sysconfig_path %__python39 platlib} %python39_version %{_python_sysconfig_var %__python39 py_version_short} %python39_version_nodots %{_python_sysconfig_var %__python39 py_version_nodot} %python39_sysconfig_path() %{_python_sysconfig_path %__python39 %1} %python39_sysconfig_var() %{_python_sysconfig_var %__python39 %1} %python39_bin_suffix %{?!_python39_bin_suffix:%python39_version}%{?_python39_bin_suffix} # Check if there is a major version symlink to our flavor in the current build system. If so, we are the primary provider. %python39_provides %(provides=""; \ for flavorbin in %{_bindir}/python?; do \ if [ $flavorbin != %__python39 -a $(realpath $flavorbin) = %__python39 ]; then \ provides="$provides $(basename $flavorbin)"; \ fi; \ done; \ echo ${provides# }; \ ) %ifpython39 %if "%{python_flavor}" == "python39" %python39_only() %if "%{python_flavor}" == "python39" \ %** \ %endif %python39_build \ %{_python_use_flavor python39} \ %__python39 %{py_setup} %{?py_setup_args} build \\\ --executable="%__python39 %python39_shbang_opts" %python39_install(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python39} \ myargs="%{**}" \ %__python39 %{py_setup} %{?py_setup_args} install \\\ -O1 --skip-build --force --root %{buildroot} --prefix %{_prefix} $myargs \ %python39_compile \ %python39_fix_shebang %python39_pytest(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python39} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python39_sitelib} PYTHONDONTWRITEBYTECODE=1 %__python39 -m pytest -v $myargs %python39_pytest_arch(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python39} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python39_sitearch} PYTHONDONTWRITEBYTECODE=1 %__python39 -m pytest -v $myargs %python39_pyunittest(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python39} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python39_sitelib} PYTHONDONTWRITEBYTECODE=1 %__python39 -m unittest $myargs %python39_pyunittest_arch(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python39} \ myargs="%{**}" \ PYTHONPATH=${PYTHONPATH:+$PYTHONPATH:}%{buildroot}%{python39_sitearch} PYTHONDONTWRITEBYTECODE=1 %__python39 -m unittest $myargs ##### PEP517/PEP518 macros ##### %python39_pyproject_wheel(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python39} \ myargs="%{**}" \ if [ -f %{_pyproject_anywheeldir}/*-none-any.whl ]; then \ echo "Already found a compatible wheel in %{_pyproject_anywheeldir}" \ mkdir -p %{_pyproject_wheeldir} \ cp %{_pyproject_anywheeldir}/*-none-any.whl %{_pyproject_wheeldir}/ \ else \ %__python39 -mpip wheel %{pyproject_wheel_args} ${myargs:-.}\ if [ -f %{_pyproject_wheeldir}/*-none-any.whl ]; then \ mkdir -p %{_pyproject_anywheeldir} \ cp %{_pyproject_wheeldir}/*-none-any.whl %{_pyproject_anywheeldir}/ \ fi \ fi %python39_pyproject_install(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ %{_python_use_flavor python39} \ myargs="%{**}" \ havereq=0 \ if [ -n "${myargs}" ]; then \ for a in ${myargs}; do \ pep440req=$(echo $(basename -- ${a}) | sed -E 's/([^-]+)-([^-]+)-.+\\.whl/\\1==\\2/') \ if [ -f ${a} -a $(basename -- ${a}) != "${pep440req}" ]; then \ myargs=$(echo ${myargs} | sed "s|${a}|${pep440req}|") \ mkdir -p %{_pyproject_wheeldir} \ cp $a %{_pyproject_wheeldir} \ havereq=1 \ fi \ done \ fi \ if [ $havereq -eq 0 ]; then \ # Fallback for old macro usages which expect a wheel in the current directory \ ls %{_pyproject_wheeldir}/*.whl || (mkdir -p %{_pyproject_wheeldir}/; cp *.whl %{_pyproject_wheeldir}/) \ for w in %{_pyproject_wheeldir}/*.whl; do \ myargs="$myargs $(echo $(basename ${w}) | sed -E 's/([^-]+)-([^-]+)-.+\\.whl/\\1==\\2/')" \ done \ fi \ %__python39 -mpip install %{pyproject_install_args} $myargs \ %python39_compile \ %python39_fix_shebang %python39_compile \ for d in %{buildroot}%{python39_sitelib} %{buildroot}%{python39_sitearch}; do \ if [ -d $d ]; then \ find $d -iname '*.pyc' -delete \ find $d -iname '*.py' -print0 | xargs -0 %__python39 -c ' \ import sys, py_compile \ for f in sys.argv[1:]: \ fp=f[len("%{buildroot}"):] \ print("Generating cached byte-code for " + str(fp)) \ if sys.version[0] == "2": \ py_compile.compile(f, dfile=fp) \ else: \ for o in [0, 1]: \ py_compile.compile(f, dfile=fp, optimize=o) \ ' \ fi \ done %python39_fix_shebang \ %python39_fix_shebang_path %{buildroot}%{_bindir}/* %{buildroot}%{_sbindir}/* %python39_fix_shebang_path(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) \ myargs="%{**}" \ for f in ${myargs}; do \ if [ -f "$f" -a -x "$f" -a -w "$f" ] \ then \ # in i586 sed fails when following symlinks to long paths, so \ # changing to the target directory avoid this problem \ pushd $(dirname $f) \ sed -i --follow-symlinks "1s@#\\!.*python\\S*@#\\!$(realpath %__python39)@" "$(basename $f)" \ popd \ fi \ done # Alternative entries in file section %python39_alternative() %{_python_macro_init} \ %{lua:local link, name, path = python_alternative_names(rpm.expand("%1"), rpm.expand("%python39_bin_suffix")) \ local libalternatives = rpm.expand("%{with libalternatives}") \ if libalternatives == "1" then \ if not link:startswith(rpm.expand("%{_mandir}")) then \ local prio = alternative_prio("python39") \ print(rpm.expand("%dir %{_datadir}/libalternatives/" .. name .. "\\\n")) \ print(rpm.expand("%{_datadir}/libalternatives/" .. name .. "/" .. prio .. ".conf\\\n")) \ print(link .. "\\\n") \ end \ print(path .. "\\\n") \ else \ print(rpm.expand("%ghost %{_sysconfdir}/alternatives/" .. name .. "\\\n")) \ print(link .. "\\\n") \ print(path .. "\\\n") \ end \ } # Commands for RPM scriptlets: These must not be empty even if there is no operation for # either update-alternatives or libalternatives. %python39_install_alternative() \# python39_install_alternative: \ %{?!with_libalternatives:%{_python_macro_init}%{lua:python_install_ualternative("python39") \ }}%{?with_libalternatives:\: \# no install scriptlet action for libalternatives} %python39_uninstall_alternative() \# python39_uninstall_alternative: \ %{?!with_libalternatives:%{uninstall_alternative -n %1 -t %{_bindir}/%1-%{python39_bin_suffix} \ }}%{?with_libalternatives:\: \# no uninstall scriptlet action for libalternatives} %python39_reset_alternative() \# python39_reset_alternative: \ %{?!with_libalternatives:\: \# reset action only for libalternatives \ }%{?with_libalternatives:%{reset_alternative -n %1 -t %{_bindir}/%1-%{python39_bin_suffix}}} ##### compatibility short-name macros ##### # fedora expects %py_shbang_opts and %pyX_shbang_opts, possibly to be redefinable? # we expect everything to start with binary name, so we actually use %pythonX_shbang_opts # so if a specfile redefines the %pyX_, the correct one will be used %py2_shbang_opts %py_shbang_opts %python2_shbang_opts %py2_shbang_opts %py3_shbang_opts %py_shbang_opts %python3_shbang_opts %py3_shbang_opts %py2_build %python2_build %py2_install %python2_install %py3_build %python3_build %py3_install %python3_install %py2_ver %python2_version %py3_ver %python3_version %py_dist_name() %{python_dist_name %{?**}} %py2_dist() %{python2_dist %{?**}} %py3_dist() %{python3_dist %{?**}} %python2_prefix %{?python2_package_prefix}%{?!python2_package_prefix:python} ## Python Buildset Begin # default-prjconf: buildset definitions for python-rpm-macros. # # This is usually overridden by the distribution's prjconf, landing in ~/.rpmmacros. # This file provides the default definition from Factory (Tumbleweed) for pure rpmbuild packaging. # Macros: ## PYTHON MACROS BEGIN # order of %pythons is important: The last flavor overrides any operation on conflicting files and definitions during expansions, # making it the "default" in many cases --> keep the primary python3 provider at the end. ##%pythons %{?!skip_python3:%{?!skip_python310:python310} %{?!skip_python312:python312} %{?!skip_python311:python311}} # modifiered for eisfair 3.13, 2025-03-29 %pythons %{?!skip_python3:%{?!skip_python313:python313}} %add_python() %{expand:%%define pythons %1 %pythons} %_without_python2 1 # This method for generating python_modules gets too deep to expand for rpm at about 5 python flavors. # Hence, python_module_iter is replaced by python_module_lua in macros.lua. # However, OBS cannot expand lua, but has a much higher expansion depth, so this works fine for the server side resolver. %python_module_iter(a:) %{expand:%%define python %{-a*}} ( %python-%args ) %{expand:%%{?!python_module_iter_%1:%%{python_module_iter -a%*}}%%{?python_module_iter_%1}} # pseudo-undefine for obs: reset for the next expansion within the next call of python_module %python_module_iter_STOP %global python %%%%python %python_module() %{?!python_module_lua:%{expand:%%define args %{**}} %{expand:%%{python_module_iter -a %{pythons} STOP}}}%{?python_module_lua:%python_module_lua %{**}} # gh#openSUSE/python-rpm-macros#127 ... define our current primary Python interpreter %primary_python python311 ## PYTHON MACROS END # :Macros ## Python Buildset End %python_flavor %{_python_macro_init}%{lua: print(flavor)} %if_python_kind() %if "%{python_flavor}" == "%1" %if_not_python_kind() %if "%{python_flavor}" != "%1" %ifpycache %if "%{python_flavor}" != "python2" %pycache_only() %ifpycache \ %** \ %endif %_python_use_flavor() \ last_flavor=`[ -f _current_flavor ] && cat _current_flavor || true` \ if [ -z "$last_flavor" ]; then last_flavor="tmp"; fi \ if [ "$last_flavor" != "%1" ]; then \ if [ -d build ]; then mv build _build.$last_flavor; fi \ if [ -d _build.%1 ]; then mv _build.%1 build; fi \ fi \ echo %1 > _current_flavor \ python_flavor=%1 \ %{nil} %_python_stash_flavor() \ if [ -d build ]; then mv build _build.%1; fi \ if [ -d _build.tmp ]; then mv _build.tmp build; fi \ %{nil} ### LUA-MACROS ### %_python_definitions %{lua: -- declare common functions function string.startswith(str, prefix) return str:sub(1, prefix:len()) == prefix end function string.endswith(str, suffix) return str:sub(-suffix:len()) == suffix end function string.basename(str) while true do local idx = str:find("/") if not idx then return str end str = str:sub(idx + 1) end end function lookup_table(tbl) local result = {} for _,v in ipairs(tbl) do result[v] = true end return result end -- macro replacements SHORT_FLAVORS = { -- ?? python = "py", -- ?? python2 = "py2", python3 = "py3", pypy = "pypy", } function replace_macros(str, targetflavor) local LONG_MACROS = { "sitelib", "sitearch", "alternative", "install_alternative", "uninstall_alternative", "reset_alternative", "version", "version_nodots", "bin_suffix", "prefix", "provides"} local SHORT_MACROS = { "ver" } for _, srcflavor in ipairs({flavor, "python"}) do str = str:gsub("%%__" .. srcflavor, "%%__" .. targetflavor) for _, macro in ipairs(LONG_MACROS) do local from = string.format("%s_%s", srcflavor, macro) local to = string.format("%s_%s", targetflavor, macro) str = str:gsub("%%" .. from, "%%" .. to) str = str:gsub("%%{" .. from .. "}", "%%{" .. to .. "}") str = str:gsub("%%{" .. from .. "(%s+.-)}", "%%{" .. to .. "%1}") end for _, macro in ipairs(SHORT_MACROS) do local from = string.format("%s_%s", SHORT_FLAVORS[srcflavor], macro) local to = string.format("%s_%s", SHORT_FLAVORS[targetflavor], macro) str = str:gsub("%%" .. from, "%%" .. to) str = str:gsub("%%{" .. from .. "}", "%%{" .. to .. "}") end end return str end function package_name(flavor, modname, subpkg, append) if flavor == "python2" and old_python2 then flavor = "python" end local name = flavor .. "-" .. modname if subpkg and subpkg ~= "" then name = name .. "-" .. subpkg end if append and append ~= "" then name = name .. " " .. replace_macros(append, flavor) end return name end -- alternative-related local bindir = rpm.expand("%{_bindir}") local mandir = rpm.expand("%{_mandir}") local ext_man, ext_man_expr ext_man = rpm.expand("%{ext_man}") if ext_man == "" then ext_man_expr = "%.%d$" else -- ASSUMPTION: ext_man:startswith(".") ext_man_expr = "%.%d%" .. ext_man .. "$" end function python_alternative_names(arg, binsuffix, keep_path_unmangled) local link, name, path name = arg:basename() local man_ending = arg:match(ext_man_expr) or arg:match("%.%d$") if arg:startswith("/") then link = arg elseif man_ending then link = mandir .. "/man" .. man_ending:sub(2,2) .. "/" .. arg else link = bindir .. "/" .. arg end if man_ending then path = link:sub(1, -man_ending:len()-1) .. "-" .. binsuffix .. man_ending else path = link .. "-" .. binsuffix end -- now is the time to append ext_man if appropriate -- "link" and "name" get ext_man always if ext_man ~= "" and man_ending and not arg:endswith(ext_man) then link = link .. ext_man name = name .. ext_man if not keep_path_unmangled then path = path .. ext_man end end return link, name, path end function alternative_prio(flavor) local prio = rpm.expand("%" .. flavor .. "_version_nodots") -- increase priority for primary python3 flavor local provides = rpm.expand("%" .. flavor .. "_provides") .. " " if provides:match("python3%s") then prio = prio + 1000 end return prio end function python_install_ualternative(flavor) local prio = alternative_prio(flavor) local binsuffix = rpm.expand("%" .. flavor .. "_bin_suffix") local params = {} for p in string.gmatch(rpm.expand("%*"), "%S+") do table.insert(params, p) end if #params == 0 then print("error") return end local link, name, path = python_alternative_names(params[1], binsuffix) print(string.format("update-alternatives --quiet --install %s %s %s %s", link, name, path, prio)) table.remove(params, 1) for _, v in ipairs(params) do print(string.format(" \\\\\\n --slave %s %s %s", python_alternative_names(v, binsuffix))) end end function python_install_libalternative(flavor, target) local prio = alternative_prio(flavor) local binsuffix = rpm.expand("%" .. flavor .. "_bin_suffix") local ldir = rpm.expand("%{buildroot}%{_datadir}/libalternatives") local link, name, path = python_alternative_names(target, binsuffix) local man_ending = name:match(ext_man_expr) local entry, lname if man_ending then lname=name:sub(1,-ext_man:len()-3) entry="man=" .. path:basename():sub(1,-ext_man:len()-1) else entry="binary=" .. path lname=name end print(string.format("mkdir -p %s/%s\\n", ldir, lname)) print(string.format("echo %s >> %s/%s/%s.conf\\n", entry, ldir, lname, prio)) end } %_python_scan_spec() %{lua: \ local last_python = rpm.expand("%python_for_executables")\ local insert_last_python = false\ \ pythons = {}\ -- make sure that last_python is the last item in the list\ for str in string.gmatch(rpm.expand("%pythons"), "%S+") do\ if str == last_python then\ insert_last_python = true\ else\ table.insert(pythons, str)\ end\ end\ -- ...but check that it is actually in the buildset\ if insert_last_python then table.insert(pythons, last_python) end\ \ modname = rpm.expand("%name")\ local spec_name_prefix = "python"\ -- modname from name\ local name = modname\ for _,py in ipairs(pythons) do\ if name:find(py .. "%-") == 1 then\ spec_name_prefix = py\ modname = name:sub(py:len() + 2)\ break\ end\ end\ -- try to match "python-"\ if name == modname and name:find("python%-") == 1 then\ spec_name_prefix = "python"\ modname = name:sub(8)\ end\ -- if not found, modname == %name, spec_name_prefix == "python"\ \ system_python = rpm.expand("%system_python")\ -- is the package built for python2 as "python-foo" ?\ old_python2 = rpm.expand("%python2_prefix") == "python"\ is_called_python = spec_name_prefix == "python"\ \ -- detect `flavor`, used for evaluating %ifmacros\ if is_called_python then\ -- either system_python (if found in %pythons)\ -- or the last entry of %pythons\ for _,py in ipairs(pythons) do\ flavor = py\ if flavor == system_python then break end\ end\ else\ -- specname is something other than "python-", and it is a valid\ -- python flavor (otherwise spec_name_prefix defaults to "python"\ -- so `is_called_python` is true), so we use it literally\ flavor = spec_name_prefix\ end\ \ -- find the spec file\ specpath = rpm.expand("%_specfile")\ } %python_subpackages() %{lua: \ rpm.expand("%_python_macro_init")\ _python_subpackages_emitted = true\ \ local current_flavor = flavor\ local original_flavor = rpm.expand("%python_flavor")\ \ subpackage_only = rpm.expand("%{python_subpackage_only}") == "1"\ if subpackage_only then\ is_called_python = false\ modname = ""\ end\ \ -- line processing functions\ local function print_altered(line)\ -- set %name macro to proper flavor-name\ if not subpackage_only then\ line = line:gsub("%%{?name}?", current_flavor .. "-" .. modname)\ end\ -- print expanded\ print(rpm.expand(replace_macros(line, current_flavor)) .. "\\n")\ end\ \ local function ignore_line(line) end\ \ local function files_line(line)\ -- unexpand %license at start of line\ if line:startswith("%license") then\ line = "%" .. line\ end\ return print_altered(line)\ end\ \ local PROPERTY_COPY_UNMODIFIED = lookup_table { "Summary:", "Version:", "BuildArch:" }\ local PROPERTY_COPY_MODIFIED = lookup_table {\ "Requires:", "Provides:",\ "Recommends:", "Suggests:",\ "Conflicts:", "Obsoletes:",\ "Supplements:", "Enhances:",\ "%requires_eq", "%requires_ge",\ "Requires(pre):", "Requires(preun):", "Requires(post):", "Requires(postun):",\ "Requires(pretrans):", "Requires(posttrans):",\ }\ local PROPERTY_COPY_DEFAULT_PROVIDER = lookup_table {\ "Conflicts:", "Obsoletes:", "Provides:", "Supplements:", "Enhances:",\ }\ \ local function process_package_line(line)\ -- This function processes package tags like requirements and capabilities.\ -- It supports the python- prefix for plain packages, packageand(python-a:python-b:...), and boolean dependencies.\ -- "Requires: python-foo" -> "Requires: python3-foo"\ -- "Requires: %{name} = %{version}" -> "Requires: python3-modname = %{version}"\ \ -- first split Property: value\ local property, value = line:match("^([A-Z%%]%S+)%s*(.*)$")\ \ -- split and rewrite every package value either plain or inside boolean dependencies and packageand() -- recursive\ local function replace_prefix(value, flavor)\ local function replace_prefix_r(ivalue)\ return replace_prefix(ivalue, flavor)\ end\ local function rename_package(package)\ if package == "python" or package == flavor then\ -- specialcase plain "python"\ package = current_flavor\ else\ package = package:gsub("^" .. flavor .. "(%W)", current_flavor .. "%1")\ package = package:gsub("^python(%W)", current_flavor .. "%1")\ end\ return package\ end\ local before, inner, space, remainder\ inner, space, remainder = value:match("^packageand(%b())(%s*)(.*)$")\ if inner then\ return "packageand(" .. inner:sub(2,-2):gsub("[^:]+", rename_package) .. ")" .. space .. replace_prefix_r(tostring(remainder))\ end\ before, inner, space, remainder = value:match("^([^()]*)(%b())(%s*)(.*)$")\ if inner then\ return replace_prefix_r(tostring(before)) .. "(".. replace_prefix_r(inner:sub(2, -2)) .. ")" .. space .. replace_prefix_r(tostring(remainder))\ end\ return value:gsub("%S+", rename_package)\ end\ \ if PROPERTY_COPY_UNMODIFIED[property] then\ print_altered(line)\ elseif PROPERTY_COPY_MODIFIED[property] then\ -- specifically handle %name macro before expansion\ if not subpackage_only then\ line = line:gsub("%%{?name}?", current_flavor .. "-" .. modname)\ end\ local function print_property_copy_modified(value)\ value = replace_prefix(value, flavor)\ -- rely on print_altered to perform expansion on the result\ print_altered(string.format("%s %s", property, value))\ end\ if PROPERTY_COPY_DEFAULT_PROVIDER[property] then\ -- print renamed lines for all flavors which the current_flavor provides.\ for iflavor in string.gmatch(rpm.expand("%{?" .. current_flavor .. "_provides}") .. " " .. current_flavor, "%S+" ) do\ current_flavor = iflavor -- make sure to process the main current_flavor last for final reset.\ print_property_copy_modified(value)\ end\ else\ print_property_copy_modified(value)\ end\ \ end\ end\ \ local auto_posttrans = {}\ local auto_posttrans_current = {}\ local auto_posttrans_backslash = false\ \ local function expect_alternatives(line)\ if auto_posttrans_backslash then\ local apc = auto_posttrans_current\ apc[#apc] = apc[#apc] .. "\\n" .. line\ auto_posttrans_backslash = line:endswith("\\\\")\ elseif line:startswith("%python_install_alternative")\ or line:startswith("%{python_install_alternative") -- "}"\ or line:startswith("%" .. flavor .. "_install_alternative")\ or line:startswith("%{" .. flavor .. "_install_alternative") -- "}"\ then\ table.insert(auto_posttrans_current, line)\ auto_posttrans_backslash = line:endswith("\\\\")\ else\ auto_posttrans_backslash = false\ end\ return print_altered(line)\ end\ -- end line processing functions\ \ local function print_provided_flavor(modname)\ for provided_flavor in string.gmatch(rpm.expand("%{?" .. current_flavor .. "_provides}"), "%S+" ) do\ local pkg = provided_flavor .. "-" .. modname\ print(rpm.expand("Obsoletes: " .. pkg .. " < %{?epoch:%{epoch}:}%{version}-%{release}\\n"))\ print(rpm.expand("Provides: " .. pkg .. " = %{?epoch:%{epoch}:}%{version}-%{release}\\n"))\ end\ end\ \ local function section_headline(section, flavor, param)\ if not param then param = "" end\ local subpkg = " " .. param; local flags = ""\ for flag in subpkg:gmatch("(%s%-[flp]%s+%S+)") do\ flags = flags .. flag\ end\ subpkg = subpkg:gsub("(%s%-[flp]%s+%S+)", "")\ subpkg = subpkg:gsub("^%s*(.-)%s*$", "%1")\ if section == "files" then\ local python_files = param:match("%%{?python_files}?")\ local filessubpkg = param:match("%%{python_files%s*(.-)}")\ if filessubpkg then python_files = true end\ if is_called_python and not python_files then\ -- kingly hack. but RPM's native %error does not work.\ local errmsg =\ 'error: Package with "python-" prefix must not contain unmarked "%files" sections.\\n' ..\ 'error: Use "%files %python_files" or "%files %{python_files foo} instead.\\n'\ io.stderr:write(errmsg)\ print(errmsg)\ error('Invalid spec file')\ end\ if python_files then subpkg = filessubpkg end\ end\ return "%" .. section .. " -n " .. package_name(flavor, modname, subpkg, flags) .. "\\n"\ end\ \ local python2_binsuffix = rpm.expand("%python2_bin_suffix")\ local function dump_alternatives_posttrans()\ if not old_python2 and current_flavor == "python2" then\ for label, value in pairs(auto_posttrans) do\ if value ~= false then\ print(section_headline("posttrans", current_flavor, label))\ for _,line in ipairs(value) do\ -- RPM needs {} characters in Lua macros to match, so\ -- this is an opening "{" for this one: ----------v\ firstarg = line:match("install_alternative%s+([^%s}]+)")\ if firstarg then\ local _,_,path = python_alternative_names(firstarg, python2_binsuffix)\ print(string.format('if [ -e "%s" ]; then\\n', path))\ print_altered(line)\ print("fi\\n")\ end\ end\ end\ end\ end\ auto_posttrans = {}\ end\ \ local function should_expect_alternatives(section, param)\ if old_python2 or current_flavor ~= "python2" then return false end\ if param == nil then param = "" end\ if section == "posttrans" then\ auto_posttrans[param] = false\ return false\ end\ if section == "post" and auto_posttrans[param] ~= false then\ auto_posttrans_current = {}\ auto_posttrans[param] = auto_posttrans_current\ return true\ end\ return false\ end\ \ local function match_braces(line)\ local count = 0\ for c in line:gmatch(".") do\ if c == "{" then count = count + 1\ elseif c == "}" and count > 0 then count = count - 1\ end\ end\ return count == 0\ end\ \ local KNOWN_SECTIONS = lookup_table {"package", "description", "files", "prep",\ "build", "install", "check", "clean", "pre", "post", "preun", "postun",\ "pretrans", "posttrans", "changelog"}\ local COPIED_SECTIONS = lookup_table {"description", "files",\ "pre", "post", "preun", "postun", "pretrans", "posttrans"}\ \ -- before we start, print Provides: python2-modname\ if is_called_python and old_python2 and not subpackage_only then\ print(rpm.expand("Provides: python2-" .. modname .. " = %{?epoch:%{epoch}:}%{version}-%{release}\\n"))\ end\ \ for _,python in ipairs(pythons) do\ local is_current_flavor = python == flavor\ -- "python-foo" case:\ if is_called_python then\ if old_python2 then\ -- if we're in old-style package, "python" == "python2"\ is_current_flavor = python == "python2"\ else\ -- else nothing is current flavor, always generate\ is_current_flavor = false\ end\ end\ \ current_flavor = python\ \ -- rescan spec for each flavor\ if not is_current_flavor or subpackage_only then\ local spec, err = io.open(specpath, "r")\ if err then print ("could not find spec file at path: " .. specpath) return end\ \ rpm.define("python_flavor " .. python)\ \ local section_function\ \ if subpackage_only then\ section_function = ignore_line\ else\ section_function = process_package_line\ print(section_headline("package", current_flavor, nil))\ print_provided_flavor(modname)\ end\ \ while true do\ -- collect lines until braces match. it's what rpm does, kind of.\ local eof = false\ local line = spec:read()\ if line == nil then break end\ while not match_braces(line) do\ local nl = spec:read()\ if nl == nil then eof = true break end\ line = line .. "\\n" .. nl\ end\ if eof then break end\ --io.stderr:write(current_flavor .. " >".. tostring(line) .."<\\n")\ \ -- match section delimiter\ local section_noparam = line:match("^%%(%S+)(%s*)$")\ local section_withparam, param = line:match("^%%(%S+)%s+(.+)$")\ local newsection = section_noparam or section_withparam\ \ if KNOWN_SECTIONS[newsection] then\ -- enter new section\ local ignore_section = false\ if subpackage_only then\ ignore_section = true\ if param then\ local subparam\ if newsection == "files" then\ subparam = param:match("%%{python_files%s+(.*)}")\ else\ subparam = param:match("^%-n%s+python%-(.*)$")\ end\ if subparam then\ local submodname, subsubparam = rpm.expand(subparam):match("^(%S+)%s*(.*)$")\ modname = submodname\ param = subsubparam\ ignore_section = false\ end\ end\ elseif (param and param:startswith("-n")) then\ ignore_section = true\ end\ if ignore_section then\ section_function = ignore_line\ elseif newsection == "package" then\ print(section_headline("package", current_flavor, param))\ if subpackage_only then\ print_provided_flavor(modname)\ else\ -- only valid param is a regular subpackage name\ print_provided_flavor(modname .. "-" .. param)\ end\ section_function = process_package_line\ elseif newsection == "files" and current_flavor == flavor then\ section_function = ignore_line\ elseif COPIED_SECTIONS[newsection] then\ print(section_headline(newsection, current_flavor, param))\ if should_expect_alternatives(newsection, param) then\ section_function = expect_alternatives\ elseif newsection == "files" then\ section_function = files_line\ else\ section_function = print_altered\ end\ else\ section_function = ignore_line\ end\ elseif line:startswith("%python_subpackages") then\ -- ignore\ elseif line:startswith("%if") then\ -- RPM handles %if on top level, whole sections can be conditional.\ -- We must copy the %if declarations always, even if they are part\ -- of non-copied sections. Otherwise we miss this:\ -- %files A\ -- /bin/something\ -- %if %condition\ -- %files B\ -- /bin/otherthing\ -- %endif\ print_altered(line)\ -- We are, however, copying expanded versions. This way, specifically,\ -- macros like %ifpython3 are evaluated differently in the top-level spec\ -- itself and in the copied sections.\ --io.stderr:write(rpm.expand(line) .. "\\n")\ elseif line:startswith("%else") or line:startswith("%endif") then\ print(line .. "\\n")\ --io.stderr:write(line .. "\\n")\ else\ section_function(line)\ end\ end\ \ dump_alternatives_posttrans()\ \ spec:close()\ end\ end\ \ -- restore %python_flavor for further processing\ rpm.define("python_flavor " .. original_flavor)\ } %python_exec(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-=) %{lua: \ local args = rpm.expand("%**")\ print(rpm.expand("%{python_expand $python " .. args .. "}"))\ } %python_expand(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-=) %{lua: \ -- force spec scan\ rpm.expand("%_python_macro_init")\ local args = rpm.expand("%**")\ for _, python in ipairs(pythons) do\ print(rpm.expand("%{_python_use_flavor " .. python .. "}\\n"))\ local cmd = replace_macros(args, python)\ -- when used as call of the executable, basename only\ cmd = cmd:gsub("$python%f[%s\\"\\'\\\\%)&|;<>]", string.basename(rpm.expand("%__" .. python)))\ -- when used as flavor expansion for a custom macro\ cmd = cmd:gsub("$python", python)\ print(rpm.expand(cmd .. "\\n"))\ end\ } %python_build(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-=) %{lua: \ rpm.expand("%_python_macro_init")\ for _, python in ipairs(pythons) do\ print(rpm.expand("%" .. python .. "_build %**"))\ end\ } %python_install(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-=) %{lua: \ rpm.expand("%_python_macro_init")\ for _, python in ipairs(pythons) do\ print(rpm.expand("%" .. python .. "_install %**"))\ end\ } %pyproject_wheel(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) %{lua: \ rpm.expand("%_python_macro_init")\ for _, python in ipairs(pythons) do\ print(rpm.expand("%" .. python .. "_pyproject_wheel %**"))\ end\ } %pyproject_install(+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-=) %{lua: \ rpm.expand("%_python_macro_init")\ for _, python in ipairs(pythons) do\ print(rpm.expand("%" .. python .. "_pyproject_install %**"))\ end\ } %python_compileall() %{lua: \ rpm.expand("%_python_macro_init")\ for _, python in ipairs(pythons) do\ print(rpm.expand("%" .. python .. "_compile"))\ end\ } %python_files() %{lua: \ rpm.expand("%_python_macro_init")\ local nparams = rpm.expand("%#")\ local param = ""\ if tonumber(nparams) > 0 then param = rpm.expand("%1") end\ \ if subpackage_only then\ modname = param\ param = ""\ end\ \ print("-n " .. package_name(flavor, modname, param))\ \ if not _python_subpackages_emitted then\ print("\\n/%python_subpackages_macro_not_present\\n")\ io.stderr:write("%python_subpackages macro not present\\n"\ .. "(To get rid of this error, either add a %python_subpackages macro to preamble "\ .. "or remove %python_files.\\n")\ error("%python_subpackages macro not present\\n")\ end\ } %python_clone(a) %{lua: \ rpm.expand("%_python_macro_init")\ local param = rpm.expand("%1")\ local link, name, path\ for _, python in ipairs(pythons) do\ local binsuffix = rpm.expand("%" .. python .. "_bin_suffix")\ link,name,path = python_alternative_names(param, binsuffix, true)\ print(rpm.expand(string.format("cp %s %s\\n", param, path)))\ print(rpm.expand(string.format("sed -ri \\"1s@#!.*python\\\\S*@#!%s@\\" %s\\n", "$(realpath %__" .. python .. ")", path)))\ end\ \ -- %python_clone -a\ if rpm.expand("%{?-a}") == "-a" then\ local buildroot = rpm.expand("%{buildroot}")\ if link:startswith(buildroot) then link = link:sub(buildroot:len() + 1) end\ print(rpm.expand(string.format("%%{prepare_alternative -t %s %s}\\n", link, name)))\ if rpm.expand("%{with libalternatives}") == "1" then\ for _, python in ipairs(pythons) do\ python_install_libalternative(python, link)\ end\ end\ end\ } -- called by %python_module, see buildset.in %python_module_lua() %{lua: \ rpm.expand("%_python_macro_init")\ local params = rpm.expand("%**")\ -- The Provides: tag does not support boolean dependencies, so only add parens if needed\ local lpar = ""\ local rpar = ""\ local OPERATORS = lookup_table { 'and', 'or', 'if', 'with', 'without', 'unless'}\ for p in string.gmatch(params, "%S+") do\ if OPERATORS[p] then\ lpar = "("\ rpar = ")"\ break\ end\ end\ for _, python in ipairs(pythons) do\ local python_prefix = rpm.expand("%" .. python .. "_prefix")\ print(lpar .. python_prefix .. "-" .. string.gsub(params, "%%python", python_prefix) .. rpar .. " ")\ end\ } ### LUA-MACROS ### %_python_macro_init %{_python_definitions}%{_python_scan_spec}%{lua: rpm.define("_python_macro_init %{nil}")}