style: format entire depot with nixpkgs-fmt

This CL can be used to compare the style of nixpkgs-fmt against other
formatters (nixpkgs, alejandra).

Change-Id: I87c6abff6bcb546b02ead15ad0405f81e01b6d9e
Reviewed-on: https://cl.tvl.fyi/c/depot/+/4397
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
Reviewed-by: lukegb <lukegb@tvl.fyi>
Reviewed-by: wpcarro <wpcarro@gmail.com>
Reviewed-by: Profpatsch <mail@profpatsch.de>
Reviewed-by: kanepyork <rikingcoding@gmail.com>
Reviewed-by: tazjin <tazjin@tvl.su>
Reviewed-by: cynthia <cynthia@tvl.fyi>
Reviewed-by: edef <edef@edef.eu>
Reviewed-by: eta <tvl@eta.st>
Reviewed-by: grfn <grfn@gws.fyi>
This commit is contained in:
Vincent Ambo 2022-01-30 19:06:58 +03:00 committed by tazjin
parent 2d10d60fac
commit aa122cbae7
310 changed files with 7278 additions and 5490 deletions

View file

@ -30,7 +30,8 @@ let
</style>
'';
};
in pkgs.runCommandNoCC "corp-website" {} ''
in
pkgs.runCommandNoCC "corp-website" { } ''
mkdir $out
cp ${index} $out/index.html
''

View file

@ -4,14 +4,16 @@
{ nixpkgsBisectPath ? null
, parentTargetMap ? null
, nixpkgsConfig ? {}, ... }@args:
, nixpkgsConfig ? { }
, ...
}@args:
let
inherit (builtins)
filter
;
readTree = import ./nix/readTree {};
readTree = import ./nix/readTree { };
# Disallow access to //users from other depot parts.
usersFilter = readTree.restrictFolder {
@ -70,7 +72,8 @@ let
# Is this tree node eligible for build inclusion?
eligible = node: (node ? outPath) && !(node.meta.ci.skip or false);
in readTree.fix(self: (readDepot {
in
readTree.fix (self: (readDepot {
depot = self;
# Pass third_party as 'pkgs' (for compatibility with external
@ -110,8 +113,10 @@ in readTree.fix(self: (readDepot {
});
# Derivation that gcroots all depot targets.
ci.gcroot = with self.third_party.nixpkgs; makeSetupHook {
name = "depot-gcroot";
deps = self.ci.targets;
} emptyFile;
ci.gcroot = with self.third_party.nixpkgs; makeSetupHook
{
name = "depot-gcroot";
deps = self.ci.targets;
}
emptyFile;
})

View file

@ -33,7 +33,8 @@ let
cp ${frontend} $out/index.html
''}/")
'';
in depot.nix.buildLisp.program {
in
depot.nix.buildLisp.program {
name = "gemma";
deps = with depot.third_party.lisp; [

View file

@ -4,19 +4,20 @@ let
inherit (pkgs) python3 python3Packages;
opts = {
pname = "idualctl";
pname = "idualctl";
version = "0.1";
src = ./.;
src = ./.;
propagatedBuildInputs = [
depot.third_party.python.broadlink
];
};
package = python3Packages.buildPythonPackage opts;
script = python3Packages.buildPythonApplication opts;
in depot.nix.readTree.drvTargets {
script = python3Packages.buildPythonApplication opts;
in
depot.nix.readTree.drvTargets {
inherit script;
python = python3.withPackages (_: [ package ]);
python = python3.withPackages (_: [ package ]);
setAlarm = pkgs.writeShellScriptBin "set-alarm" ''
echo "setting an alarm for ''${1}"
${pkgs.systemd}/bin/systemd-run --user --on-calendar="''${1} Europe/London" --unit=light-alarm.service

View file

@ -1,6 +1,7 @@
{ depot ? (import ../../../. {})
{ depot ? (import ../../../. { })
, pkgs ? depot.third_party.nixpkgs
, ... }:
, ...
}:
let
basePkg = pkgs.haskellPackages.callPackage ./pkg.nix { };

View file

@ -1,5 +1,15 @@
{ mkDerivation, base, bytestring, chatter, containers, envy
, irc-client, lens, lib, random, relude, text
{ mkDerivation
, base
, bytestring
, chatter
, containers
, envy
, irc-client
, lens
, lib
, random
, relude
, text
}:
mkDerivation {
pname = "owothia";
@ -8,8 +18,16 @@ mkDerivation {
isLibrary = false;
isExecutable = true;
executableHaskellDepends = [
base bytestring chatter containers envy irc-client lens random
relude text
base
bytestring
chatter
containers
envy
irc-client
lens
random
relude
text
];
license = "unknown";
hydraPlatforms = lib.platforms.none;

View file

@ -1,4 +1,4 @@
{ pkgs ? (import ../../../. {}).third_party, ... }:
{ pkgs ? (import ../../../. { }).third_party, ... }:
let
inherit (pkgs)

View file

@ -12,7 +12,8 @@ let
gopkgs."github.com".pkg.browser.gopkg
];
};
in uggc.overrideAttrs(old: {
in
uggc.overrideAttrs (old: {
buildCommand = old.buildCommand + ''
install -D ${./uggc.desktop} $out/share/applications/uggc.desktop
sed "s|@out@|$out|g" -i $out/share/applications/uggc.desktop

View file

@ -38,6 +38,7 @@ let
"ecl" # refuses to create non-ASCII paths even on POSIX…
];
};
in bin // {
in
bin // {
inherit lib;
}

View file

@ -10,7 +10,7 @@
# with `binify { exe = …; name = "hello" }`.
{ exe, name }:
pkgs.runCommandLocal "${name}-bin" {} ''
pkgs.runCommandLocal "${name}-bin" { } ''
mkdir -p $out/bin
ln -sT ${lib.escapeShellArg exe} $out/bin/${lib.escapeShellArg name}
''

View file

@ -4,8 +4,9 @@
# buildGo provides Nix functions to build Go packages in the style of Bazel's
# rules_go.
{ pkgs ? import <nixpkgs> {}
, ... }:
{ pkgs ? import <nixpkgs> { }
, ...
}:
let
inherit (builtins)
@ -40,7 +41,7 @@ let
xFlags = x_defs: spaceOut (map (k: "-X ${k}=${x_defs."${k}"}") (attrNames x_defs));
pathToName = p: replaceStrings ["/"] ["_"] (toString p);
pathToName = p: replaceStrings [ "/" ] [ "_" ] (toString p);
# Add an `overrideGo` attribute to a function result that works
# similar to `overrideAttrs`, but is used specifically for the
@ -52,49 +53,50 @@ let
# High-level build functions
# Build a Go program out of the specified files and dependencies.
program = { name, srcs, deps ? [], x_defs ? {} }:
let uniqueDeps = allDeps (map (d: d.gopkg) deps);
in runCommand name {} ''
${go}/bin/go tool compile -o ${name}.a -trimpath=$PWD -trimpath=${go} ${includeSources uniqueDeps} ${spaceOut srcs}
mkdir -p $out/bin
export GOROOT_FINAL=go
${go}/bin/go tool link -o $out/bin/${name} -buildid nix ${xFlags x_defs} ${includeLibs uniqueDeps} ${name}.a
'';
program = { name, srcs, deps ? [ ], x_defs ? { } }:
let uniqueDeps = allDeps (map (d: d.gopkg) deps);
in runCommand name { } ''
${go}/bin/go tool compile -o ${name}.a -trimpath=$PWD -trimpath=${go} ${includeSources uniqueDeps} ${spaceOut srcs}
mkdir -p $out/bin
export GOROOT_FINAL=go
${go}/bin/go tool link -o $out/bin/${name} -buildid nix ${xFlags x_defs} ${includeLibs uniqueDeps} ${name}.a
'';
# Build a Go library assembled out of the specified files.
#
# This outputs both the sources and compiled binary, as both are
# needed when downstream packages depend on it.
package = { name, srcs, deps ? [], path ? name, sfiles ? [] }:
let
uniqueDeps = allDeps (map (d: d.gopkg) deps);
package = { name, srcs, deps ? [ ], path ? name, sfiles ? [ ] }:
let
uniqueDeps = allDeps (map (d: d.gopkg) deps);
# The build steps below need to be executed conditionally for Go
# assembly if the analyser detected any *.s files.
#
# This is required for several popular packages (e.g. x/sys).
ifAsm = do: lib.optionalString (sfiles != []) do;
asmBuild = ifAsm ''
${go}/bin/go tool asm -trimpath $PWD -I $PWD -I ${go}/share/go/pkg/include -D GOOS_linux -D GOARCH_amd64 -gensymabis -o ./symabis ${spaceOut sfiles}
${go}/bin/go tool asm -trimpath $PWD -I $PWD -I ${go}/share/go/pkg/include -D GOOS_linux -D GOARCH_amd64 -o ./asm.o ${spaceOut sfiles}
'';
asmLink = ifAsm "-symabis ./symabis -asmhdr $out/go_asm.h";
asmPack = ifAsm ''
${go}/bin/go tool pack r $out/${path}.a ./asm.o
'';
# The build steps below need to be executed conditionally for Go
# assembly if the analyser detected any *.s files.
#
# This is required for several popular packages (e.g. x/sys).
ifAsm = do: lib.optionalString (sfiles != [ ]) do;
asmBuild = ifAsm ''
${go}/bin/go tool asm -trimpath $PWD -I $PWD -I ${go}/share/go/pkg/include -D GOOS_linux -D GOARCH_amd64 -gensymabis -o ./symabis ${spaceOut sfiles}
${go}/bin/go tool asm -trimpath $PWD -I $PWD -I ${go}/share/go/pkg/include -D GOOS_linux -D GOARCH_amd64 -o ./asm.o ${spaceOut sfiles}
'';
asmLink = ifAsm "-symabis ./symabis -asmhdr $out/go_asm.h";
asmPack = ifAsm ''
${go}/bin/go tool pack r $out/${path}.a ./asm.o
'';
gopkg = (runCommand "golib-${name}" {} ''
mkdir -p $out/${path}
${srcList path (map (s: "${s}") srcs)}
${asmBuild}
${go}/bin/go tool compile -pack ${asmLink} -o $out/${path}.a -trimpath=$PWD -trimpath=${go} -p ${path} ${includeSources uniqueDeps} ${spaceOut srcs}
${asmPack}
'') // {
inherit gopkg;
goDeps = uniqueDeps;
goImportPath = path;
};
in gopkg;
gopkg = (runCommand "golib-${name}" { } ''
mkdir -p $out/${path}
${srcList path (map (s: "${s}") srcs)}
${asmBuild}
${go}/bin/go tool compile -pack ${asmLink} -o $out/${path}.a -trimpath=$PWD -trimpath=${go} -p ${path} ${includeSources uniqueDeps} ${spaceOut srcs}
${asmPack}
'') // {
inherit gopkg;
goDeps = uniqueDeps;
goImportPath = path;
};
in
gopkg;
# Build a tree of Go libraries out of an external Go source
# directory that follows the standard Go layout and was not built
@ -110,10 +112,10 @@ let
};
# Build a Go library out of the specified protobuf definition.
proto = { name, proto, path ? name, goPackage ? name, extraDeps ? [] }: (makeOverridable package) {
proto = { name, proto, path ? name, goPackage ? name, extraDeps ? [ ] }: (makeOverridable package) {
inherit name path;
deps = [ protoLibs.goProto.proto.gopkg ] ++ extraDeps;
srcs = lib.singleton (runCommand "goproto-${name}.pb.go" {} ''
srcs = lib.singleton (runCommand "goproto-${name}.pb.go" { } ''
cp ${proto} ${baseNameOf proto}
${protobuf}/bin/protoc --plugin=${protoLibs.goProto.protoc-gen-go.gopkg}/bin/protoc-gen-go \
--go_out=plugins=grpc,import_path=${baseNameOf path}:. ${baseNameOf proto}
@ -124,7 +126,8 @@ let
# Build a Go library out of the specified gRPC definition.
grpc = args: proto (args // { extraDeps = [ protoLibs.goGrpc.gopkg ]; });
in {
in
{
# Only the high-level builder functions are exposed, but made
# overrideable.
program = makeOverridable program;

View file

@ -8,7 +8,7 @@
# users a quick introduction to how to use buildGo.
let
buildGo = import ../default.nix {};
buildGo = import ../default.nix { };
# Example use of buildGo.package, which creates an importable Go
# package from the specified source files.
@ -29,7 +29,8 @@ let
# Example use of buildGo.program, which builds an executable using
# the specified name and dependencies (which in turn must have been
# created via buildGo.package etc.)
in buildGo.program {
in
buildGo.program {
name = "example";
srcs = [

View file

@ -17,12 +17,12 @@ let
inherit (pkgs) lib runCommand go jq ripgrep;
pathToName = p: replaceStrings ["/"] ["_"] (toString p);
pathToName = p: replaceStrings [ "/" ] [ "_" ] (toString p);
# Collect all non-vendored dependencies from the Go standard library
# into a file that can be used to filter them out when processing
# dependencies.
stdlibPackages = runCommand "stdlib-pkgs.json" {} ''
stdlibPackages = runCommand "stdlib-pkgs.json" { } ''
export HOME=$PWD
export GOPATH=/dev/null
${go}/bin/go list std | \
@ -45,20 +45,28 @@ let
};
mkset = path: value:
if path == [] then { gopkg = value; }
if path == [ ] then { gopkg = value; }
else { "${head path}" = mkset (tail path) value; };
last = l: elemAt l ((length l) - 1);
toPackage = self: src: path: depMap: entry:
let
localDeps = map (d: lib.attrByPath (d ++ [ "gopkg" ]) (
throw "missing local dependency '${lib.concatStringsSep "." d}' in '${path}'"
) self) entry.localDeps;
localDeps = map
(d: lib.attrByPath (d ++ [ "gopkg" ])
(
throw "missing local dependency '${lib.concatStringsSep "." d}' in '${path}'"
)
self)
entry.localDeps;
foreignDeps = map (d: lib.attrByPath [ d.path ] (
throw "missing foreign dependency '${d.path}' in '${path}, imported at ${d.position}'"
) depMap) entry.foreignDeps;
foreignDeps = map
(d: lib.attrByPath [ d.path ]
(
throw "missing foreign dependency '${d.path}' in '${path}, imported at ${d.position}'"
)
depMap)
entry.foreignDeps;
args = {
srcs = map (f: src + ("/" + f)) entry.files;
@ -74,22 +82,28 @@ let
binArgs = args // {
name = (last ((lib.splitString "/" path) ++ entry.locator));
};
in if entry.isCommand then (program binArgs) else (package libArgs);
in
if entry.isCommand then (program binArgs) else (package libArgs);
in { src, path, deps ? [] }: let
in
{ src, path, deps ? [ ] }:
let
# Build a map of dependencies (from their import paths to their
# derivation) so that they can be conditionally imported only in
# sub-packages that require them.
depMap = listToAttrs (map (d: {
name = d.goImportPath;
value = d;
}) (map (d: d.gopkg) deps));
depMap = listToAttrs (map
(d: {
name = d.goImportPath;
value = d;
})
(map (d: d.gopkg) deps));
name = pathToName path;
analysisOutput = runCommand "${name}-structure.json" {} ''
analysisOutput = runCommand "${name}-structure.json" { } ''
${analyser}/bin/analyser -path ${path} -source ${src} > $out
'';
analysis = fromJSON (readFile analysisOutput);
in lib.fix(self: foldl' lib.recursiveUpdate {} (
in
lib.fix (self: foldl' lib.recursiveUpdate { } (
map (entry: mkset entry.locator (toPackage self src path depMap entry)) analysis
))

View file

@ -8,7 +8,8 @@
let
inherit (builtins) fetchGit map;
in rec {
in
rec {
goProto = external {
path = "github.com/golang/protobuf";
src = fetchGit {

View file

@ -4,7 +4,7 @@
# buildLisp is designed to enforce conventions and do away with the
# free-for-all of existing Lisp build systems.
{ pkgs ? import <nixpkgs> {}, ... }:
{ pkgs ? import <nixpkgs> { }, ... }:
let
inherit (builtins) map elemAt match filter;
@ -70,11 +70,16 @@ let
implFilter = impl: xs:
let
isFilterSet = x: builtins.isAttrs x && !(lib.isDerivation x);
in builtins.map (
x: if isFilterSet x then x.${impl.name} or x.default else x
) (builtins.filter (
x: !(isFilterSet x) || x ? ${impl.name} || x ? default
) xs);
in
builtins.map
(
x: if isFilterSet x then x.${impl.name} or x.default else x
)
(builtins.filter
(
x: !(isFilterSet x) || x ? ${impl.name} || x ? default
)
xs);
# Generates lisp code which instructs the given lisp implementation to load
# all the given dependencies.
@ -103,17 +108,21 @@ let
# 'allDeps' flattens the list of dependencies (and their
# dependencies) into one ordered list of unique deps which
# all use the given implementation.
allDeps = impl: deps: let
# The override _should_ propagate itself recursively, as every derivation
# would only expose its actually used dependencies. Use implementation
# attribute created by withExtras if present, override in all other cases
# (mainly bundled).
deps' = builtins.map (dep: dep."${impl.name}" or (dep.overrideLisp (_: {
implementation = impl;
}))) deps;
in (lib.toposort dependsOn (lib.unique (
lib.flatten (deps' ++ (map (d: d.lispDeps) deps'))
))).result;
allDeps = impl: deps:
let
# The override _should_ propagate itself recursively, as every derivation
# would only expose its actually used dependencies. Use implementation
# attribute created by withExtras if present, override in all other cases
# (mainly bundled).
deps' = builtins.map
(dep: dep."${impl.name}" or (dep.overrideLisp (_: {
implementation = impl;
})))
deps;
in
(lib.toposort dependsOn (lib.unique (
lib.flatten (deps' ++ (map (d: d.lispDeps) deps'))
))).result;
# 'allNative' extracts all native dependencies of a dependency list
# to ensure that library load paths are set correctly during all
@ -138,42 +147,49 @@ let
withExtras = f: args:
let
drv = (makeOverridable f) args;
in lib.fix (self:
drv.overrideLisp (old:
let
implementation = old.implementation or defaultImplementation;
brokenOn = old.brokenOn or [];
targets = lib.subtractLists (brokenOn ++ [ implementation.name ])
(builtins.attrNames impls);
in {
passthru = (old.passthru or {}) // {
repl = implementation.lispWith [ self ];
in
lib.fix (self:
drv.overrideLisp
(old:
let
implementation = old.implementation or defaultImplementation;
brokenOn = old.brokenOn or [ ];
targets = lib.subtractLists (brokenOn ++ [ implementation.name ])
(builtins.attrNames impls);
in
{
passthru = (old.passthru or { }) // {
repl = implementation.lispWith [ self ];
# meta is done via passthru to minimize rebuilds caused by overriding
meta = (old.passthru.meta or {}) // {
inherit targets;
};
} // builtins.listToAttrs (builtins.map (impl: {
inherit (impl) name;
value = self.overrideLisp (_: {
implementation = impl;
});
}) (builtins.attrValues impls));
}) // {
overrideLisp = new: withExtras f (args // new args);
});
# meta is done via passthru to minimize rebuilds caused by overriding
meta = (old.passthru.meta or { }) // {
inherit targets;
};
} // builtins.listToAttrs (builtins.map
(impl: {
inherit (impl) name;
value = self.overrideLisp (_: {
implementation = impl;
});
})
(builtins.attrValues impls));
}) // {
overrideLisp = new: withExtras f (args // new args);
});
# 'testSuite' builds a Common Lisp test suite that loads all of srcs and deps,
# and then executes expression to check its result
testSuite = { name, expression, srcs, deps ? [], native ? [], implementation }:
testSuite = { name, expression, srcs, deps ? [ ], native ? [ ], implementation }:
let
lispDeps = allDeps implementation (implFilter implementation deps);
lispNativeDeps = allNative native lispDeps;
filteredSrcs = implFilter implementation srcs;
in runCommandNoCC name {
LD_LIBRARY_PATH = lib.makeLibraryPath lispNativeDeps;
LANG = "C.UTF-8";
} ''
in
runCommandNoCC name
{
LD_LIBRARY_PATH = lib.makeLibraryPath lispNativeDeps;
LANG = "C.UTF-8";
} ''
echo "Running test suite ${name}"
${implementation.runScript} ${
@ -452,15 +468,16 @@ let
} $@
'';
bundled = name: runCommandNoCC "${name}-cllib" {
passthru = {
lispName = name;
lispNativeDeps = [];
lispDeps = [];
lispBinary = false;
repl = impls.ecl.lispWith [ (impls.ecl.bundled name) ];
};
} ''
bundled = name: runCommandNoCC "${name}-cllib"
{
passthru = {
lispName = name;
lispNativeDeps = [ ];
lispDeps = [ ];
lispBinary = false;
repl = impls.ecl.lispWith [ (impls.ecl.bundled name) ];
};
} ''
mkdir -p "$out"
ln -s "${ecl-static}/lib/ecl-${ecl-static.version}/${name}.${impls.ecl.faslExt}" -t "$out"
ln -s "${ecl-static}/lib/ecl-${ecl-static.version}/lib${name}.a" "$out/${name}.a"
@ -489,7 +506,8 @@ let
# See https://ccl.clozure.com/docs/ccl.html#building-definitions
faslExt =
/**/ if targetPlatform.isPowerPC && targetPlatform.is32bit then "pfsl"
/**/
if targetPlatform.isPowerPC && targetPlatform.is32bit then "pfsl"
else if targetPlatform.isPowerPC && targetPlatform.is64bit then "p64fsl"
else if targetPlatform.isx86_64 && targetPlatform.isLinux then "lx64fsl"
else if targetPlatform.isx86_32 && targetPlatform.isLinux then "lx32fsl"
@ -572,7 +590,7 @@ let
lib.optionalString (deps != [])
"--load ${writeText "load.lisp" (impls.ccl.genLoadLisp lispDeps)}"
} "$@"
'';
'';
};
};
@ -586,37 +604,42 @@ let
library =
{ name
, implementation ? defaultImplementation
, brokenOn ? [] # TODO(sterni): make this a warning
, brokenOn ? [ ] # TODO(sterni): make this a warning
, srcs
, deps ? []
, native ? []
, deps ? [ ]
, native ? [ ]
, tests ? null
, passthru ? {}
, passthru ? { }
}:
let
filteredDeps = implFilter implementation deps;
filteredSrcs = implFilter implementation srcs;
lispNativeDeps = (allNative native filteredDeps);
lispDeps = allDeps implementation filteredDeps;
testDrv = if ! isNull tests
then testSuite {
name = tests.name or "${name}-test";
srcs = filteredSrcs ++ (tests.srcs or []);
deps = filteredDeps ++ (tests.deps or []);
expression = tests.expression;
inherit implementation;
}
testDrv =
if ! isNull tests
then
testSuite
{
name = tests.name or "${name}-test";
srcs = filteredSrcs ++ (tests.srcs or [ ]);
deps = filteredDeps ++ (tests.deps or [ ]);
expression = tests.expression;
inherit implementation;
}
else null;
in lib.fix (self: runCommandNoCC "${name}-cllib" {
LD_LIBRARY_PATH = lib.makeLibraryPath lispNativeDeps;
LANG = "C.UTF-8";
passthru = passthru // {
inherit lispNativeDeps lispDeps;
lispName = name;
lispBinary = false;
tests = testDrv;
};
} ''
in
lib.fix (self: runCommandNoCC "${name}-cllib"
{
LD_LIBRARY_PATH = lib.makeLibraryPath lispNativeDeps;
LANG = "C.UTF-8";
passthru = passthru // {
inherit lispNativeDeps lispDeps;
lispName = name;
lispBinary = false;
tests = testDrv;
};
} ''
${if ! isNull testDrv
then "echo 'Test ${testDrv} succeeded'"
else "echo 'No tests run'"}
@ -637,13 +660,13 @@ let
program =
{ name
, implementation ? defaultImplementation
, brokenOn ? [] # TODO(sterni): make this a warning
, brokenOn ? [ ] # TODO(sterni): make this a warning
, main ? "${name}:main"
, srcs
, deps ? []
, native ? []
, deps ? [ ]
, native ? [ ]
, tests ? null
, passthru ? {}
, passthru ? { }
}:
let
filteredSrcs = implFilter implementation srcs;
@ -656,45 +679,53 @@ let
deps = lispDeps;
srcs = filteredSrcs;
};
testDrv = if ! isNull tests
then testSuite {
name = tests.name or "${name}-test";
srcs =
( # testSuite does run implFilter as well
filteredSrcs ++ (tests.srcs or []));
deps = filteredDeps ++ (tests.deps or []);
expression = tests.expression;
inherit implementation;
}
testDrv =
if ! isNull tests
then
testSuite
{
name = tests.name or "${name}-test";
srcs =
(
# testSuite does run implFilter as well
filteredSrcs ++ (tests.srcs or [ ])
);
deps = filteredDeps ++ (tests.deps or [ ]);
expression = tests.expression;
inherit implementation;
}
else null;
in lib.fix (self: runCommandNoCC "${name}" {
nativeBuildInputs = [ makeWrapper ];
LD_LIBRARY_PATH = libPath;
LANG = "C.UTF-8";
passthru = passthru // {
lispName = name;
lispDeps = [ selfLib ];
lispNativeDeps = native;
lispBinary = true;
tests = testDrv;
};
} (''
${if ! isNull testDrv
then "echo 'Test ${testDrv} succeeded'"
else ""}
mkdir -p $out/bin
${implementation.runScript} ${
implementation.genDumpLisp {
inherit name main;
deps = ([ selfLib ] ++ lispDeps);
}
in
lib.fix (self: runCommandNoCC "${name}"
{
nativeBuildInputs = [ makeWrapper ];
LD_LIBRARY_PATH = libPath;
LANG = "C.UTF-8";
passthru = passthru // {
lispName = name;
lispDeps = [ selfLib ];
lispNativeDeps = native;
lispBinary = true;
tests = testDrv;
};
}
'' + lib.optionalString implementation.wrapProgram ''
wrapProgram $out/bin/${name} \
--prefix LD_LIBRARY_PATH : "${libPath}" \
--add-flags "\$NIX_BUILDLISP_LISP_ARGS --"
''));
(''
${if ! isNull testDrv
then "echo 'Test ${testDrv} succeeded'"
else ""}
mkdir -p $out/bin
${implementation.runScript} ${
implementation.genDumpLisp {
inherit name main;
deps = ([ selfLib ] ++ lispDeps);
}
}
'' + lib.optionalString implementation.wrapProgram ''
wrapProgram $out/bin/${name} \
--prefix LD_LIBRARY_PATH : "${libPath}" \
--add-flags "\$NIX_BUILDLISP_LISP_ARGS --"
''));
# 'bundled' creates a "library" which makes a built-in package available,
# such as any of SBCL's sb-* packages or ASDF. By default this is done
@ -714,11 +745,13 @@ let
}:
implementation.bundled or (defaultBundled implementation) name;
in (makeOverridable bundled') {
in
(makeOverridable bundled') {
inherit name;
};
in {
in
{
library = withExtras library;
program = withExtras program;
inherit bundled;

View file

@ -14,15 +14,16 @@ let
];
};
# Example Lisp program.
#
# This builds & writes an executable for a program using the library
# above to disk.
#
# By default, buildLisp.program expects the entry point to be
# `$name:main`. This can be overridden by configuring the `main`
# attribute.
in buildLisp.program {
# Example Lisp program.
#
# This builds & writes an executable for a program using the library
# above to disk.
#
# By default, buildLisp.program expects the entry point to be
# `$name:main`. This can be overridden by configuring the `main`
# attribute.
in
buildLisp.program {
name = "example";
deps = [ libExample ];

View file

@ -13,9 +13,9 @@ let
;
bins = getBins mandoc [ "mandoc" ]
// getBins gzip [ "gzip" ]
// getBins coreutils [ "mkdir" "ln" "cp" ]
;
// getBins gzip [ "gzip" ]
// getBins coreutils [ "mkdir" "ln" "cp" ]
;
defaultGzip = true;
@ -35,41 +35,68 @@ let
}:
{ content
, ...
}@page: let
}@page:
let
source = builtins.toFile (basename false page) content;
in runExecline (basename gzip page) {} ([
(if requireLint then "if" else "foreground") [
bins.mandoc "-mdoc" "-T" "lint" source
in
runExecline (basename gzip page) { } ([
(if requireLint then "if" else "foreground")
[
bins.mandoc
"-mdoc"
"-T"
"lint"
source
]
"importas" "out" "out"
"importas"
"out"
"out"
] ++ (if gzip then [
"redirfd" "-w" "1" "$out"
bins.gzip "-c" source
"redirfd"
"-w"
"1"
"$out"
bins.gzip
"-c"
source
] else [
bins.cp "--reflink=auto" source "$out"
bins.cp
"--reflink=auto"
source
"$out"
]));
buildManPages =
name:
{ derivationArgs ? {}
{ derivationArgs ? { }
, gzip ? defaultGzip
, ...
}@args:
pages:
runExecline "${name}-man-pages" {
inherit derivationArgs;
} ([
"importas" "out" "out"
] ++ lib.concatMap ({ name, section, content }@page: [
"if" [ bins.mkdir "-p" (manDir page) ]
"if" [
bins.ln "-s"
(buildManPage args page)
(target gzip page)
]
]) pages);
runExecline "${name}-man-pages"
{
inherit derivationArgs;
}
([
"importas"
"out"
"out"
] ++ lib.concatMap
({ name, section, content }@page: [
"if"
[ bins.mkdir "-p" (manDir page) ]
"if"
[
bins.ln
"-s"
(buildManPage args page)
(target gzip page)
]
])
pages);
in {
in
{
__functor = _: buildManPages;
single = buildManPage;

View file

@ -29,7 +29,8 @@ let
unsafeDiscardStringContext;
inherit (pkgs) lib runCommandNoCC writeText;
in rec {
in
rec {
# Creates a Nix expression that yields the target at the specified
# location in the repository.
#
@ -42,14 +43,15 @@ in rec {
descend = expr: attr: "builtins.getAttr \"${attr}\" (${expr})";
targetExpr = foldl' descend "import ./. {}" target.__readTree;
subtargetExpr = descend targetExpr target.__subtarget;
in if target ? __subtarget then subtargetExpr else targetExpr;
in
if target ? __subtarget then subtargetExpr else targetExpr;
# Create a pipeline label from the target's tree location.
mkLabel = target:
let label = concatStringsSep "/" target.__readTree;
in if target ? __subtarget
then "${label}:${target.__subtarget}"
else label;
then "${label}:${target.__subtarget}"
else label;
# Determine whether to skip a target if it has not diverged from the
# HEAD branch.
@ -74,33 +76,36 @@ in rec {
# Create a pipeline step from a single target.
mkStep = headBranch: parentTargetMap: target:
let
label = mkLabel target;
drvPath = unsafeDiscardStringContext target.drvPath;
shouldSkip' = shouldSkip parentTargetMap;
in {
label = ":nix: " + label;
key = hashString "sha1" label;
skip = shouldSkip' label drvPath;
command = mkBuildCommand target drvPath;
env.READTREE_TARGET = label;
let
label = mkLabel target;
drvPath = unsafeDiscardStringContext target.drvPath;
shouldSkip' = shouldSkip parentTargetMap;
in
{
label = ":nix: " + label;
key = hashString "sha1" label;
skip = shouldSkip' label drvPath;
command = mkBuildCommand target drvPath;
env.READTREE_TARGET = label;
# Add a dependency on the initial static pipeline step which
# always runs. This allows build steps uploaded in batches to
# start running before all batches have been uploaded.
depends_on = ":init:";
};
# Add a dependency on the initial static pipeline step which
# always runs. This allows build steps uploaded in batches to
# start running before all batches have been uploaded.
depends_on = ":init:";
};
# Helper function to inelegantly divide a list into chunks of at
# most n elements.
#
# This works by assigning each element a chunk ID based on its
# index, and then grouping all elements by their chunk ID.
chunksOf = n: list: let
chunkId = idx: toString (idx / n + 1);
assigned = lib.imap1 (idx: value: { inherit value ; chunk = chunkId idx; }) list;
unchunk = mapAttrs (_: elements: map (e: e.value) elements);
in unchunk (lib.groupBy (e: e.chunk) assigned);
chunksOf = n: list:
let
chunkId = idx: toString (idx / n + 1);
assigned = lib.imap1 (idx: value: { inherit value; chunk = chunkId idx; }) list;
unchunk = mapAttrs (_: elements: map (e: e.value) elements);
in
unchunk (lib.groupBy (e: e.chunk) assigned);
# Define a build pipeline chunk as a JSON file, using the pipeline
# format documented on
@ -120,104 +125,112 @@ in rec {
attrValues (mapAttrs (makePipelineChunk name) (chunksOf 192 steps));
# Create a pipeline structure for the given targets.
mkPipeline = {
# HEAD branch of the repository on which release steps, GC
# anchoring and other "mainline only" steps should run.
headBranch,
mkPipeline =
{
# HEAD branch of the repository on which release steps, GC
# anchoring and other "mainline only" steps should run.
headBranch
, # List of derivations as read by readTree (in most cases just the
# output of readTree.gather) that should be built in Buildkite.
#
# These are scheduled as the first build steps and run as fast as
# possible, in order, without any concurrency restrictions.
drvTargets
, # Derivation map of a parent commit. Only targets which no longer
# correspond to the content of this map will be built. Passing an
# empty map will always build all targets.
parentTargetMap ? { }
, # A list of plain Buildkite step structures to run alongside the
# build for all drvTargets, but before proceeding with any
# post-build actions such as status reporting.
#
# Can be used for things like code formatting checks.
additionalSteps ? [ ]
, # A list of plain Buildkite step structures to run after all
# previous steps succeeded.
#
# Can be used for status reporting steps and the like.
postBuildSteps ? [ ]
}:
let
# Convert a target into all of its build and post-build steps,
# treated separately as they need to be in different chunks.
targetToSteps = target:
let
step = mkStep headBranch parentTargetMap target;
# List of derivations as read by readTree (in most cases just the
# output of readTree.gather) that should be built in Buildkite.
#
# These are scheduled as the first build steps and run as fast as
# possible, in order, without any concurrency restrictions.
drvTargets,
# Split build/post-build steps
splitExtraSteps = partition ({ postStep, ... }: postStep)
(attrValues (mapAttrs
(name: value: {
inherit name value;
postStep = (value ? prompt) || (value.postBuild or false);
})
(target.meta.ci.extraSteps or { })));
# Derivation map of a parent commit. Only targets which no longer
# correspond to the content of this map will be built. Passing an
# empty map will always build all targets.
parentTargetMap ? {},
mkExtraStep' = { name, value, ... }: mkExtraStep step name value;
extraBuildSteps = map mkExtraStep' splitExtraSteps.wrong; # 'wrong' -> no prompt
extraPostSteps = map mkExtraStep' splitExtraSteps.right; # 'right' -> has prompt
in
{
buildSteps = [ step ] ++ extraBuildSteps;
postSteps = extraPostSteps;
};
# A list of plain Buildkite step structures to run alongside the
# build for all drvTargets, but before proceeding with any
# post-build actions such as status reporting.
#
# Can be used for things like code formatting checks.
additionalSteps ? [],
# Combine all target steps into separate build and post-build step lists.
steps = foldl'
(acc: t: {
buildSteps = acc.buildSteps ++ t.buildSteps;
postSteps = acc.postSteps ++ t.postSteps;
})
{ buildSteps = [ ]; postSteps = [ ]; }
(map targetToSteps drvTargets);
# A list of plain Buildkite step structures to run after all
# previous steps succeeded.
#
# Can be used for status reporting steps and the like.
postBuildSteps ? []
}: let
# Convert a target into all of its build and post-build steps,
# treated separately as they need to be in different chunks.
targetToSteps = target: let
step = mkStep headBranch parentTargetMap target;
buildSteps =
# Add build steps for each derivation target and their extra
# steps.
steps.buildSteps
# Split build/post-build steps
splitExtraSteps = partition ({ postStep, ... }: postStep)
(attrValues (mapAttrs (name: value: {
inherit name value;
postStep = (value ? prompt) || (value.postBuild or false);
}) (target.meta.ci.extraSteps or {})));
# Add additional steps (if set).
++ additionalSteps;
mkExtraStep' = { name, value, ... }: mkExtraStep step name value;
extraBuildSteps = map mkExtraStep' splitExtraSteps.wrong; # 'wrong' -> no prompt
extraPostSteps = map mkExtraStep' splitExtraSteps.right; # 'right' -> has prompt
in {
buildSteps = [ step ] ++ extraBuildSteps;
postSteps = extraPostSteps;
};
postSteps =
# Add post-build steps for each derivation target.
steps.postSteps
# Combine all target steps into separate build and post-build step lists.
steps = foldl' (acc: t: {
buildSteps = acc.buildSteps ++ t.buildSteps;
postSteps = acc.postSteps ++ t.postSteps;
}) { buildSteps = []; postSteps = []; } (map targetToSteps drvTargets);
# Add any globally defined post-build steps.
++ postBuildSteps;
buildSteps =
# Add build steps for each derivation target and their extra
# steps.
steps.buildSteps
# Add additional steps (if set).
++ additionalSteps;
postSteps =
# Add post-build steps for each derivation target.
steps.postSteps
# Add any globally defined post-build steps.
++ postBuildSteps;
buildChunks = pipelineChunks "build" buildSteps;
postBuildChunks = pipelineChunks "post" postSteps;
chunks = buildChunks ++ postBuildChunks;
in runCommandNoCC "buildkite-pipeline" {} ''
mkdir $out
echo "Generated ${toString (length chunks)} pipeline chunks"
${
lib.concatMapStringsSep "\n"
(chunk: "cp ${chunk.path} $out/${chunk.filename}") chunks
}
'';
buildChunks = pipelineChunks "build" buildSteps;
postBuildChunks = pipelineChunks "post" postSteps;
chunks = buildChunks ++ postBuildChunks;
in
runCommandNoCC "buildkite-pipeline" { } ''
mkdir $out
echo "Generated ${toString (length chunks)} pipeline chunks"
${
lib.concatMapStringsSep "\n"
(chunk: "cp ${chunk.path} $out/${chunk.filename}") chunks
}
'';
# Create a drvmap structure for the given targets, containing the
# mapping of all target paths to their derivations. The mapping can
# be persisted for future use.
mkDrvmap = drvTargets: writeText "drvmap.json" (toJSON (listToAttrs (map (target: {
name = mkLabel target;
value = {
drvPath = unsafeDiscardStringContext target.drvPath;
mkDrvmap = drvTargets: writeText "drvmap.json" (toJSON (listToAttrs (map
(target: {
name = mkLabel target;
value = {
drvPath = unsafeDiscardStringContext target.drvPath;
# Include the attrPath in the output to reconstruct the drv
# without parsing the human-readable label.
attrPath = target.__readTree ++ lib.optionals (target ? __subtarget) [
target.__subtarget
];
};
}) drvTargets)));
# Include the attrPath in the output to reconstruct the drv
# without parsing the human-readable label.
attrPath = target.__readTree ++ lib.optionals (target ? __subtarget) [
target.__subtarget
];
};
})
drvTargets)));
# Implementation of extra step logic.
#
@ -278,34 +291,37 @@ in rec {
# Create the Buildkite configuration for an extra step, optionally
# wrapping it in a gate group.
mkExtraStep = parent: key: {
command,
label ? key,
prompt ? false,
needsOutput ? false,
branches ? null,
alwaysRun ? false,
postBuild ? false
}@cfg: let
parentLabel = parent.env.READTREE_TARGET;
mkExtraStep = parent: key: { command
, label ? key
, prompt ? false
, needsOutput ? false
, branches ? null
, alwaysRun ? false
, postBuild ? false
}@cfg:
let
parentLabel = parent.env.READTREE_TARGET;
step = {
label = ":gear: ${label} (from ${parentLabel})";
skip = if alwaysRun then false else parent.skip or false;
depends_on = lib.optional (!alwaysRun && !needsOutput) parent.key;
branches = if branches != null then lib.concatStringsSep " " branches else null;
step = {
label = ":gear: ${label} (from ${parentLabel})";
skip = if alwaysRun then false else parent.skip or false;
depends_on = lib.optional (!alwaysRun && !needsOutput) parent.key;
branches = if branches != null then lib.concatStringsSep " " branches else null;
command = pkgs.writeShellScript "${key}-script" ''
set -ueo pipefail
${lib.optionalString needsOutput "echo '~~~ Preparing build output of ${parentLabel}'"}
${lib.optionalString needsOutput parent.command}
echo '+++ Running extra step command'
exec ${command}
'';
};
in if (isString prompt)
then mkGatedStep {
inherit step label parent prompt;
}
command = pkgs.writeShellScript "${key}-script" ''
set -ueo pipefail
${lib.optionalString needsOutput "echo '~~~ Preparing build output of ${parentLabel}'"}
${lib.optionalString needsOutput parent.command}
echo '+++ Running extra step command'
exec ${command}
'';
};
in
if (isString prompt)
then
mkGatedStep
{
inherit step label parent prompt;
}
else step;
}

View file

@ -17,9 +17,10 @@ let
drvSeqL = defun [ (list drv) drv drv ]
(drvDeps: drvOut:
let
drvOutOutputs = drvOut.outputs or ["out"];
drvOutOutputs = drvOut.outputs or [ "out" ];
in
pkgs.runCommandLocal drvOut.name {
pkgs.runCommandLocal drvOut.name
{
# we inherit all attributes in order to replicate
# the original derivation as much as possible
outputs = drvOutOutputs;
@ -29,15 +30,18 @@ let
}
# the outputs of the original derivation are replicated
# by creating a symlink to the old output path
(lib.concatMapStrings (output: ''
target=${lib.escapeShellArg drvOut.${output}}
# if the target is already a symlink, follow it until its not;
# this is done to prevent too many dereferences
target=$(readlink -e "$target")
# link to the output
ln -s "$target" "${"$"}${output}"
'') drvOutOutputs));
(lib.concatMapStrings
(output: ''
target=${lib.escapeShellArg drvOut.${output}}
# if the target is already a symlink, follow it until its not;
# this is done to prevent too many dereferences
target=$(readlink -e "$target")
# link to the output
ln -s "$target" "${"$"}${output}"
'')
drvOutOutputs));
in {
in
{
__functor = _: drvSeqL;
}

View file

@ -14,7 +14,8 @@ let
inherit (depot.nix.runTestsuite) runTestsuite it assertEq;
};
in {
in
{
__functor = _: emptyDerivation;
inherit tests;
}

View file

@ -11,7 +11,7 @@
let
bins = getBins pkgs.s6-portable-utils [ "s6-touch" ]
// getBins pkgs.execline [ "importas" "exec" ];
// getBins pkgs.execline [ "importas" "exec" ];
emptiness = {
name = "empty-derivation";
@ -21,12 +21,16 @@ let
builder = bins.exec;
args = [
bins.importas "out" "out"
bins.s6-touch "$out"
bins.importas
"out"
"out"
bins.s6-touch
"$out"
];
};
in (derivation emptiness) // {
in
(derivation emptiness) // {
# This allows us to call the empty derivation
# like a function and override fields/add new fields.
__functor = _: overrides:

View file

@ -10,10 +10,17 @@ let
];
fooOut = emptyDerivation {
builder = writeExecline "foo-builder" {} [
"importas" "out" "out"
"redirfd" "-w" "1" "$out"
bins.s6-echo "-n" "foo"
builder = writeExecline "foo-builder" { } [
"importas"
"out"
"out"
"redirfd"
"-w"
"1"
"$out"
bins.s6-echo
"-n"
"foo"
];
};
@ -26,7 +33,8 @@ let
"bar")
];
in runTestsuite "emptyDerivation" [
in
runTestsuite "emptyDerivation" [
empty
overrideBuilder
]

View file

@ -16,14 +16,17 @@ let
# escapeExecline [ "if" [ "somecommand" ] "true" ]
# == ''"if" { "somecommand" } "true"''
escapeExecline = execlineList: lib.concatStringsSep " "
(let
go = arg:
if builtins.isString arg then [(escapeExeclineArg arg)]
else if builtins.isPath arg then [(escapeExeclineArg "${arg}")]
else if lib.isDerivation arg then [(escapeExeclineArg arg)]
else if builtins.isList arg then [ "{" ] ++ builtins.concatMap go arg ++ [ "}" ]
else abort "escapeExecline can only hande nested lists of strings, was ${lib.generators.toPretty {} arg}";
in builtins.concatMap go execlineList);
(
let
go = arg:
if builtins.isString arg then [ (escapeExeclineArg arg) ]
else if builtins.isPath arg then [ (escapeExeclineArg "${arg}") ]
else if lib.isDerivation arg then [ (escapeExeclineArg arg) ]
else if builtins.isList arg then [ "{" ] ++ builtins.concatMap go arg ++ [ "}" ]
else abort "escapeExecline can only hande nested lists of strings, was ${lib.generators.toPretty {} arg}";
in
builtins.concatMap go execlineList
);
in
escapeExecline

View file

@ -26,14 +26,16 @@
let
getBins = drv: xs:
let f = x:
# TODO(Profpatsch): typecheck
let x' = if builtins.isString x then { use = x; as = x; } else x;
in {
name = x'.as;
value = "${lib.getBin drv}/bin/${x'.use}";
};
in builtins.listToAttrs (builtins.map f xs);
let
f = x:
# TODO(Profpatsch): typecheck
let x' = if builtins.isString x then { use = x; as = x; } else x;
in {
name = x'.as;
value = "${lib.getBin drv}/bin/${x'.use}";
};
in
builtins.listToAttrs (builtins.map f xs);
tests = import ./tests.nix {
@ -42,7 +44,8 @@ let
inherit (depot.nix.runTestsuite) assertEq it runTestsuite;
};
in {
in
{
__functor = _: getBins;
inherit tests;
}

View file

@ -5,11 +5,11 @@ let
drv2 = writeScriptBin "goodbye" "tschau";
bins = getBins drv [
"hello"
{ use = "hello"; as = "also-hello"; }
]
// getBins drv2 [ "goodbye" ]
;
"hello"
{ use = "hello"; as = "also-hello"; }
]
// getBins drv2 [ "goodbye" ]
;
simple = it "path is equal to the executable name" [
(assertEq "path"
@ -33,8 +33,8 @@ let
];
in
runTestsuite "getBins" [
simple
useAs
secondDrv
]
runTestsuite "getBins" [
simple
useAs
secondDrv
]

View file

@ -8,31 +8,31 @@
For example, given the following original document:
{
a = "b";
c = {
a = "b";
c = {
d = "e";
f = "g";
}
}
}
Changing the value of `a` and removing `f` can be achieved by merging the patch
{
a = "z";
c.f = null;
a = "z";
c.f = null;
}
which results in
{
a = "z";
c = {
a = "z";
c = {
d = "e";
};
};
}
Pseudo-code:
define MergePatch(Target, Patch):
define MergePatch(Target, Patch):
if Patch is an Object:
if Target is not an Object:
Target = {} # Ignore the contents and set it to an empty Object
@ -55,19 +55,19 @@ let
mergePatch = target: patch:
if lib.isAttrs patch
then
let target' = if lib.isAttrs target then target else {};
let target' = if lib.isAttrs target then target else { };
in foldlAttrs
(acc: patchEl:
if patchEl.value == null
then removeAttrs acc [ patchEl.name ]
else acc // {
${patchEl.name} =
mergePatch
(acc.${patchEl.name} or "unnused")
patchEl.value;
})
target'
patch
(acc: patchEl:
if patchEl.value == null
then removeAttrs acc [ patchEl.name ]
else acc // {
${patchEl.name} =
mergePatch
(acc.${patchEl.name} or "unnused")
patchEl.value;
})
target'
patch
else patch;
inherit (depot.nix.runTestsuite)
@ -93,46 +93,49 @@ let
};
emptyPatch = it "the empty patch returns the original target" [
(assertEq "id"
(mergePatch testTarget {})
(mergePatch testTarget { })
testTarget)
];
nonAttrs = it "one side is a non-attrset value" [
(assertEq "target is a value means the value is replaced by the patch"
(mergePatch 42 testPatch)
(mergePatch {} testPatch))
(mergePatch { } testPatch))
(assertEq "patch is a value means it replaces target alltogether"
(mergePatch testTarget 42)
42)
];
rfcExamples = it "the examples from the RFC" [
(assertEq "a subset is deleted and overwritten"
(mergePatch testTarget testPatch) {
(mergePatch testTarget testPatch)
{
a = "z";
c = {
d = "e";
};
})
(assertEq "a more complicated example from the example section"
(mergePatch {
title = "Goodbye!";
(mergePatch
{
title = "Goodbye!";
author = {
givenName = "John";
familyName = "Doe";
};
tags = [ "example" "sample" ];
content = "This will be unchanged";
} {
title = "Hello!";
phoneNumber = "+01-123-456-7890";
author.familyName = null;
tags = [ "example" ];
})
tags = [ "example" "sample" ];
content = "This will be unchanged";
}
{
title = "Hello!";
phoneNumber = "+01-123-456-7890";
author.familyName = null;
tags = [ "example" ];
})
{
title = "Hello!";
phoneNumber = "+01-123-456-7890";
author = {
givenName = "John";
};
author = {
givenName = "John";
};
tags = [ "example" ];
content = "This will be unchanged";
})
@ -144,42 +147,45 @@ let
(assertEq "test number ${toString index}"
(mergePatch target patch)
res);
in it "the test suite from the RFC" [
(r 1 {"a" = "b";} {"a" = "c";} {"a" = "c";})
(r 2 {"a" = "b";} {"b" = "c";} {"a" = "b"; "b" = "c";})
(r 3 {"a" = "b";} {"a" = null;} {})
(r 4 {"a" = "b"; "b" = "c";}
{"a" = null;}
{"b" = "c";})
(r 5 {"a" = ["b"];} {"a" = "c";} {"a" = "c";})
(r 6 {"a" = "c";} {"a" = ["b"];} {"a" = ["b"];})
(r 7 {"a" = {"b" = "c";}; }
{"a" = {"b" = "d"; "c" = null;};}
{"a" = {"b" = "d";};})
(r 8 {"a" = [{"b" = "c";}];}
{"a" = [1];}
{"a" = [1];})
(r 9 ["a" "b"] ["c" "d"] ["c" "d"])
(r 10 {"a" = "b";} ["c"] ["c"])
(r 11 {"a" = "foo";} null null)
(r 12 {"a" = "foo";} "bar" "bar")
(r 13 {"e" = null;} {"a" = 1;} {"e" = null; "a" = 1;})
(r 14 [1 2]
{"a" = "b"; "c" = null;}
{"a" = "b";})
(r 15 {}
{"a" = {"bb" = {"ccc" = null;};};}
{"a" = {"bb" = {};};})
];
in
it "the test suite from the RFC" [
(r 1 { "a" = "b"; } { "a" = "c"; } { "a" = "c"; })
(r 2 { "a" = "b"; } { "b" = "c"; } { "a" = "b"; "b" = "c"; })
(r 3 { "a" = "b"; } { "a" = null; } { })
(r 4 { "a" = "b"; "b" = "c"; }
{ "a" = null; }
{ "b" = "c"; })
(r 5 { "a" = [ "b" ]; } { "a" = "c"; } { "a" = "c"; })
(r 6 { "a" = "c"; } { "a" = [ "b" ]; } { "a" = [ "b" ]; })
(r 7 { "a" = { "b" = "c"; }; }
{ "a" = { "b" = "d"; "c" = null; }; }
{ "a" = { "b" = "d"; }; })
(r 8 { "a" = [{ "b" = "c"; }]; }
{ "a" = [ 1 ]; }
{ "a" = [ 1 ]; })
(r 9 [ "a" "b" ] [ "c" "d" ] [ "c" "d" ])
(r 10 { "a" = "b"; } [ "c" ] [ "c" ])
(r 11 { "a" = "foo"; } null null)
(r 12 { "a" = "foo"; } "bar" "bar")
(r 13 { "e" = null; } { "a" = 1; } { "e" = null; "a" = 1; })
(r 14 [ 1 2 ]
{ "a" = "b"; "c" = null; }
{ "a" = "b"; })
(r 15 { }
{ "a" = { "bb" = { "ccc" = null; }; }; }
{ "a" = { "bb" = { }; }; })
];
in runTestsuite "mergePatch" [
in
runTestsuite "mergePatch" [
emptyPatch
nonAttrs
rfcExamples
rfcTests
];
in {
in
{
__functor = _: mergePatch;
inherit tests;

View file

@ -28,6 +28,6 @@ attrs:
lib.concatStrings
(lib.mapAttrsToList
(k: v: depot.nix.netstring.fromString
( depot.nix.netstring.fromString k
+ depot.nix.netstring.fromString v))
(depot.nix.netstring.fromString k
+ depot.nix.netstring.fromString v))
attrs)

View file

@ -6,9 +6,11 @@ let
;
in
rustSimpleBin {
name = "nint";
dependencies = [
depot.third_party.rust-crates.serde_json
];
} (builtins.readFile ./nint.rs)
rustSimpleBin
{
name = "nint";
dependencies = [
depot.third_party.rust-crates.serde_json
];
}
(builtins.readFile ./nint.rs)

View file

@ -43,10 +43,13 @@ let
children = readDir path;
isVisible = f: f == ".skip-subtree" || (substring 0 1 f) != ".";
names = filter isVisible (attrNames children);
in listToAttrs (map (name: {
inherit name;
value = children.${name};
}) names);
in
listToAttrs (map
(name: {
inherit name;
value = children.${name};
})
names);
# Create a mark containing the location of this attribute and
# a list of all child attribute names added by readTree.
@ -57,12 +60,13 @@ let
# Import a file and enforce our calling convention
importFile = args: scopedArgs: path: parts: filter:
let
importedFile = if scopedArgs != {}
then builtins.scopedImport scopedArgs path
else import path;
let
importedFile =
if scopedArgs != { }
then builtins.scopedImport scopedArgs path
else import path;
pathType = builtins.typeOf importedFile;
in
in
if pathType != "lambda"
then builtins.throw "readTree: trying to import ${toString path}, but its a ${pathType}, you need to make it a function like { depot, pkgs, ... }"
else importedFile (filter parts (argsWithPath args parts));
@ -76,8 +80,9 @@ let
dir = readDirVisible initPath;
joinChild = c: initPath + ("/" + c);
self = if rootDir
then { __readTree = []; }
self =
if rootDir
then { __readTree = [ ]; }
else importFile args scopedArgs initPath parts argsFilter;
# Import subdirectories of the current one, unless the special
@ -88,33 +93,41 @@ let
# should be ignored, but its content is not inspected by
# readTree
filterDir = f: dir."${f}" == "directory";
children = if hasAttr ".skip-subtree" dir then [] else map (c: {
name = c;
value = readTree {
inherit argsFilter scopedArgs;
args = args;
initPath = (joinChild c);
rootDir = false;
parts = (parts ++ [ c ]);
};
}) (filter filterDir (attrNames dir));
children = if hasAttr ".skip-subtree" dir then [ ] else
map
(c: {
name = c;
value = readTree {
inherit argsFilter scopedArgs;
args = args;
initPath = (joinChild c);
rootDir = false;
parts = (parts ++ [ c ]);
};
})
(filter filterDir (attrNames dir));
# Import Nix files
nixFiles = if hasAttr ".skip-subtree" dir then []
nixFiles =
if hasAttr ".skip-subtree" dir then [ ]
else filter (f: f != null) (map nixFileName (attrNames dir));
nixChildren = map (c: let
p = joinChild (c + ".nix");
childParts = parts ++ [ c ];
imported = importFile args scopedArgs p childParts argsFilter;
in {
name = c;
value =
if isAttrs imported
then imported // marker childParts {}
else imported;
}) nixFiles;
nixChildren = map
(c:
let
p = joinChild (c + ".nix");
childParts = parts ++ [ c ];
imported = importFile args scopedArgs p childParts argsFilter;
in
{
name = c;
value =
if isAttrs imported
then imported // marker childParts { }
else imported;
})
nixFiles;
nodeValue = if dir ? "default.nix" then self else {};
nodeValue = if dir ? "default.nix" then self else { };
allChildren = listToAttrs (
if dir ? "default.nix"
@ -123,9 +136,9 @@ let
);
in
if isAttrs nodeValue
then nodeValue // allChildren // (marker parts allChildren)
else nodeValue;
if isAttrs nodeValue
then nodeValue // allChildren // (marker parts allChildren)
else nodeValue;
# Function which can be used to find all readTree targets within an
# attribute set.
@ -143,40 +156,42 @@ let
# should be included in the build.
gather = eligible: node:
if node ? __readTree then
# Include the node itself if it is eligible.
(if eligible node then [ node ] else [])
# Include the node itself if it is eligible.
(if eligible node then [ node ] else [ ])
# Include eligible children of the node
++ concatMap (gather eligible) (map (attr: node."${attr}") node.__readTreeChildren)
# Include specified sub-targets of the node
++ filter eligible (map
(k: (node."${k}" or {}) // {
# Keep the same tree location, but explicitly mark this
# node as a subtarget.
__readTree = node.__readTree;
__readTreeChildren = [];
__subtarget = k;
})
(node.meta.targets or []))
else [];
(k: (node."${k}" or { }) // {
# Keep the same tree location, but explicitly mark this
# node as a subtarget.
__readTree = node.__readTree;
__readTreeChildren = [ ];
__subtarget = k;
})
(node.meta.targets or [ ]))
else [ ];
# Determine whether a given value is a derivation.
# Copied from nixpkgs/lib for cases where lib is not available yet.
isDerivation = x: isAttrs x && x ? type && x.type == "derivation";
in {
in
{
inherit gather;
__functor = _:
{ path
, args
, filter ? (_parts: x: x)
, scopedArgs ? {} }:
readTree {
inherit args scopedArgs;
argsFilter = filter;
initPath = path;
rootDir = true;
parts = [];
};
, scopedArgs ? { }
}:
readTree {
inherit args scopedArgs;
argsFilter = filter;
initPath = path;
rootDir = true;
parts = [ ];
};
# In addition to readTree itself, some functionality is exposed that
# is useful for users of readTree.
@ -193,7 +208,7 @@ in {
# which should be able to access the restricted folder.
#
# reason: Textual explanation for the restriction (included in errors)
restrictFolder = { folder, exceptions ? [], reason }: parts: args:
restrictFolder = { folder, exceptions ? [ ], reason }: parts: args:
if (elemAt parts 0) == folder || elem parts exceptions
then args
else args // {
@ -224,8 +239,8 @@ in {
drvTargets = attrs: attrs // {
meta = {
targets = builtins.filter
(x: isDerivation attrs."${x}")
(builtins.attrNames attrs);
} // (attrs.meta or {});
(x: isDerivation attrs."${x}")
(builtins.attrNames attrs);
} // (attrs.meta or { });
};
}

View file

@ -10,13 +10,13 @@ let
tree-ex = depot.nix.readTree {
path = ./test-example;
args = {};
args = { };
};
example = it "corresponds to the README example" [
(assertEq "third_party attrset"
(lib.isAttrs tree-ex.third_party
&& (! lib.isDerivation tree-ex.third_party))
&& (! lib.isDerivation tree-ex.third_party))
true)
(assertEq "third_party attrset other attribute"
tree-ex.third_party.favouriteColour
@ -37,7 +37,7 @@ let
tree-tl = depot.nix.readTree {
path = ./test-tree-traversal;
args = {};
args = { };
};
traversal-logic = it "corresponds to the traversal logic in the README" [
@ -82,7 +82,7 @@ let
"Picked up through the drv")
(assertEq "default.nix drv is not changed by readTree"
tree-tl.default-nix.can-be-drv
(import ./test-tree-traversal/default-nix/can-be-drv/default.nix {}))
(import ./test-tree-traversal/default-nix/can-be-drv/default.nix { }))
];
# these each call readTree themselves because the throws have to happen inside assertThrows
@ -90,7 +90,7 @@ let
(assertThrows "this file is not a function"
(depot.nix.readTree {
path = ./test-wrong-not-a-function;
args = {};
args = { };
}).not-a-function)
# cant test for that, assertThrows cant catch this error
# (assertThrows "this file is a function but doesnt have dots"
@ -99,12 +99,13 @@ let
read-markers = depot.nix.readTree {
path = ./test-marker;
args = {};
args = { };
};
assertMarkerByPath = path:
assertEq "${lib.concatStringsSep "." path} is marked correctly"
(lib.getAttrFromPath path read-markers).__readTree path;
(lib.getAttrFromPath path read-markers).__readTree
path;
markers = it "marks nodes correctly" [
(assertMarkerByPath [ "directory-marked" ])
@ -119,7 +120,8 @@ let
read-markers.directory-marked.nested.__readTreeChildren [ ])
];
in runTestsuite "readTree" [
in
runTestsuite "readTree" [
example
traversal-logic
wrong

View file

@ -1,3 +1,3 @@
{ ... }:
{}
{ }

View file

@ -1,3 +1,3 @@
{ ... }:
{}
{ }

View file

@ -1,3 +1,3 @@
{ ... }:
{}
{ }

View file

@ -1,3 +1,3 @@
{ ... }:
{}
{ }

View file

@ -3,6 +3,6 @@
with depot.nix.yants;
defun [ path drv ] (file: pkgs.runCommandNoCC "${file}.rendered.html" {} ''
defun [ path drv ] (file: pkgs.runCommandNoCC "${file}.rendered.html" { } ''
cat ${file} | ${depot.tools.cheddar}/bin/cheddar --about-filter ${file} > $out
'')

View file

@ -9,7 +9,7 @@ let
runExeclineLocal = name: args: execline:
runExecline name
(args // {
derivationArgs = args.derivationArgs or {} // {
derivationArgs = args.derivationArgs or { } // {
preferLocalBuild = true;
allowSubstitutes = false;
};
@ -23,7 +23,8 @@ let
inherit pkgs;
};
in {
in
{
__functor = _: runExecline;
local = runExeclineLocal;
inherit tests;

View file

@ -35,32 +35,32 @@
let
bins = getBins pkgs.execline [
"execlineb"
{ use = "if"; as = "execlineIf"; }
"redirfd"
"importas"
"exec"
]
// getBins pkgs.s6-portable-utils [
"s6-cat"
"s6-grep"
"s6-touch"
"s6-test"
"s6-chmod"
];
"execlineb"
{ use = "if"; as = "execlineIf"; }
"redirfd"
"importas"
"exec"
]
// getBins pkgs.s6-portable-utils [
"s6-cat"
"s6-grep"
"s6-touch"
"s6-test"
"s6-chmod"
];
in
# TODO: move name into the attrset
name:
{
# a string to pass as stdin to the execline script
stdin ? ""
# a program wrapping the acutal execline invocation;
# should be in Bernstein-chaining style
# a string to pass as stdin to the execline script
stdin ? ""
# a program wrapping the acutal execline invocation;
# should be in Bernstein-chaining style
, builderWrapper ? bins.exec
# additional arguments to pass to the derivation
, derivationArgs ? {}
# additional arguments to pass to the derivation
, derivationArgs ? { }
}:
# the execline script as a nested list of string,
# representing the blocks;
@ -90,33 +90,33 @@ derivation (derivationArgs // {
passAsFile = [
"_runExeclineScript"
"_runExeclineStdin"
] ++ derivationArgs.passAsFile or [];
] ++ derivationArgs.passAsFile or [ ];
# the default, exec acts as identity executable
builder = builderWrapper;
args = [
bins.importas # import script file as $script
"-ui" # drop the envvar afterwards
"script" # substitution name
bins.importas # import script file as $script
"-ui" # drop the envvar afterwards
"script" # substitution name
"_runExeclineScriptPath" # passed script file
bins.importas # do the same for $stdin
bins.importas # do the same for $stdin
"-ui"
"stdin"
"_runExeclineStdinPath"
bins.redirfd # now we
"-r" # read the file
"0" # into the stdin of execlineb
"$stdin" # that was given via stdin
bins.redirfd # now we
"-r" # read the file
"0" # into the stdin of execlineb
"$stdin" # that was given via stdin
bins.execlineb # the actual invocation
bins.execlineb # the actual invocation
# TODO(Profpatsch): depending on the use-case, -S0 might not be enough
# in all use-cases, then a wrapper for execlineb arguments
# should be added (-P, -S, -s).
"-S0" # set $@ inside the execline script
"-W" # die on syntax error
"$script" # substituted by importas
"-S0" # set $@ inside the execline script
"-W" # die on syntax error
"$script" # substituted by importas
];
})

View file

@ -1,23 +1,29 @@
{ stdenv, pkgs, runExecline, runExeclineLocal, getBins, writeScript
# https://www.mail-archive.com/skaware@list.skarnet.org/msg01256.html
, coreutils }:
{ stdenv
, pkgs
, runExecline
, runExeclineLocal
, getBins
, writeScript
# https://www.mail-archive.com/skaware@list.skarnet.org/msg01256.html
, coreutils
}:
let
bins = getBins coreutils [ "mv" ]
// getBins pkgs.execline [
"execlineb"
{ use = "if"; as = "execlineIf"; }
"redirfd"
"importas"
]
// getBins pkgs.s6-portable-utils [
"s6-chmod"
"s6-grep"
"s6-touch"
"s6-cat"
"s6-test"
];
// getBins pkgs.execline [
"execlineb"
{ use = "if"; as = "execlineIf"; }
"redirfd"
"importas"
]
// getBins pkgs.s6-portable-utils [
"s6-chmod"
"s6-grep"
"s6-touch"
"s6-cat"
"s6-test"
];
# execline block of depth 1
block = args: builtins.map (arg: " ${arg}") args ++ [ "" ];
@ -31,49 +37,80 @@ let
builder = bins.execlineIf;
args =
(block [
bins.redirfd "-r" "0" file # read file to stdin
bins.s6-grep "-F" "-q" line # and grep for the line
bins.redirfd
"-r"
"0"
file # read file to stdin
bins.s6-grep
"-F"
"-q"
line # and grep for the line
])
++ [
# if the block succeeded, touch $out
bins.importas "-ui" "out" "out"
bins.s6-touch "$out"
bins.importas
"-ui"
"out"
"out"
bins.s6-touch
"$out"
];
preferLocalBuild = true;
allowSubstitutes = false;
};
# basic test that touches out
basic = runExeclineLocal "run-execline-test-basic" {
} [
"importas" "-ui" "out" "out"
"${bins.s6-touch}" "$out"
basic = runExeclineLocal "run-execline-test-basic"
{ } [
"importas"
"-ui"
"out"
"out"
"${bins.s6-touch}"
"$out"
];
# whether the stdin argument works as intended
stdin = fileHasLine "foo" (runExeclineLocal "run-execline-test-stdin" {
stdin = "foo\nbar\nfoo";
} [
"importas" "-ui" "out" "out"
# this pipes stdout of s6-cat to $out
# and s6-cat redirects from stdin to stdout
"redirfd" "-w" "1" "$out" bins.s6-cat
stdin = fileHasLine "foo" (runExeclineLocal "run-execline-test-stdin"
{
stdin = "foo\nbar\nfoo";
} [
"importas"
"-ui"
"out"
"out"
# this pipes stdout of s6-cat to $out
# and s6-cat redirects from stdin to stdout
"redirfd"
"-w"
"1"
"$out"
bins.s6-cat
]);
wrapWithVar = runExeclineLocal "run-execline-test-wrap-with-var" {
builderWrapper = writeScript "var-wrapper" ''
#!${bins.execlineb} -S0
export myvar myvalue $@
'';
} [
"importas" "-ui" "v" "myvar"
"if" [ bins.s6-test "myvalue" "=" "$v" ]
"importas" "out" "out"
bins.s6-touch "$out"
wrapWithVar = runExeclineLocal "run-execline-test-wrap-with-var"
{
builderWrapper = writeScript "var-wrapper" ''
#!${bins.execlineb} -S0
export myvar myvalue $@
'';
} [
"importas"
"-ui"
"v"
"myvar"
"if"
[ bins.s6-test "myvalue" "=" "$v" ]
"importas"
"out"
"out"
bins.s6-touch
"$out"
];
in [
in
[
basic
stdin
wrapWithVar

View file

@ -38,11 +38,11 @@ let
;
bins = depot.nix.getBins pkgs.coreutils [ "printf" ]
// depot.nix.getBins pkgs.s6-portable-utils [ "s6-touch" "s6-false" "s6-cat" ];
// depot.nix.getBins pkgs.s6-portable-utils [ "s6-touch" "s6-false" "s6-cat" ];
# Returns true if the given expression throws when `deepSeq`-ed
throws = expr:
!(builtins.tryEval (builtins.deepSeq expr {})).success;
!(builtins.tryEval (builtins.deepSeq expr { })).success;
# rewrite the builtins.partition result
# to use `ok` and `err` instead of `right` and `wrong`.
@ -99,11 +99,12 @@ let
(context: desc: res:
if res
then { yep = { test = desc; }; }
else { nope = {
test = desc;
inherit context;
};
});
else {
nope = {
test = desc;
inherit context;
};
});
# assert that left and right values are equal
assertEq = defun [ string any any AssertResult ]
@ -111,7 +112,7 @@ let
let
context = { not-equal = { inherit left right; }; };
in
assertBoolContext context desc (left == right));
assertBoolContext context desc (left == right));
# assert that the expression throws when `deepSeq`-ed
assertThrows = defun [ string any AssertResult ]
@ -119,7 +120,7 @@ let
let
context = { should-throw = { inherit expr; }; };
in
assertBoolContext context desc (throws expr));
assertBoolContext context desc (throws expr));
# assert that the expression does not throw when `deepSeq`-ed
assertDoesNotThrow = defun [ string any AssertResult ]
@ -144,31 +145,50 @@ let
yep = _: true;
nope = _: false;
};
res = partitionTests (it:
(partitionTests goodAss it.asserts).err == []
) itResults;
prettyRes = lib.generators.toPretty {} res;
res = partitionTests
(it:
(partitionTests goodAss it.asserts).err == [ ]
)
itResults;
prettyRes = lib.generators.toPretty { } res;
in
if res.err == []
then depot.nix.runExecline.local "testsuite-${name}-successful" {} [
"importas" "out" "out"
if res.err == [ ]
then
depot.nix.runExecline.local "testsuite-${name}-successful" { } [
"importas"
"out"
"out"
# force derivation to rebuild if test case list changes
"ifelse" [ bins.s6-false ] [
bins.printf "" (builtins.hashString "sha512" prettyRes)
"ifelse"
[ bins.s6-false ]
[
bins.printf
""
(builtins.hashString "sha512" prettyRes)
]
"if" [ bins.printf "%s\n" "testsuite ${name} successful!" ]
bins.s6-touch "$out"
"if"
[ bins.printf "%s\n" "testsuite ${name} successful!" ]
bins.s6-touch
"$out"
]
else depot.nix.runExecline.local "testsuite-${name}-failed" {
stdin = prettyRes + "\n";
} [
"importas" "out" "out"
"if" [ bins.printf "%s\n" "testsuite ${name} failed!" ]
"if" [ bins.s6-cat ]
"exit" "1"
else
depot.nix.runExecline.local "testsuite-${name}-failed"
{
stdin = prettyRes + "\n";
} [
"importas"
"out"
"out"
"if"
[ bins.printf "%s\n" "testsuite ${name} failed!" ]
"if"
[ bins.s6-cat ]
"exit"
"1"
]);
in {
in
{
inherit
assertEq
assertThrows

View file

@ -45,14 +45,16 @@ let
let
withLeading = p: if builtins.substring 0 1 p == "/" then p else "/" + p;
fullPath =
/**/ if builtins.isPath path then path
/**/
if builtins.isPath path then path
else if builtins.isString path then (root + withLeading path)
else builtins.throw "Unsupported path type ${builtins.typeOf path}";
strPath = toString fullPath;
contextPath = "${fullPath}";
belowRoot = builtins.substring rootLength (-1) strPath;
prefix = builtins.substring 0 rootLength strPath;
in assert toString root == prefix; {
in
assert toString root == prefix; {
src = contextPath;
dst = belowRoot;
};
@ -61,10 +63,12 @@ let
in
# TODO(sterni): teach readTree to also read symlinked directories,
# so we ln -sT instead of cp -aT.
pkgs.runCommandNoCC "sparse-${builtins.baseNameOf root}" {} (
lib.concatMapStrings ({ src, dst }: ''
mkdir -p "$(dirname "$out${dst}")"
cp -aT --reflink=auto "${src}" "$out${dst}"
'') symlinks
# so we ln -sT instead of cp -aT.
pkgs.runCommandNoCC "sparse-${builtins.baseNameOf root}" { } (
lib.concatMapStrings
({ src, dst }: ''
mkdir -p "$(dirname "$out${dst}")"
cp -aT --reflink=auto "${src}" "$out${dst}"
'')
symlinks
)

View file

@ -4,22 +4,24 @@ let
# if so sets `isTag` to `true` and sets the name and value.
# If not, sets `isTag` to `false` and sets `errmsg`.
verifyTag = tag:
let cases = builtins.attrNames tag;
len = builtins.length cases;
let
cases = builtins.attrNames tag;
len = builtins.length cases;
in
if builtins.length cases == 1
then let name = builtins.head cases; in {
isTag = true;
name = name;
val = tag.${name};
errmsg = null;
}
then
let name = builtins.head cases; in {
isTag = true;
name = name;
val = tag.${name};
errmsg = null;
}
else {
isTag = false;
errmsg =
( "match: an instance of a sum is an attrset "
+ "with exactly one element, yours had ${toString len}"
+ ", namely: ${lib.generators.toPretty {} cases}" );
("match: an instance of a sum is an attrset "
+ "with exactly one element, yours had ${toString len}"
+ ", namely: ${lib.generators.toPretty {} cases}");
name = null;
val = null;
};
@ -63,21 +65,22 @@ let
# ] 1
# => { smol = 1; }
discrDef = defTag: fs: v:
let res = lib.findFirst
(t: t.val v)
null
(map assertIsTag fs);
let
res = lib.findFirst
(t: t.val v)
null
(map assertIsTag fs);
in
if res == null
then { ${defTag} = v; }
else { ${res.name} = v; };
if res == null
then { ${defTag} = v; }
else { ${res.name} = v; };
# Like `discrDef`, but fail if there is no match.
discr = fs: v:
let res = discrDef null fs v; in
assert lib.assertMsg (res != null)
"tag.discr: No predicate found that matches ${lib.generators.toPretty {} v}";
res;
assert lib.assertMsg (res != null)
"tag.discr: No predicate found that matches ${lib.generators.toPretty {} v}";
res;
# The canonical pattern matching primitive.
# A sum value is an attribute set with one element,
@ -104,17 +107,17 @@ let
match = sum: matcher:
let cases = builtins.attrNames sum;
in assert
let len = builtins.length cases; in
lib.assertMsg (len == 1)
( "match: an instance of a sum is an attrset "
+ "with exactly one element, yours had ${toString len}"
+ ", namely: ${lib.generators.toPretty {} cases}" );
let len = builtins.length cases; in
lib.assertMsg (len == 1)
("match: an instance of a sum is an attrset "
+ "with exactly one element, yours had ${toString len}"
+ ", namely: ${lib.generators.toPretty {} cases}");
let case = builtins.head cases;
in assert
lib.assertMsg (matcher ? ${case})
( "match: \"${case}\" is not a valid case of this sum, "
lib.assertMsg (matcher ? ${case})
("match: \"${case}\" is not a valid case of this sum, "
+ "the matcher accepts: ${lib.generators.toPretty {}
(builtins.attrNames matcher)}" );
(builtins.attrNames matcher)}");
matcher.${case} sum.${case};
# A `match` with the arguments flipped.
@ -148,15 +151,16 @@ let
;
};
in {
inherit
verifyTag
tagName
tagValue
discr
discrDef
match
matchLam
tests
;
in
{
inherit
verifyTag
tagName
tagValue
discr
discrDef
match
matchLam
tests
;
}

View file

@ -17,7 +17,7 @@ let
errmsg = null;
})
(assertEq "is not Tag"
(removeAttrs (verifyTag { foo = "bar"; baz = 42; }) ["errmsg"])
(removeAttrs (verifyTag { foo = "bar"; baz = 42; }) [ "errmsg" ])
{
isTag = false;
name = null;
@ -41,7 +41,8 @@ let
(discr [
{ bool = lib.isBool; }
{ int = lib.isInt; }
] true)
]
true)
{ bool = true; })
(assertEq "fallback to default"
(discrDef "def" [
@ -53,19 +54,24 @@ let
match-test = it "can match things" [
(assertEq "match example"
(let
success = { res = 42; };
failure = { err = "no answer"; };
matcher = {
res = i: i + 1;
err = _: 0;
};
in {
one = match success matcher;
two = match failure matcher;
(
let
success = { res = 42; };
failure = { err = "no answer"; };
matcher = {
res = i: i + 1;
err = _: 0;
};
in
{
one = match success matcher;
two = match failure matcher;
}
)
{
one = 43;
two = 0;
})
{ one = 43;
two = 0; })
(assertEq "matchLam & pipe"
(lib.pipe { foo = 42; } [
(matchLam {
@ -81,8 +87,8 @@ let
];
in
runTestsuite "tag" [
isTag-test
discr-test
match-test
]
runTestsuite "tag" [
isTag-test
discr-test
match-test
]

View file

@ -27,4 +27,5 @@ let
# Actual ACL entries
ACLs = list acl;
};
in config: pkgs.writeText "tailscale-acl.json" (toJSON (aclConfig config))
in
config: pkgs.writeText "tailscale-acl.json" (toJSON (aclConfig config))

View file

@ -34,14 +34,14 @@ let
basename = builtins.unsafeDiscardStringContext
(builtins.baseNameOf strPath);
in
# If p is a direct child of storeDir, we need to remove
# If p is a direct child of storeDir, we need to remove
# the leading hash as well to make sure that:
# `storePathName drv == storePathName (toString drv)`.
if noStoreDir == basename
then builtins.substring 33 (-1) basename
else basename
if noStoreDir == basename
then builtins.substring 33 (-1) basename
else basename
else builtins.throw "Don't know how to get (base)name of "
+ lib.generators.toPretty {} p;
+ lib.generators.toPretty { } p;
/* Query the type of a path exposing the same information as would be by
`builtins.readDir`, but for a single, specific target path.
@ -106,7 +106,7 @@ let
# We need to call toString to prevent unsafeDiscardStringContext
# from importing a path into store which messes with base- and
# dirname of course.
path'= builtins.unsafeDiscardStringContext (toString path);
path' = builtins.unsafeDiscardStringContext (toString path);
# To read the containing directory we absolutely need
# to keep the string context, otherwise a derivation
# would not be realized before our check (at eval time)
@ -120,20 +120,22 @@ let
# directory. If not, either the target doesn't exist or is a regular file.
# TODO(sterni): is there a way to check reliably if the symlink target exists?
isSymlinkDir = builtins.pathExists (path' + "/.");
in {
in
{
${thisPathType} =
/**/ if thisPathType != "symlink" then true
else if isSymlinkDir then "directory"
else "regular-or-missing";
/**/
if thisPathType != "symlink" then true
else if isSymlinkDir then "directory"
else "regular-or-missing";
};
pathType' = path:
let
p = pathType path;
in
if p ? missing
then builtins.throw "${lib.generators.toPretty {} path} does not exist"
else p;
if p ? missing
then builtins.throw "${lib.generators.toPretty {} path} does not exist"
else p;
/* Check whether the given path is a directory.
Throws if the path in question doesn't exist.
@ -151,9 +153,11 @@ let
Type: path(-like) -> bool
*/
realPathIsDirectory = path: let
pt = pathType' path;
in pt ? directory || pt.symlink or null == "directory";
realPathIsDirectory = path:
let
pt = pathType' path;
in
pt ? directory || pt.symlink or null == "directory";
/* Check whether the given path is a regular file.
Throws if the path in question doesn't exist.
@ -169,7 +173,8 @@ let
*/
isSymlink = path: pathType' path ? symlink;
in {
in
{
inherit
storePathName
pathType

View file

@ -26,38 +26,53 @@ let
pathPredicates = it "judges paths correctly" (lib.flatten [
# isDirectory
(assertUtilsPred "directory isDirectory"
(isDirectory ./directory) true)
(isDirectory ./directory)
true)
(assertUtilsPred "symlink not isDirectory"
(isDirectory ./symlink-directory) false)
(isDirectory ./symlink-directory)
false)
(assertUtilsPred "file not isDirectory"
(isDirectory ./directory/file) false)
(isDirectory ./directory/file)
false)
# realPathIsDirectory
(assertUtilsPred "directory realPathIsDirectory"
(realPathIsDirectory ./directory) true)
(realPathIsDirectory ./directory)
true)
(assertUtilsPred "symlink to directory realPathIsDirectory"
(realPathIsDirectory ./symlink-directory) true)
(realPathIsDirectory ./symlink-directory)
true)
(assertUtilsPred "realPathIsDirectory resolves chained symlinks"
(realPathIsDirectory ./symlink-symlink-directory) true)
(realPathIsDirectory ./symlink-symlink-directory)
true)
# isRegularFile
(assertUtilsPred "file isRegularFile"
(isRegularFile ./directory/file) true)
(isRegularFile ./directory/file)
true)
(assertUtilsPred "symlink not isRegularFile"
(isRegularFile ./symlink-file) false)
(isRegularFile ./symlink-file)
false)
(assertUtilsPred "directory not isRegularFile"
(isRegularFile ./directory) false)
(isRegularFile ./directory)
false)
# isSymlink
(assertUtilsPred "symlink to file isSymlink"
(isSymlink ./symlink-file) true)
(isSymlink ./symlink-file)
true)
(assertUtilsPred "symlink to directory isSymlink"
(isSymlink ./symlink-directory) true)
(isSymlink ./symlink-directory)
true)
(assertUtilsPred "symlink to symlink isSymlink"
(isSymlink ./symlink-symlink-file) true)
(isSymlink ./symlink-symlink-file)
true)
(assertUtilsPred "symlink to missing file isSymlink"
(isSymlink ./missing) true)
(isSymlink ./missing)
true)
(assertUtilsPred "directory not isSymlink"
(isSymlink ./directory) false)
(isSymlink ./directory)
false)
(assertUtilsPred "file not isSymlink"
(isSymlink ./directory/file) false)
(isSymlink ./directory/file)
false)
# missing files throw
(assertThrows "isDirectory throws on missing file"
(isDirectory ./does-not-exist))
@ -89,15 +104,18 @@ let
storePathNameTests = it "correctly gets the basename of a store path" [
(assertEq "base name of a derivation"
(storePathName depot.tools.cheddar) depot.tools.cheddar.name)
(storePathName depot.tools.cheddar)
depot.tools.cheddar.name)
(assertEq "base name of a store path string"
(storePathName cheddarStorePath) depot.tools.cheddar.name)
(storePathName cheddarStorePath)
depot.tools.cheddar.name)
(assertEq "base name of a path within a store path"
(storePathName "${cheddarStorePath}/bin/cheddar") "cheddar")
(assertEq "base name of a path"
(storePathName ../default.nix) "default.nix")
(assertEq "base name of a cleanSourced path"
(storePathName cleanedSource) cleanedSource.name)
(storePathName cleanedSource)
cleanedSource.name)
];
in

