conda-forge / ruamel.yaml-feedstock

A conda-smithy repository for ruamel.yaml.
BSD 3-Clause "New" or "Revised" License
1 stars 20 forks source link

Resolving "cyclic" dependency with ruamel.yaml.clib #119

Open mbargull opened 4 years ago

mbargull commented 4 years ago

I gave the awkward "circular dependency" mentioned in https://github.com/conda-forge/ruamel.yaml.clib-feedstock/pull/3#issuecomment-549126205 a look this morning.

Here is what we've got:

So, to cleanly resolve this messy situation (and assuming upstream doesn't change things in the foreseeable future), we can create yet another ruamel.yaml.* package that hosts only the Python code for ruamel.yaml (since the Python package has only an optional dependency on the C extension, as noted above). My proposal for the ruamel packages is thus:

Now, a slight issue/decision remains: We could make the current recipe have multiple outputs and create the proposed ruamel.yaml and ruamel.yaml.pylib packages from this repo. However, this would introduce a dependency cycle not in the actual package builds but between ruamel.yaml-feedstock and ruamel.yaml.clib-feedstock:

So, to avoid this "conda(-forge)-build-system-only" dependency, we'd need to not use outputs here, but

  1. Submit a new package ruamel.yaml.pylib to staged-recipes to create ruamel.yaml.pylib-feedstock.
  2. Change this repo's recipe to be noarch: generic and depend on ruamel.yaml.pylib and ruamel.yaml.clib (Even though this package will be "empty", we should retain the source: to continue getting updates via the bot and stay in-sync with the new ruamel.yaml.pylib.)
  3. Fix/update ruamel.yaml.clib's recipe to depend on ruamel.yaml.pylib.

Thoughts, @conda-forge/ruamel, @conda-forge/ruamel-yaml, @conda-forge/ruamel-yaml-clib, @jjhelmus, @mingwandroid, @msarahan?

mbargull commented 4 years ago

If we update/split the packages as outlined above, one case we have to take into account is this:

remove ruamel.yaml=NEW, leave ruamel.yaml.pylib=NEW in place, install ruamel.yaml=OLD

conda install ruamel.yaml=OLD

if conda only warns in case of clobbering, ruamel.yaml.pylib=NEW is now broken

remove ruamel.yaml.pylib=NEW, leave ruamel.yaml=OLD in place

conda remove ruamel.yaml.pylib

now ruamel.yaml=OLD is broken, too, i.e., import ruamel.yaml fails



Solutions:
1. Add a `constrains` requirements to `ruamel.yaml.pylib` for `ruamel.yaml>=NEW`:
   - This would introduce a dependency cycle in the `constrains`, which is not optimal.
     I know `conda` had issues with this at some point; not sure what the current state of this is.
   - `>=NEW` hits a limitation of `conda` if it does not indicate a version change; meaning:
     If we do not increase the version but only the build number, we are not able to express "either a new version or newer builds of the current version" with `conda`'s current capabilities.
- Add a `constrains` requirement on old `ruamel.yaml` builds:
  - metadata patching
  - can just do `constrain: ["ruamel.yaml.pylib<0a0" ]` to prevent `ruamel.yaml=OLD` and `ruame.yaml.pylib` from being simultaneously installed.

I'm generally no big fan of patching metadata. However, in this case it is the less troublesome solution and only affects `constrains` dependencies and "packages coming from the future" (from the PoV of `ruamel.yaml=OLD`) and thus should not change the consistency of current installations.
mbargull commented 4 years ago

If we do not increase the version but only the build number

We could lump the build into a "custom" conda-forge-specific version number, of course, meaning: have contrains: [ "ruamel.yaml>=0.16.5.0.post0" ] or something. This still leaves the "cycle in constrains dependencies" issue, though..