indexer/flake.nix
Ricardo (XenGi) Band 63c6f4b761
Some checks failed
CI pipeline for ffd-indexer / checks (go test + golangci) (push) Failing after 26s
CI pipeline for ffd-indexer / build binaries + containers (push) Failing after 3s
CI pipeline for ffd-indexer / format (gofmt + nixfmt) (push) Failing after 3s
CI pipeline for ffd-indexer / integration (live scrape + Typesense) (push) Failing after 20s
🔥
2026-10-01 00:37:44 +02:00

221 lines
8.1 KiB
Nix

{
description = "Federated Forge Discovery Indexer";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable-small";
flake-utils.url = "github:numtide/flake-utils";
gomod2nix = {
url = "github:tweag/gomod2nix";
inputs.nixpkgs.follows = "nixpkgs";
inputs.flake-utils.follows = "flake-utils";
};
};
outputs =
{
self,
nixpkgs,
flake-utils,
gomod2nix,
}:
flake-utils.lib.eachDefaultSystem (
system:
let
pkgs = import nixpkgs {
inherit system;
overlays = [ gomod2nix.overlays.default ];
};
go = pkgs.go_1_27;
version = "0.0.1";
# Git commit (full + short) used for container labels. Inside a real
# flake build (including CI's shallow clone) `self.rev` is populated;
# on a dirty working tree it is null and we fall back to empty so the
# label is simply omitted.
rev = self.rev or "";
shortRev =
if rev != "" then
builtins.substring 0 7 rev
else
(self.dirtyShortRev or "");
# Inject version + commit into the binaries via the Go linker, and
# reuse the same values for the OCI image labels.
goLdflags = [
"-X git.xengi.de/ffd/indexer/internal/version.Version=${version}"
"-X git.xengi.de/ffd/indexer/internal/version.Commit=${shortRev}"
];
ffd-indexer = pkgs.buildGoApplication {
inherit go;
pname = "ffd-indexer";
inherit version;
ldflags = goLdflags;
src = ./.;
modules = ./gomod2nix.toml;
# buildGoApplication runs `go install ./...`, which names each binary
# after the last element of its package path:
# git.xengi.de/ffd/indexer -> "indexer"
# git.xengi.de/ffd/indexer/cmd/ffd-metrics -> "ffd-metrics"
# Rename "indexer" to the service/container name "ffd-indexer".
postInstall = ''
mv "$out/bin/indexer" "$out/bin/ffd-indexer"
'';
};
# Long-running Prometheus metrics daemon. It is a separate binary but is
# built in the same derivation; keep it as its own output alias for the
# NixOS module and containers.
ffd-metrics = pkgs.runCommand "ffd-metrics" { } ''
mkdir -p "$out/bin"
ln -s "${ffd-indexer}/bin/ffd-metrics" "$out/bin/ffd-metrics"
'';
go-test = pkgs.stdenv.mkDerivation {
name = "go-test";
dontBuild = true;
src = ./.;
doCheck = true;
nativeBuildInputs = [
go
pkgs.writableTmpDirAsHomeHook
];
checkPhase = ''
go test -v ./...
'';
installPhase = ''
mkdir "$out"
'';
};
go-lint = pkgs.stdenv.mkDerivation {
name = "go-lint";
dontBuild = true;
src = ./.;
doCheck = true;
nativeBuildInputs = [
pkgs.golangci-lint
go
pkgs.writableTmpDirAsHomeHook
];
checkPhase = ''
golangci-lint run
'';
installPhase = ''
mkdir "$out"
'';
};
in
{
checks = { inherit go-test go-lint; };
formatter = pkgs.nixfmt-tree;
devShells.default = pkgs.mkShell {
buildInputs = [
go
pkgs.go-tools # staticcheck
gomod2nix.packages.${system}.default
];
packages = with pkgs; [
mkcert
sqlite # debugging the index db
typesense
skopeo # copy OCI/container images to a registry (CI publishing)
];
shellHook = ''
# Local dev Typesense defaults (see packages.typesense-server).
export TYPESENSE_API_KEY="''${TYPESENSE_API_KEY:-dev-key}"
export TYPESENSE_URL="''${TYPESENSE_URL:-http://localhost:8108}"
echo "Typesense dev: run 'typesense-server' (port 8108, api key $TYPESENSE_API_KEY)"
'';
};
packages = {
default = ffd-indexer;
inherit ffd-metrics;
# Runs a local Typesense instance for development.
typesense-server = pkgs.writeScriptBin "typesense-server" ''
#!${pkgs.bash}/bin/bash
set -euo pipefail
ROOT="$(git rev-parse --show-toplevel 2>/dev/null || echo "$PWD")"
DATA_DIR="$ROOT/.typesense/data"
API_KEY="''${TYPESENSE_API_KEY:-dev-key}"
PORT="''${TYPESENSE_PORT:-8108}"
# Peering port follows the API port so multiple dev instances
# (different TYPESENSE_PORT) do not collide on the default 8107.
PEERING_PORT=$((PORT - 1))
mkdir -p "$DATA_DIR"
echo "Starting Typesense on 127.0.0.1:$PORT (api key: $API_KEY, data: $DATA_DIR)"
exec ${pkgs.typesense}/bin/typesense-server \
--data-dir="$DATA_DIR" \
--api-key="$API_KEY" \
--api-port="$PORT" \
--peering-port="$PEERING_PORT" \
--api-address=127.0.0.1 \
--enable-cors
'';
container = pkgs.dockerTools.buildImage {
name = "ffd-indexer";
contents = [
ffd-indexer
pkgs.cacert # TLS CA for HTTPS requests to the forges
];
config = {
# The user must provide their own config file and mount it at
# /etc/ffd-indexer/config.yaml, e.g.:
# docker run -v $PWD/config.yaml:/etc/ffd-indexer/config.yaml ffd-indexer
Labels = {
"org.opencontainers.image.title" = "ffd-indexer";
"org.opencontainers.image.description" = "Federated Forge Discovery Indexer (scraper)";
"org.opencontainers.image.licenses" = "AGPL-3.0-or-later";
"org.opencontainers.image.source" = "https://git.xengi.de/ffd/indexer";
"org.opencontainers.image.vendor" = "ffd";
"org.opencontainers.image.version" = version;
"org.opencontainers.image.revision" = shortRev;
};
Volumes = {
"/etc/ffd-indexer" = { };
};
Cmd = [
"${ffd-indexer}/bin/ffd-indexer"
"-config"
"/etc/ffd-indexer/config.yaml"
];
};
};
# Long-running metrics image. It shares the same config file shape and
# reads the same DB volume as the indexer.
container-metrics = pkgs.dockerTools.buildImage {
name = "ffd-metrics";
contents = [
ffd-indexer
pkgs.cacert
];
config = {
Labels = {
"org.opencontainers.image.title" = "ffd-metrics";
"org.opencontainers.image.description" = "Federated Forge Discovery Indexer (Prometheus metrics daemon)";
"org.opencontainers.image.licenses" = "AGPL-3.0-or-later";
"org.opencontainers.image.source" = "https://git.xengi.de/ffd/indexer";
"org.opencontainers.image.vendor" = "ffd";
"org.opencontainers.image.version" = version;
"org.opencontainers.image.revision" = shortRev;
};
Volumes = {
"/etc/ffd-indexer" = { };
};
ExposedPorts = {
"9090/tcp" = { };
};
Cmd = [
"${ffd-indexer}/bin/ffd-metrics"
"-config"
"/etc/ffd-indexer/config.yaml"
];
};
};
};
nixosModules.default = import ./option.nix;
}
)
// {
# Overlay so the NixOS module's default package (`pkgs.ffd-indexer`)
# resolves to this flake's package.
overlays.default = final: prev: {
ffd-indexer = self.packages.${final.system}.default;
ffd-metrics = self.packages.${final.system}.ffd-metrics;
};
};
}