View file

@ -1,6 +1,6 @@
{ depot, pkgs, ... }:
{ name, src, deps ? (_: []), emacs ? pkgs.emacs27-nox }:
{ name, src, deps ? (_: [ ]), emacs ? pkgs.emacs27-nox }:
let
inherit (pkgs) emacsPackages emacsPackagesGen;
@ -8,11 +8,13 @@ let
finalEmacs = (emacsPackagesGen emacs).emacsWithPackages deps;
srcFile = if isString src
srcFile =
if isString src
then toFile "${name}.el" src
else src;
in depot.nix.writeScriptBin name ''
in
depot.nix.writeScriptBin name ''
#!/bin/sh
${finalEmacs}/bin/emacs --batch --no-site-file --script ${srcFile} $@
''

View file

@ -14,9 +14,10 @@ name:
# "env": dont substitute, set # and 0…n environment vaariables, where n=$#
# "none": dont substitute or set any positional arguments
# "env-no-push": like "env", but bypass the push-phase. Not recommended.
argMode ? "var",
# Number of arguments to be substituted as variables (passed to "var"/"-s" or "var-full"/"-S"
readNArgs ? 0,
argMode ? "var"
, # Number of arguments to be substituted as variables (passed to "var"/"-s" or "var-full"/"-S"
readNArgs ? 0
,
}:
# Nested list of lists of commands.
# Inner lists are translated to execline blocks.
@ -24,7 +25,7 @@ argList:
let
env =
if argMode == "var" then "s${toString readNArgs}"
if argMode == "var" then "s${toString readNArgs}"
else if argMode == "var-full" then "S${toString readNArgs}"
else if argMode == "env" then ""
else if argMode == "none" then "P"
@ -32,7 +33,7 @@ let
else abort ''"${toString argMode}" is not a valid argMode, use one of "var", "var-full", "env", "none", "env-no-push".'';
in
depot.nix.writeScript name ''
#!${pkgs.execline}/bin/execlineb -W${env}
${depot.nix.escapeExecline argList}
''
depot.nix.writeScript name ''
#!${pkgs.execline}/bin/execlineb -W${env}
${depot.nix.escapeExecline argList}
''

