Compare commits

...

136 Commits

Author SHA1 Message Date
18ebfb9d9f fix feedsearch-crawler to build outside of overlay 2023-05-03 08:16:46 +00:00
a8584cf8dc linux-megous: fix eval error from aliased kernelPatches 2023-05-03 07:25:21 +00:00
57fcd33392 fix dangling reference to feeds.[passthru.]update 2023-05-03 06:48:38 +00:00
569a990488 fix so pythonPackagesExtensions takes effect when importing my packages w/o overlay 2023-05-03 06:47:41 +00:00
915f792b74 overlay: fix pythonPackagesExtension directive 2023-05-03 06:22:33 +00:00
897ba300b2 move pythonPackagesExtensions up to toplevel where it belongs 2023-05-03 06:13:18 +00:00
89f81da134 cleanup: move my packages to just one toplevel scope
having multiple scopes -- particularly near the toplevel -- was actually just a complication
2023-05-03 05:59:48 +00:00
1b76f1d643 cleanup: place packages into scopes
this helps for my own packages which depend on eachother: they should now evaluate without an overlay
2023-05-03 03:19:39 +00:00
9f21fbceda nur: better docs for my entrypoint 2023-05-03 00:56:23 +00:00
2450bb6f06 refactor package layout to conform better with NUR expectations 2023-05-02 01:27:51 +00:00
7d581f93cc uninsane-dot-org: 2023-04-20 -> 2023-04-30
notably, fix some on-site links

