-*- mode: org -*-
#+TITLE:       configuration nix
#+DESCRIPTION: makefile for spine
#+FILETAGS:    :spine:build:tools:
#+AUTHOR:      Ralph Amissah
#+EMAIL:       [[mailto:ralph.amissah@gmail.com][ralph.amissah@gmail.com]]
#+COPYRIGHT:   Copyright (C) 2015 - 2024 Ralph Amissah
#+LANGUAGE:    en
#+STARTUP:     show4levels hideblocks hidestars noindent entitiespretty
#+PROPERTY:    header-args  :exports code
#+PROPERTY:    header-args+ :noweb yes
#+PROPERTY:    header-args+ :results no
#+PROPERTY:    header-args+ :cache no
#+PROPERTY:    header-args+ :padline no
#+PROPERTY:    header-args+ :mkdirp yes
#+OPTIONS:     H:3 num:nil toc:t \n:t ::t |:t ^:nil -:t f:t *:t

* nix :nix:
** flake.nix :flake:

# "github:nixos/nixpkgs"; "github:NixOS/nixpkgs/nixpkgs-unstable"; "nixpkgs/nixos-unstable"; "nixpkgs/nixos-21.11";
# [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ];
# [ dub dmd ]; [ dub ldc ]; [ dub gdc ];

