(Simplify structure) |
|||
Line 31: | Line 31: | ||
* '''dist:''' auto-adjusted when packaging a tag or commit | * '''dist:''' auto-adjusted when packaging a tag or commit | ||
C. (Optionnal) The packager calls the '''%forgemetacheck''' macro to display the values of computed variables | C. (Optionnal) The packager calls the '''%forgemetacheck''' macro to display the values of computed variables. ''%forgemetacheck'' emits rpm warnings. It should be safe to call from any point of the spec file. | ||
{{Admon/note | On variable resolution | | |||
'''forgemetacheck''' resolves the values of rpm variables at one point of the spec file. Since most of those variables are themselves composed of other variables, it is possible for those values to change if one of the variables used in the composition is overridden by the packager after the '''forgemetacheck''' call. | |||
}} | |||
D. The packager uses the computed metadata as needed. | D. The packager uses the computed metadata as needed. | ||
Line 38: | Line 42: | ||
=== Packaging a release (except for GitLab) === | === Packaging a release (except for GitLab) === | ||
%global forgeurl https://github.com/ | %global forgeurl https://github.com/alecthomas/kingpin/ | ||
Version: | Version: 2.2.5 | ||
%forgemeta | %forgemeta | ||
%forgemetacheck '''(optionnal)''' | |||
… | |||
Release: 1%{?dist} | Release: 1%{?dist} | ||
… | … | ||
Line 51: | Line 56: | ||
%prep | %prep | ||
%setup %{?setupargs} | %setup %{?setupargs} | ||
%forgemetacheck output: | |||
Forge-specific packaging variables | |||
forgeurl: “https://github.com/alecthomas/kingpin” | |||
forgesource: “https://github.com/alecthomas/kingpin/archive/v2.2.5.tar.gz#/kingpin-2.2.5.tar.gz” | |||
shortcommit: “” | |||
Generic variables | |||
setupargs: “-n kingpin-2.2.5” | |||
archivename: “kingpin-2.2.5” | |||
archiveext: “tar.gz” | |||
archiveurl: “https://github.com/alecthomas/kingpin/archive/v2.2.5.tar.gz” | |||
scm: “” | |||
tag: “” | |||
commit: “” | |||
dist: “.fc28” (snapshot date is computed once the corresponding source file is available) | |||
=== Packaging a release (GitLab) === | === Packaging a release (GitLab) === | ||
Line 65: | Line 86: | ||
%forgemeta | %forgemeta | ||
… | |||
Release: 1%{?dist} | Release: 1%{?dist} | ||
… | … | ||
Line 75: | Line 96: | ||
=== Packaging a release tag=== | === Packaging a release tag=== | ||
%global forgeurl https://github.com/ | %global forgeurl https://github.com/apache/thrift/ | ||
Version: 0.10.0 | Version: 0.10.0 | ||
%global tag %{version} | %global tag %{version} | ||
%forgemeta | %forgemeta | ||
%forgemetacheck '''(optionnal)''' | |||
… | |||
Release: 1%{?dist} | Release: 1%{?dist} | ||
… | … | ||
Line 90: | Line 112: | ||
%setup %{?setupargs} | %setup %{?setupargs} | ||
%forgemetacheck output: | |||
Forge-specific packaging variables | Forge-specific packaging variables | ||
forgeurl: “https://github.com/apache/thrift” | forgeurl: “https://github.com/apache/thrift” | ||
Line 181: | Line 129: | ||
=== Packaging a commit === | === Packaging a commit === | ||
%global forgeurl https://code.googlesource.com/google-api-go-client/ | %global forgeurl https://code.googlesource.com/google-api-go-client/ | ||
%global commit 3a1d936b7575b82197a1fea0632218dd07b1e65c | %global commit 3a1d936b7575b82197a1fea0632218dd07b1e65c | ||
%forgemeta | %forgemeta | ||
%forgemetacheck | %forgemetacheck '''(optionnal)''' | ||
… | |||
Version: 0 | |||
Release: 0.1%{?dist} | |||
… | |||
URL: %{forgeurl} | |||
Source: %{forgesource} | |||
… | |||
%prep | |||
%setup %{?setupargs} | |||
''' | |||
%forgemetacheck output: | |||
Forge-specific packaging variables | Forge-specific packaging variables | ||
Line 201: | Line 160: | ||
commit: “3a1d936b7575b82197a1fea0632218dd07b1e65c” | commit: “3a1d936b7575b82197a1fea0632218dd07b1e65c” | ||
dist: “.git3a1d936.fc28” (snapshot date is computed once the corresponding source file is available) | dist: “.git3a1d936.fc28” (snapshot date is computed once the corresponding source file is available) | ||
=== Packaging a pre-release commit === | |||
{{Admon/note | On Version declaration order | | |||
It is generally safe to declare ''Version'' before calling ''%forgemeta'' even for pre or post-releases. '''Except for GitLab'''. Due to GitLab's use of ''commit'' for release downloads, you MUST declare ''Version'' after calling ''%forgemeta'' when the packaged ''commit'' does not match the 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 %{?setupargs} | |||
Post-release packaging is similar. See also [[Packaging:Versioning#Release_and_post-release_versions]]. | |||
==Extending the macro== | ==Extending the macro== |
Revision as of 10:14, 10 December 2017
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 software hosting service
- 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
- scm: the source code management engine used by the software hosting service, if packaging a tag or a commit, and if the service allows different engines.
B. The packager calls the %forgemeta macro to compute rpm-oriented metadata:
- forgesource: the corresponding source file URL, that can be used as Source:
- shortcommit: a commit hash reduction
- setupargs: the arguments that %setup will need
- archivename: the corresponding archive name (often used by setupargs)
- archiveext: the corresponding archive extension
- archiveurl: the archive URL, without renaming
- dist: auto-adjusted when packaging a tag or commit
C. (Optionnal) The packager calls the %forgemetacheck macro to display the values of computed variables. %forgemetacheck emits rpm warnings. It should be safe to call from any point of the spec file.
D. The packager uses the computed metadata as needed.
Packaging examples
Packaging a release (except for GitLab)
%global forgeurl https://github.com/alecthomas/kingpin/ Version: 2.2.5 %forgemeta %forgemetacheck (optionnal) … Release: 1%{?dist} … URL: %{forgeurl} Source: %{forgesource} … %prep %setup %{?setupargs}
%forgemetacheck output:
Forge-specific packaging variables forgeurl: “https://github.com/alecthomas/kingpin” forgesource: “https://github.com/alecthomas/kingpin/archive/v2.2.5.tar.gz#/kingpin-2.2.5.tar.gz” shortcommit: “” Generic variables setupargs: “-n kingpin-2.2.5” archivename: “kingpin-2.2.5” archiveext: “tar.gz” archiveurl: “https://github.com/alecthomas/kingpin/archive/v2.2.5.tar.gz” scm: “” tag: “” commit: “” dist: “.fc28” (snapshot date is computed once the corresponding source file is available)
Packaging a release (GitLab)
%global forgeurl https://gitlab.example.com/foo/bar %global commit 2a810629566a2d0f0d4107df244e8828b9f7bd5c Version: 8.18.1 %forgemeta … Release: 1%{?dist} … URL: %{forgeurl} Source: %{forgesource} … %prep %setup %{?setupargs}
Packaging a release tag
%global forgeurl https://github.com/apache/thrift/ Version: 0.10.0 %global tag %{version} %forgemeta %forgemetacheck (optionnal) … Release: 1%{?dist} … URL: %{forgeurl} Source: %{forgesource} … %prep %setup %{?setupargs}
%forgemetacheck output:
Forge-specific packaging variables forgeurl: “https://github.com/apache/thrift” forgesource: “https://github.com/apache/thrift/archive/0.10.0.tar.gz#/thrift-0.10.0.tar.gz” shortcommit: “” Generic variables setupargs: “-n thrift-0.10.0” archivename: “thrift-0.10.0” archiveext: “tar.gz” archiveurl: “https://github.com/apache/thrift/archive/0.10.0.tar.gz” scm: “git” tag: “0.10.0” commit: “” dist: “.fc28” (snapshot date is computed once the corresponding source file is available)
Packaging a commit
%global forgeurl https://code.googlesource.com/google-api-go-client/ %global commit 3a1d936b7575b82197a1fea0632218dd07b1e65c %forgemeta %forgemetacheck (optionnal) … Version: 0 Release: 0.1%{?dist} … URL: %{forgeurl} Source: %{forgesource} … %prep %setup %{?setupargs}
%forgemetacheck output:
Forge-specific packaging variables forgeurl: “https://code.googlesource.com/google-api-go-client” forgesource: “https://code.googlesource.com/google-api-go-client/+archive/3a1d936b7575b82197a1fea0632218dd07b1e65c.tar.gz#/google-api-go-client-3a1d936b7575b82197a1fea0632218dd07b1e65c.tar.gz” shortcommit: “” Generic variables setupargs: “-c” archivename: “google-api-go-client-3a1d936b7575b82197a1fea0632218dd07b1e65c” archiveext: “tar.gz” archiveurl: “https://code.googlesource.com/google-api-go-client/+archive/3a1d936b7575b82197a1fea0632218dd07b1e65c.tar.gz” scm: “git” tag: “” commit: “3a1d936b7575b82197a1fea0632218dd07b1e65c” dist: “.git3a1d936.fc28” (snapshot date is computed once the corresponding source file is available)
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 %{?setupargs}
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 == "vvv") then … end
or
if (string.match(forge, "vvv")) then … end
- change the "vvv" value
- adapt the initial normalization rule
forgeurl = string.match(forgeurl, "www")
- adapt the initial error message
error("xxx URLs must match “yyy”!")
- set the hosting service defaults
if (archiveext == "") then rpm.define("archiveext tar.xz") end if (setupargs == "") then rpm.define("setupargs -n %{archivename}") end if (commit ~= "") or (tag ~= "") then rpm.define("scm git") end
- scrap the variables you need from forgeurl using:
local myvariable = string.match(forgeurl, "zzz")
- use your variables to define archivename and archiveurl in the following if tag/commit/version block
- install the result in /usr/lib/rpm/macros.d/macros.forge-srpm
- 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.”.