1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
.Dd October 31, 2026
.Dt RUNGOCOMMAND 7
.Os
.Sh NAME
.Nm runGoCommand
.Nd a Nix derivation whose builder is a Go program
.Sh SYNOPSIS
.Bd -literal
depot.nix.runGoCommand "name" ./builder.go {
  input = somePackage;
  flag = "x";
}
.Ed
.Sh DESCRIPTION
.Nm
is the Go counterpart of
.Li pkgs.runCommand :
instead of a bash script run under stdenv's setup, the build step is a
Go program.
The file is compiled for the build machine with
.Xr buildGo 7
and becomes the derivation's
.Va builder
itself.
There is no shell, no
.Pa setup
script, no hooks and no implicit
.Ev PATH .
.Pp
It exists because builders that assemble file trees \(em copy this, write
that, generate a config, refuse if a store path leaks \(em grow into shell
scripts whose quoting, globbing and error handling are each a bug waiting to
happen.
In Go they are typed, testable, and fail loudly.
.Ss Arguments
.Bl -tag -width "derivationArgs"
.It Va name
The derivation's name.
.It Va builder
The Go file, package
.Li main .
It is the whole builder: one file, importing only the standard library and
.Li drv .
.It Va derivationArgs
Passed to
.Fn derivation
as they are.
As with any derivation, each attribute becomes an environment variable of
the builder: a package becomes its store path, a list its elements separated
by spaces.
The builder reads them with
.Fn drv.Env
and
.Fn drv.EnvList .
.Pp
.Va name ,
.Va builder ,
.Va args
and
.Va system
are reserved.
.Va system
in particular is
.Fn derivation Ns 's
build platform, so an input called
.Li system
would silently select another platform; it is an evaluation error instead.
.El
.Ss The drv package
Every builder can
.Li import "drv" ,
a small stdlib-only helper package
.Pq Pa drv/drv.go .
Its functions do not return errors: a builder has nothing to recover to, so
any failure prints a message and exits non-zero, which fails the build.
.Bl -tag -width "CopyTree(src, dst)"
.It Fn Out
.Ev $out .
.It Fn Env name
A required variable; missing is fatal.
.It Fn EnvList name
A list attribute, split.
.It Fn Run prog args...
Run a program, output to the build log.
.Va prog
must be a path; pass the package in
.Va derivationArgs
and join
.Li /bin/foo .
.It Fn RunIn dir prog args...
.Fn Run
in a directory.
.It Fn Output prog args...
Run and return stdout.
.It Fn Pipe r w prog args...
Run with stdin and stdout attached.
.It Fn Mkdir paths...
.It Fn Write path content mode
.It Fn WriteShebang path interpreter lines...
An executable script:
.Li #! Ns Va interpreter
(arguments included, e.g.\&
.Qq /bin/execlineb -P ) ,
then the lines, each newline-terminated.
.It Fn Touch path
.It Fn Symlink target link
.It Fn CopyFile src dst mode
Mode 0 keeps the source's mode, owner-writable.
.It Fn CopyTree src dst
Recursive, symlinks preserved, everything owner-writable.
.It Fn Glob pattern
.It Fn Check err context...
.It Fn Fatalf format args...
.El
.Sh EXAMPLES
.Bd -literal
// builder.go
package main

import "drv"

func main() {
	out := drv.Out()
	drv.Mkdir(out + "/bin")
	drv.CopyFile(drv.Env("hello")+"/bin/hello", out+"/bin/hello", 0)
	drv.Run(out+"/bin/hello", "-g", "built by a Go builder")
}
.Ed
.Bd -literal
depot.nix.runGoCommand "example" ./builder.go {
  hello = pkgs.hello;
}
.Ed
.Sh SEE ALSO
.Xr buildGo 7 ,
.Pa //nix/runExecline
.Sh CAVEATS
.Bl -bullet
.It
The builder runs with the bare build environment Nix provides: no
.Ev PATH ,
no
.Ev HOME
beyond
.Pa /homeless-shelter .
Programs that look themselves up on
.Ev PATH
need it set via
.Va derivationArgs .
.It
Because there is no stdenv, nothing is patched, stripped or checked
afterwards: the builder's output is the output.
.It
Changing a builder recompiles it, which costs a second or two.
.El