nixbuild/derivation.go
Ophestra 5c632a9ad8
derivation: parse nix derivation show
This time it's JSON, and actual intended behaviour.
2025-07-15 01:51:55 +09:00

89 lines
2.3 KiB
Go

package nixbuild
import (
"context"
"encoding/json"
"errors"
"io"
"iter"
)
type (
// DerivationMap is the output of `nix derivation show`.
DerivationMap map[string]Derivation
// Derivation is a description of a derivation.
Derivation struct {
// Args are arguments passed to Builder.
Args []string `json:"args"`
// Builder is the store path of the program that builds the [Derivation].
Builder string `json:"builder"`
// System is the value of pkgs.system during evaluation.
System string `json:"system"`
// Name is the user-facing name of a derivation, as seen in the nix store path suffix.
Name string `json:"name"`
Environment json.RawMessage `json:"env"`
InputDerivations InputDerivationsMap `json:"inputDrvs"`
InputSources []string `json:"inputSrcs"`
Outputs OutputsMap `json:"outputs"`
}
// OutputsMap is an output name to [Output] map.
OutputsMap map[string]Output
// Output is an output of a [Derivation].
Output struct {
Path string `json:"path"`
}
// InputDerivationsMap is a store path to metadata map.
InputDerivationsMap map[string]InputDerivation
// InputDerivation contains input derivation metadata.
InputDerivation struct {
DynamicOutputs json.RawMessage `json:"dynamicOutputs"`
Outputs []string `json:"outputs"`
}
)
// DerivationShow returns a [DerivationMap] describing all entries yielded by installables.
func DerivationShow(ctx context.Context, installables iter.Seq[string]) (DerivationMap, error) {
c, cancel := context.WithCancel(ctx)
defer cancel()
cmd := Nix(c, CommandDerivation, CommandDerivationShow,
FlagStdin)
ir, iw := io.Pipe()
cmd.Stdin = ir
or, ow := io.Pipe()
cmd.Stdout = ow
if Stderr != nil {
cmd.Stderr = Stderr
}
cmd.Cancel = func() error { _ = ow.Close(); return cmd.Process.Kill() }
if err := cmd.Start(); err != nil {
return nil, err
}
done := make(chan error)
var v DerivationMap
go func() { done <- json.NewDecoder(or).Decode(&v) }()
if _, err := WriteStdin(iw, installables); err != nil {
return nil, errors.Join(err, cmd.Wait())
}
if err := iw.Close(); err != nil {
return nil, errors.Join(err, cmd.Wait())
}
if err := cmd.Wait(); err != nil {
// deferred cancel closes pipe
return nil, err
}
err := <-done
return v, err
}