-
-
Notifications
You must be signed in to change notification settings - Fork 14.8k
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
Introduce types.orderOf
#97392
base: master
Are you sure you want to change the base?
Introduce types.orderOf
#97392
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
imports = [ ./orderable.nix ]; | ||
|
||
value.a.before.e = true; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
{ lib, ... }: { | ||
imports = [ | ||
{ | ||
options.value = lib.mkOption { | ||
type = lib.types.orderOf { | ||
elemType = lib.types.submodule ({ name, ... }: { | ||
options.data = lib.mkOption { | ||
type = lib.types.str; | ||
default = name; | ||
}; | ||
}); | ||
}; | ||
}; | ||
} | ||
{ | ||
options.value = lib.mkOption { | ||
type = lib.types.orderOf { | ||
before = a: b: a.value.before.${b.name} or false; | ||
elemType = lib.types.submodule { | ||
options.before = lib.mkOption { | ||
type = lib.types.attrsOf lib.types.bool; | ||
default = {}; | ||
}; | ||
}; | ||
}; | ||
}; | ||
} | ||
{ | ||
options.value = lib.mkOption { | ||
type = lib.types.orderOf { | ||
before = a: b: b.value.after.${a.name} or false; | ||
elemType = lib.types.submodule { | ||
options.after = lib.mkOption { | ||
type = lib.types.attrsOf lib.types.bool; | ||
default = {}; | ||
}; | ||
}; | ||
}; | ||
}; | ||
} | ||
]; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
{ | ||
|
||
config.value = { | ||
e = { | ||
before.c = true; | ||
before.a = true; | ||
}; | ||
d = { | ||
after.e = true; | ||
}; | ||
c = { | ||
after.e = true; | ||
before.b = true; | ||
}; | ||
b = { | ||
after.d = true; | ||
before.a = true; | ||
}; | ||
a = { | ||
after.d = true; | ||
}; | ||
}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ lib, ... }: | ||
{ | ||
options.value = lib.mkOption { | ||
type = lib.types.orderOf { | ||
before = a: b: a.value.before.${b.name} or false || b.value.after.${a.name} or false; | ||
elemType = lib.types.submodule ({ name, ... }: { | ||
options.data = lib.mkOption { | ||
type = lib.types.str; | ||
default = name; | ||
}; | ||
options.after = lib.mkOption { | ||
type = lib.types.attrsOf lib.types.bool; | ||
default = {}; | ||
}; | ||
options.before = lib.mkOption { | ||
type = lib.types.attrsOf lib.types.bool; | ||
default = {}; | ||
}; | ||
}); | ||
}; | ||
}; | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -360,6 +360,106 @@ | |||||
</para> | ||||||
</listitem> | ||||||
</varlistentry> | ||||||
<varlistentry> | ||||||
<term> | ||||||
<varname>types.orderOf</varname> { | ||||||
<replaceable>before</replaceable> ? a: b: false, | ||||||
<replaceable>elemType</replaceable> } | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
</term> | ||||||
<listitem> | ||||||
<para> | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The fact that types can produce a result that is of a very different shape is non-obvious but essential to the understanding of |
||||||
A set of elements of type <replaceable>elemType</replaceable>, ordered | ||||||
according to the given partial ordering function <replaceable>before | ||||||
</replaceable>, equivalent to a | ||||||
<link xlink:href="https://en.wikipedia.org/wiki/Directed_acyclic_graph"> | ||||||
DAG (directed acyclic graph)</link>. This type takes an attribute set | ||||||
with the following attributes as a parameter: | ||||||
<itemizedlist> | ||||||
<listitem><para> | ||||||
<replaceable>elemType</replaceable> | ||||||
The type of elements. The <literal>orderOf</literal> type accepts | ||||||
the same values as <literal>attrsOf elemType</literal> accepts. | ||||||
</para></listitem> | ||||||
<listitem><para> <replaceable>before</replaceable> | ||||||
The partial ordering function. It takes two parameters, each an | ||||||
attribute set of the form | ||||||
<variablelist> | ||||||
<varlistentry> | ||||||
<term><varname>name</varname></term> | ||||||
<listitem> | ||||||
<para> | ||||||
The attribute name of the entry. | ||||||
</para> | ||||||
</listitem> | ||||||
</varlistentry> | ||||||
<varlistentry> | ||||||
<term><varname>value</varname></term> | ||||||
<listitem> | ||||||
<para> | ||||||
The attribute value of the entry. This is of type <replaceable>elemType</replaceable>. | ||||||
</para> | ||||||
</listitem> | ||||||
</varlistentry> | ||||||
</variablelist> | ||||||
This function should return <literal>true</literal> if the first parameter should be ordered <emphasis>before</emphasis> the second one. | ||||||
</para></listitem> | ||||||
</itemizedlist> | ||||||
The result of this type is a list of <replaceable>elemType</replaceable> | ||||||
items, ordered according to the <replaceable>before</replaceable> function. | ||||||
If there are multiple possible orderings an arbitrary one of them is chosen. | ||||||
</para> | ||||||
<example xml:id="ex-orderOf"><title><literal>orderOf</literal> Example</title><para> | ||||||
Here is a simple example of using this type to order a list of text | ||||||
entries by allowing them to specify which entries they should come | ||||||
before of. | ||||||
<programlisting> | ||||||
{ lib, ... }: | ||||||
{ | ||||||
options.value = lib.mkOption { | ||||||
type = lib.types.orderOf { | ||||||
# a should come before b if the value of a specifies { before.<b> = true; } | ||||||
before = a: b: a.value.before.${b.name} or false; | ||||||
elemType = lib.types.submodule { | ||||||
options.text = lib.mkOption { | ||||||
type = lib.types.str; | ||||||
}; | ||||||
options.before = lib.mkOption { | ||||||
type = lib.types.attrsOf lib.types.bool; | ||||||
default = {}; | ||||||
}; | ||||||
}; | ||||||
}; | ||||||
}; | ||||||
|
||||||
config.value = { | ||||||
foo = { | ||||||
text = "This is foo"; | ||||||
before.bar = true; | ||||||
}; | ||||||
bar = { | ||||||
text = "This is bar"; | ||||||
}; | ||||||
}; | ||||||
} | ||||||
</programlisting> | ||||||
This option will evaluate to | ||||||
<programlisting> | ||||||
[ | ||||||
{ | ||||||
text = "This is foo"; | ||||||
before = { | ||||||
bar = true; | ||||||
}; | ||||||
} | ||||||
{ | ||||||
text = "This is bar"; | ||||||
before = { }; | ||||||
} | ||||||
] | ||||||
</programlisting> | ||||||
</para></example> | ||||||
</listitem> | ||||||
</varlistentry> | ||||||
<varlistentry> | ||||||
<term> | ||||||
<varname>types.lazyAttrsOf</varname> <replaceable>t</replaceable> | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
toposort
isO(n^2)
, so I’m kinda afraid this might slow down the module system even more if it’s used in a few places.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if it's possible to implement
toposort
more efficiently. However I can look into whether it's possible to implement a different interface more efficiently, e.g. something that isn't based on abefore
function but on a successor mapping instead, e.g.graphToposort { foo = [ "bar" ]; bar = []; }
representingfoo
having a directed edge tobar
. In theory, topo sorts can beO(|N| + |E|)
, though that might not be implementable in Nix.