#1097 Use caret in Obsoletes to simplify renaming and replacing of packages
Opened 8 months ago by zbyszek. Modified 7 months ago
zbyszek/packaging-committee simplify-obsoletes  into  master

@@ -1697,7 +1697,7 @@ 

  There are specific guidelines for handling tmpfiles.d configurations and directories (in /run and /run/lock): xref:Tmpfiles.d.adoc[Tmpfiles.d].

  

  [#renaming-or-replacing-existing-packages]

- == Renaming/Replacing Existing Packages

+ == Renaming/Replacing or Removing Existing Packages

  

  NOTE: FESCo has a https://fedoraproject.org/wiki/Package_Renaming_Process#Re-review_required[package renaming policy] that should be followed when renaming an existing package.

  
@@ -1710,24 +1710,42 @@ 

  Obsoletes: oldpackagename < $obsEVR

  ....

  

- $provEVR refers to an (Epoch-)Version-Release tuple the original unchanged package would have had if it had been version or release bumped. You usually use macros here because the provides EVR should continue to go up as the renamed package advances in version and release. $obsEVR is an (Epoch-)Version-Release tuple arranged so that there is a clean upgrade path but without gratuitously polluting the version space upwards. You usually do not use macros for this as you're simply trying to advance beyond the last known release under the old name.

+ `+$provEVR+` uses the version of the providing package (and continues to go up over time).

+ Usually it is just `+%{version}-%{release}+`.

+ You usually use macros here because the version and release should continue to go up as the renamed package advances.

  

- If a package supersedes/replaces an existing package without being a sufficiently compatible replacement as defined above, use only the `+Obsoletes:+` line from the above example.

+ `+$obsEVR+` is an (Epoch-)Version-Release arranged so that there is a clean upgrade path but without gratuitously polluting the version space upwards.

+ You usually do not use macros for this as you're simply trying to advance beyond the last known release under the old name.

+ When deciding what $obsEVR should be, remember that it needs to be higher than the previous `Release` with `+%{?dist}+` expanded.

  

- CAUTION: *Take `+%{?dist}+` into account*: When deciding what $obsEVR should be, remember that it needs to be higher than the previous `Release:` with `+%{?dist}+` expanded. Example: if the package previously had `+Release: 4%{?dist}+` the release in $obsEVR should be at least 5.

+ Example: if the package previously had `+Release: 4%{?dist}+` the release in `$obsEVR` should be at least 5.

  

- If retired packages need to be removed from end user machines because they cause dependency issues which interfere with upgrades or are otherwise harmful, a packager MAY request that `+Obsoletes:+` be added to `+fedora-obsolete-packages+`. Simply file a bugzilla ticket https://bugzilla.redhat.com/enter_bug.cgi?product=Fedora&version=rawhide&component=fedora-obsolete-packages[here]. Please include information on which packages need to be obsoleted, the exact versions which need to be obsoleted, and the reasons why they cannot be allowed to remain installed.

+ A simplified form of `+$obsEVR+` may be used when it is expected that the unretired package will have a higher version.

+ (The typical case is when the last built version is already behind upstream at the time when the Obsoletes is added,

+ so it clear that even it package is brought back, it will be with a higher version.)

+ In this case, the release marker is replaced by `+^+`.

  

- If the obsoleted package had an Epoch set, it must be preserved in both the `+Provides:+` and `+Obsoletes:+`. For example, assume foo being renamed to bar, bar is compatible with foo, and the last foo package release being foo-1.0-3%\{?dist} with Epoch: 2. The following should be added to bar (and similarly for all subpackages as applicable):

+ If a package supersedes/replaces an existing package without being a sufficiently compatible replacement as defined above, use only the `+Obsoletes:+` line.

+ 

+ If the obsoleted package had an Epoch set, it must be preserved in both the `+Provides:+` and `+Obsoletes:+`. For example, assume `foo` being renamed to `bar`, `bar` is compatible with `foo`, and the last `foo` package release being `+foo-2:1.0-3.fc25+` (the epoch is "2"). The following should be added to `bar` (and similarly for all subpackages as applicable):

  

  ....

  Provides: foo = 2:%{version}-%{release}

- Obsoletes: foo <= 2:1.0-4   # Important: We set the Obsoletes release to 4 to be higher than the previous Release: 3%{?dist}

+ Obsoletes: foo < 2:1.0-4   # Important: We set the Obsoletes release to 4 to be higher than the previous Release: 3%{?dist}

+ ....

+ 

+ In the simplified form of `+$obsEVR+` this would become

  ....

+ Provides: foo = 2:%{version}-%{release}

+ Obsoletes: foo < 2:1.0^    # This obsoletes versions like 2:0.9-1.fc35 or 2:1.0-35.eln100, but not 2:1.0.0-1.fc35 or 2:1.0.1-1.fc35.

+ ....

+ 

+ 

+ Explicit `+Provides:+` need to be aware of whether the package is supplying things that can be used in an arch-independent or arch-specific fashion. For packages that are not noarch, `+Provides:+` should be made arch-specific by applying the `+%{?_isa}+` macro to the end of the string in Provides (e.g. `+Provides: foo%{?_isa} = 2:%{version}-%{release}+`). Packages that explicitly provide things that can be used in an arch-independent way (for example, those whose dependents don't need to be of the same arch—need not apply this macro. In some cases, a package will supply multiple elements, some of which may be consumed only by dependents of an identical arch and some which may be consumed by dependents of any arch. In such cases, both arch-specific and arch-independent `+Provides:+` are warranted.

  

- Explicit `+Provides:+` need to be aware of whether the package is supplying things that can be used in an arch-independent or arch-specific fashion. For packages that are not noarch, `+Provides:+` should be made arch-specific by applying the `+%{?_isa}+` macro to the end of the text string in Provides (e.g. `+Provides: foo%{?_isa} = 2:%{version}-%{release}+`). Packages that explicitly provide things that can be used in an arch-independent way (for example, those whose dependents don't need to be of the same arch—need not apply this macro. In some cases, a package will supply multiple elements, some of which may be consumed only by dependents of an identical arch and some which may be consumed by dependents of any arch. In such cases, both arch-specific and arch-independent Provides: are warranted.

+ Examples of packages that should explicitly provide only arch-specific `+Provides:+` include native code libraries or plug-ins and their associated -devel packages. Packages that should explicitly provide only arch-independent `+Provides:+` include most standalone programs (in addition to all noarch packages). Even though these programs may themselves be arch-specific, clients that run them should not care about their arch. A package that explicitly provides, for example, both a native code library as well as an interpreted language interface to that library should have both arch-specific (for clients of the native code library) and arch-independent (for clients of the interpreted language interface) `+Provides:+`.

  

- Examples of packages that should explicitly provide only arch-specific `+Provides:+` include native code libraries or plug-ins and their associated -devel packages. Packages that should explicitly provide only arch-independent `+Provides:+` include most stand-alone programs (in addition to all noarch packages). Even though these programs may themselves be arch-specific, clients that run them should not care about their arch in most cases. A package that explicitly provides, for example, both a native code library as well as an interpreted language interface to that library should have both arch-specific (for clients of the native code library) and arch-independent (for clients of the interpreted language interface) Provides:.

+ If retired packages need to be removed from end user machines because they cause dependency issues which interfere with upgrades or are otherwise harmful, a packager SHOULD request that `+Obsoletes:+` be added to `+fedora-obsolete-packages+`. Simply file a bugzilla ticket https://bugzilla.redhat.com/enter_bug.cgi?product=Fedora&version=rawhide&component=fedora-obsolete-packages[here]. Please include information which packages need to be obsoleted, the versions which need to be obsoleted, and the reasons why they cannot be allowed to remain installed.

  

  If there is no standard naming for a package or other long term naming compatibility requirements involved with the rename, the Provides should be assumed to be deprecated and short lived and removed in the distro release after the next one (i.e., if introduced in FC-X, keep in all subsequent package revisions for distros FC-X and FC-(X+1), drop in FC-(X+2)), and the distro version where it is planned to be dropped documented in a comment in the specfile. Maintainers of affected packages should be notified and encouraged to switch to use the new name. Forward compatibility Provides: in older distro branches can be considered in order to make it possible for package maintainers to keep same simple specfiles between branches but still switch to the newer name.

  

Let's make things easier for packagers.

(Why is pagure showing commits in reverse order??)

rebased onto e5e28670e7ab801e8847f91db2d0fc037a2fd41a

8 months ago

I am not sure I understand this mechanism.

Let's say we remove foo from Fedora and the last version we had was 1.0-5. If we obsolete < 1.0^, there is no way to reintroduce foo version 1.0 without bumping the epoch. And since obsoletes that are present at GA time remain active for the entire lifetime of the Fedora release, there is no way to remove it.

Just specify the version as 1.0^. (Or 1.0^0 or 1.0^unretired or 1.0^back_in_business or whatever strikes your fancy).

Yes, this is a bit ugly, but I think this should be pretty rare case. We don't obsolete packages by default, and only when they start to cause upgrade problems. So usually enough time passes for the package to have another upstream release in the mean time. I think the advantage of simplicity outweighs the ugliness of handling the exact same version unretirement. (Getting the release wrong in Obsoletes is a fairly frequent bug which should be eliminated by this change.)

So usually enough time passes for the package to have another upstream release in the mean time.

I don't agree with this claim. It might be that way for some packages, but not for others.

-1. I don't want to lose the ability to unretire a package at the same upstream version with a higher release. The established way to do this is more elegant and self explanatory than creating fake ugly versions. In the words of one of the sentences this change would remove, we shouldn't "gratuitously pollut[e] the version space upwards".

If we want to give packagers some room for error on this, we could relax the language to allow a reasonable increase, such as Obsoletes: foo < 2:1.0-100. If unretired the package could bump to release 101 without changing the upstream version.

This merits more discussion; tagging as meeting.

I agree with the premise. It's annoying to have to keep updating obsoletes when an older branch gets updated. Either requiring a caret for unretiring[^1] or leaving some "slack" in the retired release would work.

Honestly neither is particularly palatable. I don't know which is worse. Would you prefer mustard or mayo on your lutefisk sandwich?

[^1]: Today I learned that word is actually in the dictionary. I was going to use "resurrection".

Edit: awww, no markdown footnotes on Pagure.

Metadata Update from @tibbs:
- Pull-request tagged with: meeting

8 months ago

rebased onto d5acff5

7 months ago

OK, I did some investigation using git-seed-latest.tar.xz, and it turns out we unretire packages in the same version quite often. (In fact, the typical pattern seems to be: the package is rebuilt without any changes accumulating a release number like -25, then it's retired because it doesn't build, it is unretired and sometimes not even fixed, goes up to maybe -35, and is retired again.)

I adjusted the PR to suggest $obsVER with ^ as an option. If you think this is still too much / too-narrow of a use case, I'll drop this from the PR.