moved to devenv

This commit is contained in:
2026-06-22 12:07:27 +01:00
parent 72c93e88c1
commit 192564fb79
34 changed files with 15242 additions and 108 deletions

1
.devenv/bash-bash Symbolic link
View File

@@ -0,0 +1 @@
/nix/store/cgjr3kj3hs7ngznyws5qfg16c8scpys0-bash-interactive-5.3p9

View File

@@ -0,0 +1,603 @@
# Shared library functions for devenv evaluation
{ inputs }:
rec {
# Helper to get overlays for a given input
getOverlays =
inputName: inputAttrs:
let
lib = inputs.nixpkgs.lib;
in
map
(
overlay:
let
input =
inputs.${inputName} or (throw "No such input `${inputName}` while trying to configure overlays.");
in
input.overlays.${overlay}
or (throw "Input `${inputName}` has no overlay called `${overlay}`. Supported overlays: ${lib.concatStringsSep ", " (builtins.attrNames input.overlays)}")
) inputAttrs.overlays or [ ];
# Main function to create devenv configuration for a specific system with profiles support
# This is the full-featured version used by default.nix
mkDevenvForSystem =
{ version
, is_development_version ? false
, require_version_match ? false
, system
, devenv_root
, git_root ? null
, devenv_dotfile
, devenv_dotfile_path
, devenv_tmpdir
, devenv_runtime
, devenv_state ? null
, devenv_istesting ? false
, devenv_direnvrc_latest_version
, active_profiles ? [ ]
, hostname
, username
, cli_options ? [ ]
, skip_local_src ? false
, secretspec ? null
, devenv_inputs ? { }
, devenv_imports ? [ ]
, impure ? false
, nixpkgs_config ? { }
, lock_fingerprint ? null
, primops ? { }
}:
let
inherit (inputs) nixpkgs;
lib = nixpkgs.lib;
targetSystem = system;
overlays = lib.flatten (lib.mapAttrsToList getOverlays devenv_inputs);
# Helper to create pkgs for a given system with nixpkgs_config
mkPkgsForSystem =
evalSystem:
import nixpkgs {
system = evalSystem;
config = nixpkgs_config // {
# nixpkgs' check-meta.nix natively handles permittedInsecurePackages
# via allowInsecureDefaultPredicate using the full derivation name.
# We must NOT override allowInsecurePredicate here, as lib.getName
# strips the version, causing mismatches with user-provided entries
# like "openssl-1.1.1w".
#
# For unfree packages, nixpkgs does not natively support
# permittedUnfreePackages, so we provide a custom predicate.
allowUnfreePredicate =
if nixpkgs_config.allowUnfree or false then
(_: true)
else if (nixpkgs_config.permittedUnfreePackages or [ ]) != [ ] then
(pkg: builtins.elem (lib.getName pkg) (nixpkgs_config.permittedUnfreePackages or [ ]))
else
(_: false);
} // lib.optionalAttrs ((nixpkgs_config.allowlistedLicenses or [ ]) != [ ]) {
allowlistedLicenses = map (name: lib.licenses.${name}) (nixpkgs_config.allowlistedLicenses or [ ]);
} // lib.optionalAttrs ((nixpkgs_config.blocklistedLicenses or [ ]) != [ ]) {
blocklistedLicenses = map (name: lib.licenses.${name}) (nixpkgs_config.blocklistedLicenses or [ ]);
};
inherit overlays;
};
pkgsBootstrap = mkPkgsForSystem targetSystem;
# Helper to import a path, trying .nix first then /devenv.nix
# Returns a list of modules, including devenv.local.nix when present
tryImport =
resolvedPath: basePath:
if lib.hasSuffix ".nix" basePath then
[ (import resolvedPath) ]
else
let
devenvpath = resolvedPath + "/devenv.nix";
localpath = resolvedPath + "/devenv.local.nix";
in
if builtins.pathExists devenvpath then
[ (import devenvpath) ] ++ lib.optional (builtins.pathExists localpath) (import localpath)
else
throw (basePath + "/devenv.nix file does not exist");
importModule =
path:
if lib.hasPrefix "path:" path then
# path: prefix indicates a local filesystem path - strip it and import directly
let
actualPath = builtins.substring 5 999999 path;
in
tryImport (/. + actualPath) path
else if lib.hasPrefix "/" path then
# Absolute path - import directly (avoids input resolution and NAR hash computation)
tryImport (/. + path) path
else if lib.hasPrefix "./" path then
# Relative paths are relative to devenv_root, not bootstrap directory
let
relPath = builtins.substring 1 255 path;
in
tryImport (/. + devenv_root + relPath) path
else if lib.hasPrefix "../" path then
# Parent relative paths also relative to devenv_root
tryImport (/. + devenv_root + "/${path}") path
else
let
paths = lib.splitString "/" path;
name = builtins.head paths;
input = inputs.${name} or (throw "Unknown input ${name}");
subpath = "/${lib.concatStringsSep "/" (builtins.tail paths)}";
devenvpath = input + subpath;
in
tryImport devenvpath path;
# Common modules shared between main evaluation and cross-system evaluation
mkCommonModules =
evalPkgs:
[
(
{ config, ... }:
{
_module.args.pkgs = evalPkgs.appendOverlays (config.overlays or [ ]);
_module.args.secretspec = secretspec;
_module.args.devenvPrimops = primops;
}
)
(inputs.devenv.modules + /top-level.nix)
(
{ options, ... }:
{
config.devenv = lib.mkMerge [
{
root = devenv_root;
dotfile = devenv_dotfile;
}
(
if builtins.hasAttr "cli" options.devenv then
{
cli.version = version;
cli.isDevelopment = is_development_version;
}
else
{
cliVersion = version;
}
)
(lib.optionalAttrs
(builtins.hasAttr "cli" options.devenv
&& builtins.hasAttr "requireVersionMatch" options.devenv.cli)
{
cli.requireVersionMatch = require_version_match;
}
)
(lib.optionalAttrs (builtins.hasAttr "tmpdir" options.devenv) {
tmpdir = devenv_tmpdir;
})
(lib.optionalAttrs (builtins.hasAttr "isTesting" options.devenv) {
isTesting = devenv_istesting;
})
(lib.optionalAttrs (builtins.hasAttr "runtime" options.devenv) {
runtime = devenv_runtime;
})
(lib.optionalAttrs (builtins.hasAttr "state" options.devenv && devenv_state != null) {
state = lib.mkForce devenv_state;
})
(lib.optionalAttrs (builtins.hasAttr "direnvrcLatestVersion" options.devenv) {
direnvrcLatestVersion = devenv_direnvrc_latest_version;
})
];
}
)
(
{ options, ... }:
{
config = lib.mkMerge [
(lib.optionalAttrs (builtins.hasAttr "git" options) {
git.root = git_root;
})
];
}
)
]
++ (lib.flatten (map importModule devenv_imports))
++ (if !skip_local_src then (importModule (devenv_root + "/devenv.nix")) else [ ])
++ [
(
let
localPath = devenv_root + "/devenv.local.nix";
in
if builtins.pathExists localPath then import localPath else { }
)
cli_options
];
# Phase 1: Base evaluation to extract profile definitions
baseProject = lib.evalModules {
specialArgs = inputs // {
inherit inputs secretspec primops;
};
modules = mkCommonModules pkgsBootstrap;
};
# Phase 2: Extract and apply profiles using extendModules with priority overrides
project =
let
# Build ordered list of profile names: hostname -> user -> manual
manualProfiles = active_profiles;
currentHostname = hostname;
currentUsername = username;
hostnameProfiles = lib.optional
(
currentHostname != null
&& currentHostname != ""
&& builtins.hasAttr currentHostname (baseProject.config.profiles.hostname or { })
) "hostname.${currentHostname}";
userProfiles = lib.optional
(
currentUsername != null
&& currentUsername != ""
&& builtins.hasAttr currentUsername (baseProject.config.profiles.user or { })
) "user.${currentUsername}";
# Ordered list of profiles to activate
orderedProfiles = hostnameProfiles ++ userProfiles ++ manualProfiles;
# Resolve profile extends with cycle detection
resolveProfileExtends =
profileName: visited:
if builtins.elem profileName visited then
throw "Circular dependency detected in profile extends: ${lib.concatStringsSep " -> " visited} -> ${profileName}"
else
let
profile = getProfileConfig profileName;
extends = profile.extends or [ ];
newVisited = visited ++ [ profileName ];
extendedProfiles = lib.flatten (map (name: resolveProfileExtends name newVisited) extends);
in
extendedProfiles ++ [ profileName ];
# Get profile configuration by name from baseProject
getProfileConfig =
profileName:
if lib.hasPrefix "hostname." profileName then
let
name = lib.removePrefix "hostname." profileName;
in
baseProject.config.profiles.hostname.${name}
else if lib.hasPrefix "user." profileName then
let
name = lib.removePrefix "user." profileName;
in
baseProject.config.profiles.user.${name}
else
let
availableProfiles = builtins.attrNames (baseProject.config.profiles or { });
hostnameProfiles = map (n: "hostname.${n}") (
builtins.attrNames (baseProject.config.profiles.hostname or { })
);
userProfiles = map (n: "user.${n}") (builtins.attrNames (baseProject.config.profiles.user or { }));
allAvailableProfiles = availableProfiles ++ hostnameProfiles ++ userProfiles;
in
baseProject.config.profiles.${profileName}
or (throw "Profile '${profileName}' not found. Available profiles: ${lib.concatStringsSep ", " allAvailableProfiles}");
# Fold over ordered profiles to build final list with extends
expandedProfiles = lib.foldl'
(
acc: profileName:
let
allProfileNames = resolveProfileExtends profileName [ ];
in
acc ++ allProfileNames
) [ ]
orderedProfiles;
# Map over expanded profiles and apply priorities
allPrioritizedModules = lib.imap0
(
index: profileName:
let
profilePriority = (lib.modules.defaultOverridePriority - 1) - index;
profileConfig = getProfileConfig profileName;
typeNeedsOverride =
type:
if type == null then
false
else
let
typeName = type.name or type._type or "";
isLeafType = builtins.elem typeName [
"str"
"int"
"bool"
"enum"
"path"
"package"
"float"
"anything"
];
in
if isLeafType then
true
else if typeName == "nullOr" then
let
innerType =
type.elemType
or (if type ? nestedTypes && type.nestedTypes ? elemType then type.nestedTypes.elemType else null);
in
if innerType != null then typeNeedsOverride innerType else false
else
false;
pathNeedsOverride =
optionPath:
let
directOption = lib.attrByPath optionPath null baseProject.options;
in
if directOption != null && lib.isOption directOption then
typeNeedsOverride directOption.type
else if optionPath != [ ] then
let
parentPath = lib.init optionPath;
parentOption = lib.attrByPath parentPath null baseProject.options;
in
if parentOption != null && lib.isOption parentOption then
let
freeformType = parentOption.type.freeformType or parentOption.type.nestedTypes.freeformType or null;
elementType =
if freeformType ? elemType then
freeformType.elemType
else if freeformType ? nestedTypes && freeformType.nestedTypes ? elemType then
freeformType.nestedTypes.elemType
else
freeformType;
in
typeNeedsOverride elementType
else
false
else
false;
applyModuleOverride =
config:
if builtins.isFunction config then
let
wrapper = args: applyOverrideRecursive (config args) [ ];
in
lib.mirrorFunctionArgs config wrapper
else
applyOverrideRecursive config [ ];
applyOverrideRecursive =
config: optionPath:
if lib.isAttrs config && config ? _type then
config
else if lib.isAttrs config then
lib.mapAttrs (name: value: applyOverrideRecursive value (optionPath ++ [ name ])) config
else if pathNeedsOverride optionPath then
lib.mkOverride profilePriority config
else
config;
prioritizedConfig = (
profileConfig.module
// {
imports = lib.map
(
importItem:
importItem
// {
imports = lib.map (nestedImport: applyModuleOverride nestedImport) (importItem.imports or [ ]);
}
)
(profileConfig.module.imports or [ ]);
}
);
in
prioritizedConfig
)
expandedProfiles;
in
if allPrioritizedModules == [ ] then
baseProject
else
baseProject.extendModules { modules = allPrioritizedModules; };
config = project.config;
# Per-container scoped re-evaluation that flips `isBuilding` for the
# container being built. Selecting one container cannot pollute the
# evaluation of any other operation, since each `containerBuilds.<name>`
# is its own `extendModules` scope.
mkContainerBuilds =
evalProject:
lib.genAttrs (lib.attrNames evalProject.config.containers) (
name:
let
scoped = evalProject.extendModules {
modules = [{
container.isBuilding = lib.mkForce true;
containers.${name}.isBuilding = lib.mkForce true;
}];
};
in
scoped.config.containers.${name}
);
containerBuilds = mkContainerBuilds project;
# Apply config overlays to pkgs
pkgs = pkgsBootstrap.appendOverlays (config.overlays or [ ]);
options = pkgs.nixosOptionsDoc {
options = builtins.removeAttrs project.options [ "_module" ];
warningsAreErrors = false;
transformOptions =
let
isDocType =
v:
builtins.elem v [
"literalDocBook"
"literalExpression"
"literalMD"
"mdDoc"
];
in
lib.attrsets.mapAttrs (
_: v:
if v ? _type && isDocType v._type then
v.text
else if v ? _type && v._type == "derivation" then
v.name
else
v
);
};
build =
options: config:
lib.concatMapAttrs
(
name: option:
if lib.isOption option then
let
typeName = option.type.name or "";
in
if
builtins.elem typeName [
"output"
"outputOf"
]
then
{
${name} = config.${name};
}
else
{ }
else if builtins.isAttrs option && !lib.isDerivation option then
let
v = build option config.${name};
in
if v != { } then { ${name} = v; } else { }
else
{ }
)
options;
# Helper to evaluate devenv for a specific system (for cross-compilation, e.g. macOS building Linux containers)
evalForSystem =
evalSystem:
let
evalPkgs = mkPkgsForSystem evalSystem;
evalProject = lib.evalModules {
specialArgs = inputs // {
inherit inputs secretspec primops;
};
modules = mkCommonModules evalPkgs;
};
in
{
config = evalProject.config;
containerBuilds = mkContainerBuilds evalProject;
};
# All supported systems for cross-compilation (lazily evaluated)
allSystems = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
# Generate perSystem entries for all systems (only evaluated when accessed)
perSystemConfigs = lib.genAttrs allSystems (
perSystem:
if perSystem == targetSystem then
{ inherit config containerBuilds; }
else
evalForSystem perSystem
);
in
{
inherit
pkgs
config
options
project
;
bash = pkgs.bash;
shell = config.shell;
optionsJSON = options.optionsJSON;
info = config.info;
ci = config.ciDerivation;
build = build project.options config;
devenv = {
# Backwards compatibility: wrap config in devenv attribute for code expecting devenv.config.*
inherit config containerBuilds;
# perSystem structure for cross-compilation (e.g. macOS building Linux containers)
perSystem = perSystemConfigs;
};
};
# Simplified devenv evaluation for inputs
# This is a lightweight version suitable for evaluating an input's devenv.nix
mkDevenvForInput =
{
# The input to evaluate (must have outPath and sourceInfo)
input
, # All resolved inputs (for specialArgs)
allInputs
, # System to evaluate for
system ? builtins.currentSystem
, # Nixpkgs to use (defaults to allInputs.nixpkgs)
nixpkgs ? allInputs.nixpkgs or (throw "nixpkgs input required")
, # Devenv modules (defaults to allInputs.devenv)
devenv ? allInputs.devenv or (throw "devenv input required")
,
}:
let
devenvPath = input.outPath + "/devenv.nix";
hasDevenv = builtins.pathExists devenvPath;
in
if !hasDevenv then
throw ''
Input does not have a devenv.nix file.
Expected file at: ${devenvPath}
To use this input's devenv configuration, the input must provide a devenv.nix file.
''
else
let
pkgs = import nixpkgs {
inherit system;
config = { };
};
lib = pkgs.lib;
project = lib.evalModules {
specialArgs = allInputs // {
inputs = allInputs;
secretspec = null;
};
modules = [
(
{ config, ... }:
{
_module.args.pkgs = pkgs.appendOverlays (config.overlays or [ ]);
}
)
(devenv.outPath + "/src/modules/top-level.nix")
(import devenvPath)
];
};
in
{
inherit pkgs;
config = project.config;
options = project.options;
inherit project;
};
}

