Blame SOURCES/macros.openstack-singlespec

838cdc
%prepare_alternative(t:) \
838cdc
%define alternative_target %{-t:%{-t*}}%{!-t:%{_bindir}/%1} \
838cdc
rm -f %{buildroot}%{alternative_target} \
838cdc
alternative_target="%{alternative_target}" \
838cdc
if [[ "$alternative_target" == %{_mandir}* ]]; then \
838cdc
    rm -f %{buildroot}${alternative_target%%%%%{ext_man}} \
838cdc
    rm -f %{buildroot}%{alternative_target}%{ext_man} \
838cdc
fi \
838cdc
mkdir -p %{buildroot}%{_sysconfdir}/alternatives \
838cdc
touch %{buildroot}%{_sysconfdir}/alternatives/%1 \
838cdc
ln -sf %{_sysconfdir}/alternatives/%1 %{buildroot}%{alternative_target} \
838cdc
%{nil}
838cdc
838cdc
%install_alternative(s:t:p:n:) \
838cdc
%define alternative_name %{-n:%{-n*}}%{!-n:%1} \
838cdc
%define alternative_source %{-s:%{-s*}}%{!-s:%{_bindir}/%{alternative_name}} \
838cdc
%define alternative_target %{-t:%{-t*}}%{!-t:%2} \
838cdc
%define alternative_priority %{-p:%{-p*}}%{!-p:%3} \
838cdc
update-alternatives --install \\\
838cdc
    %{alternative_source} \\\
838cdc
    %{alternative_name} \\\
838cdc
    %{alternative_target} \\\
838cdc
    %{alternative_priority}
838cdc
838cdc
%uninstall_alternative(n:t:) \
838cdc
%define alternative_name %{-n:%{-n*}}%{!-n:%1} \
838cdc
%define alternative_target %{-t:%{-t*}}%{!-t:%2} \
838cdc
if [ ! -e "%{alternative_target}" ]; then \
838cdc
    update-alternatives --quiet --remove "%{alternative_name}" "%{alternative_target}" \
838cdc
fi \
838cdc
%{nil}
838cdc
838cdc
%alternative_for() \
838cdc
%1 \
838cdc
%ghost %{_sysconfdir}/alternatives/%{basename:%1}
838cdc
838cdc
%system_python python2
838cdc
%python_for_executables python3
838cdc
838cdc
##### common functionality #####
838cdc
838cdc
%_python_sysconfig_path() %(%1 -c "import sysconfig as s; print(s.get_paths().get('%2'))")
838cdc
%_python_sysconfig_var()  %(%1 -c "import sysconfig as s; print(s.get_config_var('%2'))")
838cdc
838cdc
%_rec_macro_helper %{lua:
838cdc
    rpm.define("_rec_macro_helper %{nil}")
838cdc
    function expand_macro(name, args)
838cdc
        local interp = rpm.expand("%python_flavor")
838cdc
        local args   = args and rpm.expand(args) or ""
838cdc
        print(rpm.expand("%{" .. interp .. "_" .. name .. " " .. args .."}"))
838cdc
    end
838cdc
    function call_sysconfig(which, interp)
838cdc
        local arg = rpm.expand("%1")
838cdc
        print(rpm.expand("%{_python_sysconfig_" .. which .. " " .. interp .. " " .. arg .. "}"))
838cdc
    end
838cdc
}
838cdc
838cdc
##### fedora compatibility #####
838cdc
838cdc
%py_setup setup.py
838cdc
%py_shbang_opts -s
838cdc
838cdc
##### binary suffixes for flavors #####
838cdc
838cdc
%python2_bin_suffix %python2_version
838cdc
%python3_bin_suffix %python3_version
838cdc
%pypy3_bin_suffix   pp%{pypy3_version}
838cdc
838cdc
##### preferred configuration #####
838cdc
838cdc
%python_sitelib          %{_python_sysconfig_path %python_flavor purelib}
838cdc
%python_sitearch         %{_python_sysconfig_path %python_flavor platlib}
838cdc
%python_version          %{_python_sysconfig_var  %python_flavor py_version_short}
838cdc
%python_version_nodots   %{_python_sysconfig_var  %python_flavor py_version_nodot}
838cdc
838cdc
%python_prefix                  %{_rec_macro_helper}%{lua:expand_macro("prefix")}
838cdc
%python_bin_suffix              %{_rec_macro_helper}%{lua:expand_macro("bin_suffix")}
838cdc
838cdc
%python_sysconfig_path()        %{_rec_macro_helper}%{lua:call_sysconfig("path", "%python_flavor")}
838cdc
%python_sysconfig_var()         %{_rec_macro_helper}%{lua:call_sysconfig("var", "%python_flavor")}
838cdc
838cdc
%python_alternative()           %{_rec_macro_helper}%{lua:expand_macro("alternative", "%**")}
838cdc
%python_install_alternative()   %{_rec_macro_helper}%{lua:expand_macro("install_alternative", "%**")}
838cdc
%python_uninstall_alternative() %{_rec_macro_helper}%{lua:expand_macro("uninstall_alternative", "%**")}
838cdc
838cdc
%py_ver  %python_version
838cdc
838cdc
##### macro definitions for flavor "pypy3" #####
838cdc
838cdc
%__pypy3               /usr/bin/pypy3
838cdc
838cdc
%pypy3_shbang_opts     %py_shbang_opts
838cdc
838cdc
%pypy3_prefix          pypy3
838cdc
%pypy3_sitelib         %{_python_sysconfig_path pypy3 purelib}
838cdc
%pypy3_sitearch        %{_python_sysconfig_path pypy3 platlib}
838cdc
%pypy3_version         %{_python_sysconfig_var pypy3 py_version_short}
838cdc
%pypy3_version_nodots  %{_python_sysconfig_var pypy3 py_version_nodot}
838cdc
838cdc
%pypy3_sysconfig_path() %{_rec_macro_helper}%{lua:call_sysconfig("path", "pypy3")}
838cdc
%pypy3_sysconfig_var()  %{_rec_macro_helper}%{lua:call_sysconfig("var", "pypy3")}
838cdc
838cdc
%ifpypy3      %if "%{python_flavor}" == "pypy3"
838cdc
838cdc
%pypy3_only() %if "%{python_flavor}" == "pypy3" \
838cdc
%** \
838cdc
%endif
838cdc
838cdc
%pypy3_build \
838cdc
%{_python_use_flavor pypy3} \
838cdc
%__pypy3 %{py_setup} %{?py_setup_args} build \\\
838cdc
    --executable="%__pypy3 %pypy3_shbang_opts"
