114 lines
3.2 KiB
Nix
114 lines
3.2 KiB
Nix
# Copyright 2019 Google LLC.
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
{ pkgs, program, package }:
|
|
|
|
let
|
|
inherit (builtins)
|
|
elemAt
|
|
foldl'
|
|
fromJSON
|
|
head
|
|
length
|
|
listToAttrs
|
|
readFile
|
|
replaceStrings
|
|
tail
|
|
throw;
|
|
|
|
inherit (pkgs) lib runCommand go jq ripgrep;
|
|
|
|
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" { } ''
|
|
export HOME=$PWD
|
|
export GOPATH=/dev/null
|
|
${go}/bin/go list std | \
|
|
${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}";
|
|
};
|
|
};
|
|
|
|
mkset = path: 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: cgodeps:
|
|
let
|
|
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)
|
|
(lib.filter (d: d.path != "C") entry.foreignDeps);
|
|
|
|
args = {
|
|
srcs = map (f: src + ("/" + f)) entry.files;
|
|
deps = localDeps ++ foreignDeps;
|
|
};
|
|
|
|
libArgs = args // {
|
|
name = pathToName entry.name;
|
|
path = lib.concatStringsSep "/" ([ path ] ++ entry.locator);
|
|
sfiles = map (f: src + ("/" + f)) entry.sfiles;
|
|
cgofiles = map (f: src + ("/" + f)) entry.cgofiles;
|
|
inherit cgodeps;
|
|
inherit (entry) packageName cgocflags cgoldflags;
|
|
cfiles = map (f: src + ("/" + f)) entry.cfiles;
|
|
cxxfiles = map (f: src + ("/" + f)) entry.cxxfiles;
|
|
};
|
|
|
|
binArgs = args // {
|
|
name = (last ((lib.splitString "/" path) ++ entry.locator));
|
|
};
|
|
in
|
|
if entry.isCommand then (program binArgs) else (package libArgs);
|
|
|
|
in
|
|
{ src, path, deps ? [ ], tags ? [ ], cgo ? false, cgodeps ? [ ] }:
|
|
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));
|
|
|
|
name = pathToName path;
|
|
analysisOutput = runCommand "${name}-structure.json" { } ''
|
|
${analyser}/bin/analyser -path ${path} -source ${src} -tags "${lib.concatStringsSep " " tags}" ${if cgo then "-cgo" else ""} > $out
|
|
'';
|
|
analysis = fromJSON (readFile analysisOutput);
|
|
in
|
|
lib.fix (self: foldl' lib.recursiveUpdate { } (
|
|
map (entry: mkset entry.locator (toPackage self src path depMap entry cgodeps)) analysis
|
|
))
|