moved to devenv
This commit is contained in:
1
.devenv/bash-bash
Symbolic link
1
.devenv/bash-bash
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
/nix/store/cgjr3kj3hs7ngznyws5qfg16c8scpys0-bash-interactive-5.3p9
|
||||||
603
.devenv/bootstrap/bootstrapLib.nix
Normal file
603
.devenv/bootstrap/bootstrapLib.nix
Normal 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;
|
||||||
|
};
|
||||||
|
}
|
||||||
19
.devenv/bootstrap/default.nix
Normal file
19
.devenv/bootstrap/default.nix
Normal 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
|
||||||
157
.devenv/bootstrap/resolve-lock.nix
Normal file
157
.devenv/bootstrap/resolve-lock.nix
Normal 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
1
.devenv/gc/shell
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
/nix/store/qfli8mq0fxc3lfj1w7yv00zgf8n3fa6c-devenv-shell
|
||||||
1
.devenv/gc/task-config-devenv-config-task-config
Symbolic link
1
.devenv/gc/task-config-devenv-config-task-config
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
/nix/store/vsp3fis0yyfrw5zdw1r908cz5wkwy1qs-tasks.json
|
||||||
0
.devenv/imports.txt
Normal file
0
.devenv/imports.txt
Normal file
10
.devenv/input-paths.txt
Normal file
10
.devenv/input-paths.txt
Normal 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
1
.devenv/load-exports
Executable file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
BIN
.devenv/nix-eval-cache.db-shm
Normal file
BIN
.devenv/nix-eval-cache.db-shm
Normal file
Binary file not shown.
BIN
.devenv/nix-eval-cache.db-wal
Normal file
BIN
.devenv/nix-eval-cache.db-wal
Normal file
Binary file not shown.
12
.devenv/nixpkgs-config-f0bff968555a3434.nix
Normal file
12
.devenv/nixpkgs-config-f0bff968555a3434.nix
Normal 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
1
.devenv/profile
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
/nix/store/z7jz33yvsqvfv3qxpy2r9mp3mh0ngcvg-devenv-profile
|
||||||
1
.devenv/run
Symbolic link
1
.devenv/run
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
/run/user/1000/devenv-3f21a4e
|
||||||
2265
.devenv/shell-3f79910ee86ced32.sh
Executable file
2265
.devenv/shell-3f79910ee86ced32.sh
Executable file
File diff suppressed because it is too large
Load Diff
2265
.devenv/shell-7f08e6d76227994d.sh
Executable file
2265
.devenv/shell-7f08e6d76227994d.sh
Executable file
File diff suppressed because it is too large
Load Diff
2265
.devenv/shell-e893b9157f2d2e31.sh
Executable file
2265
.devenv/shell-e893b9157f2d2e31.sh
Executable file
File diff suppressed because it is too large
Load Diff
2257
.devenv/shell-env.sh
Normal file
2257
.devenv/shell-env.sh
Normal file
File diff suppressed because it is too large
Load Diff
163
.devenv/shell-rcfile.sh
Normal file
163
.devenv/shell-rcfile.sh
Normal 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
1
.devenv/state/files.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"managedFiles":[]}
|
||||||
BIN
.devenv/state/tasks.db-shm
Normal file
BIN
.devenv/state/tasks.db-shm
Normal file
Binary file not shown.
BIN
.devenv/state/tasks.db-wal
Normal file
BIN
.devenv/state/tasks.db-wal
Normal file
Binary file not shown.
6
.devenv/task-names.txt
Normal file
6
.devenv/task-names.txt
Normal 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
2464
.devenv/zsh/.zcompdump
Normal file
File diff suppressed because it is too large
Load Diff
2467
.devenv/zsh/.zcompdump-HACKSTATION-5.9.1
Normal file
2467
.devenv/zsh/.zcompdump-HACKSTATION-5.9.1
Normal file
File diff suppressed because it is too large
Load Diff
BIN
.devenv/zsh/.zcompdump-HACKSTATION-5.9.1.zwc
Normal file
BIN
.devenv/zsh/.zcompdump-HACKSTATION-5.9.1.zwc
Normal file
Binary file not shown.
6
.devenv/zsh/.zshenv
Normal file
6
.devenv/zsh/.zshenv
Normal 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
200
.devenv/zsh/.zshrc
Normal 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
|
||||||
|
|
||||||
5
cases.md
5
cases.md
@@ -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
65
devenv.lock
Normal 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
11
devenv.nix
Normal 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
0
devenv.yaml
Normal file
61
flake.lock
generated
61
flake.lock
generated
@@ -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
|
|
||||||
}
|
|
||||||
42
flake.nix
42
flake.nix
@@ -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
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user