-
Notifications
You must be signed in to change notification settings - Fork 40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SPEC: create standard key for communicating dynamic dependencies to vendors/packagers #112
Comments
If it's meant to be only human-readable, and not machine-readable, then couldn't comments in Makefile.PL serve the same purpose? That is -- authors should already be properly annotating their dynamic prereqs. |
Comments in Makefile.PL don't only serve this purpose -- there may be many unrelated comments. This proposal makes it easy to find and to write tools that can display it. Whether there needs to be a lot of structure for a given module or just a single comment field is a bikeshed matter that can be settled later. |
This sounds like a good idea, but it may be helpful to be slightly more machine-readable (even if we don't strictly guarantee it) |
I approve the idea of this feature. But concerning the design, I think it would be worth trying to keep the structures similar to other existing structures in the spec:
So here is an alternate proposal: dynamic_prereqs => {
"Win32 only" => {
condition => "required on Win32",
prereqs => {
runtime => { requires => { "Win32::Foo::Bar" => "1.23" } },
},
},
"Faster with Wibble::XS" => {
condition => "needs a compiler",
prereqs => {
runtime => { requires => { "Wibble::XS" => "0" } },
},
},
"perls before 5.14, avoid RT#666" => {
condition => "perl before 5.14",
prereqs => {
runtime => { requires => { "Devel::ReallyAnnoying" => "0.17" } },
},
},
"Prettier output, optional" => {
condition => "used at runtime if available",
prereqs => {
# Notice I've changed the requirement type to 'recommends'
runtime => { recommends => { "Data::ReallyOptional::Foo" => "0" } },
},
}, |
Should probably define how these "imagined to be handled" in the development lifecycle. For instance, "optional_features" is otherwise the same as this, but there's the question of "when does tooling handle this, before, or after ./configure?" "Can configure change this and emit the result in MYMETA.*?" etc. Given all the examples are /runtime requires/ this suggests the latter is happening. So theoretical examples with configure_requires might be nice. |
@xsawyerx had the example that an admin wants to know before running .PL and wants something more direct than having to read/grok a possibly poorly documented *.PL file. (Often for custom non-toolchain packaging e.g. chef/RPMs etc.) He should explain this idea further, I think, as I just wrote it up so it wouldn't get lost. |
It is sub-optimal (for the lack of a better term) to require to run code in order to know which modules will be required. Let's take MetaCPAN for example: MetaCPAN would like to list all the requirements. Modules have a way to list requirements. Unfortunately, modules need to account for some dynamically-decided requirements (and possibly other configuration options), so they specify If MetaCPAN knew about this, MetaCPAN could list them under "The following might be required, depending on your situation". A proper modal could include the information about when and why they could be required. |
Now, taking a vendor tooling perspective, it is preferable (for the lack of a stronger term) to not run third-party code in order to understand what the requirements are. It is also preferable to read these from a machine-readable file rather than sifting through a A good example of how far the last sentence can go is the In C world we know that the contract between the developer and the user is the help menu of the |
@xsawyerx can you state why this is better than using the The only real distinction I'm seeing here is optional features are "user decides" where dynamic_config is "makefile.PL + env decides". I think that might be a a narrow enough distinction to consider unifying the data structures somehow. maybe an "available_if" => "condition" in "optional_features" |
At least some of what @xsawyerx is talking about are the automatic configure-time dependencies that people enable via Makefile.PL probes. Then there are things like "runs faster if these XS modules are installed", which could be considered as |
Any system that is powerful enough to be useful will essentially be a DSL:
|
Goal is to avoid a Turing complete. Aim is "human readable info in well
|
It feels like half the people in this thread are assuming this spec is for something that will be machine-parsable. I thought it was only intended to be human-readable.. but I will bet you a dollar that someone will see this data and write a tool to try to parse it... |
@kentfredric You use Some of the modules in In short, very different things. |
Yeah. They become more different really specifically because of the "non-turing complete" goal. Mentally and logically, there will be cases where there are "optional features" that the user cant choose because system requirements prohibits it. However, there's no present way to express that, other than munging optional features during Granted having non-turing conditions on the optional features can't help that situation either. Was hoping to euthanise two birds with one needle. |
I don't think the differences have to do with turing-complete conditions. The optional features are meant for the user to decide and dynamic config is meant for the computer to decide. That makes optional features at least supposed to handle only optional features, decided by the user (and sure, possibly a default value here), while dynamic config is meant for supported (on a technical/platform/etc.) configuration - the ol' "You have Windows, you need this module". It's not something a user picks or decides. It's not "optional". The reason they are confusing is because they both fall under "You might get these installed", but for different reasons and purposes, and by different agents. |
Meta files have always been meant for machines, and I never really considered JSON human-friendly. It that's what you want, why not add a |
That's sadly of limited utility here, because one of the motivations here is "Because the actual deps are declared in a structure, metacpan can display them ... somehow". This seems to be part of our ongoing struggle how META.json is used during the install process and as a non-installation informational-transfer structure. I do agree I would rather we not continue to proliferate this sin. But there's not a lot of ways out atm. |
JSON human-friendliness is out of scope here. The intent was there is part of meta files meant purely for machines and part of meta (such as I've never been enchanted by But to agree somewhat with @Leont, I think that "human readable info in a well defined place" only gives frustrations to humans wanting that information in a 100% machine readable way. Despites not being an ideal solution |
The problem here is that the "condition" here is not designed to be computable, it is only informational, its just a free-form text field. Making "condition" computable means we have to implement an entire mini-language to define the use of conditions. Hence, the actual conditions are to be ignored by automated processes, and are only a suggestion for humans to read to understand what the attached payload does. Quote:
Emphasis added. This data does not have a "machine" as its end user like the rest of the CPAN tools do. Even optional features have "a machine" as the end user, because the machine evaluates the structures and presents choices based on those choices to the user. There is however no desire for this feature to be used in an automated fashion by installers in the initial design request.
Hence, the more pragmatic approach is: "Here's some deps, and here's a description that humans can read to determine what they might do, but run the code itself to determine what in fact must happen". Having 2 different code systems to determine the same answer is surely going to turn into self abuse. I can at best see a middle ground where the "dynamic_prereqs" stash contains a "Token" key of some kind that identifies "this block of stuff is turned on by code", and then the *.PL files can then refer to that same token and implement the actual logic to enable that prereqs set. |
I'm just going to dump a non-JSON alternative solution to poison your mind with, because personally, inventing a new turing complete language when everyone is going to have Perl at the ready anyway ( and will need it anyway for an implementation of this new language ): Inspired by CPANFile syntax hybridised with syntax from @karenetheridge's DZP:DynamicPrereqs. providing "Additional Win32 Support" => sub {
condition "Needs win32" => sub { $^O =~ qr/Win32/ };
requires "Win32::Foo::Bar" => "1.23";
};
providing "Acceleration via Wibble::XS" => sub {
condition "Needs C Compiler" => \&has_compiler;
requires "Wibble::XS";
};
providing "perls before 5.14, avoid RT#666" => sub {
condition "Needs Perl 5.14 or earlier" => sub { $] <= 5.14 };
requires "Devel::ReallyAnnoying" => "0.17";
};
providing "Prettier output, optional" => sub {
condition "Already has thing" => sub { has_module("Data::ReallyOptional::Foo", ">=0"); };
on "test" => sub {
recommends "Data::ReallyOptional::Foo";
};
}; This structure can be statically extracted to produce a non-executable textual description that a Vendor can read without needing to know any deep magic, doesn't require them to learn a new language. And the structure itself can also be directly executable by installer toolchains. ( because the "condition" block simply associates a reference to the sub, which can then be executed as needed ) The non-executable descriptive parts of this can be statically extracted and stuffed in a JSON file somewhere as "information only" usages similar to how cpanfile currently serves as a staging ground for META.json. |
I think this completely misses the point here. A vendor shouldn't have to run code to know what the prereqs are. We have a meta file to convey dependencies. If we have condition-based dependencies, we should at least make those visible. It really is that simple. |
One part of the equation is having a framework to expose that data. The other part of that equation is having a mechanism to communicate that data to the META.json. And ideally, one does so without duplicating effort. So: requirements:
Obviously its too hard to derive 3 from 1 without horror shows. And its an expected problem to have 3 constantly in sync with 1 if they're implemented independently. And obviously, native code structures don't convert 3 to 1 on their own. Hence, the proposed secondary structure that can be used to produce targets both 1 and 3. |
I declare this thread "bikeshedded". At this point, we know what the ideas are. Should we ever have a v3 spec RFC, the specifics can be debated then. |
From discussion with @xsawyerx, we have a gap in META when dynamic config is true (or missing) that vendors or packagers have no way to know what might be included in any standard way. They have to run the .PL file or read it in order to discover it.
We could have a meta field that provides module names as keys and data structures with version and rationale that explains the conditions for a dynamic dependency (in a human-readable way).
Eg.
The text was updated successfully, but these errors were encountered: