2019-12-12 04:23:09 +01:00
|
|
|
# Copyright 2019 Google LLC.
|
|
|
|
# SPDX-License-Identifier: Apache-2.0
|
2019-12-13 00:00:20 +01:00
|
|
|
{ pkgs, program, package }:
|
2019-12-12 04:23:09 +01:00
|
|
|
|
|
|
|
let
|
2019-12-13 00:30:47 +01:00
|
|
|
inherit (builtins)
|
|
|
|
elemAt
|
|
|
|
foldl'
|
|
|
|
fromJSON
|
|
|
|
head
|
|
|
|
length
|
2019-12-13 01:07:47 +01:00
|
|
|
listToAttrs
|
2019-12-13 00:30:47 +01:00
|
|
|
readFile
|
|
|
|
replaceStrings
|
|
|
|
tail
|
|
|
|
throw;
|
|
|
|
|
2019-12-13 00:00:20 +01:00
|
|
|
inherit (pkgs) lib runCommand go jq ripgrep;
|
|
|
|
|
|
|
|
pathToName = p: replaceStrings ["/"] ["_"] (toString p);
|
|
|
|
|
2019-12-12 04:23:09 +01:00
|
|
|
# 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" {} ''
|
2019-12-20 15:30:36 +01:00
|
|
|
export HOME=$PWD
|
2019-12-12 04:23:09 +01:00
|
|
|
export GOPATH=/dev/null
|
|
|
|
${go}/bin/go list all | \
|
|
|
|
${ripgrep}/bin/rg -v 'vendor' | \
|
|
|
|
${jq}/bin/jq -R '.' | \
|
|
|
|
${jq}/bin/jq -c -s 'map({key: ., value: true}) | from_entries' \
|
|
|
|
> $out
|
|
|
|
'';
|
|
|
|
|
|
|
|
analyser = program {
|
|
|
|
name = "analyser";
|
|
|
|
|
|
|
|
srcs = [
|
|
|
|
./main.go
|
|
|
|
];
|
|
|
|
|
|
|
|
x_defs = {
|
|
|
|
"main.stdlibList" = "${stdlibPackages}";
|
|
|
|
};
|
|
|
|
};
|
2019-12-13 00:00:20 +01:00
|
|
|
|
|
|
|
mkset = path: value:
|
|
|
|
if path == [] then { gopkg = value; }
|
|
|
|
else { "${head path}" = mkset (tail path) value; };
|
|
|
|
|
2019-12-13 00:26:08 +01:00
|
|
|
last = l: elemAt l ((length l) - 1);
|
|
|
|
|
2019-12-13 01:07:47 +01:00
|
|
|
toPackage = self: src: path: depMap: entry:
|
2019-12-13 00:26:08 +01:00
|
|
|
let
|
2019-12-13 01:07:47 +01:00
|
|
|
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 ] (
|
|
|
|
throw "missing foreign dependency '${d}' in '${path}'"
|
|
|
|
) depMap) entry.foreignDeps;
|
|
|
|
|
2019-12-13 00:26:08 +01:00
|
|
|
args = {
|
|
|
|
srcs = map (f: src + ("/" + f)) entry.files;
|
2019-12-13 01:07:47 +01:00
|
|
|
deps = localDeps ++ foreignDeps;
|
2019-12-13 00:26:08 +01:00
|
|
|
};
|
2019-12-13 01:07:47 +01:00
|
|
|
|
2019-12-13 00:26:08 +01:00
|
|
|
libArgs = args // {
|
|
|
|
name = pathToName entry.name;
|
|
|
|
path = lib.concatStringsSep "/" ([ path ] ++ entry.locator);
|
2019-12-13 16:15:53 +01:00
|
|
|
sfiles = map (f: src + ("/" + f)) entry.sfiles;
|
2019-12-13 00:26:08 +01:00
|
|
|
};
|
2019-12-13 01:07:47 +01:00
|
|
|
|
2019-12-13 00:26:08 +01:00
|
|
|
binArgs = args // {
|
2019-12-15 16:57:10 +01:00
|
|
|
name = (last ((lib.splitString "/" path) ++ entry.locator));
|
2019-12-13 00:26:08 +01:00
|
|
|
};
|
|
|
|
in if entry.isCommand then (program binArgs) else (package libArgs);
|
2019-12-13 00:00:20 +01:00
|
|
|
|
|
|
|
in { src, path, deps ? [] }: let
|
2019-12-13 01:07:47 +01:00
|
|
|
# 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;
|
|
|
|
}) deps);
|
|
|
|
|
2019-12-13 00:00:20 +01:00
|
|
|
name = pathToName path;
|
|
|
|
analysisOutput = runCommand "${name}-structure.json" {} ''
|
|
|
|
${analyser}/bin/analyser -path ${path} -source ${src} > $out
|
|
|
|
'';
|
|
|
|
analysis = fromJSON (readFile analysisOutput);
|
|
|
|
in lib.fix(self: foldl' lib.recursiveUpdate {} (
|
2019-12-13 01:07:47 +01:00
|
|
|
map (entry: mkset entry.locator (toPackage self src path depMap entry)) analysis
|
2019-12-13 00:00:20 +01:00
|
|
|
))
|