fix(fava): Respect ledger ordering

This commit pulls in an upstream patch which I made in
<https://github.com/beancount/fava/pull/1833>. The upstream patch is a
fix for the issue.

Change-Id: I33d93f01a04d774dfe1ba2dbc13bc99231e4846b
Reviewed-on: https://git.clicks.codes/c/Infra/NixFiles/+/794
Reviewed-by: Samuel Shuert <coded@clicks.codes>
Tested-by: Skyler Grey <minion@clicks.codes>
diff --git a/overlays/fava/1833-respect-ordering.patch b/overlays/fava/1833-respect-ordering.patch
new file mode 100644
index 0000000..2005e70
--- /dev/null
+++ b/overlays/fava/1833-respect-ordering.patch
@@ -0,0 +1,76 @@
+From dd216b91fa2bf2c25fe92baec921d0668ac5a01b Mon Sep 17 00:00:00 2001
+From: Skyler Grey <minion@clicks.codes>
+Date: Sun, 14 Jul 2024 13:49:58 +0000
+Subject: [PATCH] fix: Respect ordering of provided ledgers
+
+Previously the _add_env_filenames function converted the filenames to a
+set. As [sets are unordered](https://docs.python.org/3/tutorial/datastructures.html#sets),
+this prevented specifying order. Some bits of the code, notably the
+default "/" route, relied on order to determine which the default ledger
+was
+
+The use of set() was first introduced in f33a63e35a1751001ac10fb992aba4e434ea7321.
+It's not entirely clear from the commit, but presumably it was intended
+to filter out duplicate items as this is a common pattern in Python. The
+type is hinted to be an Iterable[] and lists are used in other places,
+such as tests, so nothing requires using a set
+
+To make test changes as minimal as possible, this commit makes the files
+included from environment variables be ordered *first*
+---
+ src/fava/cli.py   | 7 ++++---
+ tests/test_cli.py | 6 +++---
+ 2 files changed, 7 insertions(+), 6 deletions(-)
+
+diff --git a/src/fava/cli.py b/src/fava/cli.py
+index 6d9b45594..2ae854b2f 100644
+--- a/src/fava/cli.py
++++ b/src/fava/cli.py
+@@ -37,18 +37,19 @@ def __init__(self) -> None:  # pragma: no cover
+         super().__init__("No file specified")
+ 
+ 
+-def _add_env_filenames(filenames: tuple[str, ...]) -> set[str]:
++def _add_env_filenames(filenames: tuple[str, ...]) -> tuple[str, ...]:
+     """Read additional filenames from BEANCOUNT_FILE."""
+     env_filename = os.environ.get("BEANCOUNT_FILE")
+     if not env_filename:
+-        return set(filenames)
++        return filenames
+ 
+     env_names = env_filename.split(os.pathsep)
+     for name in env_names:
+         if not Path(name).is_absolute():
+             raise NonAbsolutePathError(name)
+ 
+-    return set(filenames + tuple(env_names))
++    all_names = tuple(env_names) + filenames
++    return tuple(name for [index, name] in enumerate(all_names) if index == all_names.index(name))
+ 
+ 
+ @click.command(context_settings={"auto_envvar_prefix": "FAVA"})
+diff --git a/tests/test_cli.py b/tests/test_cli.py
+index dc7466b75..9d94c046f 100644
+--- a/tests/test_cli.py
++++ b/tests/test_cli.py
+@@ -29,17 +29,17 @@ def test__add_env_filenames(
+     other = str(absolute_path / "other")
+ 
+     monkeypatch.delenv("BEANCOUNT_FILE", raising=False)
+-    assert _add_env_filenames((asdf,)) == {asdf}
++    assert _add_env_filenames((asdf,)) == (asdf,)
+ 
+     monkeypatch.setenv("BEANCOUNT_FILE", "path")
+     with pytest.raises(NonAbsolutePathError):
+         _add_env_filenames((asdf,))
+ 
+     monkeypatch.setenv("BEANCOUNT_FILE", absolute)
+-    assert _add_env_filenames((asdf,)) == {absolute, asdf}
++    assert _add_env_filenames((asdf,)) == (absolute, asdf)
+ 
+     monkeypatch.setenv("BEANCOUNT_FILE", os.pathsep.join([absolute, other]))
+-    assert _add_env_filenames((asdf,)) == {absolute, other, asdf}
++    assert _add_env_filenames((asdf,)) == (absolute, other, asdf)
+ 
+ 
+ @pytest.fixture
diff --git a/overlays/fava/1833-respect-ordering.patch.license b/overlays/fava/1833-respect-ordering.patch.license
new file mode 100644
index 0000000..10aa550
--- /dev/null
+++ b/overlays/fava/1833-respect-ordering.patch.license
@@ -0,0 +1,3 @@
+SPDX-FileCopyrightText: 2015-2016 Dominik Aumayr <dominik@aumayr.name>
+
+SPDX-License-Identifier: MIT
diff --git a/overlays/fava/default.nix b/overlays/fava/default.nix
new file mode 100644
index 0000000..1a9d549
--- /dev/null
+++ b/overlays/fava/default.nix
@@ -0,0 +1,24 @@
+# SPDX-FileCopyrightText: 2024 Clicks Codes
+#
+# SPDX-License-Identifier: GPL-3.0-only
+
+{inputs, ...}: final: prev: {
+  fava = prev.fava.overrideAttrs (prevAttrs: let
+    version = "1.28";
+  in {
+    inherit version;
+    src = prev.fetchPypi {
+      pname = "fava";
+      inherit version;
+      hash = "sha256-sWHVkR0/0VMGzH5OMxOCK4usf7G0odzMtr82ESRQhrk=";
+    };
+
+    propagatedBuildInputs = prevAttrs.propagatedBuildInputs ++ [
+      prev.python3.pkgs.watchfiles
+    ];
+
+    patches = (prevAttrs.patches or []) ++ [
+      ./1833-respect-ordering.patch
+    ];
+  });
+}