f9efe2
-- Lua code used by macros.forge and derivatives
f9efe2
f9efe2
-- Computes the suffix of a version string, removing vprefix if it matches
f9efe2
-- For example with vprefix 1.2.3: 1.2.3.rc2 → .rc2 but 1.2.30 → 1.2.30 not 0
f9efe2
local function getversionsuffix(vstring,vprefix)
f9efe2
  if (string.sub(vstring, 1, #vprefix) == vprefix) and
f9efe2
     (not string.match(string.sub(vstring, #vprefix + 1), "^%.?%d")) then
f9efe2
    return string.sub(vstring, #vprefix + 1)
f9efe2
  else
f9efe2
    return vstring
f9efe2
  end
f9efe2
end
f9efe2
f9efe2
-- Check if an identified url is sane
f9efe2
local function checkforgeurl(url, id, silent)
f9efe2
  local checkedurl  = nil
f9efe2
  local checkedid   = nil
f9efe2
  local urlpatterns = {
f9efe2
    gitlab = {
f9efe2
      pattern     = 'https://[^/]+/[^/]+/[^/#?]+',
f9efe2
      description = 'https://(…[-.])gitlab[-.]…/owner/repo'},
f9efe2
    pagure = {
f9efe2
      pattern     = 'https://[^/]+/[^/#?]+',
f9efe2
      description = 'https://pagure.io/repo'},
f9efe2
    pagure_ns = {
f9efe2
      pattern     = 'https://[^/]+/[^/]+/[^/#?]+',
f9efe2
      description = 'https://pagure.io/namespace/repo'},
f9efe2
    pagure_fork = {
f9efe2
      pattern     = 'https://[^/]+/fork/[^/]+/[^/#?]+',
f9efe2
      description = 'https://pagure.io/fork/owner/repo'},
f9efe2
    pagure_ns_fork = {
f9efe2
      pattern     = 'https://[^/]+/fork/[^/]+/[^/]+/[^/#?]+',
f9efe2
      description = 'https://pagure.io/fork/owner/namespace/repo'},
f9efe2
    ["gitea.com"] = {
f9efe2
      pattern     = 'https://[^/]+/[^/]+/[^/#?]+',
f9efe2
      description = 'https://gitea.com/owner/repo'},
f9efe2
    github = {
f9efe2
      pattern     = 'https://[^/]+/[^/]+/[^/#?]+',
f9efe2
      description = 'https://(…[-.])github[-.]…/owner/repo'},
f9efe2
    ["code.googlesource.com"] = {
f9efe2
      pattern     = 'https://code.googlesource.com/[^#?]*[^/#?]+',
f9efe2
      description = 'https://code.googlesource.com/…/repo'},
f9efe2
    ["bitbucket.org"] = {
f9efe2
      pattern     = 'https://[^/]+/[^/]+/[^/#?]+',
f9efe2
      description = 'https://bitbucket.org/owner/repo'}}
f9efe2
  if (urlpatterns[id] ~= nil) then
f9efe2
    checkedurl = string.match(url,urlpatterns[id]["pattern"])
f9efe2
    if (checkedurl == nil) then
f9efe2
      if not silent then
f9efe2
        rpm.expand("%{error:" .. id .. " URLs must match " .. urlpatterns[id]["description"] .. " !}")
f9efe2
      end
f9efe2
    else
f9efe2
      checkedid = id
f9efe2
    end
f9efe2
  end
f9efe2
  return checkedurl, checkedid
f9efe2
end
f9efe2
f9efe2
-- Check if an url matches a known forge
f9efe2
local function idforge(url, silent)
f9efe2
  local forgeurl = nil
f9efe2
  local forge    = nil
f9efe2
  if (url ~= "") then
f9efe2
    forge = string.match(url, "^[^:]+://([^/]+)/")
f9efe2
    if (forge == nil) then
f9efe2
      if not silent then
f9efe2
        rpm.expand("%{error:URLs must include a protocol such as https:// and a path starting with / !}")
f9efe2
      end
f9efe2
    else
f9efe2
      if (forge == "pagure.io") then
f9efe2
        if     string.match(url, "[^:]+://pagure.io/fork/[^/]+/[^/]+/[^/]+") then
f9efe2
          forge = "pagure_ns_fork"
f9efe2
        elseif string.match(url, "[^:]+://pagure.io/fork/[^/]+/[^/]+") then
f9efe2
          forge = "pagure_fork"
f9efe2
        elseif  string.match(url, "[^:]+://pagure.io/[^/]+/[^/]+") then
f9efe2
          forge = "pagure_ns"
f9efe2
        elseif  string.match(url, "[^:]+://pagure.io/[^/]+") then
f9efe2
          forge = "pagure"
f9efe2
        end
f9efe2
      elseif (string.match(forge, "^gitlab[%.-]") or string.match(forge, "[%.-]gitlab[%.]")) then
f9efe2
        forge = "gitlab"
f9efe2
      elseif (string.match(forge, "^github[%.-]") or string.match(forge, "[%.-]github[%.]")) then
f9efe2
        forge = "github"
f9efe2
      end
f9efe2
      forgeurl, forge = checkforgeurl(url, forge, silent)
f9efe2
    end
f9efe2
  end
f9efe2
  return forgeurl, forge
f9efe2
end
f9efe2
f9efe2
-- The forgemeta macro main processing function
f9efe2
-- See the documentation in the macros.forge file for argument description
f9efe2
-- Also called directly by gometa
f9efe2
local function meta(suffix, verbose, informative, silent)
f9efe2
  local fedora = require "fedora.common"
f9efe2
  local ismain = (suffix == "") or (suffix == "0")
f9efe2
  if ismain then
f9efe2
    fedora.zalias({"forgeurl", "forgesource", "forgesetupargs",
f9efe2
                      "archivename", "archiveext", "archiveurl",
f9efe2
                      "topdir", "extractdir", "repo", "owner", "namespace",
f9efe2
                      "scm", "tag", "commit", "shortcommit", "branch", "version",
f9efe2
                      "date", "distprefix"}, verbose)
f9efe2
  end
f9efe2
  local variables = {
f9efe2
    default = {
f9efe2
      scm         = "git",
f9efe2
      archiveext  = "tar.bz2",
f9efe2
      repo        = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "^[^:]+://[^/]+/[^/]+/([^/?#]+)"))}',
f9efe2
      archivename = "%{repo"         .. suffix .. "}-%{ref"           .. suffix .. "}",
f9efe2
      topdir      = "%{archivename"  .. suffix .. "}" },
f9efe2
    gitlab = {
f9efe2
      archiveurl  = "%{forgeurl"     .. suffix .. "}/-/archive/%{ref" .. suffix .. "}/%{archivename" .. suffix .. "}.%{archiveext" .. suffix .. "}" },
f9efe2
    pagure = {
f9efe2
      archiveext  = "tar.gz",
f9efe2
      repo        = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "^[^:]+://[^/]+/([^/?#]+)"))}',
f9efe2
      archiveurl  = "%{forgeurl"     .. suffix .. "}/archive/%{ref"   .. suffix .. "}/%{archivename" .. suffix .. "}.%{archiveext" .. suffix .. "}" },
f9efe2
    pagure_ns = {
f9efe2
      archiveext  = "tar.gz",
f9efe2
      namespace   = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "^[^:]+://[^/]+/([^/]+)/[^/?#]+"))}',