View File

@@ -0,0 +1,19 @@
args@{ system
, # The project root (location of devenv.nix)
devenv_root
, ...
}:
let
inherit
(import ./resolve-lock.nix {
src = devenv_root;
inherit system;
})
inputs
;
bootstrapLib = import ./bootstrapLib.nix { inherit inputs; };
in
bootstrapLib.mkDevenvForSystem args

View File

@@ -0,0 +1,157 @@
# Adapted from https://git.lix.systems/lix-project/flake-compat/src/branch/main/default.nix
{ src
, system ? builtins.currentSystem or "unknown-system"
,
}:
let
lockFilePath = src + "/devenv.lock";
lockFile = builtins.fromJSON (builtins.readFile lockFilePath);
rootSrc = {
lastModified = 0;
lastModifiedDate = formatSecondsSinceEpoch 0;
# *hacker voice*: it's definitely a store path, I promise (actually a
# nixlang path value, likely not pointing at the store).
outPath = src;
};
# Format number of seconds in the Unix epoch as %Y%m%d%H%M%S.
formatSecondsSinceEpoch =
t:
let
rem = x: y: x - x / y * y;
days = t / 86400;
secondsInDay = rem t 86400;
hours = secondsInDay / 3600;
minutes = (rem secondsInDay 3600) / 60;
seconds = rem t 60;
# Courtesy of https://stackoverflow.com/a/32158604.
z = days + 719468;
era = (if z >= 0 then z else z - 146096) / 146097;
doe = z - era * 146097;
yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
y = yoe + era * 400;
doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
mp = (5 * doy + 2) / 153;
d = doy - (153 * mp + 2) / 5 + 1;
m = mp + (if mp < 10 then 3 else -9);
y' = y + (if m <= 2 then 1 else 0);
pad = s: if builtins.stringLength s < 2 then "0" + s else s;
in
"${toString y'}${pad (toString m)}${pad (toString d)}${pad (toString hours)}${pad (toString minutes)}${pad (toString seconds)}";
allNodes = builtins.mapAttrs
(
key: node:
let
sourceInfo =
if key == lockFile.root then
rootSrc
# Path inputs pointing to project root (path = ".") should use rootSrc
# to avoid fetchTree hashing the entire project directory
else if node.locked.type or null == "path" && node.locked.path or null == "." then
rootSrc
else
let
locked = node.locked;
isRelativePath = p: p != null && (builtins.substring 0 2 p == "./" || builtins.substring 0 3 p == "../");
# Resolve relative paths against src
resolvedLocked = locked
// (if locked.type or null == "path" && isRelativePath (locked.path or null)
then { path = toString src + "/${locked.path}"; }
else { })
// (if locked.type or null == "git" && isRelativePath (locked.url or null)
then { url = toString src + "/${locked.url}"; }
else { });
in
builtins.fetchTree (node.info or { } // removeAttrs resolvedLocked [ "dir" ]);
subdir = if key == lockFile.root then "" else node.locked.dir or "";
outPath = sourceInfo + ((if subdir == "" then "" else "/") + subdir);
# Resolve a input spec into a node name. An input spec is
# either a node name, or a 'follows' path from the root
# node.
resolveInput =
inputSpec: if builtins.isList inputSpec then getInputByPath lockFile.root inputSpec else inputSpec;
# Follow an input path (e.g. ["dwarffs" "nixpkgs"]) from the
# root node, returning the final node.
getInputByPath =
nodeName: path:
if path == [ ] then
nodeName
else
getInputByPath
# Since this could be a 'follows' input, call resolveInput.
(resolveInput lockFile.nodes.${nodeName}.inputs.${builtins.head path})
(builtins.tail path);
inputs = builtins.mapAttrs (inputName: inputSpec: allNodes.${resolveInput inputSpec}) (
node.inputs or { }
);
# Only import flake.nix for non-root nodes (root doesn't need it)
flake = if key == lockFile.root then null else import (outPath + "/flake.nix");
outputs = if key == lockFile.root then { } else flake.outputs (inputs // { self = result; });
# Lazy devenv evaluation for this input
devenvEval =
let
bootstrapLib = import ./bootstrapLib.nix { inputs = inputs; };
in
bootstrapLib.mkDevenvForInput {
input = { inherit outPath sourceInfo; };
allInputs = inputs;
inherit system;
};
result =
outputs
// sourceInfo
// {
inherit outPath;
inherit inputs;
inherit outputs;
inherit sourceInfo;
_type = "flake";
devenv = devenvEval;
};
nonFlakeResult = sourceInfo // {
inherit outPath;
inherit inputs;
inherit sourceInfo;
_type = "flake";
devenv = devenvEval;
};
in
if node.flake or true && key != lockFile.root then
assert builtins.isFunction flake.outputs;
result
else
nonFlakeResult
)
lockFile.nodes;
result =
if !(builtins.pathExists lockFilePath) then
throw "${lockFilePath} does not exist"
else if lockFile.version >= 5 && lockFile.version <= 7 then
allNodes.${lockFile.root}
else
throw "lock file '${lockFilePath}' has unsupported version ${toString lockFile.version}";
in
{
inputs = result.inputs or { } // {
self = result;
};
}