838cdc
838cdc
%pypy3_install \
838cdc
%{_python_use_flavor pypy3} \
838cdc
%__pypy3 %{py_setup} %{?py_setup_args} install \\\
838cdc
    -O1 --skip-build --force --root %{buildroot} --prefix %{_prefix}
838cdc
838cdc
%pypy3_alternative() %{_python_macro_init} \
838cdc
%{lua:local link, name, path = python_alternative_names(rpm.expand("%1"), rpm.expand("%pypy3_bin_suffix")) \
838cdc
print(rpm.expand("%ghost %{_sysconfdir}/alternatives/" .. name .. "\\\n")) \
838cdc
print(link .. "\\\n") \
838cdc
print(path .. "\\\n") }
838cdc
838cdc
%pypy3_install_alternative() %{_python_macro_init} \
838cdc
%{lua:python_install_alternative("pypy3")}
838cdc
838cdc
%pypy3_uninstall_alternative() \
838cdc
%{uninstall_alternative -n %1 -t %{_bindir}/%1-%pypy3_bin_suffix}
838cdc
838cdc
##### macro definitions for flavor "python2" #####
838cdc
838cdc
%__python2               /usr/bin/python2
838cdc
838cdc
%python2_shbang_opts     %py_shbang_opts
838cdc
838cdc
%python2_prefix          python2
838cdc
%python2_sitelib         %{_python_sysconfig_path python2 purelib}
838cdc
%python2_sitearch        %{_python_sysconfig_path python2 platlib}
838cdc
%python2_version         %{_python_sysconfig_var python2 py_version_short}
838cdc
%python2_version_nodots  %{_python_sysconfig_var python2 py_version_nodot}
838cdc
838cdc
%python2_sysconfig_path() %{_rec_macro_helper}%{lua:call_sysconfig("path", "python2")}
838cdc
%python2_sysconfig_var()  %{_rec_macro_helper}%{lua:call_sysconfig("var", "python2")}
838cdc
838cdc
%ifpython2      %if "%{python_flavor}" == "python2"
838cdc
838cdc
%python2_only() %if "%{python_flavor}" == "python2" \
838cdc
%** \
838cdc
%endif
838cdc
838cdc
%python2_build \
838cdc
%{_python_use_flavor python2} \
838cdc
%__python2 %{py_setup} %{?py_setup_args} build \\\
838cdc
    --executable="%__python2 %python2_shbang_opts"
838cdc
838cdc
%python2_install \
838cdc
%{_python_use_flavor python2} \
838cdc
%__python2 %{py_setup} %{?py_setup_args} install \\\
838cdc
    -O1 --skip-build --force --root %{buildroot} --prefix %{_prefix}
838cdc
838cdc
%python2_alternative() %{_python_macro_init} \
838cdc
%{lua:local link, name, path = python_alternative_names(rpm.expand("%1"), rpm.expand("%python2_bin_suffix")) \
838cdc
print(rpm.expand("%ghost %{_sysconfdir}/alternatives/" .. name .. "\\\n")) \
838cdc
print(link .. "\\\n") \
838cdc
print(path .. "\\\n") }
838cdc
838cdc
%python2_install_alternative() %{_python_macro_init} \
838cdc
%{lua:python_install_alternative("python2")}
838cdc
838cdc
%python2_uninstall_alternative() \
838cdc
%{uninstall_alternative -n %1 -t %{_bindir}/%1-%python2_bin_suffix}
838cdc
838cdc
##### macro definitions for flavor "python3" #####
838cdc
838cdc
%__python3               /usr/bin/python3
838cdc
838cdc
%python3_shbang_opts     %py_shbang_opts
838cdc
838cdc
%python3_prefix          python3
838cdc
%python3_sitelib         %{_python_sysconfig_path python3 purelib}
838cdc
%python3_sitearch        %{_python_sysconfig_path python3 platlib}
838cdc
%python3_version         %{_python_sysconfig_var python3 py_version_short}
838cdc
%python3_version_nodots  %{_python_sysconfig_var python3 py_version_nodot}
838cdc
838cdc
%python3_sysconfig_path() %{_rec_macro_helper}%{lua:call_sysconfig("path", "python3")}
838cdc
%python3_sysconfig_var()  %{_rec_macro_helper}%{lua:call_sysconfig("var", "python3")}
838cdc
838cdc
%ifpython3      %if "%{python_flavor}" == "python3"
838cdc
838cdc
%python3_only() %if "%{python_flavor}" == "python3" \
838cdc
%** \
838cdc
%endif
838cdc
838cdc
%python3_build \
838cdc
%{_python_use_flavor python3} \
838cdc
%__python3 %{py_setup} %{?py_setup_args} build \\\
838cdc
    --executable="%__python3 %python3_shbang_opts"