f9efe2
      repo        = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "^[^:]+://[^/]+/[^/]+/([^/?#]+)"))}',
f9efe2
      archivename = "%{namespace"    .. suffix .. "}-%{repo"          .. suffix .. "}-%{ref"         .. suffix .. "}",
f9efe2
      archiveurl  = "%{forgeurl"     .. suffix .. "}/archive/%{ref"   .. suffix .. "}/%{archivename" .. suffix .. "}.%{archiveext" .. suffix .. "}" },
f9efe2
    pagure_fork = {
f9efe2
      archiveext  = "tar.gz",
f9efe2
      owner       = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "https://[^/]+/fork/([^/]+)/[^/?#]+"))}',
f9efe2
      repo        = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "https://[^/]+/fork/[^/]+/([^/?#]+)"))}',
f9efe2
      archivename = "%{owner"        .. suffix .. "}-%{repo"          .. suffix .. "}-%{ref"         .. suffix .. "}",
f9efe2
      archiveurl  = "%{forgeurl"     .. suffix .. "}/archive/%{ref"   .. suffix .. "}/%{archivename" .. suffix .. "}.%{archiveext" .. suffix .. "}" },
f9efe2
    pagure_ns_fork = {
f9efe2
      owner       = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "https://[^/]+/fork/([^/]+)/[^/]+/[^/?#]+"))}',
