Hello
I'm trying to figure out the best way to version an "adaptor" crate.
What's an adaptor crate
Best if I give the concrete example. I maintain the signal-hook. Currently, I'm getting a huge help with carving integrations into the async world into separate crates, so eventually there will be something like signal-hook-tokio
and signal-hook-async-std
and signal-hook-mio
(unfortunately, there seems to be no obvious way to create a runtime-agnostic adaptation at this point yet, but eventually in some future time maybe even signal-hook-async
). The signal-hook
would contain only the blocking primitives, like the Signals
iterator.
And all these signal-hook-*
crates is what I call adaptor crates, they connect the signal hook with something else.
The problem with versioning
The usual major.minor.patch versioning scheme is somehow linear. One can support multiple version lines in parallel (having both 1.* and 2.* supported and keep releasing both for a time, for example), but there's still some reasonable notion of what is a higher version.
But it seems the version number of the adaptor is at least 2D, possibly 3D. I'd need to bump the version in "incompatible" way under these conditions:
- There are incompatible API changes inside the adaptor.
-
signal-hook
releases an incompatible version - The adapted-to crate (eg.
tokio
) releases an incompatible version
However, I'd still like to be able to support both older and newer adapted-to crate for an extended time, possibly cross a breaking release of the base (signal-hook
) which makes the versioning all that harder.
Ideas
Take first free version number
So let's say I support tokio 0.1 and tokio 0.2. These are already released as signal-hook-tokio-0.3
and signal-hook-tokio-0.4
and I bump signal-hook
to 0.4
. Then I'd release two versions as:
-
signal-hook-tokio-0.5
(for tokio 0.1) -
signal-hook-tokio-0.6
(for tokio 0.2)
This is simple, but quite a mess for crate users to follow. It'd probably need some kind of lookup table of the right version number to use.
Complex version scheme
Don't use the major.minor.patch, but something like base_semi_major-adapted_semi_major-major.minor.patch
. So, adaptor for tokio-0.2.* for signal-hook-0.3.* would be signal-hook-tokio-0.3-0.2-0.1.3
(it would become signal-hook-tokio-0.3-1-1.0.0
once tokio releases a 1.0 version).
This expresses the semantics of the 3D versioning that it is in practice, so I kind of like this approach. Cargo seems fine accepting such version too. But I don't know what, if anything, will break if I use that ‒ cargo update
, what will happen on crates.io, etc.
Does anyone have experience or theories about this?
Separate crates
In this scheme, adaptor for tokio
is not one crate, but multiple, depending on the tokio version supported. So one would have eg. signal-hook-tokio_0_1-0.1.2
(the 0_1
is part of the name, not version).
This would work OK, though a never version would not be discovered by cargo outdated
automatically. On the other hand, it would be easy to spot and guess that the number in the name needs to be updated.
This, however, sounds inelegant and a bit dangerous. What I fear is a squatter/attacker being faster in releasing eg signal-hook-tokio_0_3
once tokio-0.3
is released and injecting some vulnerability in that. But as the user would „only“ bump the version, they would not be aware of this operation potentially changing the author of the dependency being used, skipping on proper research of the quality or security of the dependency, assuming this is just another version of the same. I could probably pre-register bunch of future versions, but that seems somewhat wrong too.
The same as above, but with number-less "leader"
The idea here is that the newest version of the adapted to crate is supported by a crate without the version in the name and only once (or maybe in addition) it becomes obsolete, it is published as the separate crate with the version-in-name as above.
This has the advantage that if one wants to keep up to date on all dependencies, the versions don't need to change. But it's still only a variation of the above with all the disadvantages.
Suggestions?
So I'm trying to reach out and asking on opinions and experiences (from both sides ‒ as a maintainer and as a user) with something like this. I'm OK if someone suggests something better than all these, or if some of the ideas are torn to shreds (which'll make choosing from the left ones easier).