838cdc
838cdc
%python3_install \
838cdc
%{_python_use_flavor python3} \
838cdc
%__python3 %{py_setup} %{?py_setup_args} install \\\
838cdc
    -O1 --skip-build --force --root %{buildroot} --prefix %{_prefix}
838cdc
838cdc
%python3_alternative() %{_python_macro_init} \
838cdc
%{lua:local link, name, path = python_alternative_names(rpm.expand("%1"), rpm.expand("%python3_bin_suffix")) \
838cdc
print(rpm.expand("%ghost %{_sysconfdir}/alternatives/" .. name .. "\\\n")) \
838cdc
print(link .. "\\\n") \
838cdc
print(path .. "\\\n") }
838cdc
838cdc
%python3_install_alternative() %{_python_macro_init} \
838cdc
%{lua:python_install_alternative("python3")}
838cdc
838cdc
%python3_uninstall_alternative() \
838cdc
%{uninstall_alternative -n %1 -t %{_bindir}/%1-%python3_bin_suffix}
838cdc
838cdc
##### compatibility short-name macros #####
838cdc
838cdc
# fedora expects %py_shbang_opts and %pyX_shbang_opts, possibly to be redefinable?
838cdc
# we expect everything to start with binary name, so we actually use %pythonX_shbang_opts
838cdc
# so if a specfile redefines the %pyX_, the correct one will be used
838cdc
%py2_shbang_opts %py_shbang_opts
838cdc
%python2_shbang_opts %py2_shbang_opts
838cdc
%py3_shbang_opts %py_shbang_opts
838cdc
%python3_shbang_opts %py3_shbang_opts
838cdc
838cdc
%py2_build   %python2_build
838cdc
%py2_install %python2_install
838cdc
%py3_build   %python3_build
838cdc
%py3_install %python3_install
838cdc
838cdc
%py2_ver     %python2_version
838cdc
%py3_ver     %python3_version
838cdc
838cdc
%python2_prefix   %{?python2_package_prefix}%{?!python2_package_prefix:python}
838cdc
838cdc
%pythons  %{?!skip_python2:python2} %{?!skip_python3:python3}
838cdc
838cdc
# This method for generating python_modules gets too deep to expand at about 5 python flavors.
838cdc
# It is replaced by a Lua macro in macros.lua
838cdc
# However, OBS has a much higher expansion depth, so this works fine.
838cdc
%python_module_iter(a:) %{-a*}-%{args} %{expand:%%{?!python_module_iter_%1:%%{python_module_iter -a %*}}}
838cdc
%python_module_iter_STOP stop
838cdc
%python_module() %{expand:%%define args %{**}} %{expand:%%{python_module_iter -a %{pythons} STOP}}
838cdc
838cdc
%add_python() %{expand:%%define pythons %pythons %1}
838cdc
838cdc
%python_flavor %{_python_macro_init}%{lua: print(flavor)}
838cdc
838cdc
%if_python_kind()     %if "%{python_flavor}" == "%1"
838cdc
%if_not_python_kind() %if "%{python_flavor}" != "%1"
838cdc
838cdc
%ifpycache %if "%{python_flavor}" != "python2"
838cdc
838cdc
%pycache_only() %ifpycache \
838cdc
%** \
838cdc
%endif
838cdc
838cdc
%_python_use_flavor() \
838cdc
python_flavor=`[ -f _current_flavor ] && cat _current_flavor || true` \
838cdc
if [ -z "$python_flavor" ]; then python_flavor="tmp"; fi \
838cdc
if [ "$python_flavor" != "%1" ]; then \
838cdc
    if [ -d build ]; then mv build _build.$python_flavor; fi \
838cdc
    if [ -d _build.%1 ]; then mv _build.%1 build; fi \
