Skip to content

Instantly share code, notes, and snippets.

@AndersonTorres
Last active September 27, 2021 21:01
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save AndersonTorres/9fa2b059da82c951f7c9036dd054fdb1 to your computer and use it in GitHub Desktop.
Save AndersonTorres/9fa2b059da82c951f7c9036dd054fdb1 to your computer and use it in GitHub Desktop.
A project workflow for Nixpkgs/NixOS

Standard project structure

This is a project structure I’ve found useful. Looking for any thoughts/comments/feedback. Roughly, I found a tension between the style nixpkgs expects and the style conducive to development, so I extracted the common portion into a derivation.nix which is used by the remaining .nix files. This setup allows me to use nix build, nix-shell, overlays, Hydra, alternate packaging schemes, cross-compiling, etc.

================================================================================

pin-nixpkgs.nix

used to pin nixpkgs to a specific version. If this is not needed, you may import in subsequent files instead.

   let
     baseUrl = "https://github.com/NixOS/nixpkgs/archive";
     stable = {
	tag = "20.03";
	# sha256 is optional for builtins.fetchTarball
     };
     unstable = {
	tag = "fce7562cf46727fdaf801b232116bc9ce0512049";
     };
     nixpkgsStable = builtins.fetchTarball {
	url = "${baseUrl}/${stable.tag}.tar.gz";
     };
     nixpkgsUnstable = builtins.fetchTarball {
	url = "${baseUrl}/${unstable.tag}.tar.gz";
     };
   in nixpkgsStable

derivation.nix

This is a nixpkgs compatible derivation, ready to be added as a PR and used via callPackage.​

{stdenv, pkgconfig, meson, ninja, boost, ... }:
stdenv.mkDerivation rec {
  name = "my-project-${version}";
  version = "0.0.1";

  src = ./. ;
  nativeBuildInputs = [ pkgconfig meson ninja ];
  buildInputs = [ boost ];

  enableParallelBuilding = true;
  releaseName = name;

  meta = with stdenv.lib; {
    description = "Some Project in C++";
    homepage = https://example.org/my-project;
    license = licenses.gpl3Plus;
    platforms = platforms.linux;
    maintainers = [ "me@example.org" ];
  };
}

overlay.nix

This allows for easy inclusion into a custom nixpkgs via the overlay system. Sometimes I add multiple versions here with different options or inputs.​

self: super: {
  my-project = self.callPackage ./derivation.nix{ };
}

default.nix

This allows for nix-build and nix-shell to automatically do TheRightThing. This can also allow importing other overlays and custom nixpkgs. This file will NOT work for inclusion into the Nixpkgs repo as default.nix, use the derivation.nix for that instead.​

   let
     nixpkgs = import ./pin-nixpkgs.nix;
     pkgs = import nixpkgs {
	config = {};
	overlays = [
	  (import ./overlay.nix)
	  # (import /other/overlays/too/)
	];
     };

   in pkgs.my-project

release.nix

This is for additional build and packaging as needed. Also used by hydra to specify builds. This allows me to build specific releases, for example nix build -f release.nix nix-build-arm or nix build -f release.nix deb-installer .​

{ nixpkgs ? (import ./nixpkgs.nix), ... } :
let
  pkgs = import nixpkgs {config={};};
  pkgs-arm = import nixpkgs {system="armv7l-linux";config={};};

  nixBuild = drv : extraAttrs :drv.overrideAttrs (old:{
    initPhase = ''
      mkdir -p $out/nix-support
      echo "$system" > $out/nix-support/system
    '';
    prePhases  = ["initPhase"] ++ (if builtins.hasAttr "prePhases" old then old.prePhases else []);
    postPhases = (if builtins.hasAttr "postPhases" old then old.postPhases else []) ++ ["finalPhase"];
    finalPhase = ''
      if test -e $src/nix-support/hydra-release-name; then
        cp $src/nix-support/hydra-release-name $out/nix-support/hydra-release-name
      fi
    '';
  }//extraAttrs);

  jobs = rec {
    nix-build = { system ? builtins.currentSystem }: 
                    nixBuild (pkgs.callPackage ./derivation.nix {}) {};

    nix-build-arm = { system ? builtins.currentSystem }: 
                    with pkgs-arm; 
                    (nixBuild (pkgs-arm.callPackage ./derivation.nix {
                        stdenv = pkgs-arm.stdenv;
                        system = "armv7l-linux";
                    }){});
  };
in
  jobs

spec.nix

used by hydra to specify build sets. TODO: should probably refactor the nixpkgs pin in a DRY way with nixpkgs.nix above.​

{ nixpkgs ? (import ./nixpkgs.nix), declInput }:
let pkgs = import nixpkgs {config = {};}; in {
  jobsets = pkgs.runCommand "spec.json" {} ''
    cat <<EOF
    ${builtins.toXML declInput}
    EOF
    cat > $out <<EOF
    {
      "master": {
        "enabled": 1,
        "hidden": false,
        "description": "my-project",
        "nixexprinput": "src",
        "nixexprpath": "release.nix",
        "checkinterval": 90,
        "schedulingshares": 100,
        "enableemail": true,
        "emailoverride": "",
        "keepnr": 10,
        "inputs": {
            "src": { "type": "git", "value": "file:///repo.git", "emailresponsible": true },
            "nixpkgs": { "type": "git", "value": "git://github.com/NixOS/nixpkgs.git e797e0091356c25282fba4d19690666d4b6f6d0b", "emailresponsible": false }
        }
      },
      "staging": {
        "enabled": 1,
        "hidden": false,
        "description": "my-project",
        "nixexprinput": "src",
        "nixexprpath": "release.nix",
        "checkinterval": 90,
        "schedulingshares": 100,
        "enableemail": false,
        "emailoverride": "",
        "keepnr": 10,
        "inputs": {
            "src": { "type": "git", "value": "file:///repo.git", "emailresponsible": true },
            "nixpkgs": { "type": "git", "value": "git://github.com/NixOS/nixpkgs.git e797e0091356c25282fba4d19690666d4b6f6d0b", "emailresponsible": false }
        }
      }
    }
    EOF
    '';
}

spec.json

declarative jobset used in hydra, basically just points to the above spec.nix. TODO: refactor nixpkgs reference to nixpkgs.nix (or have nixpkgs.nix refer to this one)

{
    "enabled": 1,
    "hidden": true,
    "description": "Jobsets",
    "nixexprinput": "src",
    "nixexprpath": "spec.nix",
    "checkinterval": 300,
    "schedulingshares": 10,
    "enableemail": false,
    "emailoverride": "",
    "keepnr": 3,
    "inputs": {
        "src": { "type": "git", "value": "file:///repo.git", "emailresponsible": true },
        "nixpkgs": { "type": "git", "value": "git://github.com/NixOS/nixpkgs.git e797e0091356c25282fba4d19690666d4b6f6d0b", "emailresponsible": false }
    }
}

shell.nix

if a custom shell environment is needed, override the default.nix here

META

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment