problem-solving icon indicating copy to clipboard operation
problem-solving copied to clipboard

META6 specification only exists "de facto"

Open JJ opened this issue 4 years ago • 53 comments

The META6 format was defined in S22, and is arguably not part of the language. There's a single test for S22, but it does not really check an interpreter of that format, just that the format can be used correctly. The interpreters of this format are, in general, external utilities

  • zef has probably got the most complete implementation, since it really needs it to find the correct dependencies.
  • META6 is not as complete, and until recently, it could not actually understand Associative values for depends. This is the one, BTW, used by Test::META, which is what we use to test p6c new modules.
  • Pakku::Meta was added yesterday to the ecosystem (it might have existed before as part of another distribution).

As far as I understand, there're no tests that cover all posibilities in S22, not even "currently adopted" possibilities. zef is the standard de facto, so the test we have now is "if it goes with zef, we're good". But not having a common set of (roast or roast-like) tests is an obstacle for evolution, should we need to extend it somehow (as was suggested here).

There are also a number of ambiguities that are not solved; mainly with the "depends" key and the "source-url" key. Build dependencies can appear in the depends → requires → key and in the build-depends key. Is there any precedence? Should we take both into account?

JJ avatar Sep 29 '20 09:09 JJ

I would say that it would probably benefit in the first place from a machine readable specification (probably JSON Schema,) with some annotation describing the roles and responsibilities of parsers, testers, installers, the core and so forth.

I'm guessing that extension could be achieved with JSON prefixes (e.g. prefix:name ,) but I'm not clear how these can be properly disambiguated like you might with XML Schema at the moment.

jonathanstowe avatar Sep 29 '20 10:09 jonathanstowe

However, we should also check that meaning is what it should be, and resolve ambiguities, but yes, JSON Schema would be a nice first step.

JJ avatar Sep 29 '20 12:09 JJ

I'm not going to share the whole generated schema right now because there are a couple of things that aren't expressed well in a simple schema, but it looks like people have already been extending it themselves without causing any great harm to the tools, here is the complete list of top level properties found in all the extent META files:

abstract aoi api auth author authors build build-depends builder depends description dynamic_config emulates excludes generated_by history license meta6 meta-spec meta-version name no_index perl prereqs production provides raku release_status repo-type resources source source-type source-url superseded-by supersedes support tags test-depends version x_serialization_backend

:-D

jonathanstowe avatar Sep 29 '20 13:09 jonathanstowe

Interestingly it seems that at least seven of the META files that are fetched by the zef CPAN backend were generated by the Perl 5 toolchain which would explain some of the weirder outliers above.

jonathanstowe avatar Sep 29 '20 13:09 jonathanstowe

Okay leaving out the ones that appear to be Perl 5 meta files we have:

aoi
api
auth
author
authority
authors
bin
build
build-depends
builder
creator
depends
description
emulates
excludes
history
licence
license
meta6
meta-version
name
perl
production
provides
raku
raku: 
repo-type
resource
resources
scripts
source
source-type
source-url
superseded-by
supersedes
support
tags
test-depends
version

The aoi is mine and the raku: appears to be all of the modules of @ramiroencinas for some reason. Altogether more sensible and I may be able to smack the generated schema into something useable.

jonathanstowe avatar Sep 29 '20 14:09 jonathanstowe

The builder and build seem to be some extension that both zef and Distribution::Builder::MakeFromJSON know about but seem to be undocumented anywhere. The object version of requires seems to be similarly mostly undocumented and should be clarified in word and a schema rather than example and folklore.

I think however that I can get a schema that will validate most instances.

jonathanstowe avatar Sep 29 '20 17:09 jonathanstowe

... and then we will need to publish that schema in some official way so that we can validate META6.json validators...

JJ avatar Sep 29 '20 17:09 JJ

Well, it would be stick it in it's own repository with tagged versions and so forth, probably the tags would align with some meta-version ....

jonathanstowe avatar Sep 29 '20 17:09 jonathanstowe

We should be wary of specifying things raku does not itself use. For instance it would seem a bit odd to me for the roast to specify what source-url, an ecosystem specific field, is supposed to mean. Raku doesn’t even have a way to parse dependency specifications from depends (nor does it use them currently), so how can we reasonably spec that?

Having a schema and tooling seems perfectly reasonable. Speccing everything in the roast seems short sighted.

ugexe avatar Sep 29 '20 19:09 ugexe

Personally, I'm not leaning toward speccing this in roast - I agree that is largely ecosystem specific, but it should be specified somewhere.