f9efe2
      namespace   = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "https://[^/]+/fork/[^/]+/([^/]+)/[^/?#]+")}',
f9efe2
      repo        = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "https://[^/]+/fork/[^/]+/[^/]+/([^/?#]+)")}',
f9efe2
      archivename = "%{owner"        .. suffix .. "}-%{namespace"     .. suffix .. "}-%{repo"        .. suffix .. "}-%{ref"        .. suffix .. "}",
f9efe2
      archiveurl  = "%{forgeurl"     .. suffix .. "}/archive/%{ref"   .. suffix .. "}/%{archivename" .. suffix .. "}.%{archiveext" .. suffix .. "}" },
f9efe2
    ["gitea.com"] = {
f9efe2
      archiveext  = "tar.gz",
f9efe2
      archivename = "%{fileref"      .. suffix .. "}",
f9efe2
      archiveurl  = "%{forgeurl"     .. suffix .. "}/archive/%{ref"   .. suffix .. "}.%{archiveext" .. suffix .. "}",
f9efe2
      topdir      = "%{repo}" },
f9efe2
    github = {
f9efe2
      archiveext  = "tar.gz",
f9efe2
      archivename = "%{repo"         .. suffix .. "}-%{fileref"       .. suffix .. "}",
f9efe2
      archiveurl  = "%{forgeurl"     .. suffix .. "}/archive/%{ref"   .. suffix .. "}/%{archivename" .. suffix .. "}.%{archiveext" .. suffix .. "}" },
f9efe2
    ["code.googlesource.com"] = {
f9efe2
      archiveext  = "tar.gz",
f9efe2
      repo        = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "^[^:]+://.+/([^/?#]+)"))}',
f9efe2
      archiveurl  = "%{forgeurl"     .. suffix .. "}/+archive/%{ref"  .. suffix .. "}.%{archiveext"  .. suffix .. "}",
f9efe2
      topdir      = "" },
f9efe2
    ["bitbucket.org"] = {
f9efe2
      shortcommit = '%{lua:print(string.sub(rpm.expand("%{commit'     .. suffix .. '}"), 1, 12))}',
f9efe2
      owner       = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "^[^:]+://[^/]+/([^/?#]+)"))}',
f9efe2
      archivename = "%{owner"        .. suffix .. "}-%{repo"          .. suffix .. "}-%{shortcommit" .. suffix .. "}",
f9efe2
      archiveurl  = "%{forgeurl"     .. suffix .. "}/get/%{ref"       .. suffix .. "}.%{archiveext"  .. suffix .. "}" } }
f9efe2
  -- Packaging a moving branch is quite a bad idea, but since at least Gitlab
f9efe2
  -- will treat branches and tags the same way better support branches explicitly
f9efe2
  -- than have packagers hijack %{tag} to download branch states
f9efe2
  local spec = {}
f9efe2
  for _, v in ipairs({'forgeurl','tag','commit','branch','version'}) do
f9efe2
    spec[v] = rpm.expand("%{?" .. v .. suffix .. "}")
f9efe2
  end
f9efe2
  -- Compute the reference of the object to fetch
f9efe2
  local isrelease = false
f9efe2
  if     (spec["tag"]     ~= "") then       ref = "%{?tag"     .. suffix .. "}"
f9efe2
  elseif (spec["commit"]  ~= "") then       ref = "%{?commit"  .. suffix .. "}"
f9efe2
  elseif (spec["branch"]  ~= "") then       ref = "%{?branch"  .. suffix .. "}"
f9efe2
  else                                      ref = "%{?version" .. suffix .. "}"
f9efe2
                                      isrelease = true
f9efe2
  end
f9efe2
  if (rpm.expand(ref) == "") then
f9efe2
    if (suffix == "") then
f9efe2
      rpm.expand("%{error:You need to define Version:, %{commit} or %{tag} before the macro invocation !}")
f9efe2
    else
f9efe2
      rpm.expand("%{error:You need to define %{version" .. suffix .. "}, %{commit" .. suffix .. "} or %{tag" .. suffix .. "} before the macro invocation !}")
f9efe2
    end
f9efe2
  end
f9efe2
  local    forgeurl = spec["forgeurl"]
f9efe2
  -- For backwards compatibility only
f9efe2
  local expliciturl = rpm.expand("%{?-u*}")
f9efe2
  if   (expliciturl ~= "") then
