Skip to content

Repository files navigation

🏔️ dag

A lightweight implementation of home-manager's directed acyclic graph (DAG) helpers.

Why?

Because Home Manager nailed it, IMO.

And having a single, familiar paradigm for writing structured information spread across a large flake seemed useful. Especially with the ascendency of flake.parts, the advent of the dendritic pattern, and the AOP of den.

d'ya like dags?

Installation

Flake

dag is a zero-dependency library, so it needs your version of nixpkgs to borrow from the Nix standard library.

# flake.nix{inputs={nixpkgs.url="github:nixos/nixpgks";dag.url="github:denful/dag";};outputs=inputs: letdag=inputs.dag.lib{inherit(inputs.nixpkgs)lib;};in{# use dag API};}

Flake Parts and/or Den

If you want the dag library to be available in the top-level attrset for each flake-part, do something like this:

# flake.nix{inputs={nixpkgs.url="github:nixos/nixpgks";flake-parts.url="github:hercules-ci/flake-parts";dag.url="github:denful/dag";};outputs=inputs@{nixpkgs,flake-parts,dag, ...}:
flake-parts.lib.mkFlake{inheritinputs;}{_module.args.dag=inputs.dag.lib{inherit(nixpkgs)lib;};};}

Usage

For the following examples, we'll assume you're using Flake Parts, and have access to the config.flake freeform attribute.

Rendering a DAG

1. Create the entries 🌪️

# somewhere.nix{dag, ... }:
{flake.song.somewhere=dag.entryBefore["out"]"Somewhere";}# out.nix{dag, ... }:
{flake.song.out=dag.entryAnywhere"out";}# there.nix{dag, ... }:
{flake.song.there=dag.entryBetween["otr-0"]["out"]"there";}# over-the-rainbow.nix{dag, ... }:
{flake.song=dag.entriesAnywhere"otr"["over""the""rainbow"];}

2. Render them to a string 🪄

In a README file or script or whatever.

