mirror of
https://github.com/nix-community/dream2nix.git
synced 2024-11-23 00:13:02 +03:00
feat(paths): init new core module 'paths'
This is to improve package location finding at eval time and script execution time. Deprecates options lock.{repoRoot,lockFileRel} as well as option eval-cache.{repoRoot, cacheFileRel} Instead the user must now set: - paths.projectRoot: pointing to the repoRoot - paths.package: pointing to the package directory - paths.projectRootFile can be used to define a marker file to find the project root. The default is '.git' but it could be set to 'flake.nix' for example - lock files are by default put in the same directory as the package definition
This commit is contained in:
parent
39885acca7
commit
87722db970
@ -1,4 +1,4 @@
|
||||
{config, ...}: {
|
||||
lock.repoRoot = ./.;
|
||||
lock.lockFileRel = "/locks/${config.name}.json";
|
||||
paths.projectRoot = ./.;
|
||||
paths.package = "/packages/${config.name}";
|
||||
}
|
||||
|
33
modules/dream2nix/core/assertions.nix
Normal file
33
modules/dream2nix/core/assertions.nix
Normal file
@ -0,0 +1,33 @@
|
||||
{lib, ...}:
|
||||
with lib; {
|
||||
options = {
|
||||
assertions = mkOption {
|
||||
type = types.listOf types.unspecified;
|
||||
internal = true;
|
||||
default = [];
|
||||
example = [
|
||||
{
|
||||
assertion = false;
|
||||
message = "you can't enable this for that reason";
|
||||
}
|
||||
];
|
||||
description = lib.mdDoc ''
|
||||
This option allows modules to express conditions that must
|
||||
hold for the evaluation of the system configuration to
|
||||
succeed, along with associated error messages for the user.
|
||||
'';
|
||||
};
|
||||
|
||||
warnings = mkOption {
|
||||
internal = true;
|
||||
default = [];
|
||||
type = types.listOf types.str;
|
||||
example = ["The `foo' service is deprecated and will go away soon!"];
|
||||
description = lib.mdDoc ''
|
||||
This option allows modules to show warnings to users during
|
||||
the evaluation of the system configuration.
|
||||
'';
|
||||
};
|
||||
};
|
||||
# impl of assertions is in <nixpkgs/nixos/modules/system/activation/top-level.nix>
|
||||
}
|
@ -1,11 +1,13 @@
|
||||
{
|
||||
imports = [
|
||||
./assertions.nix
|
||||
./docs
|
||||
./deps
|
||||
./env
|
||||
./eval-cache
|
||||
./flags
|
||||
./lock
|
||||
./paths
|
||||
./public
|
||||
./ui
|
||||
];
|
||||
|
@ -46,17 +46,17 @@
|
||||
|
||||
# LOAD
|
||||
|
||||
file = cfg.repoRoot + cfg.cacheFileRel;
|
||||
file = config.paths.cacheFileAbs;
|
||||
|
||||
refreshCommand =
|
||||
l.unsafeDiscardStringContext
|
||||
"cat $(nix-build ${cfg.newFile.drvPath} --no-link) > $(git rev-parse --show-toplevel)/${cfg.cacheFileRel}";
|
||||
"cat $(nix-build ${cfg.newFile.drvPath} --no-link) > $(realpath $(${config.paths.findRoot})/${config.paths.package}/${config.paths.cacheFile})";
|
||||
|
||||
newFileMsg = "To generate a new cache file, execute:\n ${refreshCommand}";
|
||||
|
||||
ifdInfoMsg = "Information on how to fix this is shown below if evaluated with `--allow-import-from-derivation`";
|
||||
|
||||
cacheMissingMsg = "The cache file ${cfg.cacheFileRel} for drv-parts module '${packageName}' doesn't exist, please create it.";
|
||||
cacheMissingMsg = "The cache file ${config.paths.package}/${config.paths.cacheFile} for drv-parts module '${packageName}' doesn't exist, please create it.";
|
||||
|
||||
cacheMissingError =
|
||||
l.trace ''
|
||||
@ -69,7 +69,7 @@
|
||||
${newFileMsg}
|
||||
'';
|
||||
|
||||
cacheInvalidMsg = "The cache file ${cfg.cacheFileRel} for drv-parts module '${packageName}' is outdated, please update it.";
|
||||
cacheInvalidMsg = "The cache file ${config.paths.package}/${config.paths.cacheFile} for drv-parts module '${packageName}' is outdated, please update it.";
|
||||
|
||||
cacheInvalidError =
|
||||
l.trace ''
|
||||
@ -112,15 +112,16 @@
|
||||
|
||||
eval-cache.content = loadedContent;
|
||||
|
||||
deps = {nixpkgs, ...}: {
|
||||
inherit
|
||||
(nixpkgs)
|
||||
jq
|
||||
runCommand
|
||||
writeText
|
||||
writeScript
|
||||
;
|
||||
};
|
||||
deps = {nixpkgs, ...}:
|
||||
lib.mapAttrs (_: lib.mkOptionDefault) {
|
||||
inherit
|
||||
(nixpkgs)
|
||||
jq
|
||||
runCommand
|
||||
writeText
|
||||
writeScript
|
||||
;
|
||||
};
|
||||
};
|
||||
|
||||
configIfDisabled = l.mkIf (! cfg.enable) {
|
||||
|
@ -7,23 +7,6 @@
|
||||
t = l.types;
|
||||
in {
|
||||
options.eval-cache = {
|
||||
# GLOBAL OPTIONS
|
||||
repoRoot = l.mkOption {
|
||||
type = t.path;
|
||||
description = "The root of the current repo. Eg. 'self' in a flake";
|
||||
example = lib.literalExpression ''
|
||||
self
|
||||
'';
|
||||
};
|
||||
|
||||
cacheFileRel = l.mkOption {
|
||||
type = t.str;
|
||||
description = "Location of the cache file relative to the repoRoot";
|
||||
example = lib.literalExpression ''
|
||||
/rel/path/to/my/package/cache.json
|
||||
'';
|
||||
};
|
||||
|
||||
# LOCAL OPTIONS
|
||||
enable = l.mkEnableOption "the evaluation cache for this derivation";
|
||||
|
||||
@ -33,7 +16,7 @@ in {
|
||||
};
|
||||
};
|
||||
|
||||
invalidationFields = l.mkOption rec {
|
||||
invalidationFields = l.mkOption {
|
||||
type = t.attrsOf t.anything;
|
||||
description = "Fields, when changed, require refreshing the cache";
|
||||
default = {};
|
||||
@ -42,7 +25,7 @@ in {
|
||||
};
|
||||
};
|
||||
|
||||
fields = l.mkOption rec {
|
||||
fields = l.mkOption {
|
||||
type = t.attrsOf t.anything;
|
||||
description = "Fields for which to cache evaluation";
|
||||
default = {};
|
||||
|
@ -7,7 +7,7 @@
|
||||
cfg = config.lock;
|
||||
|
||||
# LOAD
|
||||
file = cfg.repoRoot + cfg.lockFileRel;
|
||||
file = config.paths.lockFileAbs;
|
||||
data = l.fromJSON (l.readFile file);
|
||||
fileExists = l.pathExists file;
|
||||
|
||||
@ -23,10 +23,10 @@
|
||||
from pathlib import Path
|
||||
|
||||
repo_path = Path(subprocess.run(
|
||||
['git', 'rev-parse', '--show-toplevel'],
|
||||
check=True, text=True, capture_output=True)
|
||||
.stdout.strip())
|
||||
lock_path_rel = Path('${cfg.lockFileRel}') # noqa: E501
|
||||
['${config.paths.findRoot}'], # noqa: E501
|
||||
check=True, text=True, capture_output=True
|
||||
).stdout.strip())
|
||||
lock_path_rel = Path('${config.paths.package}/${config.paths.lockFile}') # noqa: E501
|
||||
lock_path = repo_path / lock_path_rel.relative_to(lock_path_rel.anchor)
|
||||
|
||||
if lock_path.exists():
|
||||
@ -45,7 +45,7 @@
|
||||
['git', 'rev-parse', '--show-toplevel'],
|
||||
check=True, text=True, capture_output=True)
|
||||
.stdout.strip())
|
||||
lock_path_rel = Path('${cfg.lockFileRel}') # noqa: E501
|
||||
lock_path_rel = Path('${config.paths.package}/${config.paths.lockFile}') # noqa: E501
|
||||
lock_path = repo_path / lock_path_rel.relative_to(lock_path_rel.anchor)
|
||||
lock_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
@ -126,30 +126,30 @@
|
||||
'';
|
||||
|
||||
errorMissingFile = ''
|
||||
The lock file ${cfg.repoRoot}${cfg.lockFileRel}
|
||||
The lock file ${config.paths.package}/${config.paths.lockFile}
|
||||
for drv-parts module '${config.name}' is missing.
|
||||
|
||||
To update it using flakes:
|
||||
|
||||
nix run -L .#${config.name}.config.lock.refresh
|
||||
|
||||
To update it without flakes:
|
||||
|
||||
bash -c $(nix-build ${config.lock.refresh.drvPath} --no-link)/bin/refresh
|
||||
|
||||
To update it using flakes:
|
||||
|
||||
nix run -L .#${config.name}.config.lock.refresh
|
||||
'';
|
||||
|
||||
errorOutdated = field: ''
|
||||
The lock file ${cfg.repoRoot}${cfg.lockFileRel}
|
||||
The lock file ${config.paths.package}/${config.paths.lockFile}
|
||||
for drv-parts module '${config.name}' does not contain field `${field}`.
|
||||
|
||||
To update it using flakes:
|
||||
|
||||
nix run -L .#${config.name}.config.lock.refresh
|
||||
|
||||
To update it without flakes:
|
||||
|
||||
bash -c $(nix-build ${config.lock.refresh.drvPath} --no-link)/bin/refresh
|
||||
|
||||
To update it using flakes:
|
||||
|
||||
nix run -L .#${config.name}.config.lock.refresh
|
||||
|
||||
'';
|
||||
|
||||
fileContent =
|
||||
|
@ -6,23 +6,12 @@
|
||||
l = lib // builtins;
|
||||
t = l.types;
|
||||
in {
|
||||
imports = [
|
||||
(lib.mkRemovedOptionModule ["lock" "repoRoot"] "Use paths.projectRoot instead.")
|
||||
(lib.mkRemovedOptionModule ["lock" "lockFileRel"] "Use paths.package instead.")
|
||||
];
|
||||
options.lock = {
|
||||
# GLOBAL OPTIONS
|
||||
repoRoot = l.mkOption {
|
||||
type = t.path;
|
||||
description = "The root of the current repo. Eg. 'self' in a flake";
|
||||
example = lib.literalExpression ''
|
||||
self
|
||||
'';
|
||||
};
|
||||
|
||||
lockFileRel = l.mkOption {
|
||||
type = t.str;
|
||||
description = "Location of the cache file relative to the repoRoot";
|
||||
example = lib.literalExpression ''
|
||||
/rel/path/to/my/package/cache.json
|
||||
'';
|
||||
};
|
||||
|
||||
content = l.mkOption {
|
||||
type = t.submodule {
|
||||
|
31
modules/dream2nix/core/paths/default.nix
Normal file
31
modules/dream2nix/core/paths/default.nix
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
imports = [
|
||||
./interface.nix
|
||||
];
|
||||
deps = {nixpkgs, ...}: {
|
||||
python3 = nixpkgs.python3;
|
||||
substituteAll = nixpkgs.substituteAll;
|
||||
# runCommand = nixpkgs.runCommand;
|
||||
};
|
||||
paths = {
|
||||
lockFileAbs =
|
||||
config.paths.projectRoot + "/" + config.paths.package + "/" + config.paths.lockFile;
|
||||
cacheFileAbs =
|
||||
config.paths.projectRoot + "/" + config.paths.package + "/" + config.paths.cacheFile;
|
||||
|
||||
# - identify the root by searching for the marker config.paths.projectRootFile in the current dir and parents
|
||||
# - if the marker file is not found, raise an error
|
||||
findRoot = let
|
||||
program = config.deps.substituteAll {
|
||||
src = ./find-root.py;
|
||||
projectRootFile = config.paths.projectRootFile;
|
||||
python3 = config.deps.python3;
|
||||
postInstall = "chmod +x $out";
|
||||
};
|
||||
in "${program}";
|
||||
};
|
||||
}
|
25
modules/dream2nix/core/paths/find-root.py
Executable file
25
modules/dream2nix/core/paths/find-root.py
Executable file
@ -0,0 +1,25 @@
|
||||
#!@python3@/bin/python3
|
||||
|
||||
# - identify the root by searching for the marker config.paths.projectRootFile in the current dir and parents
|
||||
# - if the marker file is not found, raise an error
|
||||
|
||||
import os
|
||||
|
||||
|
||||
def find_root():
|
||||
marker = "@projectRootFile@"
|
||||
path = os.getcwd()
|
||||
while True:
|
||||
if os.path.exists(os.path.join(path, marker)):
|
||||
return path
|
||||
newpath = os.path.dirname(path)
|
||||
if newpath == path:
|
||||
raise Exception(
|
||||
f"Could not find root directory (marker file: {marker})\n"
|
||||
"Ensure that paths.projectRoot and paths.projectRootFile are set correctly and you are working somewhere within the project directory."
|
||||
)
|
||||
path = newpath
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(find_root())
|
82
modules/dream2nix/core/paths/interface.nix
Normal file
82
modules/dream2nix/core/paths/interface.nix
Normal file
@ -0,0 +1,82 @@
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
options.paths = lib.mapAttrs (_: lib.mkOption) {
|
||||
# mandatory fields
|
||||
projectRoot = {
|
||||
type = lib.types.path;
|
||||
description = ''
|
||||
Path to the root of the project on which dream2nix operates.
|
||||
Must contain the marker file specified by 'paths.projectRootFile'
|
||||
|
||||
This helps locating lock files at evaluation time.
|
||||
'';
|
||||
example = lib.literalExpression "./.";
|
||||
};
|
||||
package = {
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
Path to the directory containing the definition of the current package.
|
||||
Relative to 'paths.projectRoot'.
|
||||
|
||||
This helps locating package definitions for lock & update scripts.
|
||||
'';
|
||||
};
|
||||
|
||||
# optional fields
|
||||
projectRootFile = {
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
File name to look for to determine the root of the project.
|
||||
Ensure 'paths.projectRoot' contains a file named like this.
|
||||
|
||||
This helps locating package definitions for lock & update scripts.
|
||||
'';
|
||||
example = ".git";
|
||||
default = ".git";
|
||||
};
|
||||
lockFile = {
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
Path to the lock file of the current package.
|
||||
Relative to "''${paths.projectRoot}/''${paths.package}"".
|
||||
'';
|
||||
default = "lock.json";
|
||||
};
|
||||
cacheFile = {
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
Path to the eval cache file of the current package.
|
||||
Relative to "''${paths.projectRoot}/''${paths.package}"".
|
||||
'';
|
||||
default = "cache.json";
|
||||
};
|
||||
|
||||
# internal fields
|
||||
lockFileAbs = {
|
||||
internal = true;
|
||||
type = lib.types.path;
|
||||
description = ''
|
||||
Absolute path to the lock file of the current package.
|
||||
Derived from 'paths.projectRoot', 'paths.package' and 'paths.lockFile'.
|
||||
'';
|
||||
};
|
||||
cacheFileAbs = {
|
||||
internal = true;
|
||||
type = lib.types.path;
|
||||
description = ''
|
||||
Absolute path to the eval cache file of the current package.
|
||||
Derived from 'paths.projectRoot', 'paths.package' and 'paths.cacheFile'.
|
||||
'';
|
||||
};
|
||||
findRoot = {
|
||||
internal = true;
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
Executable script to find the package definition of the current package.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
@ -18,11 +18,13 @@
|
||||
}: let
|
||||
l = lib // builtins;
|
||||
|
||||
packages = lib.filterAttrs (name: _: lib.hasPrefix "example-package-" name) self'.checks;
|
||||
|
||||
scripts =
|
||||
l.flatten
|
||||
(l.mapAttrsToList
|
||||
(name: pkg: pkg.config.lock.refresh or [])
|
||||
self'.packages);
|
||||
packages);
|
||||
|
||||
update-locks =
|
||||
config.writers.writePureShellScript
|
||||
|
@ -25,8 +25,7 @@
|
||||
|
||||
# A module imported into every package setting up the eval cache
|
||||
setup = {config, ...}: {
|
||||
lock.repoRoot = self;
|
||||
eval-cache.repoRoot = self;
|
||||
paths.projectRoot = self;
|
||||
eval-cache.enable = true;
|
||||
deps.npm = inputs.nixpkgs.legacyPackages.${system}.nodejs.pkgs.npm.override (old: rec {
|
||||
version = "8.19.4";
|
||||
@ -59,7 +58,10 @@
|
||||
flip mapAttrs' examples
|
||||
(name: _: {
|
||||
name = "example-package-${name}";
|
||||
value = examplesPath + "/${name}";
|
||||
value = {
|
||||
module = examplesPath + "/${name}";
|
||||
packagePath = "/examples/packages/${dirName}/${name}";
|
||||
};
|
||||
});
|
||||
|
||||
allExamples = mapAttrsToList (dirName: _: readExamples dirName) examplePackagesDirs;
|
||||
@ -72,11 +74,10 @@
|
||||
allModules = flip mapAttrs' allModules' (name: module: {
|
||||
inherit name;
|
||||
value = [
|
||||
module
|
||||
module.module
|
||||
setup
|
||||
{
|
||||
lock.lockFileRel = "/locks/${name}/lock-${system}.json";
|
||||
eval-cache.cacheFileRel = "/locks/${name}/cache-${system}.json";
|
||||
paths.package = module.packagePath;
|
||||
}
|
||||
];
|
||||
});
|
||||
|
@ -7,12 +7,13 @@ let
|
||||
# TODO: modify this according to your repo structure
|
||||
setupModule = {config, ...}: {
|
||||
# Define the root of your repo. All other paths are relative to it.
|
||||
lock.repoRoot = ./.;
|
||||
lock.projectRoot = ./.;
|
||||
|
||||
# define how a specific lock file should be called
|
||||
# This definition will produce lock files like:
|
||||
# my-package-x86_64-linux-lock.json
|
||||
lock.lockFileRel = "/${config.name}-${config.deps.stdenv.system}-lock.json";
|
||||
paths.package = ".";
|
||||
paths.lockFile = "/${config.name}-${config.deps.stdenv.system}-lock.json";
|
||||
};
|
||||
|
||||
# evaluate package module
|
||||
|
Loading…
Reference in New Issue
Block a user