feat: basic bump
This commit is contained in:
commit
c86df50063
12 changed files with 535 additions and 0 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
|
@ -0,0 +1 @@
|
|||
use flake
|
||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
.build
|
||||
.direnv
|
||||
11
Makefile
Normal file
11
Makefile
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
OUT_DIR = .build
|
||||
OBJECTS = src/*.c
|
||||
|
||||
prep-out:
|
||||
@mkdir -p $(OUT_DIR)/bin
|
||||
|
||||
build: prep-out
|
||||
@gcc -o $(OUT_DIR)/bin/out $(OBJECTS)
|
||||
|
||||
run: build
|
||||
@$(OUT_DIR)/bin/out
|
||||
77
flake.lock
generated
Normal file
77
flake.lock
generated
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1778716662,
|
||||
"narHash": "sha256-m1Yf0wZ8j1OHjTc2UwHwyQRSnNeSgLJOd7q5Y45hzi4=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "f7c1a2d347e4c52d5fb8d10cb4d94b5884e546fb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"import-tree": {
|
||||
"locked": {
|
||||
"lastModified": 1778781969,
|
||||
"narHash": "sha256-Jjuz5CmSkur8KvLDoGa+vylEp+RkQtv4mt/qcMznpH0=",
|
||||
"owner": "vic",
|
||||
"repo": "import-tree",
|
||||
"rev": "d321337efd0f23a9eb14a42adb7b2c29313ab274",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "vic",
|
||||
"repo": "import-tree",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1781074563,
|
||||
"narHash": "sha256-md8WlXOlfnIeHeOScMTTHFyf2d6iaTwPl2apR5EQ3P4=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9ae611a455b90cf061d8f332b977e387bda8e1ca",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"lastModified": 1777168982,
|
||||
"narHash": "sha256-GOkGPcboWE9BmGCRMLX3worL4EMnsnG8MyKmXNeYuhQ=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"rev": "f5901329dade4a6ea039af1433fb087bd9c1fe14",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-parts": "flake-parts",
|
||||
"import-tree": "import-tree",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
11
flake.nix
Normal file
11
flake.nix
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
|
||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||
import-tree.url = "github:vic/import-tree";
|
||||
};
|
||||
|
||||
outputs =
|
||||
inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./nix-modules);
|
||||
}
|
||||
245
nix-modules/packages/boilerplate/boilerplate.py
Normal file
245
nix-modules/packages/boilerplate/boilerplate.py
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
KIND_LAYOUTS = {
|
||||
"layer": Path("nix-modules/features/layers"),
|
||||
"feature": Path("nix-modules/features"),
|
||||
"host": Path("nix-modules/hosts"),
|
||||
"package": Path("nix-modules/packages"),
|
||||
}
|
||||
|
||||
|
||||
NAME_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.-]*$")
|
||||
|
||||
|
||||
def nix_string(value: str) -> str:
|
||||
return json.dumps(value)
|
||||
|
||||
|
||||
def git_root() -> Path | None:
|
||||
result = subprocess.run(
|
||||
["git", "rev-parse", "--show-toplevel"],
|
||||
check=False,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
return None
|
||||
return Path(result.stdout.strip())
|
||||
|
||||
|
||||
def host_templates(name: str) -> dict[Path, str]:
|
||||
return {
|
||||
Path("default.nix"):
|
||||
textwrap.dedent(
|
||||
f"""\
|
||||
{{ self, inputs, ... }}:
|
||||
{{
|
||||
flake.nixosConfigurations.{name} = inputs.nixpkgs.lib.nixosSystem {{
|
||||
system = builtins.currentSystem;
|
||||
modules = [
|
||||
self.nixosModules.{name}Configuration
|
||||
];
|
||||
}};
|
||||
}}
|
||||
"""
|
||||
),
|
||||
Path("configuration.nix"):
|
||||
textwrap.dedent(
|
||||
f"""\
|
||||
{{ self, inputs, ... }}:
|
||||
{{
|
||||
flake.nixosModules.{name}Configuration =
|
||||
{{ pkgs, lib, ... }}:
|
||||
{{
|
||||
imports = [
|
||||
self.nixosModules.{name}Hardware
|
||||
];
|
||||
system.stateVersion = "25.11";
|
||||
}};
|
||||
}}
|
||||
"""
|
||||
),
|
||||
Path("hardware-configuration.nix"):
|
||||
textwrap.dedent(
|
||||
f"""\
|
||||
{{ self, inputs, ... }}:
|
||||
{{
|
||||
flake.nixosModules.{name}Hardware =
|
||||
{{ lib, pkgs, ... }}:
|
||||
{{
|
||||
config = {{
|
||||
# If you're building a full system here, you'd likely want to just copy the hardware
|
||||
# configuration generated by the NixOS installer. I've added some stuff here just so
|
||||
# `nix flake check` passes on initialization of the flake and to show how it _could_
|
||||
# look. You can find it here: `/etc/nixos/hardware-configuration.nix`
|
||||
|
||||
boot.loader.grub.devices = [ "/dev/sda" ];
|
||||
|
||||
fileSystems."/" = {{
|
||||
device = "tmpfs";
|
||||
fsType = "tmpfs";
|
||||
}};
|
||||
}};
|
||||
}};
|
||||
}}
|
||||
"""
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def template(kind: str, name: str) -> str:
|
||||
if kind in {"layer", "feature"}:
|
||||
return textwrap.dedent(
|
||||
f"""\
|
||||
{{ self, inputs, ... }}:
|
||||
{{
|
||||
flake.nixosModules.{name} = {{ pkgs, lib, ... }}:
|
||||
{{
|
||||
config = {{
|
||||
}};
|
||||
}};
|
||||
}}
|
||||
"""
|
||||
)
|
||||
|
||||
if kind == "host":
|
||||
quoted_name = nix_string(name)
|
||||
return textwrap.dedent(
|
||||
f"""\
|
||||
{{ self, inputs, ... }}:
|
||||
{{
|
||||
flake.nixosModules.{name} = {{ pkgs, lib, ... }}:
|
||||
{{
|
||||
config = {{
|
||||
networking.hostName = {quoted_name};
|
||||
# system.stateVersion = "25.11";
|
||||
}};
|
||||
}};
|
||||
|
||||
flake.nixosConfigurations.{name} = inputs.nixpkgs.lib.nixosSystem {{
|
||||
modules = [
|
||||
self.nixosModules.{name}
|
||||
];
|
||||
}};
|
||||
}}
|
||||
"""
|
||||
)
|
||||
|
||||
if kind == "package":
|
||||
quoted_name = nix_string(name)
|
||||
return textwrap.dedent(
|
||||
f"""\
|
||||
{{ self, inputs, ... }}:
|
||||
{{
|
||||
perSystem =
|
||||
{{ pkgs, ... }}:
|
||||
{{
|
||||
packages.{name} = pkgs.writeShellApplication {{
|
||||
name = {quoted_name};
|
||||
runtimeInputs = [ ];
|
||||
text = ''
|
||||
echo "TODO: implement {name}"
|
||||
'';
|
||||
}};
|
||||
}};
|
||||
}}
|
||||
"""
|
||||
)
|
||||
|
||||
raise ValueError(f"Unsupported kind: {kind}")
|
||||
|
||||
|
||||
def planned_files(kind: str, name: str, multifile: bool) -> dict[Path, str]:
|
||||
if kind == "host":
|
||||
return host_templates(name)
|
||||
|
||||
target = Path("default.nix") if multifile else Path(f"{name}.nix")
|
||||
return {target: template(kind, name)}
|
||||
|
||||
|
||||
def write_file(path: Path, content: str) -> None:
|
||||
if path.exists():
|
||||
raise FileExistsError(f"Refusing to overwrite existing path: {path}")
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(content.rstrip() + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def stage(paths: list[Path], root: Path) -> None:
|
||||
subprocess.run(
|
||||
["git", "add", "--", *[str(path.relative_to(root)) for path in paths]],
|
||||
check=True,
|
||||
cwd=root,
|
||||
)
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Generate Nix boilerplate modules")
|
||||
parser.add_argument("kind", choices=sorted(KIND_LAYOUTS))
|
||||
parser.add_argument("name")
|
||||
parser.add_argument("--no-git-stage", action="store_true", help="Do not stage created files")
|
||||
parser.add_argument("--dry-run", action="store_true", help="Print planned files without creating them")
|
||||
parser.add_argument(
|
||||
"--multifile",
|
||||
action="store_true",
|
||||
help="Create <name>/default.nix instead of <name>.nix",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
|
||||
if not NAME_RE.fullmatch(args.name):
|
||||
print(
|
||||
"name must match ^[A-Za-z0-9][A-Za-z0-9_.-]*$",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 2
|
||||
|
||||
root = git_root()
|
||||
if root is None:
|
||||
if args.dry_run or args.no_git_stage:
|
||||
root = Path.cwd()
|
||||
else:
|
||||
print("not inside a git repository; use --no-git-stage", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
files = planned_files(args.kind, args.name, args.multifile)
|
||||
base = root / KIND_LAYOUTS[args.kind]
|
||||
target_base = base / args.name if args.kind == "host" else base
|
||||
targets = [target_base / rel for rel in files]
|
||||
|
||||
if args.dry_run:
|
||||
print("dry run: no files will be created")
|
||||
for target in targets:
|
||||
print(target.relative_to(root))
|
||||
return 0
|
||||
|
||||
try:
|
||||
for rel_path, content in files.items():
|
||||
write_file(target_base / rel_path, content)
|
||||
except FileExistsError as err:
|
||||
print(err, file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if not args.no_git_stage:
|
||||
stage(targets, root)
|
||||
|
||||
for target in targets:
|
||||
print(target.relative_to(root))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
32
nix-modules/packages/boilerplate/default.nix
Normal file
32
nix-modules/packages/boilerplate/default.nix
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{ self, inputs, ... }:
|
||||
{
|
||||
perSystem =
|
||||
{ pkgs, lib, ... }:
|
||||
{
|
||||
packages.boilerplate = pkgs.stdenvNoCC.mkDerivation {
|
||||
pname = "boilerplate";
|
||||
version = "0.1.0";
|
||||
|
||||
src = ./.;
|
||||
|
||||
dontConfigure = true;
|
||||
dontBuild = true;
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
substituteInPlace boilerplate.py \
|
||||
--replace-fail '#!/usr/bin/env python3' '#!${pkgs.python3}/bin/python3'
|
||||
install -Dm755 boilerplate.py "$out/bin/boilerplate"
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
meta = {
|
||||
description = "Generate boilerplate Nix modules";
|
||||
license = lib.licenses.mit;
|
||||
mainProgram = "boilerplate";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
10
nix-modules/parts.nix
Normal file
10
nix-modules/parts.nix
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
config = {
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"x86_64-darwin"
|
||||
"aarch64-linux"
|
||||
"aarch64-darwin"
|
||||
];
|
||||
};
|
||||
}
|
||||
23
nix-modules/shell.nix
Normal file
23
nix-modules/shell.nix
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{ ... }:
|
||||
{
|
||||
perSystem =
|
||||
{ pkgs, self', ... }:
|
||||
{
|
||||
# An example devshell with some Rust and Nix tools
|
||||
devShells.default = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
glibc
|
||||
gcc
|
||||
gnumake
|
||||
clang
|
||||
clang-tools
|
||||
nixfmt
|
||||
nil
|
||||
alejandra
|
||||
self'.packages.boilerplate
|
||||
];
|
||||
nativeBuildInputs = [ pkgs.pkg-config ];
|
||||
env.CPATH = "${pkgs.glibc.dev}/include";
|
||||
};
|
||||
};
|
||||
}
|
||||
14
src/jalloc.c
Normal file
14
src/jalloc.c
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define HEAP_SIZE (1024 * 1024)
|
||||
|
||||
static uint8_t heap[HEAP_SIZE];
|
||||
static size_t heap_offset = 0;
|
||||
|
||||
void* jalloc(size_t size) {
|
||||
void* ptr = &heap[heap_offset];
|
||||
heap_offset += size;
|
||||
return ptr;
|
||||
}
|
||||
3
src/jalloc.h
Normal file
3
src/jalloc.h
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#include <stddef.h>
|
||||
|
||||
void* jalloc(size_t size);
|
||||
106
src/main.c
Normal file
106
src/main.c
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
#include "jalloc.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void test_jalloc(void) {
|
||||
int passed = 0, failed = 0;
|
||||
|
||||
// --- Test 1: Basic write/read ---
|
||||
{
|
||||
size_t size = 64;
|
||||
uint8_t *buf = (uint8_t *)jalloc(size);
|
||||
if (!buf) {
|
||||
printf("[FAIL] Test 1: jalloc returned NULL for size %zu\n", size);
|
||||
failed++;
|
||||
} else {
|
||||
for (size_t i = 0; i < size; i++) buf[i] = (uint8_t)i;
|
||||
int ok = 1;
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
if (buf[i] != (uint8_t)i) { ok = 0; break; }
|
||||
}
|
||||
printf("[%s] Test 1: sequential byte pattern (%zu bytes)\n",
|
||||
ok ? "PASS" : "FAIL", size);
|
||||
ok ? passed++ : failed++;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Test 2: Multiple independent allocations don't overlap ---
|
||||
{
|
||||
size_t size = 128;
|
||||
uint8_t *a = (uint8_t *)jalloc(size);
|
||||
uint8_t *b = (uint8_t *)jalloc(size);
|
||||
if (!a || !b) {
|
||||
printf("[FAIL] Test 2: jalloc returned NULL\n");
|
||||
failed++;
|
||||
} else {
|
||||
memset(a, 0xAA, size);
|
||||
memset(b, 0xBB, size);
|
||||
int ok = 1;
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
if (a[i] != 0xAA || b[i] != 0xBB) { ok = 0; break; }
|
||||
}
|
||||
printf("[%s] Test 2: two allocations don't overlap (%zu bytes each)\n",
|
||||
ok ? "PASS" : "FAIL", size);
|
||||
ok ? passed++ : failed++;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Test 3: Small allocation (1 byte) ---
|
||||
{
|
||||
uint8_t *buf = (uint8_t *)jalloc(1);
|
||||
if (!buf) {
|
||||
printf("[FAIL] Test 3: jalloc returned NULL for 1 byte\n");
|
||||
failed++;
|
||||
} else {
|
||||
*buf = 0x42;
|
||||
int ok = (*buf == 0x42);
|
||||
printf("[%s] Test 3: single byte allocation\n", ok ? "PASS" : "FAIL");
|
||||
ok ? passed++ : failed++;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Test 4: Large allocation ---
|
||||
{
|
||||
size_t size = 1024 * 1024; // 1 MiB
|
||||
uint8_t *buf = (uint8_t *)jalloc(size);
|
||||
if (!buf) {
|
||||
printf("[FAIL] Test 4: jalloc returned NULL for %zu bytes\n", size);
|
||||
failed++;
|
||||
} else {
|
||||
memset(buf, 0xCD, size);
|
||||
int ok = 1;
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
if (buf[i] != 0xCD) { ok = 0; break; }
|
||||
}
|
||||
printf("[%s] Test 4: large allocation (%zu bytes)\n",
|
||||
ok ? "PASS" : "FAIL", size);
|
||||
ok ? passed++ : failed++;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Test 5: String write/read ---
|
||||
{
|
||||
const char *msg = "Hello, jalloc!";
|
||||
size_t size = strlen(msg) + 1;
|
||||
char *buf = (char *)jalloc(size);
|
||||
if (!buf) {
|
||||
printf("[FAIL] Test 5: jalloc returned NULL\n");
|
||||
failed++;
|
||||
} else {
|
||||
strcpy(buf, msg);
|
||||
int ok = (strcmp(buf, msg) == 0);
|
||||
printf("[%s] Test 5: string integrity (\"%s\")\n",
|
||||
ok ? "PASS" : "FAIL", buf);
|
||||
ok ? passed++ : failed++;
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n=== Results: %d passed, %d failed ===\n", passed, failed);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
test_jalloc();
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue