Compare commits
136 Commits
wip/less-d
...
staging/nu
Author | SHA1 | Date | |
---|---|---|---|
18ebfb9d9f | |||
a8584cf8dc | |||
57fcd33392 | |||
569a990488 | |||
915f792b74 | |||
897ba300b2 | |||
89f81da134 | |||
1b76f1d643 | |||
9f21fbceda | |||
2450bb6f06 | |||
7d581f93cc | |||
96d113ffac | |||
b247c920f6 | |||
dfa921035d | |||
0c59f4e59c | |||
3dda51db7d | |||
b5a6a7a57c | |||
f300cb1202 | |||
10a100c961 | |||
25d2234c69 | |||
fa5bc18721 | |||
7c1961eba8 | |||
b0c68308b7 | |||
6f7b7ddb84 | |||
1cc139c45c | |||
d06516a71b | |||
1c5a7b72ea | |||
afc916c9f8 | |||
7b141f6f58 | |||
94b7826099 | |||
fd82256bbc | |||
ec7f36913c | |||
6324d8004f | |||
4b8fddeb3f | |||
871975a597 | |||
1e6e41a9cb | |||
2f375b7778 | |||
df2e3a1b03 | |||
718a4b61d7 | |||
d617c0259f | |||
83e404f000 | |||
ba11bba909 | |||
af394b315e | |||
44195a7d87 | |||
44e356cf6b | |||
7aafc6719e | |||
f6579b865b | |||
8d5c917c79 | |||
4c74a95194 | |||
a6056aeb47 | |||
ac3e384b63 | |||
3338e93c87 | |||
97cb72db7c | |||
f7f6b80cd0 | |||
d60fe7a93c | |||
e2fa18b7c7 | |||
3226615885 | |||
dd99e66fb5 | |||
2e45145e72 | |||
9783646a0d | |||
c24f4d1659 | |||
f220771b58 | |||
cb9854c297 | |||
d422dcdd89 | |||
4e4e7e4991 | |||
9c09d03e5c | |||
1f0fbe29a8 | |||
131a828ed0 | |||
a4bcb44677 | |||
d385845dd5 | |||
66c42916c8 | |||
c6d4784dae | |||
b282e5beb2 | |||
20f4251c6e | |||
5d0630cad4 | |||
2dbf3b4732 | |||
8e8e63a33f | |||
6b7a8f9fec | |||
b85bdf26fd | |||
2fa76836b5 | |||
5c8cca6a52 | |||
1f2c9a9a5e | |||
337fb9e9d9 | |||
e7f02c057e | |||
8df87256a1 | |||
09a1d286d0 | |||
0662b06df6 | |||
b0a99da884 | |||
12fd7ebc41 | |||
f4a04ff6ba | |||
89e2a83067 | |||
ae78f2b6c2 | |||
198c40df66 | |||
a952f84ee4 | |||
c9e55a586b | |||
aa8c3affcd | |||
692f47d02d | |||
0ac17c32a3 | |||
2ff4df069e | |||
b11759a0a6 | |||
6af0d54e7b | |||
f87c115f7c | |||
099cd12bdd | |||
bf67def14a | |||
39e7e2230e | |||
4ff82f002b | |||
781a149542 | |||
b7f2f4f5c4 | |||
e3cb51951c | |||
94ac4ec0e9 | |||
348bd0f177 | |||
bae0e3df76 | |||
429951cfcc | |||
b23262b367 | |||
464e348545 | |||
62c1f4009b | |||
2373d28eb8 | |||
d76591349e | |||
4361bd45c7 | |||
be33684d5d | |||
d2ef8d113e | |||
54d29ca190 | |||
875482f395 | |||
dac245e032 | |||
e7edafcfec | |||
00af6104be | |||
40c9517dc6 | |||
c2915e29d4 | |||
b6edf768b9 | |||
27be182eb7 | |||
ddf1be7410 | |||
ad819e4cc0 | |||
6407f156b2 | |||
6d419b8279 | |||
bf3e0ad790 | |||
0c07e03ad6 |
100
README.md
Normal file
100
README.md
Normal file
@@ -0,0 +1,100 @@
|
||||
## What's Here
|
||||
|
||||
this is the top-level repo from which i configure/deploy all my NixOS machines:
|
||||
- desktop
|
||||
- laptop
|
||||
- server
|
||||
- mobile phone
|
||||
|
||||
i enjoy a monorepo approach. this repo references [nixpkgs][nixpkgs], a couple 3rd party
|
||||
nix modules like [sops][sops], the sources for [uninsane.org][uninsane-org], and that's
|
||||
about it. custom derivations and modules (some of which i try to upstream) live
|
||||
directly here; even the sources for those packages is often kept here too.
|
||||
|
||||
[nixpkgs]: https://github.com/NixOS/nixpkgs
|
||||
[sops]: https://github.com/Mic92/sops-nix
|
||||
[uninsane-org]: https://uninsane.org
|
||||
|
||||
## Layout
|
||||
- `hosts/`
|
||||
- the bulk of config which isn'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.
|
||||
- `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.
|
||||
- `overlays/`
|
||||
- exposed via the `overlays` output in `flake.nix`.
|
||||
- predominantly a list of `callPackage` directives.
|
||||
- `pkgs/`
|
||||
- derivations for things not yet packaged in nixpkgs.
|
||||
- derivations for things from nixpkgs which i need to `override` for some reason.
|
||||
- inline code for wholly custom packages (e.g. `pkgs/sane-scripts/` for CLI tools
|
||||
that are highly specific to my setup).
|
||||
- `scripts/`
|
||||
- scripts which are referenced by other things in this repo.
|
||||
- these aren't generally user-facing, but they're factored out so that they can
|
||||
be invoked directly when i need to debug.
|
||||
- `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
|
||||
- `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.
|
||||
|
||||
|
||||
## Key Points of Interest
|
||||
|
||||
i.e. you might find value in using these in your own config:
|
||||
|
||||
- `modules/fs/`
|
||||
- use this to statically define leafs and nodes anywhere in the filesystem,
|
||||
not just inside `/nix/store`.
|
||||
- e.g. specify that `/var/www` should be:
|
||||
- owned by a specific user/group
|
||||
- set to a specific mode
|
||||
- symlinked to some other path
|
||||
- populated with some statically-defined data
|
||||
- populated according to some script
|
||||
- created as a dependency of some service (e.g. `nginx`)
|
||||
- values defined here are applied neither at evaluation time _nor_ at activation time.
|
||||
- rather, they become systemd services.
|
||||
- systemd manages dependencies
|
||||
- e.g. link `/var/www -> /mnt/my-drive/www` only _after_ `/mnt/my-drive/www` appears)
|
||||
- this is akin to using [Home Manager's][home-manager] file API -- the part which lets you
|
||||
statically define `~/.config` files -- just with a different philosophy.
|
||||
- `modules/persist/`
|
||||
- my alternative to the Impermanence module.
|
||||
- this builds atop `modules/fs/` to achieve things stock impermanence can't:
|
||||
- persist things to encrypted storage which is unlocked at login time (pam_mount).
|
||||
- "persist" cache directories -- to free up RAM -- but auto-wipe them on mount
|
||||
and encrypt them to ephemeral keys so they're unreadable post shutdown/unmount.
|
||||
- `modules/programs.nix`
|
||||
- like nixpkgs' `programs` options, but allows both system-wide or per-user deployment.
|
||||
- allows `fs` and `persist` config values to be gated behind program deployment:
|
||||
- e.g. `/home/<user>/.mozilla/firefox` is persisted only for users who
|
||||
`sane.programs.firefox.enableFor.user."<user>" = true;`
|
||||
- `modules/users.nix`
|
||||
- convenience layer atop the above modules so that you can just write
|
||||
`fs.".config/git"` instead of `fs."/home/colin/.config/git"`
|
||||
|
||||
some things in here could easily find broader use. if you would find benefit in
|
||||
them being factored out of my config, message me and we could work to make that happen.
|
||||
|
||||
[home-manager]: https://github.com/nix-community/home-manager
|
||||
|
||||
## 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)
|
||||
|
||||
## Contact
|
||||
|
||||
if you want to contact me for questions, or collaborate to split something useful into a shared repo, etc,
|
||||
you can reach me via any method listed [here](https://uninsane.org/about).
|
32
flake.lock
generated
32
flake.lock
generated
@@ -18,11 +18,11 @@
|
||||
"mobile-nixos": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1679516998,
|
||||
"narHash": "sha256-w4baQlS84X8Lf0E5RN0nGkx03luDuV1X0+jWMAXm6fs=",
|
||||
"lastModified": 1680563603,
|
||||
"narHash": "sha256-gxSci3NTlzgkAOhaC93Q4lReX/Pjd7++imD85JOAlps=",
|
||||
"owner": "nixos",
|
||||
"repo": "mobile-nixos",
|
||||
"rev": "7a6e97e3af73c4cca87e12c83abcb4913dac7dbc",
|
||||
"rev": "4aa0afd84005b79be4d5361b56a60df9e9bd4ea3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -66,11 +66,11 @@
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1680390120,
|
||||
"narHash": "sha256-RyDJcG/7mfimadlo8vO0QjW22mvYH1+cCqMuigUntr8=",
|
||||
"lastModified": 1682173319,
|
||||
"narHash": "sha256-tPhOpJJ+wrWIusvGgIB2+x6ILfDkEgQMX0BTtM5vd/4=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "c1e2efaca8d8a3db6a36f652765d6c6ba7bb8fae",
|
||||
"rev": "ee7ec1c71adc47d2e3c2d5eb0d6b8fbbd42a8d1c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -82,11 +82,11 @@
|
||||
},
|
||||
"nixpkgs-unpatched": {
|
||||
"locked": {
|
||||
"lastModified": 1680415272,
|
||||
"narHash": "sha256-S2J9n+sSeAAdXWHrz/s9pyS5fhbQilfNqYrs6RCUyN8=",
|
||||
"lastModified": 1682404149,
|
||||
"narHash": "sha256-vilYNldFXiu56HGD0lPcWsiED7EmjGMViCLZoQsv7Jk=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "66f60deb8aa348ca81d60d0639ae420c667ff92a",
|
||||
"rev": "d0ea36ece469a71a909ebff90777c2f7a49478bb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -113,11 +113,11 @@
|
||||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1680404136,
|
||||
"narHash": "sha256-06D8HJmRv4DdpEQGblMhx2Vm81SBWM61XBBIx7QQfo0=",
|
||||
"lastModified": 1682338428,
|
||||
"narHash": "sha256-T7AL/Us6ecxowjMAlO77GETTQO2SO+1XX2+Y/OSfHk8=",
|
||||
"owner": "Mic92",
|
||||
"repo": "sops-nix",
|
||||
"rev": "b93eb910f768f9788737bfed596a598557e5625d",
|
||||
"rev": "7c8e9727a2ecf9994d4a63d577ad5327e933b6a4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -134,11 +134,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1680086409,
|
||||
"narHash": "sha256-Q2QcVgKvTj/LLuZX9dP8ImySWD5sTn8DDI5+EggRn2c=",
|
||||
"lastModified": 1682815555,
|
||||
"narHash": "sha256-mu4axnbR6cSgnNBGrSydxmKlKWrnHLKlpNmmbqD2V9E=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "068f176a64f0e26dc8c1f0eccf28cbd05be4909b",
|
||||
"revCount": 182,
|
||||
"rev": "da209f34ce34eb6b8c4d2b3256a02eb23ad9f655",
|
||||
"revCount": 191,
|
||||
"type": "git",
|
||||
"url": "https://git.uninsane.org/colin/uninsane"
|
||||
},
|
||||
|
59
flake.nix
59
flake.nix
@@ -26,14 +26,26 @@
|
||||
# <https://github.com/nixos/nixpkgs/tree/nixos-22.11>
|
||||
# nixpkgs-stable.url = "github:nixos/nixpkgs?ref=nixos-22.11";
|
||||
|
||||
# branch workflow:
|
||||
# - daily:
|
||||
# - nixos-unstable cut from master after enough packages have been built in caches.
|
||||
# - every 6 hours:
|
||||
# - master auto-merged into staging.
|
||||
# - 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?
|
||||
# - for everyday development, prefer `nixos-unstable` branch, as it provides good caching.
|
||||
# - if need to test bleeding updates (e.g. if submitting code into staging):
|
||||
# - use `staging-next` if it's been cut (i.e. if there's an active staging-next -> master PR)
|
||||
# - use `staging` if no staging-next branch has been cut.
|
||||
#
|
||||
# <https://github.com/nixos/nixpkgs/tree/nixos-unstable>
|
||||
# nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||
nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=staging-next";
|
||||
|
||||
# nixpkgs = {
|
||||
# url = "./nixpatches";
|
||||
# inputs.nixpkgs.follows = "nixpkgs-unpatched";
|
||||
# };
|
||||
# nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=staging";
|
||||
|
||||
mobile-nixos = {
|
||||
# <https://github.com/nixos/mobile-nixos>
|
||||
@@ -229,9 +241,12 @@
|
||||
(! elem name [ "feeds" "pythonPackagesExtensions" ])
|
||||
&& (allPkgs.lib.meta.availableOn allPkgs.stdenv.hostPlatform pkg)
|
||||
)
|
||||
(allPkgs.sane // {
|
||||
inherit (allPkgs) uninsane-dot-org;
|
||||
})
|
||||
(
|
||||
# expose sane packages and chosen inputs (uninsane.org)
|
||||
(import ./pkgs { pkgs = allPkgs; }) // {
|
||||
inherit (allPkgs) uninsane-dot-org;
|
||||
}
|
||||
)
|
||||
)
|
||||
# self.legacyPackages;
|
||||
{ inherit (self.legacyPackages) x86_64-linux; }
|
||||
@@ -241,20 +256,20 @@
|
||||
let
|
||||
pkgs = self.legacyPackages."x86_64-linux";
|
||||
deployScript = action: pkgs.writeShellScript "deploy-moby" ''
|
||||
nixos-rebuild --flake '.#cross-moby' build
|
||||
nixos-rebuild --flake '.#moby' build $@
|
||||
sudo nix sign-paths -r -k /run/secrets/nix_serve_privkey $(readlink ./result)
|
||||
nixos-rebuild --flake '.#cross-moby' ${action} --target-host colin@moby --use-remote-sudo
|
||||
nixos-rebuild --flake '.#moby' ${action} --target-host colin@moby-hn --use-remote-sudo $@
|
||||
'';
|
||||
in {
|
||||
update-feeds = {
|
||||
type = "app";
|
||||
program = "${pkgs.feeds.passthru.updateScript}";
|
||||
program = "${pkgs.feeds.updateScript}";
|
||||
};
|
||||
|
||||
init-feed = {
|
||||
# use like `nix run '.#init-feed' uninsane.org`
|
||||
type = "app";
|
||||
program = "${pkgs.feeds.passthru.initFeedScript}";
|
||||
program = "${pkgs.feeds.initFeedScript}";
|
||||
};
|
||||
|
||||
deploy-moby-test = {
|
||||
@@ -262,7 +277,7 @@
|
||||
type = "app";
|
||||
program = ''${deployScript "test"}'';
|
||||
};
|
||||
deploy-moby-switch = {
|
||||
deploy-moby = {
|
||||
# `nix run '.#deploy-moby-switch'`
|
||||
type = "app";
|
||||
program = ''${deployScript "switch"}'';
|
||||
@@ -270,14 +285,26 @@
|
||||
};
|
||||
|
||||
templates = {
|
||||
python-data = {
|
||||
env.python-data = {
|
||||
# initialize with:
|
||||
# - `nix flake init -t '/home/colin/dev/nixos/#python-data'`
|
||||
# - `nix flake init -t '/home/colin/dev/nixos/#env.python-data'`
|
||||
# then enter with:
|
||||
# - `nix develop`
|
||||
path = ./templates/python-data;
|
||||
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";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@
|
||||
"desktopGuiApps"
|
||||
"stepmania"
|
||||
];
|
||||
sane.programs.mx-sanebot.enableFor.system = true; # for the docs
|
||||
|
||||
sops.secrets.colin-passwd = {
|
||||
sopsFile = ../../../secrets/lappy.yaml;
|
||||
|
34
hosts/by-name/servo/services/calibre.nix
Normal file
34
hosts/by-name/servo/services/calibre.nix
Normal file
@@ -0,0 +1,34 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
cweb-cfg = config.services.calibre-web;
|
||||
inherit (cweb-cfg) user group;
|
||||
inherit (cweb-cfg.listen) ip port;
|
||||
svc-dir = "/var/lib/${cweb-cfg.dataDir}";
|
||||
in
|
||||
# XXX: disabled because of runtime errors like:
|
||||
# > File "/nix/store/c7jqvx980nlg9xhxi065cba61r2ain9y-calibre-web-0.6.19/lib/python3.10/site-packages/calibreweb/cps/db.py", line 926, in speaking_language
|
||||
# > languages = self.session.query(Languages) \
|
||||
# > AttributeError: 'NoneType' object has no attribute 'query'
|
||||
lib.mkIf false
|
||||
{
|
||||
sane.persist.sys.plaintext = [
|
||||
{ inherit user group; mode = "0700"; directory = svc-dir; }
|
||||
];
|
||||
|
||||
services.calibre-web.enable = true;
|
||||
services.calibre-web.listen.ip = "127.0.0.1";
|
||||
# XXX: externally populate `${svc-dir}/metadata.db` (once) from
|
||||
# <https://github.com/janeczku/calibre-web/blob/master/library/metadata.db>
|
||||
# i don't know why you have to do this??
|
||||
# services.calibre-web.options.calibreLibrary = svc-dir;
|
||||
|
||||
services.nginx.virtualHosts."calibre.uninsane.org" = {
|
||||
addSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://${ip}:${builtins.toString port}";
|
||||
};
|
||||
};
|
||||
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."calibre" = "native";
|
||||
}
|
@@ -1,8 +1,10 @@
|
||||
{ ... }:
|
||||
{
|
||||
imports = [
|
||||
./calibre.nix
|
||||
./ddns-afraid.nix
|
||||
./ddns-he.nix
|
||||
./email
|
||||
./ejabberd.nix
|
||||
./freshrss.nix
|
||||
./gitea.nix
|
||||
@@ -11,12 +13,13 @@
|
||||
./jackett.nix
|
||||
./jellyfin.nix
|
||||
./kiwix-serve.nix
|
||||
./komga.nix
|
||||
./lemmy.nix
|
||||
./matrix
|
||||
./navidrome.nix
|
||||
./nixserve.nix
|
||||
./nginx.nix
|
||||
./pleroma.nix
|
||||
./postfix.nix
|
||||
./postgres.nix
|
||||
./prosody.nix
|
||||
./transmission.nix
|
||||
|
37
hosts/by-name/servo/services/email/default.nix
Normal file
37
hosts/by-name/servo/services/email/default.nix
Normal file
@@ -0,0 +1,37 @@
|
||||
# nix configs to reference:
|
||||
# - <https://gitlab.com/simple-nixos-mailserver/nixos-mailserver>
|
||||
# - <https://github.com/nix-community/nur-combined/-/tree/master/repos/eh5/machines/srv-m/mail-rspamd.nix>
|
||||
# - postfix / dovecot / rspamd / stalwart-jmap / sogo
|
||||
#
|
||||
# rspamd:
|
||||
# - nixos: <https://nixos.wiki/wiki/Rspamd>
|
||||
# - guide: <https://rspamd.com/doc/quickstart.html>
|
||||
# - non-nixos example: <https://dataswamp.org/~solene/2021-07-13-smtpd-rspamd.html>
|
||||
#
|
||||
#
|
||||
# my rough understanding of the pieces:
|
||||
# - postfix handles SMTP protocol with the rest of the world.
|
||||
# - dovecot implements IMAP protocol.
|
||||
# - client auth (i.e. validate that user@uninsane.org is who they claim)
|
||||
# - "folders" (INBOX, JUNK) are internal to dovecot?
|
||||
# or where do folders live, on-disk?
|
||||
#
|
||||
# - non-local clients (i.e. me) interact with BOTH postfix and dovecot, but primarily dovecot:
|
||||
# - mail reading is done via IMAP (so, dovecot)
|
||||
# - mail sending is done via SMTP/submission port (so, postfix)
|
||||
# - but postfix delegates authorization of that outgoing mail to dovecot, on the server side
|
||||
#
|
||||
# - local clients (i.e. sendmail) interact only with postfix
|
||||
|
||||
{ ... }:
|
||||
{
|
||||
imports = [
|
||||
./dovecot.nix
|
||||
./postfix.nix
|
||||
];
|
||||
|
||||
|
||||
#### SPAM FILTERING
|
||||
# services.rspamd.enable = true;
|
||||
# services.rspamd.postfix.enable = true;
|
||||
}
|
135
hosts/by-name/servo/services/email/dovecot.nix
Normal file
135
hosts/by-name/servo/services/email/dovecot.nix
Normal file
@@ -0,0 +1,135 @@
|
||||
# dovecot config options: <https://doc.dovecot.org/configuration_manual/>
|
||||
#
|
||||
# sieve docs:
|
||||
# - sieve language examples: <https://doc.dovecot.org/configuration_manual/sieve/examples/>
|
||||
# - sieve protocol/language: <https://proton.me/support/sieve-advanced-custom-filters>
|
||||
|
||||
{ config, lib, pkgs, ... }:
|
||||
{
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
# exposed over non-vpn imap.uninsane.org
|
||||
143 # IMAP
|
||||
993 # IMAPS
|
||||
];
|
||||
|
||||
# exists only to manage certs for dovecot
|
||||
services.nginx.virtualHosts."imap.uninsane.org" = {
|
||||
enableACME = true;
|
||||
};
|
||||
|
||||
sane.services.trust-dns.zones."uninsane.org".inet = {
|
||||
CNAME."imap" = "native";
|
||||
};
|
||||
|
||||
sops.secrets."dovecot_passwd" = {
|
||||
owner = config.users.users.dovecot2.name;
|
||||
# TODO: debug why mail can't be sent without this being world-readable
|
||||
mode = "0444";
|
||||
};
|
||||
|
||||
# inspired by https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/
|
||||
services.dovecot2.enable = true;
|
||||
# services.dovecot2.enableLmtp = true;
|
||||
services.dovecot2.sslServerCert = "/var/lib/acme/imap.uninsane.org/fullchain.pem";
|
||||
services.dovecot2.sslServerKey = "/var/lib/acme/imap.uninsane.org/key.pem";
|
||||
services.dovecot2.enablePAM = false;
|
||||
|
||||
# sieve scripts require me to set a user for... idk why?
|
||||
services.dovecot2.mailUser = "colin";
|
||||
services.dovecot2.mailGroup = "users";
|
||||
users.users.colin.isSystemUser = lib.mkForce false;
|
||||
|
||||
services.dovecot2.extraConfig =
|
||||
let
|
||||
passwdFile = config.sops.secrets.dovecot_passwd.path;
|
||||
in
|
||||
''
|
||||
passdb {
|
||||
driver = passwd-file
|
||||
args = ${passwdFile}
|
||||
}
|
||||
userdb {
|
||||
driver = passwd-file
|
||||
args = ${passwdFile}
|
||||
}
|
||||
|
||||
# allow postfix to query our auth db
|
||||
service auth {
|
||||
unix_listener auth {
|
||||
mode = 0660
|
||||
user = postfix
|
||||
group = postfix
|
||||
}
|
||||
}
|
||||
auth_mechanisms = plain login
|
||||
|
||||
# accept incoming messaging from postfix
|
||||
# service lmtp {
|
||||
# unix_listener dovecot-lmtp {
|
||||
# mode = 0600
|
||||
# user = postfix
|
||||
# group = postfix
|
||||
# }
|
||||
# }
|
||||
|
||||
# plugin {
|
||||
# sieve_plugins = sieve_imapsieve
|
||||
# }
|
||||
|
||||
mail_debug = yes
|
||||
auth_debug = yes
|
||||
# verbose_ssl = yes
|
||||
'';
|
||||
|
||||
services.dovecot2.mailboxes = {
|
||||
# special-purpose mailboxes: "All" "Archive" "Drafts" "Flagged" "Junk" "Sent" "Trash"
|
||||
# RFC6154 describes these special mailboxes: https://www.ietf.org/rfc/rfc6154.html
|
||||
# how these boxes are treated is 100% up to the client and server to decide.
|
||||
# client behavior:
|
||||
# iOS
|
||||
# - Drafts: ?
|
||||
# - Sent: works
|
||||
# - Trash: works
|
||||
# - Junk: works ("mark" -> "move to Junk")
|
||||
# aerc
|
||||
# - Drafts: works
|
||||
# - Sent: works
|
||||
# - Trash: no; deleted messages are actually deleted
|
||||
# use `:move trash` instead
|
||||
# - Junk: ?
|
||||
# Sent mailbox: all sent messages are copied to it. unclear if this happens server-side or client-side.
|
||||
Drafts = { specialUse = "Drafts"; auto = "create"; };
|
||||
Sent = { specialUse = "Sent"; auto = "create"; };
|
||||
Trash = { specialUse = "Trash"; auto = "create"; };
|
||||
Junk = { specialUse = "Junk"; auto = "create"; };
|
||||
};
|
||||
|
||||
services.dovecot2.mailPlugins = {
|
||||
perProtocol = {
|
||||
# imap.enable = [
|
||||
# "imap_sieve"
|
||||
# ];
|
||||
lda.enable = [
|
||||
"sieve"
|
||||
];
|
||||
# lmtp.enable = [
|
||||
# "sieve"
|
||||
# ];
|
||||
};
|
||||
};
|
||||
services.dovecot2.modules = [
|
||||
pkgs.dovecot_pigeonhole # enables sieve execution (?)
|
||||
];
|
||||
services.dovecot2.sieveScripts = {
|
||||
# if any messages fail to pass (or lack) DKIM, move them to Junk
|
||||
# XXX the key name ("after") is only used to order sieve execution/ordering
|
||||
after = builtins.toFile "ensuredkim.sieve" ''
|
||||
require "fileinto";
|
||||
|
||||
if not header :contains "Authentication-Results" "dkim=pass" {
|
||||
fileinto "Junk";
|
||||
stop;
|
||||
}
|
||||
'';
|
||||
};
|
||||
}
|
@@ -1,7 +1,6 @@
|
||||
# DOCS:
|
||||
# - dovecot config: <https://doc.dovecot.org/configuration_manual/>
|
||||
# postfix config options: <https://www.postfix.org/postconf.5.html>
|
||||
|
||||
{ config, lib, ... }:
|
||||
{ lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
submissionOptions = {
|
||||
@@ -30,20 +29,12 @@ in
|
||||
];
|
||||
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
# exposed over non-vpn imap.uninsane.org
|
||||
143 # IMAP
|
||||
993 # IMAPS
|
||||
|
||||
# exposed over vpn mx.uninsane.org
|
||||
25 # SMTP
|
||||
465 # SMTPS
|
||||
587 # SMTPS/submission
|
||||
];
|
||||
|
||||
# exists only to manage certs for dovecot
|
||||
services.nginx.virtualHosts."imap.uninsane.org" = {
|
||||
enableACME = true;
|
||||
};
|
||||
# exists only to manage certs for Postfix
|
||||
services.nginx.virtualHosts."mx.uninsane.org" = {
|
||||
enableACME = true;
|
||||
@@ -54,7 +45,6 @@ in
|
||||
MX."@" = "10 mx.uninsane.org.";
|
||||
# XXX: RFC's specify that the MX record CANNOT BE A CNAME
|
||||
A."mx" = "185.157.162.178";
|
||||
CNAME."imap" = "native";
|
||||
|
||||
# Sender Policy Framework:
|
||||
# +mx => mail passes if it originated from the MX
|
||||
@@ -98,18 +88,40 @@ in
|
||||
@uninsane.org colin
|
||||
'';
|
||||
|
||||
services.postfix.extraConfig = ''
|
||||
services.postfix.config = {
|
||||
# smtpd_milters = local:/run/opendkim/opendkim.sock
|
||||
# milter docs: http://www.postfix.org/MILTER_README.html
|
||||
# mail filters for receiving email and authorized SMTP clients
|
||||
# mail filters for receiving email and from authorized SMTP clients (i.e. via submission)
|
||||
# smtpd_milters = inet:185.157.162.190:8891
|
||||
smtpd_milters = unix:/run/opendkim/opendkim.sock
|
||||
# opendkim.sock will add a Authentication-Results header, with `dkim=pass|fail|...` value to received messages
|
||||
smtpd_milters = "unix:/run/opendkim/opendkim.sock";
|
||||
# mail filters for sendmail
|
||||
non_smtpd_milters = $smtpd_milters
|
||||
milter_default_action = accept
|
||||
inet_protocols = ipv4
|
||||
smtp_tls_security_level = may
|
||||
'';
|
||||
non_smtpd_milters = "$smtpd_milters";
|
||||
|
||||
# what to do when a milter exits unexpectedly:
|
||||
milter_default_action = "accept";
|
||||
|
||||
inet_protocols = "ipv4";
|
||||
smtp_tls_security_level = "may";
|
||||
|
||||
# hand received mail over to dovecot so that it can run sieves & such
|
||||
mailbox_command = ''${pkgs.dovecot}/libexec/dovecot/dovecot-lda -f "$SENDER" -a "$RECIPIENT"'';
|
||||
|
||||
# hand received mail over to dovecot
|
||||
# virtual_alias_maps = [
|
||||
# "hash:/etc/postfix/virtual"
|
||||
# ];
|
||||
# mydestination = "";
|
||||
# virtual_mailbox_domains = [ "localhost" "uninsane.org" ];
|
||||
# # virtual_mailbox_maps = "hash:/etc/postfix/virtual";
|
||||
# virtual_transport = "lmtp:unix:/run/dovecot2/dovecot-lmtp";
|
||||
|
||||
# anti-spam options: <https://www.postfix.org/SMTPD_ACCESS_README.html>
|
||||
# reject_unknown_sender_domain: causes postfix to `dig <sender> MX` and make sure that exists.
|
||||
# but may cause problems receiving mail from google & others who load-balance?
|
||||
# - <https://unix.stackexchange.com/questions/592131/how-to-reject-email-from-unknown-domains-with-postfix-on-centos>
|
||||
# smtpd_sender_restrictions = reject_unknown_sender_domain
|
||||
};
|
||||
|
||||
services.postfix.enableSubmission = true;
|
||||
services.postfix.submissionOptions = submissionOptions;
|
||||
@@ -124,6 +136,8 @@ in
|
||||
};
|
||||
|
||||
|
||||
#### OPENDKIM
|
||||
|
||||
services.opendkim.enable = true;
|
||||
# services.opendkim.domains = "csl:uninsane.org";
|
||||
services.opendkim.domains = "uninsane.org";
|
||||
@@ -147,59 +161,6 @@ in
|
||||
UMask = lib.mkForce "0011";
|
||||
};
|
||||
|
||||
# inspired by https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/
|
||||
services.dovecot2.enable = true;
|
||||
services.dovecot2.mailboxes = {
|
||||
# special-purpose mailboxes: "All" "Archive" "Drafts" "Flagged" "Junk" "Sent" "Trash"
|
||||
# RFC6154 describes these special mailboxes: https://www.ietf.org/rfc/rfc6154.html
|
||||
# how these boxes are treated is 100% up to the client and server to decide.
|
||||
# client behavior:
|
||||
# iOS
|
||||
# - Drafts: ?
|
||||
# - Sent: works
|
||||
# - Trash: works
|
||||
# aerc
|
||||
# - Drafts: works
|
||||
# - Sent: works
|
||||
# - Trash: no; deleted messages are actually deleted
|
||||
# use `:move trash` instead
|
||||
# Sent mailbox: all sent messages are copied to it. unclear if this happens server-side or client-side.
|
||||
Drafts = { specialUse = "Drafts"; auto = "create"; };
|
||||
Sent = { specialUse = "Sent"; auto = "create"; };
|
||||
Trash = { specialUse = "Trash"; auto = "create"; };
|
||||
};
|
||||
services.dovecot2.sslServerCert = "/var/lib/acme/imap.uninsane.org/fullchain.pem";
|
||||
services.dovecot2.sslServerKey = "/var/lib/acme/imap.uninsane.org/key.pem";
|
||||
services.dovecot2.enablePAM = false;
|
||||
services.dovecot2.extraConfig =
|
||||
let
|
||||
passwdFile = config.sops.secrets.dovecot_passwd.path;
|
||||
in
|
||||
''
|
||||
passdb {
|
||||
driver = passwd-file
|
||||
args = ${passwdFile}
|
||||
}
|
||||
userdb {
|
||||
driver = passwd-file
|
||||
args = ${passwdFile}
|
||||
}
|
||||
|
||||
# allow postfix to query our auth db
|
||||
service auth {
|
||||
unix_listener auth {
|
||||
mode = 0660
|
||||
user = postfix
|
||||
group = postfix
|
||||
}
|
||||
}
|
||||
auth_mechanisms = plain login
|
||||
|
||||
|
||||
mail_debug = yes
|
||||
auth_debug = yes
|
||||
# verbose_ssl = yes
|
||||
'';
|
||||
|
||||
#### OUTGOING MESSAGE REWRITING:
|
||||
services.postfix.enableHeaderChecks = true;
|
||||
@@ -221,10 +182,4 @@ in
|
||||
# pattern = "/^Subject:.*activate your account/";
|
||||
# }
|
||||
];
|
||||
|
||||
sops.secrets."dovecot_passwd" = {
|
||||
owner = config.users.users.dovecot2.name;
|
||||
# TODO: debug why mail can't be sent without this being world-readable
|
||||
mode = "0444";
|
||||
};
|
||||
}
|
22
hosts/by-name/servo/services/komga.nix
Normal file
22
hosts/by-name/servo/services/komga.nix
Normal file
@@ -0,0 +1,22 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
svc-cfg = config.services.komga;
|
||||
inherit (svc-cfg) user group port stateDir;
|
||||
in
|
||||
{
|
||||
sane.persist.sys.plaintext = [
|
||||
{ inherit user group; mode = "0700"; directory = stateDir; }
|
||||
];
|
||||
|
||||
services.komga.enable = true;
|
||||
services.komga.port = 11319; # chosen at random
|
||||
|
||||
services.nginx.virtualHosts."komga.uninsane.org" = {
|
||||
addSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:${builtins.toString port}";
|
||||
};
|
||||
};
|
||||
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."komga" = "native";
|
||||
}
|
60
hosts/by-name/servo/services/lemmy.nix
Normal file
60
hosts/by-name/servo/services/lemmy.nix
Normal file
@@ -0,0 +1,60 @@
|
||||
{ config, lib, ... }:
|
||||
let
|
||||
inherit (builtins) toString;
|
||||
inherit (lib) mkForce;
|
||||
uiPort = 1234; # default ui port is 1234
|
||||
backendPort = 8536; # default backend port is 8536
|
||||
# - i guess the "backend" port is used for federation?
|
||||
in {
|
||||
services.lemmy = {
|
||||
enable = true;
|
||||
settings.hostname = "lemmy.uninsane.org";
|
||||
settings.options.federation.enabled = true;
|
||||
settings.options.port = backendPort;
|
||||
# settings.database.host = "localhost";
|
||||
ui.port = uiPort;
|
||||
database.createLocally = true;
|
||||
};
|
||||
|
||||
systemd.services.lemmy.serviceConfig = {
|
||||
# fix to use a normal user so we can configure perms correctly
|
||||
DynamicUser = mkForce false;
|
||||
User = "lemmy";
|
||||
Group = "lemmy";
|
||||
Environment = [ "RUST_BACKTRACE=full" ];
|
||||
};
|
||||
users.groups.lemmy = {};
|
||||
users.users.lemmy = {
|
||||
group = "lemmy";
|
||||
isSystemUser = true;
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."lemmy.uninsane.org" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations = let
|
||||
ui = "http://127.0.0.1:${toString uiPort}";
|
||||
backend = "http://127.0.0.1:${toString backendPort}";
|
||||
in {
|
||||
# see <LemmyNet/lemmy:docker/federation/nginx.conf>
|
||||
"~ ^/(api|pictrs|feeds|nodeinfo|.well-known)" = {
|
||||
extraConfig = ''
|
||||
set $proxpass ${ui};
|
||||
if ($http_accept = "application/activity+json") {
|
||||
set $proxpass ${backend};
|
||||
}
|
||||
if ($http_accept = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") {
|
||||
set $proxpass ${backend};
|
||||
}
|
||||
|
||||
# Cuts off the trailing slash on URLs to make them valid
|
||||
rewrite ^(.+)/+$ $1 permanent;
|
||||
'';
|
||||
proxyPass = "$proxpass";
|
||||
};
|
||||
"/".proxyPass = ui;
|
||||
};
|
||||
};
|
||||
|
||||
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."lemmy" = "native";
|
||||
}
|
@@ -5,9 +5,8 @@
|
||||
{
|
||||
imports = [
|
||||
./discord-puppet.nix
|
||||
# ./irc.nix
|
||||
# TODO(2023/03/10): disabled because it's not bridging and mautrix_signal is hogging CPU
|
||||
# ./signal.nix
|
||||
./irc.nix
|
||||
./signal.nix
|
||||
];
|
||||
|
||||
sane.persist.sys.plaintext = [
|
||||
|
@@ -0,0 +1,13 @@
|
||||
diff --git a/src/irc/ConnectionInstance.ts b/src/irc/ConnectionInstance.ts
|
||||
index 688036ca..3373fa27 100644
|
||||
--- a/src/irc/ConnectionInstance.ts
|
||||
+++ b/src/irc/ConnectionInstance.ts
|
||||
@@ -149,7 +149,7 @@ export class ConnectionInstance {
|
||||
if (this.dead) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
- ircReason = ircReason || reason;
|
||||
+ ircReason = "bye"; // don't reveal through the IRC quit message that we're a bridge
|
||||
log.info(
|
||||
"disconnect()ing %s@%s - %s", this.nick, this.domain, reason
|
||||
);
|
50
hosts/by-name/servo/services/matrix/irc-no-reveal-mxid.patch
Normal file
50
hosts/by-name/servo/services/matrix/irc-no-reveal-mxid.patch
Normal file
@@ -0,0 +1,50 @@
|
||||
diff --git a/config.schema.yml b/config.schema.yml
|
||||
index 2e71c8d6..42ba8ba1 100644
|
||||
--- a/config.schema.yml
|
||||
+++ b/config.schema.yml
|
||||
@@ -433,7 +433,7 @@ properties:
|
||||
type: "boolean"
|
||||
realnameFormat:
|
||||
type: "string"
|
||||
- enum: ["mxid","reverse-mxid"]
|
||||
+ enum: ["mxid","reverse-mxid","localpart"]
|
||||
ipv6:
|
||||
type: "object"
|
||||
properties:
|
||||
diff --git a/src/irc/IdentGenerator.ts b/src/irc/IdentGenerator.ts
|
||||
index 7a2b5cf1..50f7815a 100644
|
||||
--- a/src/irc/IdentGenerator.ts
|
||||
+++ b/src/irc/IdentGenerator.ts
|
||||
@@ -74,6 +74,9 @@ export class IdentGenerator {
|
||||
else if (server.getRealNameFormat() === "reverse-mxid") {
|
||||
realname = IdentGenerator.sanitiseRealname(IdentGenerator.switchAroundMxid(matrixUser));
|
||||
}
|
||||
+ else if (server.getRealNameFormat() == "localpart") {
|
||||
+ realname = IdentGenerator.sanitiseRealname(matrixUser.localpart);
|
||||
+ }
|
||||
else {
|
||||
throw Error('Invalid value for realNameFormat');
|
||||
}
|
||||
diff --git a/src/irc/IrcServer.ts b/src/irc/IrcServer.ts
|
||||
index 2af73ab4..895b9783 100644
|
||||
--- a/src/irc/IrcServer.ts
|
||||
+++ b/src/irc/IrcServer.ts
|
||||
@@ -101,7 +101,7 @@ export interface IrcServerConfig {
|
||||
};
|
||||
lineLimit: number;
|
||||
userModes?: string;
|
||||
- realnameFormat?: "mxid"|"reverse-mxid";
|
||||
+ realnameFormat?: "mxid"|"reverse-mxid"|"localpart";
|
||||
pingTimeoutMs: number;
|
||||
pingRateMs: number;
|
||||
kickOn: {
|
||||
@@ -289,7 +289,7 @@ export class IrcServer {
|
||||
return this.config.ircClients.userModes || "";
|
||||
}
|
||||
|
||||
- public getRealNameFormat(): "mxid"|"reverse-mxid" {
|
||||
+ public getRealNameFormat(): "mxid"|"reverse-mxid"|"localpart" {
|
||||
return this.config.ircClients.realnameFormat || "mxid";
|
||||
}
|
||||
|
||||
|
@@ -1,21 +1,120 @@
|
||||
# config docs:
|
||||
# - <https://github.com/matrix-org/matrix-appservice-irc/blob/develop/config.sample.yaml>
|
||||
# TODO: /quit message for bridged users reveals to IRC users that i'm using a bridge;
|
||||
# probably want to remove that.
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
ircServer = { name, additionalAddresses ? [], sasl ? true }: let
|
||||
lowerName = lib.toLower name;
|
||||
in {
|
||||
# XXX sasl: appservice doesn't support NickServ identification (only SASL, or PASS if sasl = false)
|
||||
inherit name additionalAddresses sasl;
|
||||
port = 6697;
|
||||
ssl = true;
|
||||
botConfig = {
|
||||
# bot has no presence in IRC channel; only real Matrix users
|
||||
enabled = false;
|
||||
# this is the IRC username/nickname *of the bot* (not visible in channels): not of the end-user.
|
||||
# the irc username/nick of a mapped Matrix user is determined further down in `ircClients` section.
|
||||
# if `enabled` is false, then this name probably never shows up on the IRC side (?)
|
||||
nick = "uninsane";
|
||||
username = "uninsane";
|
||||
joinChannelsIfNoUsers = false;
|
||||
};
|
||||
dynamicChannels = {
|
||||
enabled = true;
|
||||
aliasTemplate = "#irc_${lowerName}_$CHANNEL";
|
||||
published = false; # false => irc rooms aren't listed in homeserver public rooms list
|
||||
federate = false; # false => Matrix users from other homeservers can't join IRC channels
|
||||
};
|
||||
ircClients = {
|
||||
nickTemplate = "$LOCALPARTsane"; # @colin:uninsane.org (Matrix) -> colinsane (IRC)
|
||||
realnameFormat = "reverse-mxid"; # @colin:uninsane.org (Matrix) -> org.uninsane:colin (IRC)
|
||||
# realnameFormat = "localpart"; # @colin:uninsane.org (Matrix) -> colin (IRC) -- but requires the mxid patch below
|
||||
# by default, Matrix will convert messages greater than (3) lines into a pastebin-like URL to send to IRC.
|
||||
lineLimit = 20;
|
||||
# Rizon in particular allows only 4 connections from one IP before a 30min ban.
|
||||
# that's effectively reduced to 2 during a netsplit, or maybe during a restart.
|
||||
# - https://wiki.rizon.net/index.php?title=Connection/Session_Limit_Exemptions
|
||||
# especially, misconfigurations elsewhere in this config may cause hundreds of connections
|
||||
# so this is a safeguard.
|
||||
maxClients = 2;
|
||||
# don't have the bridge disconnect me from IRC when idle.
|
||||
idleTimeout = 0;
|
||||
concurrentReconnectLimit = 2;
|
||||
reconnectIntervalMs = 60000;
|
||||
kickOn = {
|
||||
# remove Matrix user from room when...
|
||||
channelJoinFailure = false;
|
||||
ircConnectionFailure = false;
|
||||
userQuit = true;
|
||||
};
|
||||
};
|
||||
matrixClients = {
|
||||
userTemplate = "@irc_${lowerName}_$NICK"; # the :uninsane.org part is appended automatically
|
||||
};
|
||||
|
||||
# this will let this user message the appservice with `!join #<IRCChannel>` and the rest "Just Works"
|
||||
"@colin:uninsane.org" = "admin";
|
||||
|
||||
membershipLists = {
|
||||
enabled = true;
|
||||
global = {
|
||||
ircToMatrix = {
|
||||
initial = true;
|
||||
incremental = true;
|
||||
requireMatrixJoined = false;
|
||||
};
|
||||
matrixToIrc = {
|
||||
initial = true;
|
||||
incremental = true;
|
||||
};
|
||||
};
|
||||
ignoreIdleUsersOnStartup = {
|
||||
enabled = false; # false => always bridge users, even if idle
|
||||
};
|
||||
};
|
||||
# sync room description?
|
||||
bridgeInfoState = {
|
||||
enabled = true;
|
||||
initial = true;
|
||||
};
|
||||
|
||||
# for per-user IRC password:
|
||||
# - invite @irc_${lowerName}_NickServ:uninsane.org to a DM and type `help` => register
|
||||
# - invite the matrix-appservice-irc user to a DM and type `!help` => add PW to database
|
||||
# to validate that i'm authenticated on the IRC network, DM @irc_${lowerName}_NickServ:uninsane.org:
|
||||
# - send: `STATUS colinsane`
|
||||
# - response should be `3`: "user recognized as owner via password identification"
|
||||
# passwordEncryptionKeyPath = "/path/to/privkey"; # appservice will generate its own if unspecified
|
||||
};
|
||||
in
|
||||
{
|
||||
|
||||
nixpkgs.overlays = [
|
||||
(next: prev: {
|
||||
matrix-appservice-irc = prev.matrix-appservice-irc.overrideAttrs (super: {
|
||||
patches = super.patches or [] ++ [
|
||||
./irc-no-reveal-bridge.patch
|
||||
# ./irc-no-reveal-mxid.patch
|
||||
];
|
||||
});
|
||||
})
|
||||
];
|
||||
|
||||
sane.persist.sys.plaintext = [
|
||||
# TODO: mode?
|
||||
# user and group are both "matrix-appservice-irc"
|
||||
{ user = "993"; group = "992"; directory = "/var/lib/matrix-appservice-irc"; }
|
||||
{ user = "matrix-appservice-irc"; group = "matrix-appservice-irc"; directory = "/var/lib/matrix-appservice-irc"; }
|
||||
];
|
||||
|
||||
services.matrix-synapse.settings.app_service_config_files = [
|
||||
"/var/lib/matrix-appservice-irc/registration.yml" # auto-created by irc appservice
|
||||
];
|
||||
|
||||
# note: Rizon allows only FOUR simultaneous IRC connections per IP: https://wiki.rizon.net/index.php?title=Connection/Session_Limit_Exemptions
|
||||
# Rizon supports CertFP for auth: https://wiki.rizon.net/index.php?title=CertFP
|
||||
services.matrix-appservice-irc.enable = true;
|
||||
services.matrix-appservice-irc.registrationUrl = "http://127.0.0.1:8009";
|
||||
# settings documented here: https://github.com/matrix-org/matrix-appservice-irc/blob/develop/config.sample.yaml
|
||||
services.matrix-appservice-irc.settings = {
|
||||
homeserver = {
|
||||
url = "http://127.0.0.1:8008";
|
||||
@@ -28,68 +127,11 @@
|
||||
|
||||
ircService = {
|
||||
servers = {
|
||||
"irc.rizon.net" = {
|
||||
name = "Rizon";
|
||||
port = 6697; # SSL port
|
||||
ssl = true;
|
||||
sasl = true; # appservice doesn't support NickServ identification
|
||||
botConfig = {
|
||||
# bot has no presence in IRC channel; only real Matrix users
|
||||
enabled = false;
|
||||
# nick = "UninsaneDotOrg";
|
||||
nick = "uninsane";
|
||||
username = "uninsane";
|
||||
};
|
||||
dynamicChannels = {
|
||||
enabled = true;
|
||||
aliasTemplate = "#irc_rizon_$CHANNEL";
|
||||
};
|
||||
ircClients = {
|
||||
nickTemplate = "$LOCALPARTsane";
|
||||
# by default, Matrix will convert messages greater than (3) lines into a pastebin-like URL to send to IRC.
|
||||
lineLimit = 20;
|
||||
};
|
||||
matrixClients = {
|
||||
userTemplate = "@irc_rizon_$NICK"; # the :uninsane.org part is appended automatically
|
||||
};
|
||||
|
||||
# this will let this user message the appservice with `!join #<IRCChannel>` and the rest "Just Works"
|
||||
"@colin:uninsane.org" = "admin";
|
||||
|
||||
membershipLists = {
|
||||
enabled = true;
|
||||
global = {
|
||||
ircToMatrix = {
|
||||
initial = true;
|
||||
incremental = true;
|
||||
requireMatrixJoined = false;
|
||||
};
|
||||
matrixToIrc = {
|
||||
initial = true;
|
||||
incremental = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
# sync room description?
|
||||
bridgeInfoState = {
|
||||
enabled = true;
|
||||
initial = true;
|
||||
};
|
||||
|
||||
# hardcoded mappings, for when dynamicChannels fails us. TODO: probably safe to remove these.
|
||||
# mappings = {
|
||||
# "#chat" = {
|
||||
# roomIds = [ "!GXJSOTdbtxRboGtDep:uninsane.org" ];
|
||||
# };
|
||||
# # BakaBT requires account registration, which i think means my user needs to be added before the appservice user
|
||||
# "#BakaBT" = {
|
||||
# roomIds = [ "!feZKttuYuHilqPFSkD:uninsane.org" ];
|
||||
# };
|
||||
# };
|
||||
# for per-user IRC password:
|
||||
# invite @irc_rizon_NickServ:uninsane.org to a DM and type `help` => register
|
||||
# invite the matrix-appservice-irc user to a DM and type `!help` => add PW to database
|
||||
# passwordEncryptionKeyPath = "/path/to/privkey"; # appservice will generate its own if unspecified
|
||||
"irc.rizon.net" = ircServer { name = "Rizon"; };
|
||||
"irc.myanonamouse.net" = ircServer {
|
||||
name = "MyAnonamouse";
|
||||
additionalAddresses = [ "irc2.myanonamouse.net" ];
|
||||
sasl = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@@ -72,10 +72,8 @@
|
||||
# - #cross-compiling:nixos.org says pkgsCross.gnu64 IS KNOWN TO NOT COMPILE. let this go for now:
|
||||
|
||||
# Nixpkgs PR tracker:
|
||||
# - browserpass (2023/03/14): <https://github.com/NixOS/nixpkgs/pull/221310>
|
||||
# - gupnp_1_6 (2023/03/14): <https://github.com/NixOS/nixpkgs/pull/221308>
|
||||
# - libmbim (2023/02/22, not mine): <https://github.com/NixOS/nixpkgs/pull/217701>
|
||||
|
||||
# - 2023/04/12 (gst_all_1): https://github.com/NixOS/nixpkgs/pull/225664
|
||||
# - 2023/04/12 (subversion,serf,apr-util,pam_mount): https://github.com/NixOS/nixpkgs/pull/225977
|
||||
|
||||
{ config, lib, options, pkgs, ... }:
|
||||
|
||||
@@ -269,65 +267,67 @@ in
|
||||
# the configuration of which specific package set `pkgs.cross` refers to happens elsewhere;
|
||||
# here we just define them all.
|
||||
|
||||
nixpkgs.config.perlPackageOverrides = pkgs: (with pkgs; with pkgs.perlPackages; {
|
||||
# these are the upstream nixpkgs perl modules, but with `nativeBuildInputs = [ perl ]`
|
||||
# to fix cross compilation errors
|
||||
ModuleBuild = buildPerlPackage {
|
||||
pname = "Module-Build";
|
||||
version = "0.4231";
|
||||
src = fetchurl {
|
||||
url = "mirror://cpan/authors/id/L/LE/LEONT/Module-Build-0.4231.tar.gz";
|
||||
hash = "sha256-fg9MaSwXQMGshOoU1+o9i8eYsvsmwJh3Ip4E9DCytxc=";
|
||||
};
|
||||
# support cross-compilation by removing unnecessary File::Temp version check
|
||||
# postPatch = lib.optionalString (stdenv.hostPlatform != stdenv.buildPlatform) ''
|
||||
# sed -i '/File::Temp/d' Build.PL
|
||||
# '';
|
||||
nativeBuildInputs = [ perl ];
|
||||
meta = {
|
||||
description = "Build and install Perl modules";
|
||||
license = with lib.licenses; [ artistic1 gpl1Plus ];
|
||||
mainProgram = "config_data";
|
||||
};
|
||||
};
|
||||
FileBaseDir = buildPerlModule {
|
||||
version = "0.08";
|
||||
pname = "File-BaseDir";
|
||||
src = fetchurl {
|
||||
url = "mirror://cpan/authors/id/K/KI/KIMRYAN/File-BaseDir-0.08.tar.gz";
|
||||
hash = "sha256-wGX80+LyKudpk3vMlxuR+AKU1QCfrBQL+6g799NTBeM=";
|
||||
};
|
||||
configurePhase = ''
|
||||
runHook preConfigure
|
||||
perl Build.PL PREFIX="$out" prefix="$out"
|
||||
'';
|
||||
nativeBuildInputs = [ perl ];
|
||||
propagatedBuildInputs = [ IPCSystemSimple ];
|
||||
buildInputs = [ FileWhich ];
|
||||
meta = {
|
||||
description = "Use the Freedesktop.org base directory specification";
|
||||
license = with lib.licenses; [ artistic1 gpl1Plus ];
|
||||
};
|
||||
};
|
||||
# fixes: "FAILED IPython/terminal/tests/test_debug_magic.py::test_debug_magic_passes_through_generators - pexpect.exceptions.TIMEOUT: Timeout exceeded."
|
||||
Testutf8 = buildPerlPackage {
|
||||
pname = "Test-utf8";
|
||||
version = "1.02";
|
||||
src = fetchurl {
|
||||
url = "mirror://cpan/authors/id/M/MA/MARKF/Test-utf8-1.02.tar.gz";
|
||||
hash = "sha256-34LwnFlAgwslpJ8cgWL6JNNx5gKIDt742aTUv9Zri9c=";
|
||||
};
|
||||
nativeBuildInputs = [ perl ];
|
||||
meta = {
|
||||
description = "Handy utf8 tests";
|
||||
homepage = "https://github.com/2shortplanks/Test-utf8/tree";
|
||||
license = with lib.licenses; [ artistic1 gpl1Plus ];
|
||||
};
|
||||
};
|
||||
# inherit (pkgs.emulated.perl.pkgs)
|
||||
# Testutf8
|
||||
# ;
|
||||
});
|
||||
# nixpkgs.config.perlPackageOverrides = pkgs': (with pkgs'; with pkgs'.perlPackages; {
|
||||
# # these are the upstream nixpkgs perl modules, but with `nativeBuildInputs = [ perl ]`
|
||||
# # to fix cross compilation errors
|
||||
# # see <nixpkgs:pkgs/top-level/perl-packages.nix>
|
||||
# # TODO: try this PR: https://github.com/NixOS/nixpkgs/pull/225640
|
||||
# ModuleBuild = buildPerlPackage {
|
||||
# pname = "Module-Build";
|
||||
# version = "0.4231";
|
||||
# src = pkgs.fetchurl {
|
||||
# url = "mirror://cpan/authors/id/L/LE/LEONT/Module-Build-0.4231.tar.gz";
|
||||
# hash = "sha256-fg9MaSwXQMGshOoU1+o9i8eYsvsmwJh3Ip4E9DCytxc=";
|
||||
# };
|
||||
# # support cross-compilation by removing unnecessary File::Temp version check
|
||||
# # postPatch = lib.optionalString (pkgs.stdenv.hostPlatform != pkgs.stdenv.buildPlatform) ''
|
||||
# # sed -i '/File::Temp/d' Build.PL
|
||||
# # '';
|
||||
# nativeBuildInputs = [ perl ];
|
||||
# meta = {
|
||||
# description = "Build and install Perl modules";
|
||||
# license = with lib.licenses; [ artistic1 gpl1Plus ];
|
||||
# mainProgram = "config_data";
|
||||
# };
|
||||
# };
|
||||
# FileBaseDir = buildPerlModule {
|
||||
# version = "0.08";
|
||||
# pname = "File-BaseDir";
|
||||
# src = pkgs.fetchurl {
|
||||
# url = "mirror://cpan/authors/id/K/KI/KIMRYAN/File-BaseDir-0.08.tar.gz";
|
||||
# hash = "sha256-wGX80+LyKudpk3vMlxuR+AKU1QCfrBQL+6g799NTBeM=";
|
||||
# };
|
||||
# configurePhase = ''
|
||||
# runHook preConfigure
|
||||
# perl Build.PL PREFIX="$out" prefix="$out"
|
||||
# '';
|
||||
# nativeBuildInputs = [ perl ];
|
||||
# propagatedBuildInputs = [ IPCSystemSimple ];
|
||||
# buildInputs = [ FileWhich ];
|
||||
# meta = {
|
||||
# description = "Use the Freedesktop.org base directory specification";
|
||||
# license = with lib.licenses; [ artistic1 gpl1Plus ];
|
||||
# };
|
||||
# };
|
||||
# # fixes: "FAILED IPython/terminal/tests/test_debug_magic.py::test_debug_magic_passes_through_generators - pexpect.exceptions.TIMEOUT: Timeout exceeded."
|
||||
# Testutf8 = buildPerlPackage {
|
||||
# pname = "Test-utf8";
|
||||
# version = "1.02";
|
||||
# src = pkgs.fetchurl {
|
||||
# url = "mirror://cpan/authors/id/M/MA/MARKF/Test-utf8-1.02.tar.gz";
|
||||
# hash = "sha256-34LwnFlAgwslpJ8cgWL6JNNx5gKIDt742aTUv9Zri9c=";
|
||||
# };
|
||||
# nativeBuildInputs = [ perl ];
|
||||
# meta = {
|
||||
# description = "Handy utf8 tests";
|
||||
# homepage = "https://github.com/2shortplanks/Test-utf8/tree";
|
||||
# license = with lib.licenses; [ artistic1 gpl1Plus ];
|
||||
# };
|
||||
# };
|
||||
# # inherit (pkgs.emulated.perl.pkgs)
|
||||
# # Testutf8
|
||||
# # ;
|
||||
# });
|
||||
# XXX: replaceStdenv only affects non-cross stages
|
||||
# nixpkgs.config.replaceStdenv = { pkgs }: pkgs.ccacheStdenv;
|
||||
nixpkgs.overlays = crossOnlyUniversalOverlays ++ [
|
||||
@@ -412,9 +412,11 @@ in
|
||||
# nixpkgs hdf5 is at commit 3e847e003632bdd5fdc189ccbffe25ad2661e16f
|
||||
# hdf5 # configure: error: cannot run test program while cross compiling
|
||||
# http2
|
||||
ibus
|
||||
jellyfin-web # in node-dependencies-jellyfin-web: "node: command not found" (nodePackages don't cross compile)
|
||||
# libgccjit # "../../gcc-9.5.0/gcc/jit/jit-result.c:52:3: error: 'dlclose' was not declared in this scope" (needed by emacs!)
|
||||
# libsForQt5 # qtbase # make: g++: No such file or directory
|
||||
# perlInterpreters # perl5.36.0-Module-Build perl5.36.0-Test-utf8 (see tracking issues ^)
|
||||
perlInterpreters # perl5.36.0-Module-Build perl5.36.0-Test-utf8 (see tracking issues ^)
|
||||
# qgnomeplatform
|
||||
# qtbase
|
||||
qt5 # qt5.qtx11extras fails, but we can't selectively emulate it
|
||||
@@ -508,30 +510,8 @@ in
|
||||
# inherit (self) apacheHttpd;
|
||||
# };
|
||||
# };
|
||||
# appstream = prev.appstream.override {
|
||||
# # doesn't fix: "ld: error adding symbols: file in wrong format"
|
||||
# inherit (emulated) stdenv;
|
||||
# };
|
||||
# appstream = prev.appstream.overrideAttrs (orig: {
|
||||
# # fixes "Program 'gperf' not found or not executable"
|
||||
# # does not fix "ERROR: An exe_wrapper is needed but was not found. Please define one in cross file and check the command and/or add it to PATH."
|
||||
# nativeBuildInputs = orig.nativeBuildInputs ++ [ next.gperf ];
|
||||
# });
|
||||
# appstream = prev.appstream.overrideAttrs (upstream: {
|
||||
# # does not fix "Program 'gperf' not found or not executable"
|
||||
# nativeBuildInputs = upstream.nativeBuildInputs ++ lib.optionals (!prev.stdenv.buildPlatform.canExecute prev.stdenv.hostPlatform) [
|
||||
# next.mesonEmulatorHook
|
||||
# ];
|
||||
# });
|
||||
appstream = prev.appstream.overrideAttrs (upstream: {
|
||||
# fixes "Program 'gperf' not found or not executable"
|
||||
nativeBuildInputs = upstream.nativeBuildInputs ++ lib.optionals (!prev.stdenv.buildPlatform.canExecute prev.stdenv.hostPlatform) [
|
||||
next.mesonEmulatorHook
|
||||
] ++ [
|
||||
next.gperf
|
||||
];
|
||||
});
|
||||
|
||||
# TODO(REMOVE AFTER MERGE): https://github.com/NixOS/nixpkgs/pull/225977
|
||||
aprutil = prev.aprutil.overrideAttrs (upstream: {
|
||||
# nixpkgs patches the ldb version only for the package itself, but derivative packages (serf -> subversion) inherit the wrong -ldb-6.9 flag.
|
||||
postConfigure = upstream.postConfigure + lib.optionalString (next.stdenv.buildPlatform != next.stdenv.hostPlatform) ''
|
||||
@@ -548,21 +528,6 @@ in
|
||||
# configure: error: no acceptable C compiler found in $PATH
|
||||
inherit (emulated) stdenv;
|
||||
};
|
||||
# browserpass = prev.browserpass.override {
|
||||
# # fixes "qemu-aarch64: Could not open '/lib/ld-linux-aarch64.so.1': No such file or directory"
|
||||
# inherit (emulated) buildGoModule; # buildGoModule holds the stdenv
|
||||
# };
|
||||
browserpass = prev.browserpass.overrideAttrs (upstream: {
|
||||
# fixes "qemu-aarch64: Could not open '/lib/ld-linux-aarch64.so.1': No such file or directory"
|
||||
# default browserpass `make` both builds AND tests
|
||||
buildPhase = ''
|
||||
make browserpass
|
||||
'';
|
||||
checkPhase = ''
|
||||
make test
|
||||
'';
|
||||
doCheck = next.stdenv.hostPlatform == next.stdenv.buildPlatform;
|
||||
});
|
||||
cantarell-fonts = prev.cantarell-fonts.override {
|
||||
# fixes error where python3.10-skia-pathops dependency isn't available for the build platform
|
||||
inherit (emulated) stdenv;
|
||||
@@ -632,9 +597,6 @@ in
|
||||
];
|
||||
});
|
||||
|
||||
# fixes: "meson.build:100:0: ERROR: Dependency lookup for wayland-scanner with method 'pkgconfig' failed: Pkg-config binary for machine 0 not found. Giving up."
|
||||
fuzzel = addInputs { depsBuildBuild = [ next.pkg-config ]; } prev.fuzzel;
|
||||
|
||||
fwupd-efi = prev.fwupd-efi.override {
|
||||
# fwupd-efi queries meson host_machine to decide what arch to build for.
|
||||
# for some reason, this gives x86_64 unless meson itself is emulated.
|
||||
@@ -674,51 +636,6 @@ in
|
||||
gcr_4 = mvInputs { nativeBuildInputs = [ next.gnupg next.openssh ]; } prev.gcr_4;
|
||||
gthumb = mvInputs { nativeBuildInputs = [ next.glib ]; } prev.gthumb;
|
||||
|
||||
gmime = prev.gmime.overrideAttrs (upstream: {
|
||||
configureFlags = upstream.configureFlags ++ [
|
||||
"ac_cv_have_iconv_detect_h=yes" # fixes: "checking preferred charset formats for system iconv... cannot run test program while cross compiling"
|
||||
"--enable-cryptography=yes" # force GPGME (TODO: might not be necessary?)
|
||||
];
|
||||
postPatch = upstream.postPatch + ''
|
||||
# mimick how upstream builds iconv-detect.h
|
||||
# the resulting binary is for the host, but unlike configure we know how to invoke that.
|
||||
"$CC" ./iconv-detect.c -o iconv-detect
|
||||
./iconv-detect
|
||||
rm iconv-detect
|
||||
'';
|
||||
});
|
||||
gmime3 = prev.gmime3.overrideAttrs (upstream: {
|
||||
configureFlags = upstream.configureFlags ++ [
|
||||
"ac_cv_have_iconv_detect_h=yes" # fixes: "checking preferred charset formats for system iconv... cannot run test program while cross compiling"
|
||||
"--enable-crypto=yes" # force GPGME (TODO: might not be necessary?)
|
||||
];
|
||||
postPatch = upstream.postPatch + ''
|
||||
# mimick how upstream builds iconv-detect.h
|
||||
# the resulting binary is for the host, but unlike configure we know how to invoke that.
|
||||
"$CC" ./iconv-detect.c -o iconv-detect
|
||||
./iconv-detect
|
||||
rm iconv-detect
|
||||
'';
|
||||
nativeBuildInputs = upstream.nativeBuildInputs or [] ++ [
|
||||
next.buildPackages.gobject-introspection
|
||||
];
|
||||
# configure detects gpgme support by invoking `gpgme-config` which otherwise fails on cross-compiled builds and causes gmime3 to build without gpgme support.
|
||||
# consumers of gmime3 expect gpgme support, so make sure we build it on all platforms with this.
|
||||
GPGME_CONFIG = next.buildPackages.writeShellScript "gpgme-config" ''
|
||||
exec ${lib.getBin next.gpgme.dev}/bin/gpgme-config $@
|
||||
'';
|
||||
});
|
||||
|
||||
# gmime3 = prev.gmime3.overrideAttrs (orig: {
|
||||
# # fixes: "checking preferred charset formats for system iconv... cannot run test program while cross compiling"
|
||||
# # new error: something about python imports; doesn't happen on nixpkgs/tip.
|
||||
# configureFlags = orig.configureFlags ++ [ "ac_cv_have_iconv_detect_h=no" ];
|
||||
# nativeBuildInputs = orig.nativeBuildInputs ++ [ next.gobject-introspection ];
|
||||
# # XXX lib.remove doesn't work on pkg sets (?)
|
||||
# buildInputs = with next; [ vala zlib gpgme libidn2 libunistring ];
|
||||
# # buildInputs = lib.remove next.gobject-introspection orig.buildInputs;
|
||||
# });
|
||||
|
||||
gnome = prev.gnome.overrideScope' (self: super: {
|
||||
inherit (emulated.gnome)
|
||||
;
|
||||
@@ -817,6 +734,8 @@ in
|
||||
"-Dextensions_tool=false"
|
||||
"-Dman=false"
|
||||
"-Dgtk_doc=false"
|
||||
# fixes "src/st/meson.build:198:2: ERROR: Dependency "libmutter-test-12" not found, tried pkgconfig"
|
||||
"-Dtests=false"
|
||||
];
|
||||
outputs = [ "out" "dev" ];
|
||||
postPatch = upstream.postPatch or "" + ''
|
||||
@@ -938,39 +857,8 @@ in
|
||||
buildInputs = lib.remove next.gobject-introspection upstream.buildInputs;
|
||||
strictDeps = true;
|
||||
});
|
||||
gupnp_1_6 = prev.gupnp_1_6.overrideAttrs (orig: {
|
||||
# fixes "subprojects/gi-docgen/meson.build:10:0: ERROR: python3 not found"
|
||||
# this patch is copied from the default gupnp.
|
||||
outputs = [ "out" "dev" ]
|
||||
++ lib.optionals (prev.stdenv.buildPlatform == prev.stdenv.hostPlatform) [ "devdoc" ];
|
||||
mesonFlags = [
|
||||
"-Dgtk_doc=${lib.boolToString (prev.stdenv.buildPlatform == prev.stdenv.hostPlatform)}"
|
||||
"-Dintrospection=${lib.boolToString (prev.stdenv.buildPlatform == prev.stdenv.hostPlatform)}"
|
||||
];
|
||||
});
|
||||
|
||||
gst_all_1 = prev.gst_all_1 // {
|
||||
# gst-editing-services = prev.gst_all_1.gst-editing-services.override {
|
||||
# # fixes "Run-time dependency gst-validate-1.0 found: NO"
|
||||
# # new failure mode: "/nix/store/grqh2wygy9f9wp5bgvqn4im76v82zmcx-binutils-2.39/bin/ld: /nix/store/f7yr5z123d162p5457jh3wzkqm7x8yah-glib-2.74.3/lib/libgobject-2.0.so: error adding symbols: file in wrong format"
|
||||
# inherit (emulated) stdenv;
|
||||
# };
|
||||
# XXX this feels risky; it propagates a (conflicting) gst-plugins to all consumers
|
||||
# gst-editing-services = emulated.gst_all_1.gst-editing-services;
|
||||
# fixes "Run-time dependency gst-validate-1.0 found: NO"
|
||||
# fixes undefined references to Py_Initialize, etc.
|
||||
# - alternative is `mesonFlags = [ "-Dpython=disabled" ]`
|
||||
gst-editing-services = addBuildInputs
|
||||
[ next.python3 ]
|
||||
(mvToBuildInputs [ next.gst_all_1.gst-devtools ] prev.gst_all_1.gst-editing-services);
|
||||
# gst-editing-services =
|
||||
# (mvToBuildInputs [ next.gst_all_1.gst-devtools ] prev.gst_all_1.gst-editing-services);
|
||||
# .overrideAttrs (upstream: {
|
||||
# mesonFlags = upstream.mesonFlags ++ [
|
||||
# # disable "python formatters" to avoid undefined references to Py_Initialize, etc.
|
||||
# "-Dpython=disabled"
|
||||
# ];
|
||||
# });
|
||||
# inherit (emulated.gst_all_1) gst-plugins-good;
|
||||
# gst-plugins-good = prev.gst_all_1.gst-plugins-good.override {
|
||||
# # when invoked with `qt5Support = true`, qtbase shows up in both buildInputs and nativeBuildInputs
|
||||
@@ -1003,17 +891,20 @@ in
|
||||
i2p = mvToNativeInputs [ next.ant next.gettext ] prev.i2p;
|
||||
|
||||
# ibus = (prev.ibus.override {
|
||||
# # fixes: "configure.ac:152: error: possibly undefined macro: AM_PATH_GLIB_2_0"
|
||||
# inherit (emulated) stdenv;
|
||||
ibus = prev.ibus.overrideAttrs (upstream: {
|
||||
nativeBuildInputs = upstream.nativeBuildInputs or [] ++ [
|
||||
next.glib # fixes: ImportError: /nix/store/fi1rsalr11xg00dqwgzbf91jpl3zwygi-gobject-introspection-aarch64-unknown-linux-gnu-1.74.0/lib/gobject-introspection/giscanner/_giscanner.cpython-310-x86_64-linux-gnu.so: cannot open shared object file: No such file or directory
|
||||
next.buildPackages.gobject-introspection # fixes "_giscanner.cpython-310-x86_64-linux-gnu.so: cannot open shared object file: No such file or directory"
|
||||
];
|
||||
buildInputs = lib.remove next.gobject-introspection upstream.buildInputs ++ [
|
||||
next.vala # fixes: "Package `ibus-1.0' not found in specified Vala API directories or GObject-Introspection GIR directories"
|
||||
];
|
||||
});
|
||||
# inherit (emulated)
|
||||
# stdenv # fixes: "configure: error: cannot run test program while cross compiling"
|
||||
# gobject-introspection # "cannot open shared object ..."
|
||||
# ;
|
||||
# });
|
||||
# .overrideAttrs (upstream: {
|
||||
# nativeBuildInputs = upstream.nativeBuildInputs or [] ++ [
|
||||
# next.glib # fixes: ImportError: /nix/store/fi1rsalr11xg00dqwgzbf91jpl3zwygi-gobject-introspection-aarch64-unknown-linux-gnu-1.74.0/lib/gobject-introspection/giscanner/_giscanner.cpython-310-x86_64-linux-gnu.so: cannot open shared object file: No such file or directory
|
||||
# next.buildPackages.gobject-introspection # fixes "_giscanner.cpython-310-x86_64-linux-gnu.so: cannot open shared object file: No such file or directory"
|
||||
# ];
|
||||
# buildInputs = lib.remove next.gobject-introspection upstream.buildInputs ++ [
|
||||
# next.vala # fixes: "Package `ibus-1.0' not found in specified Vala API directories or GObject-Introspection GIR directories"
|
||||
# ];
|
||||
# });
|
||||
|
||||
# fixes "./autogen.sh: line 26: gtkdocize: not found"
|
||||
iio-sensor-proxy = mvToNativeInputs [ next.glib next.gtk-doc ] prev.iio-sensor-proxy;
|
||||
@@ -1030,22 +921,34 @@ in
|
||||
openjdk8-bootstrap = useEmulatedStdenv prev.javaPackages.compiler.openjdk8-bootstrap;
|
||||
# fixes "configure: error: Could not find required tool for WHICH"
|
||||
openjdk8 = useEmulatedStdenv prev.javaPackages.compiler.openjdk8;
|
||||
openjdk19 = (
|
||||
# fixes "configure: error: Could not find required tool for ZIPEXE"
|
||||
# new failure: "checking for cc... [not found]"
|
||||
(mvToNativeInputs
|
||||
[ next.zip ]
|
||||
(useEmulatedStdenv prev.javaPackages.compiler.openjdk19)
|
||||
).overrideAttrs (_upstream: {
|
||||
# avoid building `support/demos`, which segfaults
|
||||
buildFlags = [ "product-images" ];
|
||||
doCheck = false; # pre-emptive
|
||||
})
|
||||
);
|
||||
# openjdk19 = emulated.javaPackages.compiler.openjdk19;
|
||||
# openjdk19 = (
|
||||
# # fixes "configure: error: Could not find required tool for ZIPEXE"
|
||||
# # new failure: "checking for cc... [not found]"
|
||||
# (mvToNativeInputs
|
||||
# [ next.zip ]
|
||||
# (useEmulatedStdenv prev.javaPackages.compiler.openjdk19)
|
||||
# ).overrideAttrs (_upstream: {
|
||||
# # avoid building `support/demos`, which segfaults
|
||||
# buildFlags = [ "product-images" ];
|
||||
# doCheck = false; # pre-emptive
|
||||
# })
|
||||
# );
|
||||
openjdk19 = emulated.javaPackages.compiler.openjdk19;
|
||||
};
|
||||
};
|
||||
|
||||
jellyfin-media-player = prev.jellyfin-media-player.overrideAttrs (upstream: {
|
||||
meta = upstream.meta // {
|
||||
platforms = upstream.meta.platforms ++ [
|
||||
"aarch64-linux"
|
||||
];
|
||||
};
|
||||
});
|
||||
# jellyfin-web = prev.jellyfin-web.override {
|
||||
# # in node-dependencies-jellyfin-web: "node: command not found"
|
||||
# inherit (emulated) stdenv;
|
||||
# };
|
||||
|
||||
kitty = prev.kitty.overrideAttrs (upstream: {
|
||||
# fixes: "FileNotFoundError: [Errno 2] No such file or directory: 'pkg-config'"
|
||||
PKGCONFIG_EXE = "${next.buildPackages.pkg-config}/bin/${next.buildPackages.pkg-config.targetPrefix}pkg-config";
|
||||
@@ -1057,11 +960,6 @@ in
|
||||
./kitty-no-docs.patch
|
||||
];
|
||||
});
|
||||
|
||||
libchamplain = prev.libchamplain.overrideAttrs (upstream: {
|
||||
# fixes: "failed to produce output path for output 'devdoc'"
|
||||
outputs = lib.remove "devdoc" upstream.outputs;
|
||||
});
|
||||
libgweather = (prev.libgweather.override {
|
||||
# alternative to emulating python3 is to specify it in `buildInputs` instead of `nativeBuildInputs` (upstream),
|
||||
# but presumably that's just a different way to emulate it.
|
||||
@@ -1080,13 +978,8 @@ in
|
||||
# # fixes "Run-time dependency vapigen found: NO (tried pkgconfig)"
|
||||
# buildInputs = upstream.buildInputs ++ [ next.vala ];
|
||||
# });
|
||||
# "Can't exec "libtoolize": No such file or directory at /nix/store/r4fvx9hazsm0rdm7s393zd5v665dsh1c-autoconf-2.71/share/autoconf/Autom4te/FileUtils.pm line 294."
|
||||
libHX = mvToNativeInputs [ next.libtool ] prev.libHX;
|
||||
# fixes: "ERROR: Program 'gnutls-certtool certtool' not found or not executable"
|
||||
# N.B.: gnutls library is used by the compiled program (i.e. the host);
|
||||
# gnutls binaries are used by the build machine.
|
||||
# therefore gnutls can be specified in both buildInputs and nativeBuildInputs
|
||||
libjcat = addNativeInputs [ next.gnutls ] prev.libjcat;
|
||||
|
||||
# TODO(REMOVE AFTER MERGE): https://github.com/NixOS/nixpkgs/pull/225977
|
||||
libqmi = prev.libqmi.overrideAttrs (upstream: {
|
||||
# fixes "failed to produce output devdoc"; nixpkgs only builds that output conditionally
|
||||
outputs = [ "out" "dev" ] ++ lib.optionals (prev.stdenv.buildPlatform == prev.stdenv.hostPlatform) [
|
||||
@@ -1094,20 +987,6 @@ in
|
||||
];
|
||||
});
|
||||
|
||||
librest = prev.librest.overrideAttrs (orig: {
|
||||
# fixes "You must have gtk-doc >= 1.13 installed to build documentation"
|
||||
# by removing the "--enable-gtk-doc" flag
|
||||
configureFlags = [ "--with-ca-certificates=/etc/ssl/certs/ca-certificates.crt" ];
|
||||
});
|
||||
librest_1_0 = prev.librest_1_0.overrideAttrs (orig: {
|
||||
# fixes (meson) "Run-time dependency gi-docgen found: NO (tried pkgconfig and cmake)"
|
||||
# inspired by gupnp
|
||||
outputs = [ "out" "dev" ]
|
||||
++ lib.optionals (prev.stdenv.buildPlatform == prev.stdenv.hostPlatform) [ "devdoc" ];
|
||||
mesonFlags = orig.mesonFlags ++ [
|
||||
"-Dgtk_doc=${lib.boolToString (prev.stdenv.buildPlatform == prev.stdenv.hostPlatform)}"
|
||||
];
|
||||
});
|
||||
libsForQt5 = prev.libsForQt5.overrideScope' (self: super: {
|
||||
qgpgme = super.qgpgme.overrideAttrs (orig: {
|
||||
# fix so it can find the MOC compiler
|
||||
@@ -1121,20 +1000,6 @@ in
|
||||
});
|
||||
});
|
||||
|
||||
# libtiger = prev.libtiger.override {
|
||||
# # fails to fix: "src/tiger_internal.h:24:10: fatal error: pango/pango.h: No such file or directory"
|
||||
# inherit (emulated) stdenv;
|
||||
# };
|
||||
# libtiger = prev.libtiger.overrideAttrs (orig: {
|
||||
# # fails to fix: "src/tiger_internal.h:24:10: fatal error: pango/pango.h: No such file or directory"
|
||||
# nativeBuildInputs = orig.nativeBuildInputs ++ [ next.libkate next.cairo next.pango ];
|
||||
# });
|
||||
libtiger = prev.libtiger.overrideAttrs (_upstream: {
|
||||
# libtiger seems to expect PKG_CONFIG to be an absolute path? not sure, but without this it claims it can't find pkg-config.
|
||||
HAVE_PKG_CONFIG = "yes";
|
||||
});
|
||||
|
||||
|
||||
# fixes: "ar: command not found"
|
||||
# `ar` is provided by bintools
|
||||
ncftp = addNativeInputs [ next.bintools ] prev.ncftp;
|
||||
@@ -1263,6 +1128,7 @@ in
|
||||
# nativeBuildInputs = upstream.nativeBuildInputs ++ [ next.gpgme ];
|
||||
# });
|
||||
|
||||
# TODO(REMOVE AFTER MERGE): https://github.com/NixOS/nixpkgs/pull/225977
|
||||
# fixes: "perl: command not found"
|
||||
pam_mount = mvToNativeInputs [ next.perl ] prev.pam_mount;
|
||||
|
||||
@@ -1299,8 +1165,6 @@ in
|
||||
next.desktop-file-utils # fixes "meson.build:116:8: ERROR: Program 'update-desktop-database' not found or not executable"
|
||||
];
|
||||
} prev.phosh-mobile-settings;
|
||||
# fixes `spa/plugins/bluez5/meson.build:41:0: ERROR: Program 'gdbus-codegen' not found or not executable`
|
||||
pipewire = mvToNativeInputs [ next.glib ] prev.pipewire;
|
||||
# psqlodbc = prev.psqlodbc.override {
|
||||
# # fixes "configure: error: odbc_config not found (required for unixODBC build)"
|
||||
# inherit (emulated) stdenv;
|
||||
@@ -1316,6 +1180,10 @@ in
|
||||
];
|
||||
});
|
||||
|
||||
cryptography = py-prev.cryptography.override {
|
||||
inherit (emulated) rustPlatform; # "cargo:warning=aarch64-unknown-linux-gnu-gcc: error: unrecognized command-line option ‘-m64’"
|
||||
};
|
||||
|
||||
defcon = py-prev.defcon.overridePythonAttrs (orig: {
|
||||
nativeBuildInputs = orig.nativeBuildInputs ++ orig.nativeCheckInputs;
|
||||
});
|
||||
@@ -1429,17 +1297,6 @@ in
|
||||
# # };
|
||||
# });
|
||||
|
||||
rapidfuzz-cpp = prev.rapidfuzz-cpp.overrideAttrs (orig: {
|
||||
# fixes "error: could not find git for clone of catch2-populate"
|
||||
buildInputs = orig.buildInputs or [] ++ [ next.catch2_3 ];
|
||||
});
|
||||
rav1e = prev.rav1e.override {
|
||||
# fix "aarch64-unknown-linux-gnu-gcc: error: unrecognized command-line option '-m64'"
|
||||
inherit (emulated)
|
||||
rustPlatform
|
||||
stdenv
|
||||
;
|
||||
};
|
||||
rmlint = prev.rmlint.override {
|
||||
# fixes "Checking whether the C compiler works... no"
|
||||
# rmlint is scons; it reads the CC environment variable, though, so *may* be cross compilable
|
||||
@@ -1459,6 +1316,7 @@ in
|
||||
# inherit (emulated) stdenv;
|
||||
# };
|
||||
|
||||
# TODO(REMOVE AFTER MERGE): https://github.com/NixOS/nixpkgs/pull/225977
|
||||
# fixes "sh: line 1: ar: command not found"
|
||||
serf = addNativeInputs [ next.bintools ] prev.serf;
|
||||
|
||||
@@ -1523,6 +1381,7 @@ in
|
||||
wrapGAppsHook # introduces a competing gtk3 at link-time, unless emulated
|
||||
;
|
||||
};
|
||||
# TODO(REMOVE AFTER MERGE): https://github.com/NixOS/nixpkgs/pull/225977
|
||||
subversion = prev.subversion.overrideAttrs (upstream: {
|
||||
configureFlags = upstream.configureFlags ++ [
|
||||
# configure can't find APR and APR-util, unclear why (are they not placed on PATH?)
|
||||
@@ -1538,8 +1397,6 @@ in
|
||||
rmInputs { nativeBuildInputs = [ next.wrapGAppsHook4 ]; } prev.sysprof
|
||||
)
|
||||
);
|
||||
# fixes "configure: error: *** gdbus-codegen is required to build tpm2-abrmd; No package 'gio-unix-2.0' found"
|
||||
tpm2-abrmd = addNativeInputs [ next.glib ] prev.tpm2-abrmd;
|
||||
tracker-miners = prev.tracker-miners.override {
|
||||
# fixes "meson.build:183:0: ERROR: Can not run test applications in this cross environment."
|
||||
inherit (emulated) stdenv;
|
||||
@@ -1592,7 +1449,11 @@ in
|
||||
xdg-desktop-portal-gtk = mvToBuildInputs [ next.xdg-desktop-portal ] prev.xdg-desktop-portal-gtk;
|
||||
# fixes: "data/meson.build:33:5: ERROR: Program 'msgfmt' not found or not executable"
|
||||
# fixes: "src/meson.build:25:0: ERROR: Program 'gdbus-codegen' not found or not executable"
|
||||
xdg-desktop-portal-gnome = mvToNativeInputs [ next.gettext next.glib ] prev.xdg-desktop-portal-gnome;
|
||||
xdg-desktop-portal-gnome = (
|
||||
addNativeInputs [ next.wayland-scanner ] (
|
||||
mvToNativeInputs [ next.gettext next.glib ] prev.xdg-desktop-portal-gnome
|
||||
)
|
||||
);
|
||||
# webkitgtk = prev.webkitgtk.override { stdenv = next.ccacheStdenv; };
|
||||
# webp-pixbuf-loader = prev.webp-pixbuf-loader.override {
|
||||
# # fixes "Builder called die: Cannot wrap '/nix/store/kpp8qhzdjqgvw73llka5gpnsj0l4jlg8-gdk-pixbuf-aarch64-unknown-linux-gnu-2.42.10/bin/gdk-pixbuf-thumbnailer' because it is not an executable file"
|
||||
@@ -1602,9 +1463,11 @@ in
|
||||
webp-pixbuf-loader = prev.webp-pixbuf-loader.overrideAttrs (upstream: {
|
||||
# fixes: "Builder called die: Cannot wrap '/nix/store/kpp8qhzdjqgvw73llka5gpnsj0l4jlg8-gdk-pixbuf-aarch64-unknown-linux-gnu-2.42.10/bin/gdk-pixbuf-thumbnailer' because it is not an executable file"
|
||||
# gdk-pixbuf doesn't create a `bin/` directory when cross-compiling, breaks some thumbnailing stuff.
|
||||
# - gnome's gdk-pixbuf *explicitly* doesn't build thumbnailer on cross builds
|
||||
# see `librsvg` for a more bullet-proof cross-compilation approach
|
||||
postInstall = "";
|
||||
});
|
||||
# XXX: aarch64 webp-pixbuf-loader wanted by gdk-pixbuf-loaders.cache.drv, wanted by aarch64 gnome-control-center
|
||||
})
|
||||
];
|
||||
};
|
||||
|
@@ -11,7 +11,7 @@
|
||||
./machine-id.nix
|
||||
./net.nix
|
||||
./persist.nix
|
||||
./programs.nix
|
||||
./programs
|
||||
./secrets.nix
|
||||
./ssh.nix
|
||||
./users.nix
|
||||
|
@@ -109,13 +109,16 @@ let
|
||||
(fromDb "talesfromthebridge.buzzsprout.com" // tech)
|
||||
## UnNamed Reverse Engineering Podcast
|
||||
(fromDb "reverseengineering.libsyn.com/rss" // tech)
|
||||
## The Witch Trials of J.K. Rowling
|
||||
## - <https://www.thefp.com/witchtrials>
|
||||
(mkPod "https://feeds.megaphone.fm/RUNMED9919162779" // pol // infrequent)
|
||||
];
|
||||
|
||||
texts = [
|
||||
# AGGREGATORS (> 1 post/day)
|
||||
(fromDb "lwn.net" // tech)
|
||||
(fromDb "lesswrong.com" // rat)
|
||||
(fromDb "econlib.org" // pol)
|
||||
# (fromDb "econlib.org" // pol)
|
||||
|
||||
# AGGREGATORS (< 1 post/day)
|
||||
(fromDb "palladiummag.com" // uncat)
|
||||
@@ -134,6 +137,7 @@ let
|
||||
(fromDb "rifters.com/crawl" // uncat)
|
||||
|
||||
# DEVELOPERS
|
||||
(fromDb "blog.jmp.chat" // tech)
|
||||
(fromDb "uninsane.org" // tech)
|
||||
(fromDb "ascii.textfiles.com" // tech) # Jason Scott
|
||||
(fromDb "xn--gckvb8fzb.com" // tech)
|
||||
@@ -207,6 +211,9 @@ let
|
||||
## mostly dating topics. not advice, or humor, but looking through a social lens
|
||||
(fromDb "putanumonit.com" // rat)
|
||||
|
||||
# LOCAL
|
||||
(fromDb "capitolhillseattle.com" // pol)
|
||||
|
||||
# CODE
|
||||
# (mkText "https://github.com/Kaiteki-Fedi/Kaiteki/commits/master.atom" // tech // infrequent)
|
||||
];
|
||||
|
@@ -1,11 +0,0 @@
|
||||
# Terminal UI mail client
|
||||
{ config, sane-lib, ... }:
|
||||
|
||||
{
|
||||
sops.secrets."aerc_accounts" = {
|
||||
owner = config.users.users.colin.name;
|
||||
sopsFile = ../../../secrets/universal/aerc_accounts.conf;
|
||||
format = "binary";
|
||||
};
|
||||
sane.user.fs.".config/aerc/accounts.conf" = sane-lib.fs.wantedSymlinkTo config.sops.secrets.aerc_accounts.path;
|
||||
}
|
@@ -1,25 +1,9 @@
|
||||
{ ... }:
|
||||
{
|
||||
imports = [
|
||||
./aerc.nix
|
||||
./firefox.nix
|
||||
./gfeeds.nix
|
||||
./git.nix
|
||||
./gpodder.nix
|
||||
./keyring.nix
|
||||
./kitty
|
||||
./libreoffice.nix
|
||||
./mime.nix
|
||||
./mpv.nix
|
||||
./neovim.nix
|
||||
./newsflash.nix
|
||||
./offlineimap.nix
|
||||
./ripgrep.nix
|
||||
./splatmoji.nix
|
||||
./ssh.nix
|
||||
./sublime-music.nix
|
||||
./vlc.nix
|
||||
./xdg-dirs.nix
|
||||
./zsh
|
||||
];
|
||||
}
|
||||
|
@@ -1,10 +0,0 @@
|
||||
{ sane-lib, ... }:
|
||||
|
||||
{
|
||||
# format is <key>=%<length>%<value>
|
||||
sane.user.fs.".config/mpv/mpv.conf" = sane-lib.fs.wantedText ''
|
||||
save-position-on-quit=%3%yes
|
||||
keep-open=%3%yes
|
||||
'';
|
||||
}
|
||||
|
@@ -1,12 +0,0 @@
|
||||
# news-flash RSS viewer
|
||||
{ config, sane-lib, ... }:
|
||||
|
||||
let
|
||||
feeds = sane-lib.feeds;
|
||||
all-feeds = config.sane.feeds;
|
||||
wanted-feeds = feeds.filterByFormat ["text" "image"] all-feeds;
|
||||
in {
|
||||
sane.user.fs.".config/newsflashFeeds.opml" = sane-lib.fs.wantedText (
|
||||
feeds.feedsToOpml wanted-feeds
|
||||
);
|
||||
}
|
@@ -1,17 +0,0 @@
|
||||
# mail archiving/synchronization tool.
|
||||
#
|
||||
# manually download all emails for an account with
|
||||
# - `offlineimap -a <accountname>`
|
||||
#
|
||||
# view account names inside the secrets file, listed below.
|
||||
{ config, sane-lib, ... }:
|
||||
|
||||
{
|
||||
sops.secrets."offlineimaprc" = {
|
||||
owner = config.users.users.colin.name;
|
||||
sopsFile = ../../../secrets/universal/offlineimaprc.bin;
|
||||
format = "binary";
|
||||
};
|
||||
sane.user.fs.".config/offlineimap/config" = sane-lib.fs.wantedSymlinkTo config.sops.secrets.offlineimaprc.path;
|
||||
}
|
||||
|
@@ -1,20 +0,0 @@
|
||||
# borrows from:
|
||||
# - default config: <https://github.com/cspeterson/splatmoji/blob/master/splatmoji.config>
|
||||
# - wayland: <https://github.com/cspeterson/splatmoji/issues/32#issuecomment-830862566>
|
||||
{ pkgs, sane-lib, ... }:
|
||||
|
||||
{
|
||||
sane.user.persist.plaintext = [ ".local/state/splatmoji" ];
|
||||
sane.user.fs.".config/splatmoji/splatmoji.config" = sane-lib.fs.wantedText ''
|
||||
# XXX doesn't seem to understand ~ as shorthand for `$HOME`
|
||||
history_file=/home/colin/.local/state/splatmoji/history
|
||||
history_length=5
|
||||
# TODO: wayland equiv
|
||||
paste_command=xdotool key ctrl+v
|
||||
# rofi_command=${pkgs.wofi}/bin/wofi --dmenu --insensitive --cache-file /dev/null
|
||||
rofi_command=${pkgs.fuzzel}/bin/fuzzel -d -i -w 60
|
||||
xdotool_command=${pkgs.wtype}/bin/wtype
|
||||
# TODO: wayland equiv
|
||||
xsel_command=xsel -b -i
|
||||
'';
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
{ config, sane-lib, ... }:
|
||||
|
||||
{
|
||||
# TODO: this should only be shipped on gui platforms
|
||||
sops.secrets."sublime_music_config" = {
|
||||
owner = config.users.users.colin.name;
|
||||
sopsFile = ../../../secrets/universal/sublime_music_config.json.bin;
|
||||
format = "binary";
|
||||
};
|
||||
sane.user.fs.".config/sublime-music/config.json" = sane-lib.fs.wantedSymlinkTo config.sops.secrets.sublime_music_config.path;
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
{ config, lib, sane-lib, ... }:
|
||||
|
||||
let
|
||||
feeds = sane-lib.feeds;
|
||||
all-feeds = config.sane.feeds;
|
||||
wanted-feeds = feeds.filterByFormat ["podcast"] all-feeds;
|
||||
podcast-urls = lib.concatStringsSep "|" (
|
||||
builtins.map (feed: feed.url) wanted-feeds
|
||||
);
|
||||
in
|
||||
{
|
||||
sane.user.fs.".config/vlc/vlcrc" = sane-lib.fs.wantedText ''
|
||||
[podcast]
|
||||
podcast-urls=${podcast-urls}
|
||||
[core]
|
||||
metadata-network-access=0
|
||||
[qt]
|
||||
qt-privacy-ask=0
|
||||
'';
|
||||
}
|
@@ -1,161 +0,0 @@
|
||||
{ config, lib, pkgs, sane-lib, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
cfg = config.sane.zsh;
|
||||
# powerlevel10k prompt config
|
||||
# p10k.zsh is the auto-generated config, and i overwrite those defaults here, below.
|
||||
p10k-overrides = ''
|
||||
# powerlevel10k launches a gitstatusd daemon to accelerate git prompt queries.
|
||||
# this keeps open file handles for any git repo i touch for 60 minutes (by default).
|
||||
# that prevents unmounting whatever device the git repo is on -- particularly problematic for ~/private.
|
||||
# i can disable gitstatusd and get slower fallback git queries:
|
||||
# - either universally
|
||||
# - or selectively by path
|
||||
# see: <https://github.com/romkatv/powerlevel10k/issues/246>
|
||||
typeset -g POWERLEVEL9K_VCS_DISABLED_DIR_PATTERN='(/home/colin/private/*|/home/colin/knowledge/*)'
|
||||
# typeset -g POWERLEVEL9K_DISABLE_GITSTATUS=true
|
||||
|
||||
# show user@host also when logged into the current machine.
|
||||
# default behavior is to show it only over ssh.
|
||||
typeset -g POWERLEVEL9K_CONTEXT_{DEFAULT,SUDO}_CONTENT_EXPANSION='$P9K_CONTENT'
|
||||
'';
|
||||
|
||||
prezto-init = ''
|
||||
source ${pkgs.zsh-autosuggestions}/share/zsh-autosuggestions/zsh-autosuggestions.zsh
|
||||
source ${pkgs.zsh-syntax-highlighting}/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
|
||||
source ${pkgs.zsh-prezto}/share/zsh-prezto/init.zsh
|
||||
'';
|
||||
in
|
||||
{
|
||||
options = {
|
||||
sane.zsh = {
|
||||
showDeadlines = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "show upcoming deadlines (frommy PKM) upon shell init";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
sane.user.persist.plaintext = [
|
||||
# we don't need to full zsh dir -- just the history file --
|
||||
# but zsh will sometimes backup the history file and we get fewer errors if we do proper mounts instead of symlinks.
|
||||
# TODO: should be private?
|
||||
".local/share/zsh"
|
||||
# cache gitstatus otherwise p10k fetched it from the net EVERY BOOT
|
||||
".cache/gitstatus"
|
||||
];
|
||||
|
||||
# zsh/prezto complains if zshrc doesn't exist; but it does allow an "empty" file.
|
||||
sane.user.fs.".config/zsh/.zshrc" = sane-lib.fs.wantedText "# ";
|
||||
|
||||
# enable zsh completions
|
||||
environment.pathsToLink = [ "/share/zsh" ];
|
||||
|
||||
programs.zsh = {
|
||||
enable = true;
|
||||
histFile = "$HOME/.local/share/zsh/history";
|
||||
shellAliases = {
|
||||
":q" = "exit";
|
||||
# common typos
|
||||
"cd.." = "cd ..";
|
||||
"cd../" = "cd ../";
|
||||
};
|
||||
setOptions = [
|
||||
# defaults:
|
||||
"HIST_IGNORE_DUPS"
|
||||
"SHARE_HISTORY"
|
||||
"HIST_FCNTL_LOCK"
|
||||
# disable `rm *` confirmations
|
||||
"rmstarsilent"
|
||||
];
|
||||
|
||||
# .zshenv config:
|
||||
shellInit = ''
|
||||
ZDOTDIR=$HOME/.config/zsh
|
||||
'';
|
||||
|
||||
# .zshrc config:
|
||||
interactiveShellInit =
|
||||
(builtins.readFile ./p10k.zsh)
|
||||
+ p10k-overrides
|
||||
+ prezto-init
|
||||
+ ''
|
||||
# zmv is a way to do rich moves/renames, with pattern matching/substitution.
|
||||
# see for an example: <https://filipe.kiss.ink/zmv-zsh-rename/>
|
||||
autoload -Uz zmv
|
||||
|
||||
HISTORY_IGNORE='(sane-shutdown *|sane-reboot *|rm *|nixos-rebuild.* switch)'
|
||||
|
||||
# extra aliases
|
||||
# TODO: move to `shellAliases` config?
|
||||
function nd() {
|
||||
mkdir -p "$1";
|
||||
pushd "$1";
|
||||
}
|
||||
''
|
||||
+ lib.optionalString cfg.showDeadlines ''
|
||||
${pkgs.sane-scripts}/bin/sane-deadlines
|
||||
''
|
||||
+ ''
|
||||
# auto-cd into any of these dirs by typing them and pressing 'enter':
|
||||
hash -d 3rd="/home/colin/dev/3rd"
|
||||
hash -d dev="/home/colin/dev"
|
||||
hash -d knowledge="/home/colin/knowledge"
|
||||
hash -d nixos="/home/colin/nixos"
|
||||
hash -d nixpkgs="/home/colin/dev/3rd/nixpkgs"
|
||||
hash -d ref="/home/colin/ref"
|
||||
hash -d secrets="/home/colin/knowledge/secrets"
|
||||
hash -d tmp="/home/colin/tmp"
|
||||
hash -d uninsane="/home/colin/dev/uninsane"
|
||||
hash -d Videos="/home/colin/Videos"
|
||||
'';
|
||||
|
||||
syntaxHighlighting.enable = true;
|
||||
vteIntegration = true;
|
||||
};
|
||||
|
||||
# enable a command-not-found hook to show nix packages that might provide the binary typed.
|
||||
programs.nix-index.enable = true;
|
||||
programs.command-not-found.enable = false; #< mutually exclusive with nix-index
|
||||
|
||||
# prezto = oh-my-zsh fork; controls prompt, auto-completion, etc.
|
||||
# see: https://github.com/sorin-ionescu/prezto
|
||||
# i believe this file is auto-sourced by the prezto init.zsh script.
|
||||
sane.user.fs.".config/zsh/.zpreztorc" = sane-lib.fs.wantedText ''
|
||||
zstyle ':prezto:*:*' color 'yes'
|
||||
|
||||
# modules (they ship with prezto):
|
||||
# ENVIRONMENT: configures jobs to persist after shell exit; other basic niceties
|
||||
# TERMINAL: auto-titles terminal (e.g. based on cwd)
|
||||
# EDITOR: configures shortcuts like Ctrl+U=undo, Ctrl+L=clear
|
||||
# HISTORY: `history-stat` alias, setopts for good history defaults
|
||||
# DIRECTORY: sets AUTO_CD, adds `d` alias to list directory stack, and `1`-`9` to cd that far back the stack
|
||||
# SPECTRUM: helpers for term colors and styling. used by prompts? might be unnecessary
|
||||
# UTILITY: configures aliases like `ll`, `la`, disables globbing for things like rsync
|
||||
# adds aliases like `get` to fetch a file. also adds `http-serve` alias??
|
||||
# COMPLETION: tab completion. requires `utility` module prior to loading
|
||||
# TODO: enable AUTO_PARAM_SLASH
|
||||
zstyle ':prezto:load' pmodule \
|
||||
'environment' \
|
||||
'terminal' \
|
||||
'editor' \
|
||||
'history' \
|
||||
'directory' \
|
||||
'spectrum' \
|
||||
'utility' \
|
||||
'completion' \
|
||||
'prompt'
|
||||
|
||||
# default keymap. try also `vicmd` (vim normal mode, AKA "cmd mode") or `vi`.
|
||||
zstyle ':prezto:module:editor' key-bindings 'emacs'
|
||||
|
||||
zstyle ':prezto:module:prompt' theme 'powerlevel10k'
|
||||
|
||||
# disable `mv` confirmation (and `rm`, too, unfortunately)
|
||||
zstyle ':prezto:module:utility' safe-ops 'no'
|
||||
'';
|
||||
};
|
||||
}
|
@@ -15,6 +15,8 @@
|
||||
sane.ids.acme.gid = 996;
|
||||
sane.ids.pleroma.uid = 997;
|
||||
sane.ids.acme.uid = 998;
|
||||
sane.ids.matrix-appservice-irc.uid = 993;
|
||||
sane.ids.matrix-appservice-irc.gid = 992;
|
||||
|
||||
# greetd (used by sway)
|
||||
sane.ids.greeter.uid = 999;
|
||||
@@ -30,6 +32,12 @@
|
||||
sane.ids.mautrix-signal.gid = 2404;
|
||||
sane.ids.navidrome.uid = 2405;
|
||||
sane.ids.navidrome.gid = 2405;
|
||||
sane.ids.calibre-web.uid = 2406;
|
||||
sane.ids.calibre-web.gid = 2406;
|
||||
sane.ids.komga.uid = 2407;
|
||||
sane.ids.komga.gid = 2407;
|
||||
sane.ids.lemmy.uid = 2408;
|
||||
sane.ids.lemmy.gid = 2408;
|
||||
|
||||
sane.ids.colin.uid = 1000;
|
||||
sane.ids.guest.uid = 1100;
|
||||
|
6
hosts/common/programs/aerc.nix
Normal file
6
hosts/common/programs/aerc.nix
Normal file
@@ -0,0 +1,6 @@
|
||||
# Terminal UI mail client
|
||||
{ config, sane-lib, ... }:
|
||||
|
||||
{
|
||||
sane.programs.aerc.secrets.".config/aerc/accounts.conf" = ../../../secrets/universal/aerc_accounts.conf.bin;
|
||||
}
|
@@ -1,8 +1,8 @@
|
||||
{ lib, pkgs, ... }:
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (builtins) attrNames concatLists;
|
||||
inherit (lib) mapAttrs mapAttrsToList mkDefault mkMerge optional;
|
||||
inherit (lib) mapAttrs mapAttrsToList mkDefault mkIf mkMerge optional;
|
||||
|
||||
flattenedPkgs = pkgs // (with pkgs; {
|
||||
# XXX can't `inherit` a nested attr, so we move them to the toplevel
|
||||
@@ -98,7 +98,8 @@ let
|
||||
efivar
|
||||
flashrom
|
||||
fwupd
|
||||
ghostscript # TODO: imagemagick wrapper should add gs to PATH
|
||||
gh # MS GitHub cli
|
||||
git # needed as a user package, for config.
|
||||
gnupg
|
||||
gocryptfs
|
||||
gopass
|
||||
@@ -110,15 +111,18 @@ let
|
||||
lshw
|
||||
ffmpeg
|
||||
memtester
|
||||
neovim
|
||||
# nettools
|
||||
# networkmanager
|
||||
nixpkgs-review
|
||||
# nixos-generators
|
||||
# nettools
|
||||
nmon
|
||||
# node2nix
|
||||
oathToolkit # for oathtool
|
||||
# ponymix
|
||||
pulsemixer
|
||||
python3
|
||||
ripgrep # needed as a user package, for config.
|
||||
rsync
|
||||
# python3Packages.eyeD3 # music tagging
|
||||
sane-scripts
|
||||
@@ -133,8 +137,10 @@ let
|
||||
unar
|
||||
wireguard-tools
|
||||
xdg-utils # for xdg-open
|
||||
# yarn
|
||||
# youtube-dl
|
||||
yt-dlp
|
||||
zsh
|
||||
;
|
||||
};
|
||||
|
||||
@@ -145,15 +151,15 @@ let
|
||||
emote
|
||||
evince # works on phosh
|
||||
|
||||
# { pkg = fluffychat-moby; dir = [ ".local/share/chat.fluffy.fluffychat" ]; } # TODO: ship normal fluffychat on non-moby?
|
||||
# { pkg = fluffychat-moby; persist.plaintext = [ ".local/share/chat.fluffy.fluffychat" ]; } # TODO: ship normal fluffychat on non-moby?
|
||||
|
||||
# foliate # e-book reader
|
||||
|
||||
# XXX by default fractal stores its state in ~/.local/share/<UUID>.
|
||||
# after logging in, manually change ~/.local/share/keyrings/... to point it to some predictable subdir.
|
||||
# then reboot (so that libsecret daemon re-loads the keyring...?)
|
||||
# { pkg = fractal-latest; private = [ ".local/share/fractal" ]; }
|
||||
# { pkg = fractal-next; private = [ ".local/share/fractal" ]; }
|
||||
# { pkg = fractal-latest; persist.private = [ ".local/share/fractal" ]; }
|
||||
# { pkg = fractal-next; persist.private = [ ".local/share/fractal" ]; }
|
||||
|
||||
# "gnome.cheese"
|
||||
"gnome.dconf-editor"
|
||||
@@ -167,6 +173,7 @@ let
|
||||
"gnome.gnome-weather"
|
||||
gpodder-configured
|
||||
gthumb
|
||||
jellyfin-media-player
|
||||
# lollypop
|
||||
mpv
|
||||
networkmanagerapplet
|
||||
@@ -177,12 +184,7 @@ let
|
||||
playerctl
|
||||
# "libsForQt5.plasmatube" # Youtube player
|
||||
soundconverter
|
||||
# sublime music persists any downloaded albums here.
|
||||
# it doesn't obey a conventional ~/Music/{Artist}/{Album}/{Track} notation, so no symlinking
|
||||
# config (e.g. server connection details) is persisted in ~/.config/sublime-music/config.json
|
||||
# possible to pass config as a CLI arg (sublime-music -c config.json)
|
||||
# { pkg = sublime-music; dir = [ ".local/share/sublime-music" ]; }
|
||||
sublime-music-mobile
|
||||
sublime-music
|
||||
# tdesktop # broken on phosh
|
||||
# tokodon
|
||||
vlc
|
||||
@@ -207,13 +209,14 @@ let
|
||||
handbrake
|
||||
hase
|
||||
inkscape
|
||||
jellyfin-media-player # TODO: try on moby!
|
||||
kdenlive
|
||||
kid3 # audio tagging
|
||||
krita
|
||||
libreoffice-fresh # XXX colin: maybe don't want this on mobile
|
||||
mumble
|
||||
obsidian
|
||||
slic3r
|
||||
steam
|
||||
;
|
||||
};
|
||||
x86GuiPkgs = {
|
||||
@@ -231,6 +234,7 @@ let
|
||||
signal-desktop
|
||||
spotify
|
||||
tor-browser-bundle-bin
|
||||
zeal-qt5 # programming docs viewer. TODO: switch to zeal-qt6
|
||||
zecwallet-lite
|
||||
;
|
||||
};
|
||||
@@ -238,17 +242,39 @@ let
|
||||
# packages not part of any package set
|
||||
otherPkgs = {
|
||||
inherit (pkgs)
|
||||
mx-sanebot
|
||||
stepmania
|
||||
;
|
||||
};
|
||||
|
||||
# define -- but don't enable -- the packages in some attrset.
|
||||
# use `mkDefault` for the package here so we can customize some of them further down this file
|
||||
declarePkgs = pkgsAsAttrs: mapAttrs (_n: p: {
|
||||
package = mkDefault p;
|
||||
# no need to actually define the package here: it's defaulted
|
||||
# package = mkDefault p;
|
||||
}) pkgsAsAttrs;
|
||||
in
|
||||
{
|
||||
|
||||
imports = [
|
||||
./aerc.nix
|
||||
./git.nix
|
||||
./gnome-feeds.nix
|
||||
./gpodder.nix
|
||||
./kitty
|
||||
./libreoffice.nix
|
||||
./mpv.nix
|
||||
./neovim.nix
|
||||
./newsflash.nix
|
||||
./offlineimap.nix
|
||||
./ripgrep.nix
|
||||
./splatmoji.nix
|
||||
./sublime-music.nix
|
||||
./vlc.nix
|
||||
./web-browser.nix
|
||||
./zeal.nix
|
||||
./zsh
|
||||
];
|
||||
|
||||
config = {
|
||||
sane.programs = mkMerge [
|
||||
(declarePkgs consolePkgs)
|
||||
@@ -299,68 +325,75 @@ in
|
||||
}
|
||||
{
|
||||
# nontrivial package definitions
|
||||
imagemagick.package = pkgs.imagemagick.override {
|
||||
ghostscriptSupport = true;
|
||||
};
|
||||
|
||||
dino.private = [ ".local/share/dino" ];
|
||||
dino.persist.private = [ ".local/share/dino" ];
|
||||
|
||||
# creds, but also 200 MB of node modules, etc
|
||||
discord.private = [ ".config/discord" ];
|
||||
discord.persist.private = [ ".config/discord" ];
|
||||
|
||||
# creds/session keys, etc
|
||||
element-desktop.private = [ ".config/Element" ];
|
||||
element-desktop.persist.private = [ ".config/Element" ];
|
||||
|
||||
# `emote` will show a first-run dialog based on what's in this directory.
|
||||
# mostly, it just keeps a LRU of previously-used emotes to optimize display order.
|
||||
# TODO: package [smile](https://github.com/mijorus/smile) for probably a better mobile experience.
|
||||
emote.dir = [ ".local/share/Emote" ];
|
||||
emote.persist.plaintext = [ ".local/share/Emote" ];
|
||||
|
||||
# MS GitHub stores auth token in .config
|
||||
# TODO: we can populate gh's stuff statically; it even lets us use the same oauth across machines
|
||||
gh.persist.private = [ ".config/gh" ];
|
||||
|
||||
ghostscript = {}; # used by imagemagick
|
||||
|
||||
# XXX: we preserve the whole thing because if we only preserve gPodder/Downloads
|
||||
# then startup is SLOW during feed import, and we might end up with zombie eps in the dl dir.
|
||||
gpodder-configured.dir = [ "gPodder" ];
|
||||
gpodder-configured.persist.plaintext = [ "gPodder" ];
|
||||
|
||||
imagemagick = {
|
||||
package = pkgs.imagemagick.override {
|
||||
ghostscriptSupport = true;
|
||||
};
|
||||
suggestedPrograms = [ "ghostscript" ];
|
||||
};
|
||||
|
||||
# jellyfin stores things in a bunch of directories: this one persists auth info.
|
||||
# it *might* be possible to populate this externally (it's Qt stuff), but likely to
|
||||
# be fragile and take an hour+ to figure out.
|
||||
jellyfin-media-player.dir = [ ".local/share/Jellyfin Media Player" ];
|
||||
jellyfin-media-player.persist.plaintext = [ ".local/share/Jellyfin Media Player" ];
|
||||
|
||||
# actual monero blockchain (not wallet/etc; safe to delete, just slow to regenerate)
|
||||
# XXX: is it really safe to persist this? it doesn't have info that could de-anonymize if captured?
|
||||
monero-gui.dir = [ ".bitmonero" ];
|
||||
monero-gui.persist.plaintext = [ ".bitmonero" ];
|
||||
|
||||
mpv.dir = [ ".config/mpv/watch_later" ];
|
||||
|
||||
mumble.private = [ ".local/share/Mumble" ];
|
||||
mumble.persist.private = [ ".local/share/Mumble" ];
|
||||
|
||||
# not strictly necessary, but allows caching articles; offline use, etc.
|
||||
newsflash.dir = [ ".local/share/news-flash" ];
|
||||
nheko.private = [
|
||||
nheko.persist.private = [
|
||||
".config/nheko" # config file (including client token)
|
||||
".cache/nheko" # media cache
|
||||
".local/share/nheko" # per-account state database
|
||||
];
|
||||
|
||||
# settings (electron app)
|
||||
obsidian.dir = [ ".config/obsidian" ];
|
||||
obsidian.persist.plaintext = [ ".config/obsidian" ];
|
||||
|
||||
# creds, media
|
||||
signal-desktop.private = [ ".config/Signal" ];
|
||||
signal-desktop.persist.private = [ ".config/Signal" ];
|
||||
|
||||
# printer/filament settings
|
||||
slic3r.persist.plaintext = [ ".Slic3r" ];
|
||||
|
||||
# creds, widevine .so download. TODO: could easily manage these statically.
|
||||
spotify.dir = [ ".config/spotify" ];
|
||||
spotify.persist.plaintext = [ ".config/spotify" ];
|
||||
|
||||
# sublime music persists any downloaded albums here.
|
||||
# it doesn't obey a conventional ~/Music/{Artist}/{Album}/{Track} notation, so no symlinking
|
||||
# config (e.g. server connection details) is persisted in ~/.config/sublime-music/config.json
|
||||
# possible to pass config as a CLI arg (sublime-music -c config.json)
|
||||
# { pkg = sublime-music; dir = [ ".local/share/sublime-music" ]; }
|
||||
sublime-music-mobile.dir = [ ".local/share/sublime-music" ];
|
||||
steam.persist.plaintext = [
|
||||
".steam"
|
||||
".local/share/Steam"
|
||||
];
|
||||
|
||||
tdesktop.private = [ ".local/share/TelegramDesktop" ];
|
||||
tdesktop.persist.private = [ ".local/share/TelegramDesktop" ];
|
||||
|
||||
tokodon.private = [ ".cache/KDE/tokodon" ];
|
||||
tokodon.persist.private = [ ".cache/KDE/tokodon" ];
|
||||
|
||||
# hardenedMalloc solves a crash at startup
|
||||
# TODO 2023/02/02: is this safe to remove yet?
|
||||
@@ -368,17 +401,24 @@ in
|
||||
useHardenedMalloc = false;
|
||||
};
|
||||
|
||||
# vlc remembers play position in ~/.config/vlc/vlc-qt-interface.conf
|
||||
vlc.dir = [ ".config/vlc" ];
|
||||
whalebird.persist.private = [ ".config/Whalebird" ];
|
||||
|
||||
whalebird.private = [ ".config/Whalebird" ];
|
||||
yarn.persist.plaintext = [ ".cache/yarn" ];
|
||||
|
||||
# zcash coins. safe to delete, just slow to regenerate (10-60 minutes)
|
||||
zecwallet-lite.private = [ ".zcash" ];
|
||||
zecwallet-lite.persist.private = [ ".zcash" ];
|
||||
}
|
||||
];
|
||||
|
||||
# XXX: this might not be necessary. try removing this and cacert.unbundled (servo)?
|
||||
environment.etc."ssl/certs".source = "${pkgs.cacert.unbundled}/etc/ssl/certs/*";
|
||||
|
||||
# steam requires system-level config for e.g. firewall or controller support
|
||||
programs.steam = mkIf config.sane.programs.steam.enabled {
|
||||
enable = true;
|
||||
# not sure if needed: stole this whole snippet from the wiki
|
||||
remotePlay.openFirewall = true; # Open ports in the firewall for Steam Remote Play
|
||||
dedicatedServer.openFirewall = true; # Open ports in the firewall for Source Dedicated Server
|
||||
};
|
||||
};
|
||||
}
|
@@ -4,7 +4,7 @@ let
|
||||
mkCfg = lib.generators.toINI { };
|
||||
in
|
||||
{
|
||||
sane.user.fs.".config/git/config" = sane-lib.fs.wantedText (mkCfg {
|
||||
sane.programs.git.fs.".config/git/config" = sane-lib.fs.wantedText (mkCfg {
|
||||
user.name = "Colin";
|
||||
user.email = "colin@uninsane.org";
|
||||
alias.co = "checkout";
|
@@ -6,7 +6,7 @@ let
|
||||
all-feeds = config.sane.feeds;
|
||||
wanted-feeds = feeds.filterByFormat ["text" "image"] all-feeds;
|
||||
in {
|
||||
sane.user.fs.".config/org.gabmus.gfeeds.json" = sane-lib.fs.wantedText (
|
||||
sane.programs.gnome-feeds.fs.".config/org.gabmus.gfeeds.json" = sane-lib.fs.wantedText (
|
||||
builtins.toJSON {
|
||||
# feed format is a map from URL to a dict,
|
||||
# with dict["tags"] a list of string tags.
|
@@ -6,7 +6,7 @@ let
|
||||
all-feeds = config.sane.feeds;
|
||||
wanted-feeds = feeds.filterByFormat ["podcast"] all-feeds;
|
||||
in {
|
||||
sane.user.fs.".config/gpodderFeeds.opml" = sane-lib.fs.wantedText (
|
||||
sane.programs.gpodder.fs.".config/gpodderFeeds.opml" = sane-lib.fs.wantedText (
|
||||
feeds.feedsToOpml wanted-feeds
|
||||
);
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
{ pkgs, sane-lib, ... }:
|
||||
|
||||
{
|
||||
sane.user.fs.".config/kitty/kitty.conf" = sane-lib.fs.wantedText ''
|
||||
sane.programs.kitty.fs.".config/kitty/kitty.conf" = sane-lib.fs.wantedText ''
|
||||
# docs: https://sw.kovidgoyal.net/kitty/conf/
|
||||
# disable terminal bell (when e.g. you backspace too many times)
|
||||
enable_audio_bell no
|
@@ -2,7 +2,7 @@
|
||||
|
||||
{
|
||||
# libreoffice: disable first-run stuff
|
||||
sane.user.fs.".config/libreoffice/4/user/registrymodifications.xcu" = sane-lib.fs.wantedText ''
|
||||
sane.programs.libreoffice-fresh.fs.".config/libreoffice/4/user/registrymodifications.xcu" = sane-lib.fs.wantedText ''
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<oor:items xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<item oor:path="/org.openoffice.Office.Common/Misc"><prop oor:name="FirstRun" oor:op="fuse"><value>false</value></prop></item>
|
13
hosts/common/programs/mpv.nix
Normal file
13
hosts/common/programs/mpv.nix
Normal file
@@ -0,0 +1,13 @@
|
||||
{ sane-lib, ... }:
|
||||
|
||||
{
|
||||
sane.programs.mpv = {
|
||||
persist.plaintext = [ ".config/mpv/watch_later" ];
|
||||
# format is <key>=%<length>%<value>
|
||||
fs.".config/mpv/mpv.conf" = sane-lib.fs.wantedText ''
|
||||
save-position-on-quit=%3%yes
|
||||
keep-open=%3%yes
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
{ lib, pkgs, ... }:
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (builtins) map;
|
||||
inherit (lib) concatMapStrings optionalString;
|
||||
inherit (lib) concatMapStrings mkIf optionalString;
|
||||
# this structure roughly mirrors home-manager's `programs.neovim.plugins` option
|
||||
plugins = with pkgs.vimPlugins; [
|
||||
# docs: surround-nvim: https://github.com/ur4ltz/surround.nvim/
|
||||
@@ -72,9 +72,9 @@ let
|
||||
in
|
||||
{
|
||||
# private because there could be sensitive things in the swap
|
||||
sane.user.persist.private = [ ".cache/vim-swap" ];
|
||||
sane.programs.neovim.persist.private = [ ".cache/vim-swap" ];
|
||||
|
||||
programs.neovim = {
|
||||
programs.neovim = mkIf config.sane.programs.neovim.enabled {
|
||||
# neovim: https://github.com/neovim/neovim
|
||||
enable = true;
|
||||
viAlias = true;
|
15
hosts/common/programs/newsflash.nix
Normal file
15
hosts/common/programs/newsflash.nix
Normal file
@@ -0,0 +1,15 @@
|
||||
# news-flash RSS viewer
|
||||
{ config, sane-lib, ... }:
|
||||
|
||||
let
|
||||
feeds = sane-lib.feeds;
|
||||
all-feeds = config.sane.feeds;
|
||||
wanted-feeds = feeds.filterByFormat ["text" "image"] all-feeds;
|
||||
in {
|
||||
sane.programs.newsflash = {
|
||||
persist.plaintext = [ ".local/share/news-flash" ];
|
||||
fs.".config/newsflashFeeds.opml" = sane-lib.fs.wantedText (
|
||||
feeds.feedsToOpml wanted-feeds
|
||||
);
|
||||
};
|
||||
}
|
12
hosts/common/programs/offlineimap.nix
Normal file
12
hosts/common/programs/offlineimap.nix
Normal file
@@ -0,0 +1,12 @@
|
||||
# mail archiving/synchronization tool.
|
||||
#
|
||||
# manually download all emails for an account with
|
||||
# - `offlineimap -a <accountname>`
|
||||
#
|
||||
# view account names inside the secrets file, listed below.
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
sane.programs.offlineimap.secrets.".config/offlineimap/config" = ../../../secrets/universal/offlineimaprc.bin;
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
# .ignore file is read by ripgrep (rg), silver searcher (ag), maybe others.
|
||||
# ignore translation files by default when searching, as they tend to have
|
||||
# a LOT of duplicate text.
|
||||
sane.user.fs.".ignore" = sane-lib.fs.wantedText ''
|
||||
sane.programs.ripgrep.fs.".ignore" = sane-lib.fs.wantedText ''
|
||||
po/
|
||||
'';
|
||||
}
|
22
hosts/common/programs/splatmoji.nix
Normal file
22
hosts/common/programs/splatmoji.nix
Normal file
@@ -0,0 +1,22 @@
|
||||
# borrows from:
|
||||
# - default config: <https://github.com/cspeterson/splatmoji/blob/master/splatmoji.config>
|
||||
# - wayland: <https://github.com/cspeterson/splatmoji/issues/32#issuecomment-830862566>
|
||||
{ pkgs, sane-lib, ... }:
|
||||
|
||||
{
|
||||
sane.programs.splatmoji = {
|
||||
persist.plaintext = [ ".local/state/splatmoji" ];
|
||||
fs.".config/splatmoji/splatmoji.config" = sane-lib.fs.wantedText ''
|
||||
# XXX doesn't seem to understand ~ as shorthand for `$HOME`
|
||||
history_file=/home/colin/.local/state/splatmoji/history
|
||||
history_length=5
|
||||
# TODO: wayland equiv
|
||||
paste_command=xdotool key ctrl+v
|
||||
# rofi_command=${pkgs.wofi}/bin/wofi --dmenu --insensitive --cache-file /dev/null
|
||||
rofi_command=${pkgs.fuzzel}/bin/fuzzel -d -i -w 60
|
||||
xdotool_command=${pkgs.wtype}/bin/wtype
|
||||
# TODO: wayland equiv
|
||||
xsel_command=xsel -b -i
|
||||
'';
|
||||
};
|
||||
}
|
14
hosts/common/programs/sublime-music.nix
Normal file
14
hosts/common/programs/sublime-music.nix
Normal file
@@ -0,0 +1,14 @@
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
sane.programs.sublime-music = {
|
||||
package = pkgs.sublime-music-mobile;
|
||||
# sublime music persists any downloaded albums here.
|
||||
# it doesn't obey a conventional ~/Music/{Artist}/{Album}/{Track} notation, so no symlinking
|
||||
# config (e.g. server connection details) is persisted in ~/.config/sublime-music/config.json
|
||||
# possible to pass config as a CLI arg (sublime-music -c config.json)
|
||||
persist.plaintext = [ ".local/share/sublime-music" ];
|
||||
|
||||
secrets.".config/sublime-music/config.json" = ../../../secrets/universal/sublime_music_config.json.bin;
|
||||
};
|
||||
}
|
24
hosts/common/programs/vlc.nix
Normal file
24
hosts/common/programs/vlc.nix
Normal file
@@ -0,0 +1,24 @@
|
||||
{ config, lib, sane-lib, ... }:
|
||||
|
||||
let
|
||||
feeds = sane-lib.feeds;
|
||||
all-feeds = config.sane.feeds;
|
||||
wanted-feeds = feeds.filterByFormat ["podcast"] all-feeds;
|
||||
podcast-urls = lib.concatStringsSep "|" (
|
||||
builtins.map (feed: feed.url) wanted-feeds
|
||||
);
|
||||
in
|
||||
{
|
||||
sane.programs.vlc = {
|
||||
# vlc remembers play position in ~/.config/vlc/vlc-qt-interface.conf
|
||||
persist.plaintext = [ ".config/vlc" ];
|
||||
fs.".config/vlc/vlcrc" = sane-lib.fs.wantedText ''
|
||||
[podcast]
|
||||
podcast-urls=${podcast-urls}
|
||||
[core]
|
||||
metadata-network-access=0
|
||||
[qt]
|
||||
qt-privacy-ask=0
|
||||
'';
|
||||
};
|
||||
}
|
@@ -29,8 +29,8 @@ let
|
||||
cacheDir = ".cache/mozilla";
|
||||
desktop = "firefox.desktop";
|
||||
};
|
||||
defaultSettings = firefoxSettings;
|
||||
# defaultSettings = librewolfSettings;
|
||||
# defaultSettings = firefoxSettings;
|
||||
defaultSettings = librewolfSettings;
|
||||
|
||||
addon = name: extid: hash: pkgs.fetchFirefoxAddon {
|
||||
inherit name hash;
|
||||
@@ -146,58 +146,61 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
sane.programs.web-browser = {
|
||||
inherit package;
|
||||
# TODO: define the persistence & fs config here
|
||||
};
|
||||
sane.programs.guiApps.suggestedPrograms = [ "web-browser" ];
|
||||
config = mkMerge [
|
||||
({
|
||||
sane.programs.guiApps.suggestedPrograms = [ "web-browser" ];
|
||||
sane.programs.web-browser = {
|
||||
inherit package;
|
||||
|
||||
# uBlock filter list configuration.
|
||||
# specifically, enable the GDPR cookie prompt blocker.
|
||||
# data.toOverwrite.filterLists is additive (i.e. it supplements the default filters)
|
||||
# this configuration method is documented here:
|
||||
# - <https://github.com/gorhill/uBlock/issues/2986#issuecomment-364035002>
|
||||
# the specific attribute path is found via scraping ublock code here:
|
||||
# - <https://github.com/gorhill/uBlock/blob/master/src/js/storage.js>
|
||||
# - <https://github.com/gorhill/uBlock/blob/master/assets/assets.json>
|
||||
sane.user.fs."${cfg.browser.dotDir}/managed-storage/uBlock0@raymondhill.net.json" = sane-lib.fs.wantedText ''
|
||||
{
|
||||
"name": "uBlock0@raymondhill.net",
|
||||
"description": "ignored",
|
||||
"type": "storage",
|
||||
"data": {
|
||||
"toOverwrite": "{\"filterLists\": [\"fanboy-cookiemonster\"]}"
|
||||
}
|
||||
}
|
||||
'';
|
||||
sane.user.fs."${cfg.browser.dotDir}/${cfg.browser.libName}.overrides.cfg" = sane-lib.fs.wantedText ''
|
||||
// if we can't query the revocation status of a SSL cert because the issuer is offline,
|
||||
// treat it as unrevoked.
|
||||
// see: <https://librewolf.net/docs/faq/#im-getting-sec_error_ocsp_server_error-what-can-i-do>
|
||||
defaultPref("security.OCSP.require", false);
|
||||
'';
|
||||
# flush the cache to disk to avoid it taking up too much tmp
|
||||
sane.user.persist.byPath."${cfg.browser.cacheDir}" = lib.mkIf (cfg.persistCache != null) {
|
||||
store = cfg.persistCache;
|
||||
};
|
||||
# uBlock filter list configuration.
|
||||
# specifically, enable the GDPR cookie prompt blocker.
|
||||
# data.toOverwrite.filterLists is additive (i.e. it supplements the default filters)
|
||||
# this configuration method is documented here:
|
||||
# - <https://github.com/gorhill/uBlock/issues/2986#issuecomment-364035002>
|
||||
# the specific attribute path is found via scraping ublock code here:
|
||||
# - <https://github.com/gorhill/uBlock/blob/master/src/js/storage.js>
|
||||
# - <https://github.com/gorhill/uBlock/blob/master/assets/assets.json>
|
||||
fs."${cfg.browser.dotDir}/managed-storage/uBlock0@raymondhill.net.json" = sane-lib.fs.wantedText ''
|
||||
{
|
||||
"name": "uBlock0@raymondhill.net",
|
||||
"description": "ignored",
|
||||
"type": "storage",
|
||||
"data": {
|
||||
"toOverwrite": "{\"filterLists\": [\"fanboy-cookiemonster\"]}"
|
||||
}
|
||||
}
|
||||
'';
|
||||
fs."${cfg.browser.dotDir}/${cfg.browser.libName}.overrides.cfg" = sane-lib.fs.wantedText ''
|
||||
// if we can't query the revocation status of a SSL cert because the issuer is offline,
|
||||
// treat it as unrevoked.
|
||||
// see: <https://librewolf.net/docs/faq/#im-getting-sec_error_ocsp_server_error-what-can-i-do>
|
||||
defaultPref("security.OCSP.require", false);
|
||||
'';
|
||||
fs."${cfg.browser.dotDir}/default" = sane-lib.fs.wantedDir;
|
||||
# instruct Firefox to put the profile in a predictable directory (so we can do things like persist just it).
|
||||
# XXX: the directory *must* exist, even if empty; Firefox will not create the directory itself.
|
||||
fs."${cfg.browser.dotDir}/profiles.ini" = sane-lib.fs.wantedText ''
|
||||
[Profile0]
|
||||
Name=default
|
||||
IsRelative=1
|
||||
Path=default
|
||||
Default=1
|
||||
|
||||
sane.user.persist.byPath."${cfg.browser.dotDir}/default" = lib.mkIf (cfg.persistData != null) {
|
||||
store = cfg.persistData;
|
||||
};
|
||||
sane.user.fs."${cfg.browser.dotDir}/default" = sane-lib.fs.wantedDir;
|
||||
# instruct Firefox to put the profile in a predictable directory (so we can do things like persist just it).
|
||||
# XXX: the directory *must* exist, even if empty; Firefox will not create the directory itself.
|
||||
sane.user.fs."${cfg.browser.dotDir}/profiles.ini" = sane-lib.fs.wantedText ''
|
||||
[Profile0]
|
||||
Name=default
|
||||
IsRelative=1
|
||||
Path=default
|
||||
Default=1
|
||||
[General]
|
||||
StartWithLastProfile=1
|
||||
'';
|
||||
};
|
||||
})
|
||||
(mkIf config.sane.programs.web-browser.enabled {
|
||||
# TODO: move the persistence into the sane.programs API (above)
|
||||
# flush the cache to disk to avoid it taking up too much tmp
|
||||
sane.user.persist.byPath."${cfg.browser.cacheDir}" = lib.mkIf (cfg.persistCache != null) {
|
||||
store = cfg.persistCache;
|
||||
};
|
||||
|
||||
[General]
|
||||
StartWithLastProfile=1
|
||||
'';
|
||||
|
||||
};
|
||||
sane.user.persist.byPath."${cfg.browser.dotDir}/default" = lib.mkIf (cfg.persistData != null) {
|
||||
store = cfg.persistData;
|
||||
};
|
||||
})
|
||||
];
|
||||
}
|
16
hosts/common/programs/zeal.nix
Normal file
16
hosts/common/programs/zeal.nix
Normal file
@@ -0,0 +1,16 @@
|
||||
{ config, lib, sane-lib, ... }:
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
in {
|
||||
sane.programs.zeal-qt5 = {
|
||||
persist.plaintext = [
|
||||
".cache/Zeal"
|
||||
".local/share/Zeal"
|
||||
];
|
||||
fs.".local/share/Zeal/Zeal/system" = sane-lib.fs.wantedSymlinkTo "/run/current-system/sw/share/docset";
|
||||
};
|
||||
|
||||
environment.pathsToLink = mkIf config.sane.programs.zeal-qt5.enabled [
|
||||
"/share/docset"
|
||||
];
|
||||
}
|
166
hosts/common/programs/zsh/default.nix
Normal file
166
hosts/common/programs/zsh/default.nix
Normal file
@@ -0,0 +1,166 @@
|
||||
{ config, lib, pkgs, sane-lib, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf mkMerge mkOption types;
|
||||
cfg = config.sane.zsh;
|
||||
# powerlevel10k prompt config
|
||||
# p10k.zsh is the auto-generated config, and i overwrite those defaults here, below.
|
||||
p10k-overrides = ''
|
||||
# powerlevel10k launches a gitstatusd daemon to accelerate git prompt queries.
|
||||
# this keeps open file handles for any git repo i touch for 60 minutes (by default).
|
||||
# that prevents unmounting whatever device the git repo is on -- particularly problematic for ~/private.
|
||||
# i can disable gitstatusd and get slower fallback git queries:
|
||||
# - either universally
|
||||
# - or selectively by path
|
||||
# see: <https://github.com/romkatv/powerlevel10k/issues/246>
|
||||
typeset -g POWERLEVEL9K_VCS_DISABLED_DIR_PATTERN='(/home/colin/private/*|/home/colin/knowledge/*)'
|
||||
# typeset -g POWERLEVEL9K_DISABLE_GITSTATUS=true
|
||||
|
||||
# show user@host also when logged into the current machine.
|
||||
# default behavior is to show it only over ssh.
|
||||
typeset -g POWERLEVEL9K_CONTEXT_{DEFAULT,SUDO}_CONTENT_EXPANSION='$P9K_CONTENT'
|
||||
'';
|
||||
|
||||
prezto-init = ''
|
||||
source ${pkgs.zsh-autosuggestions}/share/zsh-autosuggestions/zsh-autosuggestions.zsh
|
||||
source ${pkgs.zsh-syntax-highlighting}/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
|
||||
source ${pkgs.zsh-prezto}/share/zsh-prezto/init.zsh
|
||||
'';
|
||||
in
|
||||
{
|
||||
options = {
|
||||
sane.zsh = {
|
||||
showDeadlines = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "show upcoming deadlines (frommy PKM) upon shell init";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkMerge [
|
||||
({
|
||||
sane.programs.zsh = {
|
||||
persist.plaintext = [
|
||||
# we don't need to full zsh dir -- just the history file --
|
||||
# but zsh will sometimes backup the history file and we get fewer errors if we do proper mounts instead of symlinks.
|
||||
# TODO: should be private?
|
||||
".local/share/zsh"
|
||||
# cache gitstatus otherwise p10k fetched it from the net EVERY BOOT
|
||||
".cache/gitstatus"
|
||||
];
|
||||
|
||||
# zsh/prezto complains if zshrc doesn't exist; but it does allow an "empty" file.
|
||||
fs.".config/zsh/.zshrc" = sane-lib.fs.wantedText "# ";
|
||||
|
||||
# prezto = oh-my-zsh fork; controls prompt, auto-completion, etc.
|
||||
# see: https://github.com/sorin-ionescu/prezto
|
||||
# i believe this file is auto-sourced by the prezto init.zsh script.
|
||||
fs.".config/zsh/.zpreztorc" = sane-lib.fs.wantedText ''
|
||||
zstyle ':prezto:*:*' color 'yes'
|
||||
|
||||
# modules (they ship with prezto):
|
||||
# ENVIRONMENT: configures jobs to persist after shell exit; other basic niceties
|
||||
# TERMINAL: auto-titles terminal (e.g. based on cwd)
|
||||
# EDITOR: configures shortcuts like Ctrl+U=undo, Ctrl+L=clear
|
||||
# HISTORY: `history-stat` alias, setopts for good history defaults
|
||||
# DIRECTORY: sets AUTO_CD, adds `d` alias to list directory stack, and `1`-`9` to cd that far back the stack
|
||||
# SPECTRUM: helpers for term colors and styling. used by prompts? might be unnecessary
|
||||
# UTILITY: configures aliases like `ll`, `la`, disables globbing for things like rsync
|
||||
# adds aliases like `get` to fetch a file. also adds `http-serve` alias??
|
||||
# COMPLETION: tab completion. requires `utility` module prior to loading
|
||||
# TODO: enable AUTO_PARAM_SLASH
|
||||
zstyle ':prezto:load' pmodule \
|
||||
'environment' \
|
||||
'terminal' \
|
||||
'editor' \
|
||||
'history' \
|
||||
'directory' \
|
||||
'spectrum' \
|
||||
'utility' \
|
||||
'completion' \
|
||||
'prompt'
|
||||
|
||||
# default keymap. try also `vicmd` (vim normal mode, AKA "cmd mode") or `vi`.
|
||||
zstyle ':prezto:module:editor' key-bindings 'emacs'
|
||||
|
||||
zstyle ':prezto:module:prompt' theme 'powerlevel10k'
|
||||
|
||||
# disable `mv` confirmation (and `rm`, too, unfortunately)
|
||||
zstyle ':prezto:module:utility' safe-ops 'no'
|
||||
'';
|
||||
};
|
||||
})
|
||||
(mkIf config.sane.programs.zsh.enabled {
|
||||
# enable zsh completions
|
||||
environment.pathsToLink = [ "/share/zsh" ];
|
||||
|
||||
programs.zsh = {
|
||||
enable = true;
|
||||
histFile = "$HOME/.local/share/zsh/history";
|
||||
shellAliases = {
|
||||
":q" = "exit";
|
||||
# common typos
|
||||
"cd.." = "cd ..";
|
||||
"cd../" = "cd ../";
|
||||
};
|
||||
setOptions = [
|
||||
# defaults:
|
||||
"HIST_IGNORE_DUPS"
|
||||
"SHARE_HISTORY"
|
||||
"HIST_FCNTL_LOCK"
|
||||
# disable `rm *` confirmations
|
||||
"rmstarsilent"
|
||||
];
|
||||
|
||||
# .zshenv config:
|
||||
shellInit = ''
|
||||
ZDOTDIR=$HOME/.config/zsh
|
||||
'';
|
||||
|
||||
# .zshrc config:
|
||||
interactiveShellInit =
|
||||
(builtins.readFile ./p10k.zsh)
|
||||
+ p10k-overrides
|
||||
+ prezto-init
|
||||
+ ''
|
||||
# zmv is a way to do rich moves/renames, with pattern matching/substitution.
|
||||
# see for an example: <https://filipe.kiss.ink/zmv-zsh-rename/>
|
||||
autoload -Uz zmv
|
||||
|
||||
HISTORY_IGNORE='(sane-shutdown *|sane-reboot *|rm *|nixos-rebuild.* switch)'
|
||||
|
||||
# extra aliases
|
||||
# TODO: move to `shellAliases` config?
|
||||
function nd() {
|
||||
mkdir -p "$1";
|
||||
pushd "$1";
|
||||
}
|
||||
''
|
||||
+ lib.optionalString cfg.showDeadlines ''
|
||||
${pkgs.sane-scripts}/bin/sane-deadlines
|
||||
''
|
||||
+ ''
|
||||
# auto-cd into any of these dirs by typing them and pressing 'enter':
|
||||
hash -d 3rd="/home/colin/dev/3rd"
|
||||
hash -d dev="/home/colin/dev"
|
||||
hash -d knowledge="/home/colin/knowledge"
|
||||
hash -d nixos="/home/colin/nixos"
|
||||
hash -d nixpkgs="/home/colin/dev/3rd/nixpkgs"
|
||||
hash -d ref="/home/colin/ref"
|
||||
hash -d secrets="/home/colin/knowledge/secrets"
|
||||
hash -d tmp="/home/colin/tmp"
|
||||
hash -d uninsane="/home/colin/dev/uninsane"
|
||||
hash -d Videos="/home/colin/Videos"
|
||||
'';
|
||||
|
||||
syntaxHighlighting.enable = true;
|
||||
vteIntegration = true;
|
||||
};
|
||||
|
||||
# enable a command-not-found hook to show nix packages that might provide the binary typed.
|
||||
programs.nix-index.enable = true;
|
||||
programs.command-not-found.enable = false; #< mutually exclusive with nix-index
|
||||
})
|
||||
];
|
||||
}
|
@@ -52,6 +52,11 @@
|
||||
sopsFile = ../../secrets/universal.yaml;
|
||||
owner = config.users.users.colin.name;
|
||||
};
|
||||
sops.secrets."mx-sanebot-env" = {
|
||||
sopsFile = ../../secrets/universal/mx-sanebot-env.bin;
|
||||
format = "binary";
|
||||
owner = config.users.users.colin.name;
|
||||
};
|
||||
sops.secrets."router_passwd" = {
|
||||
sopsFile = ../../secrets/universal.yaml;
|
||||
};
|
||||
|
@@ -101,6 +101,7 @@ in
|
||||
sane.user.fs."Videos/servo" = fs.wantedSymlinkTo "/mnt/servo-media/Videos";
|
||||
sane.user.fs."Videos/servo-incomplete" = fs.wantedSymlinkTo "/mnt/servo-media/incomplete";
|
||||
sane.user.fs."Music/servo" = fs.wantedSymlinkTo "/mnt/servo-media/Music";
|
||||
sane.user.fs."Pictures/servo-macros" = fs.wantedSymlinkTo "/mnt/servo-media/Pictures/macros";
|
||||
|
||||
# used by password managers, e.g. unix `pass`
|
||||
sane.user.fs.".password-store" = fs.wantedSymlinkTo "knowledge/secrets/accounts";
|
||||
|
@@ -126,6 +126,7 @@ in
|
||||
package = null;
|
||||
suggestedPrograms = [
|
||||
"guiApps"
|
||||
"splatmoji" # used by us, but 'enabling' it gets us persistence & cfg
|
||||
"swaylock"
|
||||
"swayidle"
|
||||
"wl-clipboard"
|
||||
|
36
integrations/nur/default.nix
Normal file
36
integrations/nur/default.nix
Normal file
@@ -0,0 +1,36 @@
|
||||
# Nix User Repository (NUR)
|
||||
# - <https://github.com/nix-community/NUR>
|
||||
#
|
||||
# this file is not reachable from the top-level of my nixos configs (i.e. toplevel flake.nix)
|
||||
# nor is it intended for anyone who wants to reference my config directly
|
||||
# (consider the toplevel flake.nix outputs instead).
|
||||
#
|
||||
# rather, this is the entrypoint through which NUR finds my packages, modules, overlays.
|
||||
# it's reachable only from those using this repo via NUR.
|
||||
#
|
||||
# to manually query available packages, modules, etc, try:
|
||||
# - nix eval --impure --expr 'builtins.attrNames (import ./. {})'
|
||||
#
|
||||
# to validate this before a push that would propagate to 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=$(nix-instantiate --find-file nixpkgs) \
|
||||
# -I ../../
|
||||
# ^ source: <https://github.com/nix-community/nur-packages-template/blob/master/.github/workflows/build.yml#L63>
|
||||
# N.B.: nur eval allows only PATH (inherited) and NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM="1" (forced),
|
||||
# hence the erasing of NIX_PATH above (to remove external overlays)
|
||||
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
let
|
||||
sanePkgs = import ../../pkgs { inherit pkgs; };
|
||||
in
|
||||
({
|
||||
overlays.pkgs = import ../../overlays/pkgs.nix;
|
||||
pkgs = sanePkgs;
|
||||
|
||||
modules = import ../../modules { inherit (pkgs) lib; };
|
||||
lib = import ../../modules/lib { inherit (pkgs) lib; };
|
||||
} // sanePkgs)
|
21
modules/data/feeds/sources/blog.jmp.chat/default.json
Normal file
21
modules/data/feeds/sources/blog.jmp.chat/default.json
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"bozo": 0,
|
||||
"content_length": 83424,
|
||||
"content_type": "application/rss+xml; charset=utf-8",
|
||||
"description": "Community News For All of Seattle's Capitol Hill",
|
||||
"favicon": "https://www.capitolhillseattle.com/favicon.ico",
|
||||
"favicon_data_uri": "data:image/png;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////39/f/h4eH/vb29/729vf/i4uL//f39/////////////////////////////////////////////f39/6+vr/81NTX/AgIC/wAAAP8AAAD/AgIC/zU1Nf+wsLD//f39////////////////////////////+vr6/2pqav8BAQH/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AQEB/2xsbP/6+vr//////////////////v7+/7u7u/9VVVX/VVVV/1VVVf9VVVX/VVVV/1VVVf9VVVX/VVVV/1VVVf9VVVX/vb29//7+/v/+/v7//////87Ozv8eHh7/HBwc/xwcHP8cHBz/t7e3/z8/P/+VlZX/WVlZ/xwcHP8cHBz/HBwc/x4eHv/Q0ND//v7+//7+/v9hYWH/AAAA/yUlJf/Dw8P/4ODg//n5+f/29vb//Pz8/+Li4v9MTEz/AAAA/wAAAP8AAAD/ZGRk///////7+/v/MTEx/xUVFf8WFhb/jY2N//7+/v/+/v7//v7+//7+/v/+/v7/+vr6/2FhYf8VFRX/FRUV/zMzM//8/Pz/7+/v/xgYGP8TExP/ExMT/xMTE/+2trb//v7+//7+/v/+/v7//v7+//7+/v/z8/P/JiYm/xMTE/8ZGRn/8PDw/+zs7P8EBAT/AAAA/wAAAP8AAAD/NjY2//39/f/+/v7//v7+//7+/v/+/v7//v7+/zk5Of8AAAD/BgYG/+3t7f/5+fn/FhYW/wAAAP8AAAD/AAAA/wICAv/T09P//v7+//7+/v/+/v7//v7+//7+/v9BQUH/AAAA/xcXF//5+fn//v7+/1FRUf8AAAD/AAAA/wAAAP8AAAD/RUVF//Pz8//+/v7//v7+//7+/v/+/v7/Li4u/wAAAP9UVFT///////////+7u7v/AQEB/wAAAP8AAAD/AAAA/wAAAP8fHx//vLy8//7+/v/+/v7/8/Pz/xEREf8BAQH/vb29/////////////f39/1hYWP8AAAD/AAAA/wAAAP8AAAD/GBgY/15eXv+Li4v/39/f/2tra/8AAAD/W1tb//7+/v/////////////////x8fH/Q0ND/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wMDA/8AAAD/RUVF//Ly8v////////////////////////////b29v+EhIT/EhIS/wAAAP8AAAD/AAAA/wAAAP8TExP/hYWF//f39/////////////////////////////////////////////Ly8v+2trb/kJCQ/5CQkP+3t7f/8/Pz////////////////////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
|
||||
"hubs": [],
|
||||
"is_podcast": false,
|
||||
"is_push": false,
|
||||
"item_count": 5,
|
||||
"last_updated": "2023-04-02T02:03:11+00:00",
|
||||
"score": 13,
|
||||
"self_url": "https://www.capitolhillseattle.com/feed/",
|
||||
"site_name": "CHS Capitol Hill Seattle News",
|
||||
"site_url": "https://www.capitolhillseattle.com",
|
||||
"title": "CHS Capitol Hill Seattle News",
|
||||
"url": "https://www.capitolhillseattle.com/feed/",
|
||||
"velocity": 1.6,
|
||||
"version": "rss20"
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
{ lib, utils, ... }:
|
||||
{ lib, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
@@ -15,7 +15,7 @@
|
||||
];
|
||||
|
||||
_module.args = {
|
||||
sane-lib = import ./lib { inherit lib utils; };
|
||||
sane-lib = import ./lib { inherit lib; };
|
||||
sane-data = import ./data { inherit lib; };
|
||||
};
|
||||
}
|
||||
|
@@ -1,12 +1,12 @@
|
||||
{ lib, ... }@moduleArgs:
|
||||
{ lib, ... }:
|
||||
|
||||
let
|
||||
sane-lib = rec {
|
||||
feeds = import ./feeds.nix moduleArgs;
|
||||
fs = import ./fs.nix moduleArgs;
|
||||
merge = import ./merge.nix ({ inherit sane-lib; } // moduleArgs);
|
||||
path = import ./path.nix moduleArgs;
|
||||
types = import ./types.nix moduleArgs;
|
||||
feeds = import ./feeds.nix { inherit lib; };
|
||||
fs = import ./fs.nix { inherit lib; };
|
||||
merge = import ./merge.nix { inherit lib sane-lib; };
|
||||
path = import ./path.nix { inherit lib; };
|
||||
types = import ./types.nix { inherit lib; };
|
||||
|
||||
# re-exports
|
||||
inherit (merge) mkTypedMerge;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
{ lib, utils, ... }:
|
||||
{ lib, ... }:
|
||||
|
||||
let path = rec {
|
||||
|
||||
|
@@ -1,11 +1,13 @@
|
||||
{ config, lib, pkgs, sane-lib, ... }:
|
||||
{ config, lib, options, pkgs, sane-lib, ... }:
|
||||
let
|
||||
inherit (builtins) any elem map;
|
||||
inherit (builtins) any attrValues elem map;
|
||||
inherit (lib)
|
||||
concatMapAttrs
|
||||
filterAttrs
|
||||
hasAttrByPath
|
||||
getAttrFromPath
|
||||
mapAttrs
|
||||
mapAttrs'
|
||||
mapAttrsToList
|
||||
mkDefault
|
||||
mkIf
|
||||
@@ -18,7 +20,7 @@ let
|
||||
;
|
||||
inherit (sane-lib) joinAttrsets;
|
||||
cfg = config.sane.programs;
|
||||
pkgSpec = types.submodule ({ name, ... }: {
|
||||
pkgSpec = types.submodule ({ config, name, ... }: {
|
||||
options = {
|
||||
package = mkOption {
|
||||
type = types.nullOr types.package;
|
||||
@@ -59,6 +61,12 @@ let
|
||||
place this program on the PATH for some specified user(s).
|
||||
'';
|
||||
};
|
||||
enabled = mkOption {
|
||||
type = types.bool;
|
||||
description = ''
|
||||
generated (i.e. read-only) value indicating if the program is enabled either for any user or for the system.
|
||||
'';
|
||||
};
|
||||
suggestedPrograms = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
@@ -71,18 +79,36 @@ let
|
||||
type = types.bool;
|
||||
default = true;
|
||||
};
|
||||
dir = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "list of home-relative paths to persist for this package";
|
||||
persist = {
|
||||
plaintext = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "list of home-relative paths to persist for this package";
|
||||
};
|
||||
private = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "list of home-relative paths to persist (in encrypted format) for this package";
|
||||
};
|
||||
};
|
||||
private = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "list of home-relative paths to persist (in encrypted format) for this package";
|
||||
fs = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
description = "files to populate when this program is enabled";
|
||||
};
|
||||
secrets = mkOption {
|
||||
type = types.attrsOf types.path;
|
||||
default = {};
|
||||
description = ''
|
||||
fs paths to link to some decrypted secret.
|
||||
the secret will have same owner as the user under which the program is enabled.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
enabled = config.enableFor.system || any (en: en) (attrValues config.enableFor.user);
|
||||
};
|
||||
});
|
||||
toPkgSpec = types.coercedTo types.package (p: { package = p; }) pkgSpec;
|
||||
|
||||
@@ -96,15 +122,45 @@ let
|
||||
environment.systemPackages = optional
|
||||
(p.package != null && p.enableFor.system)
|
||||
p.package;
|
||||
|
||||
# conditionally add to user(s) PATH
|
||||
users.users = mapAttrs (user: en: {
|
||||
packages = optional (p.package != null && en) p.package;
|
||||
}) p.enableFor.user;
|
||||
# conditionally persist relevant user dirs
|
||||
|
||||
# conditionally persist relevant user dirs and create files
|
||||
sane.users = mapAttrs (user: en: optionalAttrs en {
|
||||
persist.plaintext = p.dir;
|
||||
persist.private = p.private;
|
||||
inherit (p) persist;
|
||||
fs = mkMerge [
|
||||
p.fs
|
||||
(mapAttrs
|
||||
# link every secret into the fs
|
||||
# TODO: user the user's *actual* home directory, don't guess.
|
||||
(homePath: _src: sane-lib.fs.wantedSymlinkTo "/run/secrets/home/${user}/${homePath}")
|
||||
p.secrets
|
||||
)
|
||||
];
|
||||
}) p.enableFor.user;
|
||||
|
||||
# make secrets available for each user
|
||||
sops.secrets = concatMapAttrs
|
||||
(user: en: optionalAttrs en (
|
||||
mapAttrs'
|
||||
(homePath: src: {
|
||||
# TODO: user the user's *actual* home directory, don't guess.
|
||||
# XXX: name CAN'T START WITH '/', else sops creates the directories funny.
|
||||
# TODO: report this upstream.
|
||||
name = "home/${user}/${homePath}";
|
||||
value = {
|
||||
owner = user;
|
||||
sopsFile = src;
|
||||
format = "binary";
|
||||
};
|
||||
})
|
||||
p.secrets
|
||||
))
|
||||
p.enableFor.user;
|
||||
|
||||
}) cfg;
|
||||
in
|
||||
{
|
||||
@@ -122,6 +178,7 @@ in
|
||||
environment.systemPackages = f.environment.systemPackages;
|
||||
users.users = f.users.users;
|
||||
sane.users = f.sane.users;
|
||||
sops.secrets = f.sops.secrets;
|
||||
};
|
||||
in mkMerge [
|
||||
(take (sane-lib.mkTypedMerge take configs))
|
||||
|
@@ -2,6 +2,39 @@
|
||||
|
||||
with lib;
|
||||
let
|
||||
# TODO: upstream these "optional-dependencies"
|
||||
# - search that phrase in <nixpkgs:doc/languages-frameworks/python.section.md>
|
||||
pkg = pkgs.mautrix-signal.overridePythonAttrs (super: {
|
||||
propagatedBuildInputs = super.propagatedBuildInputs ++ (with pkgs.python3.pkgs; [
|
||||
# these optional deps come from mautrix-signal's "optional-requirements.txt"
|
||||
|
||||
# #/e2be
|
||||
# python-olm>=3,<4
|
||||
# pycryptodome>=3,<4
|
||||
# unpaddedbase64>=1,<3
|
||||
# XXX: ^above already included in nixpkgs package
|
||||
|
||||
# #/metrics
|
||||
# prometheus_client>=0.6,<0.17
|
||||
# XXX: ^above already included in nixpkgs package
|
||||
|
||||
# #/formattednumbers
|
||||
# phonenumbers>=8,<9
|
||||
# XXX: ^above already included in nixpkgs package
|
||||
|
||||
# #/qrlink
|
||||
# qrcode>=6,<8
|
||||
# Pillow>=4,<10
|
||||
# XXX: ^above already included in nixpkgs package
|
||||
|
||||
# #/stickers
|
||||
# signalstickers-client>=3,<4
|
||||
|
||||
# #/sqlite
|
||||
# aiosqlite>=0.16,<0.19
|
||||
aiosqlite
|
||||
]);
|
||||
});
|
||||
dataDir = "/var/lib/mautrix-signal";
|
||||
registrationFile = "${dataDir}/signal-registration.yaml";
|
||||
cfg = config.services.mautrix-signal;
|
||||
@@ -136,10 +169,10 @@ in
|
||||
preStart = ''
|
||||
# generate the appservice's registration file if absent
|
||||
if [ ! -f '${registrationFile}' ]; then
|
||||
${pkgs.mautrix-signal}/bin/mautrix-signal \
|
||||
${pkg}/bin/mautrix-signal \
|
||||
--generate-registration \
|
||||
--no-update \
|
||||
--base-config='${pkgs.mautrix-signal}/${pkgs.mautrix-signal.pythonModule.sitePackages}/mautrix_signal/example-config.yaml' \
|
||||
--base-config='${pkg}/${pkg.pythonModule.sitePackages}/mautrix_signal/example-config.yaml' \
|
||||
--config='${settingsFile}' \
|
||||
--registration='${registrationFile}'
|
||||
fi
|
||||
@@ -158,13 +191,13 @@ in
|
||||
ProtectControlGroups = true;
|
||||
|
||||
PrivateTmp = true;
|
||||
WorkingDirectory = pkgs.mautrix-signal;
|
||||
WorkingDirectory = pkg;
|
||||
StateDirectory = baseNameOf dataDir;
|
||||
UMask = "0027";
|
||||
EnvironmentFile = cfg.environmentFile;
|
||||
|
||||
ExecStart = ''
|
||||
${pkgs.mautrix-signal}/bin/mautrix-signal \
|
||||
${pkg}/bin/mautrix-signal \
|
||||
--config='${settingsFile}' \
|
||||
--no-update
|
||||
'';
|
||||
|
@@ -19,16 +19,3 @@ index e71b0a7613d..72779ac57a5 100644
|
||||
];
|
||||
|
||||
NIX_LDFLAGS = toString (lib.optionals stdenv.isDarwin [
|
||||
diff --git a/pkgs/development/libraries/qt-6/qtModule.nix b/pkgs/development/libraries/qt-6/qtModule.nix
|
||||
index 28180d3b0ca..f14c73b10ee 100644
|
||||
--- a/pkgs/development/libraries/qt-6/qtModule.nix
|
||||
+++ b/pkgs/development/libraries/qt-6/qtModule.nix
|
||||
@@ -61,7 +61,7 @@ stdenv.mkDerivation (args // {
|
||||
if [[ -z "$dontSyncQt" && -f sync.profile ]]; then
|
||||
# FIXME: this probably breaks crosscompiling as it's not from nativeBuildInputs
|
||||
# I don't know how to get /libexec from nativeBuildInputs to work, it's not under /bin
|
||||
- ${lib.getDev self.qtbase}/libexec/syncqt.pl -version "''${version%%-*}"
|
||||
+ perl ${lib.getDev self.qtbase}/libexec/syncqt.pl -version "''${version%%-*}"
|
||||
fi
|
||||
'';
|
||||
|
||||
|
@@ -1,178 +0,0 @@
|
||||
diff --git a/pkgs/development/libraries/sparrow3d/default.nix b/pkgs/development/libraries/sparrow3d/default.nix
|
||||
new file mode 100644
|
||||
index 00000000000..331a02efc5f
|
||||
--- /dev/null
|
||||
+++ b/pkgs/development/libraries/sparrow3d/default.nix
|
||||
@@ -0,0 +1,53 @@
|
||||
+{ lib
|
||||
+, fetchFromGitHub
|
||||
+, pkg-config
|
||||
+, SDL
|
||||
+, SDL_image
|
||||
+, SDL_mixer
|
||||
+, SDL_net
|
||||
+, SDL_ttf
|
||||
+, stdenv
|
||||
+}:
|
||||
+
|
||||
+stdenv.mkDerivation (finalAttrs: {
|
||||
+ pname = "sparrow3d";
|
||||
+ version = "2020-10-06";
|
||||
+
|
||||
+ src = fetchFromGitHub {
|
||||
+ owner = "theZiz";
|
||||
+ repo = "sparrow3d";
|
||||
+ rev = "2033349d7adeba34bda2c442e1fec22377471134";
|
||||
+ hash = "sha256-28j5nbTYBrMN8BQ6XrTlO1D8Viw+RiT3MAl99BAbhR4=";
|
||||
+ };
|
||||
+
|
||||
+ nativeBuildInputs = [
|
||||
+ pkg-config
|
||||
+ ];
|
||||
+
|
||||
+ propagatedBuildInputs = [
|
||||
+ SDL.dev
|
||||
+ SDL_image
|
||||
+ SDL_ttf
|
||||
+ SDL_mixer
|
||||
+ SDL_net
|
||||
+ ];
|
||||
+
|
||||
+ postConfigure = ''
|
||||
+ NIX_CFLAGS_COMPILE=$(pkg-config --cflags SDL_image SDL_ttf SDL_mixer SDL_net)
|
||||
+ '';
|
||||
+
|
||||
+ installPhase = ''
|
||||
+ mkdir -p $out/{include,lib/pkgconfig}
|
||||
+ cp sparrow*.h $out/include
|
||||
+ cp libsparrow{3d,Net,Sound}.so $out/lib
|
||||
+ substituteAll ${./sparrow3d.pc.in} $out/lib/pkgconfig/sparrow3d.pc
|
||||
+ '';
|
||||
+
|
||||
+ meta = with lib; {
|
||||
+ description = "a software renderer for different open handhelds like the gp2x, wiz, caanoo and pandora";
|
||||
+ homepage = "https://github.com/theZiz/sparrow3d";
|
||||
+ license = licenses.lgpl21;
|
||||
+ maintainers = with maintainers; [ colinsane ];
|
||||
+ platforms = [ "x86_64-linux" ];
|
||||
+ };
|
||||
+})
|
||||
diff --git a/pkgs/development/libraries/sparrow3d/sparrow3d.pc.in b/pkgs/development/libraries/sparrow3d/sparrow3d.pc.in
|
||||
new file mode 100644
|
||||
index 00000000000..046e174ea97
|
||||
--- /dev/null
|
||||
+++ b/pkgs/development/libraries/sparrow3d/sparrow3d.pc.in
|
||||
@@ -0,0 +1,17 @@
|
||||
+prefix=@out@
|
||||
+includedir=${prefix}/include
|
||||
+libdir=${prefix}/lib
|
||||
+
|
||||
+Name: sparrow3d
|
||||
+Description: a software renderer for different open handhelds like the gp2x, wiz, caanoo and pandora
|
||||
+URL: https://github.com/theZiz/sparrow3d
|
||||
+Version: @version@
|
||||
+Requires: \
|
||||
+ sdl \
|
||||
+ SDL_image \
|
||||
+ SDL_ttf \
|
||||
+ SDL_mixer \
|
||||
+ SDL_net
|
||||
+Cflags: -isystem${includedir}
|
||||
+Libs: -L${libdir} -lsparrow3d -lsparrowNet -lsparrowSound
|
||||
+
|
||||
diff --git a/pkgs/games/hase/default.nix b/pkgs/games/hase/default.nix
|
||||
new file mode 100644
|
||||
index 00000000000..794b6d017ae
|
||||
--- /dev/null
|
||||
+++ b/pkgs/games/hase/default.nix
|
||||
@@ -0,0 +1,49 @@
|
||||
+{ lib
|
||||
+, fetchFromGitHub
|
||||
+, pkg-config
|
||||
+, stdenv
|
||||
+, sparrow3d
|
||||
+, zlib
|
||||
+}:
|
||||
+
|
||||
+stdenv.mkDerivation {
|
||||
+ pname = "hase";
|
||||
+ version = "2020-10-06";
|
||||
+
|
||||
+ src = fetchFromGitHub {
|
||||
+ owner = "theZiz";
|
||||
+ repo = "hase";
|
||||
+ rev = "31d6840cdf0c72fc459f10402dae7726096b2974";
|
||||
+ hash = "sha256-d9So3E8nCQJ1/BdlwMkGbaFPT9mkX1VzlDGKp71ptEE=";
|
||||
+ };
|
||||
+ patches = [ ./prefer-dynamic.patch ];
|
||||
+
|
||||
+ nativeBuildInputs = [
|
||||
+ pkg-config
|
||||
+ ];
|
||||
+
|
||||
+ buildInputs = [
|
||||
+ sparrow3d
|
||||
+ zlib
|
||||
+ ];
|
||||
+
|
||||
+ buildPhase = ''
|
||||
+ NIX_CFLAGS_COMPILE=$(pkg-config --cflags sparrow3d zlib)
|
||||
+ mkdir -p $out/{bin,share/applications,share/pixmaps}
|
||||
+ # build and install are one step, and inseparable without patching
|
||||
+ ./install.sh $out
|
||||
+ '';
|
||||
+
|
||||
+ postFixup = ''
|
||||
+ substituteInPlace "$out/share/applications/hase.desktop" \
|
||||
+ --replace "Exec=hase" "Exec=$out/bin/hase"
|
||||
+ '';
|
||||
+
|
||||
+ meta = with lib; {
|
||||
+ description = "Hase is an open source gravity based artillery shooter. It is similar to Worms, Hedgewars or artillery, but the gravity force and direction depends on the mass nearby. It is optimized for mobile game consoles like the GP2X, Open Pandora or GCW Zero";
|
||||
+ homepage = "http://ziz.gp2x.de/hase/";
|
||||
+ license = licenses.gpl3;
|
||||
+ maintainers = with maintainers; [ colinsane ];
|
||||
+ platforms = [ "x86_64-linux" ];
|
||||
+ };
|
||||
+}
|
||||
diff --git a/pkgs/games/hase/prefer-dynamic.patch b/pkgs/games/hase/prefer-dynamic.patch
|
||||
new file mode 100644
|
||||
index 00000000000..ab36e6b2b3d
|
||||
--- /dev/null
|
||||
+++ b/pkgs/games/hase/prefer-dynamic.patch
|
||||
@@ -0,0 +1,13 @@
|
||||
+diff --git a/Makefile b/Makefile
|
||||
+index 95d894e..3c561c1 100644
|
||||
+--- a/Makefile
|
||||
++++ b/Makefile
|
||||
+@@ -35,7 +35,7 @@ endif
|
||||
+ LIB += -L$(SPARROW_LIB)
|
||||
+ INCLUDE += -I$(SPARROW_FOLDER)
|
||||
+
|
||||
+-HASE_STATIC = $(SPARROW_LIB)/$(SPARROW3D_STATIC_LIB) $(SPARROW_LIB)/$(SPARROWSOUND_STATIC_LIB) $(SPARROW_LIB)/$(SPARROWNET_STATIC_LIB) $(STATIC)
|
||||
++DYNAMIC += -lsparrow3d -lsparrowSound -lsparrowNet
|
||||
+
|
||||
+ ifneq ($(TARGET),win32)
|
||||
+ DYNAMIC += -lz
|
||||
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
|
||||
index 521b00eb5f5..31052251314 100644
|
||||
--- a/pkgs/top-level/all-packages.nix
|
||||
+++ b/pkgs/top-level/all-packages.nix
|
||||
@@ -23550,6 +23550,8 @@ with pkgs;
|
||||
|
||||
spaceship-prompt = callPackage ../shells/zsh/spaceship-prompt {};
|
||||
|
||||
+ sparrow3d = callPackage ../development/libraries/sparrow3d {};
|
||||
+
|
||||
spdk = callPackage ../development/libraries/spdk { };
|
||||
|
||||
speechd = callPackage ../development/libraries/speechd { };
|
||||
@@ -35570,6 +35572,8 @@ with pkgs;
|
||||
|
||||
harmonist = callPackage ../games/harmonist { };
|
||||
|
||||
+ hase = callPackage ../games/hase { };
|
||||
+
|
||||
hedgewars = libsForQt5.callPackage ../games/hedgewars {
|
||||
inherit (haskellPackages) ghcWithPackages;
|
||||
};
|
15
nixpatches/2023-04-29-lemmy.patch
Normal file
15
nixpatches/2023-04-29-lemmy.patch
Normal file
@@ -0,0 +1,15 @@
|
||||
diff --git a/pkgs/servers/web-apps/lemmy/pin.json b/pkgs/servers/web-apps/lemmy/pin.json
|
||||
index b2a1f1923ce..621b5945b6b 100644
|
||||
--- a/pkgs/servers/web-apps/lemmy/pin.json
|
||||
+++ b/pkgs/servers/web-apps/lemmy/pin.json
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
- "version": "0.17.2",
|
||||
- "serverSha256": "sha256-fkpMVm52XLyrk9RfzJpthT8fctIilawAIgfK+4TXHvU=",
|
||||
- "serverCargoSha256": "sha256-AC6EP612uaeGfqHbrHrz89h0tsNlMceEg6GxEsm1QMA=",
|
||||
+ "version": "88a0d2feec3f9b4a06f2d8d090894111afcbd9e2",
|
||||
+ "serverSha256": "sha256-jVa7SckpH21TG+i1yjJOkhEgjnZ0Zgk2IUP7sCdtv1Y=",
|
||||
+ "serverCargoSha256": "sha256-trp/TCGtAtZlKdZk2CaJ3E9Lj95cq797PLWUF/DD6/M=",
|
||||
"uiSha256": "sha256-0Zhm6Jgc6rlN4c7ryRnR45+fZEdzQhuOXSwU8Wz0D5g=",
|
||||
"uiYarnDepsSha256": "sha256-aZAclSaFZJvuK+FpCBWboGaVEOEJTxq2jnWk0A6iAFw="
|
||||
}
|
@@ -1,10 +1,4 @@
|
||||
{ fetchpatch, fetchurl }: [
|
||||
# librewolf: build with `MOZ_REQUIRE_SIGNING=false`
|
||||
(fetchpatch {
|
||||
url = "https://github.com/NixOS/nixpkgs/pull/199134.diff";
|
||||
# url = "https://git.uninsane.org/colin/nixpkgs/commit/99b82e07fee4d194520d6e8d51bc45c80a4d3c7e.diff";
|
||||
sha256 = "sha256-Ne4hyHQDwBHUlWo8Z3QyRdmEv1rYGOjFGxSfOAcLUvQ=";
|
||||
})
|
||||
|
||||
# splatmoji: init at 1.2.0
|
||||
(fetchpatch {
|
||||
@@ -38,16 +32,20 @@
|
||||
# TODO: why doesn't this apply?
|
||||
# ./2023-03-04-ccache-cross-fix.patch
|
||||
|
||||
# TODO: point to upstream PR
|
||||
./2023-03-10-hase.patch
|
||||
|
||||
# 2023-03-28: jellyfin-media-player: 1.8.1 -> 1.9.0
|
||||
# TODO: i should review/approve this PR if it works
|
||||
# 2023-04-11: bambu-studio: init at unstable-2023-01-11
|
||||
(fetchpatch {
|
||||
url = "https://github.com/NixOS/nixpkgs/pull/220974.diff";
|
||||
hash = "sha256-AK/l0vteCEg/ae4E0dS1oWnlLI4xyeyLFJcqMgCQ4RI=";
|
||||
url = "https://github.com/NixOS/nixpkgs/pull/206495.diff";
|
||||
hash = "sha256-RbQzAtFTr7Nrk2YBcHpKQMYoPlFMVSXNl96B/lkKluQ=";
|
||||
})
|
||||
|
||||
./2023-04-29-lemmy.patch
|
||||
|
||||
# 2023-04-20: perl: fix modules for compatibility with miniperl
|
||||
# (fetchpatch {
|
||||
# url = "https://github.com/NixOS/nixpkgs/pull/225640.diff";
|
||||
# hash = "sha256-MNG8C0OgdPnFQ8SF2loiEhXJuP2z4n9pkXr8Zh4X7QU=";
|
||||
# })
|
||||
|
||||
# # kaiteki: init at 2022-09-03
|
||||
# vendorHash changes too frequently (might not be reproducible).
|
||||
# using local package defn until stabilized
|
||||
|
@@ -5,12 +5,14 @@
|
||||
# - they assume too much about their environment and fail under qemu.
|
||||
#
|
||||
(next: prev: {
|
||||
# ell = prev.ell.overrideAttrs (_upstream: {
|
||||
# # 2023/02/11
|
||||
# # fixes "TEST FAILED in get_random_return_callback at unit/test-dbus-message-fds.c:278: !l_dbus_message_get_error(message, ((void *)0), ((void *)0))"
|
||||
# # unclear *why* this test fails.
|
||||
# doCheck = false;
|
||||
# });
|
||||
ell = prev.ell.overrideAttrs (_upstream: {
|
||||
# 2023/02/11
|
||||
# fixes "TEST FAILED in get_random_return_callback at unit/test-dbus-message-fds.c:278: !l_dbus_message_get_error(message, ((void *)0), ((void *)0))"
|
||||
# 2023/04/06
|
||||
# fixes "test-cipher: unit/test-cipher.c:102: test_aes_ctr: Assertion `!r' failed."
|
||||
# unclear *why* this test fails.
|
||||
doCheck = false;
|
||||
});
|
||||
# fish = prev.fish.overrideAttrs (_upstream: {
|
||||
# # 2023/02/28
|
||||
# # The following tests FAILED:
|
||||
|
@@ -18,4 +18,14 @@
|
||||
# chromium can take 4 hours to build from source, with no signs of progress.
|
||||
# disable it if you're in a rush.
|
||||
# chromium = next.emptyDirectory;
|
||||
|
||||
# lemmy-server = prev.lemmy-server.overrideAttrs (upstream: {
|
||||
# patches = upstream.patches or [] ++ [
|
||||
# (next.fetchpatch {
|
||||
# # "Fix docker federation setup (#2706)"
|
||||
# url = "https://github.com/LemmyNet/lemmy/commit/2891856b486ad9397bca1c9839255d73be66361.diff";
|
||||
# hash = "sha256-qgRvBO2y7pmOWdteu4uiZNi8hs0VazOV+L5Z0wu60/E=";
|
||||
# })
|
||||
# ];
|
||||
# });
|
||||
})
|
||||
|
@@ -1,60 +1,8 @@
|
||||
(next: prev:
|
||||
with next;
|
||||
let
|
||||
sane = rec {
|
||||
#### my own, non-upstreamable packages:
|
||||
static-nix-shell = callPackages ../pkgs/static-nix-shell { };
|
||||
sane-scripts = callPackage ../pkgs/sane-scripts { };
|
||||
feeds = recurseIntoAttrs (callPackage ../pkgs/feeds { });
|
||||
tow-boot-pinephone = callPackage ../pkgs/tow-boot-pinephone { };
|
||||
tow-boot-rpi4 = callPackage ../pkgs/tow-boot-rpi4 { };
|
||||
bootpart-uefi-x86_64 = callPackage ../pkgs/bootpart-uefi-x86_64 { };
|
||||
bootpart-tow-boot-rpi-aarch64 = callPackage ../pkgs/bootpart-tow-boot-rpi-aarch64 { };
|
||||
bootpart-u-boot-rpi-aarch64 = callPackage ../pkgs/bootpart-u-boot-rpi-aarch64 { };
|
||||
rtl8723cs-firmware = callPackage ../pkgs/rtl8723cs-firmware { };
|
||||
linux-megous = callPackage ../pkgs/linux-megous {
|
||||
kernelPatches = [
|
||||
prev.kernelPatches.bridge_stp_helper
|
||||
prev.kernelPatches.request_key_helper
|
||||
];
|
||||
};
|
||||
|
||||
sublime-music-mobile = callPackage ../pkgs/sublime-music-mobile { };
|
||||
|
||||
#### customized packages
|
||||
fluffychat-moby = callPackage ../pkgs/fluffychat-moby { };
|
||||
gpodder-configured = callPackage ../pkgs/gpodder-configured { };
|
||||
# jackett doesn't allow customization of the bind address: this will probably always be here.
|
||||
jackett = callPackage ../pkgs/jackett { inherit (prev) jackett; };
|
||||
# mozilla keeps nerfing itself and removing configuration options
|
||||
firefox-unwrapped = callPackage ../pkgs/firefox-unwrapped { inherit (prev) firefox-unwrapped; };
|
||||
|
||||
# patch rpi uboot with something that fixes USB HDD boot
|
||||
ubootRaspberryPi4_64bit = callPackage ../pkgs/ubootRaspberryPi4_64bit { };
|
||||
|
||||
gocryptfs = callPackage ../pkgs/gocryptfs { inherit (prev) gocryptfs; };
|
||||
|
||||
browserpass = callPackage ../pkgs/browserpass { inherit (prev) browserpass; };
|
||||
|
||||
fractal-latest = callPackage ../pkgs/fractal-latest { };
|
||||
|
||||
#### TEMPORARY: PACKAGES WAITING TO BE UPSTREAMED
|
||||
|
||||
pythonPackagesExtensions = prev.pythonPackagesExtensions ++ [
|
||||
(py-final: py-prev: {
|
||||
feedsearch-crawler = py-final.callPackage ../pkgs/feedsearch-crawler { };
|
||||
})
|
||||
];
|
||||
|
||||
kaiteki = callPackage ../pkgs/kaiteki { };
|
||||
lightdm-mobile-greeter = callPackage ../pkgs/lightdm-mobile-greeter { };
|
||||
browserpass-extension = callPackage ../pkgs/browserpass-extension { };
|
||||
gopass-native-messaging-host = callPackage ../pkgs/gopass-native-messaging-host { };
|
||||
tokodon = prev.libsForQt5.callPackage ../pkgs/tokodon { };
|
||||
|
||||
# provided by nixpkgs patch or upstream preview
|
||||
# splatmoji = callPackage ../pkgs/splatmoji { };
|
||||
};
|
||||
in sane // { inherit sane; }
|
||||
# expose all my packages into the root scope:
|
||||
# - `additional` packages
|
||||
# - `patched` versions of nixpkgs (which necessarily shadow their nixpkgs version)
|
||||
# - `pythonPackagesExtensions`
|
||||
import ../pkgs
|
||||
{ pkgs = next; lib = prev.lib; unpatched = prev; }
|
||||
)
|
||||
|
||||
|
30
pkgs/additional/cargo-docset/default.nix
Normal file
30
pkgs/additional/cargo-docset/default.nix
Normal file
@@ -0,0 +1,30 @@
|
||||
{ lib
|
||||
, fetchFromGitHub
|
||||
, rustPlatform
|
||||
, sqlite
|
||||
}:
|
||||
|
||||
rustPlatform.buildRustPackage rec {
|
||||
pname = "cargo-docset";
|
||||
version = "0.3.1";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "Robzz";
|
||||
repo = pname;
|
||||
rev = "v${version}";
|
||||
hash = "sha256-o2CSQiU9fEoS3eRmwphtYGZTwn3mstRm2Tlvval83+U=";
|
||||
};
|
||||
|
||||
cargoHash = "sha256-YHrSvfHfQ7kbVeCOgggYf3E7gHq+RhVKZrzP8LqX5I0=";
|
||||
|
||||
buildInputs = [
|
||||
sqlite
|
||||
];
|
||||
|
||||
meta = with lib; {
|
||||
description = "Cargo subcommand to generate a Dash/Zeal docset for your Rust packages. ";
|
||||
homepage = "https://github.com/Robzz/cargo-docset";
|
||||
license = licenses.asl20;
|
||||
maintainers = with maintainers; [ colinsane ];
|
||||
};
|
||||
}
|
@@ -1,15 +1,15 @@
|
||||
{ lib
|
||||
, callPackage
|
||||
, python3
|
||||
, sane-data
|
||||
, static-nix-shell
|
||||
, writeShellScript
|
||||
}:
|
||||
|
||||
let
|
||||
# TODO: dependency-inject this.
|
||||
sane-data = import ../../modules/data { inherit lib; };
|
||||
template = callPackage ./template.nix;
|
||||
feed-pkgs = lib.mapAttrs
|
||||
feed-pkgs' = lib.mapAttrs
|
||||
(name: feed-details: template {
|
||||
feedName = name;
|
||||
jsonPath = "modules/data/feeds/sources/${name}/default.json";
|
||||
@@ -18,9 +18,9 @@ let
|
||||
sane-data.feeds;
|
||||
update-scripts = lib.mapAttrsToList
|
||||
(name: feed: builtins.concatStringsSep " " feed.passthru.updateScript)
|
||||
feed-pkgs;
|
||||
feed-pkgs';
|
||||
in rec { # TODO: make this a scope
|
||||
inherit feed-pkgs;
|
||||
feed-pkgs = lib.recurseIntoAttrs feed-pkgs';
|
||||
update = static-nix-shell.mkPython3Bin {
|
||||
pname = "update";
|
||||
src = ./.;
|
||||
@@ -49,10 +49,9 @@ in rec { # TODO: make this a scope
|
||||
${update}/bin/update.py "$name" "$json_path"
|
||||
cat "$json_path"
|
||||
'';
|
||||
passthru = {
|
||||
updateScript = writeShellScript
|
||||
"feeds-update"
|
||||
(builtins.concatStringsSep "\n" update-scripts);
|
||||
initFeedScript = init-feed;
|
||||
};
|
||||
|
||||
updateScript = writeShellScript
|
||||
"feeds-update"
|
||||
(builtins.concatStringsSep "\n" update-scripts);
|
||||
initFeedScript = init-feed;
|
||||
}
|
@@ -3,26 +3,20 @@
|
||||
, gpodder
|
||||
, makeWrapper
|
||||
, python3
|
||||
, static-nix-shell
|
||||
, symlinkJoin
|
||||
}:
|
||||
|
||||
let
|
||||
pyEnv = python3.withPackages (_ps: [ gnome-feeds.listparser ]);
|
||||
remove-extra = stdenv.mkDerivation {
|
||||
remove-extra = static-nix-shell.mkPython3Bin {
|
||||
pname = "gpodder-remove-extra";
|
||||
version = "0.1.0";
|
||||
|
||||
src = ./.;
|
||||
|
||||
patchPhase = ''
|
||||
substituteInPlace ./remove_extra.py \
|
||||
--replace "#!/usr/bin/env nix-shell" "#!${pyEnv.interpreter}"
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin
|
||||
mv remove_extra.py $out/bin/gpodder-remove-extra
|
||||
'';
|
||||
pyPkgs = _ps: {
|
||||
"gnome-feeds.listparser" = gnome-feeds.listparser;
|
||||
};
|
||||
pkgs = {
|
||||
inherit gpodder;
|
||||
};
|
||||
};
|
||||
in
|
||||
# we use a symlinkJoin so that we can inherit the .desktop and icon files from the original gPodder
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i python3 -p "python3.withPackages (ps: [gnome-feeds.listparser])" -p gpodder
|
||||
#!nix-shell -i python3 -p "python3.withPackages (ps: [ gnome-feeds.listparser ])" -p gpodder
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
import listparser
|
@@ -33,7 +33,13 @@ rustPlatform.buildRustPackage rec {
|
||||
rev = "f3511ec71a4a1f491d759711e0bcf031e335ea70";
|
||||
hash = "sha256-U5chzm3q3vycgX1HSLf6sk6M3YoJ4CHGLKRg4ViIhu8=";
|
||||
};
|
||||
cargoHash = "sha256-2NMXR+D/CnDhUToQmMwK2Cb2l+4/N9BrCz/lt1NZ6Wk=";
|
||||
# cargoHash = "sha256-2NMXR+D/CnDhUToQmMwK2Cb2l+4/N9BrCz/lt1NZ6Wk=";
|
||||
cargoLock = {
|
||||
lockFile = "${src}/Cargo.lock";
|
||||
outputHashes = {
|
||||
"light-dm-sys-0.0.1" = "sha256-91MZhbO/Or0QOt0yVAUhtorpMBBzElFg6U59mF7WB0k=";
|
||||
};
|
||||
};
|
||||
|
||||
buildInputs = [
|
||||
gtk3
|
@@ -1,8 +1,18 @@
|
||||
{ lib, buildPackages, fetchFromGitHub, perl, buildLinux, nixosTests, modDirVersionArg ? null, ... } @ args:
|
||||
{ lib
|
||||
, buildLinux
|
||||
, buildPackages
|
||||
, fetchFromGitHub
|
||||
, kernelPatches
|
||||
, modDirVersionArg ? null
|
||||
, nixosTests
|
||||
, perl
|
||||
, ...
|
||||
} @ args:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
kernelPatches' = kernelPatches;
|
||||
base = "6.2.0";
|
||||
# set to empty if not a release candidate
|
||||
rc = "-rc5";
|
||||
@@ -15,6 +25,11 @@ in buildLinux (args // rec {
|
||||
# branchVersion needs to be x.y
|
||||
extraMeta.branch = versions.majorMinor version;
|
||||
|
||||
kernelPatches = [
|
||||
kernelPatches'.bridge_stp_helper
|
||||
kernelPatches'.request_key_helper
|
||||
];
|
||||
|
||||
src = fetchFromGitHub {
|
||||
# HOW TO UPDATE:
|
||||
# - `git fetch` from megous' github.
|
2872
pkgs/additional/mx-sanebot/Cargo.lock
generated
Normal file
2872
pkgs/additional/mx-sanebot/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
16
pkgs/additional/mx-sanebot/Cargo.toml
Normal file
16
pkgs/additional/mx-sanebot/Cargo.toml
Normal file
@@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "mx-sanebot"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
futures = "0.3"
|
||||
matrix-sdk = "0.6.2" # TODO: bump
|
||||
ruma = "*" # matrix-sdk dep
|
||||
ruma-client-api = "*" # ruma dep
|
||||
serde = "*"
|
||||
serde_json = "*"
|
||||
tokio = { version = "1.20.1", features = ["macros", "rt-multi-thread"] }
|
28
pkgs/additional/mx-sanebot/default.nix
Normal file
28
pkgs/additional/mx-sanebot/default.nix
Normal file
@@ -0,0 +1,28 @@
|
||||
{ lib
|
||||
, cargo-docset ? null
|
||||
, openssl
|
||||
, pkg-config
|
||||
, rustPlatform
|
||||
}:
|
||||
|
||||
# docs: <nixpkgs>/doc/languages-frameworks/rust.section.md
|
||||
rustPlatform.buildRustPackage {
|
||||
name = "mx-sanebot";
|
||||
src = ./.;
|
||||
cargoLock.lockFile = ./Cargo.lock;
|
||||
|
||||
nativeBuildInputs = [ pkg-config ] ++ lib.optional (cargo-docset != null) cargo-docset;
|
||||
buildInputs = [ openssl ];
|
||||
|
||||
postBuild = ''
|
||||
cargo-docset docset
|
||||
'';
|
||||
|
||||
postInstall = ''
|
||||
mkdir -p $out/share/docset
|
||||
cp -R target/docset/* $out/share/docset/
|
||||
'';
|
||||
|
||||
# enables debug builds, if we want: https://github.com/NixOS/nixpkgs/issues/60919.
|
||||
hardeningDisable = [ "fortify" ];
|
||||
}
|
60
pkgs/additional/mx-sanebot/flake.lock
generated
Normal file
60
pkgs/additional/mx-sanebot/flake.lock
generated
Normal file
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1681202837,
|
||||
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1682173319,
|
||||
"narHash": "sha256-tPhOpJJ+wrWIusvGgIB2+x6ILfDkEgQMX0BTtM5vd/4=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ee7ec1c71adc47d2e3c2d5eb0d6b8fbbd42a8d1c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixos-22.11",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
20
pkgs/additional/mx-sanebot/flake.nix
Normal file
20
pkgs/additional/mx-sanebot/flake.nix
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
description = "Sane matrix chatbot";
|
||||
inputs = {
|
||||
nixpkgs.url = "nixpkgs/nixos-22.11";
|
||||
flake-utils.url = github:numtide/flake-utils;
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils }:
|
||||
with flake-utils.lib; eachSystem allSystems (system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
};
|
||||
in rec {
|
||||
packages.mx-sanebot = pkgs.callPackage ./default.nix { };
|
||||
defaultPackage = packages.mx-sanebot;
|
||||
|
||||
devShells.default = import ./shell.nix { inherit pkgs; };
|
||||
});
|
||||
}
|
15
pkgs/additional/mx-sanebot/shell.nix
Normal file
15
pkgs/additional/mx-sanebot/shell.nix
Normal file
@@ -0,0 +1,15 @@
|
||||
{ pkgs ? import <nixpkgs> {
|
||||
overlays = [ (import ../../overlays/pkgs.nix) ]; }
|
||||
}:
|
||||
|
||||
let
|
||||
mx-sanebot = pkgs.callPackage ./. { };
|
||||
in
|
||||
pkgs.mkShell {
|
||||
nativeBuildInputs = mx-sanebot.buildInputs ++ mx-sanebot.nativeBuildInputs ++ [
|
||||
pkgs.cargo
|
||||
];
|
||||
|
||||
# Allow cargo to download crates.
|
||||
SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
|
||||
}
|
245
pkgs/additional/mx-sanebot/src/main.rs
Normal file
245
pkgs/additional/mx-sanebot/src/main.rs
Normal file
@@ -0,0 +1,245 @@
|
||||
mod msg_handler;
|
||||
mod parsing;
|
||||
|
||||
use std::env;
|
||||
|
||||
use futures::StreamExt as _;
|
||||
use matrix_sdk::{
|
||||
Client,
|
||||
config::SyncSettings,
|
||||
deserialized_responses::SyncResponse,
|
||||
};
|
||||
use ruma::{
|
||||
OwnedRoomId,
|
||||
OwnedUserId,
|
||||
events::{
|
||||
AnySyncMessageLikeEvent,
|
||||
AnySyncTimelineEvent,
|
||||
SyncMessageLikeEvent,
|
||||
room::message::{
|
||||
MessageType,
|
||||
RoomMessageEventContent,
|
||||
},
|
||||
},
|
||||
};
|
||||
use ruma_client_api::{
|
||||
filter::FilterDefinition,
|
||||
sync::sync_events::v3::Filter,
|
||||
};
|
||||
use tokio::time::{sleep, Duration};
|
||||
|
||||
use msg_handler::MessageHandler;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Runner {
|
||||
// this is actually a *handle* to the client (Arc).
|
||||
client: Client,
|
||||
}
|
||||
|
||||
/// this encodes the specific set of Matrix events i might ever care about.
|
||||
#[derive(Debug)]
|
||||
enum Event {
|
||||
/// i was invited to the given room
|
||||
Invitation(OwnedRoomId),
|
||||
/// i see a message in the given room, from the given user
|
||||
Message(OwnedRoomId, OwnedUserId, String),
|
||||
}
|
||||
|
||||
/// some action i might do, usually in response to an Event.
|
||||
#[derive(Debug)]
|
||||
enum Action {
|
||||
AcceptInvite(OwnedRoomId),
|
||||
SendMessage(OwnedRoomId, String /* text */, Option<String> /* html */),
|
||||
}
|
||||
|
||||
impl Runner {
|
||||
async fn login(
|
||||
homeserver: &str,
|
||||
username: &str,
|
||||
password: &str,
|
||||
) -> anyhow::Result<Self> {
|
||||
// TODO: look into caching the messages somewhere on disk (sled; indexeddb)
|
||||
let client = Client::builder()
|
||||
.homeserver_url(homeserver)
|
||||
.sled_store("/home/colin/mx-sanebot", None)?
|
||||
.build()
|
||||
.await?;
|
||||
println!("client built");
|
||||
client.login_username(&username, &password).initial_device_display_name("sanebot")
|
||||
.initial_device_display_name("sanebot")
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
println!("logged in as {username}");
|
||||
|
||||
Ok(Runner { client })
|
||||
}
|
||||
|
||||
async fn event_loop(&self) -> anyhow::Result<()> {
|
||||
// event types if i only care about monitoring invites
|
||||
let types_for_invites = [
|
||||
"m.room.member".to_owned(), // StrippedRoomMemberEvent
|
||||
];
|
||||
// event types i care about during normal operation
|
||||
let types_for_all = [
|
||||
"m.room.member".to_owned(), // StrippedRoomMemberEvent
|
||||
"m.room.message".to_owned(), // RoomMessageEvent
|
||||
];
|
||||
// always ignore messages from self
|
||||
let not_senders = [ self.client.user_id().unwrap().to_owned() ];
|
||||
|
||||
let build_sync_settings = |token| {
|
||||
let mut filter = FilterDefinition::default();
|
||||
filter.room.timeline.not_senders = ¬_senders;
|
||||
filter.room.timeline.types = Some(match token {
|
||||
None => &types_for_invites,
|
||||
Some(_) => &types_for_all,
|
||||
});
|
||||
let mut settings = SyncSettings::default().filter(
|
||||
Filter::FilterDefinition(filter)
|
||||
);
|
||||
if let Some(t) = token {
|
||||
settings = settings.token(t);
|
||||
}
|
||||
settings
|
||||
};
|
||||
|
||||
// initial sync during which i handle only room invites, but ignore any messages
|
||||
// from before now. this means i ignore messages from when i was offline, but in
|
||||
// doing so do not need to worry about double responses.
|
||||
let settings = build_sync_settings(None);
|
||||
let response = self.client.sync_once(settings).await.unwrap();
|
||||
let next_token = response.next_batch.clone();
|
||||
self.act_on_sync_response(response).await;
|
||||
println!("sync'd");
|
||||
|
||||
let settings = build_sync_settings(Some(next_token));
|
||||
let mut sync_stream = Box::pin(
|
||||
self.client.sync_stream(settings)
|
||||
.await
|
||||
);
|
||||
while let Some(Ok(response)) = sync_stream.next().await {
|
||||
// println!("handling sync responses");
|
||||
self.act_on_sync_response(response).await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_sync_response<'a>(&'a self, response: SyncResponse) -> impl Iterator<Item=Event> + 'a {
|
||||
let events_from_invited_rooms = response.rooms.invite
|
||||
.into_iter()
|
||||
.map(|(room_id, _room)| {
|
||||
self.parse_room_invite(room_id)
|
||||
});
|
||||
let events_from_joined_rooms = response.rooms.join
|
||||
.into_iter()
|
||||
.flat_map(move |(room_id, room)| {
|
||||
room.timeline.events.into_iter().flat_map(move |e| match e.event.deserialize() {
|
||||
Ok(event) => self.parse_timeline_event(room_id.clone(), event),
|
||||
Err(_) => None,
|
||||
})
|
||||
});
|
||||
events_from_invited_rooms.chain(events_from_joined_rooms)
|
||||
}
|
||||
|
||||
async fn act_on_sync_response(&self, response: SyncResponse) {
|
||||
for event in self.parse_sync_response(response) {
|
||||
self.act_on_event(event).await;
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_room_invite(&self, room_id: OwnedRoomId) -> Event {
|
||||
println!("Received invite {:?}", room_id);
|
||||
Event::Invitation(room_id)
|
||||
}
|
||||
|
||||
fn parse_timeline_event(&self, room_id: OwnedRoomId, event: AnySyncTimelineEvent) -> Option<Event> {
|
||||
println!("Considering timeline event {:?}", event);
|
||||
let sender = event.sender();
|
||||
// protect against a bad sync filter that would cause me to see my own events
|
||||
assert_ne!(Some(sender), self.client.user_id());
|
||||
|
||||
match event {
|
||||
AnySyncTimelineEvent::MessageLike(ref msg_like) => match msg_like {
|
||||
AnySyncMessageLikeEvent::RoomMessage(SyncMessageLikeEvent::Original(room_msg)) => match room_msg.content.msgtype {
|
||||
MessageType::Text(ref text_msg) => Some(
|
||||
Event::Message(room_id, sender.to_owned(), text_msg.body.clone())
|
||||
),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
async fn act_on_event(&self, event: Event) {
|
||||
self.perform_action(self.map_event_to_action(event)).await;
|
||||
}
|
||||
|
||||
fn map_event_to_action(&self, event: Event) -> Action {
|
||||
println!("processing event {event:?}");
|
||||
match event {
|
||||
Event::Invitation(room_id) => Action::AcceptInvite(room_id),
|
||||
Event::Message(room_id, _sender_id, body) => {
|
||||
let resp = MessageHandler.on_msg(&body);
|
||||
Action::SendMessage(room_id, resp.to_string(), resp.html())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn perform_action(&self, action: Action) {
|
||||
println!("performing action: {action:?}");
|
||||
match action {
|
||||
Action::AcceptInvite(room_id) => {
|
||||
// matrix example claims:
|
||||
// """
|
||||
// The event handlers are called before the next sync begins, but
|
||||
// methods that change the state of a room (joining, leaving a room)
|
||||
// wait for the sync to return the new room state so we need to spawn
|
||||
// a new task for them.
|
||||
// """
|
||||
let room = self.client.get_invited_room(&room_id).unwrap();
|
||||
tokio::spawn(async move {
|
||||
let mut delay = 2;
|
||||
|
||||
while let Err(err) = room.accept_invitation().await {
|
||||
// retry autojoin due to synapse sending invites, before the
|
||||
// invited user can join for more information see
|
||||
// https://github.com/matrix-org/synapse/issues/4345
|
||||
eprintln!("Failed to join room {} ({err:?}), retrying in {delay}s", room.room_id());
|
||||
|
||||
sleep(Duration::from_secs(delay)).await;
|
||||
delay *= 2;
|
||||
|
||||
if delay > 3600 {
|
||||
eprintln!("Can't join room {} ({err:?})", room.room_id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
println!("Successfully joined room {}", room.room_id());
|
||||
});
|
||||
}
|
||||
Action::SendMessage(room_id, text, html) => {
|
||||
|
||||
let room = self.client.get_joined_room(&room_id).unwrap();
|
||||
let resp_content = match html {
|
||||
None => RoomMessageEventContent::text_plain(&text),
|
||||
Some(html) => RoomMessageEventContent::text_html(&text, &html),
|
||||
};
|
||||
room.send(resp_content, None).await.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let password = env::var("SANEBOT_PASSWORD").unwrap_or("password".into());
|
||||
let runner = Runner::login("https://uninsane.org", "sanebot", &*password).await?;
|
||||
let result = runner.event_loop().await;
|
||||
println!("exiting");
|
||||
result
|
||||
}
|
308
pkgs/additional/mx-sanebot/src/msg_handler.rs
Normal file
308
pkgs/additional/mx-sanebot/src/msg_handler.rs
Normal file
@@ -0,0 +1,308 @@
|
||||
use std::borrow::ToOwned;
|
||||
use std::fmt;
|
||||
use std::process;
|
||||
use std::str;
|
||||
|
||||
use serde_json;
|
||||
use serde::Deserialize;
|
||||
|
||||
use super::parsing::{self, Parser};
|
||||
|
||||
|
||||
mod tt {
|
||||
pub(super) use super::parsing::{
|
||||
Either,
|
||||
Lit,
|
||||
Maybe,
|
||||
Nul,
|
||||
OneOrMore,
|
||||
Then,
|
||||
};
|
||||
use crate::{ilit, lit};
|
||||
|
||||
// grammar:
|
||||
// REQUEST = <!> (HELP | BT-REQ)
|
||||
//
|
||||
// HELP = <help>
|
||||
// BT-REQ = <bt> [(BT-SEARCH | BT-ADD)]
|
||||
//
|
||||
// BT-SEARCH = <search> ARGS
|
||||
// BT-ADD = <add> ARGS
|
||||
//
|
||||
// MAYBE_ARGS = [SPACE [ARGS]]
|
||||
// ARGS = ARG MAYBE_ARGS
|
||||
// ARG = NOT-SPACE [ARG]
|
||||
//
|
||||
// NOT-SPACE = (ALPHA | NUM | SPECIAL)
|
||||
pub(super) type Request = Then<Bang, Either<Help, BtReq>>;
|
||||
|
||||
pub(super) type Bang = Lit<{ '!' as u8 }>;
|
||||
pub(super) type Space = Lit<{ ' ' as u8 }>;
|
||||
pub(super) type Alpha = Either<
|
||||
ilit!('A'), Either<
|
||||
ilit!('B'), Either<
|
||||
ilit!('C'), Either<
|
||||
ilit!('D'), Either<
|
||||
ilit!('E'), Either<
|
||||
ilit!('F'), Either<
|
||||
ilit!('G'), Either<
|
||||
ilit!('H'), Either<
|
||||
ilit!('I'), Either<
|
||||
ilit!('J'), Either<
|
||||
ilit!('K'), Either<
|
||||
ilit!('L'), Either<
|
||||
ilit!('M'), Either<
|
||||
ilit!('N'), Either<
|
||||
ilit!('O'), Either<
|
||||
ilit!('P'), Either<
|
||||
ilit!('Q'), Either<
|
||||
ilit!('R'), Either<
|
||||
ilit!('S'), Either<
|
||||
ilit!('T'), Either<
|
||||
ilit!('U'), Either<
|
||||
ilit!('V'), Either<
|
||||
ilit!('W'), Either<
|
||||
ilit!('X'), Either<
|
||||
ilit!('Y'),
|
||||
ilit!('Z'),
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>;
|
||||
pub(super) type Dig = Either<
|
||||
lit!('0'), Either<
|
||||
lit!('1'), Either<
|
||||
lit!('2'), Either<
|
||||
lit!('3'), Either<
|
||||
lit!('4'), Either<
|
||||
lit!('5'), Either<
|
||||
lit!('6'), Either<
|
||||
lit!('7'), Either<
|
||||
lit!('8'),
|
||||
lit!('9'),
|
||||
>>>>>>>>>;
|
||||
pub(super) type Symbol = Either<
|
||||
Bang, Either<
|
||||
lit!('@'), Either<
|
||||
lit!('#'), Either<
|
||||
lit!('$'), Either<
|
||||
lit!('%'), Either<
|
||||
lit!('^'), Either<
|
||||
lit!('&'), Either<
|
||||
lit!('*'), Either<
|
||||
lit!('('), Either<
|
||||
lit!(')'), Either<
|
||||
lit!('-'), Either<
|
||||
lit!('_'), Either<
|
||||
lit!('+'), Either<
|
||||
lit!('='), Either<
|
||||
lit!('['), Either<
|
||||
lit!('{'), Either<
|
||||
lit!(']'), Either<
|
||||
lit!('}'), Either<
|
||||
lit!('\\'), Either<
|
||||
lit!('|'), Either<
|
||||
lit!(';'), Either<
|
||||
lit!(':'), Either<
|
||||
lit!('\''), Either<
|
||||
lit!('"'), Either<
|
||||
lit!(','), Either<
|
||||
lit!('<'), Either<
|
||||
lit!('.'), Either<
|
||||
lit!('>'), Either<
|
||||
lit!('/'), Either<
|
||||
lit!('?'), Either<
|
||||
lit!('`'),
|
||||
lit!('~'),
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>;
|
||||
// pub(super) type Whitespace = Then<Space, Maybe<Box<Whitespace>>>;
|
||||
pub(super) type Whitespace = OneOrMore<Space>;
|
||||
|
||||
pub(super) type Help = Then<
|
||||
ilit!('H'), Then<
|
||||
ilit!('E'), Then<
|
||||
ilit!('L'),
|
||||
ilit!('P'),
|
||||
>>>;
|
||||
|
||||
pub(super) type BtReq = Then<Bt, Maybe<Then<Whitespace, BtSearch>>>;
|
||||
|
||||
pub(super) type Bt = Then<
|
||||
ilit!('B'),
|
||||
ilit!('T'),
|
||||
>;
|
||||
|
||||
pub(super) type BtSearch = Then<Search, OneOrMore<SpacedArg>>;
|
||||
|
||||
pub(super) type Search = Then<
|
||||
ilit!('S'), Then<
|
||||
ilit!('E'), Then<
|
||||
ilit!('A'), Then<
|
||||
ilit!('R'), Then<
|
||||
ilit!('C'),
|
||||
ilit!('H'),
|
||||
>>>>>;
|
||||
|
||||
pub(super) type SpacedArg = Then<Whitespace, Arg>;
|
||||
pub(super) type Arg = OneOrMore<Either<
|
||||
Alpha, Either<
|
||||
Dig,
|
||||
Symbol
|
||||
>>>;
|
||||
}
|
||||
|
||||
pub struct MessageHandler;
|
||||
|
||||
impl MessageHandler {
|
||||
/// parse any message directed to me, and return text to present to the user who messaged me.
|
||||
/// the message passed here may or may not be a "valid" request.
|
||||
/// if invalid, expect an error message or help message, still meant for the user.
|
||||
pub fn on_msg(&self, msg: &str) -> Response {
|
||||
let req = self.parse_msg(msg).unwrap_or(Request::Help);
|
||||
req.evaluate()
|
||||
}
|
||||
|
||||
fn parse_msg(&self, msg: &str) -> Result<Request, ()> {
|
||||
match msg.as_bytes().parse_all::<tt::Request>() {
|
||||
Ok(req) => Ok(req.into()),
|
||||
Err(_) => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum Request {
|
||||
Help,
|
||||
Bt,
|
||||
BtSearch(String),
|
||||
}
|
||||
|
||||
impl From<tt::Request> for Request {
|
||||
fn from(t: tt::Request) -> Self {
|
||||
match t {
|
||||
tt::Then(_bang, tt::Either::A(_help)) => Self::Help,
|
||||
tt::Then(_bang, tt::Either::B(bt_req)) => match bt_req {
|
||||
tt::Then(_bt, tt::Either::A(tt::Then(_ws, bt_search))) => {
|
||||
let tt::Then(_, spaced_args) = bt_search;
|
||||
Self::BtSearch(spaced_args.to_string())
|
||||
},
|
||||
tt::Then(_bt, tt::Either::B(tt::Nul)) => Self::Bt,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn exec_stdout(program: &str, args: &[&str]) -> Option<String> {
|
||||
process::Command::new(program)
|
||||
.args(args)
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|output|
|
||||
str::from_utf8(&output.stdout).ok().map(ToOwned::to_owned)
|
||||
)
|
||||
}
|
||||
|
||||
impl Request {
|
||||
fn evaluate(self) -> Response {
|
||||
match self {
|
||||
Request::Help => Response::Help,
|
||||
Request::Bt => match exec_stdout("sane-bt-show", &[]) {
|
||||
Some(m) => Response::Bt(m),
|
||||
None => Response::Error("failed to execute sane-bt-show".to_owned()),
|
||||
},
|
||||
Request::BtSearch(phrase) => match exec_stdout("sane-bt-search", &[&*phrase, "--json"]) {
|
||||
Some(r) => match serde_json::from_str(&r) {
|
||||
Ok(torrents) => Response::BtSearch(torrents),
|
||||
Err(e) => Response::Error(format!("failed to decode sane-bt-search response: {e}")),
|
||||
},
|
||||
None => Response::Error("failed to execute sane-bt-search".to_owned()),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Torrent {
|
||||
seeders: u32,
|
||||
pub_date: String, // YYYY-MM-DD
|
||||
size: u64,
|
||||
tracker: String,
|
||||
title: String,
|
||||
magnet: String,
|
||||
}
|
||||
|
||||
pub enum Response {
|
||||
Error(String),
|
||||
Help,
|
||||
Bt(String),
|
||||
BtSearch(Vec<Torrent>),
|
||||
}
|
||||
|
||||
impl Response {
|
||||
pub fn html(&self) -> Option<String> {
|
||||
match self {
|
||||
Response::Help => Some(
|
||||
r#"
|
||||
commands:
|
||||
<ul>
|
||||
<li><code>!help</code> => show this message</li>
|
||||
<li><code>!bt</code> => show torrent statuses</li>
|
||||
<li><code>!bt search <phrase></code> => search for torrents</li>
|
||||
</ul>
|
||||
"#.to_owned()
|
||||
),
|
||||
Response::BtSearch(torrents) => Some({
|
||||
let fmt_torrents = torrents.into_iter().map(|t| {
|
||||
let Torrent {
|
||||
seeders,
|
||||
pub_date,
|
||||
size,
|
||||
tracker,
|
||||
title,
|
||||
magnet,
|
||||
} = t;
|
||||
let mib = size >> 20;
|
||||
format!(r#"
|
||||
<tr>
|
||||
<th>{seeders}</th>
|
||||
<th>{pub_date}</th>
|
||||
<th>{mib}</th>
|
||||
<th>{tracker}</th>
|
||||
<th>{title}</th>
|
||||
<th>{magnet}</th>
|
||||
</tr>
|
||||
"#)
|
||||
}).collect::<String>();
|
||||
format!(r#"
|
||||
<table>
|
||||
<tr>
|
||||
<th>Seeders</th>
|
||||
<th>Date</th>
|
||||
<th>Size (MiB)</th>
|
||||
<th>Tracker</th>
|
||||
<th>Title</th>
|
||||
<th>URL</th>
|
||||
</tr>
|
||||
{fmt_torrents}
|
||||
</table>
|
||||
"#)
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Response {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Response::Error(e) => write!(f, "{}", e)?,
|
||||
Response::Help => {
|
||||
write!(f, "commands:\n")?;
|
||||
write!(f, " !help => show this message\n")?;
|
||||
write!(f, " !bt => show torrent statuses\n")?;
|
||||
write!(f, " !bt search <phrase> => search for torrents\n")?;
|
||||
},
|
||||
Response::Bt(stdout) => write!(f, "{}", stdout)?,
|
||||
Response::BtSearch(torrents) => write!(f, "{} torrents", torrents.len())?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
183
pkgs/additional/mx-sanebot/src/parsing.rs
Normal file
183
pkgs/additional/mx-sanebot/src/parsing.rs
Normal file
@@ -0,0 +1,183 @@
|
||||
use std::fmt;
|
||||
|
||||
/// for internal use.
|
||||
/// parses only if the parser has no more bytes to yield.
|
||||
struct Eof;
|
||||
|
||||
/// literal byte (character).
|
||||
pub struct Lit<const BYTE: u8>;
|
||||
|
||||
/// parses without consuming any bytes from the parser.
|
||||
/// used to construct strictly optional constructs.
|
||||
pub struct Nul;
|
||||
|
||||
/// the two-item sequence of A followed by B.
|
||||
pub struct Then<A, B>(pub A, pub B);
|
||||
|
||||
/// if A parses, then A, else parse B.
|
||||
pub enum Either<A, B> {
|
||||
A(A),
|
||||
B(B),
|
||||
}
|
||||
|
||||
/// parse A if possible, but don't error if it isn't present.
|
||||
pub type Maybe<A> = Either<A, Nul>;
|
||||
|
||||
/// exists because Rust doesn't allow recursive type *aliases*.
|
||||
pub struct OneOrMore<A>(Then<
|
||||
A,
|
||||
Maybe<Box<OneOrMore<A>>>
|
||||
>);
|
||||
|
||||
// case-sensitive u8 character.
|
||||
#[macro_export]
|
||||
macro_rules! lit {
|
||||
($BYTE:literal) => {
|
||||
Lit<{ $BYTE as u8 }>
|
||||
}
|
||||
}
|
||||
|
||||
// case-insensitive u8 character.
|
||||
#[macro_export]
|
||||
macro_rules! ilit {
|
||||
($BYTE:literal) => {
|
||||
Either<Lit<{ ($BYTE as u8).to_ascii_lowercase() }>, Lit<{ ($BYTE as u8).to_ascii_uppercase() }>>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub type PResult<P, C> = std::result::Result<(C, P), P>;
|
||||
pub trait Parser: Sized {
|
||||
fn expect_byte(self, b: Option<u8>) -> PResult<Self, ()>;
|
||||
fn expect<C: Parse>(self) -> PResult<Self, C>;
|
||||
// {
|
||||
// // support backtracking; i.e. don't modify `self` on failed parse
|
||||
// match C::consume(self.clone()) {
|
||||
// Ok(res) => res,
|
||||
// Err(_) => self,
|
||||
// }
|
||||
// }
|
||||
fn parse_all<C: Parse>(self) -> Result<C, ()> {
|
||||
match self.expect::<Then<C, Eof>>() {
|
||||
Ok((Then(c, _eof), _p)) => Ok(c),
|
||||
Err(_p) => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Parser for &'a [u8] {
|
||||
fn expect_byte(self, b: Option<u8>) -> PResult<Self, ()> {
|
||||
match (b, self.split_first()) {
|
||||
// expected the correct character
|
||||
(Some(exp), Some((first, rest))) if *first == exp => Ok( ((), rest) ),
|
||||
// expected EOF, got EOF
|
||||
(None, None) => Ok( ((), self)),
|
||||
_ => Err(self),
|
||||
}
|
||||
}
|
||||
fn expect<C: Parse>(self) -> PResult<Self, C> {
|
||||
match C::consume(self.clone()) {
|
||||
Ok(res) => Ok(res),
|
||||
// rewind the parser should we fail
|
||||
Err(_p) => Err(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Parse: Sized {
|
||||
fn consume<P: Parser>(p: P) -> PResult<P, Self>;
|
||||
}
|
||||
|
||||
impl Parse for Eof {
|
||||
fn consume<P: Parser>(p: P) -> PResult<P, Self> {
|
||||
let (_, p) = p.expect_byte(None)?;
|
||||
Ok((Self, p))
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for Nul {
|
||||
fn consume<P: Parser>(p: P) -> PResult<P, Self> {
|
||||
Ok((Self, p))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Nul {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "")
|
||||
}
|
||||
}
|
||||
|
||||
impl<const BYTE: u8> Parse for Lit<BYTE> {
|
||||
fn consume<P: Parser>(p: P) -> PResult<P, Self> {
|
||||
let (_, p) = p.expect_byte(Some(BYTE))?;
|
||||
Ok((Self, p))
|
||||
}
|
||||
}
|
||||
|
||||
impl<const BYTE: u8> fmt::Display for Lit<BYTE> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", BYTE as char)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Parse, B: Parse> Parse for Then<A, B> {
|
||||
fn consume<P: Parser>(p: P) -> PResult<P, Self> {
|
||||
let (a, p) = p.expect()?;
|
||||
let (b, p) = p.expect()?;
|
||||
Ok((Self(a, b), p))
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: fmt::Display, B: fmt::Display> fmt::Display for Then<A, B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}{}", self.0, self.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Parse, B: Parse> Parse for Either<A, B> {
|
||||
fn consume<P: Parser>(p: P) -> PResult<P, Self> {
|
||||
let p = match p.expect() {
|
||||
Ok((a, p)) => { return Ok((Self::A(a), p)); },
|
||||
Err(p) => p,
|
||||
};
|
||||
let p = match p.expect() {
|
||||
Ok((b, p)) => { return Ok((Self::B(b), p)); },
|
||||
Err(p) => p,
|
||||
};
|
||||
Err(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: fmt::Display, B: fmt::Display> fmt::Display for Either<A, B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::A(a) => write!(f, "{}", a),
|
||||
Self::B(b) => write!(f, "{}", b),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Parse> Parse for Box<T> {
|
||||
fn consume<P: Parser>(p: P) -> PResult<P, Self> {
|
||||
match T::consume(p) {
|
||||
Ok((t, p)) => Ok((Box::new(t), p)),
|
||||
Err(p) => Err(p),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Parse> Parse for OneOrMore<T> {
|
||||
fn consume<P: Parser>(p: P) -> PResult<P, Self> {
|
||||
match p.expect() {
|
||||
Ok((t, p)) => Ok((Self(t), p)),
|
||||
Err(p) => Err(p),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Display> fmt::Display for OneOrMore<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
@@ -74,7 +74,7 @@ let
|
||||
# not sure if/where that lack of suid causes problems.
|
||||
umount = true;
|
||||
};
|
||||
prologue = "bin/sane-resholve-prologue";
|
||||
prologue = "${./resholve-prologue}";
|
||||
|
||||
# list of programs which *can* or *cannot* exec their arguments
|
||||
execer = with pkgs; [
|
||||
@@ -95,12 +95,11 @@ let
|
||||
};
|
||||
};
|
||||
|
||||
patchPhase = ''
|
||||
# remove python scripts (we package them further below)
|
||||
rm sane-bt-search
|
||||
rm sane-date-math
|
||||
rm sane-reclaim-boot-space
|
||||
'';
|
||||
# remove python scripts (we package them further below)
|
||||
patchPhase = builtins.concatStringsSep
|
||||
"\n"
|
||||
(lib.mapAttrsToList (name: pkg: "rm ${pkg.pname}") py-scripts)
|
||||
;
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin
|
||||
@@ -108,24 +107,29 @@ let
|
||||
'';
|
||||
};
|
||||
|
||||
bt-search = static-nix-shell.mkPython3Bin {
|
||||
pname = "sane-bt-search";
|
||||
src = ./src;
|
||||
pyPkgs = [ "natsort" "requests" ];
|
||||
py-scripts = {
|
||||
bt-search = static-nix-shell.mkPython3Bin {
|
||||
pname = "sane-bt-search";
|
||||
src = ./src;
|
||||
pyPkgs = [ "natsort" "requests" ];
|
||||
};
|
||||
date-math = static-nix-shell.mkPython3Bin {
|
||||
pname = "sane-date-math";
|
||||
src = ./src;
|
||||
};
|
||||
reclaim-boot-space = static-nix-shell.mkPython3Bin {
|
||||
pname = "sane-reclaim-boot-space";
|
||||
src = ./src;
|
||||
};
|
||||
ip-reconnect = static-nix-shell.mkPython3Bin {
|
||||
pname = "sane-ip-reconnect";
|
||||
src = ./src;
|
||||
};
|
||||
};
|
||||
date-math = static-nix-shell.mkPython3Bin {
|
||||
pname = "sane-date-math";
|
||||
src = ./src;
|
||||
};
|
||||
reclaim-boot-space = static-nix-shell.mkPython3Bin {
|
||||
pname = "sane-reclaim-boot-space";
|
||||
src = ./src;
|
||||
};
|
||||
|
||||
in
|
||||
symlinkJoin {
|
||||
name = "sane-scripts";
|
||||
paths = [ shell-scripts bt-search date-math reclaim-boot-space ];
|
||||
paths = [ shell-scripts ] ++ lib.attrValues py-scripts;
|
||||
meta = {
|
||||
description = "collection of scripts associated with uninsane systems";
|
||||
homepage = "https://git.uninsane.org";
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user