View file

@ -5,25 +5,31 @@
let
bins = depot.nix.getBins pkgs.s6-portable-utils [
"s6-cat"
"s6-chmod"
];
"s6-cat"
"s6-chmod"
];
in
name:
# string of the executable script that is put in $out
script:
depot.nix.runExecline name {
depot.nix.runExecline name
{
stdin = script;
derivationArgs = {
preferLocalBuild = true;
allowSubstitutes = false;
};
} [
"importas" "out" "out"
"importas"
"out"
"out"
# this pipes stdout of s6-cat to $out
# and s6-cat redirects from stdin to stdout
"if" [ "redirfd" "-w" "1" "$out" bins.s6-cat ]
bins.s6-chmod "0755" "$out"
"if"
[ "redirfd" "-w" "1" "$out" bins.s6-cat ]
bins.s6-chmod
"0755"
"$out"
]

View file

@ -2,62 +2,71 @@
let
bins = depot.nix.getBins pkgs.s6-portable-utils [ "s6-ln" "s6-ls" "s6-touch" ]
;
;
linkTo = name: path: depot.nix.runExecline.local name {} [
"importas" "out" "out"
bins.s6-ln "-s" path "$out"
linkTo = name: path: depot.nix.runExecline.local name { } [
"importas"
"out"
"out"
bins.s6-ln
"-s"
path
"$out"
];
# Build a rust executable, $out is the executable.
rustSimple = args@{name, ...}: src:
rustSimple = args@{ name, ... }: src:
linkTo name "${rustSimpleBin args src}/bin/${name}";
# Like `rustSimple`, but put the binary in `$out/bin/`.
rustSimpleBin = {
name,
dependencies ? [],
doCheck ? true,
}: src:
rustSimpleBin =
{ name
, dependencies ? [ ]
, doCheck ? true
,
}: src:
(if doCheck then testRustSimple else pkgs.lib.id)
(pkgs.buildRustCrate ({
pname = name;
version = "1.0.0";
crateName = name;
crateBin = [ name ];
dependencies = dependencies;
src = pkgs.runCommandLocal "write-main.rs" {
src = src;
passAsFile = [ "src" ];
} ''
mkdir -p $out/src/bin
cp "$srcPath" $out/src/bin/${name}.rs
find $out
'';
}));
(pkgs.buildRustCrate ({
pname = name;
version = "1.0.0";
crateName = name;
crateBin = [ name ];
dependencies = dependencies;
src = pkgs.runCommandLocal "write-main.rs"
{
src = src;
passAsFile = [ "src" ];
} ''
mkdir -p $out/src/bin
cp "$srcPath" $out/src/bin/${name}.rs
find $out
'';
}));
# Build a rust library, that can be used as dependency to `rustSimple`.
# Wrapper around `pkgs.buildRustCrate`, takes all its arguments.
rustSimpleLib = {
name,
dependencies ? [],
doCheck ? true,
}: src:
rustSimpleLib =
{ name
, dependencies ? [ ]
, doCheck ? true
,
}: src:
(if doCheck then testRustSimple else pkgs.lib.id)
(pkgs.buildRustCrate ({
pname = name;
version = "1.0.0";
crateName = name;
dependencies = dependencies;
src = pkgs.runCommandLocal "write-lib.rs" {
src = src;
passAsFile = [ "src" ];
} ''
mkdir -p $out/src
cp "$srcPath" $out/src/lib.rs
find $out
'';
}));
(pkgs.buildRustCrate ({
pname = name;
version = "1.0.0";
crateName = name;
dependencies = dependencies;
src = pkgs.runCommandLocal "write-lib.rs"
{
src = src;
passAsFile = [ "src" ];
} ''
mkdir -p $out/src
cp "$srcPath" $out/src/lib.rs
find $out
'';
}));
/* Takes a `buildRustCrate` derivation as an input,
* builds it with `{ buildTests = true; }` and runs
@ -72,19 +81,30 @@ let
testRustSimple = rustDrv:
let
crate = buildTests: rustDrv.override { inherit buildTests; };
tests = depot.nix.runExecline.local "${rustDrv.name}-tests-run" {} [
"importas" "out" "out"
"if" [
"pipeline" [ bins.s6-ls "${crate true}/tests" ]
"forstdin" "-o0" "test"
"importas" "test" "test"
tests = depot.nix.runExecline.local "${rustDrv.name}-tests-run" { } [
"importas"
"out"
"out"
"if"
[
"pipeline"
[ bins.s6-ls "${crate true}/tests" ]
"forstdin"
"-o0"
"test"
"importas"
"test"
"test"
"${crate true}/tests/$test"
]
bins.s6-touch "$out"
bins.s6-touch
"$out"
];
in depot.nix.drvSeqL [ tests ] (crate false);
in
depot.nix.drvSeqL [ tests ] (crate false);
in {
in
{
inherit
rustSimple
rustSimpleBin

View file

@ -11,15 +11,20 @@ let
coreutils
;
run = drv: depot.nix.runExecline.local "run-${drv.name}" {} [
"if" [ drv ]
"importas" "out" "out"
"${coreutils}/bin/touch" "$out"
run = drv: depot.nix.runExecline.local "run-${drv.name}" { } [
"if"
[ drv ]
"importas"
"out"
"out"
"${coreutils}/bin/touch"
"$out"
];
rustTransitiveLib = rustSimpleLib {
name = "transitive";
} ''
rustTransitiveLib = rustSimpleLib
{
name = "transitive";
} ''
pub fn transitive(s: &str) -> String {
let mut new = s.to_string();
new.push_str(" 1 2 3");
@ -37,10 +42,11 @@ let
}
'';
rustTestLib = rustSimpleLib {
name = "test_lib";
dependencies = [ rustTransitiveLib ];
} ''
rustTestLib = rustSimpleLib
{
name = "test_lib";
dependencies = [ rustTransitiveLib ];
} ''
extern crate transitive;
use transitive::{transitive};
pub fn test() -> String {
@ -48,10 +54,11 @@ let
}
'';
rustWithLib = run (rustSimple {
name = "rust-with-lib";
dependencies = [ rustTestLib ];
} ''
rustWithLib = run (rustSimple
{
name = "rust-with-lib";
dependencies = [ rustTestLib ];
} ''
extern crate test_lib;
fn main() {
@ -60,7 +67,8 @@ let
'');
in depot.nix.readTree.drvTargets {
in
depot.nix.readTree.drvTargets {
inherit
rustTransitiveLib
rustWithLib

View file

@ -6,10 +6,10 @@
#
# All types (should) compose as expected.
{ lib ? (import <nixpkgs> {}).lib, ... }:
{ lib ? (import <nixpkgs> { }).lib, ... }:
with builtins; let
prettyPrint = lib.generators.toPretty {};
prettyPrint = lib.generators.toPretty { };
# typedef' :: struct {
# name = string;
@ -34,41 +34,44 @@ with builtins; let
#
# This function is the low-level primitive used to create types. For
# many cases the higher-level 'typedef' function is more appropriate.
typedef' = { name, checkType
, checkToBool ? (result: result.ok)
, toError ? (_: result: result.err)
, def ? null
, match ? null }: {
inherit name checkToBool toError;
typedef' =
{ name
, checkType
, checkToBool ? (result: result.ok)
, toError ? (_: result: result.err)
, def ? null
, match ? null
}: {
inherit name checkToBool toError;
# check :: a -> bool
#
# This function is used to determine whether a given type is
# conformant.
check = value: checkToBool (checkType value);
# check :: a -> bool
#
# This function is used to determine whether a given type is
# conformant.
check = value: checkToBool (checkType value);
# checkType :: a -> struct { ok = bool; err = option string; }
#
# This function checks whether the passed value is type conformant
# and returns an optional type error string otherwise.
inherit checkType;
# checkType :: a -> struct { ok = bool; err = option string; }
#
# This function checks whether the passed value is type conformant
# and returns an optional type error string otherwise.
inherit checkType;
# __functor :: a -> a
#
# This function checks whether the passed value is type conformant
# and throws an error if it is not.
#
# The name of this function is a special attribute in Nix that
# makes it possible to execute a type attribute set like a normal
# function.
__functor = self: value:
let result = self.checkType value;
in if checkToBool result then value
else throw (toError value result);
};
# __functor :: a -> a
#
# This function checks whether the passed value is type conformant
# and throws an error if it is not.
#
# The name of this function is a special attribute in Nix that
# makes it possible to execute a type attribute set like a normal
# function.
__functor = self: value:
let result = self.checkType value;
in if checkToBool result then value
else throw (toError value result);
};
typeError = type: val:
"expected type '${type}', but value '${prettyPrint val}' is of type '${typeOf val}'";
"expected type '${type}', but value '${prettyPrint val}' is of type '${typeOf val}'";
# typedef :: string -> (a -> bool) -> type
#
@ -85,27 +88,34 @@ with builtins; let
});
};
checkEach = name: t: l: foldl' (acc: e:
let res = t.checkType e;
checkEach = name: t: l: foldl'
(acc: e:
let
res = t.checkType e;
isT = t.checkToBool res;
in {
ok = acc.ok && isT;
err = if isT
then acc.err
else acc.err + "${prettyPrint e}: ${t.toError e res}\n";
}) { ok = true; err = "expected type ${name}, but found:\n"; } l;
in lib.fix (self: {
in
{
ok = acc.ok && isT;
err =
if isT
then acc.err
else acc.err + "${prettyPrint e}: ${t.toError e res}\n";
})
{ ok = true; err = "expected type ${name}, but found:\n"; }
l;
in
lib.fix (self: {
# Primitive types
any = typedef "any" (_: true);
unit = typedef "unit" (v: v == {});
int = typedef "int" isInt;
bool = typedef "bool" isBool;
float = typedef "float" isFloat;
string = typedef "string" isString;
path = typedef "path" (x: typeOf x == "path");
drv = typedef "derivation" (x: isAttrs x && x ? "type" && x.type == "derivation");
any = typedef "any" (_: true);
unit = typedef "unit" (v: v == { });
int = typedef "int" isInt;
bool = typedef "bool" isBool;
float = typedef "float" isFloat;
string = typedef "string" isString;
path = typedef "path" (x: typeOf x == "path");
drv = typedef "derivation" (x: isAttrs x && x ? "type" && x.type == "derivation");
function = typedef "function" (x: isFunction x || (isAttrs x && x ? "__functor"
&& isFunction x.__functor));
&& isFunction x.__functor));
# Type for types themselves. Useful when defining polymorphic types.
type = typedef "type" (x:
@ -124,7 +134,7 @@ in lib.fix (self: {
in {
ok = isNull v || (self.type t).checkToBool res;
err = "expected type ${name}, but value does not conform to '${t.name}': "
+ t.toError v res;
+ t.toError v res;
};
};
@ -136,7 +146,8 @@ in lib.fix (self: {
list = t: typedef' rec {
name = "list<${t.name}>";
checkType = v: if isList v
checkType = v:
if isList v
then checkEach name (self.type t) v
else {
ok = false;
@ -147,7 +158,8 @@ in lib.fix (self: {
attrs = t: typedef' rec {
name = "attrs<${t.name}>";
checkType = v: if isAttrs v
checkType = v:
if isAttrs v
then checkEach name (self.type t) (attrValues v)
else {
ok = false;
@ -172,20 +184,23 @@ in lib.fix (self: {
# checkField checks an individual field of the struct against
# its definition and creates a typecheck result. These results
# are aggregated during the actual checking.
checkField = def: name: value: let result = def.checkType value; in rec {
ok = def.checkToBool result;
err = if !ok && isNull value
then "missing required ${def.name} field '${name}'\n"
else "field '${name}': ${def.toError value result}\n";
};
checkField = def: name: value:
let result = def.checkType value; in rec {
ok = def.checkToBool result;
err =
if !ok && isNull value
then "missing required ${def.name} field '${name}'\n"
else "field '${name}': ${def.toError value result}\n";
};
# checkExtraneous determines whether a (closed) struct contains
# any fields that are not part of the definition.
checkExtraneous = def: has: acc:
if (length has) == 0 then acc
else if (hasAttr (head has) def)
then checkExtraneous def (tail has) acc
else checkExtraneous def (tail has) {
then checkExtraneous def (tail has) acc
else
checkExtraneous def (tail has) {
ok = false;
err = acc.err + "unexpected struct field '${head has}'\n";
};
@ -197,85 +212,102 @@ in lib.fix (self: {
init = { ok = true; err = ""; };
extraneous = checkExtraneous def (attrNames value) init;
checkedFields = map (n:
let v = if hasAttr n value then value."${n}" else null;
in checkField def."${n}" n v) (attrNames def);
checkedFields = map
(n:
let v = if hasAttr n value then value."${n}" else null;
in checkField def."${n}" n v)
(attrNames def);
combined = foldl' (acc: res: {
ok = acc.ok && res.ok;
err = if !res.ok then acc.err + res.err else acc.err;
}) init checkedFields;
in {
combined = foldl'
(acc: res: {
ok = acc.ok && res.ok;
err = if !res.ok then acc.err + res.err else acc.err;
})
init
checkedFields;
in
{
ok = combined.ok && extraneous.ok;
err = combined.err + extraneous.err;
};
struct' = name: def: typedef' {
inherit name def;
checkType = value: if isAttrs value
checkType = value:
if isAttrs value
then (checkStruct (self.attrs self.type def) value)
else { ok = false; err = typeError name value; };
toError = _: result: "expected '${name}'-struct, but found:\n" + result.err;
toError = _: result: "expected '${name}'-struct, but found:\n" + result.err;
};
in arg: if isString arg then (struct' arg) else (struct' "anon" arg);
in
arg: if isString arg then (struct' arg) else (struct' "anon" arg);
# Enums & pattern matching
enum =
let
plain = name: def: typedef' {
inherit name def;
let
plain = name: def: typedef' {
inherit name def;
checkType = (x: isString x && elem x def);
checkToBool = x: x;
toError = value: _: "'${prettyPrint value} is not a member of enum ${name}";
};
enum' = name: def: lib.fix (e: (plain name def) // {
match = x: actions: deepSeq (map e (attrNames actions)) (
let
actionKeys = attrNames actions;
missing = foldl' (m: k: if (elem k actionKeys) then m else m ++ [ k ]) [] def;
in if (length missing) > 0
then throw "Missing match action for members: ${prettyPrint missing}"
else actions."${e x}");
});
in arg: if isString arg then (enum' arg) else (enum' "anon" arg);
checkType = (x: isString x && elem x def);
checkToBool = x: x;
toError = value: _: "'${prettyPrint value} is not a member of enum ${name}";
};
enum' = name: def: lib.fix (e: (plain name def) // {
match = x: actions: deepSeq (map e (attrNames actions)) (
let
actionKeys = attrNames actions;
missing = foldl' (m: k: if (elem k actionKeys) then m else m ++ [ k ]) [ ] def;
in
if (length missing) > 0
then throw "Missing match action for members: ${prettyPrint missing}"
else actions."${e x}"
);
});
in
arg: if isString arg then (enum' arg) else (enum' "anon" arg);
# Sum types
#
# The representation of a sum type is an attribute set with only one
# value, where the key of the value denotes the variant of the type.
sum =
let
plain = name: def: typedef' {
inherit name def;
checkType = (x:
let variant = elemAt (attrNames x) 0;
in if isAttrs x && length (attrNames x) == 1 && hasAttr variant def
then let t = def."${variant}";
v = x."${variant}";
res = t.checkType v;
in if t.checkToBool res
then { ok = true; }
else {
ok = false;
err = "while checking '${name}' variant '${variant}': "
+ t.toError v res;
}
let
plain = name: def: typedef' {
inherit name def;
checkType = (x:
let variant = elemAt (attrNames x) 0;
in if isAttrs x && length (attrNames x) == 1 && hasAttr variant def
then
let
t = def."${variant}";
v = x."${variant}";
res = t.checkType v;
in
if t.checkToBool res
then { ok = true; }
else {
ok = false;
err = "while checking '${name}' variant '${variant}': "
+ t.toError v res;
}
else { ok = false; err = typeError name x; }
);
};
sum' = name: def: lib.fix (s: (plain name def) // {
match = x: actions:
let variant = deepSeq (s x) (elemAt (attrNames x) 0);
actionKeys = attrNames actions;
defKeys = attrNames def;
missing = foldl' (m: k: if (elem k actionKeys) then m else m ++ [ k ]) [] defKeys;
in if (length missing) > 0
then throw "Missing match action for variants: ${prettyPrint missing}"
else actions."${variant}" x."${variant}";
});
in arg: if isString arg then (sum' arg) else (sum' "anon" arg);
);
};
sum' = name: def: lib.fix (s: (plain name def) // {
match = x: actions:
let
variant = deepSeq (s x) (elemAt (attrNames x) 0);
actionKeys = attrNames actions;
defKeys = attrNames def;
missing = foldl' (m: k: if (elem k actionKeys) then m else m ++ [ k ]) [ ] defKeys;
in
if (length missing) > 0
then throw "Missing match action for variants: ${prettyPrint missing}"
else actions."${variant}" x."${variant}";
});
in
arg: if isString arg then (sum' arg) else (sum' "anon" arg);
# Typed function definitions
#
@ -289,15 +321,19 @@ in lib.fix (self: {
mkFunc = sig: f: {
inherit sig;
__toString = self: foldl' (s: t: "${s} -> ${t.name}")
"λ :: ${(head self.sig).name}" (tail self.sig);
"λ :: ${(head self.sig).name}"
(tail self.sig);
__functor = _: f;
};
defun' = sig: func: if length sig > 2
defun' = sig: func:
if length sig > 2
then mkFunc sig (x: defun' (tail sig) (func ((head sig) x)))
else mkFunc sig (x: ((head (tail sig)) (func ((head sig) x))));
in sig: func: if length sig < 2
in
sig: func:
if length sig < 2
then (throw "Signature must at least have two types (a -> b)")
else defun' sig func;
@ -311,21 +347,22 @@ in lib.fix (self: {
# depend on the value being of the wrapped type.
restrict = name: pred: t:
let restriction = "${t.name}[${name}]"; in typedef' {
name = restriction;
checkType = v:
let res = t.checkType v;
in
name = restriction;
checkType = v:
let res = t.checkType v;
in
if !(t.checkToBool res)
then res
else
let
iok = pred v;
in if isBool iok then {
in
if isBool iok then {
ok = iok;
err = "${prettyPrint v} does not conform to restriction '${restriction}'";
} else
# use throw here to avoid spamming the build log
# use throw here to avoid spamming the build log
throw "restriction '${restriction}' predicate returned unexpected value '${prettyPrint iok}' instead of boolean";
};
};
})

View file

@ -25,7 +25,7 @@ let
};
testPrimitives = it "checks that all primitive types match" [
(assertDoesNotThrow "unit type" (unit {}))
(assertDoesNotThrow "unit type" (unit { }))
(assertDoesNotThrow "int type" (int 15))
(assertDoesNotThrow "bool type" (bool false))
(assertDoesNotThrow "float type" (float 13.37))
@ -44,7 +44,7 @@ let
# Test that structures work as planned.
person = struct "person" {
name = string;
age = int;
age = int;
contact = option (struct {
email = string;
@ -55,7 +55,7 @@ let
testStruct = it "checks that structures work as intended" [
(assertDoesNotThrow "person struct" (person {
name = "Brynhjulf";
age = 42;
age = 42;
contact.email = "brynhjulf@yants.nix";
}))
];
@ -70,7 +70,8 @@ let
testEnum = it "checks enum definitions and matching" [
(assertEq "enum is matched correctly"
"It is in fact red!" (colour.match "red" colourMatcher))
"It is in fact red!"
(colour.match "red" colourMatcher))
(assertThrows "out of bounds enum fails"
(colour.match "alpha" (colourMatcher // {
alpha = "This should never happen";
@ -97,7 +98,8 @@ let
testSum = it "checks sum types definitions and matching" [
(assertDoesNotThrow "creature sum type" some-human)
(assertEq "sum type is matched correctly"
"It's a human named Brynhjulf" (creature.match some-human {
"It's a human named Brynhjulf"
(creature.match some-human {
human = v: "It's a human named ${v.name}";
pet = v: "It's not supposed to be a pet!";
})
@ -106,7 +108,7 @@ let
# Test curried function definitions
func = defun [ string int string ]
(name: age: "${name} is ${toString age} years old");
(name: age: "${name} is ${toString age} years old");
testFunctions = it "checks function definitions" [
(assertDoesNotThrow "function application" (func "Brynhjulf" 42))
@ -144,13 +146,13 @@ let
];
in
runTestsuite "yants" [
testPrimitives
testPoly
testStruct
testEnum
testSum
testFunctions
testTypes
testRestrict
]
runTestsuite "yants" [
testPrimitives
testPoly
testStruct
testEnum
testSum
testFunctions
testTypes
testRestrict
]

View file

@ -2,11 +2,12 @@
{ depot, pkgs, ... }:
let
checkZone = zone: file: pkgs.runCommandNoCC "${zone}-check" {} ''
checkZone = zone: file: pkgs.runCommandNoCC "${zone}-check" { } ''
${pkgs.bind}/bin/named-checkzone -i local ${zone} ${file} | tee $out
'';
in depot.nix.readTree.drvTargets {
in
depot.nix.readTree.drvTargets {
nixery-dev = checkZone "nixery.dev" ./nixery.dev.zone;
tvl-fyi = checkZone "tvl.fyi" ./tvl.fyi.zone;
tvl-su = checkZone "tvl.su" ./tvl.su.zone;

View file

@ -2,7 +2,7 @@
depot.nix.readTree.drvTargets {
# Provide a Terraform wrapper with the right provider installed.
terraform = pkgs.terraform.withPlugins(_: [
terraform = pkgs.terraform.withPlugins (_: [
depot.third_party.terraform-provider-glesys
]);
}

View file

@ -4,6 +4,8 @@ depot.third_party.naersk.buildPackage {
src = ./.;
buildInputs = with pkgs; [
pkgconfig openssl systemd.dev
pkgconfig
openssl
systemd.dev
];
}

View file

@ -2,7 +2,7 @@
depot.nix.readTree.drvTargets {
# Provide a Terraform wrapper with the right provider installed.
terraform = pkgs.terraform.withPlugins(p: [
terraform = pkgs.terraform.withPlugins (p: [
p.keycloak
]);
}

View file

@ -10,13 +10,17 @@
# This file is the Nix derivation used to build release binaries for
# several different architectures and operating systems.
let pkgs = import ((import <nixpkgs> {}).fetchFromGitHub {
owner = "NixOS";
repo = "nixpkgs-channels";
rev = "541d9cce8af7a490fb9085305939569567cb58e6";
sha256 = "0jgz72hhzkd5vyq5v69vpljjlnf0lqaz7fh327bvb3cvmwbfxrja";
}) {};
in with pkgs; buildGoPackage rec {
let
pkgs = import
((import <nixpkgs> { }).fetchFromGitHub {
owner = "NixOS";
repo = "nixpkgs-channels";
rev = "541d9cce8af7a490fb9085305939569567cb58e6";
sha256 = "0jgz72hhzkd5vyq5v69vpljjlnf0lqaz7fh327bvb3cvmwbfxrja";
})
{ };
in
with pkgs; buildGoPackage rec {
name = "kontemplate-${version}";
version = "canon";
src = ./.;
@ -29,8 +33,8 @@ in with pkgs; buildGoPackage rec {
# reason for setting the 'allowGoReference' flag.
dontStrip = true; # Linker configuration handles stripping
allowGoReference = true;
CGO_ENABLED="0";
GOCACHE="off";
CGO_ENABLED = "0";
GOCACHE = "off";
# Configure release builds via the "build-matrix" script:
buildInputs = [ git ];

View file

@ -4,7 +4,8 @@
let
inherit (builtins) listToAttrs;
inherit (lib) range;
in {
in
{
imports = [
"${depot.path}/ops/modules/atward.nix"
"${depot.path}/ops/modules/clbot.nix"
@ -55,7 +56,13 @@ in {
initrd = {
availableKernelModules = [
"igb" "xhci_pci" "nvme" "ahci" "usbhid" "usb_storage" "sr_mod"
"igb"
"xhci_pci"
"nvme"
"ahci"
"usbhid"
"usb_storage"
"sr_mod"
];
# Enable SSH in the initrd so that we can enter disk encryption
@ -189,7 +196,7 @@ in {
++ lukegb.keys.all
++ [ grfn.keys.whitby ]
++ sterni.keys.all
;
;
};
};
@ -205,7 +212,8 @@ in {
age.secrets =
let
secretFile = name: depot.ops.secrets."${name}.age";
in {
in
{
clbot.file = secretFile "clbot";
gerrit-queue.file = secretFile "gerrit-queue";
grafana.file = secretFile "grafana";
@ -509,15 +517,16 @@ in {
job_name = "node";
scrape_interval = "5s";
static_configs = [{
targets = ["localhost:${toString config.services.prometheus.exporters.node.port}"];
targets = [ "localhost:${toString config.services.prometheus.exporters.node.port}" ];
}];
} {
job_name = "nginx";
scrape_interval = "5s";
static_configs = [{
targets = ["localhost:${toString config.services.prometheus.exporters.nginx.port}"];
}
{
job_name = "nginx";
scrape_interval = "5s";
static_configs = [{
targets = [ "localhost:${toString config.services.prometheus.exporters.nginx.port}" ];
}];
}];
}];
};
services.grafana = {
@ -526,58 +535,62 @@ in {
domain = "status.tvl.su";
rootUrl = "https://status.tvl.su";
analytics.reporting.enable = false;
extraOptions = let
options = {
auth = {
generic_oauth = {
enabled = true;
client_id = "grafana";
scopes = "openid profile email";
name = "TVL";
email_attribute_path = "mail";
login_attribute_path = "sub";
name_attribute_path = "displayName";
auth_url = "https://auth.tvl.fyi/auth/realms/TVL/protocol/openid-connect/auth";
token_url = "https://auth.tvl.fyi/auth/realms/TVL/protocol/openid-connect/token";
api_url = "https://auth.tvl.fyi/auth/realms/TVL/protocol/openid-connect/userinfo";
extraOptions =
let
options = {
auth = {
generic_oauth = {
enabled = true;
client_id = "grafana";
scopes = "openid profile email";
name = "TVL";
email_attribute_path = "mail";
login_attribute_path = "sub";
name_attribute_path = "displayName";
auth_url = "https://auth.tvl.fyi/auth/realms/TVL/protocol/openid-connect/auth";
token_url = "https://auth.tvl.fyi/auth/realms/TVL/protocol/openid-connect/token";
api_url = "https://auth.tvl.fyi/auth/realms/TVL/protocol/openid-connect/userinfo";
# Give lukegb, grfn, tazjin "Admin" rights.
role_attribute_path = "((sub == 'lukegb' || sub == 'grfn' || sub == 'tazjin') && 'Admin') || 'Editor'";
# Give lukegb, grfn, tazjin "Admin" rights.
role_attribute_path = "((sub == 'lukegb' || sub == 'grfn' || sub == 'tazjin') && 'Admin') || 'Editor'";
# Allow creating new Grafana accounts from OAuth accounts.
allow_sign_up = true;
# Allow creating new Grafana accounts from OAuth accounts.
allow_sign_up = true;
};
anonymous = {
enabled = true;
org_name = "The Virus Lounge";
org_role = "Viewer";
};
basic.enabled = false;
oauth_auto_login = true;
disable_login_form = true;
};
anonymous = {
enabled = true;
org_name = "The Virus Lounge";
org_role = "Viewer";
};
basic.enabled = false;
oauth_auto_login = true;
disable_login_form = true;
};
};
inherit (builtins) typeOf replaceStrings listToAttrs concatLists;
inherit (lib) toUpper mapAttrsToList nameValuePair concatStringsSep;
inherit (builtins) typeOf replaceStrings listToAttrs concatLists;
inherit (lib) toUpper mapAttrsToList nameValuePair concatStringsSep;
# Take ["auth" "generic_oauth" "enabled"] and turn it into OPTIONS_GENERIC_OAUTH_ENABLED.
encodeName = raw: replaceStrings ["."] ["_"] (toUpper (concatStringsSep "_" raw));
# Take ["auth" "generic_oauth" "enabled"] and turn it into OPTIONS_GENERIC_OAUTH_ENABLED.
encodeName = raw: replaceStrings [ "." ] [ "_" ] (toUpper (concatStringsSep "_" raw));
# Turn an option value into a string, but we want bools to be sensible strings and not "1" or "".
optionToString = value:
if (typeOf value) == "bool" then
if value then "true" else "false"
else builtins.toString value;
# Turn an option value into a string, but we want bools to be sensible strings and not "1" or "".
optionToString = value:
if (typeOf value) == "bool" then
if value then "true" else "false"
else builtins.toString value;
# Turn an nested options attrset into a flat listToAttrs-compatible list.
encodeOptions = prefix: inp: concatLists (mapAttrsToList (name: value:
if (typeOf value) == "set"
then encodeOptions (prefix ++ [name]) value
else [ (nameValuePair (encodeName (prefix ++ [name])) (optionToString value)) ]
) inp);
in listToAttrs (encodeOptions [] options);
# Turn an nested options attrset into a flat listToAttrs-compatible list.
encodeOptions = prefix: inp: concatLists (mapAttrsToList
(name: value:
if (typeOf value) == "set"
then encodeOptions (prefix ++ [ name ]) value
else [ (nameValuePair (encodeName (prefix ++ [ name ])) (optionToString value)) ]
)
inp);
in
listToAttrs (encodeOptions [ ] options);
provision = {
enable = true;
@ -623,8 +636,8 @@ in {
security.sudo.extraRules = [
{
groups = ["wheel"];
commands = [{ command = "ALL"; options = ["NOPASSWD"]; }];
groups = [ "wheel" ];
commands = [{ command = "ALL"; options = [ "NOPASSWD" ]; }];
}
];
@ -705,7 +718,7 @@ in {
};
# Set up a user & group for git shenanigans
groups.git = {};
groups.git = { };
users.git = {
group = "git";
isSystemUser = true;

View file

@ -3,7 +3,8 @@
let
cfg = config.services.depot.atward;
description = "atward - (attempt to) cleverly route queries";
in {
in
{
options.services.depot.atward = {
enable = lib.mkEnableOption description;

View file

@ -45,7 +45,8 @@ let
# NixOS in $STATE_DIRECTORY
(cd / && ${rebuild-system}/bin/rebuild-system)
'';
in {
in
{
options.services.depot.auto-deploy = {
enable = lib.mkEnableOption description;

View file

@ -29,7 +29,8 @@ let
echo "Skipping GC, enough space available"
fi
'';
in {
in
{
options.services.depot.automatic-gc = {
enable = lib.mkEnableOption description;

View file

@ -21,7 +21,7 @@ let
(attrValues (mapAttrs (key: value: "-${key} \"${toString value}\"") flags));
# Escapes a unit name for use in systemd
systemdEscape = name: removeSuffix "\n" (readFile (runCommandNoCC "unit-name" {} ''
systemdEscape = name: removeSuffix "\n" (readFile (runCommandNoCC "unit-name" { } ''
${pkgs.systemd}/bin/systemd-escape '${name}' >> $out
''));
@ -42,7 +42,8 @@ let
};
};
};
in {
in
{
options.services.depot.clbot = {
enable = mkEnableOption description;
@ -68,7 +69,7 @@ in {
# (notably the SSH private key) readable by this user outside of
# the module.
users = {
groups.clbot = {};
groups.clbot = { };
users.clbot = {
group = "clbot";

View file

@ -1,2 +1,2 @@
# Make readTree happy at this level.
_: {}
_: { }

View file

@ -8,7 +8,8 @@ let
inherit default;
type = lib.types.str;
};
in {
in
{
options.services.depot.gerrit-queue = {
enable = lib.mkEnableOption description;
gerritUrl = mkStringOption "https://cl.tvl.fyi";

View file

@ -12,7 +12,8 @@
let
cfg = config.services.depot.git-serving;
in {
in
{
options.services.depot.git-serving = with lib; {
enable = mkEnableOption "Enable cgit & josh configuration";

View file

@ -27,7 +27,8 @@ let
exec ${depot.third_party.irccat}/bin/irccat
'';
in {
in
{
options.services.depot.irccat = {
enable = lib.mkEnableOption description;

View file

@ -9,12 +9,13 @@ let
exec -a ${name} ${depot.ops.besadii}/bin/besadii "$@"
'';
gerritHooks = pkgs.runCommandNoCC "gerrit-hooks" {} ''
gerritHooks = pkgs.runCommandNoCC "gerrit-hooks" { } ''
mkdir -p $out
ln -s ${besadiiWithConfig "change-merged"} $out/change-merged
ln -s ${besadiiWithConfig "patchset-created"} $out/patchset-created
'';
in {
in
{
services.gerrit = {
enable = true;
listenAddress = "[::]:4778"; # 4778 - grrt

View file

@ -6,7 +6,8 @@ let
cfg = config.services.depot.nixery;
description = "Nixery - container images on-demand";
storagePath = "/var/lib/nixery/${pkgs.nixpkgsCommits.unstable}";
in {
in
{
options.services.depot.nixery = {
enable = lib.mkEnableOption description;

View file

@ -19,7 +19,8 @@ let
reverse_proxy = true
set_xauthrequest = true
'';
in {
in
{
options.services.depot.oauth2_proxy = {
enable = lib.mkEnableOption description;

View file

@ -4,7 +4,8 @@
let
cfg = config.services.depot.owothia;
description = "owothia - i'm a service owo";
in {
in
{
options.services.depot.owothia = {
enable = lib.mkEnableOption description;

View file

@ -2,7 +2,8 @@
let
cfg = config.services.depot.panettone;
in {
in
{
options.services.depot.panettone = with lib; {
enable = mkEnableOption "Panettone issue tracker";
@ -62,23 +63,26 @@ in {
assertion =
cfg.dbHost != "localhost" || config.services.postgresql.enable;
message = "Panettone requires a postgresql database";
} {
assertion =
cfg.dbHost != "localhost" || config.services.postgresql.enableTCPIP;
message = "Panettone can only connect to the postgresql database over TCP";
} {
assertion =
cfg.dbHost != "localhost" || (lib.any
(user: user.name == cfg.dbUser)
config.services.postgresql.ensureUsers);
message = "Panettone requires a database user";
} {
assertion =
cfg.dbHost != "localhost" || (lib.any
(db: db == cfg.dbName)
config.services.postgresql.ensureDatabases);
message = "Panettone requires a database";
}];
}
{
assertion =
cfg.dbHost != "localhost" || config.services.postgresql.enableTCPIP;
message = "Panettone can only connect to the postgresql database over TCP";
}
{
assertion =
cfg.dbHost != "localhost" || (lib.any
(user: user.name == cfg.dbUser)
config.services.postgresql.ensureUsers);
message = "Panettone requires a database user";
}
{
assertion =
cfg.dbHost != "localhost" || (lib.any
(db: db == cfg.dbName)
config.services.postgresql.ensureDatabases);
message = "Panettone requires a database";
}];
systemd.services.panettone = {
wantedBy = [ "multi-user.target" ];

View file

@ -3,7 +3,8 @@
let
cfg = config.services.depot.paroxysm;
description = "TVL's majestic IRC bot";
in {
in
{
options.services.depot.paroxysm.enable = lib.mkEnableOption description;
config = lib.mkIf cfg.enable {

View file

@ -8,7 +8,8 @@ let
enableDaemon = true;
withKDE = false;
};
in {
in
{
options.services.depot.quassel = with lib; {
enable = mkEnableOption "Quassel IRC daemon";
@ -70,7 +71,7 @@ in {
group = "quassel";
};
groups.quassel = {};
groups.quassel = { };
};
};
}

View file

@ -14,7 +14,8 @@ let
inherit default;
type = lib.types.str;
};
in {
in
{
options.services.depot.restic = {
enable = lib.mkEnableOption description;
bucketEndpoint = mkStringOption "objects.dc-sto1.glesys.net";

View file

@ -27,8 +27,9 @@ let
prepareArgs = args:
concatStringsSep " "
(attrValues (mapAttrs (key: value: "-${key} \"${toString value}\"")
(args // overrideArgs)));
in {
(args // overrideArgs)));
in
{
options.services.depot.smtprelay = {
enable = mkEnableOption description;

View file

@ -4,7 +4,8 @@
let
cfg = config.services.depot.sourcegraph;
in {
in
{
options.services.depot.sourcegraph = with lib; {
enable = mkEnableOption "SourceGraph code search engine";
@ -51,7 +52,8 @@ in {
# Sourcegraph needs a higher nofile limit, it logs warnings
# otherwise (unclear whether it actually affects the service).
extraOptions = [
"--ulimit" "nofile=10000:10000"
"--ulimit"
"nofile=10000:10000"
];
};
};

View file

@ -13,7 +13,7 @@ let
# All Buildkite hooks are actually besadii, but it's being invoked
# with different names.
buildkiteHooks = pkgs.runCommandNoCC "buildkite-hooks" {} ''
buildkiteHooks = pkgs.runCommandNoCC "buildkite-hooks" { } ''
mkdir -p $out/bin
ln -s ${besadiiWithConfig "post-command"} $out/bin/post-command
'';
@ -22,7 +22,8 @@ let
echo 'username=buildkite'
echo "password=$(jq -r '.gerritPassword' /run/agenix/buildkite-besadii-config)"
'';
in {
in
{
options.services.depot.buildkite = {
enable = lib.mkEnableOption description;
agentCount = lib.mkOption {
@ -33,39 +34,43 @@ in {
config = lib.mkIf cfg.enable {
# Run the Buildkite agents using the default upstream module.
services.buildkite-agents = builtins.listToAttrs (map (n: rec {
name = "whitby-${toString n}";
value = {
inherit name;
enable = true;
tokenPath = "/run/agenix/buildkite-agent-token";
hooks.post-command = "${buildkiteHooks}/bin/post-command";
services.buildkite-agents = builtins.listToAttrs (map
(n: rec {
name = "whitby-${toString n}";
value = {
inherit name;
enable = true;
tokenPath = "/run/agenix/buildkite-agent-token";
hooks.post-command = "${buildkiteHooks}/bin/post-command";
runtimePackages = with pkgs; [
bash
coreutils
credentialHelper
curl
git
gnutar
gzip
jq
nix
];
};
}) agents);
runtimePackages = with pkgs; [
bash
coreutils
credentialHelper
curl
git
gnutar
gzip
jq
nix
];
};
})
agents);
# Set up a group for all Buildkite agent users
users = {
groups.buildkite-agents = {};
users = builtins.listToAttrs (map (n: rec {
name = "buildkite-agent-whitby-${toString n}";
value = {
isSystemUser = true;
group = lib.mkForce "buildkite-agents";
extraGroups = [ name "docker" ];
};
}) agents);
groups.buildkite-agents = { };
users = builtins.listToAttrs (map
(n: rec {
name = "buildkite-agent-whitby-${toString n}";
value = {
isSystemUser = true;
group = lib.mkForce "buildkite-agents";
extraGroups = [ name "docker" ];
};
})
agents);
};
};
}

View file

@ -26,7 +26,8 @@ let
inherit (depot.ops) users;
in {
in
{
services.openldap = {
enable = true;
@ -48,7 +49,7 @@ in {
"cn=schema".includes =
map (schema: "${pkgs.openldap}/etc/schema/${schema}.ldif")
[ "core" "cosine" "inetorgperson" "nis" ];
[ "core" "cosine" "inetorgperson" "nis" ];
};
# Contents are immutable at runtime, and adding user accounts etc.

View file

@ -16,9 +16,10 @@ let
drvTargets = depot.ci.targets;
additionalSteps = [ protoCheck ];
parentTargetMap = if (externalArgs ? parentTargetMap)
parentTargetMap =
if (externalArgs ? parentTargetMap)
then builtins.fromJSON (builtins.readFile externalArgs.parentTargetMap)
else {};
else { };
postBuildSteps = [
# After successful builds, create a gcroot for builds on canon.
@ -40,7 +41,8 @@ let
};
drvmap = depot.nix.buildkite.mkDrvmap depot.ci.targets;
in pkgs.runCommandNoCC "depot-pipeline" {} ''
in
pkgs.runCommandNoCC "depot-pipeline" { } ''
mkdir $out
cp -r ${pipeline}/* $out
cp ${drvmap} $out/drvmap.json

View file

@ -22,6 +22,6 @@ in
defun [ path (attrs agenixSecret) (attrs any) ]
(path: secrets:
depot.nix.readTree.drvTargets
# Import each secret into the Nix store
(builtins.mapAttrs (name: _: "${path}/${name}") secrets))
depot.nix.readTree.drvTargets
# Import each secret into the Nix store
(builtins.mapAttrs (name: _: "${path}/${name}") secrets))

View file

@ -15,7 +15,8 @@ let
whitby = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILNh/w4BSKov0jdz3gKBc98tpoLta5bb87fQXWBhAl2I";
default.publicKeys = tazjin ++ grfn ++ sterni ++ [ whitby ];
in {
in
{
"besadii.age" = default;
"buildkite-agent-token.age" = default;
"buildkite-graphql-token.age" = default;

View file

@ -8,7 +8,7 @@ in pkgs.abseil-cpp.override {
/* TODO(tazjin): update abseil subtree
fullLlvm11Stdenv.mkDerivation rec {
fullLlvm11Stdenv.mkDerivation rec {
pname = "abseil-cpp";
version = "20200519-768eb2ca+tvl-1";
src = ./.;
@ -17,15 +17,15 @@ fullLlvm11Stdenv.mkDerivation rec {
# doCheck = true;
cmakeFlags = [
"-DCMAKE_CXX_STANDARD=17"
#"-DABSL_RUN_TESTS=1"
"-DCMAKE_CXX_STANDARD=17"
#"-DABSL_RUN_TESTS=1"
];
meta = with lib; {
description = "An open-source collection of C++ code designed to augment the C++ standard library";
homepage = https://abseil.io/;
license = licenses.asl20;
maintainers = [ maintainers.andersk ];
description = "An open-source collection of C++ code designed to augment the C++ standard library";
homepage = https://abseil.io/;
license = licenses.asl20;
maintainers = [ maintainers.andersk ];
};
}
}
*/

View file

@ -9,7 +9,8 @@ let
agenix = import src {
inherit pkgs;
};
in {
in
{
inherit src;
cli = agenix.agenix;
}

View file

@ -1,8 +1,10 @@
{ pkgs, ... }:
(import (pkgs.fetchFromGitHub {
owner = "hercules-ci";
repo = "arion";
rev = "db6d4d7490dff363de60cebbece3ae9361e3ce43";
sha256 = "0d8nqmc7fjshigax2g47ips262v8ml27x0ksq59kmprgb7ckzi5l";
}) { inherit pkgs; }).arion
(import
(pkgs.fetchFromGitHub {
owner = "hercules-ci";
repo = "arion";
rev = "db6d4d7490dff363de60cebbece3ae9361e3ce43";
sha256 = "0d8nqmc7fjshigax2g47ips262v8ml27x0ksq59kmprgb7ckzi5l";
})
{ inherit pkgs; }).arion

View file

@ -8,7 +8,8 @@
let
inherit (pkgs) bat runCommandNoCC;
in runCommandNoCC "bat-syntaxes.bin" {} ''
in
runCommandNoCC "bat-syntaxes.bin" { } ''
export HOME=$PWD
mkdir -p .config/bat/syntaxes
cp ${./Prolog.sublime-syntax} .config/bat/syntaxes

View file

@ -2,7 +2,8 @@
let
inherit (pkgs) stdenv gzip bzip2 xz luajit zlib autoconf openssl pkgconfig;
in stdenv.mkDerivation rec {
in
stdenv.mkDerivation rec {
pname = "cgit";
version = "master";
src = ./.;

View file

@ -5,4 +5,5 @@ pkgs.callPackage "${(pkgs.fetchFromGitHub {
repo = "clj2nix";
rev = "3d0a38c954c8e0926f57de1d80d357df05fc2f94";
sha256 = "0y77b988qdgsrp4w72v1f5rrh33awbps2qdgp2wr2nmmi44541w5";
})}/clj2nix.nix" {}
})}/clj2nix.nix"
{ }