1
.devenv/gc/shell Symbolic link
View File

@@ -0,0 +1 @@
/nix/store/qfli8mq0fxc3lfj1w7yv00zgf8n3fa6c-devenv-shell

View File

@@ -0,0 +1 @@
/nix/store/vsp3fis0yyfrw5zdw1r908cz5wkwy1qs-tasks.json

0
.devenv/imports.txt Normal file
View File

10
.devenv/input-paths.txt Normal file
View File

@@ -0,0 +1,10 @@
/home/user01/Projects/score-system/.devenv/bootstrap/bootstrapLib.nix
/home/user01/Projects/score-system/.devenv/bootstrap/default.nix
/home/user01/Projects/score-system/.devenv/bootstrap/resolve-lock.nix
/home/user01/Projects/score-system/devenv.local.nix
/home/user01/Projects/score-system/devenv.lock
/home/user01/Projects/score-system/devenv.nix
/home/user01/Projects/score-system/devenv.yaml
/home/user01/.config/nixpkgs/overlays
/home/user01/.config/nixpkgs/overlays.nix
/home/user01/Projects/score-system/.env

1
.devenv/load-exports Executable file
View File

@@ -0,0 +1 @@

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,12 @@
let
cfg = {};
getName = pkg: (builtins.parseDrvName (pkg.name or pkg.pname or "")).name;
in cfg // {
allowUnfreePredicate =
if cfg.allowUnfree or false then
(_: true)
else if (cfg.permittedUnfreePackages or []) != [] then
(pkg: builtins.elem (getName pkg) (cfg.permittedUnfreePackages or []))
else
(_: false);
}

