Compare commits

...

No commits in common. 'c9' and 'c10-beta' have entirely different histories.
c9 ... c10-beta

@ -0,0 +1,20 @@
#!/bin/bash -e
# If using normal root, avoid changing anything.
if [ -z "$RPM_BUILD_ROOT" -o "$RPM_BUILD_ROOT" = "/" ]; then
exit 0
fi
# Defined as %py_reproducible_pyc_path macro and passed here as
# the first command-line argument
path_to_fix=$1
# First, check that the parser is available:
if [ ! -x /usr/bin/marshalparser ]; then
echo "ERROR: If %py_reproducible_pyc_path is defined, you have to also BuildRequire: /usr/bin/marshalparser !"
exit 1
fi
# Set pipefail so if $path_to_fix does not exist, the build fails
set -o pipefail
find "$path_to_fix" -type f -name "*.pyc" | xargs /usr/bin/marshalparser --fix --overwrite

@ -0,0 +1,157 @@
#!/bin/bash
errors_terminate=$2
# Usage of %_python_bytecompile_extra is not allowed anymore
# See: https://fedoraproject.org/wiki/Changes/No_more_automagic_Python_bytecompilation_phase_3
# Therefore $1 ($default_python) is not needed and is invoked with "" by default.
# $default_python stays in the arguments for backward compatibility and $extra for the following check:
extra=$3
if [ 0$extra -eq 1 ]; then
echo -e "%_python_bytecompile_extra is discontinued, use %py_byte_compile instead.\nSee: https://fedoraproject.org/wiki/Changes/No_more_automagic_Python_bytecompilation_phase_3" >/dev/stderr
exit 1
fi
compileall_flags="$4"
# If using normal root, avoid changing anything.
if [ -z "$RPM_BUILD_ROOT" -o "$RPM_BUILD_ROOT" = "/" ]; then
exit 0
fi
# This function clamps the source mtime, see https://fedoraproject.org/wiki/Changes/ReproducibleBuildsClampMtimes
function python_clamp_source_mtime()
{
local _=$1
local python_binary=$2
local _=$3
local python_libdir="$4"
PYTHONPATH=/usr/lib/rpm/redhat/ $python_binary -B -m clamp_source_mtime -q "$python_libdir"
}
# This function now implements Python byte-compilation in three different ways:
# Python >= 3.4 and < 3.9 uses a new module compileall2 - https://github.com/fedora-python/compileall2
# In Python >= 3.9, compileall2 was merged back to standard library (compileall) so we can use it directly again.
# Python < 3.4 (inc. Python 2) uses compileall module from stdlib with some hacks
function python_bytecompile()
{
local options=$1
local python_binary=$2
local exclude=$3
local python_libdir="$4"
local compileall_flags="$5"
python_version=$($python_binary -c "import sys; sys.stdout.write('{0.major}{0.minor}'.format(sys.version_info))")
#
# Python 3.4 and higher
#
if [ "$python_version" -ge 34 ]; then
# We compile all opt levels in one go: only when $options is empty.
if [ -n "$options" ]; then
return
fi
if [ "$python_version" -ge 39 ]; then
# For Pyhon 3.9+, use the standard library
compileall_module=compileall
else
# For older Pythons, use compileall2
compileall_module=compileall2
fi
if [ "$python_version" -ge 37 ]; then
# Force the TIMESTAMP invalidation mode
invalidation_option=--invalidation-mode=timestamp
else
# For older Pythons, the option does not exist
# as the invalidation is always based on size+mtime
invalidation_option=
fi
[ ! -z $exclude ] && exclude="-x '$exclude'"
# PYTHONPATH is needed for compileall2, but doesn't hurt for the stdlib
# -o 0 -o 1 are the optimization levels
# -q disables verbose output
# -f forces the process to overwrite existing compiled files
# -x excludes paths defined by regex
# -e excludes symbolic links pointing outside the build root
# -x and -e together implements the same functionality as the Filter class below
# -s strips $RPM_BUILD_ROOT from the path
# -p prepends the leading slash to the path to make it absolute
PYTHONPATH=/usr/lib/rpm/redhat/ $python_binary -B -m $compileall_module $compileall_flags -o 0 -o 1 -q -f $exclude -s "$RPM_BUILD_ROOT" -p / --hardlink-dupes $invalidation_option -e "$RPM_BUILD_ROOT" "$python_libdir"
else
#
# Python 3.3 and lower (incl. Python 2)
#
local real_libdir=${python_libdir/$RPM_BUILD_ROOT/}
cat << EOF | $python_binary $options
import compileall, sys, os, re
python_libdir = "$python_libdir"
depth = sys.getrecursionlimit()
real_libdir = "$real_libdir"
build_root = "$RPM_BUILD_ROOT"
exclude = r"$exclude"
class Filter:
def search(self, path):
ret = not os.path.realpath(path).startswith(build_root)
if exclude:
ret = ret or re.search(exclude, path)
return ret
sys.exit(not compileall.compile_dir(python_libdir, depth, real_libdir, force=1, rx=Filter(), quiet=1))
EOF
fi
}
# .pyc/.pyo files embed a "magic" value, identifying the ABI version of Python
# bytecode that they are for.
#
# The files below RPM_BUILD_ROOT could be targeting multiple versions of
# python (e.g. a single build that emits several subpackages e.g. a
# python26-foo subpackage, a python31-foo subpackage etc)
#
# Support this by assuming that below each /usr/lib/python$VERSION/, all
# .pyc/.pyo files are to be compiled for /usr/bin/python$VERSION.
#
# For example, below /usr/lib/python2.6/, we're targeting /usr/bin/python2.6
# and below /usr/lib/python3.1/, we're targeting /usr/bin/python3.1
# Disable Python hash seed randomization
# This should help with byte-compilation reproducibility: https://bugzilla.redhat.com/show_bug.cgi?id=1686078
# Python 3.11+ no longer needs this: https://github.com/python/cpython/pull/27926 (but we support older Pythons as well)
export PYTHONHASHSEED=0
shopt -s nullglob
find "$RPM_BUILD_ROOT" -type d -print0|grep -z -E "/(usr|app)/lib(64)?/python[0-9]\.[0-9]+$" | while read -d "" python_libdir;
do
python_binary=$(basename "$python_libdir")
echo "Bytecompiling .py files below $python_libdir using $python_binary"
# Generate normal (.pyc) byte-compiled files.
python_clamp_source_mtime "" "$python_binary" "" "$python_libdir" ""
if [ $? -ne 0 -a 0$errors_terminate -ne 0 ]; then
# One or more of the files had inaccessible mtime
exit 1
fi
python_bytecompile "" "$python_binary" "" "$python_libdir" "$compileall_flags"
if [ $? -ne 0 -a 0$errors_terminate -ne 0 ]; then
# One or more of the files had a syntax error
exit 1
fi
# Generate optimized (.pyo) byte-compiled files.
# N.B. For Python 3.4+, this call does nothing
python_bytecompile "-O" "$python_binary" "" "$python_libdir" "$compileall_flags"
if [ $? -ne 0 -a 0$errors_terminate -ne 0 ]; then
# One or more of the files had a syntax error
exit 1
fi
done

@ -0,0 +1,25 @@
#!/bin/sh
# If using normal root, avoid changing anything.
if [ -z "$RPM_BUILD_ROOT" ] || [ "$RPM_BUILD_ROOT" = "/" ]; then
exit 0
fi
hardlink_if_same() {
if cmp -s "$1" "$2" ; then
ln -f "$1" "$2"
return 0
fi
return 1
}
# Hardlink identical *.pyc, *.pyo, and *.opt-[12].pyc.
# Originally from PLD's rpm-build-macros
find "$RPM_BUILD_ROOT" -type f -name "*.pyc" -not -name "*.opt-[12].pyc" | while read pyc ; do
hardlink_if_same "$pyc" "${pyc%c}o"
o1pyc="${pyc%pyc}opt-1.pyc"
hardlink_if_same "$pyc" "$o1pyc"
o2pyc="${pyc%pyc}opt-2.pyc"
hardlink_if_same "$pyc" "$o2pyc" || hardlink_if_same "$o1pyc" "$o2pyc"
done
exit 0