View file

@ -24,32 +24,33 @@
# be able to pass `specialArgs`. We depend on this because `depot`
# needs to be partially evaluated in NixOS configuration before
# module imports are resolved.
nixos = {
configuration,
specialArgs ? {},
system ? builtins.currentSystem,
...
}:
let
eval = import "${pkgs.path}/nixos/lib/eval-config.nix" {
inherit specialArgs system;
modules = [
configuration
(import "${depot.path + "/ops/modules/default-imports.nix"}")
];
};
nixos =
{ configuration
, specialArgs ? { }
, system ? builtins.currentSystem
, ...
}:
let
eval = import "${pkgs.path}/nixos/lib/eval-config.nix" {
inherit specialArgs system;
modules = [
configuration
(import "${depot.path + "/ops/modules/default-imports.nix"}")
];
};
# This is for `nixos-rebuild build-vm'.
vmConfig = (import "${pkgs.path}/nixos/lib/eval-config.nix" {
inherit specialArgs system;
modules = [
configuration
"${pkgs.path}/nixos/modules/virtualisation/qemu-vm.nix"
];
}).config;
in {
inherit (eval) pkgs config options;
system = eval.config.system.build.toplevel;
vm = vmConfig.system.build.vm;
};
# This is for `nixos-rebuild build-vm'.
vmConfig = (import "${pkgs.path}/nixos/lib/eval-config.nix" {
inherit specialArgs system;
modules = [
configuration
"${pkgs.path}/nixos/modules/virtualisation/qemu-vm.nix"
];
}).config;
in
{
inherit (eval) pkgs config options;
system = eval.config.system.build.toplevel;
vm = vmConfig.system.build.vm;
};
}