1
.devenv/profile Symbolic link
View File

@@ -0,0 +1 @@
/nix/store/z7jz33yvsqvfv3qxpy2r9mp3mh0ngcvg-devenv-profile

1
.devenv/run Symbolic link
View File

@@ -0,0 +1 @@
/run/user/1000/devenv-3f21a4e

2265
.devenv/shell-3f79910ee86ced32.sh Executable file

File diff suppressed because it is too large Load Diff

2265
.devenv/shell-7f08e6d76227994d.sh Executable file

File diff suppressed because it is too large Load Diff

2265
.devenv/shell-e893b9157f2d2e31.sh Executable file

File diff suppressed because it is too large Load Diff

2257
.devenv/shell-env.sh Normal file

File diff suppressed because it is too large Load Diff

163
.devenv/shell-rcfile.sh Normal file
View File

@@ -0,0 +1,163 @@
# Disable history during init so devenv internal commands don't pollute history.
set +o history
# Environment diff helpers (always defined for tracking)
# Environment diff helpers (inspired by direnv)
# Diff is stored in _DEVENV_DIFF env var (not a file) so each shell has its own state
# Uses gzip+base64 encoding for compact storage
# Variables to ignore in diff (shell internals that change dynamically)
__devenv_ignored_var() {
case "$1" in
_*|PWD|OLDPWD|SHLVL|SHELL|SHELLOPTS|BASHOPTS|BASH_*|HISTCMD|HISTFILE)
return 0 ;;
PS1|PS2|PS3|PS4|PROMPT|PROMPT_COMMAND|PROMPT_DIRTRIM)
return 0 ;;
COMP_*|READLINE_*|MAILCHECK|COLUMNS|LINES|RANDOM|SECONDS|LINENO|EPOCHSECONDS|EPOCHREALTIME|SRANDOM)
return 0 ;;
STARSHIP_*|__fish*|DIRENV_*|nix_saved_*)
return 0 ;;
*)
return 1 ;;
esac
}
__devenv_capture_env() {
# Capture exported variables using declare -p for proper escaping
declare -p -x 2>/dev/null | LC_ALL=C sort
}
__devenv_serialize_diff() {
# Serialize diff (stdin) to base64-encoded gzip
gzip -c | base64 -w0
}
__devenv_deserialize_diff() {
# Deserialize diff from base64-encoded gzip to stdout
echo "$1" | base64 -d | gzip -d 2>/dev/null
}
__devenv_compute_diff() {
# Compare before ($1) and current env, return diff via _DEVENV_DIFF env var
local before_file="$1"
# Create temp files
local after_file diff_content
after_file=$(mktemp)
diff_content=$(mktemp)
__devenv_capture_env > "$after_file"
# Build associative arrays for before/after
local -A before_vars after_vars
while IFS= read -r line; do
[[ "$line" != declare\ -x\ * ]] && continue
local vardef="${line#declare -x }"
local var="${vardef%%=*}"
[[ -z "$var" ]] && continue
__devenv_ignored_var "$var" && continue
before_vars["$var"]="$line"
done < "$before_file"
while IFS= read -r line; do
[[ "$line" != declare\ -x\ * ]] && continue
local vardef="${line#declare -x }"
local var="${vardef%%=*}"
[[ -z "$var" ]] && continue
__devenv_ignored_var "$var" && continue
after_vars["$var"]="$line"
done < "$after_file"
# Find PREV entries (vars that were modified or removed)
for var in "${!before_vars[@]}"; do
if [[ "${after_vars[$var]}" != "${before_vars[$var]}" ]]; then
echo "P:${before_vars[$var]}" >> "$diff_content"
fi
done
# Find NEXT entries (vars that were added or modified)
for var in "${!after_vars[@]}"; do
if [[ -z "${before_vars[$var]+x}" ]]; then
echo "N:$var" >> "$diff_content"
elif [[ "${after_vars[$var]}" != "${before_vars[$var]}" ]]; then
echo "N:$var" >> "$diff_content"
fi
done
# Serialize and store in env var
_DEVENV_DIFF=$(__devenv_serialize_diff < "$diff_content")
export _DEVENV_DIFF
rm -f "$after_file" "$diff_content"
}
__devenv_apply_reverse_diff() {
# Reverse the diff: restore PREV values, unset NEXT-only vars
[[ -z "$_DEVENV_DIFF" ]] && return
local -A prev_vars
local diff_content
diff_content=$(__devenv_deserialize_diff "$_DEVENV_DIFF")
# First pass: collect and restore PREV declarations
while IFS= read -r line; do
if [[ "$line" == P:declare\ * ]]; then
local decl="${line#P:}"
local var="${decl#declare -x }"
var="${var%%=*}"
prev_vars["$var"]=1
# Use export instead of evaluating the declare statement directly,
# because declare -x inside a function creates a local variable
# in bash 5.0+.
eval "export ${decl#declare -x }" 2>/dev/null
fi
done <<< "$diff_content"
# Second pass: unset NEXT vars that were not in PREV (added vars)
while IFS= read -r line; do
if [[ "$line" == N:* ]]; then
local var="${line#N:}"
if [[ -z "${prev_vars[$var]+x}" ]]; then
unset "$var"
fi
fi
done <<< "$diff_content"
}
# Capture environment BEFORE sourcing devenv (for diff tracking)
_devenv_before_file=$(mktemp)
__devenv_capture_env > "$_devenv_before_file"
# Source the devenv environment
source "/home/user01/Projects/score-system/.devenv/shell-env.sh"
# Compute and store the initial diff in _DEVENV_DIFF env var
__devenv_compute_diff "$_devenv_before_file"
rm -f "$_devenv_before_file"
unset _devenv_before_file
# Save PATH before zsh init potentially modifies it
export _DEVENV_PATH="$PATH"
# Save original ZDOTDIR so zsh init can restore it
if [ -n "$ZDOTDIR" ]; then
export _DEVENV_REAL_ZDOTDIR="$ZDOTDIR"
fi
# Point ZDOTDIR to our init directory containing our .zshrc
export ZDOTDIR="/home/user01/Projects/score-system/.devenv/zsh"
# Re-enable history before exec
set -o history
# Exec into zsh (resolve via PATH if not absolute, since the devenv
# environment may have added it after this process started)
if [ ! -x "/run/current-system/sw/bin/zsh" ] && ! command -v "/run/current-system/sw/bin/zsh" >/dev/null 2>&1; then
echo "devenv: error: shell '/run/current-system/sw/bin/zsh' not found" >&2
echo "devenv: add zsh to your devenv.nix packages or set SHELL to an absolute path" >&2
exit 1
fi
exec "/run/current-system/sw/bin/zsh" -i
echo "devenv: error: failed to exec into /run/current-system/sw/bin/zsh" >&2
exit 1