jonathanstowe avatar Sep 29 '20 19:09 jonathanstowe

The raku: value isn't correct in some of my modules. I meant raku. Can I correct it without breaking anything?

ramiroencinas avatar Sep 29 '20 19:09 ramiroencinas

I was rather thinking about a roast-like repo, maybe a specific one, maybe we could re-use the Raku/ecosystem and add them somewhere.

Definitely, not the roast.

JJ avatar Sep 29 '20 19:09 JJ

It would be great if META6 can validate the depends section and its sub sections like hints as well, Something similar to what it does for support section.

hythm7 avatar Sep 29 '20 19:09 hythm7

The raku: value isn't correct in some of my modules. I meant raku. Can I correct it without breaking anything?

Sure, if your modules are in the github ecosystem then you can just update in your repository, if they're in CPAN you may need to up the version and re-upload. :+1:

jonathanstowe avatar Sep 29 '20 19:09 jonathanstowe

fwiw I wrote a web service with a very naive and very incomplete validation using OpenAPI which might be useful for prototyping or bootstrapping such a validation service -- https://github.com/ugexe/Perl6-App--OpenAPI--META6Validator

ugexe avatar Sep 29 '20 19:09 ugexe

It would be great if META6 can validate the depends section and its sub sections like hints as well, Something similar to what it does for support section.

The problem is that these things aren't completely specified anyway, that's what we're trying to get at here. Though META6 isn't actually designed as a validator per-se, it's just to facilitate validation by other modules.

jonathanstowe avatar Sep 29 '20 19:09 jonathanstowe

This is my first cut at a schema that will validate at least some of the META6 in the wild:

{
   "$schema" : "http://json-schema.org/draft-04/schema#",
   "definitions" : {
      "dependency-specification" : {
         "items" : {
            "oneOf" : [
               {
                  "type" : "string"
               },
               {
                  "type" : "object",
                  "properties" : {
                     "name" : {
                        "oneOf" : [
                           {
                              "type" : "string"
                           },
                           {
                              "properties" : {
                                 "by-distro.name" : {
                                    "properties" : {},
                                    "type" : "object"
                                 }
                              },
                              "type" : "object"
                           }
                        ]
                     },
                     "from" : {
                           "type" : "string"
                     }
                  },
                  "required" : [
                     "name",
                     "from"
                  ]
               }
            ]
         },
         "type" : "array"
      },
      "dependency-specifications" : {
         "properties" : {
            "requires" : {
               "$ref" : "#/definitions/dependency-specification"
            },
            "recommends" : {
               "$ref" : "#/definitions/dependency-specification"
            }
         },
         "type" : "object",
         "required" : [
            "requires"
         ]
      }
   },
   "type" : "object",
   "properties" : {
      "api" : {
         "type" : [
            "string",
            "number"
         ]
      },
      "auth" : {
         "type" : "string"
      },
      "authors" : {
         "items" : {
            "type" : "string"
         },
         "type" : "array"
      },
      "build" : {
         "properties" : {
            "makefile-variables" : {
               "type" : "object"
            }
         },
         "type" : "object"
      },
      "build-depends" : {
         "items" : {
            "type" : "string"
         },
         "type" : "array"
      },
      "builder" : {
         "type" : "string"
      },
      "depends" : {
         "oneOf" : [
            {
               "type" : "array",
               "items" : {
                  "type" : "string"
               }
            },
            {
               "type" : "object",
               "properties" : {
                  "build" : {
                     "$ref" : "#/definitions/dependency-specifications"
                  },
                  "runtime" : {
                     "$ref" : "#/definitions/dependency-specifications"
                  },
                  "test" : {
                     "$ref" : "#/definitions/dependency-specifications"
                  }
               }
            }
         ]
      },
      "description" : {
         "type" : "string"
      },
      "emulates" : {
         "properties" : {},
         "type" : "object"
      },
      "excludes" : {
         "properties" : {},
         "type" : "object"
      },
      "history" : {
         "items" : {
            "type" : "string"
         },
         "type" : "array"
      },
      "license" : {
         "items" : {
            "type" : "string"
         },
         "type" : [
            "array",
            "string",
            "null"
         ]
      },
      "meta-version" : {
         "type" : [
            "number",
            "string"
         ]
      },
      "name" : {
         "type" : "string"
      },
      "perl" : {
         "type" : "string"
      },
      "production" : {
         "type" : "boolean"
      },
      "provides" : {
         "properties" : {},
         "type" : "object"
      },
      "raku" : {
         "type" : "string"
      },
      "repo-type" : {
         "type" : "string"
      },
      "resources" : {
         "items" : {
            "oneOf" : [
               {
                  "type" : "null"
               },
               {
                  "type" : "string"
               }
            ],
            "type" : "string"
         },
         "properties" : {},
         "type" : "array"
      },
      "source-type" : {
         "type" : "string"
      },
      "source-url" : {
         "type" : "string"
      },
      "superseded-by" : {
         "type" : "object",
         "properties" : { }
      },
      "supersedes" : {
         "type" : "object",
         "properties" : {}
      },
      "support" : {
         "type" : "object",
         "properties" : {
            "bugtracker" : {
               "type" : "string"
            },
            "email" : {
               "type" : "string"
            },
            "irc" : {
               "type" : "string"
            },
            "license" : {
               "type" : "string"
            },
            "source" : {
               "type" : "string"
            }
         }
      },
      "tags" : {
         "type" : "array",
         "items" : {
            "type" : "string"
         }
      },
      "test-depends" : {
         "type" : "array",
         "items" : {
            "type" : "string"
         }
      },
      "version" : {
         "type" : "string"
      }
   },
   "required" : [
      "auth",
      "authors",
      "depends",
      "description",
      "license",
      "meta-version",
      "name",
      "perl",
      "provides",
      "resources",
      "version"
   ]
}