f9efe2
    rpm.expand("%{warn:-u use in %%forgemeta is deprecated, use -z instead to select a separate set of rpm variables!}")
f9efe2
           forgeurl = expliciturl
f9efe2
  end
f9efe2
  local forge
f9efe2
  forgeurl,   forge = idforge(forgeurl, silent)
f9efe2
  if (forge ~= nil) then
f9efe2
    fedora.explicitset("forgeurl" .. suffix, forgeurl, verbose)
f9efe2
    -- Custom processing of quirky forges that can not be handled with simple variables
f9efe2
    if (forge == "github") then
f9efe2
      -- Workaround the way GitHub injects "v"s before some version strings (but not all!)
f9efe2
      -- To package one of the minority of sane GitHub projects that do not munge their version
f9efe2
      -- strings set tag to %{version} in your spec
f9efe2
      local fileref = ref
f9efe2
      if (ref == "%{?version"  .. suffix .. "}") then
f9efe2
        ref = "v" .. ref
f9efe2
      elseif (fileref ~= "%{?commit" .. suffix .. "}") and
f9efe2
             string.match(rpm.expand(fileref), "^v[%d]") then
f9efe2
        fileref = string.gsub(rpm.expand(fileref), "^v", "")
f9efe2
      elseif (string.match(rpm.expand(fileref), "/")) then
f9efe2
        fileref = string.gsub(rpm.expand(fileref), "/", "-")
f9efe2
      end
f9efe2
      fedora.safeset("fileref" .. suffix, fileref, verbose)
f9efe2
    elseif (forge == "gitea.com") then
f9efe2
      -- Workaround the way gitea mangles /s in ref names
f9efe2
      local fileref = ref
f9efe2
      fileref = string.gsub(rpm.expand(fileref), "/", "-")
f9efe2
      fedora.safeset("fileref" .. suffix, fileref, verbose)
f9efe2
    elseif (forge == "code.googlesource.com") then
f9efe2
      if (ref == "%{?version"  .. suffix .. "}") then
f9efe2
        ref = "v" .. ref
f9efe2
      end
f9efe2
    elseif (forge == "bitbucket.org") then
f9efe2
      if (spec["commit"] == "") then
f9efe2
        rpm.expand("%{error:All BitBucket URLs require commit value knowledge: you need to define %{commit}!}")
f9efe2
      end
f9efe2
    end
f9efe2
    fedora.safeset("ref" .. suffix, ref, verbose)
f9efe2
    -- Mass setting of the remaining variables
f9efe2
    for k,v in pairs(variables[forge]) do
f9efe2
      fedora.safeset(k .. suffix, variables[forge][k], verbose)
f9efe2
    end
f9efe2
    for k,v in pairs(variables["default"]) do
f9efe2
      if (variables[forge][k] == nil) then
f9efe2
        fedora.safeset(k .. suffix, variables["default"][k], verbose)
f9efe2
      end
f9efe2
    end
f9efe2
  end
f9efe2
  -- Generic rules
f9efe2
  for _, v in ipairs({'archiveurl','archivename','archiveext','topdir'}) do
f9efe2
    spec[v] = rpm.expand("%{?" .. v .. suffix .. "}")
f9efe2
  end
f9efe2
  -- Source URL processing (computing the forgesource spec variable)
f9efe2
  local forgesource = "%{archiveurl" .. suffix .. "}"
f9efe2
  if (string.match(spec["archiveurl"], "/([^/]+)$") ~= spec["archivename"] .. "." .. spec["archiveext"]) then
f9efe2
    forgesource     = "%{?archiveurl" .. suffix .. "}#/%{?archivename" .. suffix .. "}.%{archiveext" .. suffix .. "}"
f9efe2
  end
f9efe2
  fedora.safeset("forgesource" .. suffix, forgesource, verbose)
f9efe2
  -- Setup processing      (computing the forgesetup and extractdir variables)
f9efe2
  local forgesetupargs = "-n %{extractdir" .. suffix .. "}"
f9efe2
  local extractdir     = "%{topdir"        .. suffix .. "}"
f9efe2
  if (spec["topdir"] == "") then
f9efe2
    forgesetupargs     = "-c " .. forgesetupargs
f9efe2
    extractdir         = "%{archivename"   .. suffix .. "}"
f9efe2
  end
f9efe2
  if not ismain then
f9efe2
    if (spec["topdir"] ~= "") then
