295 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			295 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| -- 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<root> to
 | ||
| -- <root><suffix> 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
 | ||
| -- <rpmvar><suffix>, 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
 | ||
| -- <rpmvar><suffix> 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 <rpmvar><suffix> 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,
 | ||
| }
 |