From 824a30b59e2be341c5a15b00cd538b64e2c3ce4a Mon Sep 17 00:00:00 2001
From: Dom Rodriguez <shymega@shymega.org.uk>
Date: Wed, 11 Sep 2024 12:41:43 +0100
Subject: [PATCH] feat: Introduce Flake for development and builds

This PR introduces a Nix flake, allowing for InfiniSim to be built as a
Flake, including a FHS development environment.

We also introduce `flake-compat`, allowing for non-Flake Nix mahcines to
use the project as-is, both for building (`default.nix`), and
development (`shell.nix`).

Additionally, we introduce `.envrc`, meaning that with `direnv`, the Nix
Flake is activated automatically.

It should be noted that we require
https://github.com/InfiniTimeOrg/InfiniTime/pull/2121 to be merged
into mainline before this PR will work. It will currently fail - this is
expected at this stage. A lockfile needs to be generated after the above
PR is merged - this PR here should NOT be merged until that is
completed.

Signed-off-by: Dom Rodriguez <shymega@shymega.org.uk>
---
 .envrc      |   1 +
 default.nix |  11 +++++
 flake.nix   | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 shell.nix   |  11 +++++
 4 files changed, 151 insertions(+)
 create mode 100644 .envrc
 create mode 100644 default.nix
 create mode 100644 flake.nix
 create mode 100644 shell.nix

diff --git a/.envrc b/.envrc
new file mode 100644
index 0000000..3550a30
--- /dev/null
+++ b/.envrc
@@ -0,0 +1 @@
+use flake
diff --git a/default.nix b/default.nix
new file mode 100644
index 0000000..1d976a3
--- /dev/null
+++ b/default.nix
@@ -0,0 +1,11 @@
+(import (
+  let
+    lock = builtins.fromJSON (builtins.readFile ./flake.lock);
+  in
+  fetchTarball {
+    url =
+      lock.nodes.flake-compat.locked.url
+        or "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
+    sha256 = lock.nodes.flake-compat.locked.narHash;
+  }
+) { src = ./.; }).defaultNix
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..1d721bc
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,128 @@
+{
+  description = "A very basic flake";
+
+  inputs = {
+    nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
+    infinitime.url = "github:InfiniTimeOrg/InfiniTime";
+    flake-compat = {
+      url = "github:edolstra/flake-compat";
+      flake = false;
+    };
+  };
+
+  outputs =
+    { self, ... }@inputs:
+    let
+      forAllSystems =
+        function:
+        inputs.nixpkgs.lib.genAttrs
+          [
+            "x86_64-linux"
+            "aarch64-linux"
+          ]
+          (
+            system:
+            function (
+              import inputs.nixpkgs {
+                inherit system;
+                config.allowUnfree = true;
+              }
+            )
+          );
+    in
+    let
+      infinitime = inputs.infinitime.packages.x86_64-linux.infinitime;
+      lv_img_conv = inputs.infinitime.packages.x86_64-linux.lv_img_conv;
+    in
+    {
+      packages = forAllSystems (
+        pkgs: with pkgs; {
+          default = stdenv.mkDerivation rec {
+            name = "infinisim";
+            version = "v1.13.0";
+            srcs =
+              let
+                InfiniTime = (
+                  fetchFromGitHub rec {
+                    inherit (infinitime.src) owner repo rev;
+                    fetchSubmodules = true;
+                    name = repo;
+                    sha256 = "sha256-W1aKQbvYQ7yzz1mz2+356i7clkMTXoL5li3YXzysnMw=";
+                  }
+                );
+                InfiniSim = (
+                  fetchFromGitHub rec {
+                    owner = "InfiniTimeOrg"; # CHANGEME.
+                    repo = "InfiniSim";
+                    rev = "25ec7af440f3a9044b33ff3462a18589dbbe3dd9";
+                    sha256 = "sha256-wRttm6NqGTN4ZeBzWY9ySCkedKDu70A1pUPRA87IuTg=";
+                  }
+                );
+              in
+              [
+                InfiniSim
+                InfiniTime
+              ];
+
+            sourceRoot = ".";
+            postUnpack =
+              let
+                InfiniTime = (builtins.elemAt srcs 1).name;
+                InfiniSim = (builtins.elemAt srcs 0).name;
+              in
+              ''
+                cp -R ${InfiniSim} $sourceRoot/InfiniSim
+                cp -R ${InfiniTime} $sourceRoot/InfiniSim/InfiniTime
+                chmod -R u+w $sourceRoot/InfiniSim
+              '';
+
+            nativeBuildInputs =
+              with pkgs;
+              [
+                SDL2
+                libpng
+                patch
+                zlib
+              ]
+              ++ infinitime.nativeBuildInputs;
+
+            buildInputs = with pkgs; [ cmake ] ++ infinitime.buildInputs;
+
+            preConfigure =
+              let
+                InfiniSim = "$sourceRoot/InfiniSim";
+                InfiniTime = "${InfiniSim}/InfiniTime";
+              in
+              ''
+                substituteInPlace ${InfiniTime}/src/displayapp/fonts/generate.py --replace "'/usr/bin/env', 'patch'" "'${lib.getExe patch}'"
+                substituteInPlace ${InfiniTime}/src/resources/generate-fonts.py --replace "'/usr/bin/env', 'patch'" "'${lib.getExe patch}'"
+                patchShebangs ${InfiniTime}/src/displayapp/fonts/generate.py \
+                    ${InfiniTime}/tools/mcuboot/imgtool.py
+              '';
+
+            cmakeBuildDir = "InfiniSim/build";
+
+            cmakeFlags =
+              let
+                lvImgConvPath = "${lv_img_conv.outPath}/bin";
+              in
+              [
+                "-DCMAKE_PROGRAM_PATH=${lvImgConvPath}"
+                "-DInfiniTime_DIR=../InfiniTime"
+              ];
+
+            meta = with lib; {
+              maintainers = with maintainers; [ shymega ];
+              metaProgram = "infinisim";
+            };
+          };
+        }
+      );
+
+      devShells = forAllSystems (pkgs: {
+        default = pkgs.mkShell {
+          packages = [ pkgs.ninja ] ++ self.packages.${pkgs.system}.default.nativeBuildInputs;
+        };
+      });
+    };
+}
diff --git a/shell.nix b/shell.nix
new file mode 100644
index 0000000..d178307
--- /dev/null
+++ b/shell.nix
@@ -0,0 +1,11 @@
+(import (
+  let
+    lock = builtins.fromJSON (builtins.readFile ./flake.lock);
+  in
+  fetchTarball {
+    url =
+      lock.nodes.flake-compat.locked.url
+        or "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
+    sha256 = lock.nodes.flake-compat.locked.narHash;
+  }
+) { src = ./.; }).shellNix