feat(dev-env): backport matured dev-env implementation from /etc/nixos
Replace the stub dev-env with the real, working implementation that grew
in the reference machine config — de-identified for the public scaffold.
Nix layer:
- options.nix: full project schema (url/upstream/fork/category/
worktreeRoot/worktrees{branch,path,remote}/isClone/deployFlakeInput),
deploy.targets, github.forkUser, writeDirenvHints. Drops the
forgejo-URL block + deploy-flake auto-derivation (incoherent in a
scaffold that uses explicit per-project urls).
- lib.nix: mkProject + worktreePath/bareRepoPath/projectRemotes,
generalized to the explicit-url model (origin falls back to upstream).
- config.nix: renders /etc/dev-env/{config.sh,projects.json,
tmux-sessions.json}, installs helpers via writeShellScriptBin, loads
shell functions into interactive shells, wires the git pre-commit hook.
Scripts (config-driven, read /etc/dev-env at runtime):
- bootstrap.sh, nav.sh, worktree.sh, pr-helpers.sh, rebase.sh,
status.sh, deploy.sh, regtest.sh, tmux-launch.sh.
- Stripped aiolabs/forgejo/bitspire/lamassu/webapp hardcoding; the
github-fork remote is renamed 'fork' to match git.remotes vocabulary.
- Removes the dev.sh stub (the matured impl uses discrete commands +
shell functions, not a unified 'dev' CLI).
presets/example.nix: a worked, generic project list replacing the
identity-specific aiolabs preset. tests/smoke.nix + flake checks
exercise the schema; 'nix flake check' is green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
773632562e
commit
e38d313db2
17 changed files with 2925 additions and 147 deletions
|
|
@ -1,22 +1,111 @@
|
|||
# lnbits-sensei dev-env — helpers.
|
||||
#
|
||||
# Skeleton-only. Place dev-env-internal helpers here (project path
|
||||
# resolution, worktree-path expansion, remote-URL canonicalisation)
|
||||
# rather than in the global `lnbits-sensei.lib` so they're scoped to
|
||||
# the dev-env module and don't pollute the public helper namespace.
|
||||
# dev-env-internal helpers scoped to this module (project path
|
||||
# resolution, worktree-path expansion, remote construction) rather than
|
||||
# the global `lnbits-sensei.lib` namespace. Exposed as
|
||||
# `config.lnbits-sensei.devEnv.lib` so config.nix and the example preset
|
||||
# can build project entries with less boilerplate.
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
cfg = config.lnbits-sensei.devEnv;
|
||||
|
||||
# mkProject: shorthand constructor for `devEnv.projects.<name>`.
|
||||
#
|
||||
# Fills in conventional defaults so consumers write less boilerplate.
|
||||
# The returned attrset matches the `projectType` submodule schema.
|
||||
#
|
||||
# mkProject {
|
||||
# name = "lnbits";
|
||||
# url = "git@git.example.com:you/lnbits.git";
|
||||
# upstream = "https://github.com/lnbits/lnbits";
|
||||
# worktrees = { main.branch = "main"; dev.branch = "dev"; };
|
||||
# }
|
||||
mkProject =
|
||||
{
|
||||
name ? null,
|
||||
category ? null,
|
||||
url ? null, # origin remote URL
|
||||
upstream ? null,
|
||||
fork ? null, # defaults from github.forkUser when upstream is set
|
||||
worktrees ? { },
|
||||
isClone ? false,
|
||||
deployFlakeInput ? null,
|
||||
worktreeRoot ? null, # defaults to name
|
||||
}:
|
||||
{
|
||||
inherit
|
||||
url
|
||||
upstream
|
||||
category
|
||||
isClone
|
||||
deployFlakeInput
|
||||
;
|
||||
fork =
|
||||
if fork != null then
|
||||
fork
|
||||
else if upstream != null && cfg.github.forkUser != null && name != null then
|
||||
"git@github.com:${cfg.github.forkUser}/${name}.git"
|
||||
else
|
||||
null;
|
||||
worktreeRoot =
|
||||
if worktreeRoot != null then
|
||||
worktreeRoot
|
||||
else if name != null then
|
||||
name
|
||||
else
|
||||
"";
|
||||
inherit worktrees;
|
||||
};
|
||||
|
||||
# Resolve worktree filesystem paths. Projects with a category live
|
||||
# under ${root}/${category}/${worktreeRoot}/<worktree>; otherwise
|
||||
# ${root}/${worktreeRoot}/<worktree>.
|
||||
worktreePath =
|
||||
_projectName: project: worktreeName:
|
||||
let
|
||||
root = cfg.root;
|
||||
sub =
|
||||
if project.category != null then
|
||||
"${project.category}/${project.worktreeRoot}"
|
||||
else
|
||||
project.worktreeRoot;
|
||||
leaf =
|
||||
let
|
||||
wt = project.worktrees.${worktreeName} or null;
|
||||
in
|
||||
if wt != null && wt.path != null then wt.path else worktreeName;
|
||||
in
|
||||
"${root}/${sub}/${leaf}";
|
||||
|
||||
# Bare repo path (always ${root}/repos/<basename>.git). The basename
|
||||
# is derived from the project name; the bare object DB is shared by
|
||||
# every worktree of the project.
|
||||
bareRepoPath = projectName: _project: "${cfg.root}/repos/${projectName}.git";
|
||||
|
||||
# Construct the remotes for a project. `origin` is `url` if set,
|
||||
# otherwise falls back to `upstream` (pure-upstream tracking repo).
|
||||
# Projects with neither end up with no origin (filtered out).
|
||||
projectRemotes =
|
||||
project:
|
||||
lib.filterAttrs (_: v: v != null) {
|
||||
origin =
|
||||
if project.url != null then
|
||||
project.url
|
||||
else
|
||||
project.upstream;
|
||||
upstream = project.upstream;
|
||||
fork = project.fork;
|
||||
};
|
||||
|
||||
helpers = {
|
||||
# Resolve a project's on-disk root given a project name.
|
||||
# projectRoot = name: "${config.lnbits-sensei.devEnv.root}/${name}";
|
||||
projectRoot = _name: throw "dev-env.lib.projectRoot: not yet implemented";
|
||||
|
||||
# Resolve a worktree path: <root>/<project>/<worktree>.
|
||||
worktreePath =
|
||||
_project: _worktree: throw "dev-env.lib.worktreePath: not yet implemented";
|
||||
inherit
|
||||
mkProject
|
||||
worktreePath
|
||||
bareRepoPath
|
||||
projectRemotes
|
||||
;
|
||||
};
|
||||
in
|
||||
{
|
||||
|
|
|
|||
Reference in a new issue