Reusable Features
A web server needs nginx, and every server needs ssh so operators can log in. Rather than write
that into each host, you define each concern once as a feature and let hosts pick the features
they need. The webserver feature includes ssh, so a host that picks webserver gets both.
In gen a feature is an aspect: a named bundle of configuration, with its content grouped by the
class it targets, such as nixos.
let gen = inputs.gen.lib.mkGenLibs { }; m = gen.merge;
cnf.keySemantics.nixos.category = "class"; aspectSchema = gen.aspects.mkAspectSchema cnf;
fleet = m.evalModuleTree { } [ (aspectSchema.mkAspectModule { }) { options.hosts = m.mkOption { type = m.types.attrsOf m.types.raw; default = { }; }; } { aspects.ssh.nixos.services.openssh.enable = true; aspects.monitoring.nixos.services.prometheus.exporters.node.enable = true; aspects.webserver.includes = [ "ssh" ]; aspects.webserver.nixos.services.nginx.enable = true;
hosts.web-1.aspects = [ "webserver" ]; hosts.db-1.aspects = [ "ssh" "monitoring" ]; } ];
facts = gen.aspects.graphFacts cnf fleet.config.aspects; includes = id: facts.includesOf.${id} or [ ];in{ includesOf = facts.includesOf; webserverPullsIn = gen.graph.reachableFrom { edges = includes; } "webserver";}{ includesOf = { monitoring = [ ]; ssh = [ ]; webserver = [ "ssh" ]; }; webserverPullsIn = [ "ssh" ]; }How it works
Section titled “How it works”cnf tells gen what each key of an aspect means. Here nixos is a class, so everything under
aspects.<name>.nixos is NixOS configuration. A framework can declare more classes, such as one
for user environments or one for cloud resources, and other key categories, such as channels.
includes is a relation between aspects, so gen turns it into edges. graphFacts extracts those
edges as data, and every gen graph query works on them. The include closure of webserver is one
reachableFrom call. Once webserver pulls in ssh, web-1 gets the ssh daemon without anyone
writing it into that host’s configuration.
Because an aspect is data, a framework can inspect it before building anything: which classes it writes and which aspects it includes. Delivering each host’s class content to a NixOS system builder, or to any other target, is covered on Aspects and Delivery.
The theory
Section titled “The theory”Feature-oriented programming builds a family of related programs from features: units of functionality that a product either includes or leaves out, and that can depend on each other. Each host is one product of that family, assembled from the features it selects. See our reading of Apel et al. (2009). The name aspect comes from aspect-oriented programming, where one unit of code can affect many places in a system (Kiczales et al. 1997).
Palettes adapted from Catppuccin (Macchiato) (MIT), Tokyo Night (Apache-2.0), gruvbox (MIT), Catppuccin (Latte) (MIT), Rosé Pine (Dawn) (MIT).