@ -0,0 +1,163 @@
"""Module/script to clamp the mtimes of all .py files to $SOURCE_DATE_EPOCH
When called as a script with arguments, this compiles the directories
given as arguments recursively.
If upstream is interested, this can be later integrated to the compileall module
as an additional option (e.g. --clamp-source-mtime).
License:
This has been derived from the Python's compileall module
and it follows Python licensing. For more info see: https://www.python.org/psf/license/
"""
from __future__ import print_function
import os
import sys
# Python 3.6 and higher
PY36 = sys.version_info[0:2] >= (3, 6)
__all__ = ["clamp_dir", "clamp_file"]
def _walk_dir(dir, maxlevels, quiet=0):
if PY36 and quiet < 2 and isinstance(dir, os.PathLike):
dir = os.fspath(dir)
else:
dir = str(dir)
if not quiet:
print('Listing {!r}...'.format(dir))
try:
names = os.listdir(dir)
except OSError:
if quiet < 2:
print("Can't list {!r}".format(dir))
names = []
names.sort()
for name in names:
if name == '__pycache__':
continue
fullname = os.path.join(dir, name)
if not os.path.isdir(fullname):
yield fullname
elif (maxlevels > 0 and name != os.curdir and name != os.pardir and
os.path.isdir(fullname) and not os.path.islink(fullname)):
for result in _walk_dir(fullname, maxlevels=maxlevels - 1,
quiet=quiet):
yield result
def clamp_dir(dir, source_date_epoch, quiet=0):
"""Clamp the mtime of all modules in the given directory tree.
Arguments:
dir: the directory to byte-compile
source_date_epoch: integer parsed from $SOURCE_DATE_EPOCH
quiet: full output with False or 0, errors only with 1,
no output with 2
"""
maxlevels = sys.getrecursionlimit()
files = _walk_dir(dir, quiet=quiet, maxlevels=maxlevels)
success = True
for file in files:
if not clamp_file(file, source_date_epoch, quiet=quiet):
success = False
return success
def clamp_file(fullname, source_date_epoch, quiet=0):
"""Clamp the mtime of one file.
Arguments:
fullname: the file to byte-compile
source_date_epoch: integer parsed from $SOURCE_DATE_EPOCH
quiet: full output with False or 0, errors only with 1,
no output with 2
"""
if PY36 and quiet < 2 and isinstance(fullname, os.PathLike):
fullname = os.fspath(fullname)
else:
fullname = str(fullname)
name = os.path.basename(fullname)
if os.path.isfile(fullname) and not os.path.islink(fullname):
if name[-3:] == '.py':
try:
mtime = int(os.stat(fullname).st_mtime)
atime = int(os.stat(fullname).st_atime)
except OSError as e:
if quiet >= 2:
return False
elif quiet:
print('*** Error checking mtime of {!r}...'.format(fullname))
else:
print('*** ', end='')
print(e.__class__.__name__ + ':', e)
return False
if mtime > source_date_epoch:
if not quiet:
print('Clamping mtime of {!r}'.format(fullname))
try:
os.utime(fullname, (atime, source_date_epoch))
except OSError as e:
if quiet >= 2:
return False
elif quiet:
print('*** Error clamping mtime of {!r}...'.format(fullname))
else:
print('*** ', end='')
print(e.__class__.__name__ + ':', e)
return False
return True
def main():
"""Script main program."""
import argparse
source_date_epoch = os.getenv('SOURCE_DATE_EPOCH')
if not source_date_epoch:
print("Not clamping source mtimes, $SOURCE_DATE_EPOCH not set")
return True # This is a success, no action needed
try:
source_date_epoch = int(source_date_epoch)
except ValueError:
print("$SOURCE_DATE_EPOCH must be an integer")
return False
parser = argparse.ArgumentParser(
description='Clamp .py source mtime to $SOURCE_DATE_EPOCH.')
parser.add_argument('-q', action='count', dest='quiet', default=0,
help='output only error messages; -qq will suppress '
'the error messages as well.')
parser.add_argument('clamp_dest', metavar='FILE|DIR', nargs='+',
help=('zero or more file and directory paths '
'to clamp'))
args = parser.parse_args()
clamp_dests = args.clamp_dest
success = True
try:
for dest in clamp_dests:
if os.path.isfile(dest):
if not clamp_file(dest, quiet=args.quiet,
source_date_epoch=source_date_epoch):
success = False
else:
if not clamp_dir(dest, quiet=args.quiet,
source_date_epoch=source_date_epoch):
success = False
return success
except KeyboardInterrupt:
if args.quiet < 2:
print("\n[interrupted]")
return False
return True
if __name__ == '__main__':
exit_status = int(not main())
sys.exit(exit_status)