1
.devenv/state/files.json Normal file
View File

@@ -0,0 +1 @@
{"managedFiles":[]}

BIN
.devenv/state/tasks.db-shm Normal file

Binary file not shown.

BIN
.devenv/state/tasks.db-wal Normal file

Binary file not shown.

6
.devenv/task-names.txt Normal file
View File

@@ -0,0 +1,6 @@
devenv:container:copy
devenv:enterShell
devenv:enterTest
devenv:files
devenv:files:cleanup
devenv:processes:server

2464
.devenv/zsh/.zcompdump Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

6
.devenv/zsh/.zshenv Normal file
View File

@@ -0,0 +1,6 @@
# devenv zsh .zshenv - runs before /etc/zshrc.
# Prepend devenv profile site-functions so the system compinit (often
# called from /etc/zshrc on nix-darwin, Debian, etc.) picks them up.
if [ -n "$DEVENV_PROFILE" ] && [ -d "$DEVENV_PROFILE/share/zsh/site-functions" ]; then
fpath=("$DEVENV_PROFILE/share/zsh/site-functions" $fpath)
fi

200
.devenv/zsh/.zshrc Normal file
View File

@@ -0,0 +1,200 @@
# devenv zsh init - restore ZDOTDIR and source user's .zshrc
if [ -n "$_DEVENV_REAL_ZDOTDIR" ]; then
ZDOTDIR="$_DEVENV_REAL_ZDOTDIR"
unset _DEVENV_REAL_ZDOTDIR
[ -f "$ZDOTDIR/.zshenv" ] && source "$ZDOTDIR/.zshenv"
[ -f "$ZDOTDIR/.zshrc" ] && source "$ZDOTDIR/.zshrc"
else
unset ZDOTDIR
[ -f "$HOME/.zshenv" ] && source "$HOME/.zshenv"
[ -f "$HOME/.zshrc" ] && source "$HOME/.zshrc"
fi
# Restore devenv PATH after user's .zshrc may have modified it
export PATH="$_DEVENV_PATH"
# Set devenv prompt prefix
PROMPT="(devenv) ${PROMPT}"
# Hot-reload hook
autoload -Uz add-zsh-hook
__devenv_reload_apply() {
# Source new environment if a reload is pending
if [ -f "/tmp/devenv-reload-6816.sh" ]; then
# Shell out to bash to handle the env diff (bash syntax)
local reload_output
reload_output=$(bash -c '
# Environment diff helpers (inspired by direnv)
# Diff is stored in _DEVENV_DIFF env var (not a file) so each shell has its own state
# Uses gzip+base64 encoding for compact storage
# Variables to ignore in diff (shell internals that change dynamically)
__devenv_ignored_var() {
case "$1" in
_*|PWD|OLDPWD|SHLVL|SHELL|SHELLOPTS|BASHOPTS|BASH_*|HISTCMD|HISTFILE)
return 0 ;;
PS1|PS2|PS3|PS4|PROMPT|PROMPT_COMMAND|PROMPT_DIRTRIM)
return 0 ;;
COMP_*|READLINE_*|MAILCHECK|COLUMNS|LINES|RANDOM|SECONDS|LINENO|EPOCHSECONDS|EPOCHREALTIME|SRANDOM)
return 0 ;;
STARSHIP_*|__fish*|DIRENV_*|nix_saved_*)
return 0 ;;
*)
return 1 ;;
esac
}
__devenv_capture_env() {
# Capture exported variables using declare -p for proper escaping
declare -p -x 2>/dev/null | LC_ALL=C sort
}
__devenv_serialize_diff() {
# Serialize diff (stdin) to base64-encoded gzip
gzip -c | base64 -w0
}
__devenv_deserialize_diff() {
# Deserialize diff from base64-encoded gzip to stdout
echo "$1" | base64 -d | gzip -d 2>/dev/null
}
__devenv_compute_diff() {
# Compare before ($1) and current env, return diff via _DEVENV_DIFF env var
local before_file="$1"
# Create temp files
local after_file diff_content
after_file=$(mktemp)
diff_content=$(mktemp)
__devenv_capture_env > "$after_file"
# Build associative arrays for before/after
local -A before_vars after_vars
while IFS= read -r line; do
[[ "$line" != declare\ -x\ * ]] && continue
local vardef="${line#declare -x }"
local var="${vardef%%=*}"
[[ -z "$var" ]] && continue
__devenv_ignored_var "$var" && continue
before_vars["$var"]="$line"
done < "$before_file"
while IFS= read -r line; do
[[ "$line" != declare\ -x\ * ]] && continue
local vardef="${line#declare -x }"
local var="${vardef%%=*}"
[[ -z "$var" ]] && continue
__devenv_ignored_var "$var" && continue
after_vars["$var"]="$line"
done < "$after_file"
# Find PREV entries (vars that were modified or removed)
for var in "${!before_vars[@]}"; do
if [[ "${after_vars[$var]}" != "${before_vars[$var]}" ]]; then
echo "P:${before_vars[$var]}" >> "$diff_content"
fi
done
# Find NEXT entries (vars that were added or modified)
for var in "${!after_vars[@]}"; do
if [[ -z "${before_vars[$var]+x}" ]]; then
echo "N:$var" >> "$diff_content"
elif [[ "${after_vars[$var]}" != "${before_vars[$var]}" ]]; then
echo "N:$var" >> "$diff_content"
fi
done
# Serialize and store in env var
_DEVENV_DIFF=$(__devenv_serialize_diff < "$diff_content")
export _DEVENV_DIFF
rm -f "$after_file" "$diff_content"
}
__devenv_apply_reverse_diff() {
# Reverse the diff: restore PREV values, unset NEXT-only vars
[[ -z "$_DEVENV_DIFF" ]] && return
local -A prev_vars
local diff_content
diff_content=$(__devenv_deserialize_diff "$_DEVENV_DIFF")
# First pass: collect and restore PREV declarations
while IFS= read -r line; do
if [[ "$line" == P:declare\ * ]]; then
local decl="${line#P:}"
local var="${decl#declare -x }"
var="${var%%=*}"
prev_vars["$var"]=1
# Use export instead of evaluating the declare statement directly,
# because declare -x inside a function creates a local variable
# in bash 5.0+.
eval "export ${decl#declare -x }" 2>/dev/null
fi
done <<< "$diff_content"
# Second pass: unset NEXT vars that were not in PREV (added vars)
while IFS= read -r line; do
if [[ "$line" == N:* ]]; then
local var="${line#N:}"
if [[ -z "${prev_vars[$var]+x}" ]]; then
unset "$var"
fi
fi
done <<< "$diff_content"
}
# Reverse previous diff
__devenv_apply_reverse_diff
# Capture env before sourcing new devenv
_before=$(mktemp)
__devenv_capture_env > "$_before"
# Source new devenv environment
source "/tmp/devenv-reload-6816.sh"
rm -f "/tmp/devenv-reload-6816.sh"
# Compute new diff
__devenv_compute_diff "$_before"
rm -f "$_before"
# Output current environment for the calling shell to parse
export -p
' 2>/dev/null)
# Apply the environment changes
if [ -n "$reload_output" ]; then
eval "$reload_output"
fi
# Update saved PATH
_DEVENV_PATH="$PATH"
fi
}
__devenv_restore_path() {
# Restore devenv PATH (in case direnv or other tools modified it)
export PATH="$_DEVENV_PATH"
}
__devenv_precmd_hook() {
__devenv_reload_apply
__devenv_restore_path
}
add-zsh-hook precmd __devenv_precmd_hook
# Keybinding for manual reload
__devenv_reload_widget() {
__devenv_reload_apply
zle reset-prompt
}
zle -N __devenv_reload_widget
bindkey "${DEVENV_RELOAD_KEYBIND:-\\e\\C-r}" __devenv_reload_widget

