Compare commits
26
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d954115852 | ||
|
|
2e1d1ffe6d | ||
|
|
59354f2b02 | ||
|
|
0a6f10bce2 | ||
|
|
8b007ba77b | ||
|
|
be398e4671 | ||
|
|
3c168b9484 | ||
|
|
f905b6e270 | ||
|
|
f1f027abfe | ||
|
|
0243da86f2 | ||
|
|
1803da420e | ||
|
|
2fb3a0d3ba | ||
|
|
4154640637 | ||
|
|
78641f78dd | ||
|
|
0e09b1db34 | ||
|
|
82a3bdf562 | ||
|
|
46cb80f809 | ||
|
|
bce4ccb754 | ||
|
|
7c7740fe90 | ||
|
|
a59ccd293d | ||
|
|
5514047eda | ||
|
|
810f9a66f6 | ||
|
|
3aa66c48af | ||
|
|
97d63eecda | ||
|
|
1d0ced8fd4 | ||
|
|
3ebead7663 |
@@ -18,6 +18,7 @@ jobs:
|
|||||||
- "brain"
|
- "brain"
|
||||||
- "jeeves"
|
- "jeeves"
|
||||||
- "rhapsody-in-green"
|
- "rhapsody-in-green"
|
||||||
|
- "portal-1"
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|||||||
Vendored
-3
@@ -10,7 +10,6 @@
|
|||||||
"aiounifi",
|
"aiounifi",
|
||||||
"alsa",
|
"alsa",
|
||||||
"apiclient",
|
"apiclient",
|
||||||
"apscheduler",
|
|
||||||
"archlinux",
|
"archlinux",
|
||||||
"ashift",
|
"ashift",
|
||||||
"asrouter",
|
"asrouter",
|
||||||
@@ -337,8 +336,6 @@
|
|||||||
"yubioath",
|
"yubioath",
|
||||||
"yzhang",
|
"yzhang",
|
||||||
"zeroconf",
|
"zeroconf",
|
||||||
"zerotier",
|
|
||||||
"zerotierone",
|
|
||||||
"zoxide",
|
"zoxide",
|
||||||
"zram",
|
"zram",
|
||||||
"zstd"
|
"zstd"
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ in
|
|||||||
"flakes"
|
"flakes"
|
||||||
"ca-derivations"
|
"ca-derivations"
|
||||||
];
|
];
|
||||||
|
system-features = lib.mkAfter [
|
||||||
|
"gccarch-x86-64-v2"
|
||||||
|
"gccarch-x86-64-v3"
|
||||||
|
];
|
||||||
warn-dirty = false;
|
warn-dirty = false;
|
||||||
flake-registry = ""; # disable global flake registries
|
flake-registry = ""; # disable global flake registries
|
||||||
connect-timeout = 10;
|
connect-timeout = 10;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
logDriver = "local";
|
logDriver = "local";
|
||||||
storageDriver = "overlay2";
|
storageDriver = "overlay2";
|
||||||
daemon.settings = {
|
daemon.settings = {
|
||||||
|
live-restore = false;
|
||||||
experimental = true;
|
experimental = true;
|
||||||
exec-opts = [ "native.cgroupdriver=systemd" ];
|
exec-opts = [ "native.cgroupdriver=systemd" ];
|
||||||
log-opts = {
|
log-opts = {
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
nixpkgs.hostPlatform = {
|
||||||
|
system = "x86_64-linux";
|
||||||
|
gcc = {
|
||||||
|
arch = "x86-64-v3";
|
||||||
|
tune = "generic";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -22,6 +22,12 @@ hourly = 0
|
|||||||
daily = 0
|
daily = 0
|
||||||
monthly = 0
|
monthly = 0
|
||||||
|
|
||||||
|
["root_pool/nix_build"]
|
||||||
|
15_min = 1
|
||||||
|
hourly = 0
|
||||||
|
daily = 0
|
||||||
|
monthly = 0
|
||||||
|
|
||||||
["root_pool/var"]
|
["root_pool/var"]
|
||||||
15_min = 8
|
15_min = 8
|
||||||
hourly = 24
|
hourly = 24
|
||||||
|
|||||||
Generated
+18
-18
@@ -28,11 +28,11 @@
|
|||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"dir": "pkgs/firefox-addons",
|
"dir": "pkgs/firefox-addons",
|
||||||
"lastModified": 1787025780,
|
"lastModified": 1788840136,
|
||||||
"narHash": "sha256-NhyLP9G4DFOn/7aYr7K/D7hWrzEGr5EgUBV+lpdmJ24=",
|
"narHash": "sha256-ej5jnQIfjbw4wwPzy8Y4ntG9F3asdF6YBkLqpYeGUxc=",
|
||||||
"owner": "rycee",
|
"owner": "rycee",
|
||||||
"repo": "nur-expressions",
|
"repo": "nur-expressions",
|
||||||
"rev": "5ad360b6d3cb0aa1b61f9cb27fef113ca9117c37",
|
"rev": "555b23e68256c5abfb8a85a385231830d1d7ad1f",
|
||||||
"type": "gitlab"
|
"type": "gitlab"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -49,11 +49,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1786999651,
|
"lastModified": 1788651960,
|
||||||
"narHash": "sha256-MTGMFlLDTklsXhCp4r5GXB4VAVadPdalXLvUjd/K7h0=",
|
"narHash": "sha256-v9wJd32eZ2bvhBzVOd7TIjLQd011P7nwOhjKtWlci5I=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "353742587cbaf079b3caee743115d037bc51fea6",
|
"rev": "2c0350c759688177331b8f5242311fae8877bdb3",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -67,11 +67,11 @@
|
|||||||
"nixpkgs": "nixpkgs"
|
"nixpkgs": "nixpkgs"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1786867632,
|
"lastModified": 1788860136,
|
||||||
"narHash": "sha256-ez+ubZlA1RtdjCB18a6zJ9M4u8qoPDy08EcnsW5M3Xw=",
|
"narHash": "sha256-MhPMOFV4pVkygWEbQ8t1De/uQ9cWF1u++tRe2L5tG48=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixos-hardware",
|
"repo": "nixos-hardware",
|
||||||
"rev": "ff17823245ab9ff7bcae6acf950bd89cba82c38c",
|
"rev": "62173785b9a18c78b4a15aca2623d02bceb9d077",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -96,11 +96,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs-master": {
|
"nixpkgs-master": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787081018,
|
"lastModified": 1788892992,
|
||||||
"narHash": "sha256-K0uwZBtZsbBigHAMQW7YWti3gPe6a5ct5bcOw5F+Q9Y=",
|
"narHash": "sha256-cIMFh9gyU4/aLeB3JCcsWM3tTAvD9pAq9Smr1Wa8aIU=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "cacac5ac351a010599d9f9d106acfed25a8e4c77",
|
"rev": "dff6994123e257ec9901c271bc2b52e64d7c8f05",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -128,11 +128,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787001381,
|
"lastModified": 1788752844,
|
||||||
"narHash": "sha256-Ue1Yo8gfHdD4TMtNewhA4tkSYeFqXThju0nCyJc3ALo=",
|
"narHash": "sha256-VaWGJ6+cIYN2erfSecbRV+4ljI185Ty2wUrXyvQbgOw=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "ec2d622de0773551768cf98f3fc50cbcc003b9c5",
|
"rev": "dc5d91f840324650bac8c379428c7037a416959a",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -162,11 +162,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1786629091,
|
"lastModified": 1788337237,
|
||||||
"narHash": "sha256-gkig4nPi1CWc4Z50GBsjE4ygSE7hMpl/TwID2an2Cck=",
|
"narHash": "sha256-gkSH8VUtCo6hnysNmb9DbTuDepH2t5pv+QWjP75xKAk=",
|
||||||
"owner": "Mic92",
|
"owner": "Mic92",
|
||||||
"repo": "sops-nix",
|
"repo": "sops-nix",
|
||||||
"rev": "a8627b21b9107c5711c96b84f32a9a4b3d45295f",
|
"rev": "fbf759290e0cb0a98dfc813a4eb7d53ad1dacb57",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -15,12 +15,14 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
test-exclusions = import ./test-exclusions.nix;
|
||||||
|
x86-64-v3-workarounds = import ./x86-64-v3-workarounds.nix;
|
||||||
|
|
||||||
python-env = final: _prev: {
|
python-env = final: _prev: {
|
||||||
my_python = final.python314.withPackages (
|
my_python = final.python314.withPackages (
|
||||||
ps: with ps; [
|
ps: with ps; [
|
||||||
alembic
|
alembic
|
||||||
apprise
|
apprise
|
||||||
apscheduler
|
|
||||||
fastapi
|
fastapi
|
||||||
fastapi-cli
|
fastapi-cli
|
||||||
httpx
|
httpx
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
# Test exclusions for the locally rebuilt x86-64-v3 package set.
|
||||||
|
#
|
||||||
|
# Selecting x86-64-v3 changes every affected derivation, so the normal
|
||||||
|
# nixpkgs binary cache cannot be used and upstream test suites run locally.
|
||||||
|
# The jeeves builder uses /tmp/nix-builds so filesystem tests run on tmpfs
|
||||||
|
# instead of ZFS with normalization=formD and utf8only=on; those tests remain
|
||||||
|
# enabled. The remaining workarounds cover UDP readiness, resource-sensitive
|
||||||
|
# parser and nested-worker races, and mismatched timeout clocks, plus
|
||||||
|
# architecture-dependent floating-point differences whose risk we accept for
|
||||||
|
# our workloads. Keep these exceptions visible until their causes are fixed.
|
||||||
|
_final: prev: {
|
||||||
|
gnutls = prev.gnutls.overrideAttrs (old: {
|
||||||
|
# This test uses a fixed four-second sleep instead of checking UDP
|
||||||
|
# readiness; the client saw no listener in the x86-64-v3 build.
|
||||||
|
postPatch = (old.postPatch or "") + ''
|
||||||
|
sed '2iexit 77' -i tests/serv-udp.sh
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
|
||||||
|
onnxruntime = prev.onnxruntime.overrideAttrs (old: {
|
||||||
|
# OpenVINO uses a different QuantizeLinear formulation. x86-64-v3 moves
|
||||||
|
# these INT8 results by one quantization unit; we accept that inference-
|
||||||
|
# precision risk for our workloads.
|
||||||
|
env = (old.env or { }) // {
|
||||||
|
GTEST_FILTER = "*:-QuantizeLinearOpTest.Int8:QuantizeLinearOpTest.OVEP_Int8_NegativeZeroPoint:QuantizeLinearOpTest.OVEP_Int8_PositiveZeroPoint";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
prometheus = prev.prometheus.overrideAttrs (
|
||||||
|
old:
|
||||||
|
let
|
||||||
|
assets = old.passthru.assets.overrideAttrs (assetsOld: {
|
||||||
|
# CodeMirror's bounded synchronous parser can return an incomplete tree
|
||||||
|
# when these cases run on a heavily loaded builder.
|
||||||
|
postPatch = (assetsOld.postPatch or "") + ''
|
||||||
|
substituteInPlace module/codemirror-promql/src/complete/hybrid.test.ts \
|
||||||
|
--replace-fail "it(value.title, () => {" \
|
||||||
|
"(value.title === 'autocomplete topk params 2' ? it.skip : it)(value.title, () => {"
|
||||||
|
substituteInPlace module/codemirror-promql/src/parser/vector.test.ts \
|
||||||
|
--replace-fail "it(value.binaryExpr, () => {" \
|
||||||
|
"(value.binaryExpr === 'foo * on(test,blub) bar' ? it.skip : it)(value.binaryExpr, () => {"
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
in
|
||||||
|
{
|
||||||
|
postPatch = builtins.replaceStrings [ "${old.passthru.assets}" ] [ "${assets}" ] (
|
||||||
|
builtins.unsafeDiscardStringContext old.postPatch
|
||||||
|
);
|
||||||
|
passthru = old.passthru // {
|
||||||
|
inherit assets;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
pythonPackagesExtensions = prev.pythonPackagesExtensions ++ [
|
||||||
|
(_pythonFinal: pythonPrev: {
|
||||||
|
backrefs = pythonPrev.backrefs.overridePythonAttrs (old: {
|
||||||
|
# regex measures its timeout in process CPU time, while this test used
|
||||||
|
# wall time and could miss the timeout when a busy builder descheduled it.
|
||||||
|
postPatch = (old.postPatch or "") + ''
|
||||||
|
substituteInPlace tests/test_bregex.py \
|
||||||
|
--replace-fail "time.time()" "time.process_time()"
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
|
||||||
|
pytest-xdist = pythonPrev.pytest-xdist.overridePythonAttrs (old: {
|
||||||
|
# The suite exercises its own worker pools. Run the outer suite with one
|
||||||
|
# worker and allow inner workers more time on heavily loaded builders.
|
||||||
|
postPatch = (old.postPatch or "") + ''
|
||||||
|
substituteInPlace testing/test_remote.py \
|
||||||
|
--replace-fail "WAIT_TIMEOUT = 10.0" "WAIT_TIMEOUT = 60.0"
|
||||||
|
'';
|
||||||
|
preCheck = builtins.replaceStrings [ "--numprocesses=$NIX_BUILD_CORES" ] [ "--numprocesses=1" ] (
|
||||||
|
old.preCheck or ""
|
||||||
|
);
|
||||||
|
# This test deliberately crashes workers past the restart limit and
|
||||||
|
# races while checking which replacement message was emitted.
|
||||||
|
disabledTests = (old.disabledTests or [ ]) ++ [
|
||||||
|
"test_max_worker_restart_tests_queued"
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
jupyter-server = pythonPrev.jupyter-server.overridePythonAttrs (old: {
|
||||||
|
# The kernel reply arrived after the one-second outer deadline when the
|
||||||
|
# builder was heavily loaded. Keep the regression test but allow it the
|
||||||
|
# same margin as the other resource-sensitive tests.
|
||||||
|
postPatch = (old.postPatch or "") + ''
|
||||||
|
substituteInPlace tests/services/kernels/test_connection.py \
|
||||||
|
--replace-fail \
|
||||||
|
"await asyncio.wait_for(asyncio.wrap_future(conn2.request_kernel_info()), timeout=1.0)" \
|
||||||
|
"await asyncio.wait_for(asyncio.wrap_future(conn2.request_kernel_info()), timeout=10.0)"
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
|
||||||
|
scipy = pythonPrev.scipy.overridePythonAttrs (old: {
|
||||||
|
# x86-64-v3 FFT implementations produce rounding differences outside
|
||||||
|
# these tests' strict tolerances. We accept the numerical-precision
|
||||||
|
# risk for our workloads.
|
||||||
|
disabledTests = (old.disabledTests or [ ]) ++ [
|
||||||
|
"test_roundtrip_float32"
|
||||||
|
"test_roundtrip_scaling"
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
sentry-sdk = pythonPrev.sentry-sdk.overridePythonAttrs (old: {
|
||||||
|
# This test globally mocks threading.current_thread while another
|
||||||
|
# thread is running. On Python 3.14, Thread.join can race with that
|
||||||
|
# mock and exhaust its single side effect before the worker removes it.
|
||||||
|
disabledTests = (old.disabledTests or [ ]) ++ [
|
||||||
|
"test_get_current_thread_meta_main_thread"
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
torchcodec = pythonPrev.torchcodec.overridePythonAttrs (old: {
|
||||||
|
# For these 8 kHz MP3 cases, the x86-64-v3 API and CLI codec paths
|
||||||
|
# differ in 0.8% of decoded samples. Retain the original tolerance for
|
||||||
|
# 99% of samples and accept the localized audio-precision risk.
|
||||||
|
postPatch = (old.postPatch or "") + ''
|
||||||
|
substituteInPlace test/test_encoders.py \
|
||||||
|
--replace-fail \
|
||||||
|
'if sys.platform == "darwin":' \
|
||||||
|
'if sys.platform == "darwin" or (
|
||||||
|
format == "mp3"
|
||||||
|
and sample_rate == 8_000
|
||||||
|
and asset is SINE_MONO_S32
|
||||||
|
and bit_rate in (None, 0)
|
||||||
|
and num_channels in (None, 1)
|
||||||
|
):'
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Compatibility fixes for packages rebuilt with x86-64-v3.
|
||||||
|
#
|
||||||
|
# The v3 baseline enables instructions that expose source assumptions hidden
|
||||||
|
# by the generic x86-64 build. Keep compile fixes here, separate from test
|
||||||
|
# exclusions, until upstream or nixpkgs incorporates them.
|
||||||
|
_final: prev:
|
||||||
|
prev.lib.optionalAttrs ((prev.stdenv.hostPlatform.gcc.arch or null) == "x86-64-v3") {
|
||||||
|
deno =
|
||||||
|
let
|
||||||
|
librusty_v8 = prev.deno.passthru.librusty_v8.overrideAttrs (old: {
|
||||||
|
# Clang prohibits including its internal BMI2 header directly. The
|
||||||
|
# public umbrella supplies the same intrinsics with the required setup.
|
||||||
|
postPatch = (old.postPatch or "") + ''
|
||||||
|
substituteInPlace third_party/abseil-cpp/absl/container/internal/raw_hash_set.h \
|
||||||
|
--replace-fail "#include <bmi2intrin.h>" "#include <immintrin.h>"
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
in
|
||||||
|
prev.deno.override { inherit librusty_v8; };
|
||||||
|
}
|
||||||
@@ -11,7 +11,6 @@ license = "MIT"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"alembic",
|
"alembic",
|
||||||
"apprise",
|
"apprise",
|
||||||
"apscheduler",
|
|
||||||
"beautifulsoup4",
|
"beautifulsoup4",
|
||||||
"bm25s",
|
"bm25s",
|
||||||
"ebooklib",
|
"ebooklib",
|
||||||
@@ -20,7 +19,6 @@ dependencies = [
|
|||||||
"httpx",
|
"httpx",
|
||||||
"jinja2",
|
"jinja2",
|
||||||
"pgvector",
|
"pgvector",
|
||||||
"polars",
|
|
||||||
"psycopg[binary]",
|
"psycopg[binary]",
|
||||||
"pydantic",
|
"pydantic",
|
||||||
"pydantic-settings",
|
"pydantic-settings",
|
||||||
|
|||||||
@@ -176,6 +176,21 @@ def create_zfs_datasets() -> None:
|
|||||||
run_output(("zfs", "create", "root_pool/home"))
|
run_output(("zfs", "create", "root_pool/home"))
|
||||||
run_output(("zfs", "create", "-o", "reservation=1G", "root_pool/var"))
|
run_output(("zfs", "create", "-o", "reservation=1G", "root_pool/var"))
|
||||||
run_output(("zfs", "create", "-o", "compression=zstd-9", "-o", "reservation=10G", "root_pool/nix"))
|
run_output(("zfs", "create", "-o", "compression=zstd-9", "-o", "reservation=10G", "root_pool/nix"))
|
||||||
|
run_output(
|
||||||
|
(
|
||||||
|
"zfs",
|
||||||
|
"create",
|
||||||
|
"-o",
|
||||||
|
"sync=disabled",
|
||||||
|
"-o",
|
||||||
|
"redundant_metadata=some",
|
||||||
|
"-o",
|
||||||
|
"normalization=none",
|
||||||
|
"-o",
|
||||||
|
"utf8only=off",
|
||||||
|
"root_pool/nix_build",
|
||||||
|
)
|
||||||
|
)
|
||||||
datasets = run_output(("zfs", "list", "-o", "name"))
|
datasets = run_output(("zfs", "list", "-o", "name"))
|
||||||
|
|
||||||
expected_datasets = {
|
expected_datasets = {
|
||||||
@@ -183,6 +198,7 @@ def create_zfs_datasets() -> None:
|
|||||||
"root_pool/home",
|
"root_pool/home",
|
||||||
"root_pool/var",
|
"root_pool/var",
|
||||||
"root_pool/nix",
|
"root_pool/nix",
|
||||||
|
"root_pool/nix_build",
|
||||||
}
|
}
|
||||||
missing_datasets = expected_datasets.difference(datasets.splitlines())
|
missing_datasets = expected_datasets.difference(datasets.splitlines())
|
||||||
if missing_datasets:
|
if missing_datasets:
|
||||||
@@ -248,6 +264,7 @@ def create_nix_hardware_file(mnt_dir: str, disks: Sequence[str], encrypt: str |
|
|||||||
' "/home" = {\n device = "root_pool/home";\n fsType = "zfs";\n };\n\n'
|
' "/home" = {\n device = "root_pool/home";\n fsType = "zfs";\n };\n\n'
|
||||||
' "/var" = {\n device = "root_pool/var";\n fsType = "zfs";\n };\n\n'
|
' "/var" = {\n device = "root_pool/var";\n fsType = "zfs";\n };\n\n'
|
||||||
' "/nix" = {\n device = "root_pool/nix";\n fsType = "zfs";\n };\n\n'
|
' "/nix" = {\n device = "root_pool/nix";\n fsType = "zfs";\n };\n\n'
|
||||||
|
' "/nix/var/nix/builds" = {\n device = "root_pool/nix_build";\n fsType = "zfs";\n };\n\n'
|
||||||
' "/boot" = {\n'
|
' "/boot" = {\n'
|
||||||
f' device = "/dev/disk/by-uuid/{get_boot_drive_id(disks[0])}";\n'
|
f' device = "/dev/disk/by-uuid/{get_boot_drive_id(disks[0])}";\n'
|
||||||
' fsType = "vfat";\n options = [\n "fmask=0077"\n'
|
' fsType = "vfat";\n options = [\n "fmask=0077"\n'
|
||||||
@@ -270,6 +287,7 @@ def install_nixos(mnt_dir: str, disks: Sequence[str], encrypt: str | None) -> No
|
|||||||
run_output(("mount", "-o", "X-mount.mkdir", "-t", "zfs", "root_pool/home", f"{mnt_dir}/home"))
|
run_output(("mount", "-o", "X-mount.mkdir", "-t", "zfs", "root_pool/home", f"{mnt_dir}/home"))
|
||||||
run_output(("mount", "-o", "X-mount.mkdir", "-t", "zfs", "root_pool/var", f"{mnt_dir}/var"))
|
run_output(("mount", "-o", "X-mount.mkdir", "-t", "zfs", "root_pool/var", f"{mnt_dir}/var"))
|
||||||
run_output(("mount", "-o", "X-mount.mkdir", "-t", "zfs", "root_pool/nix", f"{mnt_dir}/nix"))
|
run_output(("mount", "-o", "X-mount.mkdir", "-t", "zfs", "root_pool/nix", f"{mnt_dir}/nix"))
|
||||||
|
run_output(("mount", "-o", "X-mount.mkdir", "-t", "zfs", "root_pool/nix_build", f"{mnt_dir}/nix/var/nix/builds"))
|
||||||
|
|
||||||
for disk in disks:
|
for disk in disks:
|
||||||
run_output(("mkfs.vfat", "-n", "EFI", f"{disk}-part1"))
|
run_output(("mkfs.vfat", "-n", "EFI", f"{disk}-part1"))
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
"""Van weather service - fetches weather with masked GPS location."""
|
|
||||||
@@ -1,293 +0,0 @@
|
|||||||
"""Van weather service - fetches weather with masked GPS for privacy."""
|
|
||||||
|
|
||||||
import logging
|
|
||||||
from datetime import UTC, datetime
|
|
||||||
from typing import Annotated, Any
|
|
||||||
|
|
||||||
import httpx
|
|
||||||
import typer
|
|
||||||
from apscheduler.schedulers.blocking import BlockingScheduler
|
|
||||||
from tenacity import before_sleep_log, retry, stop_after_attempt, wait_fixed
|
|
||||||
|
|
||||||
from python.common import configure_logger
|
|
||||||
from python.van_weather.models import Config, DailyForecast, HourlyForecast, Weather
|
|
||||||
|
|
||||||
# Map Pirate Weather icons to Home Assistant conditions
|
|
||||||
CONDITION_MAP = {
|
|
||||||
"clear-day": "sunny",
|
|
||||||
"clear-night": "clear-night",
|
|
||||||
"rain": "rainy",
|
|
||||||
"snow": "snowy",
|
|
||||||
"sleet": "snowy-rainy",
|
|
||||||
"wind": "windy",
|
|
||||||
"fog": "fog",
|
|
||||||
"cloudy": "cloudy",
|
|
||||||
"partly-cloudy-day": "partlycloudy",
|
|
||||||
"partly-cloudy-night": "partlycloudy",
|
|
||||||
}
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
@retry(
|
|
||||||
stop=stop_after_attempt(3),
|
|
||||||
wait=wait_fixed(5),
|
|
||||||
before_sleep=before_sleep_log(logger, logging.WARNING),
|
|
||||||
reraise=True,
|
|
||||||
)
|
|
||||||
def get_ha_state(url: str, token: str, entity_id: str) -> float:
|
|
||||||
"""Get numeric state from Home Asasistant entity."""
|
|
||||||
response = httpx.get(
|
|
||||||
f"{url}/api/states/{entity_id}",
|
|
||||||
headers={"Authorization": f"Bearer {token}"},
|
|
||||||
timeout=30,
|
|
||||||
)
|
|
||||||
response.raise_for_status()
|
|
||||||
state = response.json()["state"]
|
|
||||||
if state in ("unavailable", "unknown"):
|
|
||||||
error = f"{entity_id} is {state}"
|
|
||||||
raise ValueError(error)
|
|
||||||
return float(state)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_daily_forecast(data: dict[str, dict[str, Any]]) -> list[DailyForecast]:
|
|
||||||
"""Parse daily forecast from Pirate Weather API."""
|
|
||||||
daily = data.get("daily", {}).get("data", [])
|
|
||||||
daily_forecasts = []
|
|
||||||
for day in daily[:8]: # Up to 8 days
|
|
||||||
time_stamp = day.get("time")
|
|
||||||
if time_stamp:
|
|
||||||
date_time = datetime.fromtimestamp(time_stamp, tz=UTC).isoformat()
|
|
||||||
daily_forecasts.append(
|
|
||||||
DailyForecast(
|
|
||||||
date_time=date_time,
|
|
||||||
condition=CONDITION_MAP.get(day.get("icon", ""), "cloudy"),
|
|
||||||
temperature=day.get("temperatureHigh"),
|
|
||||||
templow=day.get("temperatureLow"),
|
|
||||||
precipitation_probability=day.get("precipProbability"),
|
|
||||||
moon_phase=day.get("moonPhase"),
|
|
||||||
wind_gust=day.get("windGust"),
|
|
||||||
cloud_cover=day.get("cloudCover"),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return daily_forecasts
|
|
||||||
|
|
||||||
|
|
||||||
def parse_hourly_forecast(data: dict[str, dict[str, Any]]) -> list[HourlyForecast]:
|
|
||||||
"""Parse hourly forecast from Pirate Weather API."""
|
|
||||||
hourly = data.get("hourly", {}).get("data", [])
|
|
||||||
hourly_forecasts = []
|
|
||||||
for hour in hourly[:48]: # Up to 48 hours
|
|
||||||
time_stamp = hour.get("time")
|
|
||||||
if time_stamp:
|
|
||||||
date_time = datetime.fromtimestamp(time_stamp, tz=UTC).isoformat()
|
|
||||||
hourly_forecasts.append(
|
|
||||||
HourlyForecast(
|
|
||||||
date_time=date_time,
|
|
||||||
condition=CONDITION_MAP.get(hour.get("icon", ""), "cloudy"),
|
|
||||||
temperature=hour.get("temperature"),
|
|
||||||
precipitation_probability=hour.get("precipProbability"),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return hourly_forecasts
|
|
||||||
|
|
||||||
|
|
||||||
@retry(
|
|
||||||
stop=stop_after_attempt(3),
|
|
||||||
wait=wait_fixed(5),
|
|
||||||
before_sleep=before_sleep_log(logger, logging.WARNING),
|
|
||||||
reraise=True,
|
|
||||||
)
|
|
||||||
def fetch_weather(api_key: str, lat: float, lon: float) -> Weather:
|
|
||||||
"""Fetch weather from Pirate Weather API."""
|
|
||||||
url = f"https://api.pirateweather.net/forecast/{api_key}/{lat},{lon}"
|
|
||||||
response = httpx.get(url, params={"units": "us"}, timeout=30)
|
|
||||||
response.raise_for_status()
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
daily_forecasts = parse_daily_forecast(data)
|
|
||||||
hourly_forecasts = parse_hourly_forecast(data)
|
|
||||||
|
|
||||||
current = data.get("currently", {})
|
|
||||||
icon = current.get("icon", "")
|
|
||||||
return Weather(
|
|
||||||
temperature=current.get("temperature"),
|
|
||||||
feels_like=current.get("apparentTemperature"),
|
|
||||||
humidity=current.get("humidity"),
|
|
||||||
wind_speed=current.get("windSpeed"),
|
|
||||||
wind_bearing=current.get("windBearing"),
|
|
||||||
condition=CONDITION_MAP.get(icon, "cloudy"),
|
|
||||||
summary=current.get("summary"),
|
|
||||||
pressure=current.get("pressure"),
|
|
||||||
visibility=current.get("visibility"),
|
|
||||||
uv_index=current.get("uvIndex"),
|
|
||||||
ozone=current.get("ozone"),
|
|
||||||
nearest_storm_distance=current.get("nearestStormDistance"),
|
|
||||||
nearest_storm_bearing=current.get("nearestStormBearing"),
|
|
||||||
precip_probability=current.get("precipProbability"),
|
|
||||||
cloud_cover=current.get("cloudCover"),
|
|
||||||
daily_forecasts=daily_forecasts,
|
|
||||||
hourly_forecasts=hourly_forecasts,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@retry(
|
|
||||||
stop=stop_after_attempt(3),
|
|
||||||
wait=wait_fixed(5),
|
|
||||||
before_sleep=before_sleep_log(logger, logging.WARNING),
|
|
||||||
reraise=True,
|
|
||||||
)
|
|
||||||
def post_to_ha(url: str, token: str, weather: Weather) -> None:
|
|
||||||
"""Post weather data to Home Assistant as sensor entities."""
|
|
||||||
headers = {"Authorization": f"Bearer {token}"}
|
|
||||||
|
|
||||||
# Post current weather as individual sensors
|
|
||||||
sensors = {
|
|
||||||
"sensor.van_weather_condition": {
|
|
||||||
"state": weather.condition or "unknown",
|
|
||||||
"attributes": {"friendly_name": "Van Weather Condition"},
|
|
||||||
},
|
|
||||||
"sensor.van_weather_temperature": {
|
|
||||||
"state": weather.temperature,
|
|
||||||
"attributes": {"unit_of_measurement": "°F", "device_class": "temperature"},
|
|
||||||
},
|
|
||||||
"sensor.van_weather_apparent_temperature": {
|
|
||||||
"state": weather.feels_like,
|
|
||||||
"attributes": {"unit_of_measurement": "°F", "device_class": "temperature"},
|
|
||||||
},
|
|
||||||
"sensor.van_weather_humidity": {
|
|
||||||
"state": int((weather.humidity or 0) * 100),
|
|
||||||
"attributes": {"unit_of_measurement": "%", "device_class": "humidity"},
|
|
||||||
},
|
|
||||||
"sensor.van_weather_pressure": {
|
|
||||||
"state": weather.pressure,
|
|
||||||
"attributes": {"unit_of_measurement": "mbar", "device_class": "pressure"},
|
|
||||||
},
|
|
||||||
"sensor.van_weather_wind_speed": {
|
|
||||||
"state": weather.wind_speed,
|
|
||||||
"attributes": {"unit_of_measurement": "mph", "device_class": "wind_speed"},
|
|
||||||
},
|
|
||||||
"sensor.van_weather_wind_bearing": {
|
|
||||||
"state": weather.wind_bearing,
|
|
||||||
"attributes": {"unit_of_measurement": "°"},
|
|
||||||
},
|
|
||||||
"sensor.van_weather_visibility": {
|
|
||||||
"state": weather.visibility,
|
|
||||||
"attributes": {"unit_of_measurement": "mi"},
|
|
||||||
},
|
|
||||||
"sensor.van_weather_uv_index": {
|
|
||||||
"state": weather.uv_index,
|
|
||||||
"attributes": {"friendly_name": "Van Weather UV Index", "icon": "mdi:sun-wireless"},
|
|
||||||
},
|
|
||||||
"sensor.van_weather_ozone": {
|
|
||||||
"state": weather.ozone,
|
|
||||||
"attributes": {"unit_of_measurement": "DU", "icon": "mdi:earth"},
|
|
||||||
},
|
|
||||||
"sensor.van_weather_nearest_storm_distance": {
|
|
||||||
"state": weather.nearest_storm_distance,
|
|
||||||
"attributes": {"unit_of_measurement": "mi", "icon": "mdi:weather-lightning"},
|
|
||||||
},
|
|
||||||
"sensor.van_weather_nearest_storm_bearing": {
|
|
||||||
"state": weather.nearest_storm_bearing,
|
|
||||||
"attributes": {"unit_of_measurement": "°", "icon": "mdi:weather-lightning"},
|
|
||||||
},
|
|
||||||
"sensor.van_weather_precip_probability": {
|
|
||||||
"state": int((weather.precip_probability or 0) * 100),
|
|
||||||
"attributes": {"unit_of_measurement": "%", "icon": "mdi:weather-rainy"},
|
|
||||||
},
|
|
||||||
"sensor.van_weather_cloud_cover": {
|
|
||||||
"state": int((weather.cloud_cover or 0) * 100),
|
|
||||||
"attributes": {"unit_of_measurement": "%", "icon": "mdi:weather-cloudy"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for entity_id, data in sensors.items():
|
|
||||||
if data["state"] is not None:
|
|
||||||
response = httpx.post(f"{url}/api/states/{entity_id}", headers=headers, json=data, timeout=30)
|
|
||||||
response.raise_for_status()
|
|
||||||
|
|
||||||
# Post daily forecast as JSON attribute sensor
|
|
||||||
daily_forecast = [
|
|
||||||
{
|
|
||||||
"datetime": daily_forecast.date_time.isoformat(),
|
|
||||||
"condition": daily_forecast.condition,
|
|
||||||
"temperature": daily_forecast.temperature,
|
|
||||||
"templow": daily_forecast.templow,
|
|
||||||
"precipitation_probability": int((daily_forecast.precipitation_probability or 0) * 100),
|
|
||||||
}
|
|
||||||
for daily_forecast in weather.daily_forecasts
|
|
||||||
]
|
|
||||||
|
|
||||||
response = httpx.post(
|
|
||||||
f"{url}/api/states/sensor.van_weather_forecast_daily",
|
|
||||||
headers=headers,
|
|
||||||
json={"state": len(daily_forecast), "attributes": {"forecast": daily_forecast}},
|
|
||||||
timeout=30,
|
|
||||||
)
|
|
||||||
response.raise_for_status()
|
|
||||||
|
|
||||||
# Post hourly forecast as JSON attribute sensor
|
|
||||||
hourly_forecast = [
|
|
||||||
{
|
|
||||||
"datetime": hourly_forecast.date_time.isoformat(),
|
|
||||||
"condition": hourly_forecast.condition,
|
|
||||||
"temperature": hourly_forecast.temperature,
|
|
||||||
"precipitation_probability": int((hourly_forecast.precipitation_probability or 0) * 100),
|
|
||||||
}
|
|
||||||
for hourly_forecast in weather.hourly_forecasts
|
|
||||||
]
|
|
||||||
|
|
||||||
response = httpx.post(
|
|
||||||
f"{url}/api/states/sensor.van_weather_forecast_hourly",
|
|
||||||
headers=headers,
|
|
||||||
json={"state": len(hourly_forecast), "attributes": {"forecast": hourly_forecast}},
|
|
||||||
timeout=30,
|
|
||||||
)
|
|
||||||
response.raise_for_status()
|
|
||||||
|
|
||||||
|
|
||||||
def update_weather(config: Config) -> None:
|
|
||||||
"""Fetch weather using last-known location, post to HA."""
|
|
||||||
lat = get_ha_state(config.ha_url, config.ha_token, config.lat_entity)
|
|
||||||
lon = get_ha_state(config.ha_url, config.ha_token, config.lon_entity)
|
|
||||||
|
|
||||||
masked_lat = round(lat, config.mask_decimals)
|
|
||||||
masked_lon = round(lon, config.mask_decimals)
|
|
||||||
|
|
||||||
logger.info(f"Masked location: {masked_lat}, {masked_lon}")
|
|
||||||
|
|
||||||
weather = fetch_weather(config.pirate_weather_api_key, masked_lat, masked_lon)
|
|
||||||
logger.info(f"Weather: {weather.temperature}°F, {weather.condition}")
|
|
||||||
|
|
||||||
post_to_ha(config.ha_url, config.ha_token, weather)
|
|
||||||
logger.info("Posted weather to HA")
|
|
||||||
|
|
||||||
|
|
||||||
def main(
|
|
||||||
ha_url: Annotated[str, typer.Option(envvar="HA_URL")],
|
|
||||||
ha_token: Annotated[str, typer.Option(envvar="HA_TOKEN")],
|
|
||||||
api_key: Annotated[str, typer.Option(envvar="PIRATE_WEATHER_API_KEY")],
|
|
||||||
interval: Annotated[int, typer.Option(help="Poll interval in seconds")] = 900,
|
|
||||||
log_level: Annotated[str, typer.Option()] = "INFO",
|
|
||||||
) -> None:
|
|
||||||
"""Fetch weather for van using masked GPS location."""
|
|
||||||
configure_logger(log_level)
|
|
||||||
|
|
||||||
config = Config(ha_url=ha_url, ha_token=ha_token, pirate_weather_api_key=api_key)
|
|
||||||
|
|
||||||
logger.info(f"Starting van weather service, polling every {interval}s")
|
|
||||||
|
|
||||||
scheduler = BlockingScheduler()
|
|
||||||
scheduler.add_job(
|
|
||||||
update_weather,
|
|
||||||
"interval",
|
|
||||||
seconds=interval,
|
|
||||||
args=[config],
|
|
||||||
next_run_time=datetime.now(UTC),
|
|
||||||
)
|
|
||||||
scheduler.start()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
typer.run(main)
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
"""Models for van weather service."""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from datetime import datetime # noqa: TC003 This is required for pydantic
|
|
||||||
|
|
||||||
from pydantic import BaseModel, field_serializer
|
|
||||||
|
|
||||||
|
|
||||||
class Config(BaseModel):
|
|
||||||
"""Service configuration."""
|
|
||||||
|
|
||||||
ha_url: str
|
|
||||||
ha_token: str
|
|
||||||
pirate_weather_api_key: str
|
|
||||||
lat_entity: str = "sensor.van_last_known_latitude"
|
|
||||||
lon_entity: str = "sensor.van_last_known_longitude"
|
|
||||||
mask_decimals: int = 1 # ~11km accuracy
|
|
||||||
|
|
||||||
|
|
||||||
class DailyForecast(BaseModel):
|
|
||||||
"""Daily forecast entry."""
|
|
||||||
|
|
||||||
date_time: datetime
|
|
||||||
condition: str | None = None
|
|
||||||
temperature: float | None = None # High
|
|
||||||
templow: float | None = None # Low
|
|
||||||
precipitation_probability: float | None = None
|
|
||||||
moon_phase: float | None = None
|
|
||||||
wind_gust: float | None = None
|
|
||||||
cloud_cover: float | None = None
|
|
||||||
|
|
||||||
@field_serializer("date_time")
|
|
||||||
def serialize_date_time(self, date_time: datetime) -> str:
|
|
||||||
"""Serialize datetime to ISO format."""
|
|
||||||
return date_time.isoformat()
|
|
||||||
|
|
||||||
|
|
||||||
class HourlyForecast(BaseModel):
|
|
||||||
"""Hourly forecast entry."""
|
|
||||||
|
|
||||||
date_time: datetime
|
|
||||||
condition: str | None = None
|
|
||||||
temperature: float | None = None
|
|
||||||
precipitation_probability: float | None = None
|
|
||||||
|
|
||||||
@field_serializer("date_time")
|
|
||||||
def serialize_date_time(self, date_time: datetime) -> str:
|
|
||||||
"""Serialize datetime to ISO format."""
|
|
||||||
return date_time.isoformat()
|
|
||||||
|
|
||||||
|
|
||||||
class Weather(BaseModel):
|
|
||||||
"""Weather data from Pirate Weather."""
|
|
||||||
|
|
||||||
temperature: float | None = None
|
|
||||||
feels_like: float | None = None
|
|
||||||
humidity: float | None = None
|
|
||||||
wind_speed: float | None = None
|
|
||||||
wind_bearing: float | None = None
|
|
||||||
condition: str | None = None
|
|
||||||
summary: str | None = None
|
|
||||||
pressure: float | None = None
|
|
||||||
visibility: float | None = None
|
|
||||||
uv_index: float | None = None
|
|
||||||
ozone: float | None = None
|
|
||||||
nearest_storm_distance: float | None = None
|
|
||||||
nearest_storm_bearing: float | None = None
|
|
||||||
precip_probability: float | None = None
|
|
||||||
cloud_cover: float | None = None
|
|
||||||
daily_forecasts: list[DailyForecast] = []
|
|
||||||
hourly_forecasts: list[HourlyForecast] = []
|
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
imports = [
|
imports = [
|
||||||
"${inputs.self}/users/math"
|
"${inputs.self}/users/math"
|
||||||
"${inputs.self}/users/richie"
|
"${inputs.self}/users/richie"
|
||||||
"${inputs.self}/users/steve"
|
|
||||||
"${inputs.self}/common/global"
|
"${inputs.self}/common/global"
|
||||||
"${inputs.self}/common/optional/docker.nix"
|
"${inputs.self}/common/optional/docker.nix"
|
||||||
"${inputs.self}/common/optional/monitoring-agent.nix"
|
"${inputs.self}/common/optional/monitoring-agent.nix"
|
||||||
@@ -14,7 +13,7 @@
|
|||||||
"${inputs.self}/common/optional/systemd-boot.nix"
|
"${inputs.self}/common/optional/systemd-boot.nix"
|
||||||
"${inputs.self}/common/optional/tailscale.nix"
|
"${inputs.self}/common/optional/tailscale.nix"
|
||||||
"${inputs.self}/common/optional/update.nix"
|
"${inputs.self}/common/optional/update.nix"
|
||||||
"${inputs.self}/common/optional/yubikey.nix"
|
"${inputs.self}/common/optional/x86-64-v3.nix"
|
||||||
"${inputs.self}/common/optional/zfs"
|
"${inputs.self}/common/optional/zfs"
|
||||||
./hardware.nix
|
./hardware.nix
|
||||||
./syncthing.nix
|
./syncthing.nix
|
||||||
|
|||||||
@@ -50,6 +50,11 @@
|
|||||||
fsType = "zfs";
|
fsType = "zfs";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
"/nix/var/nix/builds" = {
|
||||||
|
device = "root_pool/nix_build";
|
||||||
|
fsType = "zfs";
|
||||||
|
};
|
||||||
|
|
||||||
"/var" = {
|
"/var" = {
|
||||||
device = "root_pool/var";
|
device = "root_pool/var";
|
||||||
fsType = "zfs";
|
fsType = "zfs";
|
||||||
|
|||||||
@@ -22,6 +22,12 @@ hourly = 0
|
|||||||
daily = 0
|
daily = 0
|
||||||
monthly = 0
|
monthly = 0
|
||||||
|
|
||||||
|
["root_pool/nix_build"]
|
||||||
|
15_min = 1
|
||||||
|
hourly = 0
|
||||||
|
daily = 0
|
||||||
|
monthly = 0
|
||||||
|
|
||||||
["root_pool/models"]
|
["root_pool/models"]
|
||||||
15_min = 4
|
15_min = 4
|
||||||
hourly = 24
|
hourly = 24
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
"${inputs.self}/common/optional/systemd-boot.nix"
|
"${inputs.self}/common/optional/systemd-boot.nix"
|
||||||
"${inputs.self}/common/optional/tailscale.nix"
|
"${inputs.self}/common/optional/tailscale.nix"
|
||||||
"${inputs.self}/common/optional/update.nix"
|
"${inputs.self}/common/optional/update.nix"
|
||||||
|
"${inputs.self}/common/optional/x86-64-v3.nix"
|
||||||
"${inputs.self}/common/optional/zfs"
|
"${inputs.self}/common/optional/zfs"
|
||||||
./docker
|
./docker
|
||||||
./hardware.nix
|
./hardware.nix
|
||||||
|
|||||||
@@ -53,6 +53,11 @@
|
|||||||
fsType = "zfs";
|
fsType = "zfs";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
"/nix/var/nix/builds" = {
|
||||||
|
device = "root_pool/nix_build";
|
||||||
|
fsType = "zfs";
|
||||||
|
};
|
||||||
|
|
||||||
"/boot" = {
|
"/boot" = {
|
||||||
device = "/dev/disk/by-uuid/12CE-A600";
|
device = "/dev/disk/by-uuid/12CE-A600";
|
||||||
fsType = "vfat";
|
fsType = "vfat";
|
||||||
|
|||||||
@@ -79,7 +79,6 @@
|
|||||||
extraComponents = [ "isal" ];
|
extraComponents = [ "isal" ];
|
||||||
customComponents = with pkgs.home-assistant-custom-components; [
|
customComponents = with pkgs.home-assistant-custom-components; [
|
||||||
garmin_connect
|
garmin_connect
|
||||||
pirate-weather
|
|
||||||
];
|
];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
let
|
||||||
|
vars = import ./vars.nix;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
virtualisation.docker.daemon.settings."data-root" = "${vars.containers}/docker";
|
||||||
|
|
||||||
|
# nixos-container hardcodes its state directory to /var/lib/nixos-containers,
|
||||||
|
# so route it to the shared container dataset with a bind mount.
|
||||||
|
fileSystems."/var/lib/nixos-containers" = {
|
||||||
|
device = "${vars.containers}/nixos-containers";
|
||||||
|
fsType = "none";
|
||||||
|
options = [ "bind" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services = {
|
||||||
|
prepare-docker-storage = {
|
||||||
|
description = "Create Docker storage directory";
|
||||||
|
requiredBy = [ "docker.service" ];
|
||||||
|
before = [ "docker.service" ];
|
||||||
|
requires = [ "zfs-mount.service" ];
|
||||||
|
after = [ "zfs-mount.service" ];
|
||||||
|
path = [
|
||||||
|
pkgs.coreutils
|
||||||
|
pkgs.util-linux
|
||||||
|
];
|
||||||
|
|
||||||
|
unitConfig = {
|
||||||
|
DefaultDependencies = false;
|
||||||
|
RequiresMountsFor = [ "/nix" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
script = ''
|
||||||
|
mountpoint -q ${vars.containers}
|
||||||
|
install -d -m 0710 ${vars.containers}/docker
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
prepare-nixos-container-storage = {
|
||||||
|
description = "Create NixOS container storage directory";
|
||||||
|
requiredBy = [ "var-lib-nixos\\x2dcontainers.mount" ];
|
||||||
|
before = [ "var-lib-nixos\\x2dcontainers.mount" ];
|
||||||
|
requires = [ "zfs-mount.service" ];
|
||||||
|
after = [ "zfs-mount.service" ];
|
||||||
|
path = [
|
||||||
|
pkgs.coreutils
|
||||||
|
pkgs.util-linux
|
||||||
|
];
|
||||||
|
|
||||||
|
unitConfig = {
|
||||||
|
DefaultDependencies = false;
|
||||||
|
RequiresMountsFor = [ "/nix" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
script = ''
|
||||||
|
mountpoint -q ${vars.containers}
|
||||||
|
install -d -m 0755 ${vars.containers}/nixos-containers
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -4,10 +4,8 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
"${inputs.self}/users/dov"
|
|
||||||
"${inputs.self}/users/math"
|
"${inputs.self}/users/math"
|
||||||
"${inputs.self}/users/richie"
|
"${inputs.self}/users/richie"
|
||||||
"${inputs.self}/users/steve"
|
|
||||||
"${inputs.self}/common/global"
|
"${inputs.self}/common/global"
|
||||||
"${inputs.self}/common/optional/docker.nix"
|
"${inputs.self}/common/optional/docker.nix"
|
||||||
"${inputs.self}/common/optional/monitoring-agent.nix"
|
"${inputs.self}/common/optional/monitoring-agent.nix"
|
||||||
@@ -15,10 +13,12 @@ in
|
|||||||
"${inputs.self}/common/optional/syncthing_base.nix"
|
"${inputs.self}/common/optional/syncthing_base.nix"
|
||||||
"${inputs.self}/common/optional/tailscale.nix"
|
"${inputs.self}/common/optional/tailscale.nix"
|
||||||
"${inputs.self}/common/optional/update.nix"
|
"${inputs.self}/common/optional/update.nix"
|
||||||
|
"${inputs.self}/common/optional/x86-64-v3.nix"
|
||||||
"${inputs.self}/common/optional/zfs"
|
"${inputs.self}/common/optional/zfs"
|
||||||
./monitoring
|
./monitoring
|
||||||
./docker
|
./docker
|
||||||
./services
|
./services
|
||||||
|
./containers.nix
|
||||||
./hardware.nix
|
./hardware.nix
|
||||||
./networking
|
./networking
|
||||||
./programs.nix
|
./programs.nix
|
||||||
@@ -35,14 +35,6 @@ in
|
|||||||
path = ./snapshot_config.toml;
|
path = ./snapshot_config.toml;
|
||||||
EnvironmentFile = "${vars.secrets}/services/snapshot_manager";
|
EnvironmentFile = "${vars.secrets}/services/snapshot_manager";
|
||||||
};
|
};
|
||||||
|
|
||||||
zerotierone = {
|
|
||||||
enable = true;
|
|
||||||
joinNetworks = [
|
|
||||||
"e4da7455b2ae64ca"
|
|
||||||
"a09acf02330d37b9"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
users.groups = {
|
users.groups = {
|
||||||
|
|||||||
@@ -96,6 +96,11 @@ in
|
|||||||
fsType = "zfs";
|
fsType = "zfs";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
"/nix/var/nix/builds" = {
|
||||||
|
device = "root_pool/nix_build";
|
||||||
|
fsType = "zfs";
|
||||||
|
};
|
||||||
|
|
||||||
"/var" = {
|
"/var" = {
|
||||||
device = "root_pool/var";
|
device = "root_pool/var";
|
||||||
fsType = "zfs";
|
fsType = "zfs";
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
outputs,
|
pkgs,
|
||||||
utils,
|
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
|
|
||||||
@@ -12,6 +11,124 @@ let
|
|||||||
cfg = config.services.nix_builder;
|
cfg = config.services.nix_builder;
|
||||||
runnerUsername = "gitea-runner";
|
runnerUsername = "gitea-runner";
|
||||||
runnerUserid = 601;
|
runnerUserid = 601;
|
||||||
|
runnerLabels = [
|
||||||
|
"self-hosted:host"
|
||||||
|
"nixos:host"
|
||||||
|
];
|
||||||
|
containerConfig =
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
runnerConfigFile = (pkgs.formats.yaml { }).generate "gitea-runner.yaml" { };
|
||||||
|
registerRunner = pkgs.writeShellApplication {
|
||||||
|
name = "register-gitea-runner";
|
||||||
|
runtimeInputs = [
|
||||||
|
pkgs.coreutils
|
||||||
|
pkgs.hostname
|
||||||
|
config.services.gitea-actions-runner.package
|
||||||
|
];
|
||||||
|
text = builtins.readFile ./register_gitea_runner.sh;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
networking = {
|
||||||
|
hostName = "nix-builder";
|
||||||
|
useDHCP = lib.mkDefault true;
|
||||||
|
interfaces.eth0.useDHCP = true;
|
||||||
|
# Ensure containers don't inherit the host's stub resolver (127.0.0.53) which was causing issues
|
||||||
|
useHostResolvConf = false;
|
||||||
|
};
|
||||||
|
nix.settings = {
|
||||||
|
cores = 8;
|
||||||
|
max-jobs = 2;
|
||||||
|
system-features = lib.mkAfter [
|
||||||
|
"gccarch-x86-64-v2"
|
||||||
|
"gccarch-x86-64-v3"
|
||||||
|
];
|
||||||
|
trusted-substituters = [
|
||||||
|
"https://cache.nixos.org"
|
||||||
|
"https://cache.tmmworkshop.com"
|
||||||
|
"https://nix-community.cachix.org"
|
||||||
|
];
|
||||||
|
substituters = [
|
||||||
|
"https://cache.nixos.org/?priority=2&want-mass-query=true"
|
||||||
|
"https://cache.tmmworkshop.com/?priority=2&want-mass-query=true"
|
||||||
|
"https://nix-community.cachix.org/?priority=10&want-mass-query=true"
|
||||||
|
];
|
||||||
|
trusted-public-keys = [
|
||||||
|
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
|
||||||
|
"cache.tmmworkshop.com:jHffkpgbmEdstQPoihJPYW9TQe6jnQbWR2LqkNGV3iA="
|
||||||
|
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
||||||
|
];
|
||||||
|
experimental-features = [
|
||||||
|
"flakes"
|
||||||
|
"nix-command"
|
||||||
|
];
|
||||||
|
sandbox = true;
|
||||||
|
allowed-users = [ runnerUsername ];
|
||||||
|
trusted-users = [
|
||||||
|
"root"
|
||||||
|
runnerUsername
|
||||||
|
];
|
||||||
|
};
|
||||||
|
users = {
|
||||||
|
users.${runnerUsername} = {
|
||||||
|
isSystemUser = true;
|
||||||
|
group = runnerUsername;
|
||||||
|
uid = runnerUserid;
|
||||||
|
};
|
||||||
|
groups.${runnerUsername}.gid = runnerUserid;
|
||||||
|
};
|
||||||
|
services.gitea-actions-runner.instances.builder = {
|
||||||
|
enable = true;
|
||||||
|
name = "jeeves-nix-builder";
|
||||||
|
url = "http://192.168.99.14:6443/";
|
||||||
|
labels = runnerLabels;
|
||||||
|
tokenFile = "/run/secrets/gitea-runners/registration-token";
|
||||||
|
settings.runner.timeout = "12h";
|
||||||
|
hostPackages = with pkgs; [
|
||||||
|
bash
|
||||||
|
coreutils
|
||||||
|
curl
|
||||||
|
gawk
|
||||||
|
gitMinimal
|
||||||
|
gnused
|
||||||
|
my_python
|
||||||
|
nix
|
||||||
|
nixfmt
|
||||||
|
nixos-rebuild
|
||||||
|
nodejs
|
||||||
|
treefmt
|
||||||
|
wget
|
||||||
|
];
|
||||||
|
};
|
||||||
|
systemd.services."gitea-runner-builder" = {
|
||||||
|
serviceConfig = {
|
||||||
|
DynamicUser = mkForce false;
|
||||||
|
User = mkForce runnerUsername;
|
||||||
|
Group = mkForce runnerUsername;
|
||||||
|
ExecStartPre = mkForce [
|
||||||
|
"${getExe registerRunner} builder http://192.168.99.14:6443/ ${runnerConfigFile} ${escapeShellArgs runnerLabels}"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
system.stateVersion = "24.05";
|
||||||
|
};
|
||||||
|
sharedContainerPath =
|
||||||
|
(import "${pkgs.path}/nixos/lib/eval-config.nix" {
|
||||||
|
modules = [
|
||||||
|
{
|
||||||
|
boot.isNspawnContainer = true;
|
||||||
|
nixpkgs.pkgs = pkgs;
|
||||||
|
}
|
||||||
|
containerConfig
|
||||||
|
];
|
||||||
|
system = null;
|
||||||
|
}).config.system.build.toplevel;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.services.nix_builder = {
|
options.services.nix_builder = {
|
||||||
@@ -48,9 +165,11 @@ in
|
|||||||
containers = mapAttrs (
|
containers = mapAttrs (
|
||||||
name: containerCfg:
|
name: containerCfg:
|
||||||
mkIf containerCfg.enable {
|
mkIf containerCfg.enable {
|
||||||
|
path = sharedContainerPath;
|
||||||
autoStart = true;
|
autoStart = true;
|
||||||
privateNetwork = true;
|
privateNetwork = true;
|
||||||
hostBridge = cfg.bridgeName;
|
hostBridge = cfg.bridgeName;
|
||||||
|
extraFlags = [ "--hostname=${name}" ];
|
||||||
bindMounts = {
|
bindMounts = {
|
||||||
host-nix = {
|
host-nix = {
|
||||||
mountPoint = "/host-nix/var/nix/daemon-socket";
|
mountPoint = "/host-nix/var/nix/daemon-socket";
|
||||||
@@ -68,93 +187,6 @@ in
|
|||||||
isReadOnly = false;
|
isReadOnly = false;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
config =
|
|
||||||
{
|
|
||||||
config,
|
|
||||||
pkgs,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
{
|
|
||||||
networking = {
|
|
||||||
useDHCP = lib.mkDefault true;
|
|
||||||
interfaces.eth0.useDHCP = true;
|
|
||||||
# Ensure containers don't inherit the host's stub resolver (127.0.0.53) which was causing issues
|
|
||||||
useHostResolvConf = false;
|
|
||||||
};
|
|
||||||
nix.settings = {
|
|
||||||
trusted-substituters = [
|
|
||||||
"https://cache.nixos.org"
|
|
||||||
"https://cache.tmmworkshop.com"
|
|
||||||
"https://nix-community.cachix.org"
|
|
||||||
];
|
|
||||||
substituters = [
|
|
||||||
"https://cache.nixos.org/?priority=2&want-mass-query=true"
|
|
||||||
"https://cache.tmmworkshop.com/?priority=2&want-mass-query=true"
|
|
||||||
"https://nix-community.cachix.org/?priority=10&want-mass-query=true"
|
|
||||||
];
|
|
||||||
trusted-public-keys = [
|
|
||||||
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
|
|
||||||
"cache.tmmworkshop.com:jHffkpgbmEdstQPoihJPYW9TQe6jnQbWR2LqkNGV3iA="
|
|
||||||
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
|
||||||
];
|
|
||||||
experimental-features = [
|
|
||||||
"flakes"
|
|
||||||
"nix-command"
|
|
||||||
];
|
|
||||||
sandbox = true;
|
|
||||||
allowed-users = [ "gitea-runner" ];
|
|
||||||
trusted-users = [
|
|
||||||
"root"
|
|
||||||
"gitea-runner"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
nixpkgs = {
|
|
||||||
overlays = builtins.attrValues outputs.overlays;
|
|
||||||
config.allowUnfree = true;
|
|
||||||
};
|
|
||||||
users = {
|
|
||||||
users.${runnerUsername} = {
|
|
||||||
isSystemUser = true;
|
|
||||||
group = runnerUsername;
|
|
||||||
uid = runnerUserid;
|
|
||||||
};
|
|
||||||
groups.${runnerUsername}.gid = runnerUserid;
|
|
||||||
};
|
|
||||||
services.gitea-actions-runner.instances.${name} = {
|
|
||||||
enable = true;
|
|
||||||
name = "jeeves-${name}";
|
|
||||||
url = "http://192.168.99.14:6443/";
|
|
||||||
labels = [
|
|
||||||
"self-hosted:host"
|
|
||||||
"nixos:host"
|
|
||||||
];
|
|
||||||
tokenFile = "/run/secrets/gitea-runners/registration-token";
|
|
||||||
hostPackages = with pkgs; [
|
|
||||||
bash
|
|
||||||
coreutils
|
|
||||||
curl
|
|
||||||
gawk
|
|
||||||
gitMinimal
|
|
||||||
gnused
|
|
||||||
my_python
|
|
||||||
nix
|
|
||||||
nixfmt
|
|
||||||
nixos-rebuild
|
|
||||||
nodejs
|
|
||||||
treefmt
|
|
||||||
wget
|
|
||||||
];
|
|
||||||
};
|
|
||||||
systemd.services."gitea-runner-${utils.escapeSystemdPath name}" = {
|
|
||||||
serviceConfig = {
|
|
||||||
DynamicUser = mkForce false;
|
|
||||||
User = mkForce runnerUsername;
|
|
||||||
Group = mkForce runnerUsername;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
system.stateVersion = "24.05";
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
) cfg.containers;
|
) cfg.containers;
|
||||||
|
|
||||||
@@ -165,6 +197,7 @@ in
|
|||||||
value = {
|
value = {
|
||||||
requires = [ "gitea.service" ];
|
requires = [ "gitea.service" ];
|
||||||
after = [ "gitea.service" ];
|
after = [ "gitea.service" ];
|
||||||
|
serviceConfig.CPUQuota = "800%";
|
||||||
};
|
};
|
||||||
}) (builtins.attrNames (filterAttrs (_: c: c.enable) cfg.containers))
|
}) (builtins.attrNames (filterAttrs (_: c: c.enable) cfg.containers))
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
legacy_instance_dir="$STATE_DIRECTORY/$(hostname)"
|
||||||
|
instance_dir="$STATE_DIRECTORY/$1"
|
||||||
|
runner_url="$2"
|
||||||
|
runner_config_file="$3"
|
||||||
|
shift 3
|
||||||
|
runner_labels="$(IFS=,; printf '%s' "$*")"
|
||||||
|
|
||||||
|
if [ ! -e "$instance_dir" ] && [ -d "$legacy_instance_dir" ]; then
|
||||||
|
mv "$legacy_instance_dir" "$instance_dir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -vp "$instance_dir"
|
||||||
|
cd "$instance_dir" || exit 1
|
||||||
|
|
||||||
|
token_hash_file="$instance_dir/.token-hash"
|
||||||
|
token_hash_current="$(printf '%s' "$TOKEN" | sha256sum | cut -d' ' -f1)"
|
||||||
|
token_hash_stored="$(cat "$token_hash_file" 2>/dev/null || echo "")"
|
||||||
|
labels_file="$instance_dir/.labels"
|
||||||
|
labels_wanted="$(printf '%s\n' "$@" | sort)"
|
||||||
|
labels_current="$(cat "$labels_file" 2>/dev/null || echo 0)"
|
||||||
|
|
||||||
|
if [ ! -e "$instance_dir/.runner" ] || [ "$labels_wanted" != "$labels_current" ] || [ "$token_hash_current" != "$token_hash_stored" ]; then
|
||||||
|
rm -v "$instance_dir/.runner" || true
|
||||||
|
|
||||||
|
gitea-runner register --no-interactive \
|
||||||
|
--instance "$runner_url" \
|
||||||
|
--token "$TOKEN" \
|
||||||
|
--name "jeeves-$(hostname)" \
|
||||||
|
--labels "$runner_labels" \
|
||||||
|
--config "$runner_config_file"
|
||||||
|
|
||||||
|
printf '%s' "$token_hash_current" > "$token_hash_file"
|
||||||
|
printf '%s\n' "$labels_wanted" > "$labels_file"
|
||||||
|
fi
|
||||||
@@ -17,6 +17,7 @@ sudo zpool create scratch -o ashift=12 -O acltype=posixacl -O atime=off -O dnode
|
|||||||
# media datasets
|
# media datasets
|
||||||
sudo zfs create media/temp -o sync=disabled -o redundant_metadata=none
|
sudo zfs create media/temp -o sync=disabled -o redundant_metadata=none
|
||||||
sudo zfs create media/secure -o encryption=aes-256-gcm -o keyformat=hex -o keylocation=file:///root/zfs.key
|
sudo zfs create media/secure -o encryption=aes-256-gcm -o keyformat=hex -o keylocation=file:///root/zfs.key
|
||||||
|
sudo zfs create media/secure/containers -o mountpoint=/zfs/media/containers -o compression=lz4 -o sync=disabled -o redundant_metadata=some -o normalization=none -o utf8only=off
|
||||||
sudo zfs create media/secure/docker -o compression=zstd-9
|
sudo zfs create media/secure/docker -o compression=zstd-9
|
||||||
sudo zfs create media/secure/github-runners -o compression=zstd-9 -o sync=disabled
|
sudo zfs create media/secure/github-runners -o compression=zstd-9 -o sync=disabled
|
||||||
sudo zfs create media/secure/notes -o copies=2
|
sudo zfs create media/secure/notes -o copies=2
|
||||||
|
|||||||
@@ -1,80 +0,0 @@
|
|||||||
{
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
vars = import ../vars.nix;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
systemd.tmpfiles.rules = [
|
|
||||||
"d ${vars.docker_configs}/camofox-browser 0750 root root - -"
|
|
||||||
];
|
|
||||||
|
|
||||||
containers.camofox-browser = {
|
|
||||||
autoStart = true;
|
|
||||||
privateNetwork = false;
|
|
||||||
bindMounts = {
|
|
||||||
camofox-browser = {
|
|
||||||
hostPath = "${vars.docker_configs}/camofox-browser";
|
|
||||||
mountPoint = "/var/lib/camofox-browser";
|
|
||||||
isReadOnly = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
config =
|
|
||||||
{
|
|
||||||
pkgs,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
{
|
|
||||||
networking.hostName = "camofox-browser";
|
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
|
||||||
ffmpeg
|
|
||||||
git
|
|
||||||
nodejs
|
|
||||||
python3Packages.yt-dlp
|
|
||||||
];
|
|
||||||
|
|
||||||
systemd.services.camofox-browser = {
|
|
||||||
description = "Camofox browser server";
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
after = [ "network.target" ];
|
|
||||||
environment = {
|
|
||||||
CAMOFOX_HOST = "127.0.0.1";
|
|
||||||
CAMOFOX_PORT = "9377";
|
|
||||||
HOME = "/var/lib/camofox-browser";
|
|
||||||
};
|
|
||||||
path = with pkgs; [
|
|
||||||
bash
|
|
||||||
coreutils
|
|
||||||
git
|
|
||||||
nodejs
|
|
||||||
];
|
|
||||||
serviceConfig = {
|
|
||||||
Restart = "always";
|
|
||||||
RestartSec = "5s";
|
|
||||||
WorkingDirectory = "/var/lib/camofox-browser";
|
|
||||||
};
|
|
||||||
script = ''
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
app_dir=/var/lib/camofox-browser/app
|
|
||||||
|
|
||||||
if [ ! -d "$app_dir/.git" ]; then
|
|
||||||
git clone --depth 1 https://github.com/jo-inc/camofox-browser "$app_dir"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd "$app_dir"
|
|
||||||
|
|
||||||
if [ ! -d node_modules ]; then
|
|
||||||
npm install
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec npm start
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
system.stateVersion = lib.mkDefault "24.05";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -19,6 +19,7 @@ in
|
|||||||
actions = {
|
actions = {
|
||||||
ENABLED = true;
|
ENABLED = true;
|
||||||
DEFAULT_ACTIONS_URL = "github";
|
DEFAULT_ACTIONS_URL = "github";
|
||||||
|
ENDLESS_TASK_TIMEOUT = "12h";
|
||||||
};
|
};
|
||||||
service.DISABLE_REGISTRATION = true;
|
service.DISABLE_REGISTRATION = true;
|
||||||
server = {
|
server = {
|
||||||
|
|||||||
@@ -23,6 +23,12 @@ hourly = 0
|
|||||||
daily = 0
|
daily = 0
|
||||||
monthly = 0
|
monthly = 0
|
||||||
|
|
||||||
|
["root_pool/nix_build"]
|
||||||
|
15_min = 1
|
||||||
|
hourly = 0
|
||||||
|
daily = 0
|
||||||
|
monthly = 0
|
||||||
|
|
||||||
["root_pool/var"]
|
["root_pool/var"]
|
||||||
15_min = 8
|
15_min = 8
|
||||||
hourly = 24
|
hourly = 24
|
||||||
@@ -60,6 +66,12 @@ daily = 30
|
|||||||
monthly = 12
|
monthly = 12
|
||||||
|
|
||||||
# media
|
# media
|
||||||
|
["media/secure/containers"]
|
||||||
|
15_min = 2
|
||||||
|
hourly = 0
|
||||||
|
daily = 0
|
||||||
|
monthly = 0
|
||||||
|
|
||||||
["media/temp"]
|
["media/temp"]
|
||||||
15_min = 2
|
15_min = 2
|
||||||
hourly = 0
|
hourly = 0
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
inherit zfs_media zfs_storage zfs_scratch;
|
inherit zfs_media zfs_storage zfs_scratch;
|
||||||
|
containers = "${zfs_media}/containers";
|
||||||
database = "${zfs_media}/database";
|
database = "${zfs_media}/database";
|
||||||
docker = "${zfs_media}/docker";
|
docker = "${zfs_media}/docker";
|
||||||
docker_configs = "${zfs_media}/docker/configs";
|
docker_configs = "${zfs_media}/docker/configs";
|
||||||
|
|||||||
@@ -10,13 +10,12 @@
|
|||||||
"${inputs.self}/users/richie"
|
"${inputs.self}/users/richie"
|
||||||
"${inputs.self}/common/global"
|
"${inputs.self}/common/global"
|
||||||
"${inputs.self}/common/optional/tailscale.nix"
|
"${inputs.self}/common/optional/tailscale.nix"
|
||||||
|
"${inputs.self}/common/optional/x86-64-v3.nix"
|
||||||
./disk-config.nix
|
./disk-config.nix
|
||||||
./haproxy
|
./haproxy
|
||||||
./monitoring.nix
|
./monitoring.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
nixpkgs.hostPlatform = "x86_64-linux";
|
|
||||||
|
|
||||||
boot = {
|
boot = {
|
||||||
# Avoid consuming the VM's limited memory for /tmp.
|
# Avoid consuming the VM's limited memory for /tmp.
|
||||||
tmp.useTmpfs = false;
|
tmp.useTmpfs = false;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
"${inputs.self}/common/optional/syncthing_base.nix"
|
"${inputs.self}/common/optional/syncthing_base.nix"
|
||||||
"${inputs.self}/common/optional/systemd-boot.nix"
|
"${inputs.self}/common/optional/systemd-boot.nix"
|
||||||
"${inputs.self}/common/optional/tailscale.nix"
|
"${inputs.self}/common/optional/tailscale.nix"
|
||||||
|
"${inputs.self}/common/optional/x86-64-v3.nix"
|
||||||
"${inputs.self}/common/optional/yubikey.nix"
|
"${inputs.self}/common/optional/yubikey.nix"
|
||||||
"${inputs.self}/common/optional/zfs"
|
"${inputs.self}/common/optional/zfs"
|
||||||
./hardware.nix
|
./hardware.nix
|
||||||
|
|||||||
@@ -34,14 +34,22 @@
|
|||||||
device = "root_pool/root";
|
device = "root_pool/root";
|
||||||
fsType = "zfs";
|
fsType = "zfs";
|
||||||
};
|
};
|
||||||
|
|
||||||
"/home" = {
|
"/home" = {
|
||||||
device = "root_pool/home";
|
device = "root_pool/home";
|
||||||
fsType = "zfs";
|
fsType = "zfs";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
"/nix/var/nix/builds" = {
|
||||||
|
device = "root_pool/nix_build";
|
||||||
|
fsType = "zfs";
|
||||||
|
};
|
||||||
|
|
||||||
"/var" = {
|
"/var" = {
|
||||||
device = "root_pool/var";
|
device = "root_pool/var";
|
||||||
fsType = "zfs";
|
fsType = "zfs";
|
||||||
};
|
};
|
||||||
|
|
||||||
"/boot" = {
|
"/boot" = {
|
||||||
device = "/dev/disk/by-uuid/12CE-A600";
|
device = "/dev/disk/by-uuid/12CE-A600";
|
||||||
fsType = "vfat";
|
fsType = "vfat";
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
{
|
|
||||||
|
|
||||||
users = {
|
|
||||||
users.dov = {
|
|
||||||
isNormalUser = true;
|
|
||||||
|
|
||||||
shell = pkgs.zsh;
|
|
||||||
group = "dov";
|
|
||||||
openssh.authorizedKeys.keys = [
|
|
||||||
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCoSBmMfvp6aThkrfkLQ4TDwZJD0HCC0lsTIRNREIAWeduNkVFdkO3T1SMLmCKJ+zlL9xziNBEqB8NFl4TabAhptIGlKgTOc8C9eDaPQMQV8PB/4DxZhCt7O2qb4Vfcz82IHPtdwwaIsGpssgh81mQ4tPtP8BI0TluRBy+2v095s20j+PYRGrAXJtOWpVY9zaXxEJ8dXDhHDF2xzxvUcwu9NsoY8t+4/ZJ1mrTTG+eGp5gLAKnSVhAGgsmqCY577Nkso1jSzKer1XcCiaGIedpLuTzmUbOFFEVhhTSy+Ki1NLEcjGW2e6Vyg5Pm8VGN75MqyDZsi5igv9Grxq62EHQ4mFea9rns48B74O/bNQ1OoLVO9u/HwdLCgBTZzptrCmNwML6kBWrmCogoH3ueVbHwDCW5kTTMBCoVV+HaZ+qDWu7xZVx49MuCK29QGZj/IrN0N7h78KL0NYajdei87R0mcmWGP0YaJTdCQ4iKi9c77BUYQp+Qpqt+mnIX0cgjQOU= dkruger@kzin" # cspell:disable-line
|
|
||||||
];
|
|
||||||
extraGroups = [
|
|
||||||
"audio"
|
|
||||||
"video"
|
|
||||||
"users"
|
|
||||||
];
|
|
||||||
uid = 1004;
|
|
||||||
};
|
|
||||||
|
|
||||||
groups.dov.gid = 1004;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
imports = [
|
|
||||||
./direnv.nix
|
|
||||||
./git.nix
|
|
||||||
./zsh.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
programs.starship.enable = true;
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
|
|
||||||
programs.direnv = {
|
|
||||||
enable = true;
|
|
||||||
enableZshIntegration = true;
|
|
||||||
nix-direnv.enable = true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
programs.git = {
|
|
||||||
enable = true;
|
|
||||||
signing.format = null;
|
|
||||||
settings = {
|
|
||||||
user = {
|
|
||||||
email = "dov.kruger@gmail.com";
|
|
||||||
name = "Dov Kruger";
|
|
||||||
};
|
|
||||||
pull.rebase = true;
|
|
||||||
color.ui = true;
|
|
||||||
};
|
|
||||||
lfs.enable = true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
programs.zsh = {
|
|
||||||
enable = true;
|
|
||||||
syntaxHighlighting.enable = true;
|
|
||||||
history.size = 10000;
|
|
||||||
oh-my-zsh = {
|
|
||||||
enable = true;
|
|
||||||
plugins = [
|
|
||||||
"git"
|
|
||||||
"docker"
|
|
||||||
"docker-compose"
|
|
||||||
"colored-man-pages"
|
|
||||||
"rust"
|
|
||||||
"systemd"
|
|
||||||
"tmux"
|
|
||||||
"ufw"
|
|
||||||
"z"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
shellAliases = {
|
|
||||||
"lrt" = "eza --icons -lsnew";
|
|
||||||
"ls" = "eza";
|
|
||||||
"ll" = "eza --long --group";
|
|
||||||
"la" = "eza --all";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
{ config, ... }:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./cli
|
|
||||||
./programs.nix
|
|
||||||
./ssh_config.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
programs = {
|
|
||||||
home-manager.enable = true;
|
|
||||||
git.enable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
home = {
|
|
||||||
username = "dov";
|
|
||||||
homeDirectory = "/home/${config.home.username}";
|
|
||||||
stateVersion = "24.05";
|
|
||||||
sessionVariables = {
|
|
||||||
FLAKE = "$HOME/dotfiles";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
home.packages = with pkgs; [
|
|
||||||
# cli
|
|
||||||
bat
|
|
||||||
btop
|
|
||||||
eza
|
|
||||||
fd
|
|
||||||
ffmpegthumbnailer
|
|
||||||
fzf
|
|
||||||
git
|
|
||||||
gnupg
|
|
||||||
imagemagick
|
|
||||||
jq
|
|
||||||
ncdu
|
|
||||||
ouch
|
|
||||||
p7zip
|
|
||||||
poppler
|
|
||||||
rar
|
|
||||||
ripgrep
|
|
||||||
starship
|
|
||||||
tmux
|
|
||||||
unzip
|
|
||||||
yazi
|
|
||||||
zoxide
|
|
||||||
# system info
|
|
||||||
hwloc
|
|
||||||
lynis
|
|
||||||
pciutils
|
|
||||||
smartmontools
|
|
||||||
usbutils
|
|
||||||
# networking
|
|
||||||
iperf3
|
|
||||||
nmap
|
|
||||||
wget
|
|
||||||
# python
|
|
||||||
ruff
|
|
||||||
uv
|
|
||||||
# nodejs
|
|
||||||
nodejs
|
|
||||||
# Rust packages
|
|
||||||
trunk
|
|
||||||
wasm-pack
|
|
||||||
cargo-watch
|
|
||||||
cargo-generate
|
|
||||||
cargo-audit
|
|
||||||
cargo-update
|
|
||||||
# nix
|
|
||||||
nix-init
|
|
||||||
nix-output-monitor
|
|
||||||
nix-prefetch
|
|
||||||
nix-tree
|
|
||||||
nixfmt
|
|
||||||
treefmt
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
programs.ssh = {
|
|
||||||
enable = true;
|
|
||||||
enableDefaultConfig = false;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
imports = [
|
|
||||||
../home/global.nix
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -3,54 +3,17 @@
|
|||||||
home.packages = with pkgs; [
|
home.packages = with pkgs; [
|
||||||
# cli
|
# cli
|
||||||
bat
|
bat
|
||||||
btop
|
|
||||||
eza
|
|
||||||
fd
|
|
||||||
ffmpegthumbnailer
|
|
||||||
fzf
|
fzf
|
||||||
git
|
git
|
||||||
gnupg
|
|
||||||
imagemagick
|
|
||||||
jq
|
jq
|
||||||
ncdu
|
ncdu
|
||||||
ouch
|
fastfetch
|
||||||
p7zip
|
p7zip
|
||||||
poppler
|
|
||||||
rar
|
rar
|
||||||
ripgrep
|
|
||||||
starship
|
|
||||||
tmux
|
|
||||||
unzip
|
unzip
|
||||||
yazi
|
|
||||||
zoxide
|
zoxide
|
||||||
# system info
|
|
||||||
hwloc
|
|
||||||
lynis
|
|
||||||
pciutils
|
|
||||||
smartmontools
|
|
||||||
usbutils
|
|
||||||
# networking
|
|
||||||
iperf3
|
|
||||||
nmap
|
|
||||||
wget
|
|
||||||
# python
|
# python
|
||||||
ruff
|
ruff
|
||||||
uv
|
uv
|
||||||
# nodejs
|
|
||||||
nodejs
|
|
||||||
# Rust packages
|
|
||||||
trunk
|
|
||||||
wasm-pack
|
|
||||||
cargo-watch
|
|
||||||
cargo-generate
|
|
||||||
cargo-audit
|
|
||||||
cargo-update
|
|
||||||
# nix
|
|
||||||
nix-init
|
|
||||||
nix-output-monitor
|
|
||||||
nix-prefetch
|
|
||||||
nix-tree
|
|
||||||
nixfmt
|
|
||||||
treefmt
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
{ inputs, pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
"${inputs.self}/users/shared/comms.nix"
|
./comms.nix
|
||||||
"${inputs.self}/users/shared/games.nix"
|
|
||||||
"${inputs.self}/users/shared/sweet.nix"
|
|
||||||
./firefox
|
./firefox
|
||||||
|
./games.nix
|
||||||
./kitty.nix
|
./kitty.nix
|
||||||
./llm_tools.nix
|
./llm_tools.nix
|
||||||
|
./sweet.nix
|
||||||
./t3_code
|
./t3_code
|
||||||
./vscode
|
./vscode
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -3,21 +3,14 @@
|
|||||||
home.packages = with pkgs; [
|
home.packages = with pkgs; [
|
||||||
# cli
|
# cli
|
||||||
bat
|
bat
|
||||||
fd
|
|
||||||
ffmpegthumbnailer
|
|
||||||
fzf
|
fzf
|
||||||
git
|
git
|
||||||
gnupg
|
|
||||||
imagemagick
|
|
||||||
jq
|
jq
|
||||||
ncdu
|
ncdu
|
||||||
fastfetch
|
fastfetch
|
||||||
ouch
|
|
||||||
p7zip
|
p7zip
|
||||||
poppler
|
|
||||||
rar
|
rar
|
||||||
unzip
|
unzip
|
||||||
yazi
|
|
||||||
zoxide
|
zoxide
|
||||||
# Home Assistant
|
# Home Assistant
|
||||||
esphome
|
esphome
|
||||||
@@ -35,8 +28,6 @@
|
|||||||
# python
|
# python
|
||||||
ruff
|
ruff
|
||||||
uv
|
uv
|
||||||
# nodejs
|
|
||||||
nodejs
|
|
||||||
# Rust packages
|
# Rust packages
|
||||||
bacon
|
bacon
|
||||||
cargo
|
cargo
|
||||||
@@ -51,9 +42,6 @@
|
|||||||
rustfmt
|
rustfmt
|
||||||
trunk
|
trunk
|
||||||
wasm-pack
|
wasm-pack
|
||||||
# cpp
|
|
||||||
clang-tools
|
|
||||||
clang_20
|
|
||||||
# nix
|
# nix
|
||||||
nix-init
|
nix-init
|
||||||
nix-output-monitor
|
nix-output-monitor
|
||||||
@@ -61,6 +49,5 @@
|
|||||||
nix-tree
|
nix-tree
|
||||||
nixfmt
|
nixfmt
|
||||||
treefmt
|
treefmt
|
||||||
codebase-memory-mcp
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
{
|
|
||||||
pkgs,
|
|
||||||
config,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
ifTheyExist = groups: builtins.filter (group: builtins.hasAttr group config.users.groups) groups;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
|
|
||||||
users = {
|
|
||||||
users.steve = {
|
|
||||||
isNormalUser = true;
|
|
||||||
|
|
||||||
shell = pkgs.zsh;
|
|
||||||
group = "steve";
|
|
||||||
openssh.authorizedKeys.keys = [
|
|
||||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJH03VzDbUhzfhvwD+OsYh6GobODYaI9jdNdzWQoqFsp matth@Jove" # cspell:disable-line
|
|
||||||
];
|
|
||||||
extraGroups = [
|
|
||||||
"audio"
|
|
||||||
"video"
|
|
||||||
"wheel"
|
|
||||||
"users"
|
|
||||||
]
|
|
||||||
++ ifTheyExist [
|
|
||||||
"dialout"
|
|
||||||
"docker"
|
|
||||||
"hass"
|
|
||||||
"libvirtd"
|
|
||||||
"networkmanager"
|
|
||||||
"plugdev"
|
|
||||||
"scanner"
|
|
||||||
"transmission"
|
|
||||||
"uaccess"
|
|
||||||
"wireshark"
|
|
||||||
];
|
|
||||||
uid = 1005;
|
|
||||||
};
|
|
||||||
|
|
||||||
groups.steve.gid = 1005;
|
|
||||||
};
|
|
||||||
home-manager.users.steve = import ./systems/${config.networking.hostName}.nix;
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
imports = [
|
|
||||||
./direnv.nix
|
|
||||||
./git.nix
|
|
||||||
./zsh.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
programs.starship.enable = true;
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
|
|
||||||
programs.direnv = {
|
|
||||||
enable = true;
|
|
||||||
enableZshIntegration = true;
|
|
||||||
nix-direnv.enable = true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
programs.git = {
|
|
||||||
enable = true;
|
|
||||||
signing.format = null;
|
|
||||||
settings = {
|
|
||||||
user = {
|
|
||||||
email = "matthew.michal11@gmail.com";
|
|
||||||
name = "Matthew Michal";
|
|
||||||
};
|
|
||||||
pull.rebase = true;
|
|
||||||
color.ui = true;
|
|
||||||
};
|
|
||||||
lfs.enable = true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
{
|
|
||||||
programs.zsh = {
|
|
||||||
enable = true;
|
|
||||||
syntaxHighlighting.enable = true;
|
|
||||||
history.size = 10000;
|
|
||||||
oh-my-zsh = {
|
|
||||||
enable = true;
|
|
||||||
plugins = [
|
|
||||||
"git"
|
|
||||||
"docker"
|
|
||||||
"docker-compose"
|
|
||||||
"colored-man-pages"
|
|
||||||
"rust"
|
|
||||||
"systemd"
|
|
||||||
"tmux"
|
|
||||||
"ufw"
|
|
||||||
"z"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
shellAliases = {
|
|
||||||
"lrt" = "eza --icons -lsnew";
|
|
||||||
"ls" = "eza";
|
|
||||||
"ll" = "eza --long --group";
|
|
||||||
"la" = "eza --all";
|
|
||||||
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
{ config, ... }:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./cli
|
|
||||||
./programs.nix
|
|
||||||
./ssh_config.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
programs = {
|
|
||||||
home-manager.enable = true;
|
|
||||||
git.enable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
home = {
|
|
||||||
username = "steve";
|
|
||||||
homeDirectory = "/home/${config.home.username}";
|
|
||||||
stateVersion = "24.05";
|
|
||||||
sessionVariables = {
|
|
||||||
FLAKE = "$HOME/dotfiles";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
home.packages = with pkgs; [
|
|
||||||
# cli
|
|
||||||
bat
|
|
||||||
btop
|
|
||||||
eza
|
|
||||||
fd
|
|
||||||
ffmpegthumbnailer
|
|
||||||
fzf
|
|
||||||
git
|
|
||||||
gnupg
|
|
||||||
imagemagick
|
|
||||||
jq
|
|
||||||
ncdu
|
|
||||||
ouch
|
|
||||||
p7zip
|
|
||||||
poppler
|
|
||||||
rar
|
|
||||||
ripgrep
|
|
||||||
starship
|
|
||||||
tmux
|
|
||||||
unzip
|
|
||||||
yazi
|
|
||||||
zoxide
|
|
||||||
# system info
|
|
||||||
hwloc
|
|
||||||
lynis
|
|
||||||
pciutils
|
|
||||||
smartmontools
|
|
||||||
usbutils
|
|
||||||
# networking
|
|
||||||
iperf3
|
|
||||||
nmap
|
|
||||||
wget
|
|
||||||
# python
|
|
||||||
ruff
|
|
||||||
uv
|
|
||||||
# nodejs
|
|
||||||
nodejs
|
|
||||||
# Rust packages
|
|
||||||
trunk
|
|
||||||
wasm-pack
|
|
||||||
cargo-watch
|
|
||||||
cargo-generate
|
|
||||||
cargo-audit
|
|
||||||
cargo-update
|
|
||||||
# nix
|
|
||||||
nix-init
|
|
||||||
nix-output-monitor
|
|
||||||
nix-prefetch
|
|
||||||
nix-tree
|
|
||||||
nixfmt
|
|
||||||
treefmt
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
programs.ssh = {
|
|
||||||
enable = true;
|
|
||||||
enableDefaultConfig = false;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
imports = [
|
|
||||||
../home/global.nix
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
imports = [
|
|
||||||
../home/global.nix
|
|
||||||
];
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user