input-output-hk / foliage

🌿 Foliage is a tool to create custom Haskell package repositories, in a fully reproducible way.
MIT License
42 stars 9 forks source link

Add support for preferred-versions #8

Closed andreabedini closed 1 year ago

michaelpj commented 2 years ago

I think we could probably do this nicely with a field in the metadata file.

Also for deprecated versions.

andreabedini commented 2 years ago

preferred-versions is a package level property (of course). Perhaps we need to have a package-level metadata file? (i.e. _sources/pkg-name/meta.toml).

I think deprecated versions is implemented by marking those versions as not preferred, see https://hackage.haskell.org/packages/preferred

michaelpj commented 2 years ago

... is it? I would have thought it was the aggregation of whether each individual version was preferred/deprecated?

andreabedini commented 2 years ago

... is it? I would have thought it was the aggregation of whether each individual version was preferred/deprecated?

At least in hackage, it looks like preferred versions is a package level property. Eg see https://hackage.haskell.org/package/GPipe-GLFW/preferred/edit

That said, there is no difference between a version outside the preferred range and one that is deprecated. I think I will just support deprecating versions. It's left to understand how that enters in the index since I believe this information can change multiple times. I need to do some digging.

andreabedini commented 1 year ago

I thought about this today and I wrote down these notes.

Hackage index has a per package preferred-versions metadata file, with its own timestamp and last one wins semantic (just like a cabal file revision).

AFAIK what hackage server shows as “deprecated versions” are just versions that are un-preferred. I’d be happy if someone could investigate this a bit better (e.g. how does affect the solver really?).

The biggest work here is to figure out how to encode preferred-versions into meta.toml (note that our meta.json is per package version not per package).

Maybe as a list of timestamp and version ranges. I am leaning over making the whole preferred version range explicit rather than trying to figure out deltas between them (as it becomes hard to figure out what the current state).

Note that 1) we can reuse cabal parsers and logic to manipulate versions 2) hackage ends up “normalising” version ranges but I don’t think it’s necessary. So “not version 1” could work and be easy enough to type by hand.

andreabedini commented 1 year ago

Other thought. We could just mark versions as deprecated and/or preferred. E.g. deprecated-on: timestamp, preferred-on: timestamp; but that always only change one version at the time. Is that desiderabile? Is this going to put us in a corner?

michaelpj commented 1 year ago

I think it makes sense for the user-facing interface to be "is this version deprecated/preferred or not?". I think the fact that cabal turns it into a full-on constraint is juts more power than we need. We do need to do the timestamps, though... I guess in principle something can be deprecated and then later un-deprecated etc? So it's a bit like revisions, they can stack up.

andreabedini commented 1 year ago

I guess in principle something can be deprecated and then later un-deprecated etc?

Yes, so deprecated-on: timestamp would not work. Maybe we can repeat it?

deprecated-on: t1
undeprecated-on: t2
preferred-on: t3
undeprecated-on: t4

I am afraid this gets confusing quickly. What if you deprecate a version twice? Should that be an error? The preferred-versions file would not change so it should not reappear in the the index. Also (AFAIU) there are preferred versions which semantic is "deprecate the rest"; this means a the deprecated/preferred state of a version cannot be determined by looking at a single meta.toml.

yvan-sraka commented 1 year ago

I was thinking a bit about it, and I would vote for a prefered-version field in <package>/<version>/meta.toml file. This would be handled transitively, I mean if:

What your thoughts about it? Does it make sense, is there any case where this simple system fails to encode correctly “preferred version”? I was syncing about if the user wrote unintentionally a cycle of preferred versions …

michaelpj commented 1 year ago

I'm actually unsure we want preferred versions. Deprecating versions is something people actually want to do, preferring versions is a bit weird.

Does hackage even expose the ability to use them or are they just an implementation method for deprecated versions?

yvan-sraka commented 1 year ago

I'm actually unsure we want preferred versions. Deprecating versions is something people actually want to do, preferring versions is a bit weird.

I agree this sounds like an internal mechanism since I've not yet heard of any other package index giving this kind of front-facing option to the user… But I could rather understand it as a mechanism to customize the depreciation message like “please update to X version”, or maybe offering a soft-depreciation mechanism “please update to X version, as it will soon be depreciated”?

Does hackage even expose the ability to use them or are they just an implementation method for deprecated versions?

I should investigate … Unrelated, but could preferred-version go backward in time or semver ordering? e.g., could version 5.0.3 be preferred over 5.1.0?

To sum up, you suggest closing this issue in favor of just implementing https://github.com/andreabedini/foliage/issues/18 right?

andreabedini commented 1 year ago

Plenty of examples here https://hackage.haskell.org/packages/preferred

E.g. this is a package with both preferred and deprecated versions https://hackage.haskell.org/package/composition-prelude/preferred

I just notice that whole package deprecation (e.g. https://hackage.haskell.org/package/2captcha) does not seem to be reflected anywhere in the index (there's no 2captcha/preferred-versions in the index).

michaelpj commented 1 year ago

I... guess I just don't know what they're trying to do with preferred-versions? It's quite strong: it adds a constraint to the solver, so if you prefer version X.Y, then if you release X.(Y+1), you either need to also prefer X.(Y+1) or un-prefer X.Y otherwise X.(Y+1) will never get used. It seems hard to use well.

Unrelated, but could preferred-version go backward in time or semver ordering? e.g., could version 5.0.3 be preferred over 5.1.0?

I think it can be literally anything.

I am leaning over making the whole preferred version range explicit rather than trying to figure out deltas between them (as it becomes hard to figure out what the current state).

I am also wondering whether this would be simpler. I do think it would be nice to support what I think it is likely to be the most common use case: deprecate a single package version straightforwardly (it has a bug, was a mistaken release, or whatever).

andreabedini commented 1 year ago

I do think it would be nice to support what I think it is likely to be the most common use case: deprecate a single package version straightforwardly (it has a bug, was a mistaken release, or whatever).

I think this is a reasonable pragmatic choice: in the metadata, we only support deprecating versions and not preferring versions. Preferring some versions could still be done by manually deprecating all the other ones. As you say, this covers most of the use cases and it has minimal implementation cost bacause it is still metadata scoped to the package-version, i.e. we don't have to implement a new per-package metadata file.

If there's consensus, I proposed we close this one and move the discussion of the implementation to #18.

yvan-sraka commented 1 year ago

I think this is a reasonable pragmatic choice: in the metadata, we only support deprecating versions and not preferring versions. Preferring some versions could still be done by manually deprecating all the other ones. As you say, this covers most of the use cases and it has minimal implementation cost bacause it is still metadata scoped to the package-version, i.e. we don't have to implement a new per-package metadata file.

If there's consensus, I proposed we close this one and move the discussion of the implementation to #18.

I agree đź‘Ť