f9efe2
      forgesetupargs = "-T -D -b " .. suffix .. " " .. forgesetupargs
f9efe2
    else
f9efe2
      forgesetupargs = "-T -D -a " .. suffix .. " " .. forgesetupargs
f9efe2
    end
f9efe2
  end
f9efe2
  fedora.safeset("forgesetupargs" .. suffix, forgesetupargs, verbose)
f9efe2
  fedora.safeset("extractdir"     .. suffix, extractdir, verbose)
f9efe2
  -- dist processing       (computing the correct prefix for snapshots)
f9efe2
  local distprefix = ""
f9efe2
  if not isrelease then
f9efe2
    distprefix = string.lower(rpm.expand(ref))
f9efe2
    if     (ref == "%{?commit" .. suffix .. "}") then
f9efe2
      distprefix = string.sub(distprefix, 1, 7)
f9efe2
    elseif (ref ~= "%{?branch" .. suffix .. "}") then
f9efe2
      distprefix = string.gsub(distprefix,      "[%p%s]+", ".")
f9efe2
      distprefix = string.gsub(distprefix, "^" .. string.lower(rpm.expand("%{?repo}")) .. "%.?", "")
f9efe2
      local    v = string.gsub(rpm.expand("%{version}"), "[%p%s]+", ".")
f9efe2
      for _, p in ipairs({'','v','v.','version','version.','tags.v', 'tags.v.'}) do
f9efe2
        distprefix = getversionsuffix(distprefix, p .. v)
f9efe2
      end
f9efe2
      distprefix = string.gsub(distprefix, "^%.", "")
f9efe2
    end
f9efe2
    if (distprefix ~= "") then
f9efe2
      distprefix = "%{scm"     .. suffix .. "}" .. distprefix
f9efe2
      date = rpm.expand("%{?date" .. suffix .. "}")
f9efe2
      if (date ~= "") then
f9efe2
        distprefix = date .. distprefix
f9efe2
      else
f9efe2
        distprefix = "%([ -r %{_sourcedir}/%{archivename" .. suffix .. "}.%{archiveext" .. suffix .. "} ] && date +%Y%m%d -u -r %{_sourcedir}/%{archivename" .. suffix .. "}.%{archiveext" .. suffix .. "})" .. distprefix
f9efe2
      end
f9efe2
      distprefix = "." .. distprefix
f9efe2
    end
f9efe2
  end
f9efe2
  if (spec["version"] ~= "") and
f9efe2
     (spec["version"] ~= "0") and
f9efe2
     (spec["version"] ~= rpm.expand("%{?version}")) then
f9efe2
    distprefix = ".%{version" .. suffix .. "}" .. distprefix
f9efe2
  end
f9efe2
  if (rpm.expand(distprefix) ~= "") then
f9efe2
    if not ismain then
f9efe2
      distprefix = string.gsub(distprefix, "^%.", ".s")
f9efe2
    end
f9efe2
    fedora.safeset ("distprefix"    .. suffix, distprefix, verbose)
f9efe2
  end
f9efe2
  if ismain then
f9efe2
    fedora.zalias({"forgeurl", "forgesource", "forgesetupargs",
f9efe2
                      "archivename", "archiveext", "archiveurl",
f9efe2
                      "topdir", "extractdir", "repo", "owner", "namespace",
f9efe2
                      "scm", "shortcommit", "distprefix"}, verbose)
f9efe2
  end
f9efe2
  -- Final spec variable summary if the macro was called with -i
f9efe2
  if informative then
f9efe2
    rpm.expand("%{echo:Packaging variables read or set by %%forgemeta}")
f9efe2
    fedora.echovars({"forgeurl", "forgesource", "forgesetupargs",
f9efe2
                        "archivename", "archiveext", "archiveurl",
f9efe2
                        "topdir", "extractdir", "repo", "owner", "namespace",
f9efe2
                        "scm", "tag", "commit", "shortcommit", "branch", "version",
f9efe2
                        "date", "distprefix"}, suffix)
f9efe2
    fedora.echovars({"dist"},"")
f9efe2
    rpm.expand("%{echo:  (snapshot date is either manually supplied or computed once %%{_sourcedir}/%%{archivename" .. suffix .. "}.%%{archiveext" .. suffix .. "} is available)}")
f9efe2
  end
f9efe2
end
f9efe2
f9efe2
return {
f9efe2
  meta = meta,
f9efe2
}
f9efe2