Compare commits
216 Commits
wip-nm-sys
...
wip-doofne
Author | SHA1 | Date | |
---|---|---|---|
4b99607f7b | |||
0d99293b2f | |||
b3890b82dc | |||
3fc96a3e32 | |||
1af7b613bd | |||
4c8695aae8 | |||
d45e3fda5e | |||
456e0de872 | |||
7825ddc123 | |||
dd47a5083c | |||
14d5d9eb5a | |||
1f6f2399d6 | |||
b0ee12ba7b | |||
a6d268ca72 | |||
1ecc033ff5 | |||
c87dab93b3 | |||
53139a7cdf | |||
f37014a856 | |||
0237d3a144 | |||
656ad76f25 | |||
b7c71dc67b | |||
aaa40eae04 | |||
d8ed82cfdf | |||
0e73f95ab1 | |||
b1ba0cad03 | |||
4bcbfbc8aa | |||
0f6c9f3cde | |||
f4d806c0c2 | |||
6963998519 | |||
a63f6281c5 | |||
df0a8cf900 | |||
a4f5343fb5 | |||
c50a4d1d71 | |||
aadbeab3ac | |||
aafcf7b478 | |||
a78b840215 | |||
3c2347faba | |||
ebff35a378 | |||
1515f01384 | |||
60a5c61500 | |||
417b85450c | |||
2e0a3dc8ef | |||
3165c95d0f | |||
6dd4d9da3e | |||
5a086b359d | |||
a204f0a987 | |||
317251338c | |||
01cfed2438 | |||
ba0524d193 | |||
26a4f20f6c | |||
46f5a7e37d | |||
88a487f565 | |||
d037afd75c | |||
654858f8ff | |||
5abcc7d399 | |||
65823507ad | |||
63a88da3b4 | |||
734da36639 | |||
49ccf95fb3 | |||
e70d0f3c8e | |||
c00cccd429 | |||
02fdc91237 | |||
14616f9b61 | |||
f9d856b3bb | |||
d52db06ffe | |||
![]() |
dc2c31f220 | ||
52322e3207 | |||
26f1f2b581 | |||
74c188012a | |||
e0c741427e | |||
999a173001 | |||
330a64d820 | |||
2e2f5dd373 | |||
5561dde31d | |||
c3ae60d71b | |||
1c79209e23 | |||
6d1db1ee67 | |||
88d462764f | |||
8f634d9bb0 | |||
3e35210e4b | |||
04f4d330a8 | |||
ce60e53b9a | |||
3ff9f974a6 | |||
11e9ad5eca | |||
bf99a64b89 | |||
3b43562841 | |||
131e43e975 | |||
e34a9957e3 | |||
ea1a0b72b5 | |||
aab9ed0d35 | |||
f477370e4c | |||
b5fc8cfd4e | |||
4fdaacf8ad | |||
f1705686b8 | |||
0d0fa8b37f | |||
b5b39d1500 | |||
86482e922c | |||
111c69b368 | |||
60c13d34a7 | |||
823d064ab0 | |||
3f88d750c6 | |||
05f29ba01e | |||
2b11bac1eb | |||
86adc38537 | |||
b787289b39 | |||
63f3b8e89b | |||
448b8007ca | |||
9fc4119275 | |||
8f1332797d | |||
368184e24f | |||
c8e73d3f76 | |||
43da4955b7 | |||
46e9d5f758 | |||
66a012b555 | |||
fff965ab9b | |||
406adde549 | |||
c9b2699c9f | |||
f91d3e35f3 | |||
4712ba9f2d | |||
03b2f2a433 | |||
51b1a6e679 | |||
f148e5a580 | |||
079f945f38 | |||
29cc7e4676 | |||
11c97fd4c0 | |||
a5cb989c59 | |||
3d77a7cbc9 | |||
8e7401955f | |||
fa605768e7 | |||
3c279edd31 | |||
a736d6d77b | |||
8ad118162e | |||
5c13bb20d7 | |||
170d36fc05 | |||
b828edf3c7 | |||
e10dfaefe9 | |||
49e1a85afb | |||
56dfe8baa8 | |||
95685fe91f | |||
8f6b4cc551 | |||
89c9733ed2 | |||
ec29ec76f0 | |||
0f97e3d7ed | |||
6fb5cedd69 | |||
0382af1fae | |||
b24b68a6bd | |||
952da0f314 | |||
cb32dc99cd | |||
5e7a05c183 | |||
656b478cc0 | |||
fbbc0eb294 | |||
502c9d1db3 | |||
36934eedfd | |||
56f982e214 | |||
54c4cd53b3 | |||
1c4fc335b3 | |||
21d3f41b38 | |||
031ce236f3 | |||
a4eb073918 | |||
75ae868bde | |||
b6d9d58a14 | |||
14a5b8d9f2 | |||
ede68b563e | |||
33f4db254d | |||
6e8cb1bbb2 | |||
b00fb22137 | |||
4d74c2ede6 | |||
c4c5a640ce | |||
514fbca3f1 | |||
71a19e247f | |||
![]() |
bcab89dbfb | ||
f219c59ad5 | |||
197df696be | |||
c9b7f58f3d | |||
6b8371c32b | |||
11cdac0357 | |||
8b607ddefd | |||
10158bb444 | |||
1dd10450f2 | |||
e104499636 | |||
56cd1f211c | |||
14f4f1e80d | |||
52a0e8cf53 | |||
50450fe7fe | |||
4a4ffadc64 | |||
8807140c83 | |||
adc811efa1 | |||
d8fed884d0 | |||
d75f59ba06 | |||
aa0a395353 | |||
56d84dea4d | |||
3aa2ece59b | |||
07239d2a75 | |||
3fd5e15e93 | |||
97d56b0314 | |||
c18554dfbd | |||
8105e00b39 | |||
7e32fab5d4 | |||
25298c9be6 | |||
e61549d917 | |||
eca14a644b | |||
3937121522 | |||
b334db28c6 | |||
b52057e317 | |||
414ab85e20 | |||
82133a8f16 | |||
43a63d4f6e | |||
9f9fc7d65b | |||
79d395e01c | |||
394259fe21 | |||
8c256c629b | |||
0e2d86ac96 | |||
e2a1e6730d | |||
a1e923f999 | |||
09333c992c | |||
80eb385c64 |
@@ -3,6 +3,7 @@ keys:
|
||||
- &user_lappy_colin age1j2pqnl8j0krdzk6npe93s4nnqrzwx978qrc0u570gzlamqpnje9sc8le2g
|
||||
- &user_servo_colin age1z8fauff34cdecr6sjkre260luzxcca05kpcwvhx988d306tpcejsp63znu
|
||||
- &user_moby_colin age1zsrsvd7j6l62fjxpfd2qnhqlk8wk4p8r0dtxpe4sdgnh2474095qdu7xj9
|
||||
- &host_crappy age1hl50ufuxnqy0jnk8fqeu4tclh4vte2xn2d59pxff0gun20vsmv5sp78chj
|
||||
- &host_desko age1vnw7lnfpdpjn62l3u5nyv5xt2c965k96p98kc43mcnyzpetrts9q54mc9v
|
||||
- &host_lappy age1w7mectcjku6x3sd8plm8wkn2qfrhv9n6zhzlf329e2r2uycgke8qkf9dyn
|
||||
- &host_servo age1tzlyex2z6t88tg9h82943e39shxhmqeyr7ywhlwpdjmyqsndv3qq27x0rf
|
||||
@@ -15,6 +16,7 @@ creation_rules:
|
||||
- *user_lappy_colin
|
||||
- *user_servo_colin
|
||||
- *user_moby_colin
|
||||
- *host_crappy
|
||||
- *host_desko
|
||||
- *host_lappy
|
||||
- *host_servo
|
||||
|
25
README.md
25
README.md
@@ -2,6 +2,8 @@
|
||||
|
||||
# .❄️≡We|_c0m3 7o m`/ f14k≡❄️.
|
||||
|
||||
(er, it's not a flake anymore. welcome to my nix files.)
|
||||
|
||||
## What's Here
|
||||
|
||||
this is the top-level repo from which i configure/deploy all my NixOS machines:
|
||||
@@ -29,11 +31,7 @@ you might specifically be interested in these files (elaborated further in #key-
|
||||
|
||||
## Using This Repo In Your Own Config
|
||||
|
||||
this should be a pretty "standard" flake. just reference it, and import either
|
||||
- `nixosModules.sane` (for the modules)
|
||||
- `overlays.pkgs` (for the packages)
|
||||
|
||||
or follow the instructions [here][NUR] to use it via the Nix User Repositories.
|
||||
follow the instructions [here][NUR] to access my packages through the Nix User Repositories.
|
||||
|
||||
[NUR]: https://nur.nix-community.org/
|
||||
|
||||
@@ -41,19 +39,15 @@ or follow the instructions [here][NUR] to use it via the Nix User Repositories.
|
||||
- `doc/`
|
||||
- instructions for tasks i find myself doing semi-occasionally in this repo.
|
||||
- `hosts/`
|
||||
- the bulk of config which isn't factored with external use in mind.
|
||||
- configs which aren't factored with external use in mind.
|
||||
- that is, if you were to add this repo to a flake.nix for your own use,
|
||||
you won't likely be depending on anything in this directory.
|
||||
- `integrations/`
|
||||
- code intended for consumption by external tools (e.g. the Nix User Repos)
|
||||
- code intended for consumption by external tools (e.g. the Nix User Repos).
|
||||
- `modules/`
|
||||
- config which is gated behind `enable` flags, in similar style to nixpkgs'
|
||||
`nixos/` directory.
|
||||
- if you depend on this repo, it's most likely for something in this directory.
|
||||
- `nixpatches/`
|
||||
- literally, diffs i apply atop upstream nixpkgs before performing further eval.
|
||||
- config which is gated behind `enable` flags, in similar style to nixpkgs' `nixos/` directory.
|
||||
- if you depend on this repo for anything besides packages, it's most likely for something in this directory.
|
||||
- `overlays/`
|
||||
- exposed via the `overlays` output in `flake.nix`.
|
||||
- predominantly a list of `callPackage` directives.
|
||||
- `pkgs/`
|
||||
- derivations for things not yet packaged in nixpkgs.
|
||||
@@ -61,13 +55,12 @@ or follow the instructions [here][NUR] to use it via the Nix User Repositories.
|
||||
- inline code for wholly custom packages (e.g. `pkgs/additional/sane-scripts/` for CLI tools
|
||||
that are highly specific to my setup).
|
||||
- `scripts/`
|
||||
- scripts which aren't reachable on a deployed system, but may aid manual deployments
|
||||
- scripts which aren't reachable on a deployed system, but may aid manual deployments.
|
||||
- `secrets/`
|
||||
- encrypted keys, API tokens, anything which one or more of my machines needs
|
||||
read access to but shouldn't be world-readable.
|
||||
- not much to see here
|
||||
- not much to see here.
|
||||
- `templates/`
|
||||
- exposed via the `templates` output in `flake.nix`.
|
||||
- used to instantiate short-lived environments.
|
||||
- used to auto-fill the boiler-plate portions of new packages.
|
||||
|
||||
|
15
TODO.md
15
TODO.md
@@ -2,7 +2,6 @@
|
||||
- `rmDbusServices` may break sandboxing
|
||||
- e.g. if the package ships a systemd unit which references $out, then make-sandboxed won't properly update that unit.
|
||||
- `rmDbusServicesInPlace` is not affected
|
||||
- moby: touchscreen input is still enabled when screen is off
|
||||
- when moby wlan is explicitly set down (via ip link set wlan0 down), /var/lib/trust-dns/dhcp-configs doesn't get reset
|
||||
- `ip monitor` can detect those manual link state changes (NM-dispatcher it seems cannot)
|
||||
- or try dnsmasq?
|
||||
@@ -25,6 +24,8 @@
|
||||
- moby: bpf is effectively disabled?
|
||||
- `dmesg | grep 'systemd[1]: bpf-lsm: Failed to load BPF object: No such process'`
|
||||
- `dmesg | grep 'hid_bpf: error while preloading HID BPF dispatcher: -22'`
|
||||
- `s6` is not re-entrant
|
||||
- so if the desktop crashes, the login process from `unl0kr` fails to re-launch the GUI
|
||||
|
||||
## REFACTORING:
|
||||
- add import checks to my Python nix-shell scripts
|
||||
@@ -78,22 +79,21 @@
|
||||
- it adds like 50-70ms launch time _on my laptop_. i'd hate to know how much that is on the pinephone.
|
||||
- make dconf stuff less monolithic
|
||||
- i.e. per-app dconf profiles for those which need it. possible static config.
|
||||
- flatpak/spectrum has some stuff to proxy dconf per-app
|
||||
- canaries for important services
|
||||
- e.g. daily email checks; daily backup checks
|
||||
- integrate `nix check` into Gitea actions?
|
||||
|
||||
#### sudo-free world
|
||||
- `systemctl restart FOO`: needs `sudo`
|
||||
- `systemctl daemon-reload`: needs sudo
|
||||
- `watch ifconfig`: needs `SANEBOX_DISABLE=1`
|
||||
|
||||
### user experience
|
||||
- rofi: sort items case-insensitively
|
||||
- xdg-desktop-portal shouldn't kill children on exit
|
||||
- *maybe* a job for `setsid -f`?
|
||||
- replace starship prompt with something more efficient
|
||||
- watch `forkstat`: it does way too much
|
||||
- cleanup waybar so that it's not invoking playerctl every 2 seconds
|
||||
- cleanup waybar/nwg-panel so that it's not invoking playerctl every 2 seconds
|
||||
- nwg-panel: swaync icon is stuck as the refresh icon
|
||||
- nwg-panel: doesn't appear on all desktops
|
||||
- nwg-panel: doesn't know that virtual-desktop 10/TV exists
|
||||
- install apps:
|
||||
- display QR codes for WiFi endpoints: <https://linuxphoneapps.org/apps/noappid.wisperwind.wifi2qr/>
|
||||
- shopping list (not in nixpkgs): <https://linuxphoneapps.org/apps/ro.hume.cosmin.shoppinglist/>
|
||||
@@ -103,6 +103,7 @@
|
||||
- Gnome Highscore (retro games)?: <https://gitlab.gnome.org/World/highscore>
|
||||
- better maps for mobile (Osmin (QtQuick)? Pure Maps (Qt/Kirigami)?
|
||||
- note-taking app: <https://linuxphoneapps.org/categories/note-taking/>
|
||||
- Folio is nice, uses standard markdown, though it only supports flat repos
|
||||
- OSK overlay specifically for mobile gaming
|
||||
- i.e. mock joysticks, for use with SuperTux and SuperTuxKart
|
||||
- install mobile-friendly games:
|
||||
|
66
default.nix
66
default.nix
@@ -3,7 +3,65 @@
|
||||
#
|
||||
# the primary purpose of this file is so i can run `updateScript`s which expect
|
||||
# the root to be `default.nix`
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
pkgs.appendOverlays [
|
||||
(import ./overlays/all.nix)
|
||||
]
|
||||
{ }:
|
||||
let
|
||||
mkPkgs = args: (import ./pkgs/additional/nixpkgs args).extend
|
||||
(import ./overlays/all.nix);
|
||||
inherit (mkPkgs {}) lib;
|
||||
|
||||
evalHost = { name, system, branch ? "master", variant ? null }:
|
||||
let
|
||||
pkgs = mkPkgs { inherit system; variant = branch; };
|
||||
in pkgs.nixos (
|
||||
[
|
||||
(lib.optionalAttrs (variant == "light") {
|
||||
sane.maxBuildCost = 2;
|
||||
})
|
||||
(lib.optionalAttrs (variant == "min") {
|
||||
sane.maxBuildCost = 0;
|
||||
})
|
||||
(import ./hosts/instantiate.nix { hostName = name; })
|
||||
(import ./modules)
|
||||
pkgs.sops-nix.nixosModules.sops
|
||||
]
|
||||
);
|
||||
mkFlavoredHost = args: let
|
||||
host = evalHost args;
|
||||
# expose the toplevel nixos system as the toplevel attribute itself,
|
||||
# with nested aliases for other common build targets
|
||||
in host.config.system.build.toplevel.overrideAttrs (base: {
|
||||
passthru = (base.passthru or {}) // {
|
||||
config = host.config;
|
||||
fs = host.config.sane.fs;
|
||||
img = host.config.system.build.img;
|
||||
pkgs = host.config.system.build.pkgs;
|
||||
programs = lib.mapAttrs (_: p: p.package) host.config.sane.programs;
|
||||
toplevel = host.config.system.build.toplevel; #< self
|
||||
};
|
||||
});
|
||||
mkHost = args: {
|
||||
# TODO: swap order: $host-{next,staging}-{min,light}:
|
||||
# then lexicographically-adjacent targets would also have the minimal difference in closure,
|
||||
# and the order in which each target should be built is more evident
|
||||
"${args.name}" = mkFlavoredHost args;
|
||||
"${args.name}-next" = mkFlavoredHost args // { branch = "staging-next"; };
|
||||
"${args.name}-staging" = mkFlavoredHost args // { branch = "staging"; };
|
||||
"${args.name}-light" = mkFlavoredHost args // { variant = "light"; };
|
||||
"${args.name}-light-next" = mkFlavoredHost args // { variant = "light"; branch = "staging-next"; };
|
||||
"${args.name}-light-staging" = mkFlavoredHost args // { variant = "light"; branch = "staging"; };
|
||||
"${args.name}-min" = mkFlavoredHost args // { variant = "min"; };
|
||||
"${args.name}-min-next" = mkFlavoredHost args // { variant = "min"; branch = "staging-next"; };
|
||||
"${args.name}-min-staging" = mkFlavoredHost args // { variant = "min"; branch = "staging-staging"; };
|
||||
};
|
||||
|
||||
hosts = lib.foldl' (acc: host: acc // (mkHost host)) {} [
|
||||
{ name = "crappy"; system = "armv7l-linux"; }
|
||||
{ name = "desko"; system = "x86_64-linux"; }
|
||||
{ name = "lappy"; system = "x86_64-linux"; }
|
||||
{ name = "moby"; system = "aarch64-linux"; }
|
||||
{ name = "rescue"; system = "x86_64-linux"; }
|
||||
{ name = "servo"; system = "x86_64-linux"; }
|
||||
];
|
||||
in {
|
||||
inherit hosts;
|
||||
} // (mkPkgs {})
|
||||
|
25
doc/adding-a-host.md
Normal file
25
doc/adding-a-host.md
Normal file
@@ -0,0 +1,25 @@
|
||||
to add a host:
|
||||
- create the new nix targets
|
||||
- hosts/by-name/HOST
|
||||
- let the toplevel (flake.nix) know about HOST
|
||||
- build and flash an image
|
||||
- optionally expand the rootfs
|
||||
- `cfdisk /dev/sda2` -> resize partition
|
||||
- `mount /dev/sda2 boot`
|
||||
- `btrfs filesystem resize max root`
|
||||
- setup required persistent directories
|
||||
- `mkdir -p root/persist/private`
|
||||
- `gocryptfs -init root/persist/private`
|
||||
- then boot the device, and for every dangling symlink in ~/.local/share, ~/.cache, do `mkdir -p` on it
|
||||
- setup host ssh
|
||||
- `mkdir -p root/persist/plaintext/etc/ssh/host_keys`
|
||||
- boot the machine and let it create its own ssh keys
|
||||
- add the pubkey to `hosts/common/hosts.nix`
|
||||
- setup user ssh
|
||||
- `ssh-keygen`. don't enter any password; it's stored in a password-encrypted fs.
|
||||
- add the pubkey to `hosts/common/hosts.nix`
|
||||
- allow the new host to view secrets
|
||||
- instructions in hosts/common/secrets.nix
|
||||
- run `ssh-to-age` on user/host pubkeys
|
||||
- add age key to .sops.yaml
|
||||
- update encrypted secrets: `sops updatekeys path/to/secret.yaml`
|
12
doc/recovery.md
Normal file
12
doc/recovery.md
Normal file
@@ -0,0 +1,12 @@
|
||||
## deploying to SD card
|
||||
- build a toplevel config: `nix build '.#hostSystems.moby'`
|
||||
- mount a system:
|
||||
- `mkdir -p root/{nix,boot}`
|
||||
- `mount /dev/sdX1 root/boot`
|
||||
- `mount /dev/sdX2 root/nix`
|
||||
- copy the config:
|
||||
- `sudo nix copy --no-check-sigs --to root/ $(readlink result)`
|
||||
- nix will copy stuff to `root/nix/store`
|
||||
- install the boot files:
|
||||
- `sudo /nix/store/sbwpwngjlgw4f736ay9hgi69pj3fdwk5-extlinux-conf-builder.sh -d ./root/boot -t 5 -c $(readlink ./result)`
|
||||
- extlinux-conf-builder can be found in `/run/current-system/bin/switch-to-configuration`
|
330
flake.lock
generated
330
flake.lock
generated
@@ -1,330 +0,0 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-compat": {
|
||||
"locked": {
|
||||
"lastModified": 1688025799,
|
||||
"narHash": "sha256-ktpB4dRtnksm9F5WawoIkEneh1nrEvuxb5lJFt1iOyw=",
|
||||
"owner": "nix-community",
|
||||
"repo": "flake-compat",
|
||||
"rev": "8bf105319d44f6b9f0d764efa4fdef9f1cc9ba1c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": [
|
||||
"nixpkgs-wayland",
|
||||
"nix-eval-jobs",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712014858,
|
||||
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"lib-aggregate": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716725378,
|
||||
"narHash": "sha256-bNTVDAVBLFSSTU+q54cJnntmFKBi+F/D8sSqlZwBGiM=",
|
||||
"owner": "nix-community",
|
||||
"repo": "lib-aggregate",
|
||||
"rev": "dbc9130fe1455e0f6ee4d8f5f799f9be551f866b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "lib-aggregate",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"mobile-nixos": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1694749521,
|
||||
"narHash": "sha256-MiVokKlpcJmfoGuWAMeW1En7gZ5hk0rCQArYm6P9XCc=",
|
||||
"owner": "nixos",
|
||||
"repo": "mobile-nixos",
|
||||
"rev": "d25d3b87e7f300d8066e31d792337d9cd7ecd23b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "d25d3b87e7f300d8066e31d792337d9cd7ecd23b",
|
||||
"repo": "mobile-nixos",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-eval-jobs": {
|
||||
"inputs": {
|
||||
"flake-parts": "flake-parts",
|
||||
"nix-github-actions": "nix-github-actions",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1715804156,
|
||||
"narHash": "sha256-GtIHP86Cz1kD9xZO/cKbNQACHKdoT9WFbLJAq6W2EDY=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-eval-jobs",
|
||||
"rev": "bb95091f6c6f38f6cfc215a1797a2dd466312c8b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-eval-jobs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-github-actions": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs-wayland",
|
||||
"nix-eval-jobs",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1703863825,
|
||||
"narHash": "sha256-rXwqjtwiGKJheXB43ybM8NwWB8rO2dSRrEqes0S7F5Y=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-github-actions",
|
||||
"rev": "5163432afc817cf8bd1f031418d1869e4c9d5547",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-github-actions",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1715037484,
|
||||
"narHash": "sha256-OUt8xQFmBU96Hmm4T9tOWTu4oCswCzoVl+pxSq/kiFc=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ad7efee13e0d216bf29992311536fce1d3eefbef",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"lastModified": 1716684580,
|
||||
"narHash": "sha256-sIbMJWJr4hl2PWd9/iWlh89QfVzBn1NJ3u5RjeZADuM=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"rev": "d0d27192931680482081aa1c38389da2af84a651",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-next-unpatched": {
|
||||
"locked": {
|
||||
"lastModified": 1717372940,
|
||||
"narHash": "sha256-fK1PJqC8kQOy8rD7B+qmJOTx9IV8AOmFtH5Z/ip7340=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "c987c730bbf2121264ebd68921b443db5bb28543",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "staging-next",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1717265169,
|
||||
"narHash": "sha256-IITcGd6xpNoyq9SZBigCkv4+qMHSqot0RDPR4xsZ2CA=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "3b1b4895b2c5f9f5544d02132896aeb9ceea77bc",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "release-23.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-unpatched": {
|
||||
"locked": {
|
||||
"lastModified": 1717392304,
|
||||
"narHash": "sha256-i9Kh2ty++/xMj4GPTMI7vQrpH4jopjT4BUq2GKX1zug=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "77a51024c0f953d503eb3ed364aa4bff378649f8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "master",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-wayland": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"lib-aggregate": "lib-aggregate",
|
||||
"nix-eval-jobs": "nix-eval-jobs",
|
||||
"nixpkgs": [
|
||||
"nixpkgs-unpatched"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1717175759,
|
||||
"narHash": "sha256-KiM5ue/UNQt8ktoqCV4yFqhHxM31U94Mf/piKW9dZ4c=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs-wayland",
|
||||
"rev": "93b225ddba91179248b378913a91defbc6aeb899",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs-wayland",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"mobile-nixos": "mobile-nixos",
|
||||
"nixpkgs-next-unpatched": "nixpkgs-next-unpatched",
|
||||
"nixpkgs-unpatched": "nixpkgs-unpatched",
|
||||
"nixpkgs-wayland": "nixpkgs-wayland",
|
||||
"sops-nix": "sops-nix",
|
||||
"uninsane-dot-org": "uninsane-dot-org"
|
||||
}
|
||||
},
|
||||
"sops-nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs-unpatched"
|
||||
],
|
||||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1717297459,
|
||||
"narHash": "sha256-cZC2f68w5UrJ1f+2NWGV9Gx0dEYmxwomWN2B0lx0QRA=",
|
||||
"owner": "Mic92",
|
||||
"repo": "sops-nix",
|
||||
"rev": "ab2a43b0d21d1d37d4d5726a892f714eaeb4b075",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "Mic92",
|
||||
"repo": "sops-nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"treefmt-nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs-wayland",
|
||||
"nix-eval-jobs",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1711963903,
|
||||
"narHash": "sha256-N3QDhoaX+paWXHbEXZapqd1r95mdshxToGowtjtYkGI=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "49dc4a92b02b8e68798abd99184f228243b6e3ac",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"uninsane-dot-org": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs-unpatched"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1715894399,
|
||||
"narHash": "sha256-h1EdA/h74zgNPNEYbH+0mgOMlJgLVcxuZ8/ewsZlgEc=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "e6f88f563bdd1700c04018951de4f69862646dd1",
|
||||
"revCount": 240,
|
||||
"type": "git",
|
||||
"url": "https://git.uninsane.org/colin/uninsane"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.uninsane.org/colin/uninsane"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
655
flake.nix
655
flake.nix
@@ -1,655 +0,0 @@
|
||||
# FLAKE FEEDBACK:
|
||||
# - if flake inputs are meant to be human-readable, a human should be able to easily track them down given the URL.
|
||||
# - this is not the case with registry URLs, like `nixpkgs/nixos-22.11`.
|
||||
# - this is marginally the case with schemes like `github:nixos/nixpkgs`.
|
||||
# - given the *existing* `git+https://` scheme, i propose expressing github URLs similarly:
|
||||
# - `github+https://github.com/nixos/nixpkgs/tree/nixos-22.11`
|
||||
# - this would allow for the same optimizations as today's `github:nixos/nixpkgs`, but without obscuring the source.
|
||||
# a code reader could view the source being referenced simply by clicking the https:// portion of that URI.
|
||||
# - need some way to apply local patches to inputs.
|
||||
#
|
||||
#
|
||||
# DEVELOPMENT DOCS:
|
||||
# - Flake docs: <https://nixos.wiki/wiki/Flakes>
|
||||
# - Flake RFC: <https://github.com/tweag/rfcs/blob/flakes/rfcs/0049-flakes.md>
|
||||
# - Discussion: <https://github.com/NixOS/rfcs/pull/49>
|
||||
# - <https://serokell.io/blog/practical-nix-flakes>
|
||||
#
|
||||
#
|
||||
# COMMON OPERATIONS:
|
||||
# - update a specific flake input:
|
||||
# - `nix flake lock --update-input nixpkgs`
|
||||
|
||||
{
|
||||
# XXX: use the `github:` scheme instead of the more readable git+https: because it's *way* more efficient
|
||||
# preferably, i would rewrite the human-readable https URLs to nix-specific github: URLs with a helper,
|
||||
# but `inputs` is required to be a strict attrset: not an expression.
|
||||
inputs = {
|
||||
# branch workflow:
|
||||
# - daily:
|
||||
# - nixos-unstable cut from master after enough packages have been built in caches.
|
||||
# - every 6 hours:
|
||||
# - master auto-merged into staging and staging-next
|
||||
# - staging-next auto-merged into staging.
|
||||
# - manually, approximately once per month:
|
||||
# - staging-next is cut from staging.
|
||||
# - staging-next merged into master.
|
||||
#
|
||||
# which branch to source from?
|
||||
# - nixos-unstable: for everyday development; it provides good caching
|
||||
# - master: temporarily if i'm otherwise cherry-picking lots of already-applied patches
|
||||
# - staging-next: if testing stuff that's been PR'd into staging, i.e. base library updates.
|
||||
# - staging: maybe if no staging-next -> master PR has been cut yet?
|
||||
#
|
||||
# <https://github.com/nixos/nixpkgs/tree/nixos-unstable>
|
||||
# nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||
nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=master";
|
||||
# nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=nixos-staging";
|
||||
# nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=nixos-staging-next";
|
||||
nixpkgs-next-unpatched.url = "github:nixos/nixpkgs?ref=staging-next";
|
||||
|
||||
nixpkgs-wayland = {
|
||||
url = "github:nix-community/nixpkgs-wayland";
|
||||
inputs.nixpkgs.follows = "nixpkgs-unpatched";
|
||||
};
|
||||
|
||||
mobile-nixos = {
|
||||
# <https://github.com/nixos/mobile-nixos>
|
||||
# only used for building disk images, not relevant after deployment
|
||||
# TODO: replace with something else. commit `0f3ac0bef1aea70254a3bae35e3cc2561623f4c1`
|
||||
# replaces the imageBuilder with a "new implementation from celun" and wildly breaks my use.
|
||||
# pinning to d25d3b... is equivalent to holding at 2023-09-15
|
||||
url = "github:nixos/mobile-nixos?ref=d25d3b87e7f300d8066e31d792337d9cd7ecd23b";
|
||||
flake = false;
|
||||
};
|
||||
sops-nix = {
|
||||
# <https://github.com/Mic92/sops-nix>
|
||||
# used to distribute secrets to my hosts
|
||||
url = "github:Mic92/sops-nix";
|
||||
# inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.nixpkgs.follows = "nixpkgs-unpatched";
|
||||
};
|
||||
uninsane-dot-org = {
|
||||
# provides the package to deploy <https://uninsane.org>, used only when building the servo host
|
||||
url = "git+https://git.uninsane.org/colin/uninsane";
|
||||
# inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.nixpkgs.follows = "nixpkgs-unpatched";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = {
|
||||
self,
|
||||
nixpkgs-unpatched,
|
||||
nixpkgs-next-unpatched ? nixpkgs-unpatched,
|
||||
nixpkgs-wayland,
|
||||
mobile-nixos,
|
||||
sops-nix,
|
||||
uninsane-dot-org,
|
||||
...
|
||||
}@inputs:
|
||||
let
|
||||
inherit (builtins) attrNames elem listToAttrs map mapAttrs;
|
||||
# redefine some nixpkgs `lib` functions to avoid the infinite recursion
|
||||
# of if we tried to use patched `nixpkgs.lib` as part of the patching process.
|
||||
mapAttrs' = f: set:
|
||||
listToAttrs (map (attr: f attr set.${attr}) (attrNames set));
|
||||
optionalAttrs = cond: attrs: if cond then attrs else {};
|
||||
# mapAttrs but without the `name` argument
|
||||
mapAttrValues = f: mapAttrs (_: f);
|
||||
|
||||
# rather than apply our nixpkgs patches as a flake input, do that here instead.
|
||||
# this (temporarily?) resolves the bad UX wherein a subflake residing in the same git
|
||||
# repo as the main flake causes the main flake to have an unstable hash.
|
||||
patchNixpkgs = variant: nixpkgs: (import ./nixpatches/flake.nix).outputs {
|
||||
inherit variant nixpkgs;
|
||||
self = patchNixpkgs variant nixpkgs;
|
||||
};
|
||||
|
||||
nixpkgs' = patchNixpkgs "master" nixpkgs-unpatched;
|
||||
nixpkgsCompiledBy = system: nixpkgs'.legacyPackages."${system}";
|
||||
|
||||
evalHost = { name, local, target, variant ? null, nixpkgs ? nixpkgs' }: nixpkgs.lib.nixosSystem {
|
||||
system = target;
|
||||
modules = [
|
||||
{
|
||||
nixpkgs.buildPlatform.system = local;
|
||||
}
|
||||
(optionalAttrs (local != target) {
|
||||
# XXX(2023/12/11): cache.nixos.org uses `system = ...` instead of `hostPlatform.system`, and that choice impacts the closure of every package.
|
||||
# so avoid specifying hostPlatform.system on non-cross builds, so i can use upstream caches.
|
||||
nixpkgs.hostPlatform.system = target;
|
||||
})
|
||||
(optionalAttrs (variant == "light") {
|
||||
sane.maxBuildCost = 2;
|
||||
})
|
||||
(optionalAttrs (variant == "min") {
|
||||
sane.maxBuildCost = 0;
|
||||
})
|
||||
(import ./hosts/instantiate.nix { hostName = name; })
|
||||
self.nixosModules.default
|
||||
self.nixosModules.passthru
|
||||
{
|
||||
nixpkgs.overlays = [
|
||||
self.overlays.passthru
|
||||
self.overlays.sane-all
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
in {
|
||||
nixosConfigurations = let
|
||||
hosts = {
|
||||
servo = { name = "servo"; local = "x86_64-linux"; target = "x86_64-linux"; };
|
||||
desko = { name = "desko"; local = "x86_64-linux"; target = "x86_64-linux"; };
|
||||
desko-light = { name = "desko"; local = "x86_64-linux"; target = "x86_64-linux"; variant = "light"; };
|
||||
lappy = { name = "lappy"; local = "x86_64-linux"; target = "x86_64-linux"; };
|
||||
lappy-light = { name = "lappy"; local = "x86_64-linux"; target = "x86_64-linux"; variant = "light"; };
|
||||
lappy-min = { name = "lappy"; local = "x86_64-linux"; target = "x86_64-linux"; variant = "min"; };
|
||||
moby = { name = "moby"; local = "x86_64-linux"; target = "aarch64-linux"; };
|
||||
moby-light = { name = "moby"; local = "x86_64-linux"; target = "aarch64-linux"; variant = "light"; };
|
||||
moby-min = { name = "moby"; local = "x86_64-linux"; target = "aarch64-linux"; variant = "min"; };
|
||||
rescue = { name = "rescue"; local = "x86_64-linux"; target = "x86_64-linux"; };
|
||||
};
|
||||
hostsNext = mapAttrs' (h: v: {
|
||||
name = "${h}-next";
|
||||
value = v // { nixpkgs = patchNixpkgs "staging-next" nixpkgs-next-unpatched; };
|
||||
}) hosts;
|
||||
in mapAttrValues evalHost (
|
||||
hosts // hostsNext
|
||||
);
|
||||
|
||||
# unofficial output
|
||||
# this produces a EFI-bootable .img file (GPT with a /boot partition and a system (/ or /nix) partition).
|
||||
# after building this:
|
||||
# - flash it to a bootable medium (SD card, flash drive, HDD)
|
||||
# - resize the root partition (use cfdisk)
|
||||
# - mount the part
|
||||
# - chown root:nixbld <part>/nix/store
|
||||
# - chown root:root -R <part>/nix/store/*
|
||||
# - chown root:root -R <part>/persist # if using impermanence
|
||||
# - populate any important things (persist/, home/colin/.ssh, etc)
|
||||
# - boot
|
||||
# - if fs wasn't resized automatically, then `sudo btrfs filesystem resize max /`
|
||||
# - checkout this flake into /etc/nixos AND UPDATE THE FS UUIDS.
|
||||
# - `nixos-rebuild --flake './#<host>' switch`
|
||||
imgs = mapAttrValues (host: host.config.system.build.img) self.nixosConfigurations;
|
||||
|
||||
# unofficial output
|
||||
hostConfigs = mapAttrValues (host: host.config) self.nixosConfigurations;
|
||||
hostSystems = mapAttrValues (host: host.config.system.build.toplevel) self.nixosConfigurations;
|
||||
hostPkgs = mapAttrValues (host: host.config.system.build.pkgs) self.nixosConfigurations;
|
||||
hostPrograms = mapAttrValues (host: mapAttrValues (p: p.package) host.config.sane.programs) self.nixosConfigurations;
|
||||
|
||||
patched.nixpkgs = nixpkgs';
|
||||
|
||||
overlays = {
|
||||
# N.B.: `nix flake check` requires every overlay to take `final: prev:` at defn site,
|
||||
# hence the weird redundancy.
|
||||
default = final: prev: self.overlays.pkgs final prev;
|
||||
sane-all = final: prev: import ./overlays/all.nix final prev;
|
||||
pkgs = final: prev: import ./overlays/pkgs.nix final prev;
|
||||
pins = final: prev: import ./overlays/pins.nix final prev;
|
||||
preferences = final: prev: import ./overlays/preferences.nix final prev;
|
||||
passthru = final: prev:
|
||||
let
|
||||
mobile = (import "${mobile-nixos}/overlay/overlay.nix");
|
||||
uninsane = uninsane-dot-org.overlays.default;
|
||||
wayland = final: prev: {
|
||||
# default is to dump the packages into `waylandPkgs` *and* the toplevel.
|
||||
# but i just want the `waylandPkgs` set
|
||||
inherit (nixpkgs-wayland.overlays.default final prev)
|
||||
waylandPkgs
|
||||
new-wayland-protocols #< 2024/03/10: nixpkgs-wayland assumes this will be in the toplevel
|
||||
;
|
||||
};
|
||||
in
|
||||
(mobile final prev)
|
||||
// (uninsane final prev)
|
||||
// (wayland final prev)
|
||||
;
|
||||
};
|
||||
|
||||
nixosModules = rec {
|
||||
default = sane;
|
||||
sane = import ./modules;
|
||||
passthru = { ... }: {
|
||||
imports = [
|
||||
sops-nix.nixosModules.sops
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# this includes both our native packages and all the nixpkgs packages.
|
||||
legacyPackages =
|
||||
let
|
||||
allPkgsFor = sys: (nixpkgsCompiledBy sys).appendOverlays [
|
||||
self.overlays.passthru self.overlays.pkgs
|
||||
];
|
||||
in {
|
||||
x86_64-linux = allPkgsFor "x86_64-linux";
|
||||
aarch64-linux = allPkgsFor "aarch64-linux";
|
||||
};
|
||||
|
||||
# extract only our own packages from the full set.
|
||||
# because of `nix flake check`, we flatten the package set and only surface x86_64-linux packages.
|
||||
packages = mapAttrs
|
||||
(system: passthruPkgs: passthruPkgs.lib.filterAttrs
|
||||
(name: pkg:
|
||||
# keep only packages which will pass `nix flake check`, i.e. keep only:
|
||||
# - derivations (not package sets)
|
||||
# - packages that build for the given platform
|
||||
(! elem name [ "feeds" "pythonPackagesExtensions" ])
|
||||
&& (passthruPkgs.lib.meta.availableOn passthruPkgs.stdenv.hostPlatform pkg)
|
||||
)
|
||||
(
|
||||
# expose sane packages and chosen inputs (uninsane.org)
|
||||
(import ./pkgs { pkgs = passthruPkgs; }) // {
|
||||
inherit (passthruPkgs) uninsane-dot-org;
|
||||
}
|
||||
)
|
||||
)
|
||||
# self.legacyPackages;
|
||||
{
|
||||
x86_64-linux = (nixpkgsCompiledBy "x86_64-linux").appendOverlays [
|
||||
self.overlays.passthru
|
||||
];
|
||||
}
|
||||
;
|
||||
|
||||
apps."x86_64-linux" =
|
||||
let
|
||||
pkgs = self.legacyPackages."x86_64-linux";
|
||||
sanePkgs = import ./pkgs { inherit pkgs; };
|
||||
deployScript = host: addr: action: pkgs.writeShellScript "deploy-${host}" ''
|
||||
set -e
|
||||
|
||||
host="${host}"
|
||||
addr="${addr}"
|
||||
action="${if action != null then action else ""}"
|
||||
runOnTarget() {
|
||||
# run the command ($@) on the machine we're deploying to.
|
||||
# if that's a remote machine, then do it via ssh, else local shell.
|
||||
if [ -n "$addr" ]; then
|
||||
ssh "$addr" "$@"
|
||||
else
|
||||
"$@"
|
||||
fi
|
||||
}
|
||||
|
||||
nix build ".#nixosConfigurations.$host.config.system.build.toplevel" --out-link "./build/result-$host" "$@"
|
||||
storePath="$(readlink ./build/result-$host)"
|
||||
|
||||
# mimic `nixos-rebuild --target-host`, in effect:
|
||||
# - nix-copy-closure ...
|
||||
# - nix-env --set ...
|
||||
# - switch-to-configuration <boot|dry-activate|switch|test|>
|
||||
# avoid the actual `nixos-rebuild` for a few reasons:
|
||||
# - fewer nix evals
|
||||
# - more introspectability and debuggability
|
||||
# - sandbox friendliness (especially: `git` doesn't have to be run as root)
|
||||
|
||||
if [ -n "$addr" ]; then
|
||||
sudo nix store sign -r -k /run/secrets/nix_signing_key "$storePath"
|
||||
# add more `-v` for more verbosity (up to 5).
|
||||
# builders-use-substitutes false: optimizes so that the remote machine doesn't try to get paths from its substituters.
|
||||
# we already have all paths here, and the remote substitution is slow to check and SERIOUSLY flaky on moby in particular.
|
||||
nix copy -vv --option builders-use-substitutes false --to "ssh-ng://$addr" "$storePath"
|
||||
fi
|
||||
|
||||
if [ -n "$action" ]; then
|
||||
runOnTarget sudo nix-env -p /nix/var/nix/profiles/system --set "$storePath"
|
||||
runOnTarget sudo "$storePath/bin/switch-to-configuration" "$action"
|
||||
fi
|
||||
'';
|
||||
deployApp = host: addr: action: {
|
||||
type = "app";
|
||||
program = ''${deployScript host addr action}'';
|
||||
};
|
||||
|
||||
# pkg updating.
|
||||
# a cleaner alternative lives here: <https://discourse.nixos.org/t/how-can-i-run-the-updatescript-of-personal-packages/25274/2>
|
||||
# mkUpdater :: [ String ] -> { type = "app"; program = path; }
|
||||
mkUpdater = attrPath: {
|
||||
type = "app";
|
||||
program = let
|
||||
pkg = pkgs.lib.getAttrFromPath attrPath sanePkgs;
|
||||
strAttrPath = pkgs.lib.concatStringsSep "." attrPath;
|
||||
commandArgv = pkg.updateScript.command or pkg.updateScript;
|
||||
command = pkgs.lib.escapeShellArgs commandArgv;
|
||||
in builtins.toString (pkgs.writeShellScript "update-${strAttrPath}" ''
|
||||
set -x
|
||||
env UPDATE_NIX_NAME=${pkg.name} UPDATE_NIX_PNAME=${pkg.pname} UPDATE_NIX_OLD_VERSION=${pkg.version} UPDATE_NIX_ATTR_PATH=${strAttrPath} ${command}
|
||||
'');
|
||||
};
|
||||
mkUpdatersNoAliases = opts: basePath: pkgs.lib.concatMapAttrs
|
||||
(name: pkg:
|
||||
if pkg.recurseForDerivations or false then {
|
||||
"${name}" = mkUpdaters opts (basePath ++ [ name ]);
|
||||
} else if pkg.updateScript or null != null then {
|
||||
"${name}" = mkUpdater (basePath ++ [ name ]);
|
||||
} else {}
|
||||
)
|
||||
(pkgs.lib.getAttrFromPath basePath sanePkgs);
|
||||
mkUpdaters = { ignore ? [], flakePrefix ? [] }@opts: basePath:
|
||||
let
|
||||
updaters = mkUpdatersNoAliases opts basePath;
|
||||
invokeUpdater = name: pkg:
|
||||
let
|
||||
fullPath = basePath ++ [ name ];
|
||||
doUpdateByDefault = !builtins.elem fullPath ignore;
|
||||
|
||||
# in case `name` has a `.` in it, we have to quote it
|
||||
escapedPath = builtins.map (p: ''"${p}"'') fullPath;
|
||||
updatePath = builtins.concatStringsSep "." (flakePrefix ++ escapedPath);
|
||||
in pkgs.lib.optionalString doUpdateByDefault (
|
||||
pkgs.lib.escapeShellArgs [
|
||||
"nix" "run" ".#${updatePath}"
|
||||
]
|
||||
);
|
||||
in {
|
||||
type = "app";
|
||||
# top-level app just invokes the updater of everything one layer below it
|
||||
program = builtins.toString (pkgs.writeShellScript
|
||||
(builtins.concatStringsSep "-" (flakePrefix ++ basePath))
|
||||
(builtins.concatStringsSep
|
||||
"\n"
|
||||
(pkgs.lib.mapAttrsToList invokeUpdater updaters)
|
||||
)
|
||||
);
|
||||
} // updaters;
|
||||
in {
|
||||
help = {
|
||||
type = "app";
|
||||
program = let
|
||||
helpMsg = builtins.toFile "nixos-config-help-message" ''
|
||||
commands:
|
||||
- `nix run '.#help'`
|
||||
- show this message
|
||||
- `nix run '.#update.pkgs'`
|
||||
- updates every package
|
||||
- `nix run '.#update.feeds'`
|
||||
- updates metadata for all feeds
|
||||
- `nix run '.#init-feed' <url>`
|
||||
- `nix run '.#deploy.{desko,lappy,moby,servo}[-light|-test]' [nix args ...]`
|
||||
- build and deploy the host
|
||||
- `nix run '.#preDeploy.{desko,lappy,moby,servo}[-light]' [nix args ...]`
|
||||
- copy closures to a host, but don't activate it
|
||||
- or `nix run '.#preDeploy'` to target all hosts
|
||||
- `nix run '.#check'`
|
||||
- make sure all systems build; NUR evaluates
|
||||
- `nix run '.#bench'`
|
||||
- benchmark the eval time of common targets this flake provides
|
||||
|
||||
specific build targets of interest:
|
||||
- `nix build '.#imgs.rescue'`
|
||||
'';
|
||||
in builtins.toString (pkgs.writeShellScript "nixos-config-help" ''
|
||||
cat ${helpMsg}
|
||||
echo ""
|
||||
echo "complete flake structure:"
|
||||
nix flake show --option allow-import-from-derivation true
|
||||
'');
|
||||
};
|
||||
# wrangle some names to get package updaters which refer back into the flake, but also conditionally ignore certain paths (e.g. sane.feeds).
|
||||
# TODO: better design
|
||||
update = rec {
|
||||
_impl.pkgs.sane = mkUpdaters { flakePrefix = [ "update" "_impl" "pkgs" ]; ignore = [ [ "sane" "feeds" ] ]; } [ "sane" ];
|
||||
pkgs = _impl.pkgs.sane;
|
||||
_impl.feeds.sane.feeds = mkUpdaters { flakePrefix = [ "update" "_impl" "feeds" ]; } [ "sane" "feeds" ];
|
||||
feeds = _impl.feeds.sane.feeds;
|
||||
};
|
||||
|
||||
init-feed = {
|
||||
type = "app";
|
||||
program = "${pkgs.feeds.init-feed}";
|
||||
};
|
||||
|
||||
deploy = {
|
||||
desko = deployApp "desko" "desko" "switch";
|
||||
desko-light = deployApp "desko-light" "desko" "switch";
|
||||
lappy = deployApp "lappy" "lappy" "switch";
|
||||
lappy-light = deployApp "lappy-light" "lappy" "switch";
|
||||
lappy-min = deployApp "lappy-min" "lappy" "switch";
|
||||
moby = deployApp "moby" "moby" "switch";
|
||||
moby-light = deployApp "moby-light" "moby" "switch";
|
||||
moby-min = deployApp "moby-min" "moby" "switch";
|
||||
moby-test = deployApp "moby" "moby" "test";
|
||||
servo = deployApp "servo" "servo" "switch";
|
||||
|
||||
# like `nixos-rebuild --flake . switch`
|
||||
self = deployApp "$(hostname)" "" "switch";
|
||||
self-light = deployApp "$(hostname)-light" "" "switch";
|
||||
self-min = deployApp "$(hostname)-min" "" "switch";
|
||||
|
||||
type = "app";
|
||||
program = builtins.toString (pkgs.writeShellScript "deploy-all" ''
|
||||
nix run '.#deploy.lappy'
|
||||
nix run '.#deploy.moby'
|
||||
nix run '.#deploy.desko'
|
||||
nix run '.#deploy.servo'
|
||||
'');
|
||||
};
|
||||
preDeploy = {
|
||||
# build the host and copy the runtime closure to that host, but don't activate it.
|
||||
desko = deployApp "desko" "desko" null;
|
||||
desko-light = deployApp "desko-light" "desko" null;
|
||||
lappy = deployApp "lappy" "lappy" null;
|
||||
lappy-light = deployApp "lappy-light" "lappy" null;
|
||||
lappy-min = deployApp "lappy-min" "lappy" null;
|
||||
moby = deployApp "moby" "moby" null;
|
||||
moby-light = deployApp "moby-light" "moby" null;
|
||||
moby-min = deployApp "moby-min" "moby" null;
|
||||
servo = deployApp "servo" "servo" null;
|
||||
type = "app";
|
||||
program = builtins.toString (pkgs.writeShellScript "predeploy-all" ''
|
||||
# copy the -min/-light variants first; this might be run while waiting on a full build. or the full build failed.
|
||||
nix run '.#preDeploy.moby-min' -- "$@"
|
||||
nix run '.#preDeploy.lappy-min' -- "$@"
|
||||
nix run '.#preDeploy.moby-light' -- "$@"
|
||||
nix run '.#preDeploy.lappy-light' -- "$@"
|
||||
nix run '.#preDeploy.desko-light' -- "$@"
|
||||
nix run '.#preDeploy.lappy' -- "$@"
|
||||
nix run '.#preDeploy.servo' -- "$@"
|
||||
nix run '.#preDeploy.moby' -- "$@"
|
||||
nix run '.#preDeploy.desko' -- "$@"
|
||||
'');
|
||||
};
|
||||
|
||||
sync = {
|
||||
type = "app";
|
||||
program = builtins.toString (pkgs.writeShellScript "sync-all" ''
|
||||
RC_lappy=$(nix run '.#sync.lappy' -- "$@")
|
||||
RC_moby=$(nix run '.#sync.moby' -- "$@")
|
||||
RC_desko=$(nix run '.#sync.desko' -- "$@")
|
||||
|
||||
echo "lappy: $RC_lappy"
|
||||
echo "moby: $RC_moby"
|
||||
echo "desko: $RC_desko"
|
||||
'');
|
||||
};
|
||||
|
||||
sync.desko = {
|
||||
# copy music from servo to desko
|
||||
# can run this from any device that has ssh access to desko and servo
|
||||
type = "app";
|
||||
program = builtins.toString (pkgs.writeShellScript "sync-to-desko" ''
|
||||
sudo mount /mnt/desko/home
|
||||
${pkgs.sane-scripts.sync-music}/bin/sane-sync-music --compat /mnt/servo/media/Music /mnt/desko/home/Music "$@"
|
||||
'');
|
||||
};
|
||||
|
||||
sync.lappy = {
|
||||
# copy music from servo to lappy
|
||||
# can run this from any device that has ssh access to lappy and servo
|
||||
type = "app";
|
||||
program = builtins.toString (pkgs.writeShellScript "sync-to-lappy" ''
|
||||
sudo mount /mnt/lappy/home
|
||||
${pkgs.sane-scripts.sync-music}/bin/sane-sync-music --compress --compat /mnt/servo/media/Music /mnt/lappy/home/Music "$@"
|
||||
'');
|
||||
};
|
||||
|
||||
sync.moby = {
|
||||
# copy music from servo to moby
|
||||
# can run this from any device that has ssh access to moby and servo
|
||||
type = "app";
|
||||
program = builtins.toString (pkgs.writeShellScript "sync-to-moby" ''
|
||||
sudo mount /mnt/moby/home
|
||||
sudo mount /mnt/desko/home
|
||||
${pkgs.rsync}/bin/rsync -arv --exclude servo-macros /mnt/moby/home/Pictures/ /mnt/desko/home/Pictures/moby/
|
||||
# N.B.: limited by network/disk -> reduce job count to improve pause/resume behavior
|
||||
${pkgs.sane-scripts.sync-music}/bin/sane-sync-music --compress --compat --jobs 4 /mnt/servo/media/Music /mnt/moby/home/Music "$@"
|
||||
'');
|
||||
};
|
||||
|
||||
check = {
|
||||
type = "app";
|
||||
program = builtins.toString (pkgs.writeShellScript "check-all" ''
|
||||
nix run '.#check.nur'
|
||||
RC0=$?
|
||||
nix run '.#check.hostConfigs'
|
||||
RC1=$?
|
||||
nix run '.#check.rescue'
|
||||
RC2=$?
|
||||
echo "nur: $RC0"
|
||||
echo "hostConfigs: $RC1"
|
||||
echo "rescue: $RC2"
|
||||
exit $(($RC0 | $RC1 | $RC2))
|
||||
'');
|
||||
};
|
||||
|
||||
check.nur = {
|
||||
# `nix run '.#check-nur'`
|
||||
# validates that my repo can be included in the Nix User Repository
|
||||
type = "app";
|
||||
program = builtins.toString (pkgs.writeShellScript "check-nur" ''
|
||||
cd ${./.}/integrations/nur
|
||||
NIX_PATH= NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1 nix-env -f . -qa \* --meta --xml \
|
||||
--allowed-uris https://static.rust-lang.org \
|
||||
--option restrict-eval true \
|
||||
--option allow-import-from-derivation true \
|
||||
--drv-path --show-trace \
|
||||
-I nixpkgs=${nixpkgs-unpatched} \
|
||||
-I nixpkgs-overlays=${./.}/hosts/common/nix/overlay \
|
||||
-I ../../ \
|
||||
| tee # tee to prevent interactive mode
|
||||
'');
|
||||
};
|
||||
|
||||
check.hostConfigs = {
|
||||
type = "app";
|
||||
program = let
|
||||
checkHost = host: let
|
||||
shellHost = pkgs.lib.replaceStrings [ "-" ] [ "_" ] host;
|
||||
in ''
|
||||
nix build -v '.#nixosConfigurations.${host}.config.system.build.toplevel' --out-link ./build/result-${host} -j2 "$@"
|
||||
RC_${shellHost}=$?
|
||||
'';
|
||||
in builtins.toString (pkgs.writeShellScript
|
||||
"check-host-configs"
|
||||
''
|
||||
# build minimally-usable hosts first, then their full image.
|
||||
# this gives me a minimal image i can deploy or copy over, early.
|
||||
${checkHost "lappy-min"}
|
||||
${checkHost "moby-min"}
|
||||
|
||||
${checkHost "desko-light"}
|
||||
${checkHost "moby-light"}
|
||||
${checkHost "lappy-light"}
|
||||
|
||||
${checkHost "desko"}
|
||||
${checkHost "lappy"}
|
||||
${checkHost "servo"}
|
||||
${checkHost "moby"}
|
||||
${checkHost "rescue"}
|
||||
|
||||
# still want to build the -light variants first so as to avoid multiple simultaneous webkitgtk builds
|
||||
${checkHost "desko-light-next"}
|
||||
${checkHost "moby-light-next"}
|
||||
|
||||
${checkHost "desko-next"}
|
||||
${checkHost "lappy-next"}
|
||||
${checkHost "servo-next"}
|
||||
${checkHost "moby-next"}
|
||||
${checkHost "rescue-next"}
|
||||
|
||||
echo "desko: $RC_desko"
|
||||
echo "lappy: $RC_lappy"
|
||||
echo "servo: $RC_servo"
|
||||
echo "moby: $RC_moby"
|
||||
echo "rescue: $RC_rescue"
|
||||
|
||||
echo "desko-next: $RC_desko_next"
|
||||
echo "lappy-next: $RC_lappy_next"
|
||||
echo "servo-next: $RC_servo_next"
|
||||
echo "moby-next: $RC_moby_next"
|
||||
echo "rescue-next: $RC_rescue_next"
|
||||
|
||||
# i don't really care if the -next hosts fail. i build them mostly to keep the cache fresh/ready
|
||||
exit $(($RC_desko | $RC_lappy | $RC_servo | $RC_moby | $RC_rescue))
|
||||
''
|
||||
);
|
||||
};
|
||||
|
||||
check.rescue = {
|
||||
type = "app";
|
||||
program = builtins.toString (pkgs.writeShellScript "check-rescue" ''
|
||||
nix build -v '.#imgs.rescue' --out-link ./build/result-rescue-img -j2
|
||||
'');
|
||||
};
|
||||
|
||||
bench = {
|
||||
type = "app";
|
||||
program = builtins.toString (pkgs.writeShellScript "bench" ''
|
||||
doBench() {
|
||||
attrPath="$1"
|
||||
shift
|
||||
echo -n "benchmarking eval of '$attrPath'... "
|
||||
/run/current-system/sw/bin/time -f "%e sec" -o /dev/stdout \
|
||||
nix eval --no-eval-cache --quiet --raw ".#$attrPath" --apply 'result: if result != null then "" else "unexpected null"' $@ 2> /dev/null
|
||||
}
|
||||
|
||||
if [ -n "$1" ]; then
|
||||
doBench "$@"
|
||||
else
|
||||
doBench hostConfigs
|
||||
doBench hostConfigs.lappy
|
||||
doBench hostConfigs.lappy.sane.programs
|
||||
doBench hostConfigs.lappy.sane.users.colin
|
||||
doBench hostConfigs.lappy.sane.fs
|
||||
doBench hostConfigs.lappy.environment.systemPackages
|
||||
fi
|
||||
'');
|
||||
};
|
||||
};
|
||||
|
||||
templates = {
|
||||
env.python-data = {
|
||||
# initialize with:
|
||||
# - `nix flake init -t '/home/colin/dev/nixos/#env.python-data'`
|
||||
# then enter with:
|
||||
# - `nix develop`
|
||||
path = ./templates/env/python-data;
|
||||
description = "python environment for data processing";
|
||||
};
|
||||
pkgs.rust-inline = {
|
||||
# initialize with:
|
||||
# - `nix flake init -t '/home/colin/dev/nixos/#pkgs.rust-inline'`
|
||||
path = ./templates/pkgs/rust-inline;
|
||||
description = "rust package and development environment (inline rust sources)";
|
||||
};
|
||||
pkgs.rust = {
|
||||
# initialize with:
|
||||
# - `nix flake init -t '/home/colin/dev/nixos/#pkgs.rust'`
|
||||
path = ./templates/pkgs/rust;
|
||||
description = "rust package fit to ship in nixpkgs";
|
||||
};
|
||||
pkgs.make = {
|
||||
# initialize with:
|
||||
# - `nix flake init -t '/home/colin/dev/nixos/#pkgs.make'`
|
||||
path = ./templates/pkgs/make;
|
||||
description = "default Makefile-based derivation";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
44
hosts/by-name/crappy/default.nix
Normal file
44
hosts/by-name/crappy/default.nix
Normal file
@@ -0,0 +1,44 @@
|
||||
# Samsung chromebook XE303C12
|
||||
# - <https://wiki.postmarketos.org/wiki/Samsung_Chromebook_(google-snow)>
|
||||
{ ... }:
|
||||
{
|
||||
imports = [
|
||||
./fs.nix
|
||||
];
|
||||
|
||||
sane.hal.samsung.enable = true;
|
||||
sane.roles.client = true;
|
||||
# sane.roles.pc = true;
|
||||
|
||||
users.users.colin.initialPassword = "147147";
|
||||
sane.programs.sway.enableFor.user.colin = true;
|
||||
|
||||
sane.programs.calls.enableFor.user.colin = false;
|
||||
sane.programs.consoleMediaUtils.enableFor.user.colin = true;
|
||||
sane.programs.epiphany.enableFor.user.colin = true;
|
||||
sane.programs."gnome.geary".enableFor.user.colin = false;
|
||||
# sane.programs.firefox.enableFor.user.colin = true;
|
||||
sane.programs.portfolio-filemanager.enableFor.user.colin = true;
|
||||
sane.programs.signal-desktop.enableFor.user.colin = false;
|
||||
sane.programs.wike.enableFor.user.colin = true;
|
||||
|
||||
sane.programs.dino.config.autostart = false;
|
||||
sane.programs.dissent.config.autostart = false;
|
||||
sane.programs.fractal.config.autostart = false;
|
||||
|
||||
# sane.programs.guiApps.enableFor.user.colin = false;
|
||||
|
||||
# sane.programs.pcGuiApps.enableFor.user.colin = false; #< errors!
|
||||
|
||||
sane.programs.blueberry.enableFor.user.colin = false; # bluetooth manager: doesn't cross compile!
|
||||
# sane.programs.brave.enableFor.user.colin = false; # 2024/06/03: fails eval if enabled on cross
|
||||
# sane.programs.firefox.enableFor.user.colin = false; # 2024/06/03: this triggers an eval error in yarn stuff -- i'm doing IFD somewhere!!?
|
||||
sane.programs.mepo.enableFor.user.colin = false; # 2024/06/04: doesn't cross compile (nodejs)
|
||||
sane.programs.mercurial.enableFor.user.colin = false; # 2024/06/03: does not cross compile
|
||||
sane.programs.nixpkgs-review.enableFor.user.colin = false; # 2024/06/03: OOMs when cross compiling
|
||||
sane.programs.ntfy-sh.enableFor.user.colin = false; # 2024/06/04: doesn't cross compile (nodejs)
|
||||
sane.programs.pwvucontrol.enableFor.user.colin = false; # 2024/06/03: doesn't cross compile (libspa-sys)
|
||||
sane.programs."sane-scripts.bt-search".enableFor.user.colin = false; # 2024/06/03: does not cross compile
|
||||
sane.programs.sequoia.enableFor.user.colin = false; # 2024/06/03: does not cross compile
|
||||
sane.programs.zathura.enableFor.user.colin = false; # 2024/06/03: does not cross compile
|
||||
}
|
16
hosts/by-name/crappy/fs.nix
Normal file
16
hosts/by-name/crappy/fs.nix
Normal file
@@ -0,0 +1,16 @@
|
||||
{ ... }:
|
||||
{
|
||||
fileSystems."/nix" = {
|
||||
device = "/dev/disk/by-uuid/55555555-0303-0c12-86df-eda9e9311526";
|
||||
fsType = "btrfs";
|
||||
options = [
|
||||
"compress=zstd"
|
||||
"defaults"
|
||||
];
|
||||
};
|
||||
|
||||
fileSystems."/boot" = {
|
||||
device = "/dev/disk/by-uuid/303C-5A37";
|
||||
fsType = "vfat";
|
||||
};
|
||||
}
|
@@ -35,7 +35,11 @@
|
||||
sane.programs."gnome.geary".config.autostart = true;
|
||||
sane.programs.signal-desktop.config.autostart = true;
|
||||
|
||||
boot.loader.efi.canTouchEfiVariables = false;
|
||||
sane.programs.nwg-panel.config = {
|
||||
battery = false;
|
||||
brightness = false;
|
||||
};
|
||||
|
||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||
|
||||
# needed to use libimobiledevice/ifuse, for iphone sync
|
||||
@@ -52,7 +56,4 @@
|
||||
# TODO: ALLOW_USERS doesn't seem to work. still need `sudo snapper -c nix list`
|
||||
ALLOW_USERS = [ "colin" ];
|
||||
};
|
||||
|
||||
# docs: https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersion
|
||||
system.stateVersion = "21.05";
|
||||
}
|
||||
|
@@ -13,7 +13,6 @@
|
||||
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:0332:aa96/128";
|
||||
|
||||
# sane.guest.enable = true;
|
||||
boot.loader.efi.canTouchEfiVariables = false;
|
||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||
|
||||
sane.programs.stepmania.enableFor.user.colin = true;
|
||||
@@ -34,7 +33,4 @@
|
||||
SUBVOLUME = "/nix";
|
||||
ALLOW_USERS = [ "colin" ];
|
||||
};
|
||||
|
||||
# docs: https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersion
|
||||
system.stateVersion = "21.05";
|
||||
}
|
||||
|
@@ -1,7 +0,0 @@
|
||||
xkb_keymap {
|
||||
xkb_keycodes { include "evdev+aliases(qwerty)" };
|
||||
xkb_types { include "complete" };
|
||||
xkb_compat { include "complete" };
|
||||
xkb_symbols { include "pc+us+inet(evdev)" };
|
||||
xkb_geometry { include "pc(pc105)" };
|
||||
};
|
@@ -1,22 +0,0 @@
|
||||
# tow-boot: <https://tow-boot.org>
|
||||
# docs (pinephone specific): <https://github.com/Tow-Boot/Tow-Boot/tree/development/boards/pine64-pinephoneA64>
|
||||
# LED and button behavior is defined here: <https://github.com/Tow-Boot/Tow-Boot/blob/development/modules/tow-boot/phone-ux.nix>
|
||||
# - hold VOLDOWN: enter recovery mode
|
||||
# - LED will turn aqua instead of yellow
|
||||
# - recovery mode would ordinarily allow a selection of entries, but for pinephone i guess it doesn't do anything?
|
||||
# - hold VOLUP: force it to load the OS from eMMC?
|
||||
# - LED will turn blue instead of yellow
|
||||
# boot LEDs:
|
||||
# - yellow = entered tow-boot
|
||||
# - 10 red flashes => poweroff means tow-boot couldn't boot into the next stage (i.e. distroboot)
|
||||
# - distroboot: <https://source.denx.de/u-boot/u-boot/-/blob/v2022.04/doc/develop/distro.rst>)
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
# we need space in the GPT header to place tow-boot.
|
||||
# only actually need 1 MB, but better to over-allocate than under-allocate
|
||||
sane.image.extraGPTPadding = 16 * 1024 * 1024;
|
||||
sane.image.firstPartGap = 0;
|
||||
sane.image.installBootloader = ''
|
||||
dd if=${pkgs.tow-boot-pinephone}/Tow-Boot.noenv.bin of=$out/nixos.img bs=1024 seek=8 conv=notrunc
|
||||
'';
|
||||
}
|
@@ -9,16 +9,13 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
{
|
||||
imports = [
|
||||
./bootloader.nix
|
||||
./fs.nix
|
||||
./gps.nix
|
||||
./kernel.nix
|
||||
./polyfill.nix
|
||||
];
|
||||
|
||||
sane.hal.pine64.enable = true;
|
||||
sane.roles.client = true;
|
||||
sane.roles.handheld = true;
|
||||
sane.programs.zsh.config.showDeadlines = false; # unlikely to act on them when in shell
|
||||
sane.services.wg-home.enable = true;
|
||||
sane.services.wg-home.ip = config.sane.hosts.by-name."moby".wg-home.ip;
|
||||
sane.ovpn.addrV4 = "172.24.87.255";
|
||||
@@ -32,11 +29,6 @@
|
||||
sops.secrets.colin-passwd.neededForUsers = true;
|
||||
|
||||
sane.programs.sway.enableFor.user.colin = true;
|
||||
sane.programs.swaylock.enableFor.user.colin = false; #< not usable on touch
|
||||
sane.programs.schlock.enableFor.user.colin = true;
|
||||
sane.programs.swayidle.config.actions.screenoff.delay = 300;
|
||||
sane.programs.swayidle.config.actions.screenoff.enable = true;
|
||||
sane.programs.sane-input-handler.enableFor.user.colin = true;
|
||||
sane.programs.blueberry.enableFor.user.colin = false; # bluetooth manager: doesn't cross compile!
|
||||
sane.programs.fcitx5.enableFor.user.colin = false; # does not cross compile
|
||||
sane.programs.mercurial.enableFor.user.colin = false; # does not cross compile
|
||||
@@ -52,10 +44,6 @@
|
||||
# sane.programs."gnome.geary".config.autostart = true;
|
||||
# sane.programs.calls.config.autostart = true;
|
||||
|
||||
sane.programs.firefox.mime.priority = 300; # prefer other browsers when possible
|
||||
# HACK/TODO: make `programs.P.env.VAR` behave according to `mime.priority`
|
||||
sane.programs.firefox.env = lib.mkForce {};
|
||||
sane.programs.epiphany.env.BROWSER = "epiphany";
|
||||
sane.programs.pipewire.config = {
|
||||
# tune so Dino doesn't drop audio
|
||||
# there's seemingly two buffers for the mic (see: <https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/FAQ#pipewire-buffering-explained>)
|
||||
@@ -72,53 +60,7 @@
|
||||
max-quantum = 8192;
|
||||
};
|
||||
|
||||
boot.loader.efi.canTouchEfiVariables = false;
|
||||
# /boot space is at a premium. default was 20.
|
||||
# even 10 can be too much
|
||||
boot.loader.generic-extlinux-compatible.configurationLimit = 8;
|
||||
# mobile.bootloader.enable = false;
|
||||
# mobile.boot.stage-1.enable = false;
|
||||
# boot.initrd.systemd.enable = false;
|
||||
# boot.initrd.services.swraid.enable = false; # attempt to fix dm_mod stuff
|
||||
|
||||
# hardware.firmware makes the referenced files visible to the kernel, for whenever a driver explicitly asks for them.
|
||||
# these files are visible from userspace by following `/sys/module/firmware_class/parameters/path`
|
||||
#
|
||||
# mobile-nixos' /lib/firmware includes:
|
||||
# rtl_bt (bluetooth)
|
||||
# anx7688-fw.bin (USB-C chip: power negotiation, HDMI/dock)
|
||||
# ov5640_af.bin (camera module)
|
||||
# hardware.firmware = [ config.mobile.device.firmware ];
|
||||
# hardware.firmware = [ pkgs.rtl8723cs-firmware ];
|
||||
hardware.firmware = [
|
||||
(pkgs.linux-firmware-megous.override {
|
||||
# rtl_bt = false probably means no bluetooth connectivity.
|
||||
# N.B.: DON'T RE-ENABLE without first confirming that wake-on-lan works during suspend (rtcwake).
|
||||
# it seems the rtl_bt stuff ("bluetooth coexist") might make wake-on-LAN radically more flaky.
|
||||
rtl_bt = false;
|
||||
})
|
||||
];
|
||||
|
||||
system.stateVersion = "21.11";
|
||||
|
||||
# defined: https://www.freedesktop.org/software/systemd/man/machine-info.html
|
||||
# XXX colin: not sure which, if any, software makes use of this
|
||||
environment.etc."machine-info".text = ''
|
||||
CHASSIS="handset"
|
||||
'';
|
||||
|
||||
# enable rotation sensor
|
||||
# hardware.sensor.iio.enable = true;
|
||||
|
||||
services.udev.extraRules = let
|
||||
chmod = "${pkgs.coreutils}/bin/chmod";
|
||||
chown = "${pkgs.coreutils}/bin/chown";
|
||||
in ''
|
||||
# make Pinephone flashlight writable by user.
|
||||
# taken from postmarketOS: <repo:postmarketOS/pmaports:device/main/device-pine64-pinephone/60-flashlight.rules>
|
||||
SUBSYSTEM=="leds", DEVPATH=="*/*:flash", RUN+="${chmod} g+w /sys%p/brightness /sys%p/flash_strobe", RUN+="${chown} :video /sys%p/brightness /sys%p/flash_strobe"
|
||||
|
||||
# make Pinephone front LEDs writable by user.
|
||||
SUBSYSTEM=="leds", DEVPATH=="*/*:indicator", RUN+="${chmod} g+w /sys%p/brightness", RUN+="${chown} :video /sys%p/brightness"
|
||||
'';
|
||||
}
|
||||
|
@@ -1,271 +0,0 @@
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
dmesg = "${pkgs.util-linux}/bin/dmesg";
|
||||
grep = "${pkgs.gnugrep}/bin/grep";
|
||||
modprobe = "${pkgs.kmod}/bin/modprobe";
|
||||
ensureHWReady = ''
|
||||
# common boot failure:
|
||||
# blank screen (no backlight even), with the following log:
|
||||
# ```syslog
|
||||
# sun8i-dw-hdmi 1ee0000.hdmi: Couldn't get the HDMI PHY
|
||||
# ...
|
||||
# sun4i-drm display-engine: Couldn't bind all pipelines components
|
||||
# ...
|
||||
# sun8i-dw-hdmi: probe of 1ee0000.hdmi failed with error -17
|
||||
# ```
|
||||
#
|
||||
# in particular, that `probe ... failed` occurs *only* on failed boots
|
||||
# (the other messages might sometimes occur even on successful runs?)
|
||||
#
|
||||
# reloading the sun8i hdmi driver usually gets the screen on, showing boot text.
|
||||
# then restarting display-manager.service gets us to the login.
|
||||
#
|
||||
# NB: the above log is default level. though less specific, there's a `err` level message that also signals this:
|
||||
# sun4i-drm display-engine: failed to bind 1ee0000.hdmi (ops sun8i_dw_hdmi_ops [sun8i_drm_hdmi]): -17
|
||||
# NB: this is the most common, but not the only, failure mode for `display-manager`.
|
||||
# another error seems characterized by these dmesg logs, in which reprobing sun8i_drm_hdmi does not fix:
|
||||
# ```syslog
|
||||
# sun6i-mipi-dsi 1ca0000.dsi: Couldn't get the MIPI D-PHY
|
||||
# sun4i-drm display-engine: Couldn't bind all pipelines components
|
||||
# sun6i-mipi-dsi 1ca0000.dsi: Couldn't register our component
|
||||
# ```
|
||||
|
||||
if (${dmesg} --kernel --level err --color=never --notime | ${grep} -q 'sun4i-drm display-engine: failed to bind 1ee0000.hdmi')
|
||||
then
|
||||
echo "reprobing sun8i_drm_hdmi"
|
||||
# if a command here fails it errors the whole service, so prefer to log instead
|
||||
${modprobe} -r sun8i_drm_hdmi || echo "failed to unload sun8i_drm_hdmi"
|
||||
${modprobe} sun8i_drm_hdmi || echo "failed to load sub8i_drm_hdmi"
|
||||
fi
|
||||
'';
|
||||
in
|
||||
{
|
||||
# kernel compatibility (2024/05/22: 03dab630)
|
||||
# - linux-megous: boots to ssh, desktop
|
||||
# - camera apps: megapixels (no cameras found), snapshot (no cameras found)
|
||||
# - linux-postmarketos: boots to ssh. desktop ONLY if "anx7688" is in the initrd.availableKernelModules.
|
||||
# - camera apps: megapixels (both rear and front cameras work), `cam -l` (finds only the rear camera), snapshot (no cameras found)
|
||||
# - linux-megous.override { withMegiPinephoneConfig = true; }: NO SSH, NO SIGNS OF LIFE
|
||||
# - linux-megous.override { withFullConfig = false; }: boots to ssh, no desktop
|
||||
#
|
||||
boot.kernelPackages = pkgs.linuxPackagesFor (pkgs.linux-postmarketos.override {
|
||||
withModemPower = true;
|
||||
});
|
||||
# boot.kernelPackages = pkgs.linuxPackagesFor pkgs.linux-megous;
|
||||
# boot.kernelPackages = pkgs.linuxPackagesFor (pkgs.linux-megous.override {
|
||||
# withFullConfig = false;
|
||||
# });
|
||||
# boot.kernelPackages = pkgs.linuxPackagesFor (pkgs.linux-megous.override {
|
||||
# withMegiPinephoneConfig = true; #< N.B.: does not boot as of 2024/05/22!
|
||||
# });
|
||||
# boot.kernelPackages = pkgs.linuxPackagesFor pkgs.linux-manjaro;
|
||||
# boot.kernelPackages = pkgs.linuxPackagesFor pkgs.linux_latest;
|
||||
|
||||
# nixpkgs.hostPlatform.linux-kernel becomes stdenv.hostPlatform.linux-kernel
|
||||
nixpkgs.hostPlatform.linux-kernel = {
|
||||
# defaults:
|
||||
name = "aarch64-multiplatform";
|
||||
# baseConfig: defaults to "defconfig";
|
||||
# baseConfig = "pinephone_defconfig"; #< N.B.: ignored by `pkgs.linux-megous`
|
||||
DTB = true; #< DTB: compile device tree blobs
|
||||
# autoModules (default: true): for config options not manually specified, answer `m` to anything which supports it.
|
||||
# - this effectively builds EVERY MODULE SUPPORTED.
|
||||
autoModules = true; #< N.B.: ignored by `pkgs.linux-megous`
|
||||
# preferBuiltin (default: false; true for rpi): for config options which default to `Y` upstream, build them as `Y` (overriding `autoModules`)
|
||||
# preferBuiltin = false;
|
||||
|
||||
# build a compressed kernel image: without this i run out of /boot space in < 10 generations
|
||||
# target = "Image"; # <-- default
|
||||
target = "Image.gz"; # <-- compress the kernel image
|
||||
# target = "zImage"; # <-- confuses other parts of nixos :-(
|
||||
};
|
||||
|
||||
# boot.initrd.kernelModules = [
|
||||
# "drm" #< force drm to be plugged
|
||||
# ];
|
||||
boot.initrd.availableKernelModules = [
|
||||
# see <repo:postmarketOS/pmaports:device/main/device-pine64-pinephone/modules-initfs>
|
||||
# - they include sun6i_mipi_dsi sun4i_drm pwm_sun4i sun8i_mixer anx7688 gpio_vibra pinephone_keyboard
|
||||
"anx7688" #< required for display initialization and functional cameras
|
||||
# full list of modules active post-boot with the linux-megous kernel + autoModules=true:
|
||||
# - `lsmod | sort | cut -d ' ' -f 1`
|
||||
# "8723cs"
|
||||
# "axp20x_adc" #< NOT FOUND in megous-no-autoModules
|
||||
# "axp20x_battery"
|
||||
# "axp20x_pek"
|
||||
# "axp20x_usb_power"
|
||||
# "backlight"
|
||||
# "blake2b_generic"
|
||||
# "bluetooth"
|
||||
# "bridge"
|
||||
# "btbcm"
|
||||
# "btqca"
|
||||
# "btrfs"
|
||||
# "btrtl"
|
||||
# "cec"
|
||||
# "cfg80211"
|
||||
# "chacha_neon"
|
||||
# "crc_ccitt"
|
||||
# "crct10dif_ce"
|
||||
# "crypto_engine"
|
||||
# "display_connector" #< NOT FOUND in pmos
|
||||
# "drm"
|
||||
# "drm_display_helper"
|
||||
# "drm_dma_helper"
|
||||
# "drm_kms_helper"
|
||||
# "drm_shmem_helper"
|
||||
# "dw_hdmi"
|
||||
# "dw_hdmi_cec" #< NOT FOUND in pmos
|
||||
# "dw_hdmi_i2s_audio"
|
||||
# "ecc"
|
||||
# "ecdh_generic"
|
||||
# "fuse"
|
||||
# "gc2145" #< NOT FOUND in megous-no-autoModules
|
||||
# "goodix_ts"
|
||||
# "gpio_vibra" #< NOT FOUND in megous-no-autoModules
|
||||
# "gpu_sched"
|
||||
# "hci_uart"
|
||||
# "i2c_gpio"
|
||||
# "inv_mpu6050" #< NOT FOUND in megous-no-autoModules
|
||||
# "inv_mpu6050_i2c" #< NOT FOUND in megous-no-autoModules
|
||||
# "inv_sensors_timestamp" #< NOT FOUND in megous-no-autoModules
|
||||
# "ip6t_rpfilter"
|
||||
# "ip6_udp_tunnel"
|
||||
# "ip_set"
|
||||
# "ip_set_hash_ipport"
|
||||
# "ip_tables"
|
||||
# "ipt_rpfilter"
|
||||
# "joydev"
|
||||
# "led_class_flash" #< NOT FOUND in megous-no-autoModules
|
||||
# "leds_sgm3140" #< NOT FOUND in megous-no-autoModules
|
||||
# "ledtrig_pattern" #< NOT FOUND in megous-no-autoModules
|
||||
# "libarc4"
|
||||
# "libchacha"
|
||||
# "libchacha20poly1305"
|
||||
# "libcrc32c"
|
||||
# "libcurve25519_generic"
|
||||
# "lima"
|
||||
# "llc"
|
||||
# "mac80211"
|
||||
# "macvlan"
|
||||
# "mc"
|
||||
# "modem_power"
|
||||
# "mousedev"
|
||||
# "nf_conntrack"
|
||||
# "nf_defrag_ipv4"
|
||||
# "nf_defrag_ipv6"
|
||||
# "nf_log_syslog"
|
||||
# "nf_nat"
|
||||
# "nfnetlink"
|
||||
# "nf_tables"
|
||||
# "nft_chain_nat"
|
||||
# "nft_compat"
|
||||
# "nls_cp437"
|
||||
# "nls_iso8859_1"
|
||||
# "nvmem_reboot_mode"
|
||||
# "ov5640"
|
||||
# "panel_sitronix_st7703"
|
||||
# "phy_sun6i_mipi_dphy"
|
||||
# "pinctrl_axp209" #< NOT FOUND in pmos
|
||||
# "pinephone_keyboard" #< NOT FOUND in megous-no-autoModules
|
||||
# "poly1305_neon"
|
||||
# "polyval_ce"
|
||||
# "polyval_generic"
|
||||
# "ppkb_manager" #< NOT FOUND in megous-no-autoModules
|
||||
# "pwm_bl"
|
||||
# "pwm_sun4i"
|
||||
# "qrtr"
|
||||
# "raid6_pq"
|
||||
# "rfkill"
|
||||
# "rtw88_8703b"
|
||||
# "rtw88_8723cs"
|
||||
# "rtw88_8723x"
|
||||
# "rtw88_core"
|
||||
# "rtw88_sdio"
|
||||
# "sch_fq_codel"
|
||||
# "sm4"
|
||||
# "snd_soc_bt_sco"
|
||||
# "snd_soc_ec25" #< NOT FOUND in megous-no-autoModules
|
||||
# "snd_soc_hdmi_codec"
|
||||
# "snd_soc_simple_amplifier"
|
||||
# "snd_soc_simple_card"
|
||||
# "snd_soc_simple_card_utils"
|
||||
# "stk3310" #< NOT FOUND in megous-no-autoModules
|
||||
# "st_magn"
|
||||
# "st_magn_i2c"
|
||||
# "st_magn_spi" #< NOT FOUND in pmos
|
||||
# "stp"
|
||||
# "st_sensors"
|
||||
# "st_sensors_i2c"
|
||||
# "st_sensors_spi" #< NOT FOUND in pmos
|
||||
# "sun4i_drm"
|
||||
# "sun4i_i2s"
|
||||
# "sun4i_lradc_keys" #< NOT FOUND in megous-no-autoModules
|
||||
# "sun4i_tcon"
|
||||
# "sun50i_codec_analog"
|
||||
# "sun6i_csi"
|
||||
# "sun6i_dma"
|
||||
# "sun6i_mipi_dsi"
|
||||
# "sun8i_a33_mbus" #< NOT FOUND in megous-no-autoModules
|
||||
# "sun8i_adda_pr_regmap"
|
||||
# "sun8i_ce" #< NOT FOUND in pmos
|
||||
# "sun8i_codec" #< NOT FOUND in megous-no-autoModules
|
||||
# "sun8i_di" #< NOT FOUND in megous-no-autoModules
|
||||
# "sun8i_drm_hdmi"
|
||||
# "sun8i_mixer"
|
||||
# "sun8i_rotate" #< NOT FOUND in megous-no-autoModules
|
||||
# "sun8i_tcon_top"
|
||||
# "sun9i_hdmi_audio" #< NOT FOUND in megous-no-autoModules
|
||||
# "sunxi_wdt" #< NOT FOUND in pmos
|
||||
# "tap"
|
||||
# "typec" #< NOT FOUND in pmos
|
||||
# "udp_tunnel"
|
||||
# "uio" #< NOT FOUND in pmos
|
||||
# "uio_pdrv_genirq"
|
||||
# "v4l2_async"
|
||||
# "v4l2_cci" #< NOT FOUND in pmos
|
||||
# "v4l2_flash_led_class" #< NOT FOUND in megous-no-autoModules
|
||||
# "v4l2_fwnode"
|
||||
# "v4l2_mem2mem"
|
||||
# "videobuf2_common"
|
||||
# "videobuf2_dma_contig"
|
||||
# "videobuf2_memops"
|
||||
# "videobuf2_v4l2"
|
||||
# "videodev"
|
||||
# "wireguard"
|
||||
# "xor"
|
||||
# "x_tables"
|
||||
# "xt_conntrack"
|
||||
# "xt_LOG"
|
||||
# "xt_nat"
|
||||
# "xt_pkttype"
|
||||
# "xt_set"
|
||||
# "xt_tcpudp"
|
||||
# "zram"
|
||||
];
|
||||
|
||||
# disable proximity sensor.
|
||||
# the filtering/calibration is bad that it causes the screen to go fully dark at times.
|
||||
# boot.blacklistedKernelModules = [ "stk3310" ];
|
||||
|
||||
boot.kernelParams = [
|
||||
# without this some GUI apps fail: `DRM_IOCTL_MODE_CREATE_DUMB failed: Cannot allocate memory`
|
||||
# this is because they can't allocate enough video ram.
|
||||
# see related nixpkgs issue: <https://github.com/NixOS/nixpkgs/issues/260222>
|
||||
# TODO(2023/12/03): remove once mesa 23.3.1 lands: <https://github.com/NixOS/nixpkgs/pull/265740>
|
||||
#
|
||||
# the default CMA seems to be 32M.
|
||||
# i was running fine with 256MB from 2022/07-ish through 2022/12-ish, but then the phone quit reliably coming back from sleep (phosh): maybe a memory leak?
|
||||
# bumped to 512M on 2023/01
|
||||
# bumped to 1536M on 2024/05
|
||||
# `cat /proc/meminfo` to see CmaTotal/CmaFree if interested in tuning this.
|
||||
# kernel param mentioned here: <https://cateee.net/lkddb/web-lkddb/CMA_SIZE_PERCENTAGE.html>
|
||||
# i think cma mem isn't exclusive -- it can be used as ordinary `malloc`, still. i heard someone suggest the OS default should just be 50% memory to CMA.
|
||||
"cma=1536M"
|
||||
# 2023/10/20: potential fix for the lima (GPU) timeout bugs:
|
||||
# - <https://gitlab.com/postmarketOS/pmaports/-/issues/805#note_890467824>
|
||||
"lima.sched_timeout_ms=2000"
|
||||
];
|
||||
|
||||
systemd.services.unl0kr.preStart = ensureHWReady;
|
||||
}
|
@@ -1,45 +0,0 @@
|
||||
# this file configures preferences per program, without actually enabling any programs.
|
||||
# the goal is to separate the place where we decide *what* to use (i.e. `sane.programs.firefox.enable = true` -- at the toplevel)
|
||||
# from where we specific how that thing should behave *if* it's in use.
|
||||
#
|
||||
# NixOS backgrounds:
|
||||
# - <https://github.com/NixOS/nixos-artwork>
|
||||
# - <https://github.com/NixOS/nixos-artwork/issues/50> (colorful; unmerged)
|
||||
# - <https://github.com/NixOS/nixos-artwork/pull/60/files> (desktop-oriented; clean; unmerged)
|
||||
# - <https://itsfoss.com/content/images/2023/04/nixos-tutorials.png>
|
||||
|
||||
{ lib, pkgs, sane-lib, ... }:
|
||||
{
|
||||
sane.programs.firefox.config = {
|
||||
# compromise impermanence for the sake of usability
|
||||
persistCache = "private";
|
||||
persistData = "private";
|
||||
|
||||
# i don't do crypto stuff on moby
|
||||
addons.ether-metamask.enable = false;
|
||||
# sidebery UX doesn't make sense on small screen
|
||||
addons.sidebery.enable = false;
|
||||
};
|
||||
sane.programs.swaynotificationcenter.config = {
|
||||
backlight = "backlight"; # /sys/class/backlight/*backlight*/brightness
|
||||
};
|
||||
|
||||
sane.programs.alacritty.config.fontSize = 9;
|
||||
|
||||
sane.programs.sway.config = {
|
||||
font = "pango:monospace 10";
|
||||
mod = "Mod1"; # prefer Alt
|
||||
workspace_layout = "tabbed";
|
||||
};
|
||||
|
||||
sane.programs.waybar.config = {
|
||||
fontSize = 14;
|
||||
height = 26;
|
||||
persistWorkspaces = [ "1" "2" "3" "4" "5" ];
|
||||
modules.media = false;
|
||||
modules.network = false;
|
||||
modules.perf = false;
|
||||
modules.windowTitle = false;
|
||||
# TODO: show modem state
|
||||
};
|
||||
}
|
@@ -4,7 +4,6 @@
|
||||
./fs.nix
|
||||
];
|
||||
|
||||
boot.loader.efi.canTouchEfiVariables = false;
|
||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||
sane.persist.enable = false; # what we mean here is that the image is immutable; `/` is still tmpfs.
|
||||
sane.nixcache.enable = false; # don't want to be calling out to dead machines that we're *trying* to rescue
|
||||
@@ -12,7 +11,4 @@
|
||||
# auto-login at shell
|
||||
services.getty.autologinUser = "colin";
|
||||
# users.users.colin.initialPassword = "colin";
|
||||
|
||||
# docs: https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersion
|
||||
system.stateVersion = "21.05";
|
||||
}
|
||||
|
@@ -38,7 +38,6 @@
|
||||
# using root here makes sure we always have an escape hatch
|
||||
services.getty.autologinUser = "root";
|
||||
|
||||
boot.loader.efi.canTouchEfiVariables = false;
|
||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||
|
||||
# both transmission and ipfs try to set different net defaults.
|
||||
@@ -46,13 +45,5 @@
|
||||
boot.kernel.sysctl = {
|
||||
"net.core.rmem_max" = 4194304; # 4MB
|
||||
};
|
||||
|
||||
# This value determines the NixOS release from which the default
|
||||
# settings for stateful data, like file locations and database versions
|
||||
# on your system were taken. It‘s perfectly fine and recommended to leave
|
||||
# this value at the release version of the first install of this system.
|
||||
# Before changing this value read the documentation for this option
|
||||
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
|
||||
system.stateVersion = "21.11";
|
||||
}
|
||||
|
||||
|
@@ -3,9 +3,19 @@
|
||||
let
|
||||
portOpts = with lib; types.submodule {
|
||||
options = {
|
||||
visibleTo.ovpn = mkOption {
|
||||
visibleTo.ovpns = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
whether to forward inbound traffic on the OVPN vpn port to the corresponding localhost port.
|
||||
'';
|
||||
};
|
||||
visibleTo.doof = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
whether to forward inbound traffic on the doofnet vpn port to the corresponding localhost port.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -13,7 +23,7 @@ in
|
||||
{
|
||||
options = with lib; {
|
||||
sane.ports.ports = mkOption {
|
||||
# add the `visibleTo.ovpn` option
|
||||
# add the `visibleTo.{doof,ovpns}` options
|
||||
type = types.attrsOf portOpts;
|
||||
};
|
||||
};
|
||||
@@ -40,18 +50,16 @@ in
|
||||
|
||||
# tun-sea config
|
||||
sane.dns.zones."uninsane.org".inet.A."doof.tunnel" = "205.201.63.12";
|
||||
sane.dns.zones."uninsane.org".inet.AAAA."doof.tunnel" = "2602:fce8:106::51";
|
||||
networking.wireguard.interfaces.wg-doof = let
|
||||
ip = "${pkgs.iproute2}/bin/ip";
|
||||
in {
|
||||
# sane.dns.zones."uninsane.org".inet.AAAA."doof.tunnel" = "2602:fce8:106::51"; #< TODO: enable IPv6
|
||||
networking.wireguard.interfaces.wg-doof = {
|
||||
privateKeyFile = config.sops.secrets.wg_doof_privkey.path;
|
||||
# wg is active only in this namespace.
|
||||
# run e.g. ip netns exec doof <some command like ping/curl/etc, it'll go through wg>
|
||||
# sudo ip netns exec doof ping www.google.com
|
||||
interfaceNamespace = "doof";
|
||||
ips = [
|
||||
"205.201.63.12/32"
|
||||
"2602:fce8:106::51/128"
|
||||
"205.201.63.12"
|
||||
# "2602:fce8:106::51/128" #< TODO: enable IPv6
|
||||
];
|
||||
peers = [
|
||||
{
|
||||
@@ -63,45 +71,24 @@ in
|
||||
persistentKeepalive = 25; #< keep the NAT alive
|
||||
}
|
||||
];
|
||||
preSetup = ''
|
||||
${ip} netns add doof || (test -e /run/netns/doof && echo "doof already exists")
|
||||
'';
|
||||
postShutdown = ''
|
||||
${ip} netns delete doof || echo "couldn't delete doof"
|
||||
'';
|
||||
};
|
||||
sane.netns.doof.hostVethIpv4 = "10.0.2.5";
|
||||
sane.netns.doof.netnsVethIpv4 = "10.0.2.6";
|
||||
sane.netns.doof.netnsPubIpv4 = "205.201.63.12";
|
||||
sane.netns.doof.routeTable = 12;
|
||||
|
||||
# OVPN CONFIG (https://www.ovpn.com):
|
||||
# DOCS: https://nixos.wiki/wiki/WireGuard
|
||||
# if you `systemctl restart wireguard-wg-ovpns`, make sure to also restart any other services in `NetworkNamespacePath = .../ovpns`.
|
||||
# TODO: why not create the namespace as a seperate operation (nix config for that?)
|
||||
networking.wireguard.enable = true;
|
||||
networking.wireguard.interfaces.wg-ovpns = let
|
||||
ip = "${pkgs.iproute2}/bin/ip";
|
||||
in-ns = "${ip} netns exec ovpns";
|
||||
iptables = "${pkgs.iptables}/bin/iptables";
|
||||
veth-host-ip = "10.0.1.5";
|
||||
veth-local-ip = "10.0.1.6";
|
||||
vpn-ip = "185.157.162.178";
|
||||
# DNS = 46.227.67.134, 192.165.9.158, 2a07:a880:4601:10f0:cd45::1, 2001:67c:750:1:cafe:cd45::1
|
||||
vpn-dns = "46.227.67.134";
|
||||
bridgePort = port: proto: ''
|
||||
${in-ns} ${iptables} -A PREROUTING -t nat -p ${proto} --dport ${port} -m iprange --dst-range ${vpn-ip} \
|
||||
-j DNAT --to-destination ${veth-host-ip}
|
||||
'';
|
||||
bridgeStatements = lib.foldlAttrs
|
||||
(acc: port: portCfg: acc ++ (builtins.map (bridgePort port) portCfg.protocol))
|
||||
[]
|
||||
config.sane.ports.ports;
|
||||
in {
|
||||
networking.wireguard.interfaces.wg-ovpns = {
|
||||
privateKeyFile = config.sops.secrets.wg_ovpns_privkey.path;
|
||||
# wg is active only in this namespace.
|
||||
# run e.g. ip netns exec ovpns <some command like ping/curl/etc, it'll go through wg>
|
||||
# sudo ip netns exec ovpns ping www.google.com
|
||||
interfaceNamespace = "ovpns";
|
||||
ips = [
|
||||
"185.157.162.178/32"
|
||||
];
|
||||
ips = [ "185.157.162.178" ];
|
||||
peers = [
|
||||
{
|
||||
publicKey = "SkkEZDCBde22KTs/Hc7FWvDBfdOCQA4YtBEuC3n5KGs=";
|
||||
@@ -119,99 +106,11 @@ in
|
||||
# dynamicEndpointRefreshRestartSeconds = 5;
|
||||
}
|
||||
];
|
||||
preSetup = ''
|
||||
${ip} netns add ovpns || (test -e /run/netns/ovpns && echo "ovpns already exists")
|
||||
'';
|
||||
postShutdown = ''
|
||||
${in-ns} ip link del ovpns-veth-b || echo "couldn't delete ovpns-veth-b"
|
||||
${ip} link del ovpns-veth-a || echo "couldn't delete ovpns-veth-a"
|
||||
${ip} netns delete ovpns || echo "couldn't delete ovpns"
|
||||
# restore rules/routes
|
||||
${ip} rule del from ${veth-host-ip} lookup ovpns pref 50 || echo "couldn't delete init -> ovpns rule"
|
||||
${ip} route del default via ${veth-local-ip} dev ovpns-veth-a proto kernel src ${veth-host-ip} metric 1002 table ovpns || echo "couldn't delete init -> ovpns route"
|
||||
${ip} rule add from all lookup local pref 0
|
||||
${ip} rule del from all lookup local pref 100
|
||||
'';
|
||||
postSetup = ''
|
||||
# DOCS:
|
||||
# - some of this approach is described here: <https://josephmuia.ca/2018-05-16-net-namespaces-veth-nat/>
|
||||
# - iptables primer: <https://danielmiessler.com/study/iptables/>
|
||||
# create veth pair
|
||||
${ip} link add ovpns-veth-a type veth peer name ovpns-veth-b
|
||||
${ip} addr add ${veth-host-ip}/24 dev ovpns-veth-a
|
||||
${ip} link set ovpns-veth-a up
|
||||
|
||||
# mv veth-b into the ovpns namespace
|
||||
${ip} link set ovpns-veth-b netns ovpns
|
||||
${in-ns} ip addr add ${veth-local-ip}/24 dev ovpns-veth-b
|
||||
${in-ns} ip link set ovpns-veth-b up
|
||||
|
||||
# make it so traffic originating from the host side of the veth
|
||||
# is sent over the veth no matter its destination.
|
||||
${ip} rule add from ${veth-host-ip} lookup ovpns pref 50
|
||||
# for traffic originating at the host veth to the WAN, use the veth as our gateway
|
||||
# not sure if the metric 1002 matters.
|
||||
${ip} route add default via ${veth-local-ip} dev ovpns-veth-a proto kernel src ${veth-host-ip} metric 1002 table ovpns
|
||||
# give the default route lower priority
|
||||
${ip} rule add from all lookup local pref 100
|
||||
${ip} rule del from all lookup local pref 0
|
||||
|
||||
# in order to access DNS in this netns, we need to route it to the VPN's nameservers
|
||||
# - alternatively, we could fix DNS servers like 1.1.1.1.
|
||||
${in-ns} ${iptables} -A OUTPUT -t nat -p udp --dport 53 -m iprange --dst-range 127.0.0.53 \
|
||||
-j DNAT --to-destination ${vpn-dns}:53
|
||||
'' + (lib.concatStringsSep "\n" bridgeStatements);
|
||||
};
|
||||
|
||||
# create a new routing table that we can use to proxy traffic out of the root namespace
|
||||
# through the ovpns namespace, and to the WAN via VPN.
|
||||
networking.iproute2.rttablesExtraConfig = ''
|
||||
5 ovpns
|
||||
'';
|
||||
networking.iproute2.enable = true;
|
||||
|
||||
|
||||
# HURRICANE ELECTRIC CONFIG:
|
||||
# networking.sits = {
|
||||
# hurricane = {
|
||||
# remote = "216.218.226.238";
|
||||
# local = "192.168.0.5";
|
||||
# # local = "10.0.0.5";
|
||||
# # remote = "10.0.0.1";
|
||||
# # local = "10.0.0.22";
|
||||
# dev = "eth0";
|
||||
# ttl = 255;
|
||||
# };
|
||||
# };
|
||||
# networking.interfaces."hurricane".ipv6 = {
|
||||
# addresses = [
|
||||
# # mx.uninsane.org (publically routed /64)
|
||||
# {
|
||||
# address = "2001:470:b:465::1";
|
||||
# prefixLength = 128;
|
||||
# }
|
||||
# # client addr
|
||||
# # {
|
||||
# # address = "2001:470:a:466::2";
|
||||
# # prefixLength = 64;
|
||||
# # }
|
||||
# ];
|
||||
# routes = [
|
||||
# {
|
||||
# address = "::";
|
||||
# prefixLength = 0;
|
||||
# # via = "2001:470:a:466::1";
|
||||
# }
|
||||
# ];
|
||||
# };
|
||||
|
||||
# # after configuration, we want the hurricane device to look like this:
|
||||
# # hurricane: flags=209<UP,POINTOPOINT,RUNNING,NOARP> mtu 1480
|
||||
# # inet6 2001:470:a:450::2 prefixlen 64 scopeid 0x0<global>
|
||||
# # inet6 fe80::c0a8:16 prefixlen 64 scopeid 0x20<link>
|
||||
# # sit txqueuelen 1000 (IPv6-in-IPv4)
|
||||
# # test with:
|
||||
# # curl --interface hurricane http://[2607:f8b0:400a:80b::2004]
|
||||
# # ping 2607:f8b0:400a:80b::2004
|
||||
sane.netns.ovpns.hostVethIpv4 = "10.0.1.5";
|
||||
sane.netns.ovpns.netnsVethIpv4 = "10.0.1.6";
|
||||
sane.netns.ovpns.netnsPubIpv4 = "185.157.162.178";
|
||||
sane.netns.ovpns.routeTable = 11;
|
||||
sane.netns.ovpns.dns = "46.227.67.134"; #< DNS requests inside the namespace are forwarded here
|
||||
};
|
||||
}
|
||||
|
@@ -55,7 +55,7 @@ in
|
||||
# protocol = [ "tcp" "udp" ];
|
||||
# # visibleTo.lan = true;
|
||||
# # visibleTo.wan = true;
|
||||
# visibleTo.ovpn = true; # forward traffic from the VPN to the root NS
|
||||
# visibleTo.ovpns = true; # forward traffic from the VPN to the root NS
|
||||
# description = "colin-stun-turn";
|
||||
# };
|
||||
# "5349" = {
|
||||
@@ -63,7 +63,7 @@ in
|
||||
# protocol = [ "tcp" ];
|
||||
# # visibleTo.lan = true;
|
||||
# # visibleTo.wan = true;
|
||||
# visibleTo.ovpn = true;
|
||||
# visibleTo.ovpns = true;
|
||||
# description = "colin-stun-turn-over-tls";
|
||||
# };
|
||||
# }
|
||||
@@ -76,7 +76,7 @@ in
|
||||
# protocol = [ "tcp" "udp" ];
|
||||
# # visibleTo.lan = true;
|
||||
# # visibleTo.wan = true;
|
||||
# visibleTo.ovpn = true;
|
||||
# visibleTo.ovpns = true;
|
||||
# description = "colin-turn-${builtins.toString count}-of-${builtins.toString numPorts}";
|
||||
# };
|
||||
# })
|
||||
|
@@ -50,9 +50,15 @@
|
||||
ENABLE_CAPTCHA = true;
|
||||
NOREPLY_ADDRESS = "noreply.anonymous.git@uninsane.org";
|
||||
};
|
||||
session.COOKIE_SECURE = true;
|
||||
session = {
|
||||
COOKIE_SECURE = true;
|
||||
# keep me logged in for 30 days
|
||||
SESSION_LIFE_TIME = 60 * 60 * 24 * 30;
|
||||
};
|
||||
repository = {
|
||||
DEFAULT_BRANCH = "master";
|
||||
ENABLE_PUSH_CREATE_USER = true;
|
||||
ENABLE_PUSH_CREATE_ORG = true;
|
||||
};
|
||||
other = {
|
||||
SHOW_FOOTER_TEMPLATE_LOAD_TIME = false;
|
||||
|
@@ -18,13 +18,15 @@ in
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
visibleTo.ovpn = true; # so that letsencrypt can procure a cert for the mx record
|
||||
visibleTo.ovpns = true; # so that letsencrypt can procure a cert for the mx record
|
||||
visibleTo.doof = true;
|
||||
description = "colin-http-uninsane.org";
|
||||
};
|
||||
sane.ports.ports."443" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
visibleTo.doof = true;
|
||||
description = "colin-https-uninsane.org";
|
||||
};
|
||||
|
||||
|
@@ -22,8 +22,7 @@
|
||||
|
||||
sane.ports.ports."50300" = {
|
||||
protocol = [ "tcp" ];
|
||||
# not visible to WAN: i run this in a separate netns
|
||||
visibleTo.ovpn = true;
|
||||
# visibleTo.ovpns = true; #< not needed: it runs in the ovpns namespace
|
||||
description = "colin-soulseek";
|
||||
};
|
||||
|
||||
|
@@ -197,7 +197,7 @@ lib.mkIf false #< TODO: re-enable once confident of sandboxing
|
||||
sane.dns.zones."uninsane.org".inet.CNAME."bt" = "native";
|
||||
sane.ports.ports."51413" = {
|
||||
protocol = [ "tcp" "udp" ];
|
||||
visibleTo.ovpn = true;
|
||||
# visibleTo.ovpns = true; #< not needed: it runs in the ovpns namespace
|
||||
description = "colin-bittorrent";
|
||||
};
|
||||
}
|
||||
|
@@ -5,13 +5,15 @@ let
|
||||
dyn-dns = config.sane.services.dyn-dns;
|
||||
nativeAddrs = lib.mapAttrs (_name: builtins.head) config.sane.dns.zones."uninsane.org".inet.A;
|
||||
bindOvpn = "10.0.1.5";
|
||||
bindDoof = "10.0.2.5";
|
||||
in
|
||||
{
|
||||
sane.ports.ports."53" = {
|
||||
protocol = [ "udp" "tcp" ];
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
visibleTo.ovpn = true;
|
||||
visibleTo.ovpns = true;
|
||||
visibleTo.doof = true;
|
||||
description = "colin-dns-hosting";
|
||||
};
|
||||
|
||||
@@ -99,6 +101,7 @@ in
|
||||
listenAddrsIpv4 = [
|
||||
nativeAddrs."servo.lan"
|
||||
bindOvpn
|
||||
bindDoof
|
||||
];
|
||||
};
|
||||
lan = {
|
||||
|
50
hosts/common/boot.nix
Normal file
50
hosts/common/boot.nix
Normal file
@@ -0,0 +1,50 @@
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
boot.initrd.supportedFilesystems = [ "ext4" "btrfs" "ext2" "ext3" "vfat" ];
|
||||
# useful emergency utils
|
||||
boot.initrd.extraUtilsCommands = ''
|
||||
copy_bin_and_libs ${pkgs.btrfs-progs}/bin/btrfstune
|
||||
copy_bin_and_libs ${pkgs.util-linux}/bin/{cfdisk,lsblk,lscpu}
|
||||
copy_bin_and_libs ${pkgs.gptfdisk}/bin/{cgdisk,gdisk}
|
||||
copy_bin_and_libs ${pkgs.smartmontools}/bin/smartctl
|
||||
copy_bin_and_libs ${pkgs.e2fsprogs}/bin/resize2fs
|
||||
'' + lib.optionalString pkgs.stdenv.hostPlatform.isx86_64 ''
|
||||
copy_bin_and_libs ${pkgs.nvme-cli}/bin/nvme # doesn't cross compile
|
||||
'';
|
||||
boot.kernelParams = [
|
||||
"boot.shell_on_fail"
|
||||
#v experimental full pre-emption for hopefully better call/audio latency on moby.
|
||||
# also toggleable at runtime via /sys/kernel/debug/sched/preempt
|
||||
# defaults to preempt=voluntary
|
||||
# "preempt=full"
|
||||
];
|
||||
# other kernelParams:
|
||||
# "boot.trace"
|
||||
# "systemd.log_level=debug"
|
||||
# "systemd.log_target=console"
|
||||
|
||||
# moby has to run recent kernels (defined elsewhere).
|
||||
# meanwhile, kernel variation plays some minor role in things like sandboxing (landlock) and capabilities.
|
||||
# simpler to keep near the latest kernel on all devices,
|
||||
# and also makes certain that any weird system-level bugs i see aren't likely to be stale kernel bugs.
|
||||
# servo needs zfs though, which doesn't support every kernel.
|
||||
boot.kernelPackages = lib.mkDefault pkgs.zfs.latestCompatibleLinuxPackages;
|
||||
|
||||
# hack in the `boot.shell_on_fail` arg since that doesn't always seem to work.
|
||||
boot.initrd.preFailCommands = "allowShell=1";
|
||||
|
||||
# default: 4 (warn). 7 is debug
|
||||
boot.consoleLogLevel = 7;
|
||||
|
||||
boot.loader.grub.enable = lib.mkDefault false;
|
||||
boot.loader.generic-extlinux-compatible.enable = lib.mkDefault true;
|
||||
|
||||
hardware.enableAllFirmware = true; # firmware with licenses that don't allow for redistribution. fuck lawyers, fuck IP, give me the goddamn firmware.
|
||||
# hardware.enableRedistributableFirmware = true; # proprietary but free-to-distribute firmware (extraneous to `enableAllFirmware` option)
|
||||
|
||||
# default is 252274, which is too low particularly for servo.
|
||||
# manifests as spurious "No space left on device" when trying to install watches,
|
||||
# e.g. in dyn-dns by `systemctl start dyn-dns-watcher.path`.
|
||||
# see: <https://askubuntu.com/questions/828779/failed-to-add-run-systemd-ask-password-to-directory-watch-no-space-left-on-dev>
|
||||
boot.kernel.sysctl."fs.inotify.max_user_watches" = 1048576;
|
||||
}
|
@@ -1,24 +1,30 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
{
|
||||
imports = [
|
||||
./boot.nix
|
||||
./feeds.nix
|
||||
./fs.nix
|
||||
./hardware
|
||||
./home
|
||||
./hosts.nix
|
||||
./ids.nix
|
||||
./machine-id.nix
|
||||
./net
|
||||
./nix
|
||||
./nix.nix
|
||||
./persist.nix
|
||||
./polyunfill.nix
|
||||
./programs
|
||||
./quirks.nix
|
||||
./secrets.nix
|
||||
./ssh.nix
|
||||
./systemd.nix
|
||||
./users
|
||||
];
|
||||
|
||||
|
||||
# docs: https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersion
|
||||
# this affects where nixos modules look for stateful data which might have been migrated across releases.
|
||||
system.stateVersion = "21.11";
|
||||
|
||||
sane.nixcache.enable-trusted-keys = true;
|
||||
sane.nixcache.enable = lib.mkDefault true;
|
||||
sane.persist.enable = lib.mkDefault true;
|
||||
@@ -26,9 +32,6 @@
|
||||
sane.programs.sysadminUtils.enableFor.system = lib.mkDefault true;
|
||||
sane.programs.consoleUtils.enableFor.user.colin = lib.mkDefault true;
|
||||
|
||||
nixpkgs.config.allowUnfree = true; # NIXPKGS_ALLOW_UNFREE=1
|
||||
nixpkgs.config.allowBroken = true; # NIXPKGS_ALLOW_BROKEN=1
|
||||
|
||||
# time.timeZone = "America/Los_Angeles";
|
||||
time.timeZone = "Etc/UTC"; # DST is too confusing for me => use a stable timezone
|
||||
|
||||
|
@@ -195,6 +195,7 @@ let
|
||||
(fromDb "weekinethereumnews.com" // tech)
|
||||
(fromDb "willow.phantoma.online") # wizard@xyzzy.link
|
||||
(fromDb "xn--gckvb8fzb.com" // tech)
|
||||
(fromDb "xorvoid.com" // tech)
|
||||
(mkSubstack "astralcodexten" // rat // daily) # Scott Alexander
|
||||
(mkSubstack "eliqian" // rat // weekly)
|
||||
(mkSubstack "oversharing" // pol // daily)
|
||||
@@ -238,7 +239,7 @@ let
|
||||
(fromDb "youtube.com/@TomScottGo")
|
||||
(fromDb "youtube.com/@Vihart")
|
||||
(fromDb "youtube.com/@Vox")
|
||||
(fromDb "youtube.com/@Vsauce")
|
||||
# (fromDb "youtube.com/@Vsauce") # they're all like 1-minute long videos now? what happened @Vsauce?
|
||||
|
||||
# (fromDb "youtube.com/@rossmanngroup" // pol // tech) # Louis Rossmann
|
||||
];
|
||||
|
@@ -216,6 +216,7 @@ lib.mkMerge [
|
||||
programs.fuse.userAllowOther = true; #< necessary for `allow_other` or `allow_root` options.
|
||||
}
|
||||
|
||||
(remoteHome "crappy")
|
||||
(remoteHome "desko")
|
||||
(remoteHome "lappy")
|
||||
(remoteHome "moby")
|
||||
|
@@ -1,99 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
./x86_64.nix
|
||||
];
|
||||
|
||||
boot.initrd.supportedFilesystems = [ "ext4" "btrfs" "ext2" "ext3" "vfat" ];
|
||||
# useful emergency utils
|
||||
boot.initrd.extraUtilsCommands = ''
|
||||
copy_bin_and_libs ${pkgs.btrfs-progs}/bin/btrfstune
|
||||
copy_bin_and_libs ${pkgs.util-linux}/bin/{cfdisk,lsblk,lscpu}
|
||||
copy_bin_and_libs ${pkgs.gptfdisk}/bin/{cgdisk,gdisk}
|
||||
copy_bin_and_libs ${pkgs.smartmontools}/bin/smartctl
|
||||
copy_bin_and_libs ${pkgs.e2fsprogs}/bin/resize2fs
|
||||
'' + lib.optionalString pkgs.stdenv.hostPlatform.isx86_64 ''
|
||||
copy_bin_and_libs ${pkgs.nvme-cli}/bin/nvme # doesn't cross compile
|
||||
'';
|
||||
boot.kernelParams = [
|
||||
"boot.shell_on_fail"
|
||||
#v experimental full pre-emption for hopefully better call/audio latency on moby.
|
||||
# also toggleable at runtime via /sys/kernel/debug/sched/preempt
|
||||
# defaults to preempt=voluntary
|
||||
# "preempt=full"
|
||||
];
|
||||
# other kernelParams:
|
||||
# "boot.trace"
|
||||
# "systemd.log_level=debug"
|
||||
# "systemd.log_target=console"
|
||||
|
||||
# moby has to run recent kernels (defined elsewhere).
|
||||
# meanwhile, kernel variation plays some minor role in things like sandboxing (landlock) and capabilities.
|
||||
# simpler to keep near the latest kernel on all devices,
|
||||
# and also makes certain that any weird system-level bugs i see aren't likely to be stale kernel bugs.
|
||||
# servo needs zfs though, which doesn't support every kernel.
|
||||
boot.kernelPackages = lib.mkDefault pkgs.zfs.latestCompatibleLinuxPackages;
|
||||
|
||||
# TODO: remove after linux 6.9. see: <https://github.com/axboe/liburing/issues/1113>
|
||||
# - <https://github.com/neovim/neovim/issues/28149>
|
||||
# - <https://git.kernel.dk/cgit/linux/commit/?h=io_uring-6.9&id=e5444baa42e545bb929ba56c497e7f3c73634099>
|
||||
# when removing, try starting and suspending (ctrl+z) two instances of neovim simultaneously.
|
||||
# if the system doesn't freeze, then this is safe to remove.
|
||||
# added 2024-04-04
|
||||
sane.user.fs.".profile".symlink.text = lib.mkBefore ''
|
||||
export UV_USE_IO_URING=0
|
||||
'';
|
||||
|
||||
# hack in the `boot.shell_on_fail` arg since that doesn't always seem to work.
|
||||
boot.initrd.preFailCommands = "allowShell=1";
|
||||
|
||||
# default: 4 (warn). 7 is debug
|
||||
boot.consoleLogLevel = 7;
|
||||
|
||||
boot.loader.grub.enable = lib.mkDefault false;
|
||||
boot.loader.generic-extlinux-compatible.enable = lib.mkDefault true;
|
||||
|
||||
# non-free firmware
|
||||
hardware.enableRedistributableFirmware = true;
|
||||
|
||||
# default is 252274, which is too low particularly for servo.
|
||||
# manifests as spurious "No space left on device" when trying to install watches,
|
||||
# e.g. in dyn-dns by `systemctl start dyn-dns-watcher.path`.
|
||||
# see: <https://askubuntu.com/questions/828779/failed-to-add-run-systemd-ask-password-to-directory-watch-no-space-left-on-dev>
|
||||
boot.kernel.sysctl."fs.inotify.max_user_watches" = 1048576;
|
||||
|
||||
# powertop will default to putting USB devices -- including HID -- to sleep after TWO SECONDS
|
||||
powerManagement.powertop.enable = false;
|
||||
# linux CPU governor: <https://www.kernel.org/doc/Documentation/cpu-freq/governors.txt>
|
||||
# - options:
|
||||
# - "powersave" => force CPU to always run at lowest supported frequency
|
||||
# - "performance" => force CPU to always run at highest frequency
|
||||
# - "ondemand" => adjust frequency based on load
|
||||
# - "conservative" (ondemand but slower to adjust)
|
||||
# - "schedutil"
|
||||
# - "userspace"
|
||||
# - not all options are available for all platforms
|
||||
# - intel (intel_pstate) appears to manage scaling w/o intervention/control from the OS.
|
||||
# - AMD (acpi-cpufreq) appears to manage scaling via the OS *or* HW. but the ondemand defaults never put it to max hardware frequency.
|
||||
# - qualcomm (cpufreq-dt) appears to manage scaling *only* via the OS. ondemand governor exercises the full range.
|
||||
# - query details with `sudo cpupower frequency-info`
|
||||
powerManagement.cpuFreqGovernor = "ondemand";
|
||||
|
||||
# see: `man logind.conf`
|
||||
# don’t shutdown when power button is short-pressed (commonly done an accident, or by cats).
|
||||
# but do on long-press: useful to gracefully power-off server.
|
||||
services.logind.powerKey = "lock";
|
||||
services.logind.powerKeyLongPress = "poweroff";
|
||||
services.logind.lidSwitch = "lock";
|
||||
|
||||
# services.snapper.configs = {
|
||||
# root = {
|
||||
# subvolume = "/";
|
||||
# extraConfig = {
|
||||
# ALLOW_USERS = "colin";
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
# services.snapper.snapshotInterval = "daily";
|
||||
}
|
@@ -2,6 +2,14 @@
|
||||
|
||||
{
|
||||
# TODO: this should be populated per-host
|
||||
sane.hosts.by-name."crappy" = {
|
||||
ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMIvSQAGKqmymXIL4La9B00LPxBIqWAr5AsJxk3UQeY5";
|
||||
ssh.host_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMN0cpRAloCBOE5/2wuzgik35iNDv5KLceWMCVaa7DIQ";
|
||||
# wg-home.pubkey = "TODO";
|
||||
# wg-home.ip = "10.0.10.55";
|
||||
lan-ip = "10.78.79.55";
|
||||
};
|
||||
|
||||
sane.hosts.by-name."desko" = {
|
||||
ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPU5GlsSfbaarMvDA20bxpSZGWviEzXGD8gtrIowc1pX";
|
||||
ssh.host_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFw9NoRaYrM6LbDd3aFBc4yyBlxGQn8HjeHd/dZ3CfHk";
|
||||
|
@@ -32,15 +32,33 @@
|
||||
# serviceConfig.Restart = "on-abort";
|
||||
# serviceConfig.StandardError = "null";
|
||||
# serviceConfig.CapabilityBoundingSet = "CAP_SYS_ADMIN CAP_NET_ADMIN";
|
||||
# serviceConfig.ProtectSystem = true;
|
||||
# serviceConfig.ProtectHome = true;
|
||||
# serviceConfig.ProtectSystem = true; # makes empty: /boot, /usr
|
||||
# serviceConfig.ProtectHome = true; # makes empty: /home, /root, /run/user
|
||||
# serviceConfig.PrivateTmp = true;
|
||||
# serviceConfig.RestrictAddressFamilies = "AF_NETLINK AF_UNIX AF_QIPCRTR";
|
||||
# serviceConfig.NoNewPrivileges = true;
|
||||
|
||||
# TODO: sandbox more aggressively
|
||||
# - CAP_NET_ADMIN *only*?
|
||||
# it needs these paths:
|
||||
serviceConfig.CapabilityBoundingSet = [ "CAP_NET_ADMIN" ]; #< TODO: make sure this is *really* taking effect, and isn't supplemental to upstream's `CAP_SYS_ADMIN` setting
|
||||
serviceConfig.LockPersonality = true;
|
||||
# serviceConfig.PrivateUsers = true; #< untried, not likely to work since it needs capabilities
|
||||
serviceConfig.PrivateTmp = true;
|
||||
serviceConfig.ProtectClock = true; # syscall filter to prevent changing the RTC
|
||||
serviceConfig.ProtectControlGroups = true;
|
||||
serviceConfig.ProtectHome = true; # makes empty: /home, /root, /run/user
|
||||
serviceConfig.ProtectHostname = true; # prevents changing hostname
|
||||
serviceConfig.ProtectKernelLogs = true; # disable /proc/kmsg, /dev/kmsg
|
||||
serviceConfig.ProtectKernelModules = true; # syscall filter to prevent module calls
|
||||
serviceConfig.ProtectKernelTunables = true;
|
||||
serviceConfig.ProtectSystem = "strict"; # makes read-only all but /dev, /proc, /sys
|
||||
serviceConfig.RestrictAddressFamilies = [
|
||||
"AF_NETLINK"
|
||||
"AF_QIPCRTR"
|
||||
"AF_UNIX"
|
||||
];
|
||||
serviceConfig.RestrictSUIDSGID = true;
|
||||
serviceConfig.SystemCallArchitectures = "native"; # prevents e.g. aarch64 syscalls in the event that the kernel is multi-architecture.
|
||||
|
||||
# from earlier `landlock` sandboxing, i know it needs these directories:
|
||||
# - # "/"
|
||||
# - "/dev" #v modem-power + net are not enough
|
||||
# - # "/dev/modem-power"
|
||||
|
@@ -61,20 +61,46 @@ in {
|
||||
serviceConfig.AmbientCapabilities = [
|
||||
# "CAP_DAC_OVERRIDE"
|
||||
"CAP_NET_ADMIN"
|
||||
"CAP_NET_RAW"
|
||||
"CAP_NET_RAW" #< required, else `libndp: ndp_sock_open: Failed to create ICMP6 socket.`
|
||||
"CAP_NET_BIND_SERVICE" #< this *does* seem to be necessary, though i don't understand why. DHCP?
|
||||
# "CAP_SYS_MODULE"
|
||||
"CAP_AUDIT_WRITE" #< allow writing to the audit log
|
||||
# "CAP_AUDIT_WRITE" #< allow writing to the audit log (optional)
|
||||
# "CAP_KILL"
|
||||
];
|
||||
# TODO: it needs these directories:
|
||||
serviceConfig.LockPersonality = true;
|
||||
serviceConfig.NoNewPrivileges = true;
|
||||
serviceConfig.PrivateDevices = true; # remount /dev with just the basics, syscall filter to block @raw-io
|
||||
serviceConfig.PrivateIPC = true;
|
||||
serviceConfig.PrivateTmp = true;
|
||||
# serviceConfig.PrivateUsers = true; #< BREAKS NetworkManager (presumably, it causes a new user namespace, breaking CAP_NET_ADMIN & others). "platform-linux: do-change-link[3]: failure 1 (Operation not permitted)"
|
||||
serviceConfig.ProtectClock = true; # syscall filter to prevent changing the RTC
|
||||
serviceConfig.ProtectControlGroups = true;
|
||||
serviceConfig.ProtectHome = true; # makes empty: /home, /root, /run/user
|
||||
serviceConfig.ProtectHostname = true; # probably not upstreamable: prevents changing hostname
|
||||
serviceConfig.ProtectKernelLogs = true; # disable /proc/kmsg, /dev/kmsg
|
||||
serviceConfig.ProtectKernelModules = true; # syscall filter to prevent module calls (probably not upstreamable: NM will want to load modules like `ppp`)
|
||||
serviceConfig.ProtectKernelTunables = true; # but NM might need to write /proc/sys/net/...
|
||||
serviceConfig.ProtectSystem = "strict"; # makes read-only: all but /dev, /proc, /sys.
|
||||
serviceConfig.RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
"AF_NETLINK" # breaks near DHCP without this
|
||||
"AF_PACKET" # for DHCP
|
||||
"AF_UNIX"
|
||||
# AF_ALG ?
|
||||
# AF_BLUETOOTH ?
|
||||
# AF_BRIDGE ?
|
||||
];
|
||||
serviceConfig.RestrictSUIDSGID = true;
|
||||
serviceConfig.SystemCallArchitectures = "native"; # prevents e.g. aarch64 syscalls in the event that the kernel is multi-architecture.
|
||||
# from earlier `landlock` sandboxing, i know it needs these directories:
|
||||
# - "/proc/net"
|
||||
# - "/proc/sys/net"
|
||||
# - "/run/NetworkManager"
|
||||
# - "/run/systemd" # for trust-dns-nmhook
|
||||
# - "/run/udev"
|
||||
# - # "/run/wg-home.priv"
|
||||
# - "/sys/class" #< TODO: specify this more precisely
|
||||
# - "/sys/class"
|
||||
# - "/sys/devices"
|
||||
# - "/var/lib/NetworkManager"
|
||||
# - "/var/lib/trust-dns" #< for trust-dns-nmhook
|
||||
@@ -96,9 +122,29 @@ in {
|
||||
# ];
|
||||
# serviceConfig.Restart = "always";
|
||||
# serviceConfig.RestartSec = "1s";
|
||||
serviceConfig.User = "networkmanager";
|
||||
|
||||
# serviceConfig.DynamicUser = true; #< not possible, else we lose group perms (so can't write to `trust-dns`'s files in the nm hook)
|
||||
serviceConfig.User = "networkmanager"; # TODO: should arguably use `DynamicUser`
|
||||
serviceConfig.Group = "networkmanager";
|
||||
# TODO: it needs access only to the above mentioned directories
|
||||
serviceConfig.LockPersonality = true;
|
||||
serviceConfig.NoNewPrivileges = true;
|
||||
serviceConfig.PrivateDevices = true; # remount /dev with just the basics, syscall filter to block @raw-io
|
||||
serviceConfig.PrivateIPC = true;
|
||||
serviceConfig.PrivateTmp = true;
|
||||
serviceConfig.PrivateUsers = true;
|
||||
serviceConfig.ProtectClock = true; # syscall filter to prevent changing the RTC
|
||||
serviceConfig.ProtectControlGroups = true;
|
||||
serviceConfig.ProtectHome = true; # makes empty: /home, /root, /run/user
|
||||
serviceConfig.ProtectHostname = true; # probably not upstreamable: prevents changing hostname
|
||||
serviceConfig.ProtectKernelLogs = true; # disable /proc/kmsg, /dev/kmsg
|
||||
serviceConfig.ProtectKernelModules = true; # syscall filter to prevent module calls
|
||||
serviceConfig.ProtectKernelTunables = true;
|
||||
serviceConfig.ProtectSystem = "full"; # makes read-only: /boot, /etc/, /usr. `strict` isn't possible due to trust-dns hook
|
||||
serviceConfig.RestrictAddressFamilies = [
|
||||
"AF_UNIX" # required, probably for dbus or systemd connectivity
|
||||
];
|
||||
serviceConfig.RestrictSUIDSGID = true;
|
||||
serviceConfig.SystemCallArchitectures = "native"; # prevents e.g. aarch64 syscalls in the event that the kernel is multi-architecture.
|
||||
};
|
||||
|
||||
# harden wpa_supplicant (used by NetworkManager)
|
||||
@@ -109,7 +155,31 @@ in {
|
||||
"CAP_NET_ADMIN"
|
||||
"CAP_NET_RAW"
|
||||
];
|
||||
# TODO: it needs only these paths:
|
||||
serviceConfig.LockPersonality = true;
|
||||
serviceConfig.NoNewPrivileges = true;
|
||||
# serviceConfig.PrivateDevices = true; # untried, not likely to work. remount /dev with just the basics, syscall filter to block @raw-io
|
||||
serviceConfig.PrivateIPC = true;
|
||||
serviceConfig.PrivateTmp = true;
|
||||
# serviceConfig.PrivateUsers = true; #< untried, not likely to work
|
||||
serviceConfig.ProtectClock = true; # syscall filter to prevent changing the RTC
|
||||
serviceConfig.ProtectControlGroups = true;
|
||||
serviceConfig.ProtectHome = true; # makes empty: /home, /root, /run/user
|
||||
serviceConfig.ProtectHostname = true; # prevents changing hostname
|
||||
serviceConfig.ProtectKernelLogs = true; # disable /proc/kmsg, /dev/kmsg
|
||||
serviceConfig.ProtectKernelModules = true; # syscall filter to prevent module calls
|
||||
serviceConfig.ProtectKernelTunables = true; #< N.B.: i think this makes certain /proc writes fail
|
||||
serviceConfig.ProtectSystem = "strict"; # makes read-only: all but /dev, /proc, /sys.
|
||||
serviceConfig.RestrictAddressFamilies = [
|
||||
"AF_INET" #< required
|
||||
"AF_INET6"
|
||||
"AF_NETLINK" #< required
|
||||
"AF_PACKET" #< required
|
||||
"AF_UNIX" #< required (wpa_supplicant wants to use dbus)
|
||||
];
|
||||
serviceConfig.RestrictSUIDSGID = true;
|
||||
serviceConfig.SystemCallArchitectures = "native"; # prevents e.g. aarch64 syscalls in the event that the kernel is multi-architecture.
|
||||
|
||||
# from earlier `landlock` sandboxing, i know it needs only these paths:
|
||||
# - "/dev/net"
|
||||
# - "/dev/rfkill"
|
||||
# - "/proc/sys/net"
|
||||
|
@@ -59,14 +59,18 @@
|
||||
# note the import starts at repo root: this allows `./overlay/default.nix` to access the stuff at the root
|
||||
# "nixpkgs-overlays=${../../..}/hosts/common/nix-path/overlay"
|
||||
# as long as my system itself doesn't rely on NIXPKGS at runtime, we can point the overlays to git
|
||||
# to avoid switching so much during development
|
||||
"nixpkgs-overlays=/home/colin/dev/nixos/hosts/common/nix/overlay"
|
||||
# to avoid `switch`ing so much during development.
|
||||
# TODO: it would be nice to remove this someday!
|
||||
# it's an impurity that touches way more than i need and tends to cause hard-to-debug eval issues
|
||||
# when it goes wrong. should i port my `nix-shell` scripts to something more tailored to my uses
|
||||
# and then delete `nixpkgs-overlays`?
|
||||
"nixpkgs-overlays=/home/colin/dev/nixos/integrations/nixpkgs/nixpkgs-overlays.nix"
|
||||
];
|
||||
|
||||
# ensure new deployments have a source of this repo with which they can bootstrap.
|
||||
# this however changes on every commit and can be slow to copy for e.g. `moby`.
|
||||
environment.etc."nixos" = lib.mkIf (config.sane.maxBuildCost >= 3) {
|
||||
source = ../../..;
|
||||
source = pkgs.sane-nix-files;
|
||||
};
|
||||
environment.etc."nix/registry.json" = lib.mkIf (config.sane.maxBuildCost < 3) {
|
||||
enable = false;
|
@@ -1,4 +0,0 @@
|
||||
# XXX: NIX_PATH=...:nixpkgs-overlays=... will import every overlay in the directory
|
||||
# so we prefer to give it a directory with just this *one* overlay, otherwise it imports conflicting overlays
|
||||
# and gets stuck in a loop until it OOMs
|
||||
import ../../../../overlays/all.nix
|
@@ -50,6 +50,7 @@ in
|
||||
"fd"
|
||||
"file"
|
||||
"forkstat" # monitor every spawned/forked process
|
||||
"free"
|
||||
# "fwupd"
|
||||
"gawk"
|
||||
"gdb" # to debug segfaults
|
||||
@@ -84,6 +85,7 @@ in
|
||||
"parted"
|
||||
"pciutils"
|
||||
"powertop"
|
||||
"ps"
|
||||
"pstree"
|
||||
"ripgrep"
|
||||
"s6-rc" # service manager
|
||||
@@ -97,6 +99,7 @@ in
|
||||
"usbutils" # lsusb
|
||||
"util-linux" # lsblk, lscpu, etc
|
||||
"valgrind"
|
||||
"watch"
|
||||
"wget"
|
||||
"wirelesstools" # iwlist
|
||||
# "xq" # jq for XML
|
||||
@@ -240,6 +243,7 @@ in
|
||||
# "powermanga" # STYLISH space invaders derivative (keyboard-only)
|
||||
"shattered-pixel-dungeon" # doesn't cross compile
|
||||
"space-cadet-pinball" # LMB/RMB controls (bindable though. volume buttons?)
|
||||
"steam"
|
||||
"superTux" # keyboard-only controls
|
||||
"superTuxKart" # poor FPS on pinephone
|
||||
"tumiki-fighters" # keyboard-only
|
||||
@@ -293,6 +297,7 @@ in
|
||||
"loupe" # image viewer
|
||||
"mate.engrampa" # archive manager
|
||||
"mepo" # maps viewer
|
||||
"mesa-demos" # for eglinfo, glxinfo & other testing tools
|
||||
"mpv"
|
||||
"networkmanagerapplet" # for nm-connection-editor: it's better than not having any gui!
|
||||
"ntfy-sh" # notification service
|
||||
@@ -354,7 +359,7 @@ in
|
||||
"gnome.gnome-disk-utility"
|
||||
"gnome.nautilus" # file browser
|
||||
# "gnome.totem" # video player, supposedly supports UPnP
|
||||
"handbrake"
|
||||
# "handbrake" #< TODO: fix build
|
||||
"inkscape"
|
||||
# "jellyfin-media-player"
|
||||
"kdenlive"
|
||||
@@ -373,7 +378,6 @@ in
|
||||
# "slic3r"
|
||||
"soundconverter"
|
||||
"spotify" # x86-only
|
||||
"steam"
|
||||
"tor-browser" # x86-only
|
||||
# "vlc"
|
||||
"wireshark" # could maybe ship the cli as sysadmin pkg
|
||||
@@ -815,6 +819,8 @@ in
|
||||
mercurial.sandbox.net = "clearnet";
|
||||
mercurial.sandbox.whitelistPwd = true;
|
||||
|
||||
mesa-demos = {};
|
||||
|
||||
# actual monero blockchain (not wallet/etc; safe to delete, just slow to regenerate)
|
||||
monero-gui.buildCost = 1;
|
||||
# XXX: is it really safe to persist this? it doesn't have info that could de-anonymize if captured?
|
||||
@@ -1117,6 +1123,8 @@ in
|
||||
"tmp"
|
||||
];
|
||||
|
||||
watch.sandbox.enable = false; #< it executes the command it's given
|
||||
|
||||
wdisplays.sandbox.method = "bwrap";
|
||||
wdisplays.sandbox.whitelistWayland = true;
|
||||
|
||||
|
@@ -1,6 +1,12 @@
|
||||
{ ... }:
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.brave = {
|
||||
# convert eval error to build failure
|
||||
packageUnwrapped = if (builtins.tryEval pkgs.brave).success then
|
||||
pkgs.brave
|
||||
else
|
||||
pkgs.runCommandLocal "brave-not-supported" {} "false"
|
||||
;
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "inplace"; # /opt/share/brave.com vendor-style packaging
|
||||
sandbox.net = "all";
|
||||
|
@@ -1,36 +1,24 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.sane-battery-estimate = {
|
||||
packageUnwrapped = pkgs.static-nix-shell.mkBash {
|
||||
pname = "sane-battery-estimate";
|
||||
srcRoot = ./.;
|
||||
};
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.extraPaths = [
|
||||
"/sys/class/power_supply"
|
||||
"/sys/devices"
|
||||
];
|
||||
};
|
||||
|
||||
sane.programs.conky = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.net = "clearnet"; #< for the scripts it calls (weather)
|
||||
sandbox.extraPaths = [
|
||||
"/sys/class/power_supply"
|
||||
"/sys/devices" # needed by battery_estimate
|
||||
"/sys/devices" # needed by sane-sysinfo
|
||||
# "/sys/devices/cpu"
|
||||
# "/sys/devices/system"
|
||||
];
|
||||
sandbox.whitelistWayland = true;
|
||||
|
||||
suggestedPrograms = [
|
||||
"sane-battery-estimate"
|
||||
"sane-sysinfo"
|
||||
"sane-weather"
|
||||
];
|
||||
|
||||
fs.".config/conky/conky.conf".symlink.target = pkgs.substituteAll {
|
||||
src = ./conky.conf;
|
||||
bat = "sane-battery-estimate";
|
||||
bat = "sane-sysinfo";
|
||||
weather = "timeout 20 sane-weather";
|
||||
};
|
||||
|
||||
|
@@ -1,183 +0,0 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash
|
||||
|
||||
usage() {
|
||||
echo "usage: battery_estimate [options...]"
|
||||
echo
|
||||
echo "pretty-prints a battery estimate (icon to indicate state, and a duration estimate)"
|
||||
echo
|
||||
echo "options:"
|
||||
echo " --debug: output additional information, to stderr"
|
||||
echo " --minute-suffix <string>: use the provided string as a minutes suffix"
|
||||
echo " --hour-suffix <string>: use the provided string as an hours suffix"
|
||||
echo " --icon-suffix <string>: use the provided string as an icon suffix"
|
||||
echo " --percent-suffix <string>: use the provided string when displaying percents"
|
||||
}
|
||||
|
||||
# these icons may only render in nerdfonts
|
||||
icon_bat_chg=("" "" "" "")
|
||||
icon_bat_dis=("" "" "" "")
|
||||
suffix_icon=" " # thin space
|
||||
suffix_percent="%"
|
||||
# suffix_icon=" "
|
||||
|
||||
# render time like: 2ʰ08ᵐ
|
||||
# unicode sub/super-scripts: <https://en.wikipedia.org/wiki/Unicode_subscripts_and_superscripts>
|
||||
# symbol_hr="ʰ"
|
||||
# symbol_min="ᵐ"
|
||||
|
||||
# render time like: 2ₕ08ₘ
|
||||
# symbol_hr="ₕ"
|
||||
# symbol_min="ₘ"
|
||||
|
||||
# render time like: 2h08m
|
||||
# symbol_hr="h"
|
||||
# symbol_min="m"
|
||||
|
||||
# render time like: 2:08
|
||||
# symbol_hr=":"
|
||||
# symbol_min=
|
||||
|
||||
# render time like: 2꞉08⧗
|
||||
symbol_hr="꞉"
|
||||
symbol_min="⧗"
|
||||
# variants:
|
||||
# symbol_hr=":"
|
||||
# symbol_min="⧖"
|
||||
# symbol_min="⌛"
|
||||
|
||||
# render time like: 2'08"
|
||||
# symbol_hr="'"
|
||||
# symbol_min='"'
|
||||
|
||||
log() {
|
||||
if [ "$BATTERY_ESTIMATE_DEBUG" = "1" ]; then
|
||||
printf "$@" >&2
|
||||
echo >&2
|
||||
fi
|
||||
}
|
||||
|
||||
render_icon() {
|
||||
# args:
|
||||
# 1: "chg" or "dis"
|
||||
# 2: current battery percentage
|
||||
level=$(($2 / 25))
|
||||
level=$(($level > 3 ? 3 : $level))
|
||||
level=$(($level < 0 ? 0 : $level))
|
||||
log "icon: %s %d" "$1" "$level"
|
||||
if [ "$1" = "dis" ]; then
|
||||
printf "%s" "${icon_bat_dis[$level]}"
|
||||
elif [ "$1" = "chg" ]; then
|
||||
printf "%s" "${icon_bat_chg[$level]}"
|
||||
fi
|
||||
}
|
||||
|
||||
try_path() {
|
||||
# assigns output variables:
|
||||
# - perc, perc_from_full (0-100)
|
||||
# - full, rate (pos means charging)
|
||||
if [ -f "$1/capacity" ]; then
|
||||
log "perc, perc_from_full from %s" "$1/capacity"
|
||||
perc=$(cat "$1/capacity")
|
||||
perc_from_full=$((100 - $perc))
|
||||
fi
|
||||
|
||||
if [ -f "$1/charge_full_design" ] && [ -f "$1/current_now" ]; then
|
||||
log "full, rate from %s and %s" "$1/charge_full_design" "$1/current_now"
|
||||
# current is positive when charging
|
||||
full=$(cat "$1/charge_full_design")
|
||||
rate=$(cat "$1/current_now")
|
||||
elif [ -f "$1/energy_full" ] && [ -f "$1/power_now" ]; then
|
||||
log "full, rate from %s and %s" "$1/energy_full" "$1/power_now"
|
||||
# power_now is positive when discharging
|
||||
full=$(cat "$1/energy_full")
|
||||
rate=-$(cat "$1/power_now")
|
||||
elif [ -f "$1/energy_full" ] && [ -f "$1/energy_now" ]; then
|
||||
log "full, rate from %s and %s" "$1/energy_full" "$1/energy_now"
|
||||
log " this is a compatibility path for legacy Thinkpad batteries which do not populate the 'power_now' field, and incorrectly populate 'energy_now' with power info"
|
||||
# energy_now is positive when discharging
|
||||
full=$(cat "$1/energy_full")
|
||||
rate=-$(cat "$1/energy_now")
|
||||
fi
|
||||
}
|
||||
|
||||
try_all_paths() {
|
||||
try_path "/sys/class/power_supply/axp20x-battery" # Pinephone
|
||||
try_path "/sys/class/power_supply/BAT0" # Thinkpad
|
||||
log "perc: %d, perc_from_full: %d" "$perc" "$perc_from_full"
|
||||
log "full: %f, rate: %f" "$full" "$rate"
|
||||
log " rate > 0 means charging, else discharging"
|
||||
}
|
||||
|
||||
fmt_minutes() {
|
||||
# args:
|
||||
# 1: icon to render
|
||||
# 2: string to show if charge/discharge time is indefinite
|
||||
# 3: minutes to stable state (i.e. to full charge or full discharge)
|
||||
# - we work in minutes instead of hours for precision: bash math is integer-only
|
||||
log "charge/discharge time: %f min" "$3"
|
||||
# args: <battery symbol> <text if ludicrous estimate> <estimated minutes to full/empty>
|
||||
if [ -n "$3" ] && [ "$3" -lt 1440 ]; then
|
||||
hr=$(($3 / 60))
|
||||
hr_in_min=$(($hr * 60))
|
||||
min=$(($3 - $hr_in_min))
|
||||
printf "%s%s%d%s%02d%s" "$1" "$suffix_icon" "$hr" "$symbol_hr" "$min" "$symbol_min"
|
||||
else
|
||||
log "charge/discharge duration > 1d"
|
||||
printf "%s%s%s" "$1" "$suffix_icon" "$2" # more than 1d
|
||||
fi
|
||||
}
|
||||
|
||||
pretty_output() {
|
||||
if [ -n "$perc" ]; then
|
||||
duration=""
|
||||
if [ "$rate" -gt 0 ]; then
|
||||
log "charging"
|
||||
icon="$(render_icon chg $perc)"
|
||||
duration="$(($full * 60 * $perc_from_full / (100 * $rate)))"
|
||||
else
|
||||
log "discharging"
|
||||
icon="$(render_icon dis $perc)"
|
||||
if [ "$rate" -lt 0 ]; then
|
||||
duration="$(($full * 60 * $perc / (-100 * $rate)))"
|
||||
fi
|
||||
fi
|
||||
fmt_minutes "$icon" "$perc$suffix_percent" "$duration"
|
||||
fi
|
||||
}
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
"--debug")
|
||||
shift
|
||||
BATTERY_ESTIMATE_DEBUG=1
|
||||
;;
|
||||
"--icon-suffix")
|
||||
shift
|
||||
suffix_icon="$1"
|
||||
shift
|
||||
;;
|
||||
"--hour-suffix")
|
||||
shift
|
||||
symbol_hr="$1"
|
||||
shift
|
||||
;;
|
||||
"--minute-suffix")
|
||||
shift
|
||||
symbol_min="$1"
|
||||
shift
|
||||
;;
|
||||
"--percent-suffix")
|
||||
shift
|
||||
suffix_percent="$1"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
try_all_paths
|
||||
pretty_output
|
@@ -45,6 +45,7 @@
|
||||
./flare-signal.nix
|
||||
./fontconfig.nix
|
||||
./fractal.nix
|
||||
./free.nix
|
||||
./frozen-bubble.nix
|
||||
./fwupd.nix
|
||||
./g4music.nix
|
||||
@@ -93,14 +94,17 @@
|
||||
./nmcli.nix
|
||||
./notejot.nix
|
||||
./ntfy-sh.nix
|
||||
./nwg-panel
|
||||
./objdump.nix
|
||||
./obsidian.nix
|
||||
./offlineimap.nix
|
||||
./open-in-mpv.nix
|
||||
./pactl.nix
|
||||
./pipewire.nix
|
||||
./planify.nix
|
||||
./portfolio-filemanager.nix
|
||||
./playerctl.nix
|
||||
./ps.nix
|
||||
./rhythmbox.nix
|
||||
./ripgrep.nix
|
||||
./rofi
|
||||
@@ -110,6 +114,7 @@
|
||||
./sane-open.nix
|
||||
./sane-screenshot.nix
|
||||
./sane-scripts.nix
|
||||
./sane-sysinfo.nix
|
||||
./sane-theme.nix
|
||||
./sanebox.nix
|
||||
./schlock.nix
|
||||
@@ -130,6 +135,7 @@
|
||||
./swayidle.nix
|
||||
./swaylock.nix
|
||||
./swaynotificationcenter
|
||||
./switchboard.nix
|
||||
./sysvol.nix
|
||||
./tangram.nix
|
||||
./tor-browser.nix
|
||||
|
9
hosts/common/programs/free.nix
Normal file
9
hosts/common/programs/free.nix
Normal file
@@ -0,0 +1,9 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.free = {
|
||||
packageUnwrapped = pkgs.linkIntoOwnPackage pkgs.procps "bin/free";
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.isolatePids = false;
|
||||
};
|
||||
}
|
||||
|
@@ -135,65 +135,54 @@ let
|
||||
'cycle_key = "c"' 'cycle_key = "v"'
|
||||
'';
|
||||
});
|
||||
mpv-unwrapped = pkgs.mpv-unwrapped.overrideAttrs (upstream: {
|
||||
version = "0.37.0-unstable-2024-03-31";
|
||||
src = lib.warnIf (lib.versionOlder "0.37.0" upstream.version) "mpv outdated; remove patch?" pkgs.fetchFromGitHub {
|
||||
owner = "mpv-player";
|
||||
repo = "mpv";
|
||||
rev = "4ce4bf1795e6dfd6f1ddf07fb348ce5d191ab1dc";
|
||||
hash = "sha256-nOGuHq7SWDAygROV7qHtezDv1AsMpseImI8TVd3F+Oc=";
|
||||
};
|
||||
patches = [];
|
||||
});
|
||||
in
|
||||
{
|
||||
sane.programs.mpv = {
|
||||
packageUnwrapped = pkgs.wrapMpv
|
||||
(mpv-unwrapped.override rec {
|
||||
packageUnwrapped = pkgs.mpv-unwrapped.wrapper {
|
||||
mpv = pkgs.mpv-unwrapped.override rec {
|
||||
# N.B.: populating `self` to `luajit` is necessary for the resulting `lua.withPackages` function to preserve my override.
|
||||
# i use enable52Compat in order to get `table.unpack`.
|
||||
# i think using `luajit` here instead of `lua` is optional, just i get better perf with it :)
|
||||
lua = pkgs.luajit.override { enable52Compat = true; self = lua; };
|
||||
})
|
||||
{
|
||||
scripts = [
|
||||
pkgs.mpvScripts.mpris
|
||||
pkgs.mpvScripts.mpv-playlistmanager
|
||||
pkgs.mpvScripts.mpv-webm
|
||||
uosc
|
||||
visualizer
|
||||
# pkgs.mpv-uosc-latest
|
||||
];
|
||||
# extraMakeWrapperArgs = lib.optionals (cfg.config.vo != null) [
|
||||
# # 2023/08/29: fixes an error where mpv on moby launches with the message
|
||||
# # "DRM_IOCTL_MODE_CREATE_DUMB failed: Cannot allocate memory"
|
||||
# # audio still works, and controls, screenshotting, etc -- just not the actual rendering
|
||||
# #
|
||||
# # this is likely a regression for mpv 0.36.0.
|
||||
# # the actual error message *appears* to come from the mesa library, but it's tough to trace.
|
||||
# #
|
||||
# # 2024/03/02: no longer necessary, with mesa 23.3.1: <https://github.com/NixOS/nixpkgs/pull/265740>
|
||||
# #
|
||||
# # backend compatibility (2023/10/22):
|
||||
# # run with `--vo=help` to see a list of all output options.
|
||||
# # non-exhaustive (W=works, F=fails, A=audio-only, U=audio+ui only (no video))
|
||||
# # ? null Null video output
|
||||
# # A (default)
|
||||
# # A dmabuf-wayland Wayland dmabuf video output
|
||||
# # A libmpv render API for libmpv (mpv plays the audio, but doesn't even render a window)
|
||||
# # A vdpau VDPAU with X11
|
||||
# # F drm Direct Rendering Manager (software scaling)
|
||||
# # F gpu-next Video output based on libplacebo
|
||||
# # F vaapi VA API with X11
|
||||
# # F x11 X11 (software scaling)
|
||||
# # F xv X11/Xv
|
||||
# # U gpu Shader-based GPU Renderer
|
||||
# # W caca libcaca (terminal rendering)
|
||||
# # W sdl SDL 2.0 Renderer
|
||||
# # W wlshm Wayland SHM video output (software scaling)
|
||||
# "--add-flags" "--vo=${cfg.config.vo}"
|
||||
# ];
|
||||
};
|
||||
scripts = [
|
||||
pkgs.mpvScripts.mpris
|
||||
pkgs.mpvScripts.mpv-playlistmanager
|
||||
pkgs.mpvScripts.mpv-webm
|
||||
uosc
|
||||
visualizer
|
||||
# pkgs.mpv-uosc-latest
|
||||
];
|
||||
# extraMakeWrapperArgs = lib.optionals (cfg.config.vo != null) [
|
||||
# # 2023/08/29: fixes an error where mpv on moby launches with the message
|
||||
# # "DRM_IOCTL_MODE_CREATE_DUMB failed: Cannot allocate memory"
|
||||
# # audio still works, and controls, screenshotting, etc -- just not the actual rendering
|
||||
# #
|
||||
# # this is likely a regression for mpv 0.36.0.
|
||||
# # the actual error message *appears* to come from the mesa library, but it's tough to trace.
|
||||
# #
|
||||
# # 2024/03/02: no longer necessary, with mesa 23.3.1: <https://github.com/NixOS/nixpkgs/pull/265740>
|
||||
# #
|
||||
# # backend compatibility (2023/10/22):
|
||||
# # run with `--vo=help` to see a list of all output options.
|
||||
# # non-exhaustive (W=works, F=fails, A=audio-only, U=audio+ui only (no video))
|
||||
# # ? null Null video output
|
||||
# # A (default)
|
||||
# # A dmabuf-wayland Wayland dmabuf video output
|
||||
# # A libmpv render API for libmpv (mpv plays the audio, but doesn't even render a window)
|
||||
# # A vdpau VDPAU with X11
|
||||
# # F drm Direct Rendering Manager (software scaling)
|
||||
# # F gpu-next Video output based on libplacebo
|
||||
# # F vaapi VA API with X11
|
||||
# # F x11 X11 (software scaling)
|
||||
# # F xv X11/Xv
|
||||
# # U gpu Shader-based GPU Renderer
|
||||
# # W caca libcaca (terminal rendering)
|
||||
# # W sdl SDL 2.0 Renderer
|
||||
# # W wlshm Wayland SHM video output (software scaling)
|
||||
# "--add-flags" "--vo=${cfg.config.vo}"
|
||||
# ];
|
||||
};
|
||||
|
||||
suggestedPrograms = [
|
||||
"blast-to-default"
|
||||
|
@@ -14,7 +14,8 @@ let
|
||||
# docs: https://github.com/nvim-treesitter/nvim-treesitter
|
||||
# config taken from: https://github.com/i077/system/blob/master/modules/home/neovim/default.nix
|
||||
# this is required for tree-sitter to even highlight
|
||||
plugin = nvim-treesitter.withPlugins (_: nvim-treesitter.allGrammars ++ [
|
||||
# XXX(2024/06/03): `unison` removed because it doesn't cross compile
|
||||
plugin = nvim-treesitter.withPlugins (_: (lib.filter (p: p.pname != "unison-grammar") nvim-treesitter.allGrammars) ++ [
|
||||
# XXX: this is apparently not enough to enable syntax highlighting!
|
||||
# nvim-treesitter ships its own queries which may be distinct from e.g. helix.
|
||||
# the queries aren't included when i ship the grammar in this manner
|
||||
@@ -167,9 +168,27 @@ in
|
||||
vim.mpack.decode = vim.mpack.unpack
|
||||
vim.lpeg = require 'lpeg'
|
||||
"
|
||||
'' + lib.optionalString (!stdenv.buildPlatform.canExecute stdenv.hostPlatform) ''
|
||||
substituteInPlace runtime/CMakeLists.txt --replace-fail \
|
||||
'COMMAND $<TARGET_FILE:nvim_bin>' 'COMMAND ${pkgs.stdenv.hostPlatform.emulator pkgs.buildPackages} $<TARGET_FILE:nvim_bin>'
|
||||
''
|
||||
# + lib.optionalString (!stdenv.buildPlatform.canExecute stdenv.hostPlatform) ''
|
||||
# # required for x86_64 -> aarch64 (and probably armv7l too)
|
||||
# substituteInPlace runtime/CMakeLists.txt --replace-fail \
|
||||
# 'COMMAND $<TARGET_FILE:nvim_bin>' 'COMMAND ${pkgs.stdenv.hostPlatform.emulator pkgs.buildPackages} $<TARGET_FILE:nvim_bin>'
|
||||
# ''
|
||||
+ ''
|
||||
# disable translations and syntax highlighting of .vim files because they don't cross x86_64 -> armv7l
|
||||
substituteInPlace src/nvim/CMakeLists.txt --replace-fail \
|
||||
'add_subdirectory(po)' '# add_subdirectory(po)'
|
||||
# substituteInPlace src/nvim/po/CMakeLists.txt --replace-fail \
|
||||
# 'add_dependencies(nvim nvim_translations)' '# add_dependencies(nvim nvim_translations)'
|
||||
substituteInPlace runtime/CMakeLists.txt \
|
||||
--replace-fail ' ''${GENERATED_SYN_VIM}' ' # ''${GENERATED_SYN_VIM}' \
|
||||
--replace-fail ' ''${GENERATED_HELP_TAGS}' ' # ''${GENERATED_HELP_TAGS}' \
|
||||
--replace-fail 'FILES ''${GENERATED_HELP_TAGS} ''${BUILDDOCFILES}' 'FILES ''${CMAKE_CURRENT_SOURCE_DIR}/nvim.desktop' \
|
||||
--replace-fail 'FILES ''${GENERATED_SYN_VIM}' 'FILES ''${CMAKE_CURRENT_SOURCE_DIR}/nvim.desktop' \
|
||||
--replace-fail 'if(''${PACKNAME}_DOC_FILES)' 'if(false)'
|
||||
# --replace-fail ' ''${GENERATED_PACKAGE_TAGS}' ' # ''${GENERATED_PACKAGE_TAGS}' \
|
||||
# --replace-fail 'list(APPEND BUILDDOCFILES' '# list(APPEND BUILDDOCFILES'
|
||||
# --replace-fail ' FILES ''${GENERATED_HELP_TAGS} ' ' FILES ' \
|
||||
'';
|
||||
});
|
||||
in pkgs.wrapNeovimUnstable
|
||||
|
159
hosts/common/programs/nwg-panel/config.nix
Normal file
159
hosts/common/programs/nwg-panel/config.nix
Normal file
@@ -0,0 +1,159 @@
|
||||
# TODO:
|
||||
# - try this PR to get custom workspace names to work:
|
||||
# - <https://github.com/nwg-piotr/nwg-panel/pull/191>
|
||||
# - add network/bluetooth indicator
|
||||
# - <https://github.com/nwg-piotr/nwg-panel/issues/269>
|
||||
# - add CPU/meminfo executor
|
||||
# - use sane-sysinfo
|
||||
{
|
||||
components,
|
||||
height,
|
||||
playerctlChars,
|
||||
windowIcon,
|
||||
windowTitle,
|
||||
workspaceHideEmpty,
|
||||
workspaceNumbers,
|
||||
}:
|
||||
[
|
||||
{
|
||||
controls = "right";
|
||||
css-name = "panel-top";
|
||||
exclusive-zone = true;
|
||||
height = height;
|
||||
homogeneous = false; #< homogenous=false means to not force modules-{left,center,right} to an inflexible 33%/33%/33% real-estate split.
|
||||
icons = "light";
|
||||
items-padding = 0;
|
||||
layer = "bottom";
|
||||
margin-bottom = 0;
|
||||
margin-top = 0;
|
||||
menu-start = "off";
|
||||
name = "panel-top";
|
||||
# output = "All" => display the bar on every output.
|
||||
# - documented: <https://github.com/nwg-piotr/nwg-panel/issues/48>
|
||||
# alternatively, i could declare one bar per display,
|
||||
# and then customize it so that the external display(s) render a less noisy bar.
|
||||
# this will be easier once this is addressed: <https://github.com/nwg-piotr/nwg-panel/issues/215>
|
||||
output = "All";
|
||||
padding-horizontal = 0;
|
||||
padding-vertical = 0;
|
||||
position = "top";
|
||||
sigrt = 64;
|
||||
spacing = 0;
|
||||
start-hidden = false;
|
||||
use-sigrt = false;
|
||||
width = "auto";
|
||||
|
||||
modules-left = [
|
||||
"sway-workspaces"
|
||||
];
|
||||
modules-center = [
|
||||
"clock"
|
||||
];
|
||||
modules-right = [
|
||||
"playerctl"
|
||||
];
|
||||
|
||||
clock = {
|
||||
angle = 0.0;
|
||||
calendar-css-name = "calendar-window";
|
||||
calendar-icon-size = 24;
|
||||
calendar-interval = 60;
|
||||
calendar-margin-horizontal = 0;
|
||||
calendar-margin-vertical = 0;
|
||||
calendar-on = true;
|
||||
calendar-path = "";
|
||||
calendar-placement = "top";
|
||||
css-name = "clock";
|
||||
format = "%H:%M";
|
||||
interval = 30;
|
||||
on-left-click = "";
|
||||
on-middle-click = "";
|
||||
on-right-click = "";
|
||||
on-scroll-down = "";
|
||||
on-scroll-up = "";
|
||||
root-css-name = "root-clock";
|
||||
tooltip-date-format = true;
|
||||
tooltip-text = "%a; %d %b %H:%M:%S";
|
||||
};
|
||||
controls-settings = {
|
||||
battery-low-interval = 4; #< notify every N minutes when battery continues to remain low
|
||||
battery-low-level = 15; #< notify if battery is lower than this percent
|
||||
# commands.battery = ""; #< optional action to perform when battery icon is clicked in the drop-down menu
|
||||
components = components;
|
||||
click-closes = false;
|
||||
custom-items = [];
|
||||
css-name = "controls-window";
|
||||
hover-opens = false;
|
||||
icon-size = 16;
|
||||
interval = 1;
|
||||
leave-closes = false;
|
||||
menu.icon = "system-shutdown-symbolic";
|
||||
menu.items = [
|
||||
{
|
||||
# TODO: plumb through the configured locker instead of assuming `swaylock`
|
||||
name = "Lock";
|
||||
cmd = "swaylock -f -c 000000";
|
||||
}
|
||||
{
|
||||
name = "Logout";
|
||||
cmd = "swaymsg exit";
|
||||
}
|
||||
{
|
||||
name = "Reboot";
|
||||
cmd = "systemctl reboot";
|
||||
}
|
||||
{
|
||||
name = "Shutdown";
|
||||
cmd = "systemctl -i poweroff";
|
||||
}
|
||||
];
|
||||
menu.name = "Exit";
|
||||
output-switcher = true; #< allow changing the default audio sink
|
||||
#v `show-<x>` means "show the NUMERICAL VALUE corresponding to <x>"
|
||||
# e.g. show-battery means "show the battery _percentage_ next to its icon".
|
||||
show-battery = true;
|
||||
show-brightness = false;
|
||||
show-values = false;
|
||||
show-volume = false;
|
||||
# window-width: should be 360 for moby, but because of weird `margin` tweaks in style.css
|
||||
# we have to add 20px to both sides
|
||||
window-width = 400;
|
||||
};
|
||||
playerctl = {
|
||||
button-css-name = "playerctl-button";
|
||||
buttons-position = "left";
|
||||
chars = playerctlChars;
|
||||
icon-size = 16;
|
||||
interval = 2;
|
||||
label-css-name = "playerctl-label";
|
||||
scroll = false;
|
||||
};
|
||||
sway-workspaces = {
|
||||
angle = 0.0;
|
||||
custom-labels = [];
|
||||
focused-labels = [];
|
||||
hide-empty = workspaceHideEmpty;
|
||||
image-size = 16;
|
||||
mark-autotiling = true;
|
||||
mark-content = false;
|
||||
name-length = 40;
|
||||
numbers = workspaceNumbers;
|
||||
show-icon = windowIcon;
|
||||
show-layout = false;
|
||||
show-name = windowTitle;
|
||||
};
|
||||
|
||||
# unused modules:
|
||||
brightness-slider = {};
|
||||
dwl-tags = {};
|
||||
hyprland-taskbar = {};
|
||||
hyprland-workspaces = {};
|
||||
keyboard-layout = {};
|
||||
openweather = {};
|
||||
scratchpad = {};
|
||||
sway-mode = {};
|
||||
sway-taskbar = {}; #< windows-style taskbar, usually placed at the bottom of the screen, to show open windows & tab to them on click
|
||||
tray = {};
|
||||
}
|
||||
]
|
||||
|
132
hosts/common/programs/nwg-panel/default.nix
Normal file
132
hosts/common/programs/nwg-panel/default.nix
Normal file
@@ -0,0 +1,132 @@
|
||||
# nwg-panel: a wayland status bar (like waybar, etc)
|
||||
# documentation is in the GitHub Wiki:
|
||||
# - <https://github.com/nwg-piotr/nwg-panel/wiki/Configuration>
|
||||
#
|
||||
# interactively configure with: `nwg-panel-config`
|
||||
# ^ note that this may interfere with the `nwg-panel` service
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.nwg-panel;
|
||||
mkEnableOption' = default: description: lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
inherit default description;
|
||||
};
|
||||
in
|
||||
{
|
||||
sane.programs.nwg-panel = {
|
||||
configOption = with lib; mkOption {
|
||||
default = {};
|
||||
type = types.submodule {
|
||||
options = {
|
||||
clockFontSize = mkOption {
|
||||
type = types.int;
|
||||
# what looks good:
|
||||
# - 15px on moby
|
||||
# - 24px on lappy
|
||||
default = lib.min 24 (cfg.config.fontSize - 1);
|
||||
};
|
||||
fontSize = mkOption {
|
||||
type = types.int;
|
||||
default = 16;
|
||||
};
|
||||
height = mkOption {
|
||||
type = types.int;
|
||||
default = 40;
|
||||
description = ''
|
||||
height of the top bar in px.
|
||||
'';
|
||||
};
|
||||
battery = mkEnableOption' true "display battery status";
|
||||
brightness = mkEnableOption' true "display backlight level and slider";
|
||||
mediaTitle = mkEnableOption' true "display title of current song/media";
|
||||
mediaPrevNext = mkEnableOption' true "display prev/next button in media";
|
||||
windowIcon = mkEnableOption' true "display icon of active window";
|
||||
windowTitle = mkEnableOption' true "display title of active window";
|
||||
workspaceNumbers = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [
|
||||
# TODO: workspace 10 should be rendered as "TV"
|
||||
"1" "2" "3" "4" "5" "6" "7" "8" "9" "10"
|
||||
];
|
||||
description = ''
|
||||
workspaces to monitor
|
||||
'';
|
||||
};
|
||||
workspaceHideEmpty = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
packageUnwrapped = (pkgs.nwg-panel.override {
|
||||
# XXX(2024/06/13): hyprland does not cross compile
|
||||
hyprland = null;
|
||||
# XXX(2024/06/13): wlr-randr does not cross compile
|
||||
wlr-randr = null; #< only used if not on sway/hyprland; or if using dwl
|
||||
}).overrideAttrs (base: {
|
||||
patches = (base.patches or []) ++ lib.optionals (!cfg.config.mediaPrevNext) [
|
||||
./playerctl-no-prev-next.diff
|
||||
];
|
||||
|
||||
# - disable the drop-down chevron by the controls.
|
||||
# it's precious space on moby, doesn't do much to help on lappy either.
|
||||
# - disable brightness indicator for same reason.
|
||||
# - *leave* the volume indicator: one *could* remove it, however on desko that would leave the controls pane empty
|
||||
# making the dropdown inaccessible
|
||||
postPatch = (base.postPatch or "") + ''
|
||||
substituteInPlace nwg_panel/modules/controls.py --replace-fail \
|
||||
'box.pack_start(self.pan_image, False, False, 4)' \
|
||||
'# box.pack_start(self.pan_image, False, False, 4)'
|
||||
substituteInPlace nwg_panel/modules/controls.py --replace-fail \
|
||||
'box.pack_start(self.bri_image, False, False, 4)' \
|
||||
'# box.pack_start(self.bri_image, False, False, 4)'
|
||||
|
||||
# substituteInPlace nwg_panel/modules/controls.py --replace-fail \
|
||||
# 'box.pack_start(self.vol_image, False, False, 4)' \
|
||||
# '# box.pack_start(self.vol_image, False, False, 4)'
|
||||
'';
|
||||
|
||||
# XXX(2024/06/13) the bluetooth stuff doesn't cross compile, so disable it
|
||||
propagatedBuildInputs = lib.filter (p: p.pname != "pybluez") base.propagatedBuildInputs;
|
||||
|
||||
strictDeps = true;
|
||||
});
|
||||
|
||||
suggestedPrograms = [
|
||||
"pactl" # pactl required by `per-app-volume` component.
|
||||
];
|
||||
|
||||
fs.".config/nwg-panel/style.css".symlink.target = pkgs.substituteAll {
|
||||
src = ./style.css;
|
||||
inherit (cfg.config) fontSize clockFontSize;
|
||||
};
|
||||
fs.".config/nwg-panel/config".symlink.target = pkgs.writers.writeJSON "config" (import ./config.nix {
|
||||
inherit (cfg.config) height windowIcon windowTitle workspaceHideEmpty workspaceNumbers;
|
||||
# component order matters, mostly for the drop-down.
|
||||
# default for most tools (e.g. swaync) is brightness control above volume.
|
||||
components =
|
||||
lib.optionals cfg.config.brightness [
|
||||
"brightness"
|
||||
] ++ [
|
||||
"volume"
|
||||
"per-app-volume"
|
||||
] ++ lib.optionals cfg.config.battery [
|
||||
"battery"
|
||||
]
|
||||
;
|
||||
playerctlChars = if cfg.config.mediaTitle then 60 else 0;
|
||||
});
|
||||
|
||||
services.nwg-panel = {
|
||||
description = "nwg-panel status/topbar for wayland";
|
||||
partOf = [ "graphical-session" ];
|
||||
|
||||
# to debug styling, run with GTK_DEBUG=interactive
|
||||
# N.B.: G_MESSAGES_DEBUG=all causes the swaync icon to not render
|
||||
# command = "env G_MESSAGES_DEBUG=all nwg-panel";
|
||||
command = "nwg-panel";
|
||||
};
|
||||
};
|
||||
}
|
36
hosts/common/programs/nwg-panel/playerctl-no-prev-next.diff
Normal file
36
hosts/common/programs/nwg-panel/playerctl-no-prev-next.diff
Normal file
@@ -0,0 +1,36 @@
|
||||
diff --git a/nwg_panel/modules/playerctl.py b/nwg_panel/modules/playerctl.py
|
||||
index 9b53b4b..c4d96ae 100644
|
||||
--- a/nwg_panel/modules/playerctl.py
|
||||
+++ b/nwg_panel/modules/playerctl.py
|
||||
@@ -180,15 +180,6 @@ class Playerctl(Gtk.EventBox):
|
||||
if self.settings["angle"] != 0.0:
|
||||
button_box.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
|
||||
- img = Gtk.Image()
|
||||
- update_image(img, "media-skip-backward-symbolic", self.settings["icon-size"], icons_path=self.icons_path)
|
||||
- btn = Gtk.Button()
|
||||
- btn.set_image(img)
|
||||
- if self.settings["button-css-name"]:
|
||||
- btn.set_property("name", self.settings["button-css-name"])
|
||||
- btn.connect("clicked", self.launch, self.PlayerOps.PREVIOUS)
|
||||
- button_box.pack_start(btn, False, False, 1)
|
||||
-
|
||||
self.play_pause_btn = Gtk.Button()
|
||||
if self.settings["button-css-name"]:
|
||||
self.play_pause_btn.set_property("name", self.settings["button-css-name"])
|
||||
@@ -198,15 +189,6 @@ class Playerctl(Gtk.EventBox):
|
||||
self.play_pause_btn.connect("clicked", self.launch, self.PlayerOps.PLAY_PAUSE)
|
||||
button_box.pack_start(self.play_pause_btn, False, False, 1)
|
||||
|
||||
- img = Gtk.Image()
|
||||
- update_image(img, "media-skip-forward-symbolic", self.settings["icon-size"], icons_path=self.icons_path)
|
||||
- btn = Gtk.Button()
|
||||
- btn.set_image(img)
|
||||
- if self.settings["button-css-name"]:
|
||||
- btn.set_property("name", self.settings["button-css-name"])
|
||||
- btn.connect("clicked", self.launch, self.PlayerOps.NEXT)
|
||||
- button_box.pack_start(btn, False, False, 1)
|
||||
-
|
||||
self.label = AutoScrollLabel(self.settings["scroll"],
|
||||
self.settings["chars"],
|
||||
self.settings["interval"])
|
215
hosts/common/programs/nwg-panel/style.css
Normal file
215
hosts/common/programs/nwg-panel/style.css
Normal file
@@ -0,0 +1,215 @@
|
||||
/* foreground (text)/background */
|
||||
@define-color fg0 #d8d8d8;
|
||||
@define-color fg1 #ffffff;
|
||||
@define-color bg0 #130c0c;
|
||||
@define-color bg1 #1c1716;
|
||||
/* green accents */
|
||||
@define-color accent-g0 #1f5e54;
|
||||
@define-color accent-g1 #418379;
|
||||
@define-color accent-g2 #63a89c;
|
||||
/* red accents */
|
||||
@define-color accent-r0 #c96262;
|
||||
@define-color accent-r1 #d27871;
|
||||
@define-color accent-r2 #ff968b;
|
||||
/* light (teal-white) accents */
|
||||
@define-color accent-l0 #e1f0ef;
|
||||
@define-color accent-l1 #f9fffc;
|
||||
|
||||
|
||||
* {
|
||||
font-size: @fontSize@px;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
#task-box {
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
#task-box-focused {
|
||||
background-color: @accent-g2;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
|
||||
#playerctl-button {
|
||||
background-color: rgba(0, 0, 0, 0.08);
|
||||
background-image: none;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
margin: -1;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#panel-top {
|
||||
background: @accent-g1;
|
||||
color: @fg1;
|
||||
}
|
||||
|
||||
/* increase the size of each workspace icon */
|
||||
#sway-workspaces-item > label {
|
||||
padding-left: 1px;
|
||||
padding-right: 1px;
|
||||
}
|
||||
/* default config highlights hovered workspace with a gray border */
|
||||
#sway-workspaces > widget:selected {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* the CSS nodes are difficult to determine.
|
||||
* reference: <https://github.com/numixproject/numix-gtk-theme/blob/master/src/gtk-3.20/scss/widgets/_calendar.scss>
|
||||
*/
|
||||
#calendar-window {
|
||||
background-color: @accent-l0;
|
||||
}
|
||||
calendar {
|
||||
background-color: @accent-l0;
|
||||
}
|
||||
calendar :selected {
|
||||
background-color: @accent-r1;
|
||||
}
|
||||
|
||||
|
||||
#controls-window {
|
||||
border-radius: 15px;
|
||||
background: @bg1;
|
||||
color: @fg1;
|
||||
}
|
||||
|
||||
/* default config highlights selected items with a green border */
|
||||
widget:selected {
|
||||
box-shadow: none;
|
||||
background-color: @accent-g0;
|
||||
}
|
||||
#controls-window widget:selected {
|
||||
box-shadow: none;
|
||||
background-color: @accent-r0;
|
||||
}
|
||||
|
||||
/* default config puts a *ridiculous* amount of padding around the whole controls window */
|
||||
#controls-window > widget > .vertical {
|
||||
margin-left: -20px;
|
||||
margin-right: -20px;
|
||||
}
|
||||
#controls-window > widget > .vertical > .horizontal {
|
||||
margin-top: -14px; /* full reset would be -20px */
|
||||
margin-bottom: -20px;
|
||||
}
|
||||
/* add back in a little bit of padding, but in a way such that my highlights apply to it */
|
||||
#controls-window .horizontal widget > box,
|
||||
#controls-window > widget > .vertical > .horizontal > .vertical > .horizontal
|
||||
{
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
}
|
||||
#controls-window > widget > .vertical > .horizontal > .vertical > widget > box
|
||||
{
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
#controls-window > widget > .vertical > .horizontal > .vertical > box > widget > box
|
||||
{
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
/* hierarchy is .horizontal > {image, scale > { value, contents > trough > { slider, highlight } } } */
|
||||
scale {
|
||||
padding-right: 0px;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
scale trough {
|
||||
padding-left: 9px;
|
||||
padding-right: 9px;
|
||||
border-radius: 9px;
|
||||
border-color: rgba(0, 0, 0, 0);
|
||||
background: @bg0;
|
||||
}
|
||||
scale highlight {
|
||||
border-radius: 9px;
|
||||
border-color: rgba(0, 0, 0, 0);
|
||||
margin: 0px;
|
||||
margin-left: -9px;
|
||||
background: @accent-r1;
|
||||
}
|
||||
scale slider {
|
||||
margin-top: -3px;
|
||||
margin-bottom: -3px;
|
||||
background: @accent-l1;
|
||||
min-height: 25px;
|
||||
min-width: 25px;
|
||||
}
|
||||
|
||||
#clock {
|
||||
font-family: monospace;
|
||||
font-size: @clockFontSize@px;
|
||||
}
|
||||
|
||||
/* UNUSED IN MY CURRENT CONFIG: COPIED FROM SAMPLE CONFIG */
|
||||
|
||||
/* Controls window in sample config uses this name */
|
||||
/* Brightness slider popup window in sample config uses this name */
|
||||
#brightness-popup {
|
||||
border-radius: 15px;
|
||||
background: @bg1;
|
||||
color: @fg1;
|
||||
}
|
||||
#brightness-popup box {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
/* Executors usually behave better in monospace fonts */
|
||||
#executor-label {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
/* Bottom panel in sample config uses this name */
|
||||
#panel-bottom {
|
||||
background: #101010;
|
||||
color: #eeeeee;
|
||||
}
|
||||
|
||||
/* Sample executor-weather uses "css-name": "weather" */
|
||||
#weather {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* dwl-tags module */
|
||||
#dwl-tag-box {
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
#dwl-tag-occupied {
|
||||
font-family: monospace;
|
||||
color: #eee;
|
||||
background-color: #006699;
|
||||
padding-left: 3px;
|
||||
padding-right: 3px;
|
||||
}
|
||||
|
||||
#dwl-tag-free {
|
||||
font-family: monospace;
|
||||
color: #eee;
|
||||
background-color: rgba (32, 50, 90, 1.0);
|
||||
padding-left: 3px;
|
||||
padding-right: 3px;
|
||||
}
|
||||
|
||||
#dwl-tag-urgent {
|
||||
font-family: monospace;
|
||||
color: #eee;
|
||||
background-color: #ee6600;
|
||||
padding-left: 3px;
|
||||
padding-right: 3px;
|
||||
}
|
||||
|
||||
#dwl-tag-selected {
|
||||
border: solid 2px;
|
||||
border-color: #81a1c1;
|
||||
}
|
6
hosts/common/programs/pactl.nix
Normal file
6
hosts/common/programs/pactl.nix
Normal file
@@ -0,0 +1,6 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.pactl = {
|
||||
packageUnwrapped = pkgs.linkIntoOwnPackage pkgs.pulseaudio "bin/pactl";
|
||||
};
|
||||
}
|
8
hosts/common/programs/ps.nix
Normal file
8
hosts/common/programs/ps.nix
Normal file
@@ -0,0 +1,8 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.ps = {
|
||||
packageUnwrapped = pkgs.linkIntoOwnPackage pkgs.procps "bin/ps";
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.isolatePids = false;
|
||||
};
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p sane-open
|
||||
#!nix-shell -i bash -p bash -p sane-open
|
||||
|
||||
# use:
|
||||
# rofi-run-command <handler>.desktop [cmd [args ...]]
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p gnused -p rofi -p wtype
|
||||
#!nix-shell -i bash -p bash -p gnused -p rofi -p wtype
|
||||
|
||||
# "bookmarking"/snippets inspired by Luke Smith:
|
||||
# - <https://www.youtube.com/watch?v=d_11QaTlf1I>
|
||||
|
@@ -85,7 +85,7 @@ in
|
||||
"playerctl"
|
||||
"procps"
|
||||
"sane-open"
|
||||
"sway"
|
||||
# "sway" #< TODO: circular dependency :-(
|
||||
"wireplumber"
|
||||
# optional integrations:
|
||||
"megapixels"
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p coreutils -p jq -p killall -p playerctl -p procps -p sane-open -p sway -p util-linux -p wireplumber
|
||||
#!nix-shell -i bash -p bash -p coreutils -p jq -p killall -p playerctl -p procps -p sane-open -p sway -p util-linux -p wireplumber
|
||||
# vim: set filetype=bash :
|
||||
|
||||
# input map considerations
|
||||
@@ -85,21 +85,38 @@ log() {
|
||||
|
||||
## HELPERS
|
||||
|
||||
isTouchOn() {
|
||||
# success if all touch inputs have their events enabled
|
||||
# swaySetOutput true|false
|
||||
# turns the display on or off
|
||||
swaySetOutput() {
|
||||
swaymsg -- output '*' power "$1"
|
||||
}
|
||||
# swaySetTouch enabled|disabled
|
||||
# turns touch input on or off
|
||||
swaySetTouch() {
|
||||
# XXX(2024/06/09): `type:touch` method is documented, but now silently fails
|
||||
# swaymsg -- input type:touch events "$1"
|
||||
|
||||
local inputs=$(swaymsg -t get_inputs --raw | jq '. | map(select(.type == "touch")) | map(.identifier) | join(" ")' --raw-output)
|
||||
for id in "${inputs[@]}"; do
|
||||
swaymsg -- input "$id" events "$1"
|
||||
done
|
||||
}
|
||||
|
||||
# success if all touch inputs have their events enabled
|
||||
swayGetTouch() {
|
||||
swaymsg -t get_inputs --raw \
|
||||
| jq --exit-status '. | map(select(.type == "touch")) | all(.libinput.send_events == "enabled")' \
|
||||
> /dev/null
|
||||
}
|
||||
isScreenOn() {
|
||||
# success if all outputs have power
|
||||
# success if all outputs have power
|
||||
swayGetOutput() {
|
||||
swaymsg -t get_outputs --raw \
|
||||
| jq --exit-status '. | all(.power)' \
|
||||
> /dev/null
|
||||
}
|
||||
|
||||
isAllOn() {
|
||||
isTouchOn && isScreenOn
|
||||
swayGetOutput && swayGetTouch
|
||||
}
|
||||
|
||||
isInhibited() {
|
||||
@@ -134,12 +151,12 @@ unmapped() {
|
||||
}
|
||||
|
||||
allOn() {
|
||||
swaymsg -- output '*' power true
|
||||
swaymsg -- input type:touch events enabled
|
||||
swaySetOutput true
|
||||
swaySetTouch enabled
|
||||
}
|
||||
allOff() {
|
||||
swaymsg -- output '*' power false
|
||||
swaymsg -- input type:touch events disabled
|
||||
swaySetOutput false
|
||||
swaySetTouch disabled
|
||||
}
|
||||
|
||||
toggleKeyboard() {
|
||||
|
10
hosts/common/programs/sane-sysinfo.nix
Normal file
10
hosts/common/programs/sane-sysinfo.nix
Normal file
@@ -0,0 +1,10 @@
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs.sane-sysinfo = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.extraPaths = [
|
||||
"/sys/class/power_supply"
|
||||
"/sys/devices"
|
||||
];
|
||||
};
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p jq -p sway -p util-linux
|
||||
#!nix-shell -i bash -p bash -p jq -p sway -p util-linux
|
||||
|
||||
help() {
|
||||
echo "queries the focused window and apply an appropriate display-wide scale."
|
||||
|
@@ -28,7 +28,7 @@ let
|
||||
passthru.sway-unwrapped = configuredSway;
|
||||
};
|
||||
|
||||
wlroots = (pkgs.waylandPkgs.wlroots.override {
|
||||
wlroots = (pkgs.nixpkgs-wayland.wlroots.override {
|
||||
# wlroots seems to launch Xwayland itself, and i can't easily just do that myself externally.
|
||||
# so in order for the Xwayland it launches to be sandboxed, i need to patch the sandboxed version in here.
|
||||
xwayland = config.sane.programs.xwayland.package;
|
||||
@@ -60,7 +60,7 @@ let
|
||||
'';
|
||||
});
|
||||
swayPackage = wrapSway (
|
||||
(pkgs.waylandPkgs.sway-unwrapped.override {
|
||||
(pkgs.nixpkgs-wayland.sway-unwrapped.override {
|
||||
inherit wlroots;
|
||||
# about xwayland:
|
||||
# - required by many electron apps, though some electron apps support NIXOS_OZONE_WL=1 for native wayland.
|
||||
@@ -107,6 +107,14 @@ in
|
||||
default font (for e.g. window titles)
|
||||
'';
|
||||
};
|
||||
locker = mkOption {
|
||||
type = types.str;
|
||||
default = "swaylock";
|
||||
description = ''
|
||||
name of program to use as the screenlocker
|
||||
'';
|
||||
example = "schlock";
|
||||
};
|
||||
mod = mkOption {
|
||||
type = types.str;
|
||||
default = "Mod4";
|
||||
@@ -140,6 +148,7 @@ in
|
||||
"fontconfig"
|
||||
# "gnome.gnome-bluetooth" # XXX(2023/05/14): broken
|
||||
# "gnome.gnome-control-center" # XXX(2023/06/28): depends on webkitgtk4_1
|
||||
"nwg-panel"
|
||||
"pipewire"
|
||||
"playerctl" # for waybar & particularly to have playerctld running
|
||||
"rofi" # menu/launcher
|
||||
@@ -152,11 +161,11 @@ in
|
||||
# "splatmoji" # used by sway config
|
||||
"sway-contrib.grimshot" # used by sway config
|
||||
"swayidle" # enable if you need it
|
||||
"swaylock" # used by sway config
|
||||
"swaynotificationcenter" # notification daemon
|
||||
"switchboard" # network/bluetooth/sound control panel
|
||||
"sysvol" # volume notifier
|
||||
"unl0kr" # greeter
|
||||
"waybar" # used by sway config
|
||||
# "waybar"
|
||||
"wdisplays" # like xrandr
|
||||
"wireplumber" # used by sway config
|
||||
"wl-clipboard"
|
||||
@@ -179,6 +188,8 @@ in
|
||||
# xdg-desktop-portal-wlr provides portals for screenshots/screen sharing
|
||||
"xdg-desktop-portal-wlr"
|
||||
"xdg-terminal-exec" # used by sway config
|
||||
] ++ [
|
||||
cfg.config.locker
|
||||
];
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
@@ -220,6 +231,7 @@ in
|
||||
inherit (cfg.config)
|
||||
extra_lines
|
||||
font
|
||||
locker
|
||||
mod
|
||||
workspace_layout
|
||||
;
|
||||
|
@@ -16,6 +16,7 @@ set $volume_up wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+
|
||||
set $volume_down wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
|
||||
set $mute wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
|
||||
set $default_workspace_layout @workspace_layout@
|
||||
set $locker @locker@
|
||||
|
||||
set $out_tv "LG Electronics LG TV 0x01010101"
|
||||
set $out_projector "MS Telematica TV 0x00000001"
|
||||
@@ -79,7 +80,7 @@ bindsym --locked XF86MonBrightnessDown exec brightnessctl set 5%-
|
||||
#### special functions
|
||||
bindsym Print exec sane-open --application sane-screenshot.desktop
|
||||
bindsym $mod+Print exec sane-open --application sane-screenshot.desktop
|
||||
bindsym $mod+l exec s6-rc -b start swaylock
|
||||
bindsym $mod+l exec s6-rc -b start $locker
|
||||
bindsym $mod+s exec sane-open --application rofi-snippets.desktop
|
||||
# bindsym $mod+slash exec sane-open splatmoji.desktop
|
||||
bindsym $mod+d exec sane-open --application rofi.desktop
|
||||
|
@@ -44,7 +44,13 @@ let
|
||||
});
|
||||
screenOff = pkgs.writeShellScriptBin "screen-off" ''
|
||||
swaymsg -- output '*' power false
|
||||
swaymsg -- input type:touch events disabled
|
||||
# XXX(2024/06/09): `type:touch` method is documented, but now silently fails
|
||||
# swaymsg -- input type:touch events disabled
|
||||
|
||||
local inputs=$(swaymsg -t get_inputs --raw | jq '. | map(select(.type == "touch")) | map(.identifier) | join(" ")' --raw-output)
|
||||
for id in "''${inputs[@]}"; do
|
||||
swaymsg -- input "$id" events disabled
|
||||
done
|
||||
'';
|
||||
in
|
||||
{
|
||||
@@ -74,6 +80,11 @@ in
|
||||
command = lib.mkDefault "";
|
||||
};
|
||||
|
||||
suggestedPrograms = [
|
||||
"jq"
|
||||
# "sway" #< required, but circular dep
|
||||
];
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.whitelistDbus = [ "user" ]; #< might need system too, for inhibitors
|
||||
sandbox.whitelistS6 = true;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p feedbackd -p procps -p swaynotificationcenter -p util-linux
|
||||
#!nix-shell -i bash -p bash -p feedbackd -p procps -p swaynotificationcenter -p util-linux
|
||||
|
||||
# this script does some really unusual indirection with the `start` action:
|
||||
# IT'S INTENTIONAL.
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p s6 -p s6-rc
|
||||
#!nix-shell -i bash -p bash -p s6 -p s6-rc
|
||||
|
||||
# for default $PATH to take precedence over nix-shell PATH if invoked interactively,
|
||||
# otherwise we invoke a s6-rc which does not know where to find files.
|
||||
|
28
hosts/common/programs/switchboard.nix
Normal file
28
hosts/common/programs/switchboard.nix
Normal file
@@ -0,0 +1,28 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.switchboard = {
|
||||
packageUnwrapped = with pkgs.pantheon; switchboard-with-plugs.override {
|
||||
switchboardPlugs = [
|
||||
# switchboard-plug-a11y
|
||||
# switchboard-plug-about
|
||||
# switchboard-plug-applications
|
||||
# switchboard-plug-bluetooth #< TODO(2024/06/13): would be nice to have, but doesn't cross-compile
|
||||
# switchboard-plug-datetime
|
||||
# switchboard-plug-display # could be handy, but crashes
|
||||
# switchboard-plug-keyboard
|
||||
# switchboard-plug-mouse-touchpad # changing settings here doesn't actually impact anything real
|
||||
switchboard-plug-network
|
||||
# switchboard-plug-notifications
|
||||
# switchboard-plug-onlineaccounts
|
||||
# switchboard-plug-pantheon-shell
|
||||
# switchboard-plug-power # needs to be "unlocked" before it can do anything (like change display brightness)
|
||||
# switchboard-plug-printers # requires cups
|
||||
# switchboard-plug-security-privacy
|
||||
# switchboard-plug-sharing
|
||||
switchboard-plug-sound
|
||||
# switchboard-plug-wacom
|
||||
];
|
||||
xorg = pkgs.buildPackages.xorg; #< cross compilation fix (TODO: upstream)
|
||||
};
|
||||
};
|
||||
}
|
@@ -7,6 +7,9 @@
|
||||
|
||||
fs.".config/sys64/volume.css".symlink.text = ''
|
||||
window {
|
||||
background: transparent;
|
||||
}
|
||||
window > box {
|
||||
background: #000000B4;
|
||||
border-radius: 19px;
|
||||
}
|
||||
@@ -56,14 +59,15 @@
|
||||
partOf = [ "graphical-session" ];
|
||||
|
||||
# options:
|
||||
# -p {0,1,2,3} to attach to top/right/bottom/left screen edge
|
||||
# -p {bottom,left,right,top} to attach to the corresponding screen edge
|
||||
# -t N for the notifier to be dismissed after N seconds (integer only)
|
||||
# -T N reveal/hide transition time in milliseconds
|
||||
# -m N to set the indicator this many pixels in from the edge.
|
||||
# it considers sway bars, but not window titles
|
||||
# -{H,W} N to set the height/width of the notifier, in px.
|
||||
# -i N to set the size of the volume icon
|
||||
# -P to hide percentage text
|
||||
command = "sysvol -p 0 -t 1 -m 22 -H 39 -W 256 -i 32 -P";
|
||||
command = "sysvol -p top -t 1 -T 0 -m 22 -H 39 -W 256 -i 32 -P";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@@ -15,6 +15,15 @@ let
|
||||
PATH=$PATH:$extraPath command -v "$1"
|
||||
}
|
||||
|
||||
# give some time for the framebuffer device to appear;
|
||||
# unl0kr depends on it but doesn't know to wait for it.
|
||||
for _ in $(seq 25); do
|
||||
if [ -e /dev/fb0 ]; then
|
||||
break
|
||||
fi
|
||||
sleep 0.2
|
||||
done
|
||||
|
||||
# TODO: make this more robust to failure.
|
||||
# - if `unl0kr` fails, then the second `redirect-tty` sends a newline to `login`, causing it to exit and the service fails.
|
||||
# - if `redirect-tty` fails, then... the service is left hanging.
|
||||
@@ -134,8 +143,6 @@ in
|
||||
# necessary for `sanebox` to be found. TODO: add this to every systemd service.
|
||||
"/run/current-system/sw" # `/bin` is appended
|
||||
];
|
||||
# needed to find sanebox profiles (TODO: add this to every service)
|
||||
environment.XDG_DATA_DIRS = "/run/current-system/sw/share";
|
||||
|
||||
serviceConfig.Type = "simple";
|
||||
serviceConfig.Restart = "always";
|
||||
|
@@ -1,7 +1,7 @@
|
||||
[general]
|
||||
animations=false
|
||||
#backend=fbdev|drm
|
||||
#timeout=300
|
||||
# backend=fbdev|drm
|
||||
# timeout=300
|
||||
|
||||
[keyboard]
|
||||
autohide=false
|
||||
@@ -16,12 +16,14 @@ obscured=true
|
||||
default=breezy-light
|
||||
alternate=breezy-dark
|
||||
|
||||
#[input]
|
||||
#keyboard=false
|
||||
#pointer=false
|
||||
#touchscreen=false
|
||||
# [input]
|
||||
# keyboard=false
|
||||
# pointer=false
|
||||
# touchscreen=false
|
||||
|
||||
#[quirks]
|
||||
#fbdev_force_refresh=true
|
||||
#terminal_prevent_graphics_mode=true
|
||||
#terminal_allow_keyboard_input=true
|
||||
# [quirks]
|
||||
# fbdev_force_refresh=true
|
||||
# terminal_prevent_graphics_mode=true
|
||||
# TODO: terminal_allow_keyboard_input=true could be used to pipe my password
|
||||
# straight into `login`, instead of the more convoluted redirect approach??
|
||||
# terminal_allow_keyboard_input=true
|
||||
|
@@ -110,7 +110,7 @@ in
|
||||
};
|
||||
|
||||
services.waybar = {
|
||||
description = "swaybar graphical header bar/tray for sway";
|
||||
description = "waybar status/topbar for sway";
|
||||
partOf = [ "graphical-session" ];
|
||||
|
||||
# env G_MESSAGES_DEBUG=all
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p jq -p playerctl
|
||||
#!nix-shell -i bash -p bash -p jq -p playerctl
|
||||
status=$(playerctl status 2> /dev/null | tr 'A-Z' 'a-z')
|
||||
if [ -z "$status" ]; then
|
||||
status="inactive"
|
||||
|
@@ -115,6 +115,7 @@ in
|
||||
programs.zsh = lib.mkIf cfg.enabled {
|
||||
enable = true;
|
||||
shellAliases = {
|
||||
":fg" = "fg";
|
||||
":q" = "exit";
|
||||
# common typos
|
||||
"cd.." = "cd ..";
|
||||
@@ -186,7 +187,7 @@ in
|
||||
};
|
||||
|
||||
function switch() {
|
||||
nix run '.#deploy.self'
|
||||
~/nixos/scripts/deploy "$@"
|
||||
}
|
||||
'';
|
||||
|
||||
|
30
hosts/common/quirks.nix
Normal file
30
hosts/common/quirks.nix
Normal file
@@ -0,0 +1,30 @@
|
||||
# quirks: temporary patches with the goal of eventually removing them
|
||||
{ lib, ... }:
|
||||
{
|
||||
# TODO: remove after linux 6.9. see: <https://github.com/axboe/liburing/issues/1113>
|
||||
# - <https://github.com/neovim/neovim/issues/28149>
|
||||
# - <https://git.kernel.dk/cgit/linux/commit/?h=io_uring-6.9&id=e5444baa42e545bb929ba56c497e7f3c73634099>
|
||||
# when removing, try starting and suspending (ctrl+z) two instances of neovim simultaneously.
|
||||
# if the system doesn't freeze, then this is safe to remove.
|
||||
# added 2024-04-04
|
||||
sane.user.fs.".profile".symlink.text = lib.mkBefore ''
|
||||
export UV_USE_IO_URING=0
|
||||
'';
|
||||
|
||||
# powertop will default to putting USB devices -- including HID -- to sleep after TWO SECONDS
|
||||
powerManagement.powertop.enable = false;
|
||||
# linux CPU governor: <https://www.kernel.org/doc/Documentation/cpu-freq/governors.txt>
|
||||
# - options:
|
||||
# - "powersave" => force CPU to always run at lowest supported frequency
|
||||
# - "performance" => force CPU to always run at highest frequency
|
||||
# - "ondemand" => adjust frequency based on load
|
||||
# - "conservative" (ondemand but slower to adjust)
|
||||
# - "schedutil"
|
||||
# - "userspace"
|
||||
# - not all options are available for all platforms
|
||||
# - intel (intel_pstate) appears to manage scaling w/o intervention/control from the OS.
|
||||
# - AMD (acpi-cpufreq) appears to manage scaling via the OS *or* HW. but the ondemand defaults never put it to max hardware frequency.
|
||||
# - qualcomm (cpufreq-dt) appears to manage scaling *only* via the OS. ondemand governor exercises the full range.
|
||||
# - query details with `sudo cpupower frequency-info`
|
||||
powerManagement.cpuFreqGovernor = "ondemand";
|
||||
}
|
@@ -7,22 +7,12 @@ let
|
||||
haltTimeout = 10;
|
||||
in
|
||||
{
|
||||
systemd.extraConfig = ''
|
||||
# DefaultTimeoutStopSec defaults to 90s, and frequently blocks overall system shutdown.
|
||||
DefaultTimeoutStopSec=${builtins.toString haltTimeout}
|
||||
'';
|
||||
|
||||
services.journald.extraConfig = ''
|
||||
# docs: `man journald.conf`
|
||||
# merged journald config is deployed to /etc/systemd/journald.conf
|
||||
[Journal]
|
||||
# disable journal compression because the underlying fs is compressed
|
||||
Compress=no
|
||||
'';
|
||||
|
||||
# allow ordinary users to `reboot` or `shutdown`.
|
||||
# source: <https://nixos.wiki/wiki/Polkit>
|
||||
security.polkit.extraConfig = ''
|
||||
/* allow ordinary users to:
|
||||
* - reboot
|
||||
* - shutdown
|
||||
* source: <https://nixos.wiki/wiki/Polkit>
|
||||
*/
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (
|
||||
subject.isInGroup("users")
|
||||
@@ -37,5 +27,38 @@ in
|
||||
return polkit.Result.YES;
|
||||
}
|
||||
})
|
||||
|
||||
/* allow members of wheel to:
|
||||
* - systemctl daemon-reload
|
||||
* - systemctl stop|start|restart SERVICE
|
||||
*/
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (subject.isInGroup("wheel") && (
|
||||
action.id == "org.freedesktop.systemd1.reload-daemon" ||
|
||||
action.id == "org.freedesktop.systemd1.manage-units"
|
||||
)) {
|
||||
return polkit.Result.YES;
|
||||
}
|
||||
})
|
||||
'';
|
||||
|
||||
services.journald.extraConfig = ''
|
||||
# docs: `man journald.conf`
|
||||
# merged journald config is deployed to /etc/systemd/journald.conf
|
||||
[Journal]
|
||||
# disable journal compression because the underlying fs is compressed
|
||||
Compress=no
|
||||
'';
|
||||
|
||||
# see: `man logind.conf`
|
||||
# don’t shutdown when power button is short-pressed (commonly done an accident, or by cats).
|
||||
# but do on long-press: useful to gracefully power-off server.
|
||||
services.logind.powerKey = "lock";
|
||||
services.logind.powerKeyLongPress = "poweroff";
|
||||
services.logind.lidSwitch = "lock";
|
||||
|
||||
systemd.extraConfig = ''
|
||||
# DefaultTimeoutStopSec defaults to 90s, and frequently blocks overall system shutdown.
|
||||
DefaultTimeoutStopSec=${builtins.toString haltTimeout}
|
||||
'';
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@
|
||||
"media" # servo
|
||||
"networkmanager"
|
||||
"nixbuild"
|
||||
"render" # for crappy, /dev/dri/render*
|
||||
"seat" # for sway, if using seatd
|
||||
"systemd-journal" # allows to view other user's journals (esp system users)
|
||||
"transmission" # servo
|
||||
|
@@ -3,11 +3,11 @@
|
||||
{
|
||||
imports = [
|
||||
./derived-secrets
|
||||
./hal
|
||||
./hosts.nix
|
||||
./nixcache.nix
|
||||
./roles
|
||||
./services
|
||||
./wg-home.nix
|
||||
./yggdrasil.nix
|
||||
];
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash
|
||||
#!nix-shell -i bash -p bash
|
||||
file="$1"
|
||||
enc="$2"
|
||||
nibbles="$3"
|
||||
|
8
hosts/modules/hal/default.nix
Normal file
8
hosts/modules/hal/default.nix
Normal file
@@ -0,0 +1,8 @@
|
||||
{ ... }:
|
||||
{
|
||||
imports = [
|
||||
./pine64.nix
|
||||
./samsung
|
||||
./x86_64.nix
|
||||
];
|
||||
}
|
343
hosts/modules/hal/pine64.nix
Normal file
343
hosts/modules/hal/pine64.nix
Normal file
@@ -0,0 +1,343 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.hal.pine64;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
sane.hal.pine64.enable = lib.mkEnableOption "pine64-specific hardware support";
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
# kernel compatibility (2024/05/22: 03dab630)
|
||||
# - linux-megous: boots to ssh, desktop
|
||||
# - camera apps: megapixels (no cameras found), snapshot (no cameras found)
|
||||
# - linux-postmarketos-allwinner: boots to ssh. desktop ONLY if "anx7688" is in the initrd.availableKernelModules.
|
||||
# - camera apps: megapixels (both rear and front cameras work), `cam -l` (finds only the rear camera), snapshot (no cameras found)
|
||||
# - linux-megous.override { withMegiPinephoneConfig = true; }: NO SSH, NO SIGNS OF LIFE
|
||||
# - linux-megous.override { withFullConfig = false; }: boots to ssh, no desktop
|
||||
#
|
||||
boot.kernelPackages = pkgs.linuxPackagesFor (pkgs.linux-postmarketos-allwinner.override {
|
||||
withModemPower = true;
|
||||
});
|
||||
# boot.kernelPackages = pkgs.linuxPackagesFor pkgs.linux-megous;
|
||||
# boot.kernelPackages = pkgs.linuxPackagesFor (pkgs.linux-megous.override {
|
||||
# withFullConfig = false;
|
||||
# });
|
||||
# boot.kernelPackages = pkgs.linuxPackagesFor (pkgs.linux-megous.override {
|
||||
# withMegiPinephoneConfig = true; #< N.B.: does not boot as of 2024/05/22!
|
||||
# });
|
||||
# boot.kernelPackages = pkgs.linuxPackagesFor pkgs.linux-manjaro;
|
||||
# boot.kernelPackages = pkgs.linuxPackagesFor pkgs.linux_latest;
|
||||
|
||||
# nixpkgs.hostPlatform.linux-kernel becomes stdenv.hostPlatform.linux-kernel
|
||||
# ^ but only if using flakes (or rather, if *not* using `nixpkgs.nixos` to construct the host config)
|
||||
# nixpkgs.hostPlatform.linux-kernel = {
|
||||
# # defaults:
|
||||
# name = "aarch64-multiplatform";
|
||||
# # baseConfig: defaults to "defconfig";
|
||||
# # baseConfig = "pinephone_defconfig"; #< N.B.: ignored by `pkgs.linux-megous`
|
||||
# DTB = true; #< DTB: compile device tree blobs
|
||||
# # autoModules (default: true): for config options not manually specified, answer `m` to anything which supports it.
|
||||
# # - this effectively builds EVERY MODULE SUPPORTED.
|
||||
# autoModules = true; #< N.B.: ignored by `pkgs.linux-megous`
|
||||
# # preferBuiltin (default: false; true for rpi): for config options which default to `Y` upstream, build them as `Y` (overriding `autoModules`)
|
||||
# # preferBuiltin = false;
|
||||
|
||||
# # build a compressed kernel image: without this i run out of /boot space in < 10 generations
|
||||
# # target = "Image"; # <-- default
|
||||
# target = "Image.gz"; # <-- compress the kernel image
|
||||
# # target = "zImage"; # <-- confuses other parts of nixos :-(
|
||||
# };
|
||||
|
||||
# boot.initrd.kernelModules = [
|
||||
# "drm" #< force drm to be plugged
|
||||
# ];
|
||||
boot.initrd.availableKernelModules = [
|
||||
# see <repo:postmarketOS/pmaports:device/main/device-pine64-pinephone/modules-initfs>
|
||||
# - they include sun6i_mipi_dsi sun4i_drm pwm_sun4i sun8i_mixer anx7688 gpio_vibra pinephone_keyboard
|
||||
"anx7688" #< required for display initialization and functional cameras
|
||||
# full list of modules active post-boot with the linux-megous kernel + autoModules=true:
|
||||
# - `lsmod | sort | cut -d ' ' -f 1`
|
||||
# "8723cs"
|
||||
# "axp20x_adc" #< NOT FOUND in megous-no-autoModules
|
||||
# "axp20x_battery"
|
||||
# "axp20x_pek"
|
||||
# "axp20x_usb_power"
|
||||
# "backlight"
|
||||
# "blake2b_generic"
|
||||
# "bluetooth"
|
||||
# "bridge"
|
||||
# "btbcm"
|
||||
# "btqca"
|
||||
# "btrfs"
|
||||
# "btrtl"
|
||||
# "cec"
|
||||
# "cfg80211"
|
||||
# "chacha_neon"
|
||||
# "crc_ccitt"
|
||||
# "crct10dif_ce"
|
||||
# "crypto_engine"
|
||||
# "display_connector" #< NOT FOUND in pmos
|
||||
# "drm"
|
||||
# "drm_display_helper"
|
||||
# "drm_dma_helper"
|
||||
# "drm_kms_helper"
|
||||
# "drm_shmem_helper"
|
||||
# "dw_hdmi"
|
||||
# "dw_hdmi_cec" #< NOT FOUND in pmos
|
||||
# "dw_hdmi_i2s_audio"
|
||||
# "ecc"
|
||||
# "ecdh_generic"
|
||||
# "fuse"
|
||||
# "gc2145" #< NOT FOUND in megous-no-autoModules
|
||||
# "goodix_ts"
|
||||
# "gpio_vibra" #< NOT FOUND in megous-no-autoModules
|
||||
# "gpu_sched"
|
||||
# "hci_uart"
|
||||
# "i2c_gpio"
|
||||
# "inv_mpu6050" #< NOT FOUND in megous-no-autoModules
|
||||
# "inv_mpu6050_i2c" #< NOT FOUND in megous-no-autoModules
|
||||
# "inv_sensors_timestamp" #< NOT FOUND in megous-no-autoModules
|
||||
# "ip6t_rpfilter"
|
||||
# "ip6_udp_tunnel"
|
||||
# "ip_set"
|
||||
# "ip_set_hash_ipport"
|
||||
# "ip_tables"
|
||||
# "ipt_rpfilter"
|
||||
# "joydev"
|
||||
# "led_class_flash" #< NOT FOUND in megous-no-autoModules
|
||||
# "leds_sgm3140" #< NOT FOUND in megous-no-autoModules
|
||||
# "ledtrig_pattern" #< NOT FOUND in megous-no-autoModules
|
||||
# "libarc4"
|
||||
# "libchacha"
|
||||
# "libchacha20poly1305"
|
||||
# "libcrc32c"
|
||||
# "libcurve25519_generic"
|
||||
# "lima"
|
||||
# "llc"
|
||||
# "mac80211"
|
||||
# "macvlan"
|
||||
# "mc"
|
||||
# "modem_power"
|
||||
# "mousedev"
|
||||
# "nf_conntrack"
|
||||
# "nf_defrag_ipv4"
|
||||
# "nf_defrag_ipv6"
|
||||
# "nf_log_syslog"
|
||||
# "nf_nat"
|
||||
# "nfnetlink"
|
||||
# "nf_tables"
|
||||
# "nft_chain_nat"
|
||||
# "nft_compat"
|
||||
# "nls_cp437"
|
||||
# "nls_iso8859_1"
|
||||
# "nvmem_reboot_mode"
|
||||
# "ov5640"
|
||||
# "panel_sitronix_st7703"
|
||||
# "phy_sun6i_mipi_dphy"
|
||||
# "pinctrl_axp209" #< NOT FOUND in pmos
|
||||
# "pinephone_keyboard" #< NOT FOUND in megous-no-autoModules
|
||||
# "poly1305_neon"
|
||||
# "polyval_ce"
|
||||
# "polyval_generic"
|
||||
# "ppkb_manager" #< NOT FOUND in megous-no-autoModules
|
||||
# "pwm_bl"
|
||||
# "pwm_sun4i"
|
||||
# "qrtr"
|
||||
# "raid6_pq"
|
||||
# "rfkill"
|
||||
# "rtw88_8703b"
|
||||
# "rtw88_8723cs"
|
||||
# "rtw88_8723x"
|
||||
# "rtw88_core"
|
||||
# "rtw88_sdio"
|
||||
# "sch_fq_codel"
|
||||
# "sm4"
|
||||
# "snd_soc_bt_sco"
|
||||
# "snd_soc_ec25" #< NOT FOUND in megous-no-autoModules
|
||||
# "snd_soc_hdmi_codec"
|
||||
# "snd_soc_simple_amplifier"
|
||||
# "snd_soc_simple_card"
|
||||
# "snd_soc_simple_card_utils"
|
||||
# "stk3310" #< NOT FOUND in megous-no-autoModules
|
||||
# "st_magn"
|
||||
# "st_magn_i2c"
|
||||
# "st_magn_spi" #< NOT FOUND in pmos
|
||||
# "stp"
|
||||
# "st_sensors"
|
||||
# "st_sensors_i2c"
|
||||
# "st_sensors_spi" #< NOT FOUND in pmos
|
||||
# "sun4i_drm"
|
||||
# "sun4i_i2s"
|
||||
# "sun4i_lradc_keys" #< NOT FOUND in megous-no-autoModules
|
||||
# "sun4i_tcon"
|
||||
# "sun50i_codec_analog"
|
||||
# "sun6i_csi"
|
||||
# "sun6i_dma"
|
||||
# "sun6i_mipi_dsi"
|
||||
# "sun8i_a33_mbus" #< NOT FOUND in megous-no-autoModules
|
||||
# "sun8i_adda_pr_regmap"
|
||||
# "sun8i_ce" #< NOT FOUND in pmos
|
||||
# "sun8i_codec" #< NOT FOUND in megous-no-autoModules
|
||||
# "sun8i_di" #< NOT FOUND in megous-no-autoModules
|
||||
# "sun8i_drm_hdmi"
|
||||
# "sun8i_mixer"
|
||||
# "sun8i_rotate" #< NOT FOUND in megous-no-autoModules
|
||||
# "sun8i_tcon_top"
|
||||
# "sun9i_hdmi_audio" #< NOT FOUND in megous-no-autoModules
|
||||
# "sunxi_wdt" #< NOT FOUND in pmos
|
||||
# "tap"
|
||||
# "typec" #< NOT FOUND in pmos
|
||||
# "udp_tunnel"
|
||||
# "uio" #< NOT FOUND in pmos
|
||||
# "uio_pdrv_genirq"
|
||||
# "v4l2_async"
|
||||
# "v4l2_cci" #< NOT FOUND in pmos
|
||||
# "v4l2_flash_led_class" #< NOT FOUND in megous-no-autoModules
|
||||
# "v4l2_fwnode"
|
||||
# "v4l2_mem2mem"
|
||||
# "videobuf2_common"
|
||||
# "videobuf2_dma_contig"
|
||||
# "videobuf2_memops"
|
||||
# "videobuf2_v4l2"
|
||||
# "videodev"
|
||||
# "wireguard"
|
||||
# "xor"
|
||||
# "x_tables"
|
||||
# "xt_conntrack"
|
||||
# "xt_LOG"
|
||||
# "xt_nat"
|
||||
# "xt_pkttype"
|
||||
# "xt_set"
|
||||
# "xt_tcpudp"
|
||||
# "zram"
|
||||
];
|
||||
|
||||
# disable proximity sensor.
|
||||
# the filtering/calibration is bad that it causes the screen to go fully dark at times.
|
||||
# boot.blacklistedKernelModules = [ "stk3310" ];
|
||||
|
||||
boot.kernelParams = [
|
||||
# without this some GUI apps fail: `DRM_IOCTL_MODE_CREATE_DUMB failed: Cannot allocate memory`
|
||||
# this is because they can't allocate enough video ram.
|
||||
# see related nixpkgs issue: <https://github.com/NixOS/nixpkgs/issues/260222>
|
||||
# TODO(2023/12/03): remove once mesa 23.3.1 lands: <https://github.com/NixOS/nixpkgs/pull/265740>
|
||||
#
|
||||
# the default CMA seems to be 32M.
|
||||
# i was running fine with 256MB from 2022/07-ish through 2022/12-ish, but then the phone quit reliably coming back from sleep (phosh): maybe a memory leak?
|
||||
# bumped to 512M on 2023/01
|
||||
# bumped to 1536M on 2024/05
|
||||
# `cat /proc/meminfo` to see CmaTotal/CmaFree if interested in tuning this.
|
||||
# kernel param mentioned here: <https://cateee.net/lkddb/web-lkddb/CMA_SIZE_PERCENTAGE.html>
|
||||
# i think cma mem isn't exclusive -- it can be used as ordinary `malloc`, still. i heard someone suggest the OS default should just be 50% memory to CMA.
|
||||
"cma=1536M"
|
||||
# 2023/10/20: potential fix for the lima (GPU) timeout bugs:
|
||||
# - <https://gitlab.com/postmarketOS/pmaports/-/issues/805#note_890467824>
|
||||
"lima.sched_timeout_ms=2000"
|
||||
];
|
||||
|
||||
# defined: https://www.freedesktop.org/software/systemd/man/machine-info.html
|
||||
# XXX colin: diabled until/unless it's actually needed.
|
||||
# environment.etc."machine-info".text = ''
|
||||
# CHASSIS="handset"
|
||||
# '';
|
||||
|
||||
# hardware.firmware makes the referenced files visible to the kernel, for whenever a driver explicitly asks for them.
|
||||
# these files are visible from userspace by following `/sys/module/firmware_class/parameters/path`
|
||||
#
|
||||
# mobile-nixos' /lib/firmware includes:
|
||||
# rtl_bt (bluetooth)
|
||||
# anx7688-fw.bin (USB-C chip: power negotiation, HDMI/dock)
|
||||
# ov5640_af.bin (camera module)
|
||||
# hardware.firmware = [ config.mobile.device.firmware ];
|
||||
# hardware.firmware = [ pkgs.rtl8723cs-firmware ];
|
||||
hardware.firmware = [
|
||||
(pkgs.linux-firmware-megous.override {
|
||||
# rtl_bt = false probably means no bluetooth connectivity.
|
||||
# N.B.: DON'T RE-ENABLE without first confirming that wake-on-lan works during suspend (rtcwake).
|
||||
# it seems the rtl_bt stuff ("bluetooth coexist") might make wake-on-LAN radically more flaky.
|
||||
rtl_bt = false;
|
||||
})
|
||||
];
|
||||
|
||||
# enable rotation sensor
|
||||
# hardware.sensor.iio.enable = true;
|
||||
|
||||
## TOW-BOOT: <https://tow-boot.org>
|
||||
# docs (pinephone specific): <https://github.com/Tow-Boot/Tow-Boot/tree/development/boards/pine64-pinephoneA64>
|
||||
# LED and button behavior is defined here: <https://github.com/Tow-Boot/Tow-Boot/blob/development/modules/tow-boot/phone-ux.nix>
|
||||
# - hold VOLDOWN: enter recovery mode
|
||||
# - LED will turn aqua instead of yellow
|
||||
# - recovery mode would ordinarily allow a selection of entries, but for pinephone i guess it doesn't do anything?
|
||||
# - hold VOLUP: force it to load the OS from eMMC?
|
||||
# - LED will turn blue instead of yellow
|
||||
# boot LEDs:
|
||||
# - yellow = entered tow-boot
|
||||
# - 10 red flashes => poweroff means tow-boot couldn't boot into the next stage (i.e. distroboot)
|
||||
# - distroboot: <https://source.denx.de/u-boot/u-boot/-/blob/v2022.04/doc/develop/distro.rst>)
|
||||
# we need space in the GPT header to place tow-boot.
|
||||
# only actually need 1 MB, but better to over-allocate than under-allocate
|
||||
sane.image.extraGPTPadding = 16 * 1024 * 1024;
|
||||
sane.image.firstPartGap = 0;
|
||||
sane.image.installBootloader = ''
|
||||
dd if=${pkgs.tow-boot-pinephone}/Tow-Boot.noenv.bin of=$out bs=1024 seek=8 conv=notrunc
|
||||
'';
|
||||
|
||||
sane.programs.swaynotificationcenter.config = {
|
||||
backlight = "backlight"; # /sys/class/backlight/*backlight*/brightness
|
||||
};
|
||||
|
||||
services.udev.extraRules = let
|
||||
chmod = "${pkgs.coreutils}/bin/chmod";
|
||||
chown = "${pkgs.coreutils}/bin/chown";
|
||||
in ''
|
||||
# make Pinephone flashlight writable by user.
|
||||
# taken from postmarketOS: <repo:postmarketOS/pmaports:device/main/device-pine64-pinephone/60-flashlight.rules>
|
||||
SUBSYSTEM=="leds", DEVPATH=="*/*:flash", RUN+="${chmod} g+w /sys%p/brightness /sys%p/flash_strobe", RUN+="${chown} :video /sys%p/brightness /sys%p/flash_strobe"
|
||||
|
||||
# make Pinephone front LEDs writable by user.
|
||||
SUBSYSTEM=="leds", DEVPATH=="*/*:indicator", RUN+="${chmod} g+w /sys%p/brightness", RUN+="${chown} :video /sys%p/brightness"
|
||||
'';
|
||||
|
||||
systemd.services.unl0kr.preStart = let
|
||||
dmesg = "${pkgs.util-linux}/bin/dmesg";
|
||||
grep = "${pkgs.gnugrep}/bin/grep";
|
||||
modprobe = "${pkgs.kmod}/bin/modprobe";
|
||||
in ''
|
||||
# common boot failure:
|
||||
# blank screen (no backlight even), with the following log:
|
||||
# ```syslog
|
||||
# sun8i-dw-hdmi 1ee0000.hdmi: Couldn't get the HDMI PHY
|
||||
# ...
|
||||
# sun4i-drm display-engine: Couldn't bind all pipelines components
|
||||
# ...
|
||||
# sun8i-dw-hdmi: probe of 1ee0000.hdmi failed with error -17
|
||||
# ```
|
||||
#
|
||||
# in particular, that `probe ... failed` occurs *only* on failed boots
|
||||
# (the other messages might sometimes occur even on successful runs?)
|
||||
#
|
||||
# reloading the sun8i hdmi driver usually gets the screen on, showing boot text.
|
||||
# then restarting display-manager.service gets us to the login.
|
||||
#
|
||||
# NB: the above log is default level. though less specific, there's a `err` level message that also signals this:
|
||||
# sun4i-drm display-engine: failed to bind 1ee0000.hdmi (ops sun8i_dw_hdmi_ops [sun8i_drm_hdmi]): -17
|
||||
# NB: this is the most common, but not the only, failure mode for `display-manager`.
|
||||
# another error seems characterized by these dmesg logs, in which reprobing sun8i_drm_hdmi does not fix:
|
||||
# ```syslog
|
||||
# sun6i-mipi-dsi 1ca0000.dsi: Couldn't get the MIPI D-PHY
|
||||
# sun4i-drm display-engine: Couldn't bind all pipelines components
|
||||
# sun6i-mipi-dsi 1ca0000.dsi: Couldn't register our component
|
||||
# ```
|
||||
|
||||
if (${dmesg} --kernel --level err --color=never --notime | ${grep} -q 'sun4i-drm display-engine: failed to bind 1ee0000.hdmi')
|
||||
then
|
||||
echo "reprobing sun8i_drm_hdmi"
|
||||
# if a command here fails it errors the whole service, so prefer to log instead
|
||||
${modprobe} -r sun8i_drm_hdmi || echo "failed to unload sun8i_drm_hdmi"
|
||||
${modprobe} sun8i_drm_hdmi || echo "failed to load sub8i_drm_hdmi"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
250
hosts/modules/hal/samsung/default.nix
Normal file
250
hosts/modules/hal/samsung/default.nix
Normal file
@@ -0,0 +1,250 @@
|
||||
# device support for samsung XE303C12 "google-snow" model, specifically.
|
||||
# see: <https://wiki.postmarketos.org/wiki/Samsung_Chromebook_(google-snow)>
|
||||
# - build logs: <https://images.postmarketos.org/bpo/edge/google-snow/console/>
|
||||
# see: <https://github.com/thefloweringash/kevin-nix>
|
||||
# - related "depthcharge" chromebook, built with nix
|
||||
# see: <https://mobile.nixos.org/devices/lenovo-wormdingler.html>
|
||||
# - above module, integrated into an image builder
|
||||
# - implementation in modules/system-types/depthcharge
|
||||
# see: <https://web.archive.org/web/20191103000916/http://www.chromium.org/chromium-os/firmware-porting-guide/using-nv-u-boot-on-the-samsung-arm-chromebook>
|
||||
# - referenced from u-boot `doc/` directory
|
||||
# - <https://web.archive.org/web/20220813062811/https://www.chromium.org/chromium-os/how-tos-and-troubleshooting/using-an-upstream-kernel-on-snow/>
|
||||
# - <https://web.archive.org/web/20240119111314/https://www.chromium.org/chromium-os/developer-information-for-chrome-os-devices/custom-firmware/>
|
||||
# - google exynos5_defconfig: <https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/%2B/HEAD/eclass/cros-kernel>
|
||||
# see: <repo:postmarketOS/pmaports:device/community/device-google-snow>
|
||||
# - <https://gitlab.com/postmarketOS/boot-deploy/-/blob/5f08ebb05a520d0e6bccfcda324f12e4aac1623f/boot-deploy-functions.sh#L872>
|
||||
# - deviceinfo:
|
||||
# - deviceinfo_flash_method="none"
|
||||
# - deviceinfo_cgpt_kpart="/boot/vmlinuz.kpart"
|
||||
# - deviceinfo_cgpt_kpart_start="8192"
|
||||
# - deviceinfo_cgpt_kpart_size="16384"
|
||||
# - deviceinfo_kernel_cmdline="console=null"
|
||||
# - deviceinfo_depthcharge_board="snow"
|
||||
# - deviceinfo_generate_depthcharge_image="true"
|
||||
# - deviceinfo_generate_extlinux_config="true"
|
||||
# - modules-initfs:
|
||||
# - drm-dp-aux-bus
|
||||
# - panel-edp
|
||||
# - drm-kms-helper
|
||||
# - cros-ec-keyb
|
||||
# - sbs-battery
|
||||
# - tps65090-charger
|
||||
# - uas
|
||||
# - sd-mod
|
||||
# - pmOS also uses a custom alsa UCM config
|
||||
# - pmOS kernel package: linux-postmarketos-exynos5
|
||||
# - pmOS firmware packages (for WiFi/Bluetooth): linux-firmware-mrvl linux-firmware-s5p-mfc
|
||||
#
|
||||
# pmOS image has disk layout:
|
||||
# /dev/sdb1 8192 24575 16384 8M ChromeOS kernel
|
||||
# /dev/sdb2 24576 548863 524288 256M EFI System
|
||||
# /dev/sdb3 548864 31336414 30787551 14.7G Microsoft basic data
|
||||
# - built using `depthcharge-tools`: <https://github.com/alpernebbi/depthcharge-tools>
|
||||
# - expected chromeos disk layout documented: <https://www.chromium.org/chromium-os/developer-library/reference/device/disk-format/>
|
||||
#
|
||||
# typical boot process:
|
||||
# - BIOS searches for a partition `ChromeOS Kernel Type GUID (fe3a2a5d-4f32-41a7-b725-accc3285a309)`
|
||||
# - first 64K are reserved for sigantures (when verified boot is active)
|
||||
# - then kernel, some datastructures (i.e. config.txt, the command line passed to the kernel), bootloader stub
|
||||
# - BIOS loads kernel blob into RAM, then invokes the bootstub
|
||||
# - bootloader stub is an EFI application. it setups up tables and jumps into the kernel.
|
||||
# - so potentially i could put any EFI application here, and load the kernel myself from somewhere else?
|
||||
# - partitions are all 2MiB-aligned
|
||||
# according to depthcharge-tools, max image size is 8 MiB, though i don't know how strict that is.
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.hal.samsung;
|
||||
# sus commits:
|
||||
# - ad3e33fe071dffea07279f96dab4f3773c430fe2 (drm/panel: Move AUX B116XW03 out of panel-edp back to panel-simple)
|
||||
# says i should switch to `edp-panel`; chrome is lying about the panel.
|
||||
# - discussion: <https://patchwork.freedesktop.org/patch/559389/>
|
||||
# - was tested for exynos5-peach -- which worked with the patch and uses panel_simple
|
||||
# - snow was *not* tested, but previously used panel_edp
|
||||
linuxSourceHashes = {
|
||||
"6.2.16" = "sha256-dC5lp45tU4JgHS8VWezLM/z8C8UMxaIdj5I2DleMv8c="; #< boots
|
||||
"6.3.13" = "sha256-bGNcuEYBHaY34OeGkqb58dXV+JF2XY3bpBtLhg634xA="; #< boots
|
||||
"6.4.16" = "sha256-hDhelVL20AMzQeT7IDVDI35uoGEyroVPjiszO2JZzO8="; #< boots
|
||||
"6.5.13" = "sha256-lCTwq+2RyZTIX1YQa/riHf1KCnS8dTrLlljjKAXudz4="; #< boots
|
||||
"6.6.0-rc1" = "sha256-DRai7HhWVtRB0GiRCvCv2JM2TFKRsZ60ohD6GW0b8As="; #< boots. upstream/torvalds' tag is `v6.6-rc1`
|
||||
"6.6.0-rc3" = "sha256-/YcuQ5UsSObqOZ0YIbcNex5HJAL8eneDDzIiTEuMDsQ=";
|
||||
"6.6.0-rc4" = "sha256-Kbv+jU2IoC4soT3ma1ZV8Un4rTQakNjut5nlA1907GQ="; #< boots. upstream/torvalds' tag is `v6.6-rc4`
|
||||
"6.6.0-rc5" = "sha256-ia0F/W3BR+gD8qE5LEwUcJCqwBs3c5kj80DbeDzFFqY=";
|
||||
"6.6.0-rc6" = "sha256-HIrn3fkoCqVSSJ0gxY6NO8I3M8P7BD5XzQpjrhdw//s="; #< boots. upstream/torvalds' tag is `v6.6-rc6`
|
||||
"6.6.0-rc6-bi-5188" = "sha256-TmRrPy2IhnvTVlq5bNhzsvNPgRg0qk1u2Mh3q/lBask="; #< boots
|
||||
"6.6.0-rc6-bi-5264" = "sha256-BXt5O9hUC9lYITBO56Rzb9XJHThjt6DuiXizUi2G6/0="; # *does not boot*. this is commit ad3e33fe071dffea07279f96dab4f3773c430fe2; actually 6.6.0-rc1, because of merge order
|
||||
"6.6.0-rc7" = "sha256-u+seQp82USt63zgMlvDRIpDmmWD2Pha5d41CorwY7f8="; #< *does not boot*. upstream/torvalds' tag is `v6.6-rc7`
|
||||
"6.6.0" = "sha256-iUTHPMbELhtRogbrKr3n2FBwj8mbGYGacy2UgjPZZNg="; #< *does not boot*. upstream/torvalds' tag is `v6.6`
|
||||
"6.7.12" = "sha256-6Fm7lC2bwk+wYYGeasr+6tcSw+n3VE4d9JWbc9jN6fA="; #< *does not boot*
|
||||
"6.10.0-rc3" = "sha256-k9Mpff96xgfTyjRMn0wOQBOm7NKZ7IDtJBRYwrnccoY="; #< *does not boot*. upstream/torvalds' tag is `v6.10-rc3`
|
||||
};
|
||||
in
|
||||
{
|
||||
options = {
|
||||
sane.hal.samsung.enable = lib.mkEnableOption "samsung-specific hardware support";
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
boot.initrd.compressor = "gzip";
|
||||
# boot.initrd.compressorArgs = [ "--ultra" "-22" ];
|
||||
|
||||
hardware.firmware = [
|
||||
(pkgs.linux-firmware.overrideAttrs (_: {
|
||||
# mwifiex_sdio seems to require uncompressed firmware (even with a kernel configured for CONFIG_MODULE_COMPRESS_ZSTD=y)
|
||||
passthru.compressFirmware = false;
|
||||
}))
|
||||
];
|
||||
|
||||
boot.initrd.availableKernelModules = [
|
||||
# boot.initrd.kernelModules = [
|
||||
# from postmarketOS
|
||||
"drm-dp-aux-bus"
|
||||
"panel-edp"
|
||||
"drm-kms-helper"
|
||||
"cros-ec-keyb"
|
||||
"sbs-battery"
|
||||
"tps65090-charger"
|
||||
"uas"
|
||||
"sd-mod"
|
||||
];
|
||||
# N.B: mobile-nixos says these modules break udev, if builtin or run before udev:
|
||||
# "sbs-battery"
|
||||
# "sbs-charger"
|
||||
# "sbs-manager"
|
||||
|
||||
# boot.kernelPackages = with pkgs; linuxPackagesFor (linux_6_1.override {
|
||||
# preferBuiltin = false;
|
||||
# extraConfig = "";
|
||||
# structuredExtraConfig = with lib.kernel; {
|
||||
# SUN8I_DE2_CCU = lib.mkForce no; #< nixpkgs' option parser gets confused on this one, somehow
|
||||
# NET_VENDOR_MICREL = no; #< to overcome broken KS8851_MLL (broken by nixpkgs' `extraConfig`)
|
||||
# # KS8851_MLL = lib.mkForce module; #< nixpkgs' option parser gets confused on this one, somehow
|
||||
# #v XXX: required for e.g. SECURITY_LANDLOCK (specified by upstream nixpkgs) to take effect if `autoModules = false`
|
||||
# #v seems that upstream linux (the defconfigs?), it defaults to Yes for:
|
||||
# # - arch/x86/configs/x86_64_defconfig
|
||||
# # - arch/arm64/configs/defconfig
|
||||
# # but that it's left unset for e.g. arch/arm64/configs/pinephone_defconfig
|
||||
# # SECURITY = yes;
|
||||
# };
|
||||
# });
|
||||
# boot.kernelPackages = with pkgs; linuxPackagesFor linux_6_1;
|
||||
# boot.kernelPackages = with pkgs; linuxPackagesFor linux-exynos5-mainline;
|
||||
# boot.kernelPackages = with pkgs; linuxPackagesFor (linux-postmarketos-exynos5.override {
|
||||
# # linux = let version = "6.6.0-rc1"; rev = "6.6.0-rc6-bi-5264"; in {
|
||||
# # # src = pkgs.fetchzip {
|
||||
# # # url = "https://git.kernel.org/stable/t/linux-6.2.16.tar.gz";
|
||||
# # # };
|
||||
# # src = pkgs.fetchFromGitea {
|
||||
# # domain = "git.uninsane.org";
|
||||
# # owner = "colin";
|
||||
# # repo = "linux";
|
||||
# # rev = "v${rev}";
|
||||
# # hash = linuxSourceHashes."${rev}";
|
||||
# # };
|
||||
# # inherit version;
|
||||
# # modDirVersion = version;
|
||||
# # extraMakeFlags = [];
|
||||
# # };
|
||||
# # linux = linux_6_6;
|
||||
# # linux = linux_6_8;
|
||||
# # linux = linux_6_9;
|
||||
# linux = linux_latest;
|
||||
# # optimizeForSize = true;
|
||||
# # useEdpPanel = true;
|
||||
# revertPanelSimplePatch = true;
|
||||
# });
|
||||
# boot.kernelPackages = pkgs.linuxPackagesFor pkgs.linux-postmarketos-exynos5;
|
||||
boot.kernelPackages = pkgs.linuxPackagesFor (pkgs.linux-exynos5-mainline.override {
|
||||
kernelPatches = [
|
||||
pkgs.linux-postmarketos-exynos5.sanePatches.revertPanelSimplePatch
|
||||
];
|
||||
structuredExtraConfig = with lib.kernel; {
|
||||
SECURITY = yes;
|
||||
SECURITY_LANDLOCK = yes;
|
||||
LSM = freeform "landlock,lockdown,yama,loadpin,safesetid,selinux,smack,tomoyo,apparmor,bpf";
|
||||
};
|
||||
});
|
||||
|
||||
system.build.u-boot = pkgs.buildUBoot {
|
||||
defconfig = "snow_defconfig";
|
||||
extraMeta.platforms = [ "armv7l-linux" ];
|
||||
filesToInstall = [
|
||||
"u-boot" #< ELF file
|
||||
"u-boot.bin" #< raw binary, load it into RAM and jump toit
|
||||
"u-boot.cfg" #< copy of Kconfig which this u-boot was compiled with
|
||||
"u-boot.dtb"
|
||||
"u-boot.map"
|
||||
"u-boot-nodtb.bin"
|
||||
"u-boot.sym"
|
||||
];
|
||||
# CONFIG_BOOTCOMMAND: autoboot from usb, and fix the ordering so that it happens before the internal memory (mmc0)
|
||||
extraConfig = ''
|
||||
CONFIG_BOOTCOMMAND="env set bootcmd_usb0 \"devnum=0; run usb_boot\"; env set boot_targets \"usb0 mmc2 mmc1 mmc0\"; run distro_bootcmd"
|
||||
'';
|
||||
};
|
||||
|
||||
system.build.platformPartition = pkgs.runCommandLocal "kernel-partition" {
|
||||
nativeBuildInputs = with pkgs; [
|
||||
vboot_reference
|
||||
dtc
|
||||
ubootTools
|
||||
];
|
||||
} ''
|
||||
# according to depthcharge-tools, bootloader.bin is legacy, was used by the earliest
|
||||
# chromebooks (H2C) *only*.
|
||||
dd if=/dev/zero of=dummy_bootloader.bin bs=512 count=1
|
||||
echo auto > dummy_config.txt
|
||||
|
||||
# from uboot snow_defconfig, also == CONFIG_SYS_LOAD_ADDR
|
||||
CONFIG_TEXT_BASE=0x43e00000
|
||||
|
||||
cp ${config.system.build.u-boot}/u-boot.bin .
|
||||
ubootFlags=(
|
||||
-A arm # architecture
|
||||
-O linux # operating system
|
||||
-T kernel # image type
|
||||
-C none # compression
|
||||
-a $CONFIG_TEXT_BASE # load address (CONFIG_TEXT_BASE)
|
||||
-e $CONFIG_TEXT_BASE # entry point (CONFIG_SYS_LOAD_ADDR), i.e. where u-boot `bootm` should jump to to execute the kernel
|
||||
-n nixos-uboot # image name
|
||||
-d u-boot.bin # image data
|
||||
u-boot.fit # output
|
||||
)
|
||||
mkimage "''${ubootFlags[@]}"
|
||||
|
||||
futility \
|
||||
--debug \
|
||||
vbutil_kernel \
|
||||
--version 1 \
|
||||
--bootloader ./dummy_bootloader.bin \
|
||||
--vmlinuz u-boot.fit \
|
||||
--arch arm \
|
||||
--keyblock ${pkgs.buildPackages.vboot_reference}/share/vboot/devkeys/kernel.keyblock \
|
||||
--signprivate ${pkgs.buildPackages.vboot_reference}/share/vboot/devkeys/kernel_data_key.vbprivk \
|
||||
--config ./dummy_config.txt \
|
||||
--pack $out
|
||||
'';
|
||||
|
||||
# the platform partition presently only holds u-boot,
|
||||
# and it seems possibly a limitation of depthcharge that it can't launch anything > 8 MiB (?)
|
||||
# still, give a little extra room so i'm free to rearrange stuff if i find a way how.
|
||||
sane.image.platformPartSize = 256 * 1024 * 1024;
|
||||
|
||||
# depthcharge firmware is designed for an A/B partition style,
|
||||
# where partition A holds a kernel and partion B holds a different kernel.
|
||||
# an update is to flash the currently inactive partition and then mark that one as active,
|
||||
# either switching the default boot from partition A to partition B, or from B to A.
|
||||
# anyway, this relies on the partitions having some extra metadata, which we add here.
|
||||
# i believe this metadata is stored in a depthcharge-specific format, not anything
|
||||
# which can be generalized.
|
||||
sane.image.installBootloader = ''
|
||||
${lib.getExe' pkgs.buildPackages.vboot_reference "cgpt"} add ${lib.concatStringsSep " " [
|
||||
"-i 1" # work on the first partition (instead of adding)
|
||||
"-S 1" # mark as successful (so it'll be booted from)
|
||||
"-T 5" # tries remaining
|
||||
"-P 10" # priority
|
||||
"$out"
|
||||
]}
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
@@ -1,7 +1,14 @@
|
||||
{ lib, pkgs, ... }:
|
||||
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.hal.x86_64;
|
||||
in
|
||||
{
|
||||
config = lib.mkIf (pkgs.system == "x86_64-linux") {
|
||||
options = {
|
||||
sane.hal.x86_64.enable = (lib.mkEnableOption "x86_64-specific hardware support") // {
|
||||
default = pkgs.system == "x86_64-linux";
|
||||
};
|
||||
};
|
||||
config = lib.mkIf cfg.enable {
|
||||
boot.initrd.availableKernelModules = [
|
||||
"xhci_pci" "ahci" "sd_mod" "sdhci_pci" # nixos-generate-config defaults
|
||||
"usb_storage" # rpi needed this to boot from usb storage, i think.
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p gnused
|
||||
#!nix-shell -i bash -p bash -p gnused
|
||||
# usage: install-bluetooth <source_dir> <destdir>
|
||||
# source_dir contains plain-text files of any filename.
|
||||
# for each file, this extracts the MAC and creates a symlink in destdir which
|
||||
|
@@ -13,6 +13,61 @@
|
||||
"consoleMediaUtils" # overbroad, but handy on very rare occasion
|
||||
"handheldGuiApps"
|
||||
];
|
||||
sane.programs.sway.suggestedPrograms = [
|
||||
"sane-input-handler"
|
||||
];
|
||||
|
||||
sane.programs.alacritty.config.fontSize = 9;
|
||||
|
||||
sane.programs.firefox.config = {
|
||||
# compromise impermanence for the sake of usability
|
||||
persistCache = "private";
|
||||
persistData = "private";
|
||||
|
||||
# i don't do crypto stuff on moby
|
||||
addons.ether-metamask.enable = false;
|
||||
# sidebery UX doesn't make sense on small screen
|
||||
addons.sidebery.enable = false;
|
||||
};
|
||||
sane.programs.firefox.mime.priority = 300; # prefer other browsers when possible
|
||||
# HACK/TODO: make `programs.P.env.VAR` behave according to `mime.priority`
|
||||
sane.programs.firefox.env = lib.mkForce {};
|
||||
sane.programs.epiphany.env.BROWSER = "epiphany";
|
||||
|
||||
sane.programs.sway.config = {
|
||||
font = "pango:monospace 10";
|
||||
locker = "schlock";
|
||||
mod = "Mod1"; # prefer Alt
|
||||
workspace_layout = "tabbed";
|
||||
};
|
||||
|
||||
sane.programs.swayidle.config = {
|
||||
actions.screenoff.delay = 300;
|
||||
actions.screenoff.enable = true;
|
||||
};
|
||||
|
||||
sane.programs.waybar.config = {
|
||||
fontSize = 14;
|
||||
height = 26;
|
||||
persistWorkspaces = [ "1" "2" "3" "4" "5" ];
|
||||
modules.media = false;
|
||||
modules.network = false;
|
||||
modules.perf = false;
|
||||
modules.windowTitle = false;
|
||||
# TODO: show modem state
|
||||
};
|
||||
sane.programs.nwg-panel.config = {
|
||||
fontSize = 14;
|
||||
height = 26;
|
||||
windowIcon = false;
|
||||
windowTitle = false;
|
||||
mediaPrevNext = false;
|
||||
mediaTitle = false;
|
||||
workspaceNumbers = [ "1" "2" "3" "4" "5" ];
|
||||
workspaceHideEmpty = false;
|
||||
};
|
||||
|
||||
sane.programs.zsh.config.showDeadlines = false; # unlikely to act on them when in shell
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -1,30 +0,0 @@
|
||||
# docs: <nixpkgs:nixos/modules/services/networking/yggdrasil.md>
|
||||
# - or message CW/0x00
|
||||
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf mkOption types;
|
||||
cfg = config.sane.yggdrasil;
|
||||
in
|
||||
{
|
||||
options.sane.yggdrasil = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
};
|
||||
config = mkIf cfg.enable {
|
||||
services.yggdrasil = {
|
||||
enable = true;
|
||||
persistentKeys = true;
|
||||
settings = {
|
||||
IFName = "ygg0";
|
||||
Peers = [
|
||||
"tls://longseason.1200bps.xyz:13122"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
5
integrations/nixpkgs/nixpkgs-overlays.nix
Normal file
5
integrations/nixpkgs/nixpkgs-overlays.nix
Normal file
@@ -0,0 +1,5 @@
|
||||
# this file exists so i can use my custom packages inside `nix-shell`.
|
||||
# it works by using stock upstream `nixpkgs`
|
||||
# and putting NIX_PATH=nixpkgs-overlays=/path/to/here on the nixbld environment.
|
||||
#
|
||||
[(import ../../overlays/all.nix)]
|
@@ -4,6 +4,6 @@
|
||||
"site_name": " bunnie's blog",
|
||||
"site_url": "https://www.bunniestudios.com",
|
||||
"title": "bunnie's blog",
|
||||
"url": "https://www.bunniestudios.com/blog/?feed=rss2",
|
||||
"velocity": 0.108
|
||||
"url": "https://www.bunniestudios.com/blog/feed/",
|
||||
"velocity": 0.12
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"description": "Radiolab",
|
||||
"description": "Radiolab is on a curiosity bender. We ask deep questions and use investigative journalism to get the answers. A given episode might whirl you through science, legal history, and into the home of someone halfway across the world. The show is known for innovative sound design, smashing information into music. It is hosted by Lulu Miller and Latif Nasser.",
|
||||
"is_podcast": true,
|
||||
"site_name": "",
|
||||
"site_url": "",
|
||||
"title": "Radiolab",
|
||||
"url": "https://feeds.feedburner.com/radiolab",
|
||||
"velocity": 0.136
|
||||
"url": "https://feeds.simplecast.com/EmVW7VGp",
|
||||
"velocity": 0.138
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"description": "*** Named a best podcast of 2021 by Time, Vulture, Esquire and The Atlantic. ***\nEach Tuesday and Friday, Ezra Klein invites you into a conversation on something that matters. How do we address climate change if the political system fails to act? Has the logic of markets infiltrated too many aspects of our lives? What is the future of the Republican Party? What do psychedelics teach us about consciousness? What does sci-fi understand about our present that we miss? Can our food system be just to humans and animals alike?\n\nListen to this podcast in New York Times Audio, our new iOS app for news subscribers. Download now at nytimes.com/audioapp",
|
||||
"description": "Each Tuesday and Friday, Ezra Klein invites you into a conversation on something that matters. How do we address climate change if the political system fails to act? Has the logic of markets infiltrated too many aspects of our lives? What is the future of the Republican Party? What do psychedelics teach us about consciousness? What does sci-fi understand about our present that we miss? Can our food system be just to humans and animals alike?\n\nListen to this podcast in New York Times Audio, our iOS app for news subscribers. Download now at nytimes.com/audioapp",
|
||||
"is_podcast": true,
|
||||
"site_name": "",
|
||||
"site_url": "",
|
||||
"title": "The Ezra Klein Show",
|
||||
"url": "https://feeds.simplecast.com/82FI35Px",
|
||||
"velocity": 0.264
|
||||
"velocity": 0.257
|
||||
}
|
@@ -2,8 +2,8 @@
|
||||
"description": "Long conversations with clever Nixers.",
|
||||
"is_podcast": true,
|
||||
"site_name": "",
|
||||
"site_url": "",
|
||||
"site_url": "https://feeds.transistor.fm",
|
||||
"title": "Full Time Nix",
|
||||
"url": "https://feeds.transistor.fm/full-time-nix",
|
||||
"velocity": 0
|
||||
"velocity": 0.048
|
||||
}
|
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"description": "<p>Playful explorations of the rich past and exciting future that we're all building with our silly little computers. Hosted by Jimmy Miller and Ivan Reese.</p>",
|
||||
"is_podcast": true,
|
||||
"site_name": "",
|
||||
"site_url": "",
|
||||
"site_name": "Omny Studio",
|
||||
"site_url": "https://www.omnycontent.com",
|
||||
"title": "Future of Coding",
|
||||
"url": "https://www.omnycontent.com/d/playlist/c4157e60-c7f8-470d-b13f-a7b30040df73/564f493f-af32-4c48-862f-a7b300e4df49/ac317852-8807-44b8-8eff-a7b300e4df52/podcast.rss",
|
||||
"velocity": 0.028
|
||||
|
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"description": "<p>The most unruly and least considered, most shameful among various Idiomdrottning components and libraries can be found here.</p>\n <p>To contact me, <a href=\"mailto:sandra.snan@idiomdrottning.org\">send mail to sandra.snan@idiomdrottning.org</a></p>",
|
||||
"is_podcast": false,
|
||||
"site_name": "Idiomdrottning",
|
||||
"site_name": "I live like them already",
|
||||
"site_url": "https://idiomdrottning.org",
|
||||
"title": "Idiomdrottning",
|
||||
"url": "https://idiomdrottning.org/blog",
|
||||
"velocity": 0.402
|
||||
"velocity": 0.867
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"description": "Kill the Newsletter! Inbox:\n joh91bv7am2pnznv@kill-the-newsletter.com \u2192\n https://kill-the-newsletter.com/feeds/joh91bv7am2pnznv.xml",
|
||||
"description": null,
|
||||
"is_podcast": false,
|
||||
"site_name": "Kill the Newsletter!",
|
||||
"site_url": "https://kill-the-newsletter.com",
|
||||
"title": "Money Stuff",
|
||||
"url": "https://kill-the-newsletter.com/feeds/joh91bv7am2pnznv.xml",
|
||||
"velocity": 939.13
|
||||
"velocity": 0.667
|
||||
}
|
@@ -2,8 +2,8 @@
|
||||
"description": "The art, science, and history of processor design..",
|
||||
"is_podcast": true,
|
||||
"site_name": "",
|
||||
"site_url": "",
|
||||
"site_url": "https://feeds.transistor.fm",
|
||||
"title": "Microarch Club",
|
||||
"url": "https://feeds.transistor.fm/microarch-club",
|
||||
"velocity": 0.083
|
||||
"velocity": 0.08
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"description": "<p>As long as there’s been oppression, there’ve been people fighting it. This weekly podcast dives into history to drag up the wildest rebels, the most beautiful revolts, and all the people who long to be—and fight to be—free. It explores complex stories of resistance that offer lessons and inspiration for us today, focusing on the ensemble casts that make up each act of history. That is to say, this podcast focuses on Cool People Who Did Cool Stuff.</p>",
|
||||
"description": "<p>As long as there\u2019s been oppression, there\u2019ve been people fighting it. This weekly podcast dives into history to drag up the wildest rebels, the most beautiful revolts, and all the people who long to be\u2014and fight to be\u2014free. It explores complex stories of resistance that offer lessons and inspiration for us today, focusing on the ensemble casts that make up each act of history. That is to say, this podcast focuses on Cool People Who Did Cool Stuff.</p>",
|
||||
"is_podcast": true,
|
||||
"site_name": "Omny Studio",
|
||||
"site_url": "https://www.omnycontent.com",
|
||||
"title": "Cool People Who Did Cool Stuff",
|
||||
"url": "https://www.omnycontent.com/d/playlist/e73c998e-6e60-432f-8610-ae210140c5b1/45bcda9a-4724-45c0-82ca-ae7f00e1dd18/f21245f2-a297-42f7-a016-ae7f00e390c4/podcast.rss",
|
||||
"velocity": 0.271
|
||||
"velocity": 0.299
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"description": "<p>The audio companion to Bloomberg Opinion\u2019s beloved Money Stuff column hosted by its author Matt Levine, \u201cwhose deadpan style mixes technical elucidation and wit\u201d (NY Times). Once a week, Matt and his friend, Bloomberg News reporter and TV host, Katie Greifeld talk about Wall Street, finance and\u2026other stuff. New episodes every Friday.</p>",
|
||||
"description": "<p>The audio companion to Bloomberg Opinion\u2019s beloved Money Stuff column hosted by its author Matt Levine, \u201cwhose deadpan style mixes technical elucidation and wit\u201d (NY Times). Once a week, Matt and his friend, Bloomberg News reporter and TV host Katie Greifeld, talk about Wall Street, finance and\u2026other stuff. New episodes every Friday.</p>",
|
||||
"is_podcast": true,
|
||||
"site_name": "",
|
||||
"site_url": "",
|
||||
"site_name": "Omny Studio",
|
||||
"site_url": "https://www.omnycontent.com",
|
||||
"title": "Money Stuff: The Podcast",
|
||||
"url": "https://www.omnycontent.com/d/playlist/e73c998e-6e60-432f-8610-ae210140c5b1/ee4336cb-155f-4488-90e0-b1400134e40e/77e6a3a7-290d-4a82-8164-b14001353ef2/podcast.rss",
|
||||
"velocity": 0.063
|
||||
"velocity": 0.125
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"description": "<p>Comedians Dave Anthony and Gareth Reynolds picks a subject from history and examine it.</p>",
|
||||
"is_podcast": true,
|
||||
"site_name": "",
|
||||
"site_url": "",
|
||||
"site_name": "Omny Studio",
|
||||
"site_url": "https://www.omnycontent.com",
|
||||
"title": "The Dollop with Dave Anthony and Gareth Reynolds",
|
||||
"url": "https://www.omnycontent.com/d/playlist/885ace83-027a-47ad-ad67-aca7002f1df8/22b063ac-654d-428f-bd69-ae2400349cde/65ff0206-b585-4e2a-9872-ae240034c9c9/podcast.rss",
|
||||
"velocity": 0.188
|
||||
"velocity": 0.192
|
||||
}
|
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"description": "Explore human evolution one story at a time. This award-winning show blends storytelling with science that will change your understanding of who we are.",
|
||||
"is_podcast": true,
|
||||
"site_name": "",
|
||||
"site_url": "",
|
||||
"site_name": "test220119a",
|
||||
"site_url": "https://feeds.libsyn.com",
|
||||
"title": "Origin Stories",
|
||||
"url": "https://feeds.libsyn.com/65014/rss",
|
||||
"velocity": 0.024
|
||||
|
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"description": "<p>Weekly roundup of everything new in the Linux and Open Source world! May contain gaming and privacy related topics.</p>\n<p>This is a longer counterpart to the Linux and Open Source news videos available on The Linux Experiment Youtube Channel.</p>",
|
||||
"description": "<p>Weekly roundup of everything new in the Linux and Open Source world! May contain gaming and privacy related topics.</p>\n<p>This is a longer counterpart to the Linux and Open Source news videos available on The Linux Experiment Youtube Channel.</p>\n<p>I\u2019m Nick, I\u2019ve been making Linux and Open Source related videos on YouTube since 2018, with a sizeable following of more than 300 000 subscribers. I\u2019ve been using Linux since 2006, starting with Ubuntu (like most people), and I have 12 years of experience in project management and UX, and that\u2019s the lens I use to view the progress of our Linux desktops and open source applications!</p>",
|
||||
"is_podcast": true,
|
||||
"site_name": "The Linux Experiment Podcasts",
|
||||
"site_url": "https://podcast.thelinuxexp.com",
|
||||
"title": "Linux + Open Source News, by TLE",
|
||||
"title": "Linux & Open Source News",
|
||||
"url": "https://podcast.thelinuxexp.com/@tlenewspodcast/feed.xml",
|
||||
"velocity": 0.145
|
||||
"velocity": 0.147
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"description": "A Comic",
|
||||
"is_podcast": false,
|
||||
"site_name": "Poorly Drawn Lines",
|
||||
"site_name": "Poorly Drawn Lines | A Comic",
|
||||
"site_url": "https://poorlydrawnlines.com",
|
||||
"title": "Poorly Drawn Lines",
|
||||
"url": "https://poorlydrawnlines.com/feed/",
|
||||
"velocity": 0.237
|
||||
"velocity": 0.3
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"description": "Announcing appearances, publications, and analysis of questions historical, philosophical, and political by author, philosopher, and historian Richard Carrier.",
|
||||
"is_podcast": false,
|
||||
"site_name": "Richard Carrier",
|
||||
"site_name": "Richard Carrier Blogs",
|
||||
"site_url": "https://www.richardcarrier.info",
|
||||
"title": "Richard Carrier",
|
||||
"title": "Richard Carrier Blogs",
|
||||
"url": "https://www.richardcarrier.info/feed",
|
||||
"velocity": 0.141
|
||||
"velocity": 0.131
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"description": "It\u2019s getting harder and harder to talk about politics, especially if you disagree. Well, screw that. Seattle Nice aims to be the most opinionated and smartest analysis of what\u2019s really happening in Seattle politics available in any medium. Each episode dives into contentious and sometimes ridiculous topics, exploring perspectives from across Seattle's political spectrum, from city council brawls to the ways the national political conversation filters through our unique political process. Even if you\u2019re not from Seattle, you need to listen to Seattle Nice. Because it\u2019s coming for you. Unlike the sun, politics rises in the West and sets in the East.",
|
||||
"description": "<p>It\u2019s getting harder and harder to talk about politics, especially if you disagree. Well, screw that. Seattle Nice aims to be the most opinionated and smartest analysis of what\u2019s really happening in Seattle politics available in any medium. Each episode dives into contentious and sometimes ridiculous topics, exploring perspectives from across Seattle's political spectrum, from city council brawls to the ways the national political conversation filters through our unique political process. Even if you\u2019re not from Seattle, you need to listen to Seattle Nice. Because it\u2019s coming for you. Unlike the sun, politics rises in the West and sets in the East. </p>",
|
||||
"is_podcast": true,
|
||||
"site_name": "",
|
||||
"site_url": "",
|
||||
"title": "Seattle Nice",
|
||||
"url": "https://feeds.buzzsprout.com/1897925.rss",
|
||||
"velocity": 0.099
|
||||
"velocity": 0.101
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"description": "On Target Technology News",
|
||||
"is_podcast": false,
|
||||
"site_name": "SemiAccurate - On Target Technology News",
|
||||
"site_name": "SemiAccurate",
|
||||
"site_url": "https://semiaccurate.com",
|
||||
"title": "SemiAccurate",
|
||||
"url": "https://www.semiaccurate.com/feed/",
|
||||
"velocity": 0.106
|
||||
"velocity": 0.098
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"description": "Latest Saturday Morning Breakfast Cereal comics and news",
|
||||
"is_podcast": false,
|
||||
"site_name": "Saturday Morning Breakfast Cereal - Got You",
|
||||
"site_name": "Saturday Morning Breakfast Cereal - Dave",
|
||||
"site_url": "https://www.smbc-comics.com",
|
||||
"title": "Saturday Morning Breakfast Cereal",
|
||||
"url": "https://www.smbc-comics.com/comic/rss",
|
||||
"velocity": 1.172
|
||||
"velocity": 0.999
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"description": "<p>Tales From the Bridge is a bi-weekly Science Fiction podcast. Join Tristan, Kevin, James, and Sam as they chat with your favourite science fiction authors and filmmakers. We also discuss the best in sci-fi, from books and graphic novels - to television and film. We cover cutting-edge concepts in our news segment, Science Fiction-Science Fact and throw in a bit of trivia for fun. <br /><br />Apple Podcasts; https://podcasts.apple.com/us/podcast/tales-from-the-bridge-all-things-sci-fi/id1570902818 Find out more on our website: https://talesfromthebridge.buzzsprout.com/</p>",
|
||||
"description": "<p>Tales From the Bridge is a podcast that discusses all things science fiction. Join Tristan, Kevin, James, Sam as they chat with your favourite science fiction authors and filmmakers. We talk about the best in sci-fi, from books and graphic novels - to television and film. We cover cutting-edge concepts in our news segment, Science Fiction-Science Fact, and often throw in a bit of trivia for fun. <br /><br />Subscribe, follow, like and leave a review. We'd love to hear from you! </p>",
|
||||
"is_podcast": true,
|
||||
"site_name": "",
|
||||
"site_url": "",
|
||||
"title": "Tales From The Bridge: All Things Sci-Fi",
|
||||
"title": "Tales From The Bridge",
|
||||
"url": "https://feeds.buzzsprout.com/1795352.rss",
|
||||
"velocity": 0.093
|
||||
"velocity": 0.091
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user