From Fedora Project Wiki

No edit summary
(Document how to extend the macro)
Line 93: Line 93:
  %prep
  %prep
  %setup -n %{archivename}
  %setup -n %{archivename}
==Extending the macro==
If the project you're packaging is published on a software publishing service '''forgemeta''' has no knowledge of, don't be sad, that's pretty easy to fix.
* note down the archive URLs you want to generate for versions, tags and commits.
* locate the latest version of the '''forgemeta''' macro (it should be installed in  ''/usr/lib/rpm/macros.d/''  by '''fedora-rpm-macros'''),
* copy the definition block closest to your needs after the other definition blocks. It should look like :
  if (forge == "'''xxx'''") then
  …
  end
* change the '''"xxx"''' value
* adapt the initial Lua [http://lua-users.org/wiki/PatternsTutorial pattern] test to guard against URLs you don't know how to handle:
  if not ( string.match(forgeurl, "''''yyy'''") ) then
      error("'''xxx''' urls must match “'''zzz'''”!")
  end
* scrap the variables you need from '''forgeurl''' using:
  local '''myvariable''' = string.match(forgeurl, "'''abc'''")
* use them to define '''archivename''' and '''archiveurl''' in the following if ''tag''/''commit''/''version'' block
* install the result in ''/usr/lib/rpm/macros.d/''
* check it with ''forgemetacheck''' and ''rpmbuild -bs myspecfile.spec''
* submit it for inclusion in [https://bugzilla.redhat.com/enter_bug.cgi?product=Fedora&component=fedora-rpm-macros fedora-rpm-macros] once its works satisfactorily.
{{Admon/note | Don't be afraid of Lua patterns! |
While the Lua [http://lua-users.org/wiki/PatternsTutorial pattern] syntax is a bit unusual, it is quite simple. If the existing macro does not already contain something similar to what you want to accomplish you can use the '''lua''' command to launch an interactive interpreter to experiment in.
}}


==Benefits and limitations==
==Benefits and limitations==

Revision as of 21:16, 8 December 2017

Projects published on a forge can be packaged using the forgemeta macro.

Note.png
What is a “forge” for the “forgemeta” macro?
Any software publishing website, permitting the download of source code archives on normalized URLs, that can be deduced from a project root URL on the website plus version/commit/tag/scm/extension values, is a forge.

Links :

Usage

A. The packager declares upstream-dependent metadata :

  • forgeurl: the project URL on the target forge
  • version: the project version to package, if non nil (as Version: xxx)
  • commit: the commit hash to package, if any
  • tag: the project tag to package, if any

B. The packager calls the forgemeta macro to compute rpm-oriented metadata:

  • forgesource: the corresponding source file URL, that can be used as Source:
  • archiveurl: the archive URL, without renaming
  • archivename: the corresponding archive name (often used as %setup -n argument)
  • archiveext: the corresponding archive extension
  • shortcommit: a commit hash reduction
  • dist: auto-adjusted when packaging a tag or commit

C. (Optionnal) The packager calls the forgemetacheck to display the values of computed variables (except for dist which is not computed before release)

D. The packager uses the computed metadata as needed.

Packaging examples

Packaging a full version

%global forgeurl    https://github.com/foo/bar/
Version:            8.18.1
 
%forgemeta

Name:    foobar
Release: 1%{?dist}
…
URL:    %{forgeurl}
Source: %{forgesource}
…
%prep
%setup -n %{archivename}

Packaging a specific commit

%global forgeurl    https://code.googlesource.com/foobar/
%global commit      2a810629566a2d0f0d4107df244e8828b9f7bd5c

%forgemeta

Name:    foobar
Version: 0
Release: 0.1%{?dist}
…
URL:    %{forgeurl}
Source: %{forgesource}
…
%prep
%setup -c

Packaging a version that masquerades as a tag

%global forgeurl    https://github.com/foo/bar/
Version:            0.10.0
%global tag         %{version}
 
%forgemeta

Name:    foobar
Release: 1%{?dist}
…
URL:    %{forgeurl}
Source: %{forgesource}
…
%prep
%setup -n %{archivename}

Packaging a pre-version commit

%global forgeurl    https://github.com/foo/bar/
%global commit      2a810629566a2d0f0d4107df244e8828b9f7bd5c
Version:            3.2.1
 
%forgemeta

Name:    foobar
Release: 0.1%{?dist}
…
URL:    %{forgeurl}
Source: %{forgesource}
…
%prep
%setup -n %{archivename}

Extending the macro

If the project you're packaging is published on a software publishing service forgemeta has no knowledge of, don't be sad, that's pretty easy to fix.

  • note down the archive URLs you want to generate for versions, tags and commits.
  • locate the latest version of the forgemeta macro (it should be installed in /usr/lib/rpm/macros.d/ by fedora-rpm-macros),
  • copy the definition block closest to your needs after the other definition blocks. It should look like :
 if (forge == "xxx") then
 …
 end
  • change the "xxx" value
  • adapt the initial Lua pattern test to guard against URLs you don't know how to handle:
  if not ( string.match(forgeurl, "'yyy") ) then
     error("xxx urls must match “zzz”!")
  end
  • scrap the variables you need from forgeurl using:
  local myvariable = string.match(forgeurl, "abc")
  • use them to define archivename and archiveurl in the following if tag/commit/version block
  • install the result in /usr/lib/rpm/macros.d/
  • check it with forgemetacheck' and rpmbuild -bs myspecfile.spec
  • submit it for inclusion in fedora-rpm-macros once its works satisfactorily.
Note.png
Don't be afraid of Lua patterns!
While the Lua pattern syntax is a bit unusual, it is quite simple. If the existing macro does not already contain something similar to what you want to accomplish you can use the lua command to launch an interactive interpreter to experiment in.

Benefits and limitations

  • Benefits:
  1. Fedora packagers no longer need to know about the URL structure of well-known forges.
  2. Spec files are simpler, less error-prone, easier to maintain and audit.
  3. Forge URLs can be defined and fixed in a single place, without waiting for guidelines to percolate.
  4. The macros are mostly written in Lua, making them more verbose but easier to adjust and extend.
  5. The macros are written in Lua and can perform error handling.
  6. It is very easy to switch from commit to tag to version (or any combination of those).
  7. spectool just works© (in Fedora).
  8. scm snapshot date is exact and does not rely on a variable which may or may not have been updated.
  9. Almost all the computations are done in optional rpm variables that can be ignored by the packager if he does not need/does not like the result.
  10. Fedora forge know-how can be capitalized over time.
  11. The macro normalizes common spec constructs such as archivename.
  • Limitations:
  1. The macro is not intended to be used in spec files that package multiple forge archives (it could probably be extended, is the added flexibility worth the complexity?).
  2. The macro needs to be updated when a forge changes its structure (but better changing one place than lots of spec files).
  3. New forges need to be added to the macro before it can be used with them.
  4. dist munging can not be easily reverted once forgemeta has been called. The alternative would be to 1. change fedora-release to define dist as %{?snapid}%{?distroid} and set distroid to the value dist is set today, and 2. let other macros such as forgemeta define snapid later. Cleaner but a lot more invasive and more difficult to propagate downstream.
  5. dist commit date computation relies on source files with the correct modification time (incorrect source file modification time → incorrect dist date).
  6. spectool may not work in older Fedora derivatives (but just use forgemetacheck and copy the source URL form its output).
  7. The macro highlights some historical rpm design mistakes: bad separation of upstream and package metadata, special magic variables. This is why version declaration occurs in an unusual (for rpm) order and requires a specific syntax.

Testing

Just drop in /usr/lib/rpm/macros.d/ the file proposed here for inclusion in fedora-rpm-macros, and play with the result.