Projects published on a “forge” can be packaged using the forgemeta macro.
Links :
- FPC ticket
- fedora-rpm-macros RFE with the macro file
- packaging@lists.fedoraproject.org discussion
- pagure.io RFE to make pagure.io compatible with forgemeta
- GitLab CE RFE to remove GitLab quirks
- rpm RFE to get rid of the remaining %setup special cases
Usage
A. The packager declares upstream-dependent metadata :
- forgeurl: the project URL on the target forge
- version: the project release 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:
- setupargs: the arguments that %setup will need
- archiveurl: the archive URL, without renaming
- archivename: the corresponding archive name (often used by setupargs)
- 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 macro to display the values of computed variables D. The packager uses the computed metadata as needed.
Packaging examples
Packaging a release (except for GitLab)
%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 release (GitLab)
%global forgeurl https://gitlab.example.com/foo/bar %global commit 2a810629566a2d0f0d4107df244e8828b9f7bd5c 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 release accessed through 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-release commit
%global forgeurl https://gitlab.example.com/foo/bar/ %global commit 51637bc0960002b811e1c0c7be8671cf9a1cc5be %forgemeta Name: foobar Version: 3.2.6 Release: 0.1%{?dist} … URL: %{forgeurl} Source: %{forgesource} … %prep %setup -n %{archivename}
Post-release packaging is similar. See also Packaging:Versioning#Release_and_post-release_versions.
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/macros.forge-srpm 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/
- test with forgemetacheck and rpmbuild -bs myspecfile.spec
- submit the enhancement for inclusion in fedora-rpm-macros once it works satisfactorily.
Benefits and limitations
- Benefits:
- Fedora packagers no longer need to know about the URL structure of well-known forges.
- Spec files are simpler, less error-prone, easier to maintain and audit.
- Forge URLs can be defined and fixed in a single place, without waiting for guidelines to percolate.
- The macros are mostly written in Lua, making them more verbose but easier to adjust and extend.
- The macros are written in Lua and can perform error handling.
- It is very easy to switch from commit to tag to version (or any combination of those).
- spectool just works© (in Fedora).
- scm snapshot date is exact and does not rely on a variable which may or may not have been updated.
- Almost all the computations are done in optional rpm variables that can be ignored by the packager if he does not need or does not like the result.
- Fedora forge know-how can be capitalized over time.
- The macro normalizes common spec constructs such as archivename.
- Limitations:
- 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?).
- The macro needs to be updated when a forge changes its structure (but better changing one place than lots of spec files).
- New forges need to be added to the macro before it can be used with them.
- 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.
- dist commit date computation relies on source files with the correct modification time (incorrect source file modification time → incorrect dist date).
- spectool may not work in older Fedora derivatives (but just use forgemetacheck and copy the source URL form its output).
- 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. The file name must be prefixed with “macros.”.