From d9c5a914a383a3461edbfc4edc1a03c4fe7e9114 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Wed, 24 Nov 2021 16:28:40 +0100 Subject: [PATCH 1/2] Add a SEP to extend the spec syntax --- seps/sep-0002.md | 105 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 seps/sep-0002.md diff --git a/seps/sep-0002.md b/seps/sep-0002.md new file mode 100644 index 0000000..aba1573 --- /dev/null +++ b/seps/sep-0002.md @@ -0,0 +1,105 @@ +# Extend the spec syntax to allow for edge attributes + +## The problem + +The current spec syntax allows to express node properties for a DAG but doesn't have any mechanism to: +1. Express edge properties. +2. Express a DAG structure that is not "flat" from a string literal. + +So far, this limitation in the spec language didn't have a major impact on which use cases could be addressed whithin Spack's software model, mainly because of the overly strict unification policy we currently employ - _in a DAG there can be only a single spec stemming from a given package_. + +The situation will change when we'll introduce in the software model separate concretization of build dependencies and, later, compiler as dependencies. + +There issue is that, since _we might have in a DAG two or more different specs for the same package_, we also need a way to express constraints on them from the command line or, more in general, in a string form. It's essential then that the spec syntax allows building a non-flat representation of a DAG (to distinguish constraints on the same software applied from different nodes) and allows matching edge properties. + +The proposal in this SEP tries to extend the spec syntax to allow specifying arbitrary `key=value` attributes on edges and introduces a way to parse non-flat DAGs from a literal string. + +## Proposed changes + +### Specify edge attributes + +To allow specifying edge attributes from a spec string we'll introduce the use of square brackets after the `^` sigil, which can accept an arbitrary number of space separated `key=value` attributes: +``` +A ^[foo=bar] B +``` +The spec above should parse as: +``` +A +| +| foo=bar +| +B +``` +The square brackets are needed to avoid ambiguities with anonymous specs with a constraint on a variant. The following for instance: +``` +^shared=true +``` +is a syntax that can be already employed to match any node that has a shared boolean variant set to "true". + +### Parse non-flat DAGs + +Currently the spec: +``` +A ^B ^C ^D +``` +is parsed as: +``` + A + / | \ + / | \ +B C D +``` +and there is no way to express more structure, e.g. to say that D should be a dependency of C. What we propose here is to be able to use parenthesis `()` to recursively define a spec. For instance: +``` +A ^B ^(C ^D) +``` +is parsed as [^1]: +``` + A + / | +B C + | + D +``` + +[^1]: From the point of view of the concretizer C should probably imply a `root(C)` atom similarly to what is done for environments concretized together. + +### Semantic considerations on abstract specs + +The structure constructed from an initial parsing can be modified by the concretization process. For instance: +``` +A ^B +``` +doesn't imply that B will be a direct dependency of A in the concretized spec - the concretization process can push it down to a transitive dependency. Nonetheless it implies that B needs to be present in the final DAG [^2] + +Said otherwise, at the moment we have no way to pin a dependency to some root. This ability though will become important especially in light of separate concretization of build dependencies. + +When expressing a constraint on a build dependency we are more likely to want that the build dependency is attached to the root, rather than being generically "present in the DAG". Unfortunately the opposite is true for link dependencies. + +One way to allow users to express both behaviors is to introduce an edge attribute that has a meaning only for abstract specs [^3] e.g. `floating`. We can then assume that: +- `floating=true` implies that the dependency is present in the DAG and can be pushed down to be a transitive dependency +- `floating=false` implies that the dependency is pinned to the root of the context + +Then to account for the different default behaviors we want for `type=build` and `type=link` dependencies we can assume that the implicit value of the `floating` edge attribute is `false` if `type=build` is specified and `true` otherwise. + +This means, for instance, that the spec: +``` +trilinos ^[type=build]hdf5@1.2.10 ^[type=link]hdf5@1.10.12 ^zlib@1.2.8 +``` +is equivalent to the more verbose: +``` +trilinos ^[type=build floating=false]hdf5@1.2.10 ^[type=link floating=true]hdf5@1.10.12 ^[floating=true]zlib@1.2.8 +``` + +Finally it seems appropriate to restrict the `^` symbol to indicate a dependency that is in the process space [^4] of the corresponding root, rather than in the entire DAG. + +[^2]: At the ASP level this means that a `^` implies a `node(B)` fact, but no `depends_on(A, B)` fact. + +[^3]: That likely means that it should not even be present after concretization and is only used to emit the correct set of facts for clingo + +[^4]: We indicate the process space of a root as the subdag linked through edges of either `type=link` and / or `type=run` . In the future it may be restricted to just `type=link` edges (and will represent the list of nodes that need to be loaded in the same process space memory by the OS) + +### Use cases + +TODO: Add significant use cases. + From d11b0a0f698fe08642de7987b16a3dfaf9fd54e8 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Mon, 29 Nov 2021 14:34:55 +0100 Subject: [PATCH 2/2] Modified syntax according to what wwas discussed last Wednesday --- seps/sep-0002.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/seps/sep-0002.md b/seps/sep-0002.md index aba1573..ac1bee5 100644 --- a/seps/sep-0002.md +++ b/seps/sep-0002.md @@ -10,7 +10,7 @@ So far, this limitation in the spec language didn't have a major impact on which The situation will change when we'll introduce in the software model separate concretization of build dependencies and, later, compiler as dependencies. -There issue is that, since _we might have in a DAG two or more different specs for the same package_, we also need a way to express constraints on them from the command line or, more in general, in a string form. It's essential then that the spec syntax allows building a non-flat representation of a DAG (to distinguish constraints on the same software applied from different nodes) and allows matching edge properties. +There issue is that, since _we might have in a DAG two or more different specs for the same package_, we also need a way to express constraints on them from the command line or, more in general, from a string literal. It's essential then that the spec syntax allows building a non-flat representation of a DAG (to distinguish constraints on the same software applied from different nodes) and allows matching edge properties. The proposal in this SEP tries to extend the spec syntax to allow specifying arbitrary `key=value` attributes on edges and introduces a way to parse non-flat DAGs from a literal string. @@ -18,9 +18,9 @@ The proposal in this SEP tries to extend the spec syntax to allow specifying arb ### Specify edge attributes -To allow specifying edge attributes from a spec string we'll introduce the use of square brackets after the `^` sigil, which can accept an arbitrary number of space separated `key=value` attributes: +To allow specifying edge attributes from a spec string we'll introduce the use of `:` delimiters after the `^` sigil. Within the delimiters we can have an arbitrary number of space separated `key=value` attributes: ``` -A ^[foo=bar] B +A ^:foo=bar: B ``` The spec above should parse as: ``` @@ -30,7 +30,7 @@ A | B ``` -The square brackets are needed to avoid ambiguities with anonymous specs with a constraint on a variant. The following for instance: +The delimiters are needed to avoid ambiguities with anonymous specs with a constraint on a variant. The following for instance: ``` ^shared=true ``` @@ -49,9 +49,9 @@ is parsed as: / | \ B C D ``` -and there is no way to express more structure, e.g. to say that D should be a dependency of C. What we propose here is to be able to use parenthesis `()` to recursively define a spec. For instance: +and there is no way to express more structure, e.g. to say that D should be a dependency of C. What we propose here is to be able to use braces `{}` to recursively define a spec. For instance: ``` -A ^B ^(C ^D) +A ^B ^{C ^D} ``` is parsed as [^1]: ``` @@ -84,11 +84,11 @@ Then to account for the different default behaviors we want for `type=build` and This means, for instance, that the spec: ``` -trilinos ^[type=build]hdf5@1.2.10 ^[type=link]hdf5@1.10.12 ^zlib@1.2.8 +trilinos ^:type=build: hdf5@1.2.10 ^:type=link: hdf5@1.10.12 ^zlib@1.2.8 ``` is equivalent to the more verbose: ``` -trilinos ^[type=build floating=false]hdf5@1.2.10 ^[type=link floating=true]hdf5@1.10.12 ^[floating=true]zlib@1.2.8 +trilinos ^:type=build floating=false: hdf5@1.2.10 ^:type=link floating=true: hdf5@1.10.12 ^:floating=true: zlib@1.2.8 ``` Finally it seems appropriate to restrict the `^` symbol to indicate a dependency that is in the process space [^4] of the corresponding root, rather than in the entire DAG. @@ -103,3 +103,7 @@ Finally it seems appropriate to restrict the `^` symbol to indicate a dependency TODO: Add significant use cases. +### Modification history + +1. Use a pair of `:` delimiters instead of `[]` (issues wwith zsh) +2. Use braces instead of parenthesis (issues wwith shells)