Skip to content

Commit da28fb8

Browse files
authored
Merge pull request #385 from nix-community/contribute-flow
Rewrite contributors.md and integration test it
2 parents b207b3a + 919b8f6 commit da28fb8

File tree

11 files changed

+169
-106
lines changed

11 files changed

+169
-106
lines changed

docs/src/SUMMARY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
# Contributing
2828
- [Extending dream2nix](./extending-dream2nix.md)
29-
- [Contributing](./contributing.md)
29+
- [Contributing](./contributing/contributing.md)
3030

3131
# Development Roundups
3232
- [April - June 2022](./development-roundups/2022-april-june.md)

docs/src/contributing.md

Lines changed: 0 additions & 78 deletions
This file was deleted.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export dream2nix=$(realpath .)
2+
3+
# define names for new modules (pick names matching to your subsystem)
4+
export subsystem="my-subsystem" # example: nodejs
5+
export pureTranslator="my-pure-translator" # example: package-lock
6+
export impureTranslator="my-impure-translator" # example: package-json
7+
export builder="my-builder" # pick `default` as name if not sure
8+
9+
# define path to example flake
10+
export myFlake="$dream2nix/src/examples/$subsystem"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# initialize pure translator
2+
mkdir -p $dream2nix/src/subsystems/$subsystem/translators/$pureTranslator
3+
cp $dream2nix/src/templates/translators/pure.nix $dream2nix/src/subsystems/$subsystem/translators/$pureTranslator/default.nix
4+
5+
# initialize builder
6+
mkdir -p $dream2nix/src/subsystems/$subsystem/builders/$builder
7+
cp $dream2nix/src/templates/builders/default.nix $dream2nix/src/subsystems/$subsystem/builders/$builder/default.nix
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# initialize example flake
2+
mkdir -p $myFlake
3+
cp $dream2nix/tests/integration/tests/contribute/my-flake.nix $myFlake/flake.nix
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
git add .
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# inspect if your subsystem exports any package/devShell
2+
nix flake show $myFlake --override-input dream2nix $dream2nix --show-trace
3+
4+
# run your translator and dump the dream-lock.json for inspection
5+
nix run $myFlake#default.resolve --override-input dream2nix $dream2nix --show-trace
6+
7+
# test if the default package builds
8+
nix build $myFlake#default --override-input dream2nix $dream2nix --show-trace

docs/src/contributing/contributing.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# dream2nix contributors guide
2+
This guide is for you if you plan to implement support for a new subsystem in dream2nix, like for example for a new programming language.
3+
4+
If the ecosystem you are interested in is already supported by dream2nix, but you want to add support for a new type of lock-file format, this guide is still an interesting read in order to better understand the parts a dream2nix subsystem consists of.
5+
6+
## Breakdown of a subsystem
7+
A new subsystem in dream2nix is initialized by adding 3 files:
8+
9+
- one translator module
10+
- one builder module
11+
- one example flake.nix for testing the subsystem
12+
13+
It's also highly recommended to implement a discoverer module, so that projects of that subsystem can be detected automatically by dream2nix. This simplifies the UX. It won't be necessary anymore for the user to understand which ecosystem and which translator must be used in order to build packages from a certain source tree.
14+
15+
## Translator Notes
16+
17+
The task of a translator is to inspect a given source tree, parse some of the files, and extract information about a projects dependencies and how it must be built.
18+
19+
In general there are 3 different types of translators.
20+
No matter which type, all translators always produce the same output structure which is called `dream-lock`.
21+
An example of this structure can be found [here](https://github.com/nix-community/dream2nix/blob/main/src/specifications/dream-lock-example.json).
22+
There is also a [jsonschema specification](https://github.com/nix-community/dream2nix/blob/main/src/specifications/dream-lock-schema.json) for it.
23+
24+
## Translator types
25+
The different types of translators have the following properties:
26+
27+
1. pure translator
28+
29+
- returns the dream-lock as a nix attribute set
30+
- translation logic is implemented in nix language only
31+
- parsing of files and data extraction is all done during eval time
32+
- does not invoke a build or read from any build output
33+
34+
2. pure translator utilizing IFD (import from derivation)
35+
36+
- returns the dream-lock as a nix attribute set
37+
- a nix build is used in order to parse files and extract data
38+
- translation logic can be implemented in arbitrary language
39+
- the result is parsed back into nix from the build output
40+
- downside: performance impact on evaluation time
41+
42+
3. impure translator
43+
44+
- returns the dream-lock by dumping a dream-lock.json file
45+
- translator can be any executable program running independent of nix
46+
- not constrained in any way (can do arbitrary network access etc.)
47+
- downside: requires the user to run a command whenever dependencies got updated
48+
49+
## Which translator type to start with?
50+
When adding support for a new ecosystem/language, the following strategy usually works out:
51+
52+
If there exists tooling within that ecosystem that can create some kind of lock file (with URLs + checksums), implement a pure translator for that lock file format first.
53+
54+
After that, we might still need an impure translator for all the projects within that ecosystem that don't ship a lock-file. But given the fact that we already have one pure translator, all the impure translator needs to do is to run the tooling that creates the lock file and call out to the pure translator via `nix eval`.
55+
56+
If the ecosystem does not have any kind of lock file format, then only an impure translator is needed. In this case it needs to be more complex and implement some kind of routine for retrieving all URL's and hashes of the dependencies, by, for example, downloading them all and hashing them.
57+
58+
## Initializing the subsystm
59+
To initialize a new subsystem, we will:
60+
61+
- declare a few shell variables
62+
- initialize a translator and a builder from templates
63+
- initialize an example flake.nix to test the implementation
64+
65+
### declare env variables
66+
Navigate to your dream2nix checkout and execute:
67+
```bash
68+
{{#include ./00-declare-variables.sh}}
69+
```
70+
71+
### initialize templates
72+
73+
```bash
74+
{{#include ./01-initialize-templates.sh}}
75+
```
76+
77+
### initialize example flake.nix
78+
79+
Initialize the flake from a template and edit it to reference the names of your subsystem correctly.
80+
```bash
81+
{{#include ./02-initialize-example-flake.sh}}
82+
```
83+
Now edit the flake and ensure that `my-subsystem`, `my-pure-translator`, are replaced with the names defined earlier.
84+
85+
### add new files to git
86+
This is required, otherwise nix flakes won't see the new files.
87+
```bash
88+
{{#include ./03-add-files-to-git.sh}}
89+
```
90+
91+
### test example flake
92+
Always pass `--override-input dream2nix $dream2nix` in order to evaluate the example flake against your local checkout of dream2nix.
93+
94+
In the following bash snippet, arguments containing a '`#`' symbol are wrongfully highlighted as comment but are in fact required parameters.
95+
96+
Run all of the following commands now to ensure that all templates have been initialized correctly
97+
```bash
98+
{{#include ./04-test-example-flake.sh}}
99+
```
100+
101+
102+
## Iterate on the subsystem
103+
By default the templates implement a subsystem for `niv`. It reads niv's `./nix/sources.json` and builds a package for it containing the niv inputs.
104+
105+
The output of this is not useful, but demonstrates how a dream2nix translator/builder works.
106+
107+
You can now start modifying the builder/translator to implement the logic required by your subsystem.
108+
109+
You can test your implementation by executing the `nix flake show`, `nix build`, `nix run` commands from the last step above.

src/specifications/dream-lock-schema.json

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@
1515
"properties": {
1616
"type": {
1717
"enum": [
18-
"http",
18+
"archive",
1919
"git",
2020
"github",
2121
"gitlab",
22+
"http",
2223
"npm",
2324
"path",
2425
"pypi-sdist",
@@ -30,7 +31,7 @@
3031
"allOf": [
3132
{
3233
"if": {
33-
"properties": { "type": { "const": "http" } }
34+
"properties": { "type": { "const": "archive" } }
3435
},
3536
"then": {
3637
"properties": {
@@ -78,6 +79,21 @@
7879
"additionalProperties": false
7980
}
8081
},
82+
{
83+
"if": {
84+
"properties": { "type": { "const": "http" } }
85+
},
86+
"then": {
87+
"properties": {
88+
"url": { "type": "string" },
89+
"hash": { "type": "string" },
90+
"type": { "type": "string" },
91+
"dir": { "type": "string" }
92+
},
93+
"required": ["type", "url"],
94+
"additionalProperties": false
95+
}
96+
},
8197
{
8298
"if": {
8399
"properties": { "type": { "const": "npm" } }

tests/integration/tests/contribute/default.nix

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,35 +14,22 @@ in
1414
])
1515
''
1616
# create working dirs
17-
mkdir $TMPDIR/{dream2nix,test-flake}
17+
mkdir $TMPDIR/dream2nix
1818
1919
# checkout dream2nix source code
2020
cd $TMPDIR/dream2nix
2121
cp -r ${self}/* .
2222
chmod -R +w .
2323
24-
# define names for new modules
25-
subsystem="my-subsystem"
26-
pureTranslator="my-pure-translator"
27-
impureTranslator="my-impure-translator"
28-
builder="my-builder"
24+
# fake git
25+
function git(){
26+
true
27+
}
2928
30-
# initialize pure translator
31-
mkdir -p ./src/subsystems/$subsystem/translators/$pureTranslator
32-
cp ./src/templates/translators/pure.nix ./src/subsystems/$subsystem/translators/$pureTranslator/default.nix
33-
34-
# initialize builder
35-
mkdir -p ./src/subsystems/$subsystem/builders/$builder
36-
cp ./src/templates/builders/default.nix ./src/subsystems/$subsystem/builders/$builder/default.nix
37-
38-
# initialize flake for building a test package
39-
cp ${./my-flake.nix} $TMPDIR/test-flake/flake.nix
40-
cd $TMPDIR/test-flake
41-
nix flake lock --override-input dream2nix $TMPDIR/dream2nix --show-trace
42-
43-
# test `nix flake show`
44-
nix flake show --show-trace
45-
46-
# build test package
47-
nix build .#default --show-trace
29+
set -x
30+
source ${self}/docs/src/contributing/00-declare-variables.sh
31+
source ${self}/docs/src/contributing/01-initialize-templates.sh
32+
source ${self}/docs/src/contributing/02-initialize-example-flake.sh
33+
source ${self}/docs/src/contributing/03-add-files-to-git.sh
34+
source ${self}/docs/src/contributing/04-test-example-flake.sh
4835
''

tests/integration/tests/contribute/my-flake.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
source = src;
2525
projects.my-project = {
2626
name = "my-project";
27-
subsytem = "my-subsystem";
27+
subsystem = "my-subsystem";
2828
translator = "my-pure-translator";
2929
};
3030
};

0 commit comments

Comments
 (0)