-*- mode: org -*- #+TITLE: configuration nix #+DESCRIPTION: spine-search nix configuration #+FILETAGS: :spine:build:tools: #+AUTHOR: Ralph Amissah #+EMAIL: [[mailto:ralph.amissah@gmail.com][ralph.amissah@gmail.com]] #+COPYRIGHT: Copyright (C) 2015 (continuously updated, current 2026) Ralph Amissah #+LANGUAGE: en #+STARTUP: content hideblocks hidestars noindent entitiespretty #+PROPERTY: header-args+ :eval never-export :exports code #+PROPERTY: header-args+ :noweb yes :padline no #+PROPERTY: header-args+ :results silent :cache no #+PROPERTY: header-args+ :mkdirp yes #+OPTIONS: H:3 num:nil toc:t \n:t ::t |:t ^:nil -:t f:t *:t - magic single double-quote → " ← FIX changes hilighting behavior (occuring after it) in org document. INVESTIGATE (org-mode CONFIG?) FIND & FIX * nix :nix: ** flake.nix :flake: #+HEADER: :tangle ../flake.nix #+HEADER: :noweb yes #+BEGIN_SRC nix { description = "a sisu like document parser search form"; inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; inputs.spine-d-overlay = { url = "<>"; inputs.nixpkgs.follows = "nixpkgs"; }; outputs = { self, nixpkgs, spine-d-overlay, ... }@inputs: let pname = "spine_search"; version = "<>"; #shell = ./shell.nix; #devEnv = ./nixDevEnv.sh; supportedSystems = ["x86_64-linux"]; forAllSystems = nixpkgs.lib.genAttrs supportedSystems; nixpkgsFor = forAllSystems (system: import nixpkgs {inherit system;}); # nixpkgs instantiated for supported system types localOverlay = (final: prev: { ldc = prev.callPackage ./nix-overlays/ldc { }; # -> ok <> # dmd overlay: revert to GCC14; (current) GCC 15 introduced nullptr in its headers, and DMD's ImportC parser needs update to handle it, monitor and update: dmd = prev.callPackage ./nix-overlays/dmd { stdenv = prev.gcc14Stdenv; }; # -> ok <> dub = prev.callPackage ./nix-overlays/dub { }; # -> ? <> #gdc = prev.callPackage ./nix-overlays/gdc { }; }); pkgsForSystem = system: import nixpkgs { overlays = [ localOverlay ]; inherit system; }; mkSpineSearch = { pkgs, compilerPkg, compilerBin, buildType }: pkgs.stdenv.mkDerivation { inherit pname version; meta.mainProgram = "spine_search"; #executable = true; # not used src = self; buildInputs = [ pkgs.sqlite ]; nativeBuildInputs = [ pkgs.dub compilerPkg pkgs.gnumake ]; preBuild = '' export HOME=$TMPDIR #export HOME=$(pwd) ''; buildPhase = '' runHook preBuild buildCMD="dub run --cache=local --compiler=$(type -P ${compilerBin}) --build=${buildType} --combined --skip-registry=all" echo $buildCMD $buildCMD echo $buildCMD runHook postBuild ''; checkPhase = '' runHook preCheck dub test --combined --skip-registry=all runHook postCheck ''; installPhase = '' runHook preInstall mkdir -p $out/cgi-bin install -m755 -D ./cgi-bin/spine_search $out/cgi-bin/spine_search runHook postInstall ''; postInstall = '' echo `ls -la $out/cgi-bin/spine_search` ''; }; shellHook = '' export Date=`date "+%Y%m%d"` ''; mkDevShell = { pkgs, name, compiler, extraPackages ? [] }: pkgs.mkShell { inherit name shellHook; packages = [ pkgs.direnv pkgs.nix-direnv compiler pkgs.dub pkgs.dtools pkgs.gnumake pkgs.sqlite pkgs.gnugrep pkgs.gnused pkgs.ripgrep ] ++ extraPackages; }; in { packages = forAllSystems (system: let pkgs-ovl = pkgsForSystem system; pkgs-nix = nixpkgsFor.${system}; in { default = self.packages.${system}.spine-search-nixpkgs-ldc; spine-search-nixpkgs-dmd = mkSpineSearch { pkgs = pkgs-nix; # nixpkgs dmd: revert to GCC14 (same nullptr/ImportC fix as overlay dmd) compilerPkg = pkgs-nix.dmd.override { stdenv = pkgs-nix.gcc14Stdenv; }; compilerBin = "dmd"; buildType = "dmd"; }; spine-search-nixpkgs-ldc = mkSpineSearch { pkgs = pkgs-nix; compilerPkg = pkgs-nix.ldc; compilerBin = "ldmd2"; buildType = "ldmd2"; }; spine-search-overlay-dmd = mkSpineSearch { pkgs = pkgs-ovl; compilerPkg = pkgs-ovl.dmd; compilerBin = "dmd"; buildType = "dmd"; }; spine-search-overlay-ldc = mkSpineSearch { pkgs = pkgs-ovl; compilerPkg = pkgs-ovl.ldc; compilerBin = "ldmd2"; buildType = "ldmd2"; }; #spine-search-overlay-gdc = mkSpineSearch { # pkgs = pkgs-ovl; # compilerPkg = pkgs-ovl.gdc; # compilerBin = "gdc"; # buildType = "gdc"; #}; }); devShells = forAllSystems (system: let pkgs-ovl = pkgsForSystem system; pkgs-nix = nixpkgsFor.${system}; in with pkgs-nix; { dsh-d-overlay = spine-d-overlay.devShells.${system}.default; dsh-overlay = mkShell { name = "${pname}-${version} dev shell (overlay)"; packages = with pkgs-ovl; [ ldc #dmd dub gnumake sqlite ]; inherit shellHook; }; dsh-nixpkgs-dmd = mkShell { name = "${pname}-${version} dev shell (nixpkgs dmd)"; packages = [ dmd dub gnumake sqlite ]; inherit shellHook; }; dsh-nixpkgs-ldc = mkShell { name = "${pname}-${version} dev shell (nixpkgs ldc)"; packages = [ ldc dub gnumake sqlite ]; inherit shellHook; }; dsh-overlay-dmd = mkShell { name = "${pname}-${version} dev shell (overlay dmd)"; # "spine-0.18.0 base dev shell, dmd-2.111.0, dub-1.40.0"; packages = with pkgs-ovl; [ dmd dub gnumake sqlite ]; inherit shellHook; }; dsh-overlay-ldc = mkShell { name = "${pname}-${version} dev shell (overlay ldc)"; # "spine-0.18.0 base dev shell, ldc-1.42.0, dub-1.40.0"; packages = with pkgs-ovl; [ ldc dub gnumake sqlite ]; inherit shellHook; }; dsh-sqlite = mkShell { name = "${pname}-${version} dev shell (sqlite)"; packages = [ ldc #dmd dub gnumake sqlite ]; inherit shellHook; }; default = self.devShells.${system}.dsh-nixpkgs-ldc; #default = import ./shell.nix {pkgs = pkgs-nix;}; }); }; } #+END_SRC ** shell.nix :shell: #+HEADER: :tangle ../shell.nix #+HEADER: :noweb yes #+BEGIN_SRC nix #!/usr/bin/env -S nix-shell --pure #!nix-shell -i bash # Development environment for sisudoc-spine-search-cgi. # Builds the spine_search CGI binary via ./package.nix. # # Build logic for the spine_search derivation lives in ./package.nix - # this file only describes the dev shell. # # Usage: # nix-shell # enters shell, builds spine_search # nix-shell --run 'echo $SPINE_SEARCH_BIN' { pkgs ? import {}, spine-search ? pkgs.callPackage ./package.nix {}, # captured at eval time - nix-shell rewrites $SHELL at runtime, # so we must remember the user's real login shell here. userShell ? builtins.getEnv "SHELL", }: with pkgs; mkShell { name = "spine_search base dev shell"; packages = [ # ❯❯❯ spine_search CGI binary built from ./package.nix spine-search # ❯❯❯ d_build_related ldc #dmd dub # ❯❯❯ dev gnumake git # ❯❯❯ nix workflow direnv nix-direnv nix-prefetch-git nix-output-monitor nix-tree jq # ❯❯❯ sqlite sqlite ]; shellHook = '' export Date=$(date "+%Y%m%d") ## set local values in .envrc-local (or here if you must) ## spine_search lives under cgi-bin, not bin - expose it via env ## var and prepend cgi-bin to PATH for convenience. export SPINE_SEARCH_BIN="${spine-search}/cgi-bin/spine_search" export PATH="${spine-search}/cgi-bin:$PATH" echo "spine_search: $SPINE_SEARCH_BIN" ## hand off to the user's login shell (e.g. zsh) only when this ## is an interactive nix-shell entry - not under `nix-shell --run` ## or `--command`, where exec would swallow the command. Guard env ## var prevents re-entry loops. __spine_user_shell=${if userShell == "" then "" else "\"" + userShell + "\""} if [ -z "$__SPINE_SEARCH_SHELL_HANDOFF" ] \ && [ -n "$__spine_user_shell" ] \ && [ "$(basename "$__spine_user_shell")" != "bash" ] \ && [[ $- == *i* ]]; then export __SPINE_SEARCH_SHELL_HANDOFF=1 exec "$__spine_user_shell" fi unset __spine_user_shell ''; } #+END_SRC #+BEGIN_SRC nix {pkgs-nix ? import {}}: with pkgs-nix; mkShell { buildInputs = [ # ❯❯❯ nix_related #nix direnv nix-direnv nixVersions.latest #nixVersions.latest #nixVersions.git nix-prefetch-git validatePkgConfig nix-output-monitor nix-tree jq #gx #nixfmt-rfc-style git # ❯❯❯ dev gnumake ps # ❯❯❯ d_build_related # ❯❯ package manager #dub # ❯❯ compiler #dmd #ldc #rund # ❯❯ linker #lld #mold # ❯❯ builder #ninja #meson # ❯❯❯ sqlite search related sqlite # ❯❯❯ tools #aria #wget #curl ]; shellHook = '' ''; } #+END_SRC echo "ldc `${pkgs.ldc}/bin/ldc2 -v`" ** package.nix :default: #+HEADER: :tangle ../package.nix #+HEADER: :tangle-mode (identity #o644) #+HEADER: :noweb yes #+BEGIN_SRC nix # package.nix - spine_search CGI derivation (build logic) # # Standalone, callPackage-style derivation for the spine_search CGI # binary. Used by shell.nix to put a freshly-built spine_search into # the dev shell. May also be consumed via: # nix-build ./package.nix # pkgs.callPackage ./package.nix {} # # Compiler defaults to ldc/ldmd2 (matching the flake's default # package `spine-search-nixpkgs-ldc`). Override to build with dmd: # pkgs.callPackage ./package.nix { # compilerPkg = pkgs.dmd; # compilerBin = "dmd"; # buildType = "dmd"; # } # # Note: spine_search is a CGI binary and is installed to # $out/cgi-bin/spine_search (not $out/bin/), since it is intended to # be served by a web server, not invoked directly from PATH. { lib, stdenv, dub, ldc, gnumake, sqlite, compilerPkg ? ldc, compilerBin ? "ldmd2", buildType ? "ldmd2", }: stdenv.mkDerivation { pname = "spine_search"; version = "0.18.0"; src = lib.cleanSource ./.; buildInputs = [ sqlite ]; nativeBuildInputs = [ dub compilerPkg gnumake ]; preBuild = '' export HOME=$(pwd) ''; buildPhase = '' runHook preBuild buildCMD="dub run --cache=local \ --compiler=$(type -P ${compilerBin}) \ --build=${buildType} \ --combined --skip-registry=all" echo $buildCMD $buildCMD runHook postBuild ''; checkPhase = '' runHook preCheck dub test --combined --skip-registry=all runHook postCheck ''; installPhase = '' runHook preInstall mkdir -p $out/cgi-bin install -m755 -D ./cgi-bin/spine_search $out/cgi-bin/spine_search runHook postInstall ''; postInstall = '' echo `ls -la $out/cgi-bin/spine_search` ''; meta = { description = "CGI search interface for spine document collections"; homepage = "https://sisudoc.org"; license = lib.licenses.agpl3Plus; platforms = lib.platforms.linux; mainProgram = "spine_search"; }; } #+END_SRC ** derivation.nix :default: #+HEADER: :tangle ../derivation.nix #+HEADER: :tangle-mode (identity #o755) #+HEADER: :shebang "#!/usr/bin/env -S nix-build derivation.nix" #+HEADER: :noweb yes #+BEGIN_SRC nix { pkgs ? import {}, stdenv ? pkgs.stdenv, lib ? pkgs.lib, ldc ? null, dcompiler ? pkgs.ldc, dub ? pkgs.dub, }: assert dcompiler != null; with ( with lib; let filterDub = name: type: let baseName = baseNameOf (toString name); in ! ( # filter function to remove the .dub package folder from src type == "directory" && baseName == ".dub" ); targetOf = package: "${package.targetPath or "."}/${package.targetName or package.name}"; # remove reference to build tools and library sources disallowedRefs = [dcompiler dub]; removeExpr = refs: ''remove-references-to ${lib.concatMapStrings (ref: " -t ${ref}") refs}''; in { mkDubDerivation = lib.makeOverridable ({ src, nativeBuildInputs ? [], dubJSON ? src + "/dub.json", passthru ? {}, package ? lib.importJSON dubJSON, ... } @ attrs: stdenv.mkDerivation (attrs // { pname = attrs.pname or package.name; nativeBuildInputs = [dcompiler dub pkgs.removeReferencesTo] ++ nativeBuildInputs; disallowedReferences = disallowedRefs; passthru = passthru // { inherit dub dcompiler pkgs; }; src = lib.cleanSourceWith { filter = filterDub; src = lib.cleanSource src; }; preFixup = '' find $out/cgi-bin -type f -exec ${removeExpr disallowedRefs} '{}' + || true ''; buildPhase = '' runHook preBuild HOME="$PWD" #DFLAGS="-O2 -inline" for DC_ in dmd ldmd2 gdmd; do echo "- check for D compiler $DC_" DC=$(type -P $DC_ || echo "") if [ ! "$DC" == "" ]; then break fi done if [ "$DC" == "" ]; then echo "Error: could not find D compiler" >&2 exit 1 fi echo "$DC_ used as D compiler to build $pname" dub run --compiler=$DC --build=release --combined --skip-registry=all runHook postBuild ''; checkPhase = '' runHook preCheck HOME="$PWD" dub test --combined --skip-registry=all runHook postCheck ''; installPhase = '' runHook preInstall mkdir -p $out/cgi-bin install -m755 -D "${targetOf package}" "$out/cgi-bin/spine_search" runHook postInstall ''; postInstall = '' echo `ls -la $out/cgi-bin/spine_search` ''; meta = lib.optionalAttrs (package ? description) { description = package.description; } // attrs.meta or {}; } // lib.optionalAttrs (!(attrs ? version)) { name = package.name; # use name from dub.json, unless pname and version are specified })); } ); mkDubDerivation rec { pname = "spine-search"; version = "<>"; src = ./.; buildInputs = [ pkgs.sqlite ( with pkgs; [ nixVersions.latest #nixVersions.latest #nixVersions.git ## package manager dub ## compiler ldc #rund sqlite ] ) ]; meta = with pkgs.lib; { homepage = "https://sisudoc.org"; description = "cgi sqlite search form for document object search"; longDescription = '' a sisu like parser & document generator ''; license = licenses.agpl3Plus; platforms = platforms.linux; maintainers = ["RalphAmissah"]; mainProgram = "spine_search"; }; } #+END_SRC - unused - installPhase #+BEGIN_SRC text installPhase = '' mkdir -p $out/bin cp spine $out/bin chmod +x $out/bin/spine ''; #+END_SRC ** variables used SET *** spine project VERSION :version:set:project: #+NAME: spine_version #+HEADER: :noweb yes #+BEGIN_SRC emacs-lisp <<./sisudoc_spine_version_info_and_doc_header_including_copyright_and_license.org:spine_project_version()>> #+END_SRC *** nixpkgs path / url - nixpkgs_url_github - nixpkgs_url_local **** github (official) #+NAME: nixpkgs_url_github #+BEGIN_SRC shell github:NixOS/nixpkgs/nixpkgs-unstable #+END_SRC **** localhost #+NAME: nixpkgs_url_local #+BEGIN_SRC shell /srv/nix/nixpkgs #+END_SRC *** nixpkgs path options - #+NAME: nixpkgs_url #+HEADER: :noweb yes #+BEGIN_SRC org <> #+END_SRC #+NAME: nixpkgs_url_github #+BEGIN_SRC nix github:nixos/nixpkgs #+END_SRC #+NAME: nixpkgs_path_local #+BEGIN_SRC nix /srv/nix/nixpkgs #+END_SRC * SHARED ** version and other things shared *** spine project VERSION :version:set:project: #+NAME: spine_version #+HEADER: :noweb yes #+BEGIN_SRC emacs-lisp <<./sisudoc_spine_version_info_and_doc_header_including_copyright_and_license.org:spine_project_version()>> #+END_SRC *** spine project git sources **** spine project git sources url #+NAME: sisudoc_spine_nix_src #+HEADER: :noweb yes #+BEGIN_SRC emacs-lisp <<./sisudoc_spine_version_info_and_doc_header_including_copyright_and_license.org:sisudoc_spine_nix_src()>> #+END_SRC *** spine project git sources url **** spine project git sources overlay url #+NAME: sisudoc_dlang_nix_overlay_src #+HEADER: :noweb yes #+BEGIN_SRC emacs-lisp <<./sisudoc_spine_version_info_and_doc_header_including_copyright_and_license.org:sisudoc_dlang_nix_overlay_src()>> #+END_SRC ** dlang overlays *** ldc #+NAME: ldc_version #+HEADER: :noweb yes #+BEGIN_SRC emacs-lisp <<./nix-develop-dlang-shared.org:ldc-version()>> #+END_SRC *** dmd #+NAME: dmd_version #+HEADER: :noweb yes #+BEGIN_SRC emacs-lisp <<./nix-develop-dlang-shared.org:dmd-version()>> #+END_SRC *** dub #+NAME: dub_version #+HEADER: :noweb yes #+BEGIN_SRC emacs-lisp <<./nix-develop-dlang-shared.org:dub-version()>> #+END_SRC *** dtools #+NAME: dtools_version #+HEADER: :noweb yes #+BEGIN_SRC emacs-lisp <<./nix-develop-dlang-shared.org:dtools-version()>> #+END_SRC ** sha256 blank hash #+NAME: sha256-blank #+BEGIN_SRC nix <<./nix-develop-dlang-shared.org:sha256-blank()>> #+END_SRC #+NAME: blank_hash #+BEGIN_SRC nix <<./nix-develop-dlang-shared.org:sha256-blank()>> #+END_SRC