The required keys are up for discussion obviously and there may be some detail missing in the polymorphic depends.

I'll stick some annotations in later.

jonathanstowe avatar Sep 29 '20 20:09 jonathanstowe

build is builder-specific, i.e. it's a place designated for information that the module specified as builder will use. Currently the only builder implementation is Distribution::Builder::MakeFromJSON

All information in build and depends is subject to System::Query collapsing, i.e. at any point you can specify an object with a by- something.property key and the whole object gets replaced with one of the appropriate values. The "somethings" in the key may be env, env-exists for checking environment variables or distro, kernel, backend for Raku's $*DISTRO, $*KERNEL, $*BACKEND objects respectively.

E.g. the whole depends section may depend on the distro name. Or just the version of one of the dependencies may depend on the VM backend.

The depends section may also contain alternatives via an object with an any key: "depends": [ "Foo", {"any": ["Bar", "Baz"]} ]


This (and much more) is specified in S22:
https://github.com/Raku/old-design-docs/blob/master/S22-package-format.pod
I don't understand why this is called "mostly undocumented"?

The `build-depends` and `test-depends` keys are deprecated. The `depends` key 
itself is not required (after all a module may just not have any 
dependencies). Same for the `resources` key. I would argue that this is even 
true for the `provides` key. A distro may just contain resources and no 
modules. Or even more realistic, it can be just a collection of dependencies 
like `Task::Galaxy`.

niner avatar Sep 30 '20 08:09 niner

