Perl-Toolchain-Gang / CPAN-Meta

Specifications for CPAN distribution META files
36 stars 40 forks source link

Please clarify conflicts documentation regards to intent #93

Open kentfredric opened 9 years ago

kentfredric commented 9 years ago

current Pod says:

conflicts

    These libraries cannot be installed when the phase is in operation. This is a very rare situation, and the conflicts relationship should be used with great caution, or not at all.

What needs to be expanded on is the nature of the conflict this represents ( esp, in comparison to x_breaks )

Its unclear here what the semantics of self->{conflict}->{foo} = $range actually mean in terms of a install tool.

Possible interpretations include

And the nature of the breakage is unclear, as is the resolution one should take to resolve it.

Should self reject being installed where Moose is present? Should Moose be removed prior to installing self?

These are questions my head gets confused with every time I think "Oh, there's a module that causes problems for me if its installed", and I can't remember if I want conflicts or x_breaks ( and the availability of both and the lack of clarity on their usage further complicates things ).

Even https://metacpan.org/pod/Dist::Zilla::Plugin::Breaks has rather unclear verbage

Add metadata about potential breakages to your distribution

  1. Is that metadata about dependencies that might cause me to become broken?
  2. Or is that metadata about dependents I might be breaking.

Because this line directly contradicts the abstract if the abstract implies [1].

but rather indicates what modules will likely not work once your distribution is installed.

This line further clarifies its cases [2]

These modules are not prerequisites -- our distribution does not use those modules, but rather those modules use us, which suggests the abstract is misleading, and that this module indicates

"I will cause foo to be broken because they use us"

But then how it is different from conflicts is unclear.

My case that is presently thwarting me is even worse than this, because I neither use the module, and the module in question does not use me ( so it is inappropriate to state a dependency ).

I do not break it either, however, it breaks me. ( That is, the breakage appears simply when I run my code, not when it runs its ).

However, due to something I use using Module::Pluggable, the thing that is a problem is effectively use'd by me.

And I have no idea what I'm supposed to do dependency wise to express this mess.

And its even less clear to anticipate from the spec what a conflicts/breaks recognizing tool should do when confronted with such a situation.

Upgrades/Downgardes/Uninstalls are all on the table for both, deferring the problem to USER doesn't solve the essential qunadry about what the recommended action is.

Prereqs are simple: X < Y = Downgrade X to be less than Y X > Y = Upgrade X to be more than Y X != Y = Upgrade or Downgrade X until it is not Y ( But still make sure X is available ).

Conflicts/Breaks are much harder, because there's the implication of uninstalls being the default option. Conflict X > Y = Downgrade X to be less than Y or uninstall it ? Conflict X < Y = Upgrade X to be more than Y or uninstall it? Conflict X != Y = Uh ... Conflict X = Y = Roll a 1D3 and pick your upgrade/downgrade/uninstall options. Conflict X < Y , > Z, != M = BDSM loving Raptors on bicycles take me now.

karenetheridge commented 9 years ago

Its [sic] unclear here what the semantics of self->{conflict}->{foo} = $range actually mean in terms of a install tool.

Possible interpretations include

foo being installed causes self to be broken
foo will be broken by installing self

conflicts is the former. x_breaks is the latter.

And the nature of the breakage is unclear, as is the resolution one should take to resolve it.

That's up to the client. It could opt to not install the distribution, claiming an unreconcilable prerequisite. Or it could possibly choose to upgrade foo to a more recent version (if there is one), or downgrade foo to a less recent version (if there is one), if doing so doesn't violate other constraints being considered simultaneously.

I would expect CPAN.pm, cpanplus and metacpan to all choose the former route - fall over and die if it encountered a conflict currently in effect. I'd expect @mstrout's vapour cdx solver to do something more akin to the latter, as it will have sufficient state information to be able to choose something intelligently.

I can't remember if I want conflicts or x_breaks ( and the availability of both and the lack of clarity on their usage further complicates things )

x_breaks vs. a regular prerq is easy: pick the one that doesn't result in a circular dependency :)

Moose is a good example because it's quite obvious which things it is dependent on, vs. dependent on it. If there is a problem between Moose and List::Util interacting, then Moose should declare a regular prereq on the fixed version(s) (perhaps expressing it in terms of != 0.123). If there is a problem between Moose and MooseX::Aliases, it should declare an x_breaks.

I don't think I've ever seen a real example of a conflict that wasn't contrived simply for the sake of exercising the toolchain. Maybe there are two alternative implementations of an algorithm, and installing one doesn't just supersede the other (as in Alt::)?

I'm making this change in Dist::Zilla::Plugin::Breaks:

-# ABSTRACT: Add metadata about potential breakages to your distribution
+# ABSTRACT: Add metadata about potential breakages caused by your distribution
karenetheridge commented 9 years ago

One other difference between conflicts and x_breaks is the behaviour it can prevent. A matching conflicts entry can block a distribution from being installed. An x_breaks entry cannot cause a distribution to fail prereq checks - it is purely data to inform possible post-release actions.

kentfredric commented 9 years ago

I guess my problem is specific because I know a resolution to a conflict that should be indicated.

That's moderately straight forward to do with Makefile.PL hacking, but I feel such behaviour to be so common ( Old X is broken, get a new one ) that it should have some syntax for it.

conflicts is inappropriate because it is not a requirement, and I would not wish it to be. x_breaks is inappropriate because I'm not breaking it, its breaking me.

And the other approach using a prereq doesn't work because:

karenetheridge commented 9 years ago

My case that is presently thwarting me is even worse than this, because I neither use the module, and the module in question does not use me ( so it is inappropriate to state a dependency ).

I do not break it either, however, it breaks me. ( That is, the breakage appears simply when I run my code, not when it runs its ).

However, due to something I use using Module::Pluggable, the thing that is a problem is effectively use'd by me.

And I have no idea what I'm supposed to do dependency wise to express this mess.

This sounds like a case for [DynamicPrereqs] :) -- in pseudocode, you'd want to say in Makefile.PL:

- if Module::Pluggable is installed,
- and it is in the version range that is problematic,
- then add an extra prerequisite on a version that will get us out of a bad combination.

I do this in several distributions, e.g. this one in Test::LWP::UserAgent for a bug that has absolutely nothing to do with me, but still gives me test failures:

[DynamicPrereqs]
-raw = |# see RT#103423
-raw = |$WriteMakefileArgs{PREREQ_PM}{'IO::Socket::IP'} = $FallbackPrereqs{'IO::Socket::IP'} = '0.31'
-raw = |  if eval { require IO::Socket::SSL; 1 } or eval { require IO::Socket::INET6; 1 };

It's not a case for x_breaks, because it's not the other thing that becomes broken by you -- it's you that is broken by the other thing.