View File

@@ -1,5 +0,0 @@
# Cases for players or something
- player who didnt show up
- player draws
- events with multiple attempts (best / average)
- how actual points are decided

65
devenv.lock Normal file
View File

@@ -0,0 +1,65 @@
{
"nodes": {
"devenv": {
"locked": {
"dir": "src/modules",
"lastModified": 1781981587,
"narHash": "sha256-xkBPfggcaDdbBl4fhHnhgVv2XPmzM2CtNBCpSwlK4fY=",
"owner": "cachix",
"repo": "devenv",
"rev": "1ad4a4a03466826fc43127211c341d268efab21b",
"type": "github"
},
"original": {
"dir": "src/modules",
"owner": "cachix",
"repo": "devenv",
"type": "github"
}
},
"nixpkgs": {
"inputs": {
"nixpkgs-src": "nixpkgs-src"
},
"locked": {
"lastModified": 1781620901,
"narHash": "sha256-UF6scQlG+6lRkZBUpn/3KNavhOo5G8kDWhjVHcno8uc=",
"owner": "cachix",
"repo": "devenv-nixpkgs",
"rev": "2df109b343d3c68efd752e32a444a1d9b9f89afa",
"type": "github"
},
"original": {
"owner": "cachix",
"ref": "rolling",
"repo": "devenv-nixpkgs",
"type": "github"
}
},
"nixpkgs-src": {
"flake": false,
"locked": {
"lastModified": 1781454065,
"narHash": "sha256-d2xfDjnfRuf/xYGdu9VVRHiav/2w5hDL/5cw2TuVAXw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "9eac87a12312b8f60dd52e1c6e1a265f6fc7f5fc",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"devenv": "devenv",
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

11
devenv.nix Normal file
View File

@@ -0,0 +1,11 @@
{ pkgs, config, ... }: {
languages.typescript.enable = true;
packages = with pkgs; [
bun
eslint_d
];
env.DEVSHELL_NAME = "󰏖 devenv/#fab387| Bun/yellow";
processes = {
server.exec = "bun run dev";
};
}

0
devenv.yaml Normal file
View File

61
flake.lock generated
View File

@@ -1,61 +0,0 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1777578337,
"narHash": "sha256-Ad49moKWeXtKBJNy2ebiTQUEgdLyvGmTeykAQ9xM+Z4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "15f4ee454b1dce334612fa6843b3e05cf546efab",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs",
"utils": "utils"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

View File

@@ -1,42 +0,0 @@
{
description = "A simple Rust development environment";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
utils.url = "github:numtide/flake-utils";
};
outputs =
{
self,
nixpkgs,
utils,
}:
utils.lib.eachDefaultSystem (
system:
let
pkgs = import nixpkgs { inherit system; };
in
{
devShells.default = pkgs.mkShell {
name = "flake-bunshell";
buildInputs = with pkgs; [
bun
eslint_d
];
# Environment variables
shellHook = ''
export DEVSHELL_NAME="󱄅 flake/#89dceb| Bun/yellow"
# Trigger zsh
if [[ -z "$ZSH_VERSION" ]]; then
exec zsh
fi
'';
};
}
);
}