build is builder-specific, i.e. it's a place designated for information that the module specified as builder will use. Currently the only builder implementation is Distribution::Builder::MakeFromJSON All information in build and depends is subject to System::Query collapsing, i.e. at any point you can specify an object with a by- something.property key and the whole object gets replaced with one of the appropriate values. The "somethings" in the key may be env, env-exists for checking environment variables or distro, kernel, backend for Raku's $*DISTRO, $*KERNEL, $*BACKEND objects respectively. E.g. the whole depends section may depend on the distro name. Or just the version of one of the dependencies may depend on the VM backend. The depends section may also contain alternatives via an object with an any key: "depends": [ "Foo", {"any": ["Bar", "Baz"]} ] ``` This (and much more) is specified in S22: https://github.com/Raku/old-design-docs/blob/master/S22-package-format.pod I don't understand why this is called "mostly undocumented"?

Apparently, because those documents needed some updating. Also, it's not anywhere else, and anyway design documents are, literally:

may be out of date... See docs.raku.org for documentation, or the official test suite.

The documentation in docs.raku.org about META6.json is not an specification, anyway.

The build-depends and test-depends keys are deprecated. The depends key itself is not required (after all a module may just not have any dependencies). Same for the resources key. I would argue that this is even true for the provides key. A distro may just contain resources and no modules. Or even more realistic, it can be just a collection of dependencies like Task::Galaxy.

Well, that might also be underdocumented. In this issue (from exactly one month ago), you can read:

test-depends isn't deprecated, and I'm not sure why anyone would assume it is.

So, maybe, just maybe, we would need a little specification here?

JJ avatar Sep 30 '20 08:09 JJ

Apparently, because [those documents needed some updating]

I was writing specifically about "The object version of requires seems to be similarly mostly undocumented". My commit did not change anything about that. The object version of requires has been documented for years.

Also, it's not anywhere else, and anyway design documents are, literally:

may be out of date... See docs.raku.org for documentation, or the official test suite.

"may be out of date" does not mean "definitively out of date".

The documentation in docs.raku.org about META6.json is not an specification, anyway.

I disagree. I do know that when I wrote it I meant it to be a specification.

test-depends isn't deprecated, and I'm not sure why anyone would assume it is. So, maybe, just maybe, we would need a little specification here?

Huh...ok, this needs discussion then. I don't see why we'd need test-depends and build-depends when the same can already be specified in depends. But maybe there's a good reason that we discussed back then and I simply forgot.

niner avatar Sep 30 '20 09:09 niner

This (and much more) is specified in S22: https://github.com/Raku/old-design-docs/blob/master/S22-package-format.pod I don't understand why this is called "mostly undocumented"?

Largely the old-design-docs and the versioning information at the top of it :-D Might I suggest that, if it is considered a living document, we move it somewhere more obvious (maybe even part of the output of this issue.)

jonathanstowe avatar Sep 30 '20 09:09 jonathanstowe

This (and much more) is specified in S22: https://github.com/Raku/old-design-docs/blob/master/S22-package-format.pod I don't understand why this is called "mostly undocumented"?

Largely the old-design-docs and the versioning information at the top of it :-D Might I suggest that, if it is considered a living document, we move it somewhere more obvious (maybe even part of the output of this issue.)

For instance, to a tool that helps us validate a META6.json including a JSON schema and its outcomes.

JJ avatar Sep 30 '20 09:09 JJ

All information in build and depends is subject to System::Query collapsing,

This part makes providing an exhaustive schema for a META6 and any static validation against such a schema rather tricky as it is the result of the collapsing that needs to be validated because, as I understand it, the collapsing can apply to any part of the JSON to produce a value. I think a validator would need a schema with annotations to indicate which parts are subject to collapsing, pre-process those parts with System::Query and then validate the resulting structure. This may also imply that for a properly comprehensive validation there needs to be something that does what System::Query does with the result but, rather than actually taking the values from the running system, would be able to reflect the properties being queried for and allow a validator to call the collapsing method with those values in turn, which sounds like a fun project for someone :-D

jonathanstowe avatar Sep 30 '20 10:09 jonathanstowe

I really had to look up what you mean by System::Query "collapsing". Apparently it refers to this module. Again, we really need a specification with annotations for META6.json, so that we can enter deprecation cycles for some keys or whatever is needed to carry this forward.

JJ avatar Sep 30 '20 10:09 JJ

FWIW, it may be worthwhile actually writing a specification for what System::Query does too. Othewise we end up with another de facto thing in the chain.

jonathanstowe avatar Sep 30 '20 10:09 jonathanstowe

pre-process those parts with System::Query and then validate the resulting structure.

This has a further implication that https://github.com/jonathanstowe/META6 may struggle to do all of the things that people are using it for if it is to parse a META6.json into a meaningful object with the depends and build pre-processed, which may preclude round-tripping to the same JSON with the original System::Query stuff if present.

jonathanstowe avatar Sep 30 '20 14:09 jonathanstowe

I really had to look up what you mean by System::Query "collapsing".

Yeah, but for me this was the key piece of information that I was missing, once that was clear it all fell into place :-D

jonathanstowe avatar Sep 30 '20 15:09 jonathanstowe

As an aside it looks like, of all the distributions in either CPAN or the github ecosystem, only Termbox and Inline::Python use the System::Query flattening. So I'm relatively relaxed about https://github.com/Raku/problem-solving/issues/236#issuecomment-701417434 :-D

jonathanstowe avatar Sep 30 '20 17:09 jonathanstowe

Since the System::Query stuff is part of the specification a possible validator ought to understand how it works exactly and properly validate it, too (in the uncollapsed state). It's not different from e.g. dependency alternatives. In any place where it expects a module name (or object with the individual parts of the dependency specification) it has to expect an object with the any key instead.

niner avatar Sep 30 '20 18:09 niner

I don't believe that it is possible to write a determinative specification that can be used for static validation based on the behaviour of System::Query, to take by-env as an example, it is not possible to know what the possible keys or the possible values might be in advance, so for every possible value in the target one would have to (assuming JSON Schema,) a oneOf with the target value type and an object that would have a property that would any by-foo with an object value which has properties with unknown names with values that all match the target value type (or a further production of System::Query.)

jonathanstowe avatar Sep 30 '20 21:09 jonathanstowe