When calling one getopt-using macro from another,
the macro definitions from the inner macro leaked to the outer one.
rpm.define()/rpm.undefine() operate globally, not scoped to parametric
macro invocations. When a macro using getopt() is called nested inside
another getopt-using macro with overlapping option letters, the inner
cleanup_macros() wipes the outer macro's __pyproject_opt_* values.
Note: RPM's native %define/%undefine have stack-like behavior (pushing
and popping definitions), and we can invoke %define from Lua via
rpm.expand(). However, there is no way to push "not defined" onto
this stack and later pop it. Since getopt treats "not defined" and
"defined to %{nil}" differently (the former means the option was not
passed, the latter means a flag was passed without a value), the
native stacking cannot represent the full state space. We implement
our own save/restore stack on the Lua side instead.
Add a Lua-side save/restore stack: getopt() saves current macro state
before cleanup, and a new restore() function pops and reinstates it.
All getopt-using macros call %{__pyproject_getopt_restore} at the end
of their body.
Assisted-By: Claude Opus 4.6
Assisted-By: Codex
(cherry picked from Fedora commit 83ea9a1a01)
Defines a ready-to-forward form alongside %__pyproject_opt_{short}:
"-X" for flags, "-X value" for value options. This replaces the verbose
%{?__pyproject_opt_X:-X %{__pyproject_opt_X}} pattern with %{?__pyproject_optflag_X}.
Assisted-By: Claude Opus 4.6
(cherry picked from Fedora commit 9108ee5b74)
When macro arguments span across multiple lines with backslash-escaped newlines, e.g.:
%{pyproject_buildrequires \
-x pathops \
-x autohint \
-x json \
-x repacker}
rpm.define() for positional args would fail with:
Macro %__pyproject_positional_args has empty body
error: lua script failed: .../pyproject_getopt.lua:252: error defining macro
Because the "-x pathops" would be consumed by value parsing
and all the positional arguments would be just backslash-escaped newlines.
Defining the %__pyproject_positional_args macro to whitespace is not possible,
unless properly quoted.
Filter out line-continuation artifacts (tokens containing only whitespace,
backslashes, and newlines) before parsing, so they cannot be misinterpreted
as option values or positional args. Extract a shared quote_value() function
for safe embedding of values in rpm.define() calls.
Additionally, RPM may embed newlines within tokens when macros use
%{expand:} with literal newlines. Such tokens are split on newlines
before parsing.
The regression impacted parsing of 14 Fedora Rawhide spec files:
- dcm2niix
- fontmake
- fonttools
- libarrow
- python-django5
- python-django6
- python-pydantic-extra-types
- python-pydantic-settings
- python-pylero
- python-pynetdicom
- python-tablib
- python-trimesh
- python-urllib3
- scapy
And all are now fixed.
No other Fedora Rawhide spec files fail to parse due to the long option support
after this fix.
Assisted-By: Claude Opus 4.6
(cherry picked from Fedora commit 2acda15168)
All public parametric macros now accept long options in addition
to short options. For example, %pyproject_buildrequires --no-runtime
is equivalent to %pyproject_buildrequires -R.
This is implemented via a Lua option parser (pyproject_getopt.lua)
installed to %{_rpmluadir}/fedora/rpm/. All macros use (-) to opt out
of RPM native getopt and call the Lua parser for validation, mutual
exclusion checks, and value extraction.
Other changes:
- Toxenv construction inlined in Lua, replacing pyproject_construct_toxenv.py
- Added --config-settings and --directory long forms to Python argparse
- Renamed --read-pyproject-dependencies to --pyproject-dependencies
(this was not part of API and now it is, so I picked a shorter name)
- Added test_getopt_consistency.py to assert option mappings match
across macros.pyproject, Python scripts, and README.md
- Converted ~half of test specs to use long options
- Documented all short/long mappings in README.md
- All Python scripts expose their argparser() functions fer easier consistency asserts
Co-Authored-By: Maxwell G <maxwell@gtmx.me>
Assisted-By: Claude Opus 4.6
(cherry picked from Fedora commit 6d3ad45c08)