This repository has been archived by the owner on Nov 7, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 16
/
builder.nu
164 lines (129 loc) · 4.86 KB
/
builder.nu
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
156
157
158
159
160
161
162
163
164
## Utility commands
export use env.nu *
## Parse the build environment
# This branching is a necessary workaround for a bug in the Nix CLI fixed in
# https://github.com/NixOS/nix/pull/8053
let attrsJsonFile = if ($env.NIX_ATTRS_JSON_FILE | path exists) {
$env.NIX_ATTRS_JSON_FILE
} else {
$"($env.NIX_BUILD_TOP)/.attrs.json"
}
let attrs = (open $attrsJsonFile)
let initialPkgs = $attrs.packages
# Nushell attributes
let nushell = {
version: (version).version, # Nushell version
pkg: (getPkgRoot $attrs.builder), # Nushell package path
userEnvFile: $attrs.envFile # Functions that users can apply in realisation phases
}
# Derivation attributes
let drv = {
name: $attrs.name, # The name of the derivation
system: $attrs.system, # The build system
src: (glob $"($attrs.src)/**/*"), # Sources to copy into the sandbox
outputs: ($attrs.outputs | transpose key value),
initialPackages: $initialPkgs, # Packages added by user
# The packages environment variable is a space-separated string. This
# pipeline converts it into a list.
packages: (
$initialPkgs
| append $nushell.pkg # Add the Nushell package to the PATH
| split row (char space)
),
extraAttrs: ($attrs.__nu_extra_attrs | transpose key value), # Arbitrary environment variables
}
# Nix build attributes
let nix = {
sandbox: $env.NIX_BUILD_TOP, # Sandbox directory
store: $env.NIX_STORE, # Nix store root
debug: (envToBool $attrs.__nu_debug) # Whether `debug = true` is set in the derivation
}
## Provide info about the current derivation
if $nix.debug {
banner "INFO"
info $"Realising the (blue $drv.name) derivation for (blue $drv.system)"
let numCores = ($env.NIX_BUILD_CORES | into int)
info $"Running on (blue $numCores) core(if ($numCores > 1) { "s" })"
info $"Using Nushell (blue $nushell.version)"
# Nix throws an error if the outputs array is empty, so we don't need to handle that case
info "Declared build outputs:"
for output in $drv.outputs { item $output.key }
}
## Set up the environment
if $nix.debug { banner "SETUP" }
# Log user-added packages if debug is set
if (not ($drv.initialPackages | is-empty)) and $nix.debug {
let numPackages = ($drv.initialPackages | length)
info $"Adding (blue ($numPackages | into string)) package(plural $numPackages) to PATH:"
for pkg in $drv.initialPackages {
let name = (getPkgName $nix.store $pkg)
item $name
}
}
# Collect all packages into a string and set the PATH
if $nix.debug { info $"Setting (purple "PATH")" }
let packagesPath = (
$drv.packages # List of strings
| each { |pkg| $"($pkg)/bin" } # Append /bin to each package path
| str join (char esep) # Collect into a single colon-separated string
)
$env.PATH = $packagesPath
# Set user-supplied environment variables (à la FOO="bar"). Nix supplies this
# list by removing reserved attributes (name, system, build, src, system, etc.).
let numAttrs = ($drv.extraAttrs | length)
if $numAttrs != 0 {
if $nix.debug { info $"Setting (blue ($numAttrs | into string)) user-supplied environment variable(plural $numAttrs):" }
for attr in $drv.extraAttrs {
if $nix.debug { item $"(yellow $attr.key) = \"($attr.value)\"" }
load-env {$attr.key: $attr.value}
}
}
# Copy sources into sandbox
if $nix.debug { info "Copying sources" }
for src in $drv.src { cp -r -f $src $nix.sandbox }
# Set environment variables for all outputs
if $nix.debug {
let numOutputs = ($drv.outputs | length)
info $"Setting (blue ($numOutputs | into string)) output environment variable(plural $numOutputs):"
}
for output in ($drv.outputs) {
let name = ($output | get key)
let value = ($output | get value)
if $nix.debug { item $"(yellow $name) = \"($value)\"" }
load-env {$name: $value}
}
## The realisation process
if $nix.debug { banner "REALISATION" }
## Realisation phases (just build and install for now, more later)
# Run a derivation phase (skip if empty)
def runPhase [
name: string,
] {
if $name in $attrs {
let phase = ($attrs | get $name)
if $nix.debug { info $"Running (blue $name) phase" }
# We need to source the envFile prior to each phase so that custom Nushell
# commands are registered. Right now there's a single env file but in
# principle there could be per-phase scripts.
do --capture-errors {
nu --log-level warn --env-config $nushell.userEnvFile --commands $phase | print
let exitCode = $env.LAST_EXIT_CODE
if ($exitCode | into int) != 0 {
exit $exitCode
}
}
} else if $nix.debug { info $"Skipping empty (blue $name) phase" }
}
# The available phases (just one for now)
let phases = [ "build" ]
for phase in $phases { runPhase $phase }
## Run if realisation succeeds
if $nix.debug {
info "Outputs written:"
for output in ($drv.outputs) {
let name = ($output | get key)
let value = ($output | get value)
item $"(yellow $name) to (purple $value)"
}
banner "DONE!"
}