#+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.flake-utils.url = "github:numtide/flake-utils";
  inputs.d-overlay = {
    url = "git+file:///home/ralph/grotto/repo/git.repo/projects/doc-reform/packages/nix-flakes/dlang/dlang-nix-flakes";
    inputs.nixpkgs.follows = "nixpkgs";
    flake = true;
  };
  outputs = {
    self,
    nixpkgs,
    flake-utils,
    d-overlay,
  } @ inputs: let
    pname = "spine_search";
    version = "<<spine_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
    checkPhase = ''
      runHook preCheck
      dub test --combined --skip-registry=all
      runHook postCheck
    '';
    localOverlay = (final: prev: {
      ldc = prev.callPackage ./nix-overlays/ldc {  };
      dmd = prev.callPackage ./nix-overlays/dmd {  };
      dub = prev.callPackage ./nix-overlays/dub {  };
      #gdc = prev.callPackage ./nix-overlays/gdc {  }; # empty
    });
    pkgsForSystem = system: import nixpkgs {
      overlays = [
        localOverlay
      ];
      inherit system;
    };
    preBuild = ''
      export HOME=$(pwd)
    '';
    installPhase = ''
      runHook preInstall
      mkdir -p $out/share/cgi-bin
      install -m755 -D ./cgi-bin/spine_search $out/share/cgi-bin/spine_search
      runHook postInstall
    '';
    postInstall = ''
      echo `ls -la $out/share/cgi-bin/spine_search`
    '';
  in {
    packages = forAllSystems (system: let
      pkgs-ovl = pkgsForSystem system;
      pkgs-nix = nixpkgsFor.${system};
    in
      with pkgs-ovl; {
        default = stdenv.mkDerivation {
          inherit pname;
          inherit version;
          executable = true;
          src = self;
          inherit shell;
          inherit devEnv;
          buildInputs = [sqlite];
          nativeBuildInputs = [dub ldc gnumake];
          buildPhase = ''
            runHook preBuild
            for DC_ in dmd ldmd2 ldc2 gdc gdmd; do
              echo "- check for D compiler $DC_"
              DC=$(type -P $DC_ || echo "")
              if [ ! "$DC" == "" ]; then break; fi
            done
            if [ "$DC" == "" ]; then exit "Error: could not find D compiler"; fi
            echo "$DC_ used as D compiler to build $pname"
            buildCMD="dub build --cache=local --compiler=$DC --build=$DC_ --combined --skip-registry=all"
            echo $buildCMD
            $buildCMD
            echo $buildCMD
            runHook postBuild
          '';
          inherit preBuild;
          inherit checkPhase;
          inherit installPhase;
          inherit postInstall;
        };
        spine-search-nixpkgs-dmd = stdenv.mkDerivation {
          inherit pname;
          inherit version;
          meta.mainProgram = "spine_search-dmd";
          executable = true;
          src = self;
          inherit shell;
          inherit devEnv;
          buildInputs = with pkgs-nix; [sqlite];
          nativeBuildInputs = with pkgs-nix; [dub dmd gnumake];
          buildPhase = ''
            runHook preBuild
            buildCMD="dub build --cache=local --compiler=$(type -P dmd) --build=dmd --combined --skip-registry=all"
            echo $buildCMD
            $buildCMD
            echo $buildCMD
            runHook postBuild
          '';
          inherit preBuild;
          inherit checkPhase;
          inherit installPhase;
          inherit postInstall;
        };
        spine-search-nixpkgs-ldc = stdenv.mkDerivation {
          inherit pname;
          inherit version;
          meta.mainProgram = "spine_search-ldc";
          executable = true;
          src = self;
          inherit shell;
          inherit devEnv;
          buildInputs = with pkgs-nix; [sqlite];
          nativeBuildInputs = with pkgs-nix; [dub ldc gnumake];
          buildPhase = ''
            runHook preBuild
            buildCMD="dub build --cache=local --compiler=$(type -P ldc2) --build=ldc2 --combined --skip-registry=all"
            echo $buildCMD
            $buildCMD
            echo $buildCMD
            runHook postBuild
          '';
          inherit preBuild;
          inherit checkPhase;
          inherit installPhase;
          inherit postInstall;
        };
        spine-search-overlay-dmd = stdenv.mkDerivation {
          inherit pname;
          inherit version;
          meta.mainProgram = "spine_search-dmd";
          executable = true;
          src = self;
          inherit shell;
          inherit devEnv;
          buildInputs = [sqlite];
          nativeBuildInputs = [dub dmd gnumake];
          buildPhase = ''
            runHook preBuild
            buildCMD="dub build --cache=local --compiler=$(type -P dmd) --build=dmd --combined --skip-registry=all"
            echo $buildCMD
            $buildCMD
            echo $buildCMD
            runHook postBuild
          '';
          inherit preBuild;
          inherit checkPhase;
          inherit installPhase;
          inherit postInstall;
        };
        spine-search-overlay-ldc = stdenv.mkDerivation {
          inherit pname;
          inherit version;
          meta.mainProgram = "spine_search-ldc";
          executable = true;
          src = self;
          inherit shell;
          inherit devEnv;
          buildInputs = [sqlite];
          nativeBuildInputs = [dub ldc gnumake];
          buildPhase = ''
            runHook preBuild
            buildCMD="dub build --cache=local --compiler=$(type -P ldc2) --build=ldc2 --combined --skip-registry=all"
            echo $buildCMD
            $buildCMD
            echo $buildCMD
            runHook postBuild
          '';
          inherit preBuild;
          inherit checkPhase;
          inherit installPhase;
          inherit postInstall;
        };
        #spine-search-overlay-gdc = stdenv.mkDerivation {
        #  inherit pname;
        #  inherit version;
        #  meta.mainProgram = "spine_search-gdc";
        #  executable = true;
        #  src = self;
        #  inherit shell;
        #  inherit devEnv;
        #  buildInputs = [ sqlite ];
        #  nativeBuildInputs = [ dub gdc gnumake ];
        #  buildPhase = ''
        #    runHook preBuild
        #    dub build --cache=local --compiler=$(type -P gdc) --build=gdc --combined --skip-registry=all
        #    runHook postBuild
        #  '';
        #  inherit preBuild;
        #  inherit checkPhase;
        #  inherit installPhase;
        #  inherit postInstall;
        #};
        #vendorSha256 = "sha256-0Q00000000000000000000000000000000000000000=";
      });
    devShells = forAllSystems (system: let
      pkgs-ovl = pkgsForSystem system;
      pkgs-nix = nixpkgsFor.${system};
      shellHook = ''
        export DFLAGS="-O2 -boundscheck=on"
        export Date=`date "+%Y%m%d"`
        ## set local values in .envrc-local (or here if you must)
      '';
    in
      with pkgs-ovl; {
        dsh-overlay = mkShell {
          name = "spine base dev shell";
          inherit shell;
          inherit devEnv;
          packages = [
            ldc
            #dmd
            dub
            gnumake
            sqlite
          ];
          inherit shellHook;
        };
        dsh-d-overlay = d-overlay.devShells.${system}.default;
        dsh-overlay-dmd-dub = mkShell {
          name = "spine base dev shell";
          inherit shell;
          inherit devEnv;
          packages = [
            dmd
            dub
            gnumake
            sqlite
          ];
          inherit shellHook;
        };
        dsh-nixpkgs-ldc-dub = mkShell {
          name = "nixpkgs - ldc - dub";
          inherit shell;
          inherit devEnv;
          packages = with pkgs-nix; [
            ldc
            dub
            gnumake
            sqlite
          ];
          inherit shellHook;
        };
        dsh-sqlite = mkShell {
          name = "spine dev shell for latex & pdf output";
          inherit shell;
          inherit devEnv;
          packages = [
            ldc
            #dmd
            dub
            gnumake
            sqlite
          ];
          inherit shellHook;
        };
        default = import ./shell.nix {inherit pkgs-nix;};
      });
  };
}
#+END_SRC

** shell.nix :shell:

#+HEADER: :tangle ../shell.nix
#+HEADER: :tangle-mode (identity #o755)
#+HEADER: :shebang "#!/usr/bin/env -S nix-shell --pure\n#!nix-shell -i bash"
#+HEADER: :noweb yes
#+BEGIN_SRC nix
{pkgs-nix ? import <nixpkgs> {}}:
with pkgs-nix;
  mkShell {
    buildInputs = [
      # ❯❯❯ nix_related
      #nix
      direnv
      nixVersions.unstable #nixFlakes
      nix-prefetch-git
      validatePkgConfig
      nix-output-monitor
      nix-tree
      jq #gx
      #alejandra
      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`"

** default.nix :default:

#+HEADER: :tangle ../default.nix
#+HEADER: :tangle-mode (identity #o755)
#+HEADER: :shebang "#!/usr/bin/env -S nix-build"
#+BEGIN_SRC nix
{pkgs ? import <nixpkgs> {}}:
pkgs.callPackage ./devenv.nix {}
#+END_SRC

#+HEADER: :tangle-mode (identity #o755)
#+HEADER: :shebang "#!/usr/bin/env -S nix-build"
#+BEGIN_SRC nix
{ pkgs ? import <nixpkgs> {} }:
pkgs.callPackage ./derivation.nix {}
#+END_SRC

*** devenv.nix :default:devenv:

#+HEADER: :tangle ../devenv.nix
#+HEADER: :tangle-mode (identity #o644)
#+BEGIN_SRC nix
{
  pkgs ? import <nixpkgs> {},
  name ? "user-env",
}:
with pkgs;
  buildEnv {
    inherit name;
    extraOutputsToInstall = ["out" "man" "lib"]; # to get all needed symlinks
    paths = [
      # ❯❯❯ nix_related
      #nix # if not on NixOS, this is needed
      direnv
      nixVersions.unstable #nixFlakes
      nix-prefetch-git
      validatePkgConfig
      nix-output-monitor
      nix-tree
      jq #gx
      #alejandra
      git
      # ❯❯❯ dev
      gnumake
      ps
      # ❯❯❯ d_build_related
      # ❯❯ package manager
      dub
      # ❯❯ compiler
      #dmd
      ldc
      # ❯❯❯ sqlite search related
      sqlite
      # this will create a script that will rebuild and upgrade your setup; using shell script syntax
      (writeScriptBin "nix-rebuild" ''
        #!${stdenv.shell}
        #cd <path-to-flake> || exit 1
        nix flake update
        nix profile upgrade '.*'
      '')
      # puts in your root the nixpkgs version
      (writeTextFile {
        name = "nixpkgs-version";
        destination = "/nixpkgs-version";
        text = lib.version;
      })
    ];
  }
#+END_SRC

** derivation.nix :default:

#+HEADER: :tangle ../derivation.nix
#+HEADER: :tangle-mode (identity #o644)
#+HEADER: :noweb yes
#+BEGIN_SRC nix
{
  pkgs ? import <nixpkgs> {},
  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
    disallowedReferences = deps: [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 = package.name;
            nativeBuildInputs = [dcompiler dub pkgs.removeReferencesTo] ++ nativeBuildInputs;
            disallowedReferences = disallowedReferences deps;
            passthru =
              passthru
              // {
                inherit dub dcompiler pkgs;
              };
            src = lib.cleanSourceWith {
              filter = filterDub;
              src = lib.cleanSource src;
            };
            preFixup = ''
              find $out/share/cgi-bin -type f -exec ${removeExpr (disallowedReferences deps)} '{}' + || 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
                exit "Error: could not find D compiler"
              fi
              echo "$DC_ used as D compiler to build $pname"
              dub build --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/share/cgi-bin
              cp -r "${targetOf package}" $out/share/cgi-bin
              install -m755 -D $out/share/cgi-bin/spine_search spine_search
              runHook postInstall
            '';
            postInstall = ''
              echo "HERE ${targetOf package} $out/share/cgi-bin"
              echo `ls -la $out/share/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 {
    name = "spine-search-${version}";
    src = ./.;
    buildInputs = [
      pkgs.sqlite
      (
        with pkgs-nix; [
          nixVersions.unstable #nixFlakes
          ## package manager
          dub
          ## compiler
          ldc
          rund
          sqlite
        ]
      )
    ];
    meta = with pkgs-nix.lib; {
      pname = "spine-search";
      version = "<<spine_version>>";
      homepage = "https://sisudoc.org";
      description = "cgi sqlite search form for document object search";
      longDescription = ''
        a sisu like parser & document generator
      '';
      homepage = "https://sisudoc.org";
      license = licenses.agpl3Plus;
      platforms = platforms.linux;
      maintainers = ["RalphAmissah"];
    };
  }
#+END_SRC

- unused
  - installPhase

#+BEGIN_SRC txt
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
<<./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 sh
github:NixOS/nixpkgs/nixpkgs-unstable
#+END_SRC

**** localhost

#+NAME: nixpkgs_url_local
#+BEGIN_SRC sh
/srv/nix/nixpkgs
#+END_SRC

*** nixpkgs path options

- <nixpkgs>

#+NAME: nixpkgs_url
#+HEADER: :noweb yes
#+BEGIN_SRC sh
<<nixpkgs_url_github>>
#+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