838cdc
fi \
838cdc
echo %1 > _current_flavor \
838cdc
%{nil}
838cdc
838cdc
%_python_stash_flavor() \
838cdc
if [ -d build ]; then mv build _build.%1; fi \
838cdc
if [ -d _build.tmp ]; then mv _build.tmp build; fi \
838cdc
%{nil}
838cdc
838cdc
838cdc
### LUA-MACROS ###
838cdc
%_python_definitions %{lua:
838cdc
-- declare common functions
838cdc
function string.startswith(str, prefix)
838cdc
    return str:sub(1, prefix:len()) == prefix
838cdc
end
838cdc
function string.endswith(str, suffix)
838cdc
    return str:sub(-suffix:len()) == suffix
838cdc
end
838cdc
function string.basename(str)
838cdc
    while true do
838cdc
        local idx = str:find("/")
838cdc
        if not idx then return str end
838cdc
        str = str:sub(idx + 1)
838cdc
    end
838cdc
end
838cdc
function lookup_table(tbl)
838cdc
    local result = {}
838cdc
    for _,v in ipairs(tbl) do result[v] = true end
838cdc
    return result
838cdc
end
838cdc
-- macro replacements
838cdc
SHORT_FLAVORS = {
838cdc
    -- ??
838cdc
    python = "py",
838cdc
    -- ??
838cdc
    python2 = "py2",
838cdc
    python3 = "py3",
838cdc
    pypy = "pypy",
838cdc
}
838cdc
function replace_macros(str, targetflavor)
838cdc
    local LONG_MACROS = { "sitelib", "sitearch",
838cdc
        "alternative", "install_alternative", "uninstall_alternative",
838cdc
        "version", "version_nodots", "bin_suffix", "prefix"}
838cdc
    local SHORT_MACROS = { "ver" }
838cdc
    for _, srcflavor in ipairs({flavor, "python"}) do
838cdc
        str = str:gsub("%%__" .. srcflavor, "%%__" .. targetflavor)
838cdc
        for _, macro in ipairs(LONG_MACROS) do
838cdc
            local from = string.format("%s_%s", srcflavor, macro)
838cdc
            local to = string.format("%s_%s", targetflavor, macro)
838cdc
            str = str:gsub("%%" .. from, "%%" .. to)
838cdc
            str = str:gsub("%%{" .. from .. "}", "%%{" .. to .. "}")
838cdc
            str = str:gsub("%%{" .. from .. "(%s+.-)}", "%%{" .. to .. "%1}")
838cdc
        end
838cdc
        for _, macro in ipairs(SHORT_MACROS) do
838cdc
            local from = string.format("%s_%s", SHORT_FLAVORS[srcflavor], macro)
838cdc
            local to = string.format("%s_%s", SHORT_FLAVORS[targetflavor], macro)
838cdc
            str = str:gsub("%%" .. from, "%%" .. to)
838cdc
            str = str:gsub("%%{" .. from .. "}", "%%{" .. to .. "}")
838cdc
        end
838cdc
    end
838cdc
    return str
838cdc
end
838cdc
function package_name(flavor, modname, subpkg, append)
838cdc
    if flavor == "python2" and old_python2 then
838cdc
        flavor = "python"
838cdc
    end
838cdc
    local name = flavor .. "-" .. modname
838cdc
    if subpkg and subpkg ~= "" then
838cdc
        name = name .. "-" .. subpkg
838cdc
    end
838cdc
    if append and append ~= "" then
838cdc
        name = name .. " " .. append
838cdc
    end
838cdc
    return name
838cdc
end
838cdc
function pkgname_from_param(param)
838cdc
    if param == modname then
838cdc
        return ""
838cdc
    elseif param:startswith(modname .. "-") then
838cdc
        return param:sub(modname:len() + 2)
838cdc
    else
838cdc
        return "-n " .. param
838cdc
    end
838cdc
end
838cdc
-- alternative-related
838cdc
local bindir = rpm.expand("%{_bindir}")
838cdc
local mandir = rpm.expand("%{_mandir}")
838cdc
local ext_man, ext_man_expr
838cdc
ext_man = rpm.expand("%{ext_man}")
838cdc
if ext_man == "" then
838cdc
    ext_man_expr = "%.%d$"
838cdc
else
838cdc
    -- ASSUMPTION: ext_man:startswith(".")
838cdc
    ext_man_expr = "%.%d%" .. ext_man .. "$"
838cdc
end
838cdc
function python_alternative_names(arg, binsuffix, keep_path_unmangled)
838cdc
    local link, name, path
838cdc
    name = arg:basename()
838cdc
    local man_ending = arg:match(ext_man_expr) or arg:match("%.%d$")
838cdc
    if arg:startswith("/") then
838cdc
        link = arg
838cdc
    elseif man_ending then
838cdc
        link = mandir .. "/man" .. man_ending:sub(2,2) .. "/" .. arg
838cdc
    else
838cdc
        link = bindir .. "/" .. arg
838cdc
    end
838cdc
    if man_ending then
838cdc
        path = link:sub(1, -man_ending:len()-1) .. "-" .. binsuffix .. man_ending
838cdc
    else
838cdc
        path = link .. "-" .. binsuffix
838cdc
    end
838cdc
    -- now is the time to append ext_man if appropriate
838cdc
    -- "link" and "name" get ext_man always
838cdc
    if ext_man ~= "" and man_ending and not arg:endswith(ext_man) then
838cdc
        link = link .. ext_man
838cdc
        name = name .. ext_man
838cdc
        if not keep_path_unmangled then path = path .. ext_man end
838cdc
    end
838cdc
    return link, name, path
838cdc
end
838cdc
function python_install_alternative(flavor)
838cdc
    local prio      = rpm.expand("%" .. flavor .. "_version_nodots")
838cdc
    local binsuffix = rpm.expand("%" .. flavor .. "_bin_suffix")
838cdc
    local params = {}
838cdc
    for p in string.gmatch(rpm.expand("%*"), "%S+") do
838cdc
        table.insert(params, p)
838cdc
    end
838cdc
    if #params == 0 then
838cdc
        print("error")
838cdc
        return
838cdc
    end
838cdc
    local link, name, path = python_alternative_names(params[1], binsuffix)
838cdc
    print(string.format("update-alternatives --install %s %s %s %s", link, name, path, prio))
838cdc
    table.remove(params, 1)
838cdc
    for _, v in ipairs(params) do
838cdc
        print(string.format(" \\\\\\n   --slave %s %s %s", python_alternative_names(v, binsuffix)))
838cdc
    end
838cdc
end
838cdc
}
838cdc
%_python_scan_spec() %{lua: \
838cdc
    local last_python = rpm.expand("%python_for_executables")\
838cdc
    local insert_last_python = false\
838cdc
\
838cdc
    pythons = {}\
838cdc
    -- make sure that last_python is the last item in the list\
838cdc
    for str in string.gmatch(rpm.expand("%pythons"), "%S+") do\
838cdc
        if str == last_python then\
838cdc
            insert_last_python = true\
838cdc
        else\
838cdc
            table.insert(pythons, str)\
838cdc
        end\
838cdc
    end\
838cdc
    -- ...but check that it is actually in the buildset\
838cdc
    if insert_last_python then table.insert(pythons, last_python) end\
838cdc
\
838cdc
    modname = rpm.expand("%name")\
838cdc
    local spec_name_prefix = "python"\
838cdc
    -- modname from name\
838cdc
    local name = modname\
838cdc
    for _,py in ipairs(pythons) do\
838cdc
        if name:find(py .. "%-") == 1 then\
838cdc
            spec_name_prefix = py\
838cdc
            modname = name:sub(py:len() + 2)\
838cdc
            break\
838cdc
        end\
838cdc
    end\
838cdc
    -- try to match "python-"\
838cdc
    if name == modname and name:find("python%-") == 1 then\
838cdc
        spec_name_prefix = "python"\
838cdc
        modname = name:sub(8)\
838cdc
    end\
838cdc
    -- if not found, modname == %name, spec_name_prefix == "python"\
838cdc
\
838cdc
    system_python = rpm.expand("%system_python")\
838cdc
    -- is the package built for python2 as "python-foo" ?\
838cdc
    old_python2 = rpm.expand("%python2_prefix") == "python"\
838cdc
    is_called_python = spec_name_prefix == "python"\
838cdc
\
838cdc
    -- detect `flavor`, used for evaluating %ifmacros\
838cdc
    if is_called_python then\
838cdc
        -- either system_python (if found in %pythons)\
838cdc
        -- or the last entry of %pythons\
838cdc
        for _,py in ipairs(pythons) do\
838cdc
            flavor = py\
838cdc
            if flavor == system_python then break end\
838cdc
        end\
838cdc
    else\
838cdc
        -- specname is something other than "python-", and it is a valid\
838cdc
        -- python flavor (otherwise spec_name_prefix defaults to "python"\
838cdc
        -- so `is_called_python` is true), so we use it literally\
838cdc
        flavor = spec_name_prefix\
838cdc
    end\
838cdc
\
838cdc
    -- find the spec file\
838cdc
    specpath = name .. ".spec"\
838cdc
    local locations = { rpm.expand("%_sourcedir"), rpm.expand("%_specdir"), "." }\
838cdc
    for _,loc in ipairs(locations) do\
838cdc
        local filename = loc .. "/" .. specpath\
838cdc
        if posix.stat(filename, "mode") ~= nil then\
838cdc
            specpath = filename\
838cdc
            break\
838cdc
        end\
838cdc
    end\
838cdc
}
838cdc
838cdc
%python_subpackages() %{lua: \
838cdc
    rpm.expand("%_python_macro_init")\
838cdc
    _python_subpackages_emitted = true\
838cdc
\
838cdc
    local current_flavor  = flavor\
838cdc
    local original_flavor = rpm.expand("%python_flavor")\
838cdc
\
838cdc
    -- line processing functions\
838cdc
    local function print_altered(line)\
838cdc
        -- set %name macro to proper flavor-name\
838cdc
        line = line:gsub("%%{?name}?", current_flavor .. "-" .. modname)\
838cdc
        -- print expanded\
838cdc
        print(rpm.expand(replace_macros(line, current_flavor)) .. "\\n")\
838cdc
    end\
838cdc
\
838cdc
    local function ignore_line(line) end\
838cdc
\
838cdc
    local function files_line(line)\
838cdc
        -- unexpand %license at start of line\
838cdc
        if line:startswith("%license") then\
838cdc
            line = "%" .. line\
838cdc
        end\
838cdc
        return print_altered(line)\
838cdc
    end\
838cdc
\
838cdc
    local PROPERTY_COPY_UNMODIFIED = lookup_table { "Epoch:", "Summary:", "Version:", "BuildArch:" }\
838cdc
    local PROPERTY_COPY_MODIFIED = lookup_table {\
838cdc
        "Requires:", "Provides:",\
838cdc
        "Recommends:", "Suggests:",\
838cdc
        "Conflicts:", "Obsoletes:",\
838cdc
        "Supplements:", "Enhances:",\
838cdc
        "%requires_eq", "%requires_ge",\
838cdc
        "Requires(pre):", "Requires(preun):", "Requires(post):", "Requires(postun):",\
838cdc
        "Requires(pretrans):", "Requires(posttrans):",\
838cdc
    }\
838cdc
\
838cdc
    local function process_package_line(line)\
838cdc
        -- This function processes lines like "Requires: something something".\
838cdc
        -- "Requires: python-foo" -> "Requires: python3-foo"\
838cdc
        -- "Requires: %{name} = %{version}" -> "Requires: python3-modname = %{version}"\
838cdc
        -- "Supplements: packageand(python-a:python-b)" -> "Supplements: packageand(python3-a:python3-b)"\
838cdc
        -- you get the idea.\
838cdc
        -- TODO implement %$flavor_only support here?\
838cdc
\
838cdc
        -- first split Property: value\
838cdc
        local property, value = line:match("^([A-Z%%]%S+)%s*(.*)$")\
838cdc
\
838cdc
        -- "python-foo" -> "python3-foo"\
838cdc
        local function rename_package(package, flavor)\
838cdc
            if package == "python" or package == flavor then\
838cdc
                -- specialcase plain "python"\
838cdc
                package = current_flavor\
838cdc
            else\
838cdc
                package = package:gsub("^" .. flavor .. "(%W)", current_flavor .. "%1")\
838cdc
                package = package:gsub("^python(%W)", current_flavor .. "%1")\
838cdc
            end\
838cdc
            return package\
838cdc
        end\
838cdc
\
838cdc
        -- split and rewrite "packageand(a:b:c)", using rename_package() for each of a, b, c\
838cdc
        local function fix_packageand(packageand, flavor)\
838cdc
            local inner = packageand:match("^packageand%((.*)%)$")\
838cdc
            if not inner then return packageand end\
838cdc
            local eat = inner\
838cdc
            local result = "packageand("\
838cdc
            while eat do\
838cdc
                local idx = eat:find(":")\
838cdc
                local n = ""\
838cdc
                if idx then\
838cdc
                    n = eat:sub(1, idx)\
838cdc
                    eat = eat:sub(idx+1)\
838cdc
                else\
838cdc
                    n = eat\
838cdc
                    eat = nil\
838cdc
                end\
838cdc
                n = n:gsub("^%s*", "")\
838cdc
                result = result .. rename_package(n, flavor)\
838cdc
            end\
838cdc
            return result .. ")"\
838cdc
        end\
838cdc
\
838cdc
        if PROPERTY_COPY_UNMODIFIED[property] then\
838cdc
            print_altered(line)\
838cdc
        elseif PROPERTY_COPY_MODIFIED[property] then\
838cdc
            -- specifically handle %name macro before expansion\
838cdc
            line = line:gsub("%%{?name}?", current_flavor .. "-" .. modname)\
838cdc
            -- convert value using the appropriate function\
838cdc
            if value:startswith("packageand") then\
838cdc
                value = fix_packageand(value, flavor)\
838cdc
            else\
838cdc
                value = rename_package(value, flavor)\
838cdc
            end\
838cdc
            -- rely on print_altered to perform expansion on the result\
838cdc
            print_altered(string.format("%s %s", property, value))\
838cdc
        end\
838cdc
    end\
838cdc
\
838cdc
    local auto_posttrans = {}\
838cdc
    local auto_posttrans_current = {}\
838cdc
    local auto_posttrans_backslash = false\
838cdc
\
838cdc
    local function expect_alternatives(line)\
838cdc
        if auto_posttrans_backslash then\
838cdc
            local apc = auto_posttrans_current\
838cdc
            apc[#apc] = apc[#apc] .. "\\n" .. line\
838cdc
            auto_posttrans_backslash = line:endswith("\\\\")\
838cdc
        elseif line:startswith("%python_install_alternative")\
838cdc
            or line:startswith("%{python_install_alternative") -- "}"\
838cdc
            or line:startswith("%" .. flavor .. "_install_alternative")\
838cdc
            or line:startswith("%{" .. flavor .. "_install_alternative") -- "}"\
838cdc
            then\
838cdc
                table.insert(auto_posttrans_current, line)\
838cdc
                auto_posttrans_backslash = line:endswith("\\\\")\
838cdc
        else\
838cdc
            auto_posttrans_backslash = false\
838cdc
        end\
838cdc
        return print_altered(line)\
838cdc
    end\
838cdc
    -- end line processing functions\
838cdc
\
838cdc
    local function print_obsoletes(modname)\
838cdc
        if current_flavor == "python2" then\
838cdc
            print(rpm.expand("Obsoletes: python-" .. modname .. " < %{?epoch:%{epoch}:}%{version}-%{release}\\n"))\
838cdc
            print(rpm.expand("Provides: python-" .. modname .. " = %{?epoch:%{epoch}:}%{version}-%{release}\\n"))\
838cdc
        end\
838cdc
    end\
838cdc
\
838cdc
    local function files_headline(flavor, param)\
838cdc
        if not param then param = "" end\
838cdc
        local append = param:match("(%-f%s+%S+)")\
838cdc
        local nof = param:gsub("%-f%s+%S+%s*", "")\
838cdc
        local python_files = param:match("%%{?python_files}?")\
838cdc
        local subpkg = param:match("%%{python_files%s*(.-)}")\
838cdc
        if subpkg then python_files = true end\
838cdc
\
838cdc
        if is_called_python and not python_files then\
838cdc
            -- kingly hack. but RPM's native %error does not work.\
838cdc
            local errmsg =\
838cdc
                'error: Package with "python-" prefix must not contain unmarked "%files" sections.\\n' ..\
838cdc
                'error: Use "%files %python_files" or "%files %{python_files foo} instead.\\n'\
838cdc
            io.stderr:write(errmsg)\
838cdc
            print(errmsg)\
838cdc
            error('Invalid spec file')\
838cdc
        end\
838cdc
\
838cdc
        local mymodname = nof\
838cdc
        if python_files then mymodname = subpkg end\
838cdc
        return "%files -n " .. package_name(flavor, modname, mymodname, append) .. "\\n"\
838cdc
    end\
838cdc
\
838cdc
    local function section_headline(section, flavor, param)\
838cdc
        if section == "files" then\
838cdc
            return files_headline(flavor, param)\
838cdc
        else\
838cdc
            return "%" .. section .. " -n " .. package_name(flavor, modname, param) .. "\\n"\
838cdc
        end\
838cdc
    end\
838cdc
\
838cdc
    local python2_binsuffix = rpm.expand("%python2_bin_suffix")\
838cdc
    local function dump_alternatives_posttrans()\
838cdc
        if not old_python2 and current_flavor == "python2" then\
838cdc
            for label, value in pairs(auto_posttrans) do\
838cdc
                if value ~= false then\
838cdc
                    print(section_headline("posttrans", current_flavor, label))\
838cdc
                    for _,line in ipairs(value) do\
838cdc
                        -- RPM needs {} characters in Lua macros to match, so\
838cdc
                        -- this is an opening "{" for this one: ----------v\
838cdc
                        firstarg = line:match("install_alternative%s+([^%s}]+)")\
838cdc
                        if firstarg then\
838cdc
                            local _,_,path = python_alternative_names(firstarg, python2_binsuffix)\
838cdc
                            print(string.format('if [ -e "%s" ]; then\\n', path))\
838cdc
                            print_altered(line)\
838cdc
                            print("fi\\n")\
838cdc
                        end\
838cdc
                    end\
838cdc
                end\
838cdc
            end\
838cdc
        end\
838cdc
        auto_posttrans = {}\
838cdc
    end\
838cdc
\
838cdc
    local function should_expect_alternatives(section, param)\
838cdc
        if old_python2 or current_flavor ~= "python2" then return false end\
838cdc
        if param == nil then param = "" end\
838cdc
        if section == "posttrans" then\
838cdc
            auto_posttrans[param] = false\
838cdc
            return false\
838cdc
        end\
838cdc
        if section == "post" and auto_posttrans[param] ~= false then\
838cdc
            auto_posttrans_current = {}\
838cdc
            auto_posttrans[param] = auto_posttrans_current\
838cdc
            return true\
838cdc
        end\
838cdc
        return false\
838cdc
    end\
838cdc
\
838cdc
    local function match_braces(line)\
838cdc
        local count = 0\
838cdc
        for c in line:gmatch(".") do\
838cdc
            if c == "{" then count = count + 1\
838cdc
            elseif c == "}" and count > 0 then count = count - 1\
838cdc
            end\
838cdc
        end\
838cdc
        return count == 0\
838cdc
    end\
838cdc
\
838cdc
    local KNOWN_SECTIONS = lookup_table {"package", "description", "files", "prep",\
838cdc
        "build", "install", "check", "clean", "pre", "post", "preun", "postun",\
838cdc
        "pretrans", "posttrans", "changelog"}\
838cdc
    local COPIED_SECTIONS = lookup_table {"description", "files",\
838cdc
        "pre", "post", "preun", "postun", "pretrans", "posttrans"}\
838cdc
\
838cdc
    -- before we start, print Provides: python2-modname\
838cdc
    if is_called_python and old_python2 then\
838cdc
        print(rpm.expand("Provides: python2-" .. modname .. " = %{?epoch:%{epoch}:}%{version}-%{release}\\n"))\
838cdc
    end\
838cdc
\
838cdc
    for _,python in ipairs(pythons) do\
838cdc
        local is_current_flavor = python == flavor\
838cdc
        -- "python-foo" case:\
838cdc
        if is_called_python then\
838cdc
            if old_python2 then\
838cdc
                -- if we're in old-style package, "python" == "python2"\
838cdc
                is_current_flavor = python == "python2"\
838cdc
            else\
838cdc
                -- else nothing is current flavor, always generate\
838cdc
                is_current_flavor = false\
838cdc
            end\
838cdc
        end\
838cdc
\
838cdc
        current_flavor = python\
838cdc
\
838cdc
        -- rescan spec for each flavor\
838cdc
        if not is_current_flavor then\
838cdc
            local spec, err = io.open(specpath, "r")\
838cdc
            if err then print ("bad spec " .. specpath) return end\
838cdc
\
838cdc
            rpm.define("python_flavor " .. python)\
838cdc
\
838cdc
            local section_function = process_package_line\
838cdc
            print(section_headline("package", current_flavor, nil))\
838cdc
            print_obsoletes(modname)\
838cdc
\
838cdc
            while true do\
838cdc
                -- collect lines until braces match. it's what rpm does, kind of.\
838cdc
                local eof = false\
838cdc
                local line = spec:read()\
838cdc
                if line == nil then break end\
838cdc
                while not match_braces(line) do\
838cdc
                    local nl = spec:read()\
838cdc
                    if nl == nil then eof = true break end\
838cdc
                    line = line .. "\\n" .. nl\
838cdc
                end\
838cdc
                if eof then break end\
838cdc
                --io.stderr:write(current_flavor .. " >".. tostring(line) .."<\\n")\
838cdc
\
838cdc
                -- match section delimiter\
838cdc
                local section_noparam = line:match("^%%(%S+)(%s*)$")\
838cdc
                local section_withparam, param = line:match("^%%(%S+)%s+(.+)$")\
838cdc
                local newsection = section_noparam or section_withparam\
838cdc
\
838cdc
                if KNOWN_SECTIONS[newsection] then\
838cdc
                    -- enter new section\
838cdc
                    if param and param:startswith("-n") then\
838cdc
                        -- ignore named section\
838cdc
                        section_function = ignore_line\
838cdc
                    elseif newsection == "package" then\
838cdc
                        print(section_headline("package", current_flavor, param))\
838cdc
                        print_obsoletes(modname .. "-" .. param)\
838cdc
                        section_function = process_package_line\
838cdc
                    elseif newsection == "files" and current_flavor == flavor then\
838cdc
                        section_function = ignore_line\
838cdc
                    elseif COPIED_SECTIONS[newsection] then\
838cdc
                        print(section_headline(newsection, current_flavor, param))\
838cdc
                        if should_expect_alternatives(newsection, param) then\
838cdc
                            section_function = expect_alternatives\
838cdc
                        elseif newsection == "files" then\
838cdc
                            section_function = files_line\
838cdc
                        else\
838cdc
                            section_function = print_altered\
838cdc
                        end\
838cdc
                    else\
838cdc
                        section_function = ignore_line\
838cdc
                    end\
838cdc
                elseif line:startswith("%python_subpackages") then\
838cdc
                    -- ignore\
838cdc
                elseif line:startswith("%if") then\
838cdc
                    -- RPM handles %if on top level, whole sections can be conditional.\
838cdc
                    -- We must copy the %if declarations always, even if they are part\
838cdc
                    -- of non-copied sections. Otherwise we miss this:\
838cdc
                    -- %files A\
838cdc
                    -- /bin/something\
838cdc
                    -- %if %condition\
838cdc
                    -- %files B\
838cdc
                    -- /bin/otherthing\
838cdc
                    -- %endif\
838cdc
                    print_altered(line)\
838cdc
                    -- We are, however, copying expanded versions. This way, specifically,\
838cdc
                    -- macros like %ifpython3 are evaluated differently in the top-level spec\
838cdc
                    -- itself and in the copied sections.\
838cdc
                    --io.stderr:write(rpm.expand(line) .. "\\n")\
838cdc
                elseif line:startswith("%else") or line:startswith("%endif") then\
838cdc
                    print(line .. "\\n")\
838cdc
                    --io.stderr:write(line .. "\\n")\
838cdc
                else\
838cdc
                    section_function(line)\
838cdc
                end\
838cdc
            end\
838cdc
\
838cdc
            dump_alternatives_posttrans()\
838cdc
\
838cdc
            spec:close()\
838cdc
        end\
838cdc
    end\
838cdc
\
838cdc
    -- restore %python_flavor for further processing\
838cdc
    rpm.define("python_flavor " .. original_flavor)\
838cdc
}
838cdc
838cdc
%python_exec(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-=) %{lua: \
838cdc
    local args = rpm.expand("%**")\
838cdc
    print(rpm.expand("%{python_expand %__$python " .. args .. "}"))\
838cdc
}
838cdc
838cdc
%python_expand(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-=) %{lua: \
838cdc
    -- force spec scan\
838cdc
    rpm.expand("%_python_macro_init")\
838cdc
    local args = rpm.expand("%**")\
838cdc
    for _, python in ipairs(pythons) do\
838cdc
        print(rpm.expand("%{_python_use_flavor " .. python .. "}\\n"))\
838cdc
        local cmd = replace_macros(args, python)\
838cdc
        cmd = cmd:gsub("$python", python)\
838cdc
        print(rpm.expand(cmd .. "\\n"))\
838cdc
    end\
838cdc
}
838cdc
838cdc
%python_build(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-=) %{lua: \
838cdc
    rpm.expand("%_python_macro_init")\
838cdc
    for _, python in ipairs(pythons) do\
838cdc
        print(rpm.expand("%" .. python .. "_build %**"))\
838cdc
    end\
838cdc
}
838cdc
838cdc
%python_install(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-=) %{lua: \
838cdc
    rpm.expand("%_python_macro_init")\
838cdc
    for _, python in ipairs(pythons) do\
838cdc
        print(rpm.expand("%" .. python .. "_install %**"))\
838cdc
    end\
838cdc
}
838cdc
838cdc
%python_files() %{lua: \
838cdc
    rpm.expand("%_python_macro_init")\
838cdc
    local nparams = rpm.expand("%#")\
838cdc
    local param = ""\
838cdc
    if tonumber(nparams) > 0 then param = rpm.expand("%1") end\
838cdc
\
838cdc
    print("-n " .. package_name(flavor, modname, param))\
838cdc
\
838cdc
    if not _python_subpackages_emitted then\
838cdc
        print("\\n/%python_subpackages_macro_not_present\\n")\
838cdc
        io.stderr:write("%python_subpackages macro not present\\n"\
838cdc
            .. "(To get rid of this error, either add a %python_subpackages macro to preamble "\
838cdc
            .. "or remove %python_files.\\n")\
838cdc
        error("%python_subpackages macro not present\\n")\
838cdc
    end\
838cdc
}
838cdc
838cdc
%python_clone(a) %{lua: \
838cdc
    rpm.expand("%_python_macro_init")\
838cdc
    local param = rpm.expand("%1")\
838cdc
    local link, name, path\
838cdc
    for _, python in ipairs(pythons) do\
838cdc
        local binsuffix = rpm.expand("%" .. python .. "_bin_suffix")\
838cdc
        link,name,path = python_alternative_names(param, binsuffix, true)\
838cdc
        print(rpm.expand(string.format("cp %s %s\\n", param, path)))\
838cdc
        print(rpm.expand(string.format("sed -ri '1s@#!.*python.*@#!/usr/bin/%s@' %s\\n", python, path)))\
838cdc
    end\
838cdc
\
838cdc
    -- %python_clone -a\
838cdc
    if rpm.expand("%{?-a}") == "-a" then\
838cdc
        local buildroot = rpm.expand("%{buildroot}")\
838cdc
        if link:startswith(buildroot) then link = link:sub(buildroot:len() + 1) end\
838cdc
        print(rpm.expand(string.format("%%{prepare_alternative -t %s %s}\\n", link, name)))\
838cdc
    end\
838cdc
}
838cdc
838cdc
%python_module() %{lua: \
838cdc
    rpm.expand("%_python_macro_init")\
838cdc
    local params = rpm.expand("%**")\
838cdc
    for _, python in ipairs(pythons) do\
838cdc
        if python == "python2" then\
838cdc
            print(rpm.expand("%python2_prefix") .. "-" .. params)\
838cdc
        else\
838cdc
            print(python .. "-" .. params)\
838cdc
        end\
838cdc
        print(" ")\
838cdc
    end\
838cdc
}
838cdc
### LUA-MACROS ###
838cdc
838cdc
838cdc
%_python_macro_init %{_python_definitions}%{_python_scan_spec}%{lua: rpm.define("_python_macro_init %{nil}")}
838cdc