Nix files.

These new Nix files can be used as an alternative to the Stack-based
build.

Change-Id: I56ae4e27fa26541cd88583a7806f2834cb6a1735
diff --git a/.gitignore b/.gitignore
index 4353b27..184e972 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
 *.iml
 
 /config.dhall
+/result
 
 /.idea
 /.stack-work
diff --git a/default.nix b/default.nix
new file mode 100644
index 0000000..fb53cde
--- /dev/null
+++ b/default.nix
@@ -0,0 +1,19 @@
+# This file exists for legacy Nix installs (nix-build & nix-env)
+# https://nixos.wiki/wiki/Flakes#Using_flakes_project_from_a_legacy_Nix
+# You generally do *not* have to modify this ever.
+
+{ pkgs ? import <nixpkgs> { }, nix-gitignore ? pkgs.nix-gitignore }:
+
+(import
+  (
+    let
+      lock = builtins.fromJSON (builtins.readFile ./flake.lock);
+    in
+    fetchTarball {
+      url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
+      sha256 = lock.nodes.flake-compat.locked.narHash;
+    }
+  )
+  {
+    src = nix-gitignore.gitignoreSource [ ] ./.;
+  }).defaultNix
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..520f11f
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,58 @@
+{
+  "nodes": {
+    "flake-compat": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1627913399,
+        "narHash": "sha256-hY8g6H2KFL8ownSiFeMOjwPC8P0ueXpCVEbxgda3pko=",
+        "owner": "edolstra",
+        "repo": "flake-compat",
+        "rev": "12c64ca55c1014cdc1b16ed5a804aa8576601ff2",
+        "type": "github"
+      },
+      "original": {
+        "owner": "edolstra",
+        "repo": "flake-compat",
+        "type": "github"
+      }
+    },
+    "flake-utils": {
+      "locked": {
+        "lastModified": 1629284811,
+        "narHash": "sha256-JHgasjPR0/J1J3DRm4KxM4zTyAj4IOJY8vIl75v/kPI=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "c5d161cc0af116a2e17f54316f0bf43f0819785c",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1629466665,
+        "narHash": "sha256-IZ726OdbYsdGxMa4Cae54jmfbTpgfFJRr5q7Fr7a4RM=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "63047a07e9c7f376803ff7f971fc951585f0bfae",
+        "type": "github"
+      },
+      "original": {
+        "id": "nixpkgs",
+        "type": "indirect"
+      }
+    },
+    "root": {
+      "inputs": {
+        "flake-compat": "flake-compat",
+        "flake-utils": "flake-utils",
+        "nixpkgs": "nixpkgs"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..89ee1f4
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,83 @@
+/* Based on: https://github.com/srid/haskell-template */
+
+{
+  description = "Mulky Backups via Bupstash";
+
+  inputs = {
+    flake-utils.url = "github:numtide/flake-utils";
+    flake-compat = {
+      url = "github:edolstra/flake-compat";
+      flake = false;
+    };
+  };
+
+  outputs = inputs@{ self, nixpkgs, flake-utils, ... }:
+    flake-utils.lib.eachSystem [ "x86_64-linux" "x86_64-darwin" ] (system:
+      let
+        overlays = [ ];
+
+        pkgs =
+          import nixpkgs { inherit system overlays; config.allowBroken = true; };
+
+        co-log-src = pkgs.fetchgit
+          {
+            url = "https://github.com/kowainik/co-log";
+            sha256 = "sha256-XV1xh3aBRY2XwWjGRkd7F2DHf3zTeeFawHJzf05eaWE"; # pkgs.lib.fakeSha256;
+            rev = "72fbe394b437c698d574cd7604ad3f7f807383e0";
+            fetchSubmodules = false;
+          };
+
+        project = returnShellEnv:
+          pkgs.haskellPackages.developPackage {
+            inherit returnShellEnv;
+
+            name = "mulkup";
+
+            root = pkgs.nix-gitignore.gitignoreSource [ ] ./.;
+
+            withHoogle = false;
+
+            overrides = self: super: with pkgs.haskell.lib; {
+              # Use callCabal2nix to override Haskell dependencies here
+              # cf. https://tek.brick.do/K3VXJd8mEKO7
+
+              co-log-polysemy = pkgs.haskell.lib.dontCheck
+                (self.callCabal2nixWithOptions "co-log-polysemy" co-log-src "--subpath=co-log-polysemy" { });
+
+              doctest = pkgs.haskell.lib.dontCheck
+                (self.callHackage "doctest" "0.16.3" { });
+
+              optics = pkgs.haskell.lib.dontCheck
+                (self.callHackage "optics" "0.4" { });
+              optics-core = pkgs.haskell.lib.dontCheck
+                (self.callHackage "optics-core" "0.4" { });
+              optics-th = pkgs.haskell.lib.dontCheck
+                (self.callHackage "optics-th" "0.4" { });
+              optics-extra = pkgs.haskell.lib.dontCheck (
+                self.callHackageDirect
+                  {
+                    pkg = "optics-extra";
+                    ver = "0.4";
+                    sha256 = "sha256-oKV8oF0oNHyuActOA7uxBkBzlTgG8LapcKrApa2Pg6U=";
+                  }
+                  { });
+
+            };
+
+            modifier = drv:
+              pkgs.haskell.lib.addBuildTools drv (with pkgs.haskellPackages;
+              [
+                cabal-fmt
+                cabal-install
+                ghcid
+                haskell-language-server
+                ormolu
+              ]);
+          };
+
+      in
+      {
+        defaultPackage = project false;
+        devShell = project true;
+      });
+}
diff --git a/mulkup.cabal b/mulkup.cabal
index e5f5976..82fc1a6 100644
--- a/mulkup.cabal
+++ b/mulkup.cabal
@@ -13,21 +13,22 @@
   --     GHC == 9.0.1
 
   build-depends:
-    , base                   ^>= 4.15.0
-    , relude                 ^>= 1.0.0.0
+    , base
+    , relude
     , aeson
-    , bytestring             ^>= 0.10
-    , co-log                 ^>= 0.4
-    , co-log-core            ^>= 0.2.1
-    , co-log-polysemy        ^>= 0.0.1
-    , dhall                  ^>= 1.39
-    , optparse-applicative    >= 0.15     && < 0.17
-    , optics                 ^>= 0.4
-    , polysemy                >= 1.3       && < 1.7
-    , recursion-schemes      ^>= 5.2
+    , bytestring
+    , co-log
+    , co-log-core
+    , co-log-polysemy
+    , containers
+    , dhall
+    , optparse-applicative
+    , optics
+    , polysemy
+    , recursion-schemes
     , time
-    , text                   ^>= 1.2
-    , turtle                 ^>= 1.5.20
+    , text
+    , turtle
 
   default-extensions:
       BangPatterns
@@ -126,8 +127,8 @@
       Mulkup.ConfigSpec
 
   build-depends:
-    , base                   ^>= 4.15.0
-    , tasty                  ^>= 1.4
-    , tasty-hunit            ^>= 0.10
-    , tasty-smallcheck       ^>= 0.8
+    , base
+    , tasty
+    , tasty-hunit
+    , tasty-smallcheck
     , mulkup
diff --git a/shell.nix b/shell.nix
new file mode 100644
index 0000000..daa314a
--- /dev/null
+++ b/shell.nix
@@ -0,0 +1,19 @@
+# This file exists for legacy Nix installs (nix-build & nix-env)
+# https://nixos.wiki/wiki/Flakes#Using_flakes_project_from_a_legacy_Nix
+# You generally do *not* have to modify this ever.
+
+{ pkgs ? import <nixpkgs> { }, nix-gitignore ? pkgs.nix-gitignore }:
+
+(import
+  (
+    let
+      lock = builtins.fromJSON (builtins.readFile ./flake.lock);
+    in
+    fetchTarball {
+      url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
+      sha256 = lock.nodes.flake-compat.locked.narHash;
+    }
+  )
+  {
+    src = nix-gitignore.gitignoreSource [ ] ./.;
+  }).shellNix