View file

@ -5,11 +5,14 @@ let
# broken most of the time. The binaries are also fully static
# builds, instead of the half-static crap that nixpkgs produces.
easy-dhall-nix =
import (builtins.fetchTarball {
url = "https://github.com/justinwoo/easy-dhall-nix/archive/eae7f64c4d6c70681e5a56c84198236930ba425e.tar.gz";
sha256 = "1y2x15v8a679vlpxazjpibfwajp6zph60f8wjcm4xflbvazk0dx7";
}) { inherit pkgs; };
in {
import
(builtins.fetchTarball {
url = "https://github.com/justinwoo/easy-dhall-nix/archive/eae7f64c4d6c70681e5a56c84198236930ba425e.tar.gz";
sha256 = "1y2x15v8a679vlpxazjpibfwajp6zph60f8wjcm4xflbvazk0dx7";
})
{ inherit pkgs; };
in
{
dhall = easy-dhall-nix.dhall-simple;
dhall-bash = easy-dhall-nix.dhall-bash-simple;
dhall-docs = easy-dhall-nix.dhall-docs-simple;

View file

@ -7,9 +7,11 @@
{ pkgs, ... }:
(import (pkgs.fetchFromGitHub {
owner = "NixOS";
repo = "nixpkgs";
rev = "14f9ee66e63077539252f8b4550049381a082518";
sha256 = "1wn7nmb1cqfk2j91l3rwc6yhimfkzxprb8wknw5wi57yhq9m6lv1";
}) {}).elmPackages
(import
(pkgs.fetchFromGitHub {
owner = "NixOS";
repo = "nixpkgs";
rev = "14f9ee66e63077539252f8b4550049381a082518";
sha256 = "1wn7nmb1cqfk2j91l3rwc6yhimfkzxprb8wknw5wi57yhq9m6lv1";
})
{ }).elmPackages

View file

@ -1,33 +1,35 @@
{ depot, pkgs, ... }:
{
buildGerritBazelPlugin = {
name,
src,
depsOutputHash,
overlayPluginCmd ? ''
cp -R "${src}" "$out/plugins/${name}"
'',
postPatch ? "",
}: ((depot.third_party.gerrit.override {
name = "${name}.jar";
buildGerritBazelPlugin =
{ name
, src
, depsOutputHash
, overlayPluginCmd ? ''
cp -R "${src}" "$out/plugins/${name}"
''
, postPatch ? ""
,
}: ((depot.third_party.gerrit.override {
name = "${name}.jar";
src = pkgs.runCommandLocal "${name}-src" {} ''
cp -R "${depot.third_party.gerrit.src}" "$out"
chmod +w "$out/plugins"
${overlayPluginCmd}
'';
src = pkgs.runCommandLocal "${name}-src" { } ''
cp -R "${depot.third_party.gerrit.src}" "$out"
chmod +w "$out/plugins"
${overlayPluginCmd}
'';
bazelTarget = "//plugins/${name}";
}).overrideAttrs (super: {
deps = super.deps.overrideAttrs (superDeps: {
outputHash = depsOutputHash;
});
installPhase = ''
cp "bazel-bin/plugins/${name}/${name}.jar" "$out"
'';
postPatch = if super ? postPatch then ''
${super.postPatch}
${postPatch}
'' else postPatch;
}));
bazelTarget = "//plugins/${name}";
}).overrideAttrs (super: {
deps = super.deps.overrideAttrs (superDeps: {
outputHash = depsOutputHash;
});
installPhase = ''
cp "bazel-bin/plugins/${name}/${name}.jar" "$out"
'';
postPatch =
if super ? postPatch then ''
${super.postPatch}
${postPatch}
'' else postPatch;
}));
}

View file

@ -2,7 +2,8 @@
let
inherit (import ./builder.nix args) buildGerritBazelPlugin;
in depot.nix.readTree.drvTargets {
in
depot.nix.readTree.drvTargets {
# https://gerrit.googlesource.com/plugins/owners
owners = buildGerritBazelPlugin rec {
name = "owners";

View file

@ -2,7 +2,8 @@
let
inherit (import ../builder.nix args) buildGerritBazelPlugin;
in buildGerritBazelPlugin rec {
in
buildGerritBazelPlugin rec {
name = "oauth";
depsOutputHash = "sha256:0j86amkw54y177s522hc988hqg034fsrkywbsb9a7h14zwcqbran";
src = pkgs.fetchgit {

View file

@ -2,8 +2,8 @@
# `pkgs.srcOnly`.
{ pkgs, ... }:
pkgs.git.overrideAttrs(old: {
patches = (old.patches or []) ++ [
pkgs.git.overrideAttrs (old: {
patches = (old.patches or [ ]) ++ [
./0001-feat-third_party-git-date-add-dottime-format.patch
];
})

View file

@ -1,14 +1,17 @@
{ pkgs, ... }:
let
gitignoreNix = import (pkgs.fetchFromGitHub {
owner = "hercules-ci";
repo = "gitignore";
rev = "f9e996052b5af4032fe6150bba4a6fe4f7b9d698";
sha256 = "0jrh5ghisaqdd0vldbywags20m2cxpkbbk5jjjmwaw0gr8nhsafv";
}) { inherit (pkgs) lib; };
gitignoreNix = import
(pkgs.fetchFromGitHub {
owner = "hercules-ci";
repo = "gitignore";
rev = "f9e996052b5af4032fe6150bba4a6fe4f7b9d698";
sha256 = "0jrh5ghisaqdd0vldbywags20m2cxpkbbk5jjjmwaw0gr8nhsafv";
})
{ inherit (pkgs) lib; };
in {
in
{
__functor = _: gitignoreNix.gitignoreSource;
# expose extra functions here

View file

@ -3,15 +3,17 @@
depot.nix.buildGo.external {
path = "github.com/charmbracelet/bubbletea";
src =
let gitSrc = pkgs.fetchFromGitHub {
let
gitSrc = pkgs.fetchFromGitHub {
owner = "charmbracelet";
repo = "bubbletea";
rev = "v0.13.1";
sha256 = "0yf2fjkvx8ym9n6f3qp2z7sxs0qsfpj148sfvbrp38k67s3h20cs";
};
# The examples/ directory is fairly extensive,
# but it also adds most of the dependencies.
in pkgs.runCommand gitSrc.name {} ''
# The examples/ directory is fairly extensive,
# but it also adds most of the dependencies.
in
pkgs.runCommand gitSrc.name { } ''
mkdir -p $out
ln -s "${gitSrc}"/* $out
rm -r $out/examples

View file

@ -5,7 +5,7 @@
stdenv = pkgs.fullLlvm11Stdenv;
abseil-cpp = depot.third_party.abseil_cpp;
re2 = depot.third_party.re2;
}).overrideAttrs(orig: rec {
}).overrideAttrs (orig: rec {
cmakeFlags = orig.cmakeFlags ++ [
"-DCMAKE_CXX_STANDARD_REQUIRED=ON"
"-DCMAKE_CXX_STANDARD=17"

View file

@ -2,7 +2,7 @@
(pkgs.gtest.override {
stdenv = pkgs.fullLlvm11Stdenv;
}).overrideAttrs(_: {
}).overrideAttrs (_: {
src = pkgs.fetchFromGitHub {
owner = "google";
repo = "googletest";

View file

@ -8,7 +8,8 @@ let
rev = "69dc986e506ba5631c8bbf52835da076a18ec8dc";
hash = "sha256:0ybc6ivjkm7bchaszs9lhbl1gbjnyhwq7a3vw6jml3ama84l52lb";
};
in depot.third_party.naersk.buildPackage {
in
depot.third_party.naersk.buildPackage {
inherit src;
buildInputs = with pkgs; [
@ -18,8 +19,11 @@ in depot.third_party.naersk.buildPackage {
];
cargoBuildOptions = x: x ++ [
"-p" "josh"
"-p" "josh-proxy"
"-p" "josh-ui"
"-p"
"josh"
"-p"
"josh-proxy"
"-p"
"josh-ui"
];
}

View file

@ -5,7 +5,8 @@
let
src = with pkgs; srcOnly lispPackages.bordeaux-threads;
getSrc = f: "${src}/src/${f}";
in depot.nix.buildLisp.library {
in
depot.nix.buildLisp.library {
name = "bordeaux-threads";
deps = [ depot.third_party.lisp.alexandria ];

Some files were not shown because too many files have changed in this diff Show more