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