-- Convenience Lua functions that can be used within rpm macros -- Reads an rpm variable. Unlike a basic rpm.expand("{?foo}"), returns nil if -- the variable is unset, which is convenient in lua tests and enables -- differentiating unset variables from variables set to "" local function read(rpmvar) if not rpmvar or (rpm.expand("%{" .. rpmvar .. "}") == "%{" .. rpmvar .. "}") then return nil else return rpm.expand("%{?" .. rpmvar .. "}") end end -- Returns true if the macro that called this function had flag set -- – for example, hasflag("z") would give the following results: -- %foo -z bar → true -- %foo -z → true -- %foo → false local function hasflag(flag) return (rpm.expand("%{-" .. flag .. "}") ~= "") end -- Returns the argument passed to flag in the macro that called this function -- – for example, readflag("z") would give the following results: -- %foo -z bar → bar -- %foo → nil -- %foo -z "" → empty string -- %foo -z '' → empty string local function readflag(flag) if not hasflag(flag) then return nil else local a = rpm.expand("%{-" .. flag .. "*}") -- Handle "" and '' as empty strings if (a == '""') or (a == "''") then a = '' end return a end end -- Sets a spec variable; echoes the result if verbose local function explicitset(rpmvar, value, verbose) local value = value if (value == nil) or (value == "") then value = "%{nil}" end rpm.define(rpmvar .. " " .. value) if verbose then rpm.expand("%{warn:Setting %%{" .. rpmvar .. "} = " .. value .. "}") end end -- Unsets a spec variable if it is defined; echoes the result if verbose local function explicitunset(rpmvar, verbose) if (rpm.expand("%{" .. rpmvar .. "}") ~= "%{" .. rpmvar .. "}") then rpm.define(rpmvar .. " %{nil}") if verbose then rpm.expand("%{warn:Unsetting %%{" .. rpmvar .. "}}") end end end -- Sets a spec variable, if not already set; echoes the result if verbose local function safeset(rpmvar, value, verbose) if (rpm.expand("%{" .. rpmvar .. "}") == "%{" .. rpmvar .. "}") then explicitset(rpmvar,value,verbose) end end -- Aliases a list of rpm variables to the same variables suffixed with 0 (and -- vice versa); echoes the result if verbose local function zalias(rpmvars, verbose) for _, sfx in ipairs({{"","0"},{"0",""}}) do for _, rpmvar in ipairs(rpmvars) do local toalias = "%{?" .. rpmvar .. sfx[1] .. "}" if (rpm.expand(toalias) ~= "") then safeset(rpmvar .. sfx[2], toalias, verbose) end end end end -- Takes a list of rpm variable roots and a suffix and alias current to -- if it resolves to something not empty local function setcurrent(rpmvars, suffix, verbose) for _, rpmvar in ipairs(rpmvars) do if (rpm.expand("%{?" .. rpmvar .. suffix .. "}") ~= "") then explicitset( "current" .. rpmvar, "%{" .. rpmvar .. suffix .. "}", verbose) else explicitunset("current" .. rpmvar, verbose) end end end -- Echo the list of rpm variables, with suffix, if set local function echovars(rpmvars, suffix) for _, rpmvar in ipairs(rpmvars) do rpmvar = rpmvar .. suffix local header = string.sub(" " .. rpmvar .. ": ",1,21) rpm.expand("%{?" .. rpmvar .. ":%{echo:" .. header .. "%{?" .. rpmvar .. "}}}") end end -- Returns an array, indexed by suffix, containing the non-empy values of -- , with suffix an integer string or the empty string local function getsuffixed(rpmvar) local suffixes = {} zalias({rpmvar}) for suffix=0,9999 do local value = rpm.expand("%{?" .. rpmvar .. suffix .. "}") if (value ~= "") then suffixes[tostring(suffix)] = value end end -- rpm convention is to alias no suffix to zero suffix -- only add no suffix if zero suffix is different local value = rpm.expand("%{?" .. rpmvar .. "}") if (value ~= "") and (value ~= suffixes["0"]) then suffixes[""] = value end return suffixes end -- Returns the list of suffixes, including the empty string, for which -- is set to a non empty value local function getsuffixes(rpmvar) suffixes = {} for suffix in pairs(getsuffixed(rpmvar)) do table.insert(suffixes,suffix) end table.sort(suffixes, function(a,b) return (tonumber(a) or 0) < (tonumber(b) or 0) end) return suffixes end -- Returns the suffix for which has a non-empty value that -- matches best the beginning of the value string local function getbestsuffix(rpmvar, value) local best = nil local currentmatch = "" for suffix, setvalue in pairs(getsuffixed(rpmvar)) do if (string.len(setvalue) > string.len(currentmatch)) and (string.find(value, "^" .. setvalue)) then currentmatch = setvalue best = suffix end end return best end -- %writevars core local function writevars(macrofile, rpmvars) for _, rpmvar in ipairs(rpmvars) do print("sed -i 's\029" .. string.upper("@@" .. rpmvar .. "@@") .. "\029" .. rpm.expand( "%{" .. rpmvar .. "}" ) .. "\029g' " .. macrofile .. "\n") end end -- https://github.com/rpm-software-management/rpm/issues/566 -- Reformat a text intended to be used used in a package description, removing -- rpm macro generation artefacts. -- – remove leading and ending empty lines -- – trim intermediary empty lines to a single line -- – fold on spaces -- Should really be a %%{wordwrap:…} verb local function wordwrap(text) text = rpm.expand(text .. "\n") text = string.gsub(text, "\t", " ") text = string.gsub(text, "\r", "\n") text = string.gsub(text, " +\n", "\n") text = string.gsub(text, "\n+\n", "\n\n") text = string.gsub(text, "^\n", "") text = string.gsub(text, "\n( *)[-*—][  ]+", "\n%1– ") output = "" for line in string.gmatch(text, "[^\n]*\n") do local pos = 0 local advance = "" for word in string.gmatch(line, "%s*[^%s]*\n?") do local wl, bad = utf8.len(word) if not wl then print("%{warn:Invalid UTF-8 sequence detected in:}" .. "%{warn:" .. word .. "}" .. "%{warn:It may produce unexpected results.}") wl = bad end if (pos == 0) then advance, n = string.gsub(word, "^(%s*– ).*", "%1") if (n == 0) then advance = string.gsub(word, "^(%s*).*", "%1") end advance = string.gsub(advance, "– ", " ") pos = pos + wl elseif (pos + wl < 81) or ((pos + wl == 81) and string.match(word, "\n$")) then pos = pos + wl else word = advance .. string.gsub(word, "^%s*", "") output = output .. "\n" pos = utf8.len(word) end output = output .. word if pos > 80 then pos = 0 if not string.match(word, "\n$") then output = output .. "\n" end end end end output = string.gsub(output, "\n*$", "\n") return output end -- Because rpmbuild will fail if a subpackage is declared before the source -- package itself, provide a source package declaration shell as fallback. local function srcpkg(verbose) if verbose then rpm.expand([[ %{echo:Creating a header for the SRPM from %%{source_name}, %%{source_summary} and} %{echo:%%{source_description}. If that is not the intended result, please declare the} %{echo:SRPM header and set %%{source_name} in your spec file before calling a macro} %{echo:that creates other package headers.} ]]) end print(rpm.expand([[ Name: %{source_name} Summary: %{source_summary} %description %wordwrap -v source_description ]])) explicitset("currentname", "%{source_name}", verbose) end -- %new_package core local function new_package(source_name, pkg_name, name_suffix, first, verbose) -- Safety net when the wrapper is used in conjunction with traditional syntax if (not first) and (not source_name) then rpm.expand([[ %{warn:Something already set a package name. However, %%{source_name} is not set.} %{warn:Please set %%{source_name} to the SRPM name to ensure reliable processing.} ]]) if name_suffix then print(rpm.expand("%package " .. name_suffix)) else print(rpm.expand("%package -n " .. pkg_name)) end return end -- New processing if not (pkg_name or name_suffix or source_name) then rpm.expand([[ %{error:You need to set %%{source_name} or provide explicit package naming!} ]]) end if name_suffix then print(rpm.expand("%package " .. name_suffix)) explicitset("currentname", "%{source_name}-" .. name_suffix, verbose) else if not source_name then source_name = pkg_name end if (pkg_name == source_name) then safeset("source_name", source_name, verbose) print(rpm.expand("Name: %{source_name}")) else if source_name and first then srcpkg(verbose) end print(rpm.expand("%package -n " .. pkg_name)) end explicitset("currentname", pkg_name, verbose) end end return { read = read, hasflag = hasflag, readflag = readflag, explicitset = explicitset, explicitunset = explicitunset, safeset = safeset, zalias = zalias, setcurrent = setcurrent, echovars = echovars, getsuffixed = getsuffixed, getsuffixes = getsuffixes, getbestsuffix = getbestsuffix, writevars = writevars, wordwrap = wordwrap, new_package = new_package, }