├── LICENSE ├── README.md ├── flake-module.nix └── flake.nix /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Sridhar Ratnakumar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flake-root 2 | 3 | A `flake-parts` module for finding your way to the project root directory 4 | 5 | ## Why? 6 | 7 | Because Nix itself doesn't provide it: 8 | 9 | - https://github.com/NixOS/nix/issues/8034 10 | - https://github.com/NixOS/nix/issues/6241 11 | 12 | ## Usage 13 | 14 | ```nix 15 | { 16 | inputs = { 17 | flake-root.url = "github:srid/flake-root"; 18 | ... 19 | }; 20 | outputs = inputs@{ self, nixpkgs, flake-parts, ... }: 21 | flake-parts.lib.mkFlake { inherit self; } { 22 | imports = [ 23 | inputs.flake-root.flakeModule 24 | ]; 25 | perSystem = { pkgs, lib, config, ... }: { 26 | flake-root.projectRootFile = "flake.nix"; # Not necessary, as flake.nix is the default 27 | devShells.default = pkgs.mkShell { 28 | inputsFrom = [ config.flake-root.devShell ]; # Provides $FLAKE_ROOT in dev shell 29 | }; 30 | }; 31 | }; 32 | } 33 | ``` 34 | 35 | Now you have access to the program that returns the absolute path to the project root via `${lib.getExe config.flake-root.package}`. There is also `config.flake-root.devShell` which exposes a `shellHook` providing the `$FLAKE_ROOT` environment variable. 36 | 37 | ## Examples 38 | 39 | - This module is in turn used by the following `flake-parts` modules: 40 | - https://github.com/Platonic-Systems/mission-control 41 | - https://github.com/srid/proc-flake 42 | 43 | ## Credit 44 | 45 | The bash script is originally based on [numtide/treefmt](https://github.com/numtide/treefmt/blob/66959743ba9e955819a16960319a09d152acff9a/module-options.nix#L98-L109). 46 | -------------------------------------------------------------------------------- /flake-module.nix: -------------------------------------------------------------------------------- 1 | { self, lib, flake-parts-lib, ... }: 2 | let 3 | inherit (flake-parts-lib) 4 | mkPerSystemOption; 5 | inherit (lib) 6 | mkOption 7 | types; 8 | in 9 | { 10 | options = { 11 | perSystem = mkPerSystemOption 12 | ({ config, self', inputs', pkgs, system, ... }: 13 | let 14 | mainSubmodule = types.submodule { 15 | options = { 16 | projectRootFile = mkOption { 17 | type = types.str; 18 | description = "The name of the unique file that exists only at project root"; 19 | default = "flake.nix"; 20 | }; 21 | devShell = mkOption { 22 | type = types.package; 23 | readOnly = true; 24 | description = '' 25 | Devshell providing a shellHook setting $FLAKE_ROOT 26 | ''; 27 | default = pkgs.mkShell { 28 | name = "flake-root-devshell"; 29 | shellHook = '' 30 | FLAKE_ROOT="''$(${lib.getExe config.flake-root.package})" 31 | export FLAKE_ROOT 32 | ''; 33 | }; 34 | }; 35 | package = mkOption { 36 | type = types.package; 37 | readOnly = true; 38 | description = '' 39 | The Nix package providing the command to find the project root. 40 | ''; 41 | default = pkgs.writeShellApplication { 42 | name = "flake-root"; 43 | text = '' 44 | set -euo pipefail 45 | find_up() { 46 | ancestors=() 47 | while true; do 48 | if [[ -f $1 ]]; then 49 | echo "$PWD" 50 | exit 0 51 | fi 52 | ancestors+=("$PWD") 53 | if [[ $PWD == / ]] || [[ $PWD == // ]]; then 54 | echo "ERROR: Unable to locate the ${config.flake-root.projectRootFile} in any of: ''${ancestors[*]@Q}" >&2 55 | exit 1 56 | fi 57 | cd .. 58 | done 59 | } 60 | find_up "${config.flake-root.projectRootFile}" 61 | ''; 62 | }; 63 | }; 64 | }; 65 | }; 66 | 67 | in 68 | { 69 | options.flake-root = lib.mkOption { 70 | type = mainSubmodule; 71 | description = '' 72 | flake-root module options 73 | ''; 74 | default = { }; 75 | }; 76 | }); 77 | }; 78 | } 79 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "A `flake-parts` module for finding your way to the project root directory"; 3 | outputs = { self, ... }: { 4 | flakeModule = ./flake-module.nix; 5 | }; 6 | } 7 | --------------------------------------------------------------------------------