gap-system / gap

Main development repository for GAP - Groups, Algorithms, Programming, a System for Computational Discrete Algebra
https://www.gap-system.org
GNU General Public License v2.0
800 stars 163 forks source link

Dealing with Old Versions of Packages that are Broken by Releases; add "Conflicts" field to PackageInfo.g? #2077

Open stevelinton opened 6 years ago

stevelinton commented 6 years ago

In #2061, we just came across a situation we've dealt with before but not very systematically. Essentially:

  1. A package P relies (perhaps accidentally) on undocumented (or even erroneous) behaviour of existing code in the kernel or library (or in another package Q, I suppose). For brevity, I'll write this on the assumption is was the library.

  2. A change to the library changes that undocumented behaviour

  3. Perhaps after discussion, a new version of P is released, fixing the problem [sometimes it may be better to document the original behaviour and revert to it, but that is not the case I'm concerned with here]

So far, so good, but now old versions of P will not work correctly with the new library and we don't really have a good way of indicating that (unless I've missed it). We can say that the new library requires or suggests the new version of P, but we may not want to require or suggest P at all. What we want instead is for the library to be able to forbid versions of P before some landmark (perhaps with some way to override it).

This would be easy enough to do -- yet another field in GAPInfo and PackageInfo and tests in LoadPackage.

hulpke commented 6 years ago

I think this is a very good idea, but the package load mechanism then should issue an explicit error message about the need for a new package.

fingolfin commented 6 years ago

A generic way for this would be to add a Conflicts field -- this can either state that a package is completely incompatible with another ; or it can be used to say it is incompaibtle with certain versions of the package (i.e. <= 1.5, but perhaps also >= 2.0? Hmm, I guess <1.5 is more useful than <= 1.5, because usually I have a certain version which is the first known to be OK, and I want to express "every version before that" without having to worry whether the version before 1.5 was 1.4 or 1.4.1 or 1.4.27...

And once we have that, we can also edit the Dependencies record in lib/system.g to express that this GAP version is incompatible with certain packages resp. package versions.

Handling with the conflicts field has to happen in two ways now, though, when loading the package:

  1. First, we must check the Conflicts of all already loaded packages; if the package to be loaded conflicts, we refuse with a suitable error message (e.g. "Cannot load package foo 1.5, because package bar 2.1 which is already loaded conflicts with foo version < 1.7.3")
  2. Secondly, we must check the Conflicts of the package being loaded, and refuse loading it if a package it conflicts with has already been loaded.

One note: If the number of packages grows a lot, and lots of packages start using Conflicts fields, then resolving these can become quite complex (other package managers employ SAT solvers for dependency resolution). But I am not worried about that, because if we ever grow that big, we'll need a proper package manager anyway, and can take care of it then.