{ stdenv , lib , pkgs , coreutils }: { name ? "${baseAttrs.pname}-${baseAttrs.version}" , bazelTargets , bazel ? pkgs.bazel , depsHash , extraCacheInstall ? "" , extraBuildSetup ? "" , extraBuildInstall ? "" , ... }@baseAttrs: let cleanAttrs = lib.flip removeAttrs [ "bazelTargets" "depsHash" "extraCacheInstall" "extraBuildSetup" "extraBuildInstall" ]; attrs = cleanAttrs baseAttrs; base = stdenv.mkDerivation (attrs // { nativeBuildInputs = (attrs.nativeBuildInputs or []) ++ [ bazel ]; preUnpack = '' if [[ ! -d $HOME ]]; then export HOME=$NIX_BUILD_TOP/home mkdir -p $HOME fi ''; bazelTargetNames = builtins.attrNames bazelTargets; }); cache = base.overrideAttrs (base: { name = "${name}-deps"; bazelPhase = "cache"; buildPhase = '' runHook preBuild bazel sync --repository_cache=repository-cache $bazelFlags "''${bazelFlagsArray[@]}" bazel build --repository_cache=repository-cache --nobuild $bazelFlags "''${bazelFlagsArray[@]}" $bazelTargetNames runHook postBuild ''; installPhase = '' runHook preInstall mkdir $out echo "${bazel.version}" > $out/bazel_version cp -R repository-cache $out/repository-cache ${extraCacheInstall} runHook postInstall ''; outputHashMode = "recursive"; outputHash = depsHash; }); build = base.overrideAttrs (base: { bazelPhase = "build"; inherit cache; nativeBuildInputs = (base.nativeBuildInputs or []) ++ [ coreutils ]; buildPhase = '' runHook preBuild ${extraBuildSetup} bazel build --repository_cache=$cache/repository-cache $bazelFlags "''${bazelFlagsArray[@]}" $bazelTargetNames runHook postBuild ''; installPhase = '' runHook preInstall ${builtins.concatStringsSep "\n" (lib.mapAttrsToList (target: outPath: lib.optionalString (outPath != null) '' TARGET_OUTPUTS="$(bazel cquery --repository_cache=$cache/repository-cache $bazelFlags "''${bazelFlagsArray[@]}" --output=files "${target}")" if [[ "$(echo "$TARGET_OUTPUTS" | wc -l)" -gt 1 ]]; then echo "Installing ${target}'s outputs ($TARGET_OUTPUTS) into ${outPath} as a directory" mkdir -p "${outPath}" cp $TARGET_OUTPUTS "${outPath}" else echo "Installing ${target}'s output ($TARGET_OUTPUTS) to ${outPath}" mkdir -p "${dirOf outPath}" cp "$TARGET_OUTPUTS" "${outPath}" fi '') bazelTargets)} ${extraBuildInstall} runHook postInstall ''; }); in build