# readme.nix{dag,config,lib, ... }:
{flake.readme=dag.render{entries=config.flake.song;# get entries from flakeseparator=" ";# default separator is "\n"transform=lib.toUpper;# default is lib.id (no-op)};}# or if you are fine with default settings{dag,config, ... }:
{flake.readme=dagconfig.flake.song;}

3. Enjoy the result! 🌈

This should output SOMEWHERE OUT THERE OVER THE RAINBOW anywhere you use config.flake.readme.

API

dag has two main functions: entry/entries for defining dag entries, and render for compiling the final output.

There's only has one method unique to this library: render. It was heavily inspired by the formidable nvf library for configuring Neovim with Nix. All the other APIs are lifted directly from home-manager. Entry is just a functional wrapper around the basic data structure underlying the dag tools.

entry

attrtyperequireddefaultdescription
beforestring OR listOf stringno[]tags this entry must appear before
afterstring OR listOf stringno[]tags this entry must appear after
dataanynoemptythe final data to render
returnstype
entryattrset

entries

attrtyperequireddefaultdescription
beforestring OR listOf stringno[]tags this entry must appear before
afterstring OR listOf stringno[]tags this entry must appear after
tagstringyesthe prefix to use for the entry names
datalistOf anyno[]a list of data to include
returnstype
entryattrset

render

attrtyperequireddefaultdescription
entriesattrset OR listof attrsetyesa map of names to data, or a list of entries to be merged
separatorstringno"\n"a string separator for combining outputs
transformfunctionnolib.ida function that is mapped over each string output before rendering
returnstype
the rendered dagstring

Alias: nabit. Like, "Dag nabit!"... Also, like "Let's nab it!". I like puns. Sue me.

entryAnywhere

Create a DAG entry that doesn't care where it lives.

argtyperequireddefaultdescription
dataanyyesthe data for the dag
returnstype
entryattrset

entryBefore

Create a DAG entry that must be listed before one or more other entries.

argtyperequireddefaultdescription
beforeTagslistOf stringsyestag names that this should appear before
dataanyyesthe data for the dag
returnstype
entryattrset

entryAfter

Create a DAG entry that must be listed after one or more other entries.

argtyperequireddefaultdescription
afterTagslistOf stringsyestag names that this should appear after
dataanyyesthe data for the dag
returnstype
entryattrset

entryBetween

Create a DAG entry that must be listed before some entries, but after others.

argtyperequireddefaultdescription
beforeTagslistOf stringsyestag names that this should appear before
afterTagslistOf stringsyestag names that this should appear after
dataanyyesthe data for the dag
returnstype
entryattrset

entriesAnywhere

Create multiple DAG entries tagged with ${tag}-${index}, who don't care where they are listed in the main DAG. These must be merged (//) with the rest of the dag, instead of assigned to a member of a DAG.

argtyperequireddefaultdescription
tagstringyestag to prefix to each entry
datalistOf anyyesa list of data to add

NOTE: The entries will not be processed as dag entries. Just add raw data here.

returnstype
dagattrsOf entry

entriesBefore

Create multiple DAG entries tagged with ${tag}-${index} which must all be listed before the specified tags. These must be merged (//) with the rest of the dag, instead of assigned to a member of a DAG.

argtyperequireddefaultdescription
tagstringyestag to prefix to each entry
beforeTagslistOf stringsyestag names that these should appear before
datalistOf anyyesa list of data to add
returnstype
dagattrsOf entry

NOTE: The entries will not be processed as dag entries. Just add raw data here.

entriesAfter

Create multiple DAG entries tagged with ${tag}-${index} which must all be listed after the specified tags. These must be merged (//) with the rest of the dag, instead of assigned to a member of a DAG.

argtyperequireddefaultdescription
tagstringyestag to prefix to each entry
afterTagslistOf stringsyestag names that these should appear after
datalistOf anyyesa list of data to add
returnstype
dagattrsOf entry

NOTE: The entries will not be processed as dag entries. Just add raw data here.

entriesBetween

Create multiple DAG entries tagged with ${tag}-${index} which must all be listed between the specified tags. These must be merged (//) with the rest of the dag, instead of assigned to a member of a DAG.

argtyperequireddefaultdescription
tagstringyestag to prefix to each entry
beforeTagslistOf stringsyestag names that these should appear before
afterTagslistOf stringsyestag names that these should appear after
datalistOf anyyesa list of data to add
returnstype
dagattrsOf entry

NOTE: The entries will not be processed as dag entries. Just add raw data here.

Utility Functions

These little functions also come along with Home Manager's lib, and are included here for completeness.

empty

argtyperequireddefaultdescription
returnstype
an empty set {}attrset

isEntry

argtyperequireddefaultdescription
itemanyyesA value to test
returnstype
is item a valid entry?boolean

isDag

argtyperequireddefaultdescription
itemanyyesA value to test
returnstype
is item a valid dag?boolean

topoSort

Low-level handling of DAGs from Home Manager. You probably won't need to use this.

argtyperequireddefaultdescription
entriesattrsetyesa dag to be sorted
returnstype
success/failure objectsattrset

map

A map function that's DAG-aware, and can be used to transform dag values before rendering.

argtyperequireddefaultdescription
funcfunctionyesa function to apply to each value of the dag
dagattrsetyesa dag whose values you'd like to transform
returnstype
dagattrset

Development

Wanna help out? Great! Clone this, run nix develop, and then just watch to run tests with every change.

Wanna add a new feature? Great! Be sure to add something in ./tests.nix and then run just ci;

Wanna be friends? Great! I like people! But if you're NOT people—if you're a statistical model trained on the collective stolen work of humans meant to imitate a sentient being—well, then you probably don't care about being my friend anyways. So, maybe go away.

Why a mountain?

dağ is Turkish for mountain.

About

DAGaaS. For nix.

Resources

Stars

14 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages