8686 this file will be linked to the location indicated by the `path` option.
8787 '' ;
8888 } ;
89+ options . build = lib . mkOption {
90+ type = lib . types . lines ;
91+ default = "" ;
92+ description = ''
93+ If extra processing is required to generate a source file for this item,
94+ you may specify extra commands to run before the wrapper links it into place here.
95+ '' ;
96+ } ;
8997 }
9098 ) ;
9199
92100 renderBook =
93- subdir : book_src : summary : summaryVarname : bookVarname :
101+ bookSrc : summary : bookName :
94102 let
95103 renderItemSummary =
96104 node :
154162 in
155163 recsort 0 ;
156164
157- sortedBook = sortBook summary ;
158- bookSrc =
159- "${ placeholder "out" } /" + subdir + "/" + lib . removePrefix "/" ( lib . removeSuffix "/" book_src ) ;
160- summaryMD = builtins . concatStringsSep "\n " (
161- map (
162- v :
163- builtins . addErrorContext "while rendering summary item ${ builtins . toJSON v } " ( renderItemSummary v )
164- ) sortedBook
165- ) ;
166165 mkLink =
167166 node :
168167 if node . src != null && node . path != null then
@@ -171,62 +170,27 @@ let
171170 in
172171 ''
173172 mkdir -p "$(dirname ${ p } )"
173+ ${ node . build }
174174 ln -s ${ lib . escapeShellArg node . src } ${ lib . escapeShellArg "${ bookSrc } /${ lib . removePrefix "/" node . path } " }
175175 ''
176176 else
177177 "" ;
178- linkCmds = lib . pipe sortedBook [
179- ( map mkLink )
180- (
181- v :
182- [
183- "mkdir -p ${ lib . escapeShellArg "${ bookSrc } " } "
184- (
185- ''{ [ -e "$''
186- + ''${ summaryVarname } Path" ] && cat "$''
187- + ''${ summaryVarname } Path" || echo "$''
188- + ''${ summaryVarname } "; } > ${ lib . escapeShellArg "${ bookSrc } /SUMMARY.md" } ''
189- )
190- (
191- ''json2toml "$''
192- + ''${ bookVarname } Path" ${ lib . escapeShellArg "${ placeholder "out" } /${ subdir } /book.toml" } ''
193- )
194- ]
195- ++ v
196- )
197- ( builtins . concatStringsSep "\n " )
198- ] ;
178+ sortedBook = sortBook summary ;
199179 in
200180 {
201- summaryMD = summaryMD ;
202- linkCmds = linkCmds ;
181+ summaryMD = builtins . concatStringsSep "\n " (
182+ map (
183+ v :
184+ builtins . addErrorContext "while rendering summary item from book `${ bookName } `: `${ builtins . toJSON v } `" (
185+ renderItemSummary v
186+ )
187+ ) sortedBook
188+ ) ;
189+ linkCmds = builtins . concatStringsSep "\n " ( map mkLink sortedBook ) ;
203190 } ;
204191
205192 tomltype = ( pkgs . formats . json { } ) . type ;
206193
207- sanitizeShellVar =
208- s :
209- let
210- splitter = builtins . split "([^A-Za-z0-9_]+)" ;
211- genStr = str : num : builtins . concatStringsSep "" ( builtins . genList ( _ : str ) num ) ;
212- body = lib . pipe s [
213- splitter
214- ( map (
215- v :
216- if builtins . isList v then
217- let
218- bad = builtins . concatStringsSep "" v ;
219- in
220- genStr "_" ( builtins . stringLength bad )
221- else
222- v
223- ) )
224- ( builtins . concatStringsSep "" )
225- ] ;
226- in
227- # ensure valid first character
228- if builtins . match "[A-Za-z_].*" body != null then body else "_" + body ;
229-
230194 book-out-dir = "${ top . config . binName } -book-dir" ;
231195in
232196{
239203 description = ''
240204 The books are generated to:
241205
242- `'' ${passthru "out"}/'' ${config.book-out-dir}/'' ${name}`
206+ `'' ${placeholder "out"}/'' ${config.book-out-dir}/'' ${name}`
243207 '' ;
244208 } ;
245209 books = lib . mkOption {
246210 default = { } ;
247211 type = lib . types . attrsOf (
248212 lib . types . submodule (
249- { name , config , ... } :
250- let
251- pages =
252- renderBook config . generated-book-subdir config . book . book . src config . summary
253- config . generated-summary-varname
254- config . generated-book-json-varname ;
255- in
213+ { name , ... } :
256214 {
257215 options = {
258216 book = lib . mkOption {
259217 default = { } ;
260- apply = x : lib . filterAttrsRecursive ( _ : v : ! builtins . isFunction v && v != null ) x ;
261218 description = ''
262219 Values for the `book.toml` file for this book.
263220
378335 description = ''
379336 The directory within the wrapped derivation that contains the generated markdown for the book.
380337
381- `'' ${passthru "out"}/'' ${config.books.<name>.generated-book-subdir}` is the root of this book.
338+ `'' ${placeholder "out"}/'' ${config.books.<name>.generated-book-subdir}` is the root of this book.
382339 '' ;
383340 } ;
384- generatedSummary = lib . mkOption {
385- type = lib . types . str ;
386- readOnly = true ;
387- internal = true ;
388- visible = false ;
389- default = pages . summaryMD ;
390- } ;
391- buildCommands = lib . mkOption {
392- type = lib . types . str ;
393- readOnly = true ;
394- internal = true ;
395- visible = false ;
396- default = pages . linkCmds ;
397- } ;
398- generated-book-json-varname = lib . mkOption {
399- type = lib . types . str ;
400- readOnly = true ;
401- internal = true ;
402- visible = false ;
403- default = "nix_generated_book_json_${ sanitizeShellVar name } " ;
404- } ;
405- generated-summary-varname = lib . mkOption {
406- type = lib . types . str ;
407- readOnly = true ;
408- internal = true ;
409- visible = false ;
410- default = "nix_generated_summary_${ sanitizeShellVar name } " ;
411- } ;
412341 } ;
413342 }
414343 )
473402 } ;
474403 config . exePath = config . exePath ;
475404 } ) config . books ;
476- drv =
477- builtins . foldl' ( acc : v : acc // v ) { } (
478- lib . mapAttrsToList ( _ : v : {
479- ${ v . generated-summary-varname } = v . generatedSummary ;
480- ${ v . generated-book-json-varname } = builtins . toJSON v . book ;
481- } ) config . books
482- )
483- // {
484- passAsFile = builtins . concatLists (
485- lib . mapAttrsToList ( _ : v : [
486- v . generated-summary-varname
487- v . generated-book-json-varname
488- ] ) config . books
489- ) ;
490- nativeBuildInputs = [ pkgs . remarshal ] ;
491- buildPhase =
492- "runHook preBuild\n "
493- + builtins . concatStringsSep "\n " ( lib . mapAttrsToList ( _ : v : v . buildCommands ) config . books )
494- + "\n "
495- + (
496- if
497- config . mainBook != null
498- && config . wrapperVariants . "${ config . mainBook } " . enable or false == true
499- && config . books . "${ config . mainBook } " . enable or false == true
500- then
501- ''
502- rm -f $out/bin/${ config . binName }
503- ln -s ${ config . mainBook } $out/bin/${ config . binName }
504- ''
505- else
506- ""
405+ drv = {
406+ __structuredAttrs = true ;
407+ nativeBuildInputs = [
408+ pkgs . remarshal
409+ pkgs . jq
410+ ] ;
411+ bookData = lib . pipe config . books [
412+ ( lib . filterAttrs ( n : v : v . enable or false == true ) )
413+ ( builtins . mapAttrs (
414+ n : v :
415+ let
416+ src = "${ placeholder "out" } /${ v . generated-book-subdir } /${
417+ lib . removePrefix "/" ( lib . removeSuffix "/" ( v . book . book . src or "src" ) )
418+ } " ;
419+ pages = renderBook src v . summary n ;
420+ in
421+ {
422+ summary = pages . summaryMD ;
423+ book = builtins . toJSON (
424+ lib . filterAttrsRecursive ( _ : v : ! builtins . isFunction v && v != null ) v . book
425+ ) ;
426+ root = "${ placeholder "out" } /${ v . generated-book-subdir } " ;
427+ inherit src ;
428+ build = pages . linkCmds ;
429+ }
430+ ) )
431+ ] ;
432+ buildPhase = # bash
433+ ''
434+ runHook preBuild
435+ for book in $(jq -r '.bookData | keys[]' "$NIX_ATTRS_JSON_FILE"); do
436+ book_src="$(jq -r ".bookData[\"$book\"].src" "$NIX_ATTRS_JSON_FILE")"
437+ # this is the innermost dir this section handles we dont need more mkdir -p here
438+ mkdir -p "$book_src"
439+ # generate summary
440+ jq -r ".bookData[\"$book\"].summary" "$NIX_ATTRS_JSON_FILE" > "$book_src/SUMMARY.md"
441+
442+ # generate book.toml
443+ book_root="$(jq -r ".bookData[\"$book\"].root" "$NIX_ATTRS_JSON_FILE")"
444+ jq -r ".bookData[\"$book\"].book" "$NIX_ATTRS_JSON_FILE" | json2toml > "$book_root/book.toml"
445+
446+ # generate book contents
447+ eval "$(jq -r ".bookData[\"$book\"].build" "$NIX_ATTRS_JSON_FILE")"
448+ done
449+ ''
450+ +
451+ lib . optionalString
452+ (
453+ config . mainBook != null
454+ && config . wrapperVariants . "${ config . mainBook } " . enable or false == true
455+ && config . books . "${ config . mainBook } " . enable or false == true
507456 )
508- + "\n runHook postBuild" ;
509- } ;
457+ ''
458+ rm -f $out/bin/${ config . binName }
459+ ln -s ${ config . mainBook } $out/bin/${ config . binName }
460+ ''
461+ + "\n runHook postBuild" ;
462+ } ;
510463 passthru . book-out-dir = book-out-dir ;
511464 package = lib . mkDefault pkgs . mdbook ;
512465 meta . maintainers = [ wlib . maintainers . birdee ] ;
520473 you only have access to the other flags on these items at runtime.
521474
522475 To achieve greater runtime control, run the main executable with one of the generated books within the derivation
523- as input yourself, either at runtime, or within the module via `'' ${passthru "out"}/'' ${config.book-out-dir}/'' ${name}`
476+ as input yourself, either at runtime, or within the module via `'' ${placeholder "out"}/'' ${config.book-out-dir}/'' ${name}`
524477
525478 Within the module, there is an option called `mainBook` to REPLACE the main executable with a symlink to the desired book generation script.
526479
0 commit comments