```
• Updated input 'uninsane-dot-org':
    'git+https://git.uninsane.org/colin/uninsane?ref=refs%2fheads%2fmaster&rev=3b9ce28b7a65d516eedddac67a224493399e5b1e' (2023-04-20)
  → 'git+https://git.uninsane.org/colin/uninsane?ref=refs%2fheads%2fmaster&rev=da209f34ce34eb6b8c4d2b3256a02eb23ad9f655' (2023-04-30)
```
2023-04-30 00:54:08 +00:00
96d113ffac lemmy: bump to git version in attempt to debug failed launch 2023-04-30 00:54:08 +00:00
b247c920f6 README: link to the projects i reference 2023-04-29 23:14:20 +00:00
dfa921035d README.md: cleanup 2023-04-29 23:01:37 +00:00
0c59f4e59c readme.md -> README.md 2023-04-29 22:08:50 +00:00
3dda51db7d mx-sanebot: fix formatting typos 2023-04-29 10:34:46 +00:00
b5a6a7a57c mx-sanebot: pretty-print torrent search results 2023-04-29 10:32:19 +00:00
f300cb1202 mx-sanebot: factor out a helper when invoking processes 2023-04-29 09:35:07 +00:00
10a100c961 mx-sanebot: format the help message in html 2023-04-29 09:18:05 +00:00
25d2234c69 sane-bt-search: add --json flag to control output format 2023-04-29 08:59:06 +00:00
fa5bc18721 mx-sanebot: add command to search for torrents 2023-04-29 08:42:31 +00:00
7c1961eba8 mx-sanebot: port the parsing over to a more formal implementation 2023-04-29 07:31:16 +00:00
b0c68308b7 WIP: mx-sanebot: first pass at formalizing a parser 2023-04-29 03:22:10 +00:00
6f7b7ddb84 Merge branch 'master' of git.uninsane.org:colin/nix-files 2023-04-28 09:20:05 +00:00
1cc139c45c Merge branch 'staging/nixpkgs-2023-04-24-staging-next' 2023-04-28 09:19:32 +00:00
d06516a71b servo: try to ship lemmy (it's failing with some DB migration stuff) 2023-04-28 02:02:39 +00:00
1c5a7b72ea mx-sanebot: add command that can show torrent status 2023-04-28 01:50:25 +00:00
afc916c9f8 mx-sanebot: split out a cleaner API between the Matrix events and the bot's event-handling logic 2023-04-28 01:33:47 +00:00
7b141f6f58 mx-sanebot: refactor event handling
now we handle invites using the same sync idioms as with normal messages
2023-04-27 23:35:42 +00:00
94b7826099 lightdm-mobile-greeter: fix to comply with newer cargo git deps/nixpkgs requirements 2023-04-27 21:01:36 +00:00
fd82256bbc install zeal docs for packages like mx-sanebot 2023-04-27 10:07:16 +00:00
ec7f36913c mx-sanebot: allow building zeal docs 2023-04-27 08:32:24 +00:00
6324d8004f mx-sanebot: add to pkgs 2023-04-27 08:14:23 +00:00
4b8fddeb3f static-nix-shell: ensure runtime deps are on PATH 2023-04-27 08:14:11 +00:00
871975a597 mx-sanebot: split shell and default out of flake.nix 2023-04-27 08:04:39 +00:00
1e6e41a9cb add pkgs support to static-nix-shell and use it for gpodder 2023-04-27 08:00:38 +00:00
2f375b7778 cargo-docset: remove extraneous pkg-config nativeBuildInputs 2023-04-26 08:48:12 +00:00
df2e3a1b03 templates: rust: change sha256 (deprecated) to hash 2023-04-26 08:34:43 +00:00
718a4b61d7 cargo-docset: init at 0.3.1 2023-04-26 08:34:24 +00:00
d617c0259f templates: add a pure rust package template 2023-04-26 07:41:08 +00:00
83e404f000 templates: categorize by pkgs v.s. env 2023-04-26 07:35:04 +00:00
ba11bba909 rust template: remove unused build inputs 2023-04-26 07:24:12 +00:00
af394b315e add a flake template for rust binaries 2023-04-26 07:20:02 +00:00
44195a7d87 programs: ship /home secrets correctly 2023-04-26 03:46:18 +00:00
44e356cf6b programs: ship zeal (to browse programming docs) 2023-04-26 00:58:50 +00:00
7aafc6719e home: move firefox from home/firefox.nix -> programs/web-browser.nix 2023-04-26 00:53:30 +00:00
f6579b865b home: firefox: port to sane.programs API 2023-04-26 00:52:13 +00:00
8d5c917c79 home: move zsh from home -> programs 2023-04-26 00:46:35 +00:00
4c74a95194 home: zsh: port to programs API 2023-04-26 00:46:12 +00:00
a6056aeb47 home: move kitty from home -> programs 2023-04-26 00:36:37 +00:00
ac3e384b63 home: move vlc from home -> programs 2023-04-26 00:35:01 +00:00
3338e93c87 home: move sublime-music from home -> programs 2023-04-26 00:34:39 +00:00
97cb72db7c home: sublime-music: specify secrets using sane.programs API 2023-04-26 00:34:17 +00:00
f7f6b80cd0 home: move splatmoji from home -> programs 2023-04-26 00:33:04 +00:00
d60fe7a93c home: move ripgrep from home -> programs 2023-04-26 00:32:33 +00:00
e2fa18b7c7 home: move offlineimap from home -> programs 2023-04-26 00:31:56 +00:00
3226615885 home: offlineimap: specify secrets using the sane.programs API 2023-04-26 00:31:24 +00:00
dd99e66fb5 home: move newsflash from home -> programs 2023-04-26 00:29:49 +00:00
2e45145e72 home: move neovim from home -> programs 2023-04-26 00:29:10 +00:00
9783646a0d home: move mpv from home -> programs 2023-04-26 00:28:11 +00:00
c24f4d1659 home: move libreoffice from home -> programs 2023-04-26 00:27:43 +00:00
f220771b58 home: move gpodder from home -> programs 2023-04-26 00:27:15 +00:00
cb9854c297 home: move gnome-feeds from home -> programs 2023-04-26 00:26:44 +00:00
d422dcdd89 home: move git from home -> programs 2023-04-26 00:26:05 +00:00
4e4e7e4991 aerc: move from home -> programs 2023-04-26 00:25:08 +00:00
9c09d03e5c programs: add per-program secrets 2023-04-26 00:19:33 +00:00
1f0fbe29a8 programs: move to subdir 2023-04-26 00:17:20 +00:00
131a828ed0 mx-sanebot: remove dead code 2023-04-25 23:23:04 +00:00
a4bcb44677 Merge branch 'staging/nixpkgs-2023-04-19-staging-next' into master-next 2023-04-25 09:53:53 +00:00
d385845dd5 mx-sanebot: stream the sync events to avoid an inversion of control
the handler callback API is a poor fit for Rust lifetimes, so avoid it when possible
2023-04-25 09:48:42 +00:00
66c42916c8 mx-sanebot: refactor event loop 2023-04-25 08:20:56 +00:00
c6d4784dae nix update: nixpkgs 2023-04-23 -> 2023-04-25
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/7d385961ebe582fed4e850a326d8d200be79f6b8' (2023-04-23)
  → 'github:nixos/nixpkgs/d0ea36ece469a71a909ebff90777c2f7a49478bb' (2023-04-25)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/8a95e6f8cd160a05c2b560e66f702432a53b59ac' (2023-04-23)
  → 'github:Mic92/sops-nix/7c8e9727a2ecf9994d4a63d577ad5327e933b6a4' (2023-04-24)
```
2023-04-25 07:59:38 +00:00
b282e5beb2 mx-sanebot: split out some request/response interface 2023-04-25 07:44:49 +00:00
20f4251c6e nix flake update 2023/04/23 2023-04-25 06:40:01 +00:00
5d0630cad4 sane-bt-add: implement --audiobook, --vn options 2023-04-24 10:02:40 +00:00
2dbf3b4732 sane-scripts: fix broken prologue 2023-04-24 10:02:24 +00:00
8e8e63a33f matrix: re-enable shared registration secret
this allows me to create users from the CLI
2023-04-24 09:49:37 +00:00
6b7a8f9fec programs: imagemagick: ship ghostscript as a suggested package 2023-04-24 09:48:09 +00:00
b85bdf26fd sane-scripts: don't ship the prologue
it gets inlined during resholve building
2023-04-24 09:47:36 +00:00
2fa76836b5 programs: fix git/rg not having config 2023-04-24 09:40:09 +00:00
5c8cca6a52 start work on a Matrix bot to expose sane-* commands to Matrix 2023-04-24 09:39:59 +00:00
1f2c9a9a5e refactor hosts/common/home to use sane.programs API 2023-04-24 07:22:33 +00:00
337fb9e9d9 sane.programs: allow programs to define files, as per sane.fs 2023-04-24 06:49:56 +00:00
e7f02c057e steam: integrate into sane.programs, and enable for lappy 2023-04-23 23:21:08 +00:00
8df87256a1 partial nixpkgs update (ibus fails) 2023-04-21 19:41:42 +00:00
09a1d286d0 servo: enable komga, a comic/manga webapp 2023-04-21 07:15:05 +00:00
0662b06df6 servo: try to ship calibre (but i get runtime errors, so disable it) 2023-04-21 06:57:26 +00:00
b0a99da884 dovecot: if mail fails DKIM, deliver it to Junk 2023-04-20 14:25:59 +00:00
12fd7ebc41 email: split dovecot config out of postfix config 2023-04-20 09:43:39 +00:00
f4a04ff6ba reorg: move postfix stuff into an email subdir 2023-04-20 09:24:20 +00:00
89e2a83067 postfix: toy with some spam protection (but don't actually enable it) 2023-04-20 09:17:25 +00:00
ae78f2b6c2 sane-scripts: sane-ip-reconnect: port to python & only connect to networks we *know* 2023-04-20 09:11:18 +00:00
198c40df66 minor nixpkgs update (2023-04-19 -> 2023-04-19)
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/bf5b2a67bccd55572834c40a3c1c92530ab55673' (2023-04-19)
  → 'github:nixos/nixpkgs/a1cb3e73104adb41f8902093e07b8eba2114ab3f' (2023-04-19)
```
2023-04-19 13:43:12 +00:00
a952f84ee4 cross: fix patches 2023-04-19 13:42:35 +00:00
c9e55a586b flake: update nixpkgs 2023-04-16 -> 2023-04-19 (staging-next)
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/f294325aed382b66c7a188482101b0f336d1d7db' (2023-04-16)
  → 'github:nixos/nixpkgs/bf5b2a67bccd55572834c40a3c1c92530ab55673' (2023-04-19)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/de6514f8fe1b3c2b57307569a0898bc4be9ae1c5' (2023-04-17)
  → 'github:Mic92/sops-nix/5698b06b0731a2c15ff8c2351644427f8ad33993' (2023-04-18)
```
2023-04-19 11:24:21 +00:00
aa8c3affcd cross: remove patches which have been upstreamed 2023-04-19 09:20:56 +00:00
692f47d02d doc: github token could be shipped statically 2023-04-19 00:00:52 +00:00
0ac17c32a3 programs: add MS GitHub gh program 2023-04-18 22:04:00 +00:00
2ff4df069e nix update: nixpkgs: 2023-04-13 -> 2023-04-16 (nixos-unstable)
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/915c0fab841cc88045e00778b8e7fbdbdbd7d1aa' (2023-04-13)
  → 'github:nixos/nixpkgs/f294325aed382b66c7a188482101b0f336d1d7db' (2023-04-16)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/00d5fd73756d424de5263b92235563bc06f2c6e1' (2023-04-11)
  → 'github:Mic92/sops-nix/de6514f8fe1b3c2b57307569a0898bc4be9ae1c5' (2023-04-17)
• Updated input 'sops-nix/nixpkgs-stable':
    'github:NixOS/nixpkgs/e45cc0138829ad86e7ff17a76acf2d05e781e30a' (2023-04-09)
  → 'github:NixOS/nixpkgs/1040ce5f652b586da95dfd80d48a745e107b9eac' (2023-04-16)
```
2023-04-18 21:40:17 +00:00
b11759a0a6 Merge branch 'master' of git.uninsane.org:colin/nix-files 2023-04-18 06:10:47 +00:00
6af0d54e7b matrix: re-enable signal bridge 2023-04-18 06:10:17 +00:00
f87c115f7c RSS: subscribe to JMP.chat 2023-04-18 05:50:47 +00:00
099cd12bdd matrix/irc.nix: sanitize quit messages 2023-04-18 00:58:15 +00:00
bf67def14a matrix/irc.nix: MyAnonamouse: disable SASL auth
it's unclear if SASL auth *might* actually work -- just with some weird delays -- but non-SASL auth *definitely* works
2023-04-17 01:57:27 +00:00
39e7e2230e symlink Pictures/servo-macros 2023-04-17 00:46:37 +00:00
4ff82f002b matrix/irc.nix: bridge to MyAnonamouse 2023-04-16 13:13:36 +00:00
781a149542 matrix: re-enable IRC bridge 2023-04-16 00:32:04 +00:00
b7f2f4f5c4 Merge branch 'master' of git.uninsane.org:colin/nix-files 2023-04-16 00:22:00 +00:00
e3cb51951c programs: add a few (disabled) dev tools 2023-04-15 23:05:37 +00:00
94ac4ec0e9 matrix-appservice-irc: correct the user id/gid 2023-04-15 06:58:13 +00:00
348bd0f177 flake: nit: rename deploy-moby-switch -> deploy-moby 2023-04-15 06:56:24 +00:00
bae0e3df76 cross: remove browserpass patch. it's been merged upstream 2023-04-15 06:56:08 +00:00
429951cfcc cross: remove tpm2-abrmd patch. it's been upstreamed 2023-04-14 11:09:30 +00:00
b23262b367 cross: remove libtiger patch (no longer necessary?) 2023-04-14 10:51:22 +00:00
464e348545 include a reference to the rav1e PR which i'm waiting for merge 2023-04-14 09:32:35 +00:00
62c1f4009b switch browser to librewolf 2023-04-14 07:14:50 +00:00
2373d28eb8 flake update: nixpkgs 2023-04-12 -> 2023-04-13
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/cab3b7f3356fa82bfab449fa1bb7b54092dc8e17' (2023-04-12)
  → 'github:nixos/nixpkgs/915c0fab841cc88045e00778b8e7fbdbdbd7d1aa' (2023-04-13)
```
2023-04-13 22:30:52 +00:00
d76591349e cross: re-patch libgweather, which was incorrectly removed 2023-04-13 21:50:20 +00:00
4361bd45c7 sane-deadlines: fix threshold/date parsing 2023-04-13 10:02:53 +00:00
be33684d5d cross: remove upstreamed patches 2023-04-13 09:41:10 +00:00
d2ef8d113e nix update nixpkgs 2023-04-11 -> 2023-04-12
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/4e2c1815ed1a40825c52e30dc993bf3a3c136104' (2023-04-11)
  → 'github:nixos/nixpkgs/cab3b7f3356fa82bfab449fa1bb7b54092dc8e17' (2023-04-12)
```
2023-04-12 20:55:26 +00:00
54d29ca190 Merge branch 'staging/nixpkgs-2023-04-11' 2023-04-12 10:46:55 +00:00
875482f395 apply bambu-studio PR 2023-04-12 02:44:37 +00:00
dac245e032 nix update: nixpkgs 2023-04-08 -> 2023-04-11; sops-nix
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/df6db8c5b0b94b85e578d05b37e5bf3b24555638' (2023-04-08)
  → 'github:nixos/nixpkgs/4e2c1815ed1a40825c52e30dc993bf3a3c136104' (2023-04-11)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/b93eb910f768f9788737bfed596a598557e5625d' (2023-04-02)
  → 'github:Mic92/sops-nix/00d5fd73756d424de5263b92235563bc06f2c6e1' (2023-04-11)
• Updated input 'sops-nix/nixpkgs-stable':
    'github:NixOS/nixpkgs/c1e2efaca8d8a3db6a36f652765d6c6ba7bb8fae' (2023-04-01)
  → 'github:NixOS/nixpkgs/e45cc0138829ad86e7ff17a76acf2d05e781e30a' (2023-04-09)
```
2023-04-12 00:09:51 +00:00
e7edafcfec nix update nixpkgs 2023-04-02 -> 2023-04-08; mobile-nixos; uninsane-dot-org
```
• Updated input 'mobile-nixos':
    'github:nixos/mobile-nixos/7a6e97e3af73c4cca87e12c83abcb4913dac7dbc' (2023-03-22)
  → 'github:nixos/mobile-nixos/4aa0afd84005b79be4d5361b56a60df9e9bd4ea3' (2023-04-03)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/66f60deb8aa348ca81d60d0639ae420c667ff92a' (2023-04-02)
  → 'github:nixos/nixpkgs/df6db8c5b0b94b85e578d05b37e5bf3b24555638' (2023-04-08)
• Updated input 'uninsane-dot-org':
    'git+https://git.uninsane.org/colin/uninsane?ref=refs%2fheads%2fmaster&rev=068f176a64f0e26dc8c1f0eccf28cbd05be4909b' (2023-03-29)
  → 'git+https://git.uninsane.org/colin/uninsane?ref=refs%2fheads%2fmaster&rev=2970c6080187975a1fc996f541167e697d4ebebc' (2023-04-03)
```
2023-04-12 00:08:50 +00:00
00af6104be flake: pass CLI arguments into nixos-rebuild when running deploy-moby-X 2023-04-07 22:55:47 +00:00
40c9517dc6 moby: ship jellyfin (and it runs!) 2023-04-07 22:55:02 +00:00
c2915e29d4 cross compilation: disable appstream patch 2023-04-06 12:42:06 +00:00
b6edf768b9 packages: enable slic3r (3d printing software) 2023-04-06 08:46:04 +00:00
27be182eb7 Merge branch 'wip/less-disable-flakey-tests' 2023-04-06 08:42:17 +00:00
ddf1be7410 sane-scripts: sane-reclaim-disk-space: use nix-store --optimise 2023-04-06 08:41:02 +00:00
ad819e4cc0 nix flake update: nixpkgs 2023-03-31 -> 2023-04-01 2023-04-06 08:41:02 +00:00
6407f156b2 cross compilation: remove gupnp patch 2023-04-06 07:43:22 +00:00
6d419b8279 RSS: unsubscribe from text-based econlib 2023-04-04 20:46:34 +00:00
bf3e0ad790 feeds: subscribe to capitol hill seattle blog 2023-04-03 07:01:51 +00:00
0c07e03ad6 podcasts: add The Witch Trials of JK Rowling 2023-04-03 06:58:14 +00:00
170 changed files with 5881 additions and 1366 deletions

100
README.md Normal file
View 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
View File

@@ -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"
},

View File

@@ -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";
};
};
};
}

View File

@@ -19,6 +19,7 @@
"desktopGuiApps"
"stepmania"
];
sane.programs.mx-sanebot.enableFor.system = true; # for the docs
sops.secrets.colin-passwd = {
sopsFile = ../../../secrets/lappy.yaml;

View 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";
}

View File

@@ -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

View 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;
}

View 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;
}
'';
};
}

View File

@@ -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";
};
}

View 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";
}

View 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";
}

View File

@@ -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 = [

View File

@@ -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
);

View 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";
}

View File

@@ -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;
};
};
};

View File

@@ -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
})
];
};

View File

@@ -11,7 +11,7 @@
./machine-id.nix
./net.nix
./persist.nix
./programs.nix
./programs
./secrets.nix
./ssh.nix
./users.nix

View File

@@ -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)
];

View File

@@ -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;
}

View File

@@ -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
];
}

View File

@@ -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
'';
}

View File

@@ -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
);
}

View File

@@ -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;
}

View File

@@ -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
'';
}

View File

@@ -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;
}

View File

@@ -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
'';
}

View File

@@ -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'
'';
};
}

View File

@@ -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;

View 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;
}

View File

@@ -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
};
};
}

View File

@@ -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";

View File

@@ -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.

View File

@@ -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
);
}

View File

@@ -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

View File

@@ -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>

View 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
'';
};
}

View File

@@ -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;

View 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
);
};
}

View 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;
}

View File

@@ -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/
'';
}

View 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
'';
};
}

View 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;
};
}

View 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
'';
};
}

View File

@@ -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;
};
})
];
}

View 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"
];
}

View 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
})
];
}

View File

@@ -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;
};

View File

@@ -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";

View File

@@ -126,6 +126,7 @@ in
package = null;
suggestedPrograms = [
"guiApps"
"splatmoji" # used by us, but 'enabling' it gets us persistence & cfg
"swaylock"
"swayidle"
"wl-clipboard"

View 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)

File diff suppressed because one or more lines are too long

View File

@@ -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"
}

View File

@@ -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; };
};
}

View File

@@ -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;

View File

@@ -1,4 +1,4 @@
{ lib, utils, ... }:
{ lib, ... }:
let path = rec {

View File

@@ -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))

View File

@@ -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
'';

View File

@@ -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
'';

View File

@@ -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;
};

View 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="
}

View File

@@ -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

View File

@@ -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:

View File

@@ -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=";
# })
# ];
# });
})

View File

@@ -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; }
)

View 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 ];
};
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

File diff suppressed because it is too large Load Diff

View 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"] }

View 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
View 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
}

View 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; };
});
}

View 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";
}

View 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 = &not_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
}

View 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 &lt;phrase&gt;</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(())
}
}

View 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)
}
}

View File

@@ -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