@ -14,10 +14,17 @@
# Setting PYTHONHASHSEED=0 disables Python hash seed randomization
# This should help with byte-compilation reproducibility: https://bugzilla.redhat.com/show_bug.cgi?id=1686078
# Python 3.11+ no longer needs this: https://github.com/python/cpython/pull/27926 (but we support older Pythons as well)
%py_byte_compile()\
clamp_source_mtime () {\
python_binary="%{__env_unset_source_date_epoch_if_not_clamp_mtime} %1"\
bytecode_compilation_path="%2"\
PYTHONPATH="%{_rpmconfigdir}/redhat" $python_binary -s -B -m clamp_source_mtime $bytecode_compilation_path \
}\
\
py2_byte_compile () {\
python_binary="env PYTHONHASHSEED=0 %1"\
python_binary="%{__env_unset_source_date_epoch_if_not_clamp_mtime} PYTHONHASHSEED=0 %1"\
bytecode_compilation_path="%2"\
failure=0\
find $bytecode_compilation_path -type f -a -name "*.py" -print0 | xargs -0 $python_binary -s -c 'import py_compile, sys; [py_compile.compile(f, dfile=f.partition("'"$RPM_BUILD_ROOT"'")[2], doraise=True) for f in sys.argv[1:]]' || failure=1\
@ -25,28 +32,38 @@ py2_byte_compile () {\
test $failure -eq 0\
}\
\
py3_byte_compile () {\
python_binary="env PYTHONHASHSEED=0 %1"\
py34_byte_compile () {\
python_binary="%{__env_unset_source_date_epoch_if_not_clamp_mtime} PYTHONHASHSEED=0 %1"\
bytecode_compilation_path="%2"\
PYTHONPATH="%{_rpmconfigdir}/redhat" $python_binary -s -B -m compileall2 %{?_smp_build_ncpus:-j%{_smp_build_ncpus}} -o 0 -o 1 -s $RPM_BUILD_ROOT -p / --hardlink-dupes $bytecode_compilation_path \
}\
py37_byte_compile () {\
python_binary="%{__env_unset_source_date_epoch_if_not_clamp_mtime} PYTHONHASHSEED=0 %1"\
bytecode_compilation_path="%2"\
PYTHONPATH="%{_rpmconfigdir}/redhat" $python_binary -s -B -m compileall2 -o 0 -o 1 -s $RPM_BUILD_ROOT -p / $bytecode_compilation_path \
PYTHONPATH="%{_rpmconfigdir}/redhat" $python_binary -s -B -m compileall2 %{?_smp_build_ncpus:-j%{_smp_build_ncpus}} -o 0 -o 1 -s $RPM_BUILD_ROOT -p / --hardlink-dupes --invalidation-mode=timestamp $bytecode_compilation_path \
}\
\
py39_byte_compile () {\
python_binary="env PYTHONHASHSEED=0 %1"\
python_binary="%{__env_unset_source_date_epoch_if_not_clamp_mtime} PYTHONHASHSEED=0 %1"\
bytecode_compilation_path="%2"\
$python_binary -s -B -m compileall -o 0 -o 1 -s $RPM_BUILD_ROOT -p / $bytecode_compilation_path \
$python_binary -s -B -m compileall %{?_smp_build_ncpus:-j%{_smp_build_ncpus}} -o 0 -o 1 -s $RPM_BUILD_ROOT -p / --hardlink-dupes --invalidation-mode=timestamp $bytecode_compilation_path \
}\
\
# Path to intepreter should not contain any arguments \
[[ "%1" =~ " -" ]] && echo "ERROR py_byte_compile: Path to interpreter should not contain any arguments" >&2 && exit 1 \
# First, clamp source mtime https://fedoraproject.org/wiki/Changes/ReproducibleBuildsClampMtimes \
clamp_source_mtime "%1" "%2"; \
# Get version without a dot (36 instead of 3.6), bash doesn't compare floats well \
python_version=$(%1 -c "import sys; sys.stdout.write('{0.major}{0.minor}'.format(sys.version_info))") \
# compileall2 is an enhanced fork of stdlib compileall module for Python >= 3.4 \
# and it was merged back to stdlib in Python >= 3.9 \
# Only Python 3.7+ supports and needs the --invalidation-mode option \
if [ "$python_version" -ge 39 ]; then \
py39_byte_compile "%1" "%2"; \
elif [ "$python_version" -ge 37 ]; then \
py37_byte_compile "%1" "%2"; \
elif [ "$python_version" -ge 34 ]; then \
py3_byte_compile "%1" "%2"; \
py34_byte_compile "%1" "%2"; \
else \
py2_byte_compile "%1" "%2"; \
fi

@ -1,32 +1,71 @@
# Memoize a macro to avoid calling the same expensive code multiple times in
# the specfile.
# There is no error handling,
# memoizing an undefined macro (or using such a key) has undefined behavior.
# Options:
# -n - The name of the macro to wrap
# -k - The name of the macro to use as a cache key
%_python_memoize(n:k:) %{lua:
local name = opt.n
-- NB: We use rpm.expand() here instead of the macros table to make sure errors
-- are propogated properly.
local cache_key = rpm.expand("%{" .. opt.k .. "}")
if not _python_macro_cache then
-- This is intentionally a global lua table
_python_macro_cache = {}
end
if not _python_macro_cache[cache_key] then
_python_macro_cache[cache_key] = {}
end
if not _python_macro_cache[cache_key][name] then
_python_macro_cache[cache_key][name] = rpm.expand("%{" .. name .. "}")
end
print(_python_macro_cache[cache_key][name])
}
# unversioned macros: used with user defined __python, no longer part of rpm >= 4.15
# __python is defined to error by default in the srpm macros
# nb: $RPM_BUILD_ROOT is not set when the macros are expanded (at spec parse time)
# so we set it manually (to empty string), making our Python prefer the correct install scheme location
%python_sitelib %(RPM_BUILD_ROOT= %{__python} -Esc "import sysconfig; print(sysconfig.get_path('purelib'))")
%python_sitearch %(RPM_BUILD_ROOT= %{__python} -Esc "import sysconfig; print(sysconfig.get_path('platlib'))")
%python_version %(RPM_BUILD_ROOT= %{__python} -Esc "import sys; sys.stdout.write('{0.major}.{0.minor}'.format(sys.version_info))")
%python_version_nodots %(RPM_BUILD_ROOT= %{__python} -Esc "import sys; sys.stdout.write('{0.major}{0.minor}'.format(sys.version_info))")
%python_platform %(RPM_BUILD_ROOT= %{__python} -Esc "import sysconfig; print(sysconfig.get_platform())")
%python_platform_triplet %(RPM_BUILD_ROOT= %{__python} -Esc "import sysconfig; print(sysconfig.get_config_var('MULTIARCH'))")
%python_ext_suffix %(RPM_BUILD_ROOT= %{__python} -Esc "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))")
# platbase/base is explicitly set to %%{_prefix} to support custom values, such as /app for flatpaks
%__python_sitelib %(RPM_BUILD_ROOT= %{__python} -Esc "import sysconfig; print(sysconfig.get_path('purelib', vars={'platbase': '%{_prefix}', 'base': '%{_prefix}'}))")
%python_sitelib %{_python_memoize -n __python_sitelib -k __python}
%__python_sitearch %(RPM_BUILD_ROOT= %{__python} -Esc "import sysconfig; print(sysconfig.get_path('platlib', vars={'platbase': '%{_prefix}', 'base': '%{_prefix}'}))")
%python_sitearch %{_python_memoize -n __python_sitearch -k __python}
%__python_version %(RPM_BUILD_ROOT= %{__python} -Esc "import sys; sys.stdout.write('{0.major}.{0.minor}'.format(sys.version_info))")
%python_version %{_python_memoize -n __python_version -k __python}
%__python_version_nodots %(RPM_BUILD_ROOT= %{__python} -Esc "import sys; sys.stdout.write('{0.major}{0.minor}'.format(sys.version_info))")
%python_version_nodots %{_python_memoize -n __python_version_nodots -k __python}
%__python_platform %(RPM_BUILD_ROOT= %{__python} -Esc "import sysconfig; print(sysconfig.get_platform())")
%python_platform %{_python_memoize -n __python_platform -k __python}
%__python_platform_triplet %(RPM_BUILD_ROOT= %{__python} -Esc "import sysconfig; print(sysconfig.get_config_var('MULTIARCH'))")
%python_platform_triplet %{_python_memoize -n __python_platform_triplet -k __python}
%__python_ext_suffix %(RPM_BUILD_ROOT= %{__python} -Esc "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))")
%python_ext_suffix %{_python_memoize -n __python_ext_suffix -k __python}
%__python_cache_tag %(RPM_BUILD_ROOT= %{__python} -Esc "import sys; print(sys.implementation.cache_tag)")
%python_cache_tag %{_python_memoize -n __python_cache_tag -k __python}
%py_setup setup.py
%py_shbang_opts -s
%_py_shebang_s s
%__py_shebang_P %(RPM_BUILD_ROOT= %{__python} -Esc "import sys; print('P' if hasattr(sys.flags, 'safe_path') else '')")
%_py_shebang_P %{_python_memoize -n __py_shebang_P -k __python}
%py_shbang_opts -%{?_py_shebang_s}%{?_py_shebang_P}
%py_shbang_opts_nodash %(opts=%{py_shbang_opts}; echo ${opts#-})
%py_shebang_flags %(opts=%{py_shbang_opts}; echo ${opts#-})
%py_shebang_fix %{expand:\\\
if [ -f /usr/bin/pathfix%{python_version}.py ]; then
pathfix=/usr/bin/pathfix%{python_version}.py
else
# older versions of Python don't have it and must BR /usr/bin/pathfix.py from python3-devel explicitly
pathfix=/usr/bin/pathfix.py
fi
if [ -z "%{?py_shebang_flags}" ]; then
shebang_flags="-k"
else
shebang_flags="-ka%{py_shebang_flags}"
fi
$pathfix -pni %{__python} $shebang_flags}
%{__python} -B %{_rpmconfigdir}/redhat/pathfix.py -pni %{__python} $shebang_flags}
# Use the slashes after expand so that the command starts on the same line as
# the macro
@ -35,11 +74,6 @@
%{__python} %{py_setup} %{?py_setup_args} build --executable="%{__python} %{py_shbang_opts}" %{?*}
}
%py_build_egg() %{expand:\\\
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
%{__python} %{py_setup} %{?py_setup_args} bdist_egg %{?*}
}
%py_build_wheel() %{expand:\\\
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
%{__python} %{py_setup} %{?py_setup_args} bdist_wheel %{?*}
@ -47,18 +81,12 @@
%py_install() %{expand:\\\
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
%{__python} %{py_setup} %{?py_setup_args} install -O1 --skip-build --root %{buildroot} %{?*}
rm -rfv %{buildroot}%{_bindir}/__pycache__
}
%py_install_egg() %{expand:\\\
mkdir -p %{buildroot}%{python_sitelib}
%{__python} -m easy_install -m --prefix %{buildroot}%{_prefix} -Z dist/*-py%{python_version}.egg %{?*}
%{__python} %{py_setup} %{?py_setup_args} install -O1 --skip-build --root %{buildroot} --prefix %{_prefix} %{?*}
rm -rfv %{buildroot}%{_bindir}/__pycache__
}
%py_install_wheel() %{expand:\\\
%{__python} -m pip install -I dist/%{1} --root %{buildroot} --no-deps --no-index --no-warn-script-location
%{__python} -m pip install -I dist/%{1} --root %{buildroot} --prefix %{_prefix} --no-deps --no-index --no-warn-script-location
rm -rfv %{buildroot}%{_bindir}/__pycache__
for distinfo in %{buildroot}%{python_sitelib}/*.dist-info %{buildroot}%{python_sitearch}/*.dist-info; do
if [ -f ${distinfo}/direct_url.json ]; then
@ -133,6 +161,16 @@
end
}
# Environment variables for testing used standalone, e.g.:
# %%{py_test_envvars} %%{python} -m unittest
%py_test_envvars %{expand:\\\
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
PATH="%{buildroot}%{_bindir}:$PATH"\\\
PYTHONPATH="${PYTHONPATH:-%{buildroot}%{python_sitearch}:%{buildroot}%{python_sitelib}}"\\\
PYTHONDONTWRITEBYTECODE=1\\\
%{?__pytest_addopts:PYTEST_ADDOPTS="${PYTEST_ADDOPTS:-} %{__pytest_addopts}"}\\\
PYTEST_XDIST_AUTO_NUM_WORKERS="${PYTEST_XDIST_AUTO_NUM_WORKERS:-%{_smp_build_ncpus}}"}
%python_disable_dependency_generator() \
%undefine __pythondist_requires \
%{nil}

@ -17,7 +17,7 @@
# There are two macros:
#
# This always contains the major.minor version (with dots), default for %%python3_version.
%__default_python3_version 3.9
%__default_python3_version 3.12
#
# The pkgname version that determines the alternative provide name (e.g. python3.9-foo),
# set to the same as above, but historically hasn't included the dot.
@ -63,6 +63,37 @@
%python_wheel_pkg_prefix python%{?rhel:%{!?eln:%{python3_pkgversion}}}
%python_wheel_dir %{_datadir}/%{python_wheel_pkg_prefix}-wheels
### BRP scripts (and related macros)
## Automatically compile python files
%py_auto_byte_compile 1
## Should python bytecompilation errors terminate a build?
%_python_bytecompile_errors_terminate_build 1
## Should python bytecompilation compile outside python specific directories?
## This always causes errors when enabled, see https://fedoraproject.org/wiki/Changes/No_more_automagic_Python_bytecompilation_phase_3
%_python_bytecompile_extra 0
## Helper macro to unset $SOURCE_DATE_EPOCH if %%clamp_mtime_to_source_date_epoch is not set
## https://fedoraproject.org/wiki/Changes/ReproducibleBuildsClampMtimes#Python_bytecode
%__env_unset_source_date_epoch_if_not_clamp_mtime %[0%{?clamp_mtime_to_source_date_epoch} == 0 ? "env -u SOURCE_DATE_EPOCH" : "env"]
## The individual BRP scripts
%__brp_python_bytecompile %{__env_unset_source_date_epoch_if_not_clamp_mtime} %{_rpmconfigdir}/redhat/brp-python-bytecompile "" "%{?_python_bytecompile_errors_terminate_build}" "%{?_python_bytecompile_extra}" "%{?_smp_build_ncpus:-j%{_smp_build_ncpus}}"
%__brp_fix_pyc_reproducibility %{_rpmconfigdir}/redhat/brp-fix-pyc-reproducibility
%__brp_python_hardlink %{_rpmconfigdir}/redhat/brp-python-hardlink
## This macro is included in redhat-rpm-config's %%__os_install_post
# Note that the order matters:
# 1. brp-python-bytecompile can create (or replace) pyc files
# 2. brp-fix-pyc-reproducibility can modify the pyc files from above
# 3. brp-python-hardlink de-duplicates identical pyc files
%__os_install_post_python \
%{?py_auto_byte_compile:%{?__brp_python_bytecompile}} \
%{?py_reproducible_pyc_path:%{?__brp_fix_pyc_reproducibility} "%{py_reproducible_pyc_path}"} \
%{?__brp_python_hardlink} \
%{nil}
# === Macros for Build/Requires tags using Python dist tags ===
# - https://fedoraproject.org/wiki/Changes/Automatic_Provides_for_Python_RPM_Packages
# - These macros need to be in macros.python-srpm, because BuildRequires tags
@ -178,7 +209,7 @@
print('Provides: ' .. provide .. '\\n')
end
-- We only generate these Obsoletes on CentOS/RHEL to provide clean upgrade
-- path, e.g. python3-foo obsoletes python39-foo from previous RHEL.
-- path, e.g. python3-foo obsoletes python3.9-foo from previous RHEL.
-- In Fedora this is not needed as we don't ship ecosystem packages
-- for alternative Python interpreters.
if rhel ~= '' then
@ -194,15 +225,19 @@
end
}
%python_extras_subpkg(n:i:f:F) %{expand:%{lua:
%python_extras_subpkg(n:i:f:FaA) %{expand:%{lua:
local option_n = '-n (name of the base package)'
local option_i = '-i (buildroot path to metadata)'
local option_f = '-f (builddir path to a filelist)'
local option_F = '-F (skip %%files section)'
local option_a = '-a (insert BuildArch: noarch)'
local option_A = '-A (do not insert BuildArch: noarch (default))'
local value_n = rpm.expand('%{-n*}')
local value_i = rpm.expand('%{-i*}')
local value_f = rpm.expand('%{-f*}')
local value_F = rpm.expand('%{-F}')
local value_a = rpm.expand('%{-a}')
local value_A = rpm.expand('%{-A}')
local args = rpm.expand('%{*}')
if value_n == '' then
rpm.expand('%{error:%%%0: missing option ' .. option_n .. '}')
@ -219,6 +254,9 @@
if value_f ~= '' and value_F ~= '' then
rpm.expand('%{error:%%%0: simultaneous ' .. option_f .. ' and ' .. option_F .. ' options are not possible}')
end
if value_a ~= '' and value_A ~= '' then
rpm.expand('%{error:%%%0: simultaneous ' .. option_a .. ' and ' .. option_A .. ' options are not possible}')
end
if args == '' then
rpm.expand('%{error:%%%0 requires at least one argument with "extras" name}')
end
@ -246,7 +284,11 @@
elseif value_f ~= '' then
files = '%files -n ' .. rpmname .. ' -f ' .. value_f
end
for i, line in ipairs({pkgdef, summary, requires, description, files, ''}) do
local tags = summary .. '\\\n' .. requires
if value_a ~= '' then
tags = tags .. '\\\nBuildArch: noarch'
end
for i, line in ipairs({pkgdef, tags, description, files, ''}) do
print(line .. '\\\n')
end
end

@ -1,30 +1,45 @@
# nb: $RPM_BUILD_ROOT is not set when the macros are expanded (at spec parse time)
# so we set it manually (to empty string), making our Python prefer the correct install scheme location
%python3_sitelib %(RPM_BUILD_ROOT= %{__python3} -Ic "import sysconfig; print(sysconfig.get_path('purelib'))")
%python3_sitearch %(RPM_BUILD_ROOT= %{__python3} -Ic "import sysconfig; print(sysconfig.get_path('platlib'))")
%python3_version %(RPM_BUILD_ROOT= %{__python3} -Ic "import sys; sys.stdout.write('{0.major}.{0.minor}'.format(sys.version_info))")
%python3_version_nodots %(RPM_BUILD_ROOT= %{__python3} -Ic "import sys; sys.stdout.write('{0.major}{0.minor}'.format(sys.version_info))")
%python3_platform %(RPM_BUILD_ROOT= %{__python3} -Ic "import sysconfig; print(sysconfig.get_platform())")
%python3_platform_triplet %(RPM_BUILD_ROOT= %{__python3} -Ic "import sysconfig; print(sysconfig.get_config_var('MULTIARCH'))")
%python3_ext_suffix %(RPM_BUILD_ROOT= %{__python3} -Ic "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))")
# platbase/base is explicitly set to %%{_prefix} to support custom values, such as /app for flatpaks
%__python3_sitelib %(RPM_BUILD_ROOT= %{__python3} -Esc "import sysconfig; print(sysconfig.get_path('purelib', vars={'platbase': '%{_prefix}', 'base': '%{_prefix}'}))")
%python3_sitelib %{_python_memoize -n __python3_sitelib -k __python3}
%__python3_sitearch %(RPM_BUILD_ROOT= %{__python3} -Esc "import sysconfig; print(sysconfig.get_path('platlib', vars={'platbase': '%{_prefix}', 'base': '%{_prefix}'}))")
%python3_sitearch %{_python_memoize -n __python3_sitearch -k __python3}
%__python3_version %(RPM_BUILD_ROOT= %{__python3} -Esc "import sys; sys.stdout.write('{0.major}.{0.minor}'.format(sys.version_info))")
%python3_version %{_python_memoize -n __python3_version -k __python3}
%__python3_version_nodots %(RPM_BUILD_ROOT= %{__python3} -Esc "import sys; sys.stdout.write('{0.major}{0.minor}'.format(sys.version_info))")
%python3_version_nodots %{_python_memoize -n __python3_version_nodots -k __python3}
%__python3_platform %(RPM_BUILD_ROOT= %{__python3} -Esc "import sysconfig; print(sysconfig.get_platform())")
%python3_platform %{_python_memoize -n __python3_platform -k __python3}
%__python3_platform_triplet %(RPM_BUILD_ROOT= %{__python3} -Esc "import sysconfig; print(sysconfig.get_config_var('MULTIARCH'))")
%python3_platform_triplet %{_python_memoize -n __python3_platform_triplet -k __python3}
%__python3_ext_suffix %(RPM_BUILD_ROOT= %{__python3} -Esc "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))")
%python3_ext_suffix %{_python_memoize -n __python3_ext_suffix -k __python3}
%__python3_cache_tag %(RPM_BUILD_ROOT= %{__python3} -Esc "import sys; print(sys.implementation.cache_tag)")
%python3_cache_tag %{_python_memoize -n __python3_cache_tag -k __python3}
%py3dir %{_builddir}/python3-%{name}-%{version}-%{release}
%py3_shbang_opts -s
%_py3_shebang_s s
%__py3_shebang_P %(RPM_BUILD_ROOT= %{__python3} -Ic "import sys; print('P' if hasattr(sys.flags, 'safe_path') else '')")
%_py3_shebang_P %{_python_memoize -n __py3_shebang_P -k __python3}
%py3_shbang_opts -%{?_py3_shebang_s}%{?_py3_shebang_P}
%py3_shbang_opts_nodash %(opts=%{py3_shbang_opts}; echo ${opts#-})
%py3_shebang_flags %(opts=%{py3_shbang_opts}; echo ${opts#-})
%py3_shebang_fix %{expand:\\\
if [ -f /usr/bin/pathfix%{python3_version}.py ]; then
pathfix=/usr/bin/pathfix%{python3_version}.py
else
# older versions of Python don't have it and must BR /usr/bin/pathfix.py from python3-devel explicitly
pathfix=/usr/bin/pathfix.py
fi
if [ -z "%{?py3_shebang_flags}" ]; then
shebang_flags="-k"
else
shebang_flags="-ka%{py3_shebang_flags}"
fi
$pathfix -pni %{__python3} $shebang_flags}
%{__python3} -B %{_rpmconfigdir}/redhat/pathfix.py -pni %{__python3} $shebang_flags}
# Use the slashes after expand so that the command starts on the same line as
# the macro
@ -33,11 +48,6 @@
%{__python3} %{py_setup} %{?py_setup_args} build --executable="%{__python3} %{py3_shbang_opts}" %{?*}
}
%py3_build_egg() %{expand:\\\
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
%{__python3} %{py_setup} %{?py_setup_args} bdist_egg %{?*}
}
%py3_build_wheel() %{expand:\\\
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
%{__python3} %{py_setup} %{?py_setup_args} bdist_wheel %{?*}
@ -45,18 +55,12 @@
%py3_install() %{expand:\\\
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
%{__python3} %{py_setup} %{?py_setup_args} install -O1 --skip-build --root %{buildroot} %{?*}
rm -rfv %{buildroot}%{_bindir}/__pycache__
}
%py3_install_egg() %{expand:\\\
mkdir -p %{buildroot}%{python3_sitelib}
%{__python3} -m easy_install -m --prefix %{buildroot}%{_prefix} -Z dist/*-py%{python3_version}.egg %{?*}
%{__python3} %{py_setup} %{?py_setup_args} install -O1 --skip-build --root %{buildroot} --prefix %{_prefix} %{?*}
rm -rfv %{buildroot}%{_bindir}/__pycache__
}
%py3_install_wheel() %{expand:\\\
%{__python3} -m pip install -I dist/%{1} --root %{buildroot} --no-deps --no-index --no-warn-script-location
%{__python3} -m pip install -I dist/%{1} --root %{buildroot} --prefix %{_prefix} --no-deps --no-index --no-warn-script-location
rm -rfv %{buildroot}%{_bindir}/__pycache__
for distinfo in %{buildroot}%{python3_sitelib}/*.dist-info %{buildroot}%{python3_sitearch}/*.dist-info; do
if [ -f ${distinfo}/direct_url.json ]; then
@ -102,16 +106,21 @@
pyminor = path:match("/python3.(%d+)/") or "*"
dirname = path:match("(.*/)")
modulename = path:match(".*/([^/]+).py")
-- %%python3_cache_tag is not used here because this macro supports not-installed CPythons
print("\\n" .. dirname .. "__pycache__/" .. modulename .. ".cpython-3" .. pyminor .. "{,.opt-?}.pyc")
end
}
# This is intended for Python 3 only, hence also no Python version in the name.
%__pytest /usr/bin/pytest%(test %{python3_pkgversion} == 3 || echo -%{python3_version})
%pytest %{expand:\\\
# Environment variables used by %%pytest, %%tox or standalone, e.g.:
# %%{py3_test_envvars} %%{python3} -m unittest
%py3_test_envvars %{expand:\\\
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
PATH="%{buildroot}%{_bindir}:$PATH"\\\
PYTHONPATH="${PYTHONPATH:-%{buildroot}%{python3_sitearch}:%{buildroot}%{python3_sitelib}}"\\\
PYTHONDONTWRITEBYTECODE=1\\\
%{?__pytest_addopts:PYTEST_ADDOPTS="${PYTEST_ADDOPTS:-} %{__pytest_addopts}"}\\\
%__pytest}
PYTEST_XDIST_AUTO_NUM_WORKERS="${PYTEST_XDIST_AUTO_NUM_WORKERS:-%{_smp_build_ncpus}}"}
# This is intended for Python 3 only, hence also no Python version in the name.
%__pytest /usr/bin/pytest%(test %{python3_pkgversion} == 3 || echo -%{python3_version})
%pytest %py3_test_envvars %__pytest

@ -0,0 +1,199 @@
#!/usr/bin/env python3
import sys
import os
from stat import *
import getopt
err = sys.stderr.write
dbg = err
rep = sys.stdout.write
new_interpreter = None
preserve_timestamps = False
create_backup = True
keep_flags = False
add_flags = b''
def main():
global new_interpreter
global preserve_timestamps
global create_backup
global keep_flags
global add_flags
usage = ('usage: %s -i /interpreter -p -n -k -a file-or-directory ...\n' %
sys.argv[0])
try:
opts, args = getopt.getopt(sys.argv[1:], 'i:a:kpn')
except getopt.error as msg:
err(str(msg) + '\n')
err(usage)
sys.exit(2)
for o, a in opts:
if o == '-i':
new_interpreter = a.encode()
if o == '-p':
preserve_timestamps = True
if o == '-n':
create_backup = False
if o == '-k':
keep_flags = True
if o == '-a':
add_flags = a.encode()
if b' ' in add_flags:
err("-a option doesn't support whitespaces")
sys.exit(2)
if not new_interpreter or not new_interpreter.startswith(b'/') or \
not args:
err('-i option or file-or-directory missing\n')
err(usage)
sys.exit(2)
bad = 0
for arg in args:
if os.path.isdir(arg):
if recursedown(arg): bad = 1
elif os.path.islink(arg):
err(arg + ': will not process symbolic links\n')
bad = 1
else:
if fix(arg): bad = 1
sys.exit(bad)
def ispython(name):
return name.endswith('.py')
def recursedown(dirname):
dbg('recursedown(%r)\n' % (dirname,))
bad = 0
try:
names = os.listdir(dirname)
except OSError as msg:
err('%s: cannot list directory: %r\n' % (dirname, msg))
return 1
names.sort()
subdirs = []
for name in names:
if name in (os.curdir, os.pardir): continue
fullname = os.path.join(dirname, name)
if os.path.islink(fullname): pass
elif os.path.isdir(fullname):
subdirs.append(fullname)
elif ispython(name):
if fix(fullname): bad = 1
for fullname in subdirs:
if recursedown(fullname): bad = 1
return bad
def fix(filename):
## dbg('fix(%r)\n' % (filename,))
try:
f = open(filename, 'rb')
except IOError as msg:
err('%s: cannot open: %r\n' % (filename, msg))
return 1
with f:
line = f.readline()
fixed = fixline(line)
if line == fixed:
rep(filename+': no change\n')
return
head, tail = os.path.split(filename)
tempname = os.path.join(head, '@' + tail)
try:
g = open(tempname, 'wb')
except IOError as msg:
err('%s: cannot create: %r\n' % (tempname, msg))
return 1
with g:
rep(filename + ': updating\n')
g.write(fixed)
BUFSIZE = 8*1024
while 1:
buf = f.read(BUFSIZE)
if not buf: break
g.write(buf)
# Finishing touch -- move files
mtime = None
atime = None
# First copy the file's mode to the temp file
try:
statbuf = os.stat(filename)
mtime = statbuf.st_mtime
atime = statbuf.st_atime
os.chmod(tempname, statbuf[ST_MODE] & 0o7777)
except OSError as msg:
err('%s: warning: chmod failed (%r)\n' % (tempname, msg))
# Then make a backup of the original file as filename~
if create_backup:
try:
os.rename(filename, filename + '~')
except OSError as msg:
err('%s: warning: backup failed (%r)\n' % (filename, msg))
else:
try:
os.remove(filename)
except OSError as msg:
err('%s: warning: removing failed (%r)\n' % (filename, msg))
# Now move the temp file to the original file
try:
os.rename(tempname, filename)
except OSError as msg:
err('%s: rename failed (%r)\n' % (filename, msg))
return 1
if preserve_timestamps:
if atime and mtime:
try:
os.utime(filename, (atime, mtime))
except OSError as msg:
err('%s: reset of timestamp failed (%r)\n' % (filename, msg))
return 1
# Return success
return 0
def parse_shebang(shebangline):
shebangline = shebangline.rstrip(b'\n')
start = shebangline.find(b' -')
if start == -1:
return b''
return shebangline[start:]
def populate_flags(shebangline):
old_flags = b''
if keep_flags:
old_flags = parse_shebang(shebangline)
if old_flags:
old_flags = old_flags[2:]
if not (old_flags or add_flags):
return b''
# On Linux, the entire string following the interpreter name
# is passed as a single argument to the interpreter.
# e.g. "#! /usr/bin/python3 -W Error -s" runs "/usr/bin/python3 "-W Error -s"
# so shebang should have single '-' where flags are given and
# flag might need argument for that reasons adding new flags is
# between '-' and original flags
# e.g. #! /usr/bin/python3 -sW Error
return b' -' + add_flags + old_flags
def fixline(line):
if not line.startswith(b'#!'):
return line
if b"python" not in line:
return line
flags = populate_flags(line)
return b'#! ' + new_interpreter + flags + b'\n'
if __name__ == '__main__':
main()

@ -6,20 +6,11 @@
-- python3-foo -> python-foo, python3.X-foo
-- python3.X-foo -> python-foo, python3-foo
-- If only_3_to_3_X is true there is only 1 rule:
-- python3-foo -> python3X-foo
-- python3-foo -> python3.X-foo
-- There is no python-foo -> rule, python-foo packages are version agnostic.
-- Returns a table/array with strings. Empty when no rule matched.
local function python_altnames(name, only_3_to_3_X)
local xy
if only_3_to_3_X then
-- Here we hardcode the xy prefix we want to obsolete to "39", because:
-- 1. Python 3.9 will remain the main Python version in RHEL 9
-- 2. python39 in RHEL 8 is still using the dotless naming (as opposed to
-- python3.9)
xy = "39"
else
xy = rpm.expand('%{__default_python3_pkgversion}')
end
local xy = rpm.expand('%{__default_python3_pkgversion}')
local altnames = {}
local replaced
-- NB: dash needs to be escaped!

@ -1,13 +1,7 @@
Name: python-rpm-macros
Version: 3.9
Release: 52%{?dist}
Summary: The common Python RPM macros
URL: https://src.fedoraproject.org/rpms/python-rpm-macros/
# macros and lua: MIT
# import_all_modules.py: MIT
# compileall2.py: PSFv2
License: MIT and Python
URL: https://src.fedoraproject.org/rpms/python-rpm-macros/
# Macros:
Source101: macros.python
@ -22,6 +16,44 @@ Source201: python.lua
%global compileall2_version 0.7.1
Source301: https://github.com/fedora-python/compileall2/raw/v%{compileall2_version}/compileall2.py
Source302: import_all_modules.py
%global pathfix_version 1.0.0
Source303: https://github.com/fedora-python/pathfix/raw/v%{pathfix_version}/pathfix.py
Source304: clamp_source_mtime.py
# BRP scripts
# This one is from redhat-rpm-config < 190
# A new upstream is forming in https://github.com/rpm-software-management/python-rpm-packaging/blob/main/scripts/brp-python-bytecompile
# But our version is riddled with Fedora-isms
# We might eventually move to upstream source + Fedora patches, but we are not there yet
Source401: brp-python-bytecompile
# This one is from https://github.com/rpm-software-management/python-rpm-packaging/blob/main/scripts/brp-python-hardlink
# But we don't use a link in case it changes in upstream, there are no "versions" there yet
# This was removed from RPM 4.17+ so we maintain it here instead
Source402: brp-python-hardlink
# This one is from redhat-rpm-config < 190
# It has no upstream yet
Source403: brp-fix-pyc-reproducibility
# macros and lua: MIT
# import_all_modules.py: MIT
# compileall2.py, clamp_source_mtime.py: PSF-2.0
# pathfix.py: PSF-2.0
# brp scripts: GPL-2.0-or-later
License: MIT AND PSF-2.0 AND GPL-2.0-or-later
# The package version MUST be always the same as %%{__default_python3_version}.
# To have only one source of truth, we load the macro and use it.
# The macro is defined in python-srpm-macros.
%{lua:
if posix.stat(rpm.expand('%{SOURCE102}')) then
rpm.load(rpm.expand('%{SOURCE102}'))
elseif posix.stat('macros.python-srpm') then
-- something is parsing the spec without _sourcedir macro properly set
rpm.load('macros.python-srpm')
end
}
Version: %{__default_python3_version}
Release: 8.1%{?dist}
BuildArch: noarch
@ -48,7 +80,8 @@ python?-devel packages require it. So install a python-devel package instead.
Summary: RPM macros for building Python source packages
# For directory structure and flags macros
Requires: redhat-rpm-config
# Versions before 190 contained some brp scripts moved into python-srpm-macros
Requires: redhat-rpm-config >= 190
# We bundle our own software here :/
Provides: bundled(python3dist(compileall2)) = %{compileall2_version}
@ -66,15 +99,6 @@ Requires: python-srpm-macros = %{version}-%{release}
# For %%py_setup and import_all_modules.py
Requires: python-rpm-macros = %{version}-%{release}
# We obsolete the old python39-rpm-macros for a smoother upgrade from RHEL8.
# Since python39-rpm-macros are built from the python39 component in RHEL 8,
# they're fully versioned (currently `0:3.9.7`), with the patch version likely
# to increase in the future. RPM sorts this number as higher than `3.9`, which
# is the version we have in RHEL 9. Therefore we're obsoleting with an Epoch 1
# so that all versions from RHEL 8 are obsoleted (but we keep the possibility
# of increasing the epoch in RHEL 8 to stop this).
Obsoletes: python39-rpm-macros < 1:%{version}-%{release}
%description -n python3-rpm-macros
RPM macros for building Python 3 packages.
@ -83,6 +107,10 @@ RPM macros for building Python 3 packages.
%autosetup -c -T
cp -a %{sources} .
# We want to have shebang in the script upstream but not here so
# the package with macros does not depend on Python.
sed -i '1s=^#!/usr/bin/env python3==' pathfix.py
%install
mkdir -p %{buildroot}%{rpmmacrodir}
@ -93,22 +121,41 @@ install -p -m 644 -t %{buildroot}%{_rpmluadir}/fedora/srpm python.lua
mkdir -p %{buildroot}%{_rpmconfigdir}/redhat
install -m 644 compileall2.py %{buildroot}%{_rpmconfigdir}/redhat/
install -m 644 clamp_source_mtime.py %{buildroot}%{_rpmconfigdir}/redhat/
install -m 644 import_all_modules.py %{buildroot}%{_rpmconfigdir}/redhat/
install -m 644 pathfix.py %{buildroot}%{_rpmconfigdir}/redhat/
install -m 755 brp-* %{buildroot}%{_rpmconfigdir}/redhat/
# We define our own BRPs here to use the ones from the %%{buildroot},
# that way, this package can be built when it includes them for the first time.
# It also ensures that:
# - our BRPs can execute
# - if our BRPs affect this package, we don't need to build it twice
%define add_buildroot() %{lua:print((macros[macros[1]]:gsub(macros._rpmconfigdir, macros.buildroot .. macros._rpmconfigdir)))}
%global __brp_python_bytecompile %{add_buildroot __brp_python_bytecompile}
%global __brp_python_hardlink %{add_buildroot __brp_python_hardlink}
%global __brp_fix_pyc_reproducibility %{add_buildroot __brp_fix_pyc_reproducibility}
%check
# no macros in comments
! grep -E '^#[^%%]*%%[^%%]' %{buildroot}%{rpmmacrodir}/macros.*
grep -E '^#[^%%]*%%[^%%]' %{buildroot}%{rpmmacrodir}/macros.* && exit 1 || true
%files
%{rpmmacrodir}/macros.python
%{rpmmacrodir}/macros.pybytecompile
%{_rpmconfigdir}/redhat/import_all_modules.py
%{_rpmconfigdir}/redhat/pathfix.py
%files -n python-srpm-macros
%{rpmmacrodir}/macros.python-srpm
%{_rpmconfigdir}/redhat/compileall2.py
%{_rpmconfigdir}/redhat/clamp_source_mtime.py
%{_rpmconfigdir}/redhat/brp-python-bytecompile
%{_rpmconfigdir}/redhat/brp-python-hardlink
%{_rpmconfigdir}/redhat/brp-fix-pyc-reproducibility
%{_rpmluadir}/fedora/srpm/python.lua
%files -n python3-rpm-macros
@ -116,77 +163,157 @@ install -m 644 import_all_modules.py %{buildroot}%{_rpmconfigdir}/redhat/
%changelog
* Tue Feb 08 2022 Tomas Orsava <torsava@redhat.com> - 3.9-52
- %%py_provides: Do not generate Obsoletes for names containing parentheses
- Related: rhbz#1990421
* Tue Jun 25 2024 Cristian Le <fedora@lecris.me> - 3.12-8.1
- %%python_extras_subpkg: Add option -a to include BuildArch: noarch
* Mon Jun 24 2024 Troy Dawson <tdawson@redhat.com> - 3.12-8
- Bump release for June 2024 mass rebuild
* Thu Jan 25 2024 Miro Hrončok <mhroncok@redhat.com> - 3.12-7
- %%py3_test_envvars: Only set $PYTEST_XDIST_AUTO_NUM_WORKERS if not already set
* Mon Jan 22 2024 Fedora Release Engineering <releng@fedoraproject.org> - 3.12-6
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* Mon Oct 09 2023 Maxwell G <maxwell@gtmx.me> - 3.12-5
- Fix python macro memoizing to account for changing %%__python3
* Tue Sep 05 2023 Maxwell G <maxwell@gtmx.me> - 3.12-4
- Remove %%py3_build_egg and %%py3_install_egg macros.
* Wed Aug 09 2023 Karolina Surma <ksurma@redhat.com> - 3.12-3
- Declare the license as an SPDX expression
* Fri Jul 21 2023 Fedora Release Engineering <releng@fedoraproject.org> - 3.12-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
* Tue Jun 13 2023 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12-1
- Update main Python to Python 3.12
- https://fedoraproject.org/wiki/Changes/Python3.12
* Thu Mar 16 2023 Miro Hrončok <mhroncok@redhat.com> - 3.11-10
- Don't assume %%_smp_mflags only ever contains -jX, use -j%%_smp_build_ncpus directly
- Fixes: rhbz#2179149
* Tue Feb 08 2022 Tomas Orsava <torsava@redhat.com> - 3.9-51
- Add Obsoletes tags with the python39- prefix for smoother upgrade from RHEL8
- Related: rhbz#1990421
* Fri Jan 20 2023 Miro Hrončok <mhroncok@redhat.com> - 3.11-9
- Memoize values of macros that execute python to get their value
- Fixes: rhbz#2155505
* Tue Feb 01 2022 Miro Hrončok <mhroncok@redhat.com> - 3.9-50
* Fri Jan 20 2023 Fedora Release Engineering <releng@fedoraproject.org> - 3.11-8
- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild
* Mon Dec 19 2022 Miro Hrončok <mhroncok@redhat.com> - 3.11-7
- Bytecompilation: Unset $SOURCE_DATE_EPOCH when %%clamp_mtime_to_source_date_epoch is not set
- Bytecompilation: Pass --invalidation-mode=timestamp to compileall (on Python 3.7+)
- Bytecompilation: Clamp source mtime: https://fedoraproject.org/wiki/Changes/ReproducibleBuildsClampMtimes
- Bytecompilation: Compile Python files in parallel, according to %%_smp_mflags
* Sun Nov 13 2022 Miro Hrončok <mhroncok@redhat.com> - 3.11-6
- Set PYTEST_XDIST_AUTO_NUM_WORKERS=%%{_smp_build_ncpus} from %%pytest
- pytest-xdist 3+ respects this value when -n auto is used
- Expose the environment variables used by %%pytest via %%{py3_test_envvars}
* Tue Oct 25 2022 Lumír Balhar <lbalhar@redhat.com> - 3.11-5
- Include pathfix.py in this package
* Fri Jul 22 2022 Fedora Release Engineering <releng@fedoraproject.org> - 3.10-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild
* Tue Jul 19 2022 Miro Hrončok <mhroncok@redhat.com> - 3.11-3
- Add "P" to %%py3_shbang_opts, %%py3_shbang_opts_nodash, %%py3_shebang_flags
and to %%py_shbang_opts, %%py_shbang_opts_nodash, %%py_shebang_flags
- https://fedoraproject.org/wiki/Changes/PythonSafePath
* Mon Jun 20 2022 Miro Hrončok <mhroncok@redhat.com> - 3.11-2
- Define %%python3_cache_tag / %%python_cache_tag, e.g. cpython-311
* Mon Jun 13 2022 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.11-1
- Update main Python to Python 3.11
- https://fedoraproject.org/wiki/Changes/Python3.11
* Thu May 26 2022 Owen Taylor <otaylor@redhat.com> - 3.10-18
- Support installing to %%{_prefix} other than /usr
* Tue Feb 08 2022 Tomas Orsava <torsava@redhat.com> - 3.10-17
- %%py_provides: Do not generate Obsoletes for names containing parentheses
* Mon Jan 31 2022 Miro Hrončok <mhroncok@redhat.com> - 3.10-16
- Explicitly opt-out from Python name-based provides and obsoletes generators
* Wed Jan 19 2022 Tomas Orsava <torsava@redhat.com> - 3.9-49
* Tue Dec 21 2021 Tomas Orsava <torsava@redhat.com> - 3.10-15
- Add lua helper functions to make it possible to automatically generate
Obsoletes tags
- Modify the %%py_provides macro to also generate Obsoletes tags on CentOS/RHEL
- Resolves: rhbz#1990421
* Tue Dec 21 2021 Karolina Surma <ksurma@redhat.com> - 3.9-48
- Fix CI test configuration, so that pytest can import the package code
* Wed Dec 08 2021 Miro Hrončok <mhroncok@redhat.com> - 3.9-47
* Wed Dec 08 2021 Miro Hrončok <mhroncok@redhat.com> - 3.10-14
- Set %%__python3 value according to %%python3_pkgversion
I.e. when %%python3_pkgversion is 3.12, %%__python3 is /usr/bin/python3.12
* Mon Nov 01 2021 Karolina Surma <ksurma@redhat.com> - 3.9-46
* Mon Nov 01 2021 Karolina Surma <ksurma@redhat.com> - 3.10-13
- Fix multiline arguments processing for %%py_check_import
Resolves: rhbz#2018809
- Fix %%py_shebang_flags handling within %%py_check_import
Resolves: rhbz#2018615
- Process .pth files in buildroot's sitedirs in %%py_check_import
Resolves: rhbz#2018551
- Move import_all_modules.py from python-srpm-macros to python-rpm-macros
* Mon Oct 25 2021 Karolina Surma <ksurma@redhat.com> - 3.9-45
* Mon Oct 25 2021 Karolina Surma <ksurma@redhat.com> - 3.10-12
- Introduce -f (read from file) option to %%py{3}_check_import
- Introduce -t (filter top-level modules) option to %%py{3}_check_import
- Introduce -e (exclude module globs) option to %%py{3}_check_import
* Thu Sep 09 2021 Miro Hrončok <mhroncok@redhat.com> - 3.9-44
* Wed Oct 20 2021 Tomas Orsava <torsava@redhat.com> - 3.10-11
- Define a new macros %%python_wheel_dir and %%python_wheel_pkg_prefix
* Tue Oct 12 2021 Lumír Balhar <lbalhar@redhat.com> - 3.10-10
- Non-existing path in py_reproducible_pyc_path causes build to fail
Resolves: rhbz#2011056
* Thu Sep 09 2021 Miro Hrončok <mhroncok@redhat.com> - 3.10-9
- Set $RPM_BUILD_ROOT in %%{python3_...} macros
to allow selecting alternate sysconfig install scheme based on that variable
* Wed Aug 11 2021 Tomas Orsava <torsava@redhat.com> - 3.9-43
- Define a new macros %%python_wheel_dir and %%python_wheel_pkg_prefix
- Related: rhbz#1982668
* Thu Sep 09 2021 Petr Viktorin <pviktori@redhat.com> - 3.10-8
- Use --hardlink-dupes in %%py_byte_compile and brp-python-bytecompile
(for Python 3)
- Resolves: rhbz#1977895
* Fri Jul 23 2021 Fedora Release Engineering <releng@fedoraproject.org> - 3.9-7
- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild
* Tue Aug 10 2021 Mohan Boddu <mboddu@redhat.com> - 3.9-42
- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags
Related: rhbz#1991688
* Wed Jul 07 2021 Miro Hrončok <mhroncok@redhat.com> - 3.10-6
- Move Python related BuildRoot Policy scripts from redhat-rpm-config to python-srpm-macros
* Wed Jul 07 2021 Miro Hrončok <mhroncok@redhat.com> - 3.9-41
* Wed Jul 07 2021 Miro Hrončok <mhroncok@redhat.com> - 3.10-5
- Introduce %%py3_check_import
* Mon Jun 28 2021 Miro Hrončok <mhroncok@redhat.com> - 3.9-40
* Wed Jun 30 2021 Miro Hrončok <mhroncok@redhat.com> - 3.10-4
- Include brp-python-hardlink in python-srpm-macros since it is no longer in RPM 4.17+
* Mon Jun 28 2021 Miro Hrončok <mhroncok@redhat.com> - 3.10-3
- %%pytest: Set $PYTEST_ADDOPTS when %%{__pytest_addopts} is defined
- Related: rhzb#1935212
* Tue Jun 15 2021 Miro Hrončok <mhroncok@redhat.com> - 3.9-39
* Tue Jun 15 2021 Miro Hrončok <mhroncok@redhat.com> - 3.10-2
- Fix %%python_provide when fed python3.10-foo to obsolete python-foo instead of python--foo
* Tue Jun 01 2021 Miro Hrončok <mhroncok@redhat.com> - 3.10-1
- Update main Python to Python 3.10
- https://fedoraproject.org/wiki/Changes/Python3.10
* Tue Apr 27 2021 Miro Hrončok <mhroncok@redhat.com> - 3.9-38
- Escape %% symbols in macro files comments
- Fixes: rhbz#1953910
* Fri Apr 16 2021 Karolina Surma <ksurma@redhat.com> - 3.9-37
* Wed Apr 07 2021 Karolina Surma <ksurma@redhat.com> - 3.9-37
- Use sysconfig.get_path() to get %%python3_sitelib and %%python3_sitearch
- Fixes: rhbz#1947468
- Fixes: rhbz#1946972
* Fri Apr 16 2021 Miro Hrončok <mhroncok@redhat.com> - 3.9-36.1
* Mon Mar 29 2021 Miro Hrončok <mhroncok@redhat.com> - 3.9-36
- Allow commas as argument separator for extras names in %%python_extras_subpkg
- Fixes: rhbz#1936486
* Fri Apr 16 2021 Mohan Boddu <mboddu@redhat.com> - 3.9-36
- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937
* Sat Feb 20 2021 Miro Hrončok <mhroncok@redhat.com> - 3.9-35
- Fix %%python_extras_subpkg with underscores in extras names

Loading…
Cancel
Save