{ nixpkgs ? import ./Bild/Nixpkgs.nix }: let constants = import ./Bild/Constants.nix; # expose some attrs from stable, keep this minimal and simple stable = let stable = nixpkgs.nixos-24_05; in { inherit (stable) sources lib makeWrapper ccacheStdenv haskell sbcl python312 nixos mkShell dockerTools pkgs; stdenv = stable.ccacheStdenv; }; unstable = nixpkgs.nixos-unstable-small; # get the .src attributes of all drvs in each pkgset in the `sources` list, # and concat them with `:` into a Unix-style search path. # makeSourcesPath :: [pkgset] -> str makeSourcesPath = with stable; sources: lib.trivial.pipe sources [ (builtins.map lib.attrsets.attrValues) lib.lists.flatten (builtins.filter (pkg: pkg != null)) (builtins.map (pkg: if pkg ? src then pkg.src else pkg)) (lib.strings.concatStringsSep ":") ]; # this is the main library definitions, recursive references can be made with # `self.thing`, like in Python objects self = { # provided by .envrc root = builtins.getEnv "CODEROOT"; inherit (stable) sources lib makeWrapper stdenv; haskell = rec { inherit (constants) ghcCompiler; ghcVersion = ghcPackageSetFull.version; # all available packages deps = import ./Bild/Deps/Haskell.nix; packages = self.lib.attrsets.getAttrs self.haskell.deps stable.haskell.packages."${constants.ghcCompiler}"; # make a ghc with dependencies ghcWith = stable.haskell.packages.${ghcCompiler}.ghcWithHoogle; # ghc with all packages, used for generating bild's package database ghcPackageSetFull = ghcWith (p: self.lib.attrsets.attrVals deps p); # bild's dependencies, needs to be hand-written ghcPackageSetBild = ghcWith (hpkgs: with hpkgs; [ aeson async base bytestring conduit conduit-extra containers directory docopt filepath process protolude rainbow regex-applicative split tasty tasty-hunit tasty-quickcheck text hostname wai # can remove when removed from Omni.Log ]); }; lisp = { sbclWith = stable.sbcl.withPackages; }; python = { packages = self.lib.attrsets.getAttrs (import ./Bild/Deps/Python.nix) stable.python312.pkgs; pythonWith = stable.python312.withPackages; buildPythonApplication = stable.python312.pkgs.buildPythonApplication; }; # c packages are just stable, filtered to just the list of deps i want c.packages = self.lib.attrsets.getAttrs (import ./Bild/Deps/C.nix) stable.pkgs; # exposed packages for inclusion in builds pkgs = with stable.pkgs; { inherit bat bc cmark universal-ctags datasette deadnix fd figlet fzf git git-branchless gitlint groff guile hlint indent jq lolcat mypy nixfmt ormolu pkg-config ripgrep rustc tree wemux; llama-cpp = unstable.llama-cpp; # can't put this in the dev namespace because it pulls in openai with # python311, which conflicts with any other usage of openai with # python312. so i need to make a target that exposese/wraps llm like i did # with llamacpp #llm = python311.withPackages # (p: [ p.llm p.llm-ollama p.llm-sentence-transformers ]); ollama = unstable.ollama; ruff = unstable.ruff; shellcheck = unstable.shellcheck; }; # a standard nix build for bild, for bootstrapping. this should be the only # hand-written builder we need bild = self.stdenv.mkDerivation { name = "bild"; srcs = self.lib.fileset.toSource { root = ../.; fileset = self.lib.fileset.unions [ ../Alpha.hs ../Omni/Bild.hs ../Omni/Bild/Meta.hs ../Omni/Cli.hs ../Omni/Log.hs ../Omni/Namespace.hs ../Omni/Test.hs ]; }; nativeBuildInputs = [ self.haskell.ghcPackageSetBild ]; buildInputs = [ self.makeWrapper ]; propagatedBuildInputs = with self.pkgs; [ pkg-config git # this is just to get access to ghc-pkg in bild (self.haskell.ghcWith (_: [ ])) # lisp deps, remove this when i implement nix builds for lisp guile (self.lisp.sbclWith (p: with p; [ alexandria ])) # just enough to build Example.lisp ]; strictDeps = true; ghcVersion = self.haskell.ghcVersion; buildPhase = '' mkdir -p $out/bin $out/lib/ghc-$ghcVersion cp -r \ ${self.haskell.ghcPackageSetFull}/lib/ghc-$ghcVersion/package.conf.d \ $out/lib/ghc-$ghcVersion ghc \ -threaded \ -Werror \ -Wall \ -Winvalid-haddock \ -haddock \ -i. \ --make Omni/Bild.hs \ -main-is Omni.Bild \ -o $out/bin/bild ''; installPhase = '' wrapProgram $out/bin/bild \ --prefix PATH : ${ self.lib.makeBinPath [ self.haskell.ghcPackageSetBild self.pkgs.git ] } \ --set GHC_PACKAGE_PATH \ $out/lib/ghc-$ghcVersion/package.conf.d ''; }; # wrapper around bild runBildAnalyze = target: self.stdenv.mkDerivation rec { name = "bild-analysis"; src = ../.; USER = "nixbld"; HOSTNAME = "nix-sandbox"; # we need to remove the $src root because bild expects paths relative to the # working directory: TARGET = "." + self.lib.strings.removePrefix (toString src) (toString target); buildPhase = '' export CODEROOT=$(pwd) mkdir $out ${self.bild}/bin/bild --plan "$TARGET" 1> $out/analysis.json \ 2> >(tee -a $out/stderr >&2) ''; installPhase = "exit 0"; }; # gather data needed for compiling by analyzing the main module. returns the # json object of the build analyze = target: builtins.readFile (self.runBildAnalyze target + "/analysis.json"); # this does a bild build for the given target, but entirely in nix. its kinda # like IFD, but not as costly, i think run = target: import ./Bild/Builder.nix { analysisJSON = self.analyze target; bild = self; }; # the main development environment env = stable.mkShell { name = "omnidev"; # this should just be dev tools buildInputs = with self.pkgs; [ bat bc self.bild datasette universal-ctags fd figlet fzf git git-branchless gitlint jq lolcat ormolu ripgrep tree wemux ]; shellHook = '' export GHC_PACKAGE_PATH=${self.bild}/lib/ghc-${self.haskell.ghcVersion}/package.conf.d export ALL_SOURCES=${ makeSourcesPath [ self.python.packages self.haskell.packages self.c.packages self.sources ] } ''; }; # build an operating system. 'cfg' is the NixOS config os = cfg: (stable.nixos (_args: cfg)).toplevel; # build an os image for a digital ocean droplet droplet = cfg: (stable.nixos ({ modulesPath, ... }: { imports = [ "${toString modulesPath}/virtualisation/digital-ocean-image.nix" (_args: cfg) ]; })).digitalOceanImage; # build a docker image image = stable.dockerTools.buildImage; }; in self