Compare commits
77 Commits
905cdcba73
...
6bf8cd19ac
Author | SHA1 | Date |
---|---|---|
Ryan Rix | 6bf8cd19ac | |
Ryan Rix | 923978f09f | |
Ryan Rix | 52b441dd19 | |
Ryan Rix | ce7958ca5d | |
Ryan Rix | 5eb55a4add | |
Ryan Rix | dd1ae80fdb | |
Ryan Rix | d7c12716b8 | |
Ryan Rix | ada2502a76 | |
Ryan Rix | 980cae01d2 | |
Ryan Rix | e303fd5ef9 | |
Ryan Rix | 1b0895b157 | |
Ryan Rix | 2d6b02c360 | |
Ryan Rix | 20bbe5583f | |
Ryan Rix | ebacb87401 | |
Ryan Rix | e882e04fac | |
Ryan Rix | c81b2e9339 | |
Ryan Rix | f622fee2f9 | |
Ryan Rix | abda4ccf92 | |
Ryan Rix | 9751b0c587 | |
Ryan Rix | d03e278ce1 | |
Ryan Rix | 2fd4728ea8 | |
Ryan Rix | 688288a8ad | |
Ryan Rix | 2c1bfa43a7 | |
Ryan Rix | 02eadd453e | |
Ryan Rix | e844549f8e | |
Ryan Rix | 2c12aa5a9a | |
Ryan Rix | 036d94a879 | |
Ryan Rix | a1148f1bce | |
Ryan Rix | 090cd9ddd8 | |
Ryan Rix | 2ab485a1c9 | |
Ryan Rix | 08f9348f04 | |
Ryan Rix | d0f23201f2 | |
Ryan Rix | d01396fef9 | |
Ryan Rix | 655d224cbb | |
Ryan Rix | bc6dc6c20e | |
Ryan Rix | 3166991510 | |
Ryan Rix | 6df05f075d | |
Ryan Rix | 40f4ff4874 | |
Ryan Rix | 9f3054cfef | |
Ryan Rix | fb103376ae | |
Ryan Rix | 6348fec5c9 | |
Ryan Rix | db51b72bcd | |
Ryan Rix | cb0589349c | |
Ryan Rix | 9c8fda225c | |
Ryan Rix | 1d4cfad8c7 | |
Ryan Rix | 4c9839da24 | |
Ryan Rix | adf9f98e65 | |
Ryan Rix | f9f8691206 | |
Ryan Rix | 4cbdfab473 | |
Ryan Rix | 214b142222 | |
Ryan Rix | be42845fb3 | |
Ryan Rix | 2f83132b81 | |
Ryan Rix | 52373413e0 | |
Ryan Rix | f168398dea | |
Ryan Rix | 826a9c6ddb | |
Ryan Rix | 2818dfb798 | |
Ryan Rix | 96d1c671c9 | |
Ryan Rix | cf5ce0dfa0 | |
Ryan Rix | 08187fc566 | |
Ryan Rix | b021c3b610 | |
Ryan Rix | b9d513f179 | |
Ryan Rix | a395d35df7 | |
Ryan Rix | 700d63a662 | |
Ryan Rix | f8c00e1145 | |
Ryan Rix | 08aa6cd6f9 | |
Ryan Rix | 87327e9df7 | |
Ryan Rix | 41d98f8faa | |
Ryan Rix | d70666efe1 | |
Ryan Rix | 8ed2fca04d | |
Ryan Rix | a4828ff0f1 | |
Ryan Rix | 8c4cd2cfce | |
Ryan Rix | c3c01512c6 | |
Ryan Rix | 7890d41c68 | |
Ryan Rix | 50daa5588e | |
Ryan Rix | 4fecc17fd4 | |
Ryan Rix | b16909a384 | |
Ryan Rix | 3b886edbe6 |
398
akkoma.org
398
akkoma.org
|
@ -2,8 +2,8 @@
|
|||
:ID: 20221202T122017.620403
|
||||
:ROAM_REFS: https://akkoma.dev/AkkomaGang/akkoma https://akkoma.social/
|
||||
:END:
|
||||
#+TITLE: Self-Hosting on the Fediverse with (Pleroma for now, eventually) Akkoma
|
||||
#+FILETAGS: :Akkoma Social:
|
||||
#+TITLE: Self-Hosting on the Fediverse with Akkoma
|
||||
#+FILETAGS: :Project:Akkoma Social:
|
||||
#+ARCOLOGY_KEY: cce/akkoma
|
||||
|
||||
Akkoma is a [[id:62538db5-d94a-47c3-9998-086ded91fd88][Fediverse]]/[[id:activitypub][ActivityPub]] server forked from [[roam:Pleroma]] written in [[id:cce/elixir][Elixir]], supporting the [[id:339daa8c-cc01-4654-aa89-330a4e62aafa][Mastodon Server]] API. This is a light-weight thing and I intend to self-publish to the Fediverse with an instance running on [[id:20211120T220054.226284][The Wobserver]].
|
||||
|
@ -15,43 +15,43 @@ Akkoma is a [[id:62538db5-d94a-47c3-9998-086ded91fd88][Fediverse]]/[[id:activity
|
|||
:END:
|
||||
[2022-12-02 Fri 12:22]
|
||||
|
||||
* +Akkoma+ Pleroma on [[id:c75d20e6-8888-4c5a-ac97-5997e2f1c711][NixOS]]
|
||||
* Akkoma on [[id:c75d20e6-8888-4c5a-ac97-5997e2f1c711][NixOS]]
|
||||
:PROPERTIES:
|
||||
:ID: 20221202T122135.502628
|
||||
:ROAM_ALIASES: "Akkoma Server"
|
||||
:END:
|
||||
:LOGBOOK:
|
||||
CLOCK: [2022-12-02 Fri 12:22]--[2022-12-02 Fri 16:24] => 4:02
|
||||
:END:
|
||||
|
||||
Akkoma is properly on its way to being integrated with NixOS through [[id:c75d20e6-8888-4c5a-ac97-5997e2f1c711][nixpkgs]] in [[id:20221202T122230.525913][nixpkgs PR #192285]], but until then I will run pleroma after trying to get Akkoma to run in docker containers.
|
||||
|
||||
The [[https://docs.akkoma.dev/stable/installation/docker_en/][Docker installation]] instructions for Akkoma are built around [[roam:Docker Compose]] which is, fine, but I want to use my system [[id:cce/wobserver/postgres][PostgreSQL]] instead of one hidden in the Compose image so we'll have to do Some Work ourselves. I'll have to set up [[id:20221202T124113.404212][Docker on the Wobserver]] first...
|
||||
|
||||
This sucks though, i'll just wait for that nixos module and run Pleroma in the meantime. In theory it'll be easy enough to [[https://docs.akkoma.dev/stable/installation/migrating_to_akkoma/][migrate to akkoma]]...
|
||||
The configuration interface in NixOS is nicer but also quite complicated. I have this broken up a bit and it consists of *most* of the configuration but not things like emoji and some other static assets like my favicon and whatnot.
|
||||
|
||||
It's not super complicated but we'll break it up in to multiple imports so that I can explain what is going on a bit:
|
||||
|
||||
#+ARROYO_NIXOS_ROLE: server
|
||||
#+ARROYO_NIXOS_MODULE: nixos/akkoma.nix
|
||||
#+AUTO_TANGLE: t
|
||||
|
||||
Right now my Pleroma includes an un-released patch to [[https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3661][enable TLSv1.3 support]] so that I can follow users on https://defcon.social:
|
||||
=myAkkoma= carries an [[https://akkoma.dev/AkkomaGang/akkoma/commit/af7c3fab98f4f5d1fa541035fd8b2821e0abb77b][unreleased patch]] to skip over the Pleroma observability rules -- i need to fix the [[id:20220101T190353.843667][Wobservability]] section below to use this anyways, but I couldn't turn off the observability rules because they were in the DB configuration. Oughtta make sure I move that stuff out in to =config.exs= fairly often.
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/akkoma.nix :noweb yes
|
||||
{ config, pkgs, ... }:
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
# remove in 2.4.6
|
||||
myPleroma = pkgs.pleroma.overrideAttrs (old: old // {
|
||||
patches = (old.patches or []) ++ [ <arroyo/files/pleroma-tls13.patch> ];
|
||||
myAkkoma = pkgs.akkoma.overrideAttrs (old: old // {
|
||||
# patches = [
|
||||
# (<arroyo/files/akkoma-fix-pleroma-migration.patch>)
|
||||
# ];
|
||||
});
|
||||
in
|
||||
{
|
||||
in{
|
||||
imports = [
|
||||
./akkoma-users.nix
|
||||
./akkoma-statics.nix
|
||||
./akkoma-frontends.nix
|
||||
./akkoma-virtualhost.nix
|
||||
./akkoma-wobservability.nix
|
||||
./akkoma-pwa.nix
|
||||
./akkoma-config.nix
|
||||
./akkoma-mrf.nix
|
||||
];
|
||||
|
||||
services.postgresql.ensureDatabases = ["akkoma"];
|
||||
|
@ -66,60 +66,95 @@ in
|
|||
}
|
||||
];
|
||||
|
||||
systemd.services.pleroma.path = with pkgs; [exiftool ffmpeg imagemagick];
|
||||
services.pleroma = {
|
||||
services.akkoma = {
|
||||
enable = true;
|
||||
package = myPleroma;
|
||||
package = myAkkoma;
|
||||
|
||||
# don't feel like needing to chown later on...
|
||||
group = "akkoma";
|
||||
user = "akkoma";
|
||||
|
||||
configs = [
|
||||
''
|
||||
<<initial-configuration>>
|
||||
''
|
||||
];
|
||||
# manually populated
|
||||
secretConfigFile = "/srv/akkoma/secrets.exs";
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
** Initial =config.exs=
|
||||
** Akkoma Service Configuration
|
||||
|
||||
This configuration tells Pleroma that it's fine to be configured in the =admin-fe= interface and provides some defaults from the configuration generator:
|
||||
ref [[https://docs.akkoma.dev/stable/configuration/cheatsheet/][Configuration Cheat Sheet]], none of this is particularly exciting.
|
||||
|
||||
#+begin_src elixir :noweb-ref initial-configuration
|
||||
import Config
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/akkoma-config.nix
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
services.akkoma.extraPackages = with pkgs; [exiftool ffmpeg-headless imagemagick];
|
||||
# don't feel like setting password._secret here...
|
||||
services.akkoma.initDb.enable = false;
|
||||
services.akkoma.config = {
|
||||
":pleroma".":instance" = {
|
||||
name = "Computers :(";
|
||||
description = "rrix's fediverse home";
|
||||
email = "fedi@whatthefuck.computer";
|
||||
registrations_open = false;
|
||||
limit = 5000;
|
||||
local_bubble = [
|
||||
"botsin.space"
|
||||
"hackers.town"
|
||||
"tenforward.social"
|
||||
"regenerate.social"
|
||||
];
|
||||
export_prometheus_metrics = true;
|
||||
|
||||
config :pleroma, Pleroma.Web.Endpoint,
|
||||
url: [host: "notes.whatthefuck.computer", scheme: "https", port: 443],
|
||||
http: [ip: {127, 0, 0, 1}, port: 4000]
|
||||
static_dir = "/srv/akkoma/static";
|
||||
upload_dir = "/srv/akkoma/uploads";
|
||||
};
|
||||
|
||||
config :pleroma, :instance,
|
||||
name: "Computers :(",
|
||||
email: "fedi@whatthefuck.computer",
|
||||
notify_email: "fedi@whatthefuck.computer",
|
||||
limit: 5000,
|
||||
registrations_open: false
|
||||
":pleroma".":static_fe".enabled = true;
|
||||
|
||||
config :pleroma, :media_proxy,
|
||||
enabled: false,
|
||||
redirect_on_failure: true
|
||||
":pleroma"."Pleroma.Repo" = {
|
||||
adapter = (pkgs.formats.elixirConf { }).lib.mkRaw "Ecto.Adapters.Postgres";
|
||||
username = config.services.akkoma.user;
|
||||
database = "akkoma";
|
||||
hostname = "localhost";
|
||||
};
|
||||
|
||||
config :pleroma, :database, rum_enabled: false
|
||||
config :pleroma, :instance, static_dir: "/srv/akkoma/static"
|
||||
config :pleroma, Pleroma.Uploaders.Local, uploads: "/srv/akkoma/uploads"
|
||||
":pleroma".":configurable_from_database" = true;
|
||||
|
||||
# Enable Strict-Transport-Security once SSL is working:
|
||||
# config :pleroma, :http_security,
|
||||
# sts: true
|
||||
":pleroma".":media_proxy" = {
|
||||
enabled = true;
|
||||
proxy_opts.redirect_on_failure = true;
|
||||
};
|
||||
|
||||
config :pleroma, configurable_from_database: true
|
||||
":pleroma"."Pleroma.Upload".filters =
|
||||
map (pkgs.formats.elixirConf { }).lib.mkRaw [
|
||||
"Pleroma.Upload.Filter.Exiftool"
|
||||
"Pleroma.Upload.Filter.Dedupe"
|
||||
"Pleroma.Upload.Filter.AnonymizeFilename"
|
||||
];
|
||||
|
||||
config :pleroma, Pleroma.Upload, filters: [Pleroma.Upload.Filter.Exiftool, Pleroma.Upload.Filter.Dedupe]
|
||||
":pleroma"."Pleroma.Web.Endpoint" = {
|
||||
http = {
|
||||
ip = "127.0.0.1";
|
||||
port = 4000;
|
||||
};
|
||||
url = {
|
||||
host = "notes.whatthefuck.computer";
|
||||
scheme = "https";
|
||||
port = 443;
|
||||
};
|
||||
};
|
||||
|
||||
# secrets
|
||||
":pleroma"."Pleroma.Repo".password._secret = "/srv/akkoma/dbpass";
|
||||
":joken".":default_signer"._secret = "/srv/akkoma/jwt-signer";
|
||||
":pleroma"."Pleroma.Web.Endpoint" = {
|
||||
live_view.signing_salt._secret = "/srv/akkoma/liveview-salt";
|
||||
secret_key_base._secret = "/srv/akkoma/secret-key-base";
|
||||
signing_salt._secret = "/srv/akkoma/signing-salt";
|
||||
};
|
||||
":web_push_encryption".":vapid_details" = {
|
||||
private_key._secret = "/srv/akkoma/vapid-private";
|
||||
public_key._secret = "/srv/akkoma/vapid-public";
|
||||
subject = "mailto:fedi@whatthefuck.computer";
|
||||
};
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
** System Users
|
||||
|
@ -149,6 +184,99 @@ I really would like to manage my uids and gids better, but alas.
|
|||
}
|
||||
#+end_src
|
||||
|
||||
** Frontend Management
|
||||
|
||||
so if you set a =static_dir= to a mutable directory on the server, the NixOS module won't install the frontends you ask for. This is good and fine, and not a surprise, certainly not undocumented. So what if you just:
|
||||
|
||||
=pleroma_ctl frontend install admin-fe --ref stable=
|
||||
=pleroma_ctl frontend install fedibird-fe --ref akkoma=
|
||||
=pleroma_ctl frontend install pleroma-fe --ref stable=
|
||||
|
||||
That fails because =BindReadOnlyPaths= is set in the NixOS module as part of the hardening of the service. I shouldn't mind, but =** (File.Error) could not make directory (with -p) "/srv/akkoma/static/frontends/tmp": read-only file system=
|
||||
|
||||
so, okay, make sure =BindReadOnlyPaths= is not set, and set =ReadWritePaths= just to be sure.
|
||||
In theory it'd be possible to use a =system.activationScripts= entry to take =frontends.$foo.package= and slam a symlink in like I do for the terms of service above, but i'm tired.
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/akkoma-frontends.nix
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
{
|
||||
systemd.services.akkoma.serviceConfig.ReadWritePaths = [ config.services.akkoma.config.":pleroma".":instance".static_dir ];
|
||||
systemd.services.akkoma.serviceConfig.BindReadOnlyPaths = lib.mkForce [ ];
|
||||
services.akkoma.frontends = {
|
||||
primary = {
|
||||
name = "pleroma-fe";
|
||||
ref = "stable";
|
||||
};
|
||||
mastodon= {
|
||||
name = "fedibird-fe";
|
||||
ref = "akkoma";
|
||||
};
|
||||
admin = {
|
||||
name = "admin-fe";
|
||||
ref = "stable";
|
||||
};
|
||||
};
|
||||
|
||||
# shove this thing in a system.activationScript to symlink to static_dir/frontends
|
||||
# frontends.primary.package = pkgs.runCommand "akkoma-fe" {
|
||||
# config = builtins.toJSON {
|
||||
# expertLevel = 1;
|
||||
# collapseMessageWithSubject = false;
|
||||
# replyVisibility = "following";
|
||||
# hideScopeNotice = true;
|
||||
# renderMisskeyMarkdown = false;
|
||||
# hideSiteFavicon = true;
|
||||
# postContentType = "text/markdown";
|
||||
# showNavShortcuts = false;
|
||||
# };
|
||||
# nativeBuildInputs = with pkgs; [ jq xorg.lndir ];
|
||||
# passAsFile = [ "config" ];
|
||||
# } ''
|
||||
# mkdir $out
|
||||
# lndir ${pkgs.akkoma-frontends.akkoma-fe} $out
|
||||
#
|
||||
# rm $out/static/config.json
|
||||
# jq -s add ${pkgs.akkoma-frontends.akkoma-fe}/static/config.json ${config} \
|
||||
# >$out/static/config.json
|
||||
# '';
|
||||
}
|
||||
#+end_src
|
||||
|
||||
** Nginx Frontend for Akkoma
|
||||
|
||||
Nothing special here -- I have it split in to two blocks here because one of my old iterations of [[id:1d917282-ecf4-4d4c-ba49-628cbb4bb8cc][The Arcology Project]] used this domain to host short-form [[id:fa6cee69-dca0-45f5-ae9e-b71cad3702a6][IndieWeb]]/microformat notes. The old files still exist and can be resolved in the =try_files= block, and any failures will proxy through to the app backend. I also adjust the max body size for image uploads, etc. I might replace that with S3 in the future but for now the images can just go on to the file system.
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/akkoma-virtualhost.nix
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
services.nginx.virtualHosts."notes.whatthefuck.computer" = {
|
||||
root = "/srv/static-sites/notes.whatthefuck.computer/_site";
|
||||
extraConfig = ''
|
||||
client_max_body_size 100M;
|
||||
'';
|
||||
locations."/".extraConfig = ''
|
||||
try_files $uri @proxy;
|
||||
'';
|
||||
locations."@proxy" = {
|
||||
proxyPass = "http://127.0.0.1:4000";
|
||||
extraConfig = ''
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $http_host;
|
||||
'';
|
||||
};
|
||||
locations."/phoenix/live_dashboard".extraConfig = ''
|
||||
auth_basic "closed site";
|
||||
auth_basic_user_file /etc/nginx-htpasswd;
|
||||
'';
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
** Static Files
|
||||
|
||||
I could just splat this on to the filesystem but no harm in having it in the Nix store:
|
||||
|
@ -161,11 +289,6 @@ I could just splat this on to the filesystem but no harm in having it in the Nix
|
|||
what is going on here.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This is a Pleroma instance. Not because I want it to be but because
|
||||
Akkoma isn't natively packaged in NixOS yet.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<ul>
|
||||
<li>I'm not a fascist.</li>
|
||||
|
@ -192,7 +315,7 @@ I could just splat this on to the filesystem but no harm in having it in the Nix
|
|||
<p>
|
||||
At the same time, I'm likely not going to be able to go
|
||||
up against government requests for data stored on this instace. As
|
||||
of [2022-12-04] this instance has not been compelled to give data to
|
||||
of [2023-02-16] this instance has not been compelled to give data to
|
||||
any government or law enforcement agency and has not done so
|
||||
voluntarily. I'm just one homie hanging out making posts with my
|
||||
friends and trying to make new ones, and you're here reading
|
||||
|
@ -203,52 +326,24 @@ I could just splat this on to the filesystem but no harm in having it in the Nix
|
|||
#+begin_src nix :tangle ~/arroyo-nix/nixos/akkoma-statics.nix :noweb yes
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
system.activationScripts = let
|
||||
tos = pkgs.writeTextFile {
|
||||
name="pleroma-terms-of-service";
|
||||
text = ''
|
||||
<<tos>>
|
||||
let
|
||||
tos = pkgs.writeTextFile {
|
||||
name="pleroma-terms-of-service";
|
||||
text = ''
|
||||
<<tos>
|
||||
'';
|
||||
};
|
||||
in {
|
||||
install-pleroma-tos.text = ''
|
||||
};
|
||||
in
|
||||
{
|
||||
# services.akkoma.extraStatic."static/terms-of-service.html" = tos;
|
||||
system.activationScripts.install-pleroma-tos.text = ''
|
||||
echo "Installing Pleroma Terms of Service to static directory"
|
||||
export DEST_DIR=/srv/akkoma/static/
|
||||
mkdir -p $DEST_DIR
|
||||
ln -sf ${tos} $DEST_DIR/static/terms-of-service.html
|
||||
'';
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
** Nginx Frontend for Akkoma
|
||||
|
||||
Nothing special here -- I have it split in to two blocks here because one of my old iterations of [[id:1d917282-ecf4-4d4c-ba49-628cbb4bb8cc][The Arcology Project]] used this domain to host short-form [[id:fa6cee69-dca0-45f5-ae9e-b71cad3702a6][IndieWeb]]/microformat notes. The old files still exist and can be resolved in the =try_files= block, and any failures will proxy through to the app backend. I also adjust the max body size for image uploads, etc. I might replace that with S3 in the future but for now the images can just go on to the file system.
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/akkoma-frontends.nix
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
services.nginx.virtualHosts."notes.whatthefuck.computer" = {
|
||||
extraConfig = ''
|
||||
client_max_body_size 100M;
|
||||
'';
|
||||
locations."/".extraConfig = ''
|
||||
try_files $uri @proxy;
|
||||
'';
|
||||
locations."@proxy" = {
|
||||
proxyPass = "http://127.0.0.1:4000";
|
||||
extraConfig = ''
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $http_host;
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
** [[id:20220101T190353.843667][Wobservability]]
|
||||
|
@ -270,3 +365,114 @@ Enable =Pleroma.Web.Endpoint.MetricsExporter= in settings.
|
|||
];
|
||||
}
|
||||
#+end_src
|
||||
|
||||
** PWA manifest for Pleroma-FE
|
||||
|
||||
Pleroma's mute filters, etc aren't 1-1 compatible with Mastodon API so they don't work in Mastodon-FE or Subway Tooter... This is ...unfortunate. Let's see how using Pleroma-FE as a [[https://developer.mozilla.org/en-US/docs/Web/Manifest][Progressive Web App]] goes..
|
||||
|
||||
#+begin_src json :tangle ~/arroyo-nix/files/notes-pwa.json
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/web-manifest-combined.json",
|
||||
"name": "Fedi Notes",
|
||||
"short_name": "Fedi Notes",
|
||||
"start_url": "https://notes.whatthefuck.computer/",
|
||||
"display": "standalone",
|
||||
"background_color": "#004daa",
|
||||
"theme_color": "#31363b",
|
||||
"description": "Pleroma-FE on notes.whatthefuck.computer",
|
||||
"icons": [{
|
||||
"src": "https://notes.whatthefuck.computer/media/e8ecd309a5e3d99736beff056fb461ba157dc4ff9317f3cc6063c4ce280bd604.blob",
|
||||
"sizes": "312x312",
|
||||
"type": "image/png"
|
||||
}]
|
||||
}
|
||||
#+end_src
|
||||
|
||||
This needs to be shoved in to =<head>= and there's no way to do that directly in Pleroma-FE so I make a silly little HTML page and shove it on to a virtualhost:
|
||||
|
||||
#+begin_src web :tangle ~/arroyo-nix/files/notes-pwa.html
|
||||
<html>
|
||||
<head>
|
||||
<link rel="manifest" href="notes-pwa.json" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Pleroma-FE as PWA</h1>
|
||||
<p>
|
||||
On browsers which support "add to home screen" or similar
|
||||
things, you can create a Progressive Web App which will
|
||||
load the <code>Computer :(</code> site in a dedicated frame.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
#+end_src
|
||||
|
||||
And this is installed, like so:
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/akkoma-pwa.nix
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
system.activationScripts = let
|
||||
json = <arroyo/files/notes-pwa.json>;
|
||||
html = <arroyo/files/notes-pwa.html>;
|
||||
in {
|
||||
install-pleroma-tos.text = ''
|
||||
echo "Installing Pleroma PWA manifest and static page"
|
||||
export DEST_DIR=/srv/static-sites/default
|
||||
mkdir -p $DEST_DIR
|
||||
ln -sf ${html} $DEST_DIR/pwa.html
|
||||
ln -sf ${json} $DEST_DIR/notes-pwa.json
|
||||
'';
|
||||
};
|
||||
services.nginx.virtualHosts."fontkeming.fail".extraConfig = ''
|
||||
disable_symlinks off;
|
||||
'';
|
||||
}
|
||||
#+end_src
|
||||
|
||||
## why 404?
|
||||
|
||||
** NEXT Akkoma Moderation Rules
|
||||
|
||||
the new [[https://docs.akkoma.dev/stable-docs/configuration/mrf/][Message Rewrite Facility]] x [[https://fediblock.neocities.org/][fediblock]] dropped. I don't see a lot of this stuff and part of me thinks that having it boosted in to my TWKN or even home timeline is a great signal that I should be unfollowing whoever is bringing the filth in to my instance, but also I want to respect my own sanity.
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/akkoma-mrf.nix :noweb yes
|
||||
{ pkgs, ... }:
|
||||
|
||||
let ecf = pkgs.formats.elixirConf {};
|
||||
in
|
||||
{
|
||||
services.akkoma.config = {
|
||||
":pleroma".":instance" = {
|
||||
quarantined_instances = [
|
||||
<<quarantined_instances()>>
|
||||
];
|
||||
};
|
||||
|
||||
":pleroma".":mrf".policies = ecf.lib.mkRaw "Pleroma.Web.ActivityPub.MRF.SimplePolicy";
|
||||
":pleroma".":mrf_simple".reject = [
|
||||
<<reject_instances()>>
|
||||
];
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
These two functions generate those from a table I don't export.
|
||||
|
||||
#+NAME: quarantined_instances
|
||||
#+begin_src emacs-lisp :noweb-ref quarantined_instances :var tbl=blocked-domains
|
||||
(->> tbl
|
||||
(-map #'first)
|
||||
(--map (format "\"%s\"" it))
|
||||
(s-join "\n"))
|
||||
#+end_src
|
||||
|
||||
This elixirConf stuff, and the declarative config model, is pretty slick. [[file:~/Code/nixpkgs/pkgs/pkgs-lib/formats.nix::{ lib, pkgs }:][<nixpkgs/pkgs/pkgs-lib/formats.nix>]]
|
||||
|
||||
#+NAME: reject_instances
|
||||
#+begin_src emacs-lisp :noweb-ref reject_instances :var tbl=blocked-domains
|
||||
(->> tbl
|
||||
(--map (format "(ecf.lib.mkTuple [\"%s\" \"%s\"])" (first it) (second it)))
|
||||
(s-join "\n"))
|
||||
#+end_src
|
||||
|
||||
|
|
|
@ -4,17 +4,20 @@
|
|||
:END:
|
||||
#+TITLE: Themeing my Emacs and Desktop
|
||||
#+PROPERTY: header-args :mkdirp yes
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
#+PROPERTY: header-args:emacs-lisp :tangle appearance.el
|
||||
|
||||
#+ARCOLOGY_KEY: cce/appearance
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
* Themeing my Emacs
|
||||
|
||||
#+ARROYO_EMACS_MODULE: appearance
|
||||
#+ARCOLOGY_KEY: cce/appearance
|
||||
#+ARROYO_MODULE_WANTS: cce/configure_packaging.org
|
||||
#+ARROYO_MODULE_WANTS: cce/external_display_test_functions.org
|
||||
#+ARROYO_MODULE_WANTS: cce/emacs_session.org
|
||||
#+ARROYO_MODULE_WANTS: cce/shared_cce_helpers.org
|
||||
|
||||
#+ARROYO_MODULE_WANTS: cce/configure_packaging.org
|
||||
#+ARROYO_MODULE_WANTS: cce/external_display_test_functions.org
|
||||
#+ARROYO_MODULE_WANTS: cce/emacs_session.org
|
||||
#+ARROYO_MODULE_WANTS: cce/shared_cce_helpers.org
|
||||
#+ARROYO_MODULE_WANTS: cce/diminish.org
|
||||
#+ARROYO_MODULE_WANTED: cce/run_hooks_after_init.org
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
|
@ -25,23 +28,17 @@ I generally prefer dark and muted colors for the computers that I use. Barring e
|
|||
|
||||
Right now, I am experimenting with using some themes from the [[https://github.com/hlissner/emacs-doom-themes/][Doom Themes]] or [[https://github.com/protesilaos/ef-themes][ef-themes]] repositories, trying to find an earthy natural theme which I can use also on my web sites.
|
||||
|
||||
I load a dark theme and a light theme, +=manegarm= and =acario-light=+ =ef-autumn= and =ef-spring= respectively.
|
||||
I load a dark theme and a light theme, +=manegarm= and =acario-light=+ +=ef-autumn= and =ef-spring=+ =ef-bio= and =ef-cyprus= respectively.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(load custom-file)
|
||||
;; (use-package doom-themes
|
||||
;; :ensure t
|
||||
;; :demand
|
||||
;; :config
|
||||
;; (load-theme 'doom-manegarm t)
|
||||
;; (load-theme 'doom-opera-light t t))
|
||||
|
||||
(use-package ef-themes
|
||||
:ensure t
|
||||
:demand
|
||||
:config
|
||||
(load-theme 'ef-autumn t)
|
||||
(load-theme 'ef-spring t t))
|
||||
(load-theme 'ef-bio t)
|
||||
(load-theme 'ef-cyprus t t))
|
||||
#+end_src
|
||||
|
||||
I don't use my mouse very often so things like icon-bars and scroll-bars aren't useful to me. The modeline contains the buffer's progress, and I don't actually use the scrollbar to navigate. This leaves a tiny bit more room for the fringe and the buffers, which I consider a win.
|
||||
|
@ -53,6 +50,10 @@ I don't use my mouse very often so things like icon-bars and scroll-bars aren't
|
|||
(column-number-mode -1)
|
||||
(line-number-mode -1)
|
||||
(setq x-stretch-cursor t)
|
||||
(setq visible-bell t)
|
||||
(with-eval-after-load "diminish"
|
||||
(diminish 'buffer-face-mode)
|
||||
(diminish 'evil-collection-unimpaired-mode))
|
||||
#+END_SRC
|
||||
|
||||
** Set cursor for each =evil-state= based on Doom Theme colors
|
||||
|
@ -95,7 +96,7 @@ Here is a set of functions for [[id:cce/cce][CCE]] which set up my font preferen
|
|||
(with-eval-after-load 'org (set-face-attribute 'org-block nil :inherit 'fixed-pitch))
|
||||
(with-eval-after-load 'linum (set-face-attribute 'linum nil :inherit 'default :height size)))
|
||||
(set-face-attribute 'default nil :height size)
|
||||
(set-face-attribute 'fixed-pitch nil)
|
||||
;; (set-face-attribute 'fixed-pitch nil)
|
||||
(set-face-attribute 'variable-pitch nil :slant 'oblique :height size)
|
||||
(cce/enable-ipaex-font (/ size 3)))
|
||||
#+end_src
|
||||
|
@ -114,6 +115,8 @@ This calculates the DPI of external displays, assuming they report their physica
|
|||
(defun cce/refresh-display-scale ()
|
||||
(interactive)
|
||||
(cond ((not (cce/has-display-frames)) nil)
|
||||
((equal (system-name) "window-smoke") (cce/set-font-scale 110))
|
||||
((equal (system-name) "rose-quine") (cce/set-font-scale 125))
|
||||
((cce/external-display-connected) (-> (cce/external-display-dpis)
|
||||
(first)
|
||||
(cdr)
|
||||
|
|
|
@ -44,7 +44,10 @@ in
|
|||
|
||||
home.file.".config/autostart/cantata.desktop".source = "${cantata}/share/applications/cantata.desktop";
|
||||
home.file.".config/autostart/signal-desktop.desktop".source = "${signal-desktop}/share/applications/signal-desktop.desktop";
|
||||
home.file.".config/autostart/discord.desktop".source = "${discord}/share/applications/discord.desktop";
|
||||
home.file.".config/autostart/discord.desktop" = {
|
||||
enable= false;
|
||||
source = "${discord}/share/applications/discord.desktop";
|
||||
};
|
||||
home.file.".config/autostart/element-desktop.desktop".source = "${element-desktop}/share/applications/element-desktop.desktop";
|
||||
|
||||
home.packages = [
|
||||
|
@ -63,8 +66,10 @@ in
|
|||
(mkNixGLWrapper { name="xournalpp"; })
|
||||
|
||||
(mkNixGLWrapper { name="element-desktop"; })
|
||||
(mkNixGLWrapper { name="neochat"; })
|
||||
(mkNixGLWrapper { name="discord"; })
|
||||
(mkNixGLWrapper { name="signal-desktop"; })
|
||||
(mkNixGLWrapper { name="tokodon"; })
|
||||
# (mkNixGLWrapper { name="tdesktop"; }) # telegram-desktop
|
||||
|
||||
pavucontrol
|
||||
|
@ -74,6 +79,8 @@ in
|
|||
|
||||
cataclysm-dda
|
||||
(mkNixGLWrapper { name="runelite"; })
|
||||
(mkNixGLWrapper { name="ryujinx"; })
|
||||
(mkNixGLWrapper { name="yuzu-mainline"; })
|
||||
|
||||
virt-manager
|
||||
libvirt
|
||||
|
|
|
@ -8,11 +8,13 @@
|
|||
#+PROPERTY: header-args:emacs-lisp :tangle code-base.el
|
||||
#+PROPERTY: header-args:yaml :tangle roles/endpoint/tasks/code-base.yml
|
||||
|
||||
#+ARROYO_EMACS_MODULE: code-base
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
#+ARROYO_MODULE_WANTS: cce/configure_packaging.org
|
||||
#+ARCOLOGY_KEY: cce/code-base
|
||||
|
||||
#+ARROYO_EMACS_MODULE: code-base
|
||||
#+ARROYO_MODULE_WANTS: cce/configure_packaging.org
|
||||
#+ARROYO_MODULE_WANTS: cce/diminish.org
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(provide 'cce/code-base)
|
||||
#+end_src
|
||||
|
@ -20,13 +22,14 @@
|
|||
I like having line numbers when I'm programming.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(setq linum-delay t
|
||||
linum-eager nil)
|
||||
(add-hook 'prog-mode-hook 'linum-mode)
|
||||
;; (setq linum-delay t
|
||||
;; linum-eager nil)
|
||||
(add-hook 'prog-mode-hook 'display-line-numbers-mode)
|
||||
#+end_src
|
||||
|
||||
Eldoc is useful wherever the major mode supports it
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(global-eldoc-mode)
|
||||
(diminish 'eldoc-mode)
|
||||
#+end_src
|
||||
|
|
|
@ -50,6 +50,7 @@ SCHEDULED: <2022-05-27 Fri>
|
|||
:PROPERTIES:
|
||||
:ID: 20220611T182415.660603
|
||||
:ROAM_REFS: https://github.com/NixOS/nixpkgs/pull/176978
|
||||
:ROAM_ALIASES: beetcamp
|
||||
:END:
|
||||
:LOGBOOK:
|
||||
- Note taken on [2022-06-11 Sat 18:24] \\
|
||||
|
@ -75,7 +76,7 @@ python3Packages.buildPythonPackage {
|
|||
|
||||
format = "pyproject";
|
||||
|
||||
propagatedBuildInputs = with python3Packages; [ setuptools poetry requests cached-property pycountry python-dateutil ordered-set ]
|
||||
propagatedBuildInputs = with python3Packages; [ setuptools poetry-core requests cached-property pycountry python-dateutil ordered-set ]
|
||||
++ (lib.optional propagateBeets [ beets ]);
|
||||
|
||||
postInstall = ''
|
||||
|
@ -110,6 +111,7 @@ python3Packages.buildPythonPackage {
|
|||
* File Organization
|
||||
:PROPERTIES:
|
||||
:ID: music-file-organization
|
||||
:ROAM_ALIASES: "Music File Organization"
|
||||
:END:
|
||||
|
||||
I keep my music in =~/Music= and a few subdirectories underneath it so that i can use [[id:cce/syncthing][Syncthing]]'s filtering to narrow the [[id:3182614c-9122-4b01-ac3f-9f99e56bfdbd][Music]] i sync to devices with less storage like the [[id:cosmo_communicator][Cosmo Communicator]] or whatever.
|
||||
|
@ -172,7 +174,7 @@ echo $TMPD
|
|||
* Beets Configuration
|
||||
|
||||
#+begin_src yaml :tangle ~/Music/beets/config.yaml
|
||||
plugins: fetchart embedart convert scrub replaygain lastgenre web acousticbrainz fetchart smartplaylist copyartifacts discogs bandcamp
|
||||
plugins: fetchart embedart convert scrub replaygain lastgenre web fetchart smartplaylist copyartifacts discogs bandcamp
|
||||
directory: /home/rrix/Music
|
||||
library: /home/rrix/Music/beets/musiclibrary.blb
|
||||
art_filename: albumart
|
||||
|
@ -214,7 +216,7 @@ import:
|
|||
log: /home/rrix/Music/beets/beet.log
|
||||
#+end_src
|
||||
|
||||
I use =beetcamp=:
|
||||
I use [[id:20220611T182415.660603][=beetcamp=]]:
|
||||
|
||||
#+begin_src yaml :tangle ~/Music/beets/config.yaml
|
||||
bandcamp:
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
:PROPERTIES:
|
||||
:ID: 20230201T121135.988658
|
||||
:ROAM_ALIASES: Bitwarden
|
||||
:END:
|
||||
#+TITLE: Bitwarden on NixOS/Home Manager
|
||||
#+filetags: :Project:
|
||||
|
||||
#+ARCOLOGY_KEY: cce/bitwarden
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
I used [[id:cce/the_standard_unix_password_manager][The Standard UNIX Password Manager]] but I would prefer to stop caring about that PGP key. I set up [[id:20230201T121604.003311][vaultwarden]] on [[id:20211120T220054.226284][The Wobserver]] and this will talk to that. There's also a [[id:cce/a_basic_firefox_installation][Firefox]] addon available.
|
||||
|
||||
* Bitwarden CLI client on [[id:cce/my_nixos_configuration][Endpoint Configuration]]
|
||||
|
||||
#+ARROYO_HOME_MODULE: hm/bitwarden.nix
|
||||
#+ARROYO_NIXOS_ROLE: endpoint
|
||||
#+ARROYO_EMACS_MODULE: bitwarden
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/hm/bitwarden.nix
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
home.packages = [ pkgs.bitwarden ];
|
||||
programs.rbw = {
|
||||
enable = true;
|
||||
settings = {
|
||||
email = "ryan@whatthefuck.computer";
|
||||
pinentry = "qt";
|
||||
base_url = "https://vault.whatthefuck.computer";
|
||||
};
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
** NEXT add [[https://github.com/seanfarley/emacs-bitwarden/][emacs-bitwarden]] or similar wrapper around =rbw=
|
||||
|
||||
#+begin_src emacs-lisp :tangle ~/org/cce/bitwarden.el
|
||||
|
||||
#+end_src
|
|
@ -156,12 +156,13 @@ Updating the Nixpkgs checkout can be by invoking something like =cce/update-nixp
|
|||
(let ((path "/home/rrix/Code/nixpkgs/"))
|
||||
(with-current-buffer (find-file-noselect path)
|
||||
(let* ((channel-status (split-string
|
||||
(plz "GET" "https://channels.nix.gsc.io/nixpkgs-unstable/latest")
|
||||
(plz "GET" "https://channels.nix.gsc.io/nixos-23.05/latest")
|
||||
" "))
|
||||
(nixpkgs-unstable-ts (string-to-number (second channel-status)))
|
||||
(nixpkgs-unstable (first channel-status)))
|
||||
(magit-fetch-all nil)
|
||||
(magit-merge-plain "origin/nixpkgs-unstable")
|
||||
(shell-command "git fetch --all")
|
||||
;; (magit-fetch-all nil)
|
||||
(magit-merge-plain "origin/nixos-23.05")
|
||||
(message "updated nixpkgs checkout to %s"
|
||||
(format-time-string "%c" nixpkgs-unstable-ts))))))
|
||||
(provide 'cce/nixpkgs)
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
#+PROPERTY: header-args :mkdirp yes :results none
|
||||
#+PROPERTY: header-args:emacs-lisp :tangle aggressive-indent.el
|
||||
|
||||
#+ARROYO_EMACS_MODULE: aggressive-indent
|
||||
#+ARCOLOGY_KEY: cce/aggressive-indent
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
#+ARROYO_EMACS_MODULE: aggressive-indent
|
||||
#+ARROYO_MODULE_WANTS: cce/basic_emacs_coding_config.org
|
||||
#+ARROYO_MODULE_WANTS: cce/diminish.org
|
||||
|
||||
Emacs has a package which will dynamically re-align code whenever I make changes to the buffer. For languages that don't use whitespace for defining context (python, makefile, for example), this is optimal and it does a good job showing me when I've made syntax errors. Sometimes it's a bit too annoying, but alas.
|
||||
|
||||
|
@ -18,5 +20,7 @@ Emacs has a package which will dynamically re-align code whenever I make changes
|
|||
(provide 'cce/aggressive-indent)
|
||||
(use-package aggressive-indent
|
||||
:diminish "⮕"
|
||||
:config (global-aggressive-indent-mode))
|
||||
:config
|
||||
(add-to-list 'aggressive-indent-excluded-modes 'shell-mode)
|
||||
(global-aggressive-indent-mode))
|
||||
#+end_src
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
:PROPERTIES:
|
||||
:ID: cce/company_code_completion
|
||||
:END:
|
||||
#+TITLE: Company Code Completion
|
||||
#+TITLE: Company Mode Code Completion
|
||||
#+filetags: :Emacs:CCE:Coding:
|
||||
#+PROPERTY: header-args :mkdirp yes :results none
|
||||
#+PROPERTY: header-args:emacs-lisp :tangle company.el
|
||||
|
@ -44,3 +44,4 @@ These four combined give me basic completion in all buffers, based on words in t
|
|||
(use-package company-prescient :init (company-prescient-mode +1))
|
||||
#+END_SRC
|
||||
#+ARROYO_MODULE_WANTS: cce/selectrum_etc.org
|
||||
#+ARROYO_MODULE_WANTS: cce/diminish.org
|
||||
|
|
|
@ -9,37 +9,43 @@ Okay, so [[id:cce/selectrum_etc][Consult]] provides a composable, high performan
|
|||
|
||||
[[https://github.com/jgru/consult-org-roam/][jgru/consult-org-roam]] provides a bunch of nice features which should be bound in to my org-roam command prefix.. It's not in MELPA or anything, just another thing that expects me to use =straight-use-package= to load it --- well here is some fucked up stuff for providing it to [[id:arroyo/emacs][Arroyo Emacs]]'s init generator via =ARROYO_HOME_EPKGS=.
|
||||
|
||||
#+ARROYO_EMACS_MODULE: consult-org-roam
|
||||
#+ARROYO_MODULE_WANTS: cce/configure_packaging.org
|
||||
#+ARROYO_MODULE_WANTS: cce/evil_mode.org
|
||||
#+ARROYO_MODULE_WANTS: cce/org_mode_installation.org
|
||||
#+ARROYO_EMACS_MODULE: consult-org-roam
|
||||
#+ARROYO_MODULE_WANTS: cce/diminish.org
|
||||
#+ARROYO_MODULE_WANTS: cce/org-roam.org
|
||||
#+ARROYO_MODULE_WANTS: cce/selectrum_etc.org
|
||||
|
||||
#+ARCOLOGY_KEY: cce/consult-buffer-org-roam
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
#+begin_src emacs-lisp :tangle consult-org-roam.el :results none
|
||||
(condition-case nil
|
||||
(use-package consult-org-roam
|
||||
:init
|
||||
(require 'consult-org-roam)
|
||||
;; Activate the minor-mode
|
||||
(consult-org-roam-mode 1)
|
||||
;; restore behavior of consult-buffer overridden by consult-org-roam-buffer... prefer mine.
|
||||
(consult-customize
|
||||
consult--source-buffer
|
||||
:items (lambda ()
|
||||
(consult--buffer-query :sort 'visibility
|
||||
:as #'buffer-name)))
|
||||
:custom
|
||||
(consult-org-roam-grep-func #'consult-ripgrep)
|
||||
:config
|
||||
;; Eventually suppress previewing for certain functions
|
||||
(consult-customize
|
||||
consult-org-roam-forward-links
|
||||
:preview-key (kbd "M-."))
|
||||
:bind (:map org-roam-prefix-map)
|
||||
("b" . consult-org-roam-backlinks)
|
||||
("/" . consult-org-roam-search)
|
||||
:after (consult org-roam))
|
||||
(error nil))
|
||||
(use-package consult-org-roam
|
||||
:diminish
|
||||
:init
|
||||
(message "Loading consult-org-roam HERE")
|
||||
(require 'consult-org-roam)
|
||||
;; Activate the minor-mode
|
||||
(consult-org-roam-mode 1)
|
||||
;; restore behavior of consult-buffer overridden by consult-org-roam-buffer... prefer mine.
|
||||
:custom
|
||||
(consult-org-roam-grep-func #'consult-ripgrep)
|
||||
:config
|
||||
;; Eventually suppress previewing for certain functions
|
||||
(message "Trying to override consult-org-roam-buffer behavior HERE...")
|
||||
(consult-org-roam-buffer--customize-source-buffer nil)
|
||||
(consult-customize
|
||||
consult-org-roam-forward-links
|
||||
:preview-key (kbd "M-."))
|
||||
:bind (:map org-roam-prefix-map)
|
||||
("b" . consult-org-roam-backlinks)
|
||||
("/" . consult-org-roam-search)
|
||||
:hook
|
||||
(after-cce . (lambda ()
|
||||
(message "Trying to override consult-org-roam-buffer behavior HERE (after-cce)...")
|
||||
(consult-org-roam-buffer--customize-source-buffer nil)))
|
||||
:after (consult org-roam))
|
||||
|
||||
(provide 'cce/consult-org-roam)
|
||||
#+end_src
|
||||
|
@ -71,10 +77,6 @@ in epkgs.melpaBuild {
|
|||
});
|
||||
#+end_src
|
||||
|
||||
#+ARCOLOGY_KEY: cce/consult-buffer-org-roam
|
||||
#+ARROYO_MODULE_WANTS: cce/org-roam.org
|
||||
#+ARROYO_MODULE_WANTS: cce/selectrum_etc.org
|
||||
|
||||
#+begin_src emacs-lisp :tangle consult-org-roam.el :results none
|
||||
(condition-case nil
|
||||
(progn
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
:PROPERTIES:
|
||||
:ID: 20230321T143139.441973
|
||||
:END:
|
||||
#+TITLE: My Brother Printer and CUPS Setup
|
||||
#+filetags: :Project:
|
||||
|
||||
#+ARROYO_NIXOS_MODULE: nixos/cups.nix
|
||||
#+ARROYO_NIXOS_EXCLUDE: droid
|
||||
#+AUTO_TANGLE: t
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/cups.nix
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
# environment.systemPackages = with pkgs; [ gscan2pdf skanlite gocr ];
|
||||
|
||||
services.printing.enable = true;
|
||||
services.printing.drivers = [ pkgs.brlaser ];
|
||||
hardware.printers.ensurePrinters = [
|
||||
{
|
||||
name = "brotha";
|
||||
description = "Brother DCP-L2550DW";
|
||||
deviceUri = "dnssd://Brother%20DCP-L2550DW%20series._ipp._tcp.local/?uuid=e3248000-80ce-11db-8000-b42200ae9c8e";
|
||||
location = "tearoom";
|
||||
model = "everywhere";
|
||||
}
|
||||
];
|
||||
|
||||
hardware.sane.enable = true;
|
||||
services.saned.enable = true;
|
||||
}
|
||||
#+end_src
|
||||
|
||||
* NEXT gscan2pdf broken [[https://github.com/NixOS/nixpkgs/issues/223446][in nixpkgs-unstable]]
|
||||
SCHEDULED: <2023-04-03 Mon>
|
|
@ -4,7 +4,7 @@
|
|||
:ROAM_ALIASES: Datasette
|
||||
:END:
|
||||
#+title: Datasette: An open source multi-tool for exploring and publishing data
|
||||
#+filetags: :Archive:CCE:Development:Tools:
|
||||
#+filetags: :Project:Archive:CCE:Development:Tools:
|
||||
#+AUTO_TANGLE: t
|
||||
#+ARCOLOGY_KEY: cce/datasette
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
@ -19,7 +19,8 @@ Datasette is aimed at data journalists, museum curators, archivists, local gover
|
|||
|
||||
These could be used to generate [[id:1fb8fb45-fac5-4449-a347-d55118bb377e][org-mode]] files for [[id:1d917282-ecf4-4d4c-ba49-628cbb4bb8cc][The Arcology Project]] and my [[id:knowledge_base][Knowledge Base]]....
|
||||
|
||||
* iNaturalist to [[roam:Sqlite][Sqlite]]
|
||||
* NEXT pull ~/DataExports from [[id:20211029T115928.954970][Virtuous Cassette]] and move to [[id:cce/syncthing][Syncthing]]
|
||||
* Inaturalist to [[roam:Sqlite][Sqlite]]
|
||||
:PROPERTIES:
|
||||
:ID: 20220727T152924.019338
|
||||
:END:
|
||||
|
|
17
delve.org
17
delve.org
|
@ -4,7 +4,7 @@
|
|||
:ROAM_ALIASES: delve publicimageltd/delve
|
||||
:END:
|
||||
#+TITLE: publicimageltd/delve
|
||||
#+filetags: :Archive:CCE:
|
||||
#+filetags: :Project:Archive:CCE:
|
||||
|
||||
#+ARCOLOGY_KEY: cce/delve
|
||||
#+AUTO_TANGLE: t
|
||||
|
@ -21,12 +21,12 @@ Opening Delve the first time, you can browse your zettelkasten by ROAM_TAG, or u
|
|||
#+END_QUOTE
|
||||
|
||||
#+begin_src emacs-lisp :tangle delve.el
|
||||
(use-package lister)
|
||||
(use-package delve
|
||||
:config
|
||||
(require 'delve-minor-mode)
|
||||
(evil-set-initial-state 'delve-mode 'motion)
|
||||
(delve-global-minor-mode))
|
||||
;; (use-package lister)
|
||||
;; (use-package delve
|
||||
;; :config
|
||||
;; (require 'delve-minor-mode)
|
||||
;; (evil-set-initial-state 'delve-mode 'motion)
|
||||
;; (delve-global-minor-mode))
|
||||
(provide 'cce/delve)
|
||||
#+end_src
|
||||
|
||||
|
@ -53,3 +53,6 @@ delve = epkgs.melpaBuild {
|
|||
};
|
||||
};
|
||||
#+end_src
|
||||
|
||||
* NEXT Investigate patching failure to =(require 'delve)=
|
||||
* NEXT Configure this with useful dashboards
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
:PROPERTIES:
|
||||
:roam_refs: https://github.com/emacsmirror/diminish/blob/master/diminish.el#L129
|
||||
:ID: 20220907T235417.715959
|
||||
:END:
|
||||
#+title: diminish/diminish.el at master · emacsmirror/diminish
|
||||
#+filetags: :Archive:
|
||||
|
||||
#+ARCOLOGY_KEY: lionsrear/poetry/diminish.el
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
[[file:archive.org][Archive]] [[id:Poetry][Poetry]] [[id:cce/emacs][Emacs]]
|
||||
|
||||
Just reading some code...
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
;; Plumber Bob was not from Seattle, my grey city, for rainy Seattle is a
|
||||
;; city of interiors, a city of the self-diminished. When I moved here one
|
||||
;; sunny June I was delighted to find that ducks and geese were common in
|
||||
;; the streets. But I hoped to find a loon or two, and all I found were
|
||||
;; ducks and geese. I wondered about this; I wondered why there were no
|
||||
;; loons in Seattle; but my confusion resulted from my ignorance of the
|
||||
;; psychology of rain, which is to say my ignorance of diminished modes.
|
||||
;; What I needed, and lacked, was a way to discover they were there.
|
||||
|
||||
;;;###autoload
|
||||
(defun diminished-modes ()
|
||||
"Echo all active diminished or minor modes as if they were minor.
|
||||
#+end_src
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
;; A human mind is a Black Forest of diminished modes. Some are dangerous;
|
||||
;; most of the mind of an intimate is a secret stranger, and these diminished
|
||||
;; modes are rendered more unpredictable by their long isolation from the
|
||||
;; corrective influence of interaction with reality. The student of history
|
||||
;; learns that this description applies to whole societies as well. In some
|
||||
;; ways the self-diminished are better able to discern the night worker.
|
||||
;; They are rendered safer by their heightened awareness of others'
|
||||
;; diminished modes, and more congenial by the spare blandness of their own
|
||||
;; mode lines. To some people rain is truly depressing, but others it just
|
||||
;; makes pensive, and, forcing them indoors where they may not have the
|
||||
;; luxury of solitude, teaches them to self-diminish. That was what I had
|
||||
;; not understood when I was searching for loons among the ducks and geese.
|
||||
;; Loons come to Seattle all the time, but the ones that like it learn to be
|
||||
;; silent, learn to self-diminish, and take on the colors of ducks and geese.
|
||||
;; Now, here a dozen years, I can recognize them everywhere, standing quietly
|
||||
;; in line with the ducks and geese at the espresso counter, gazing placidly
|
||||
;; out on the world through loon-red eyes, thinking secret thoughts.
|
||||
#+end_src
|
||||
|
||||
I use diminish, extensively:
|
||||
|
||||
#+ARROYO_EMACS_MODULE: diminish
|
||||
|
||||
#+begin_src emacs-lisp :tangle ~/org/cce/diminish.el
|
||||
(use-package diminish)
|
||||
(provide 'cce/diminish)
|
||||
#+end_src
|
40
direnv.org
40
direnv.org
|
@ -6,7 +6,7 @@
|
|||
#+filetags: :CCE:
|
||||
#+ARCOLOGY_KEY: cce/direnv
|
||||
|
||||
#+PROPERTY: header-args :mkdirp yes :results none
|
||||
#+PROPERTY: header-args :mkdirp yes
|
||||
#+PROPERTY: header-args:emacs-lisp :tangle direnv.el
|
||||
|
||||
#+ARROYO_EMACS_MODULE: direnv
|
||||
|
@ -38,6 +38,7 @@ Anyways it has an [[id:cce/emacs][Emacs]] package which works really well and re
|
|||
(provide 'cce/direnv)
|
||||
#+end_src
|
||||
|
||||
|
||||
#+ARROYO_HOME_MODULE: hm/direnv.nix
|
||||
#+begin_src nix :tangle ~/arroyo-nix/hm/direnv.nix
|
||||
{pkgs, ...}:
|
||||
|
@ -58,3 +59,40 @@ Anyways it has an [[id:cce/emacs][Emacs]] package which works really well and re
|
|||
'';
|
||||
}
|
||||
#+end_src
|
||||
|
||||
With =direnv= activated, any directory with a =shell.nix= in it and an =.envrc= file that says =use nix= in it can be allowed to spawn development environments:
|
||||
|
||||
#+begin_src shell
|
||||
cat ~/org/arcology-fastapi/.envrc
|
||||
#+end_src
|
||||
|
||||
#+results:
|
||||
: use nix
|
||||
|
||||
* Direnv [[id:arroyo/system-cache][arroyo-db]] integration
|
||||
:PROPERTIES:
|
||||
:ID: 20230526T105534.711282
|
||||
:END:
|
||||
|
||||
One of the issues of doing [[id:cce/literate_programming][Literate Programming with Org Babel]] is that if I work inside of my [[id:cce/org-roam][org-roam]] directory the direnv stuff won't map to the tangled directory. If I add a =ARROYO_DIRENV_DIR= file property to a document it will use the directory environment from that directory instead of the org-roam directory:
|
||||
|
||||
#+begin_src emacs-lisp :results none
|
||||
(with-eval-after-load "arroyo-db"
|
||||
(add-to-list 'arroyo-db-keywords "ARROYO_DIRENV_DIR")
|
||||
(defun direnv--directory ()
|
||||
"Return the relevant directory for the current buffer, or nil."
|
||||
(let* ((buffer (or (buffer-base-buffer) (current-buffer)))
|
||||
(mode (buffer-local-value 'major-mode buffer))
|
||||
(file-name (buffer-file-name buffer))
|
||||
(arroyo-maybe (when (and file-name
|
||||
(equal (file-name-extension file-name) "org"))
|
||||
(arroyo-db-get "ARROYO_DIRENV_DIR" (expand-file-name file-name))))
|
||||
(buffer-directory
|
||||
(cond (arroyo-maybe
|
||||
arroyo-maybe)
|
||||
(file-name
|
||||
(file-name-directory file-name))
|
||||
((apply #'direnv--provided-mode-derived-p mode direnv-non-file-modes)
|
||||
default-directory))))
|
||||
buffer-directory)))
|
||||
#+end_src
|
||||
|
|
|
@ -16,15 +16,55 @@
|
|||
|
||||
I'm trying something new, coming back to a modeline customization suite. This time, we find ourselves with the [[https://github.com/seagle0128/doom-modeline][Doom Mode Line]], which I use in a pretty "out of the box" configuration for now. I add icon representations for [[id:cce/exwm][EXWM]] buffers so that they're not just default "document" icons.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package all-the-icons)
|
||||
#+begin_src emacs-lisp :noweb yes
|
||||
(use-package nerd-icons)
|
||||
(use-package doom-modeline
|
||||
:after all-the-icons
|
||||
:after nerd-icons
|
||||
:custom
|
||||
(nerd-icons-font-family "Symbols Nerd Font Mono")
|
||||
:config
|
||||
(setq doom-modeline-unicode-fallback t
|
||||
doom-modeline-enable-word-count nil)
|
||||
(doom-modeline-mode 1))
|
||||
(add-to-list 'all-the-icons-mode-icon-alist
|
||||
'(exwm-mode all-the-icons-faicon "desktop"
|
||||
:height 1.0 :face all-the-icons-purple))
|
||||
doom-modeline-enable-word-count nil
|
||||
doom-modeline-minor-modes t)
|
||||
(doom-modeline-mode 1)
|
||||
(add-to-list 'nerd-icons-mode-icon-alist
|
||||
'(exwm-mode nerd-icons-faicon "nf-fa-desktop"
|
||||
:height 1.0 :face all-the-icons-purple))
|
||||
<<org-titles-modeline>>
|
||||
)
|
||||
#+end_src
|
||||
|
||||
* [[id:cce/org-roam][org-roam]] buffer titles in Doom Modeline
|
||||
:PROPERTIES:
|
||||
:ID: 20230717T093538.797067
|
||||
:END:
|
||||
|
||||
This function overrides/extends the function which Doom Modeline uses to set the buffer title in the modeline. It queries the [[id:cce/org-roam][org-roam]] database for the file's title, and falls back to the ='auto= [[help:doom-modeline-buffer-file-name-style]] if there isn't one.
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref org-titles-modeline
|
||||
(defun doom-modeline-buffer-file-name ()
|
||||
"Propertize file name based on `doom-modeline-buffer-file-name-style'."
|
||||
(let* ((buffer-file-name (file-local-name (or (buffer-file-name (buffer-base-buffer)) "")))
|
||||
(buffer-file-truename (file-local-name
|
||||
(or buffer-file-truename (file-truename buffer-file-name) "")))
|
||||
(file-name
|
||||
(when (equal major-mode 'org-mode)
|
||||
(caar (org-roam-db-query [:select title :from files :where (= file $s1)]
|
||||
(buffer-file-name)))))
|
||||
(file-name-fallback
|
||||
(if (doom-modeline-project-p)
|
||||
(doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink 'shrink 'hide)
|
||||
(propertize "%b" 'face 'doom-modeline-buffer-file)))
|
||||
(file-name
|
||||
(propertize (or file-name file-name-fallback) 'face 'doom-modeline-buffer-file)))
|
||||
(propertize (if (string-empty-p file-name)
|
||||
(propertize "%b" 'face 'doom-modeline-buffer-file)
|
||||
file-name)
|
||||
'mouse-face 'mode-line-highlight
|
||||
'help-echo (concat buffer-file-truename
|
||||
(unless (string= (file-name-nondirectory buffer-file-truename)
|
||||
(buffer-name))
|
||||
(concat "\n" (buffer-name)))
|
||||
"\nmouse-1: Previous buffer\nmouse-3: Next buffer")
|
||||
'local-map mode-line-buffer-identification-keymap)))
|
||||
#+end_src
|
||||
|
|
|
@ -5,11 +5,17 @@
|
|||
#+TITLE: DrawingBot
|
||||
#+FILETAGS: :Software:CCE:
|
||||
|
||||
#+ARCOLOGY_KEY: cce/drawingbot
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
#+begin_quote
|
||||
DrawingBotV3 is a software for converting images to line drawings for Plotters / Drawing Machines / 3D printers. It also serves as an application for visual artists to create stylised line drawings from images / video
|
||||
#+end_quote
|
||||
|
||||
* DrawingBot V3 on NixOS
|
||||
:PROPERTIES:
|
||||
:ID: 20221228T201404.439331
|
||||
:END:
|
||||
|
||||
#+ARROYO_HOME_MODULE: hm/drawingbot.nix
|
||||
#+ARROYO_NIXOS_ROLE: endpoint
|
||||
|
|
|
@ -24,8 +24,7 @@ I use [[id:cce/emacs_and_the_language_server_protocol][Language Server Protocol]
|
|||
(use-package elixir-mode
|
||||
:config
|
||||
(setq lsp-ui-flycheck-enable 1)
|
||||
(setq lsp-clients-elixir-server-executable
|
||||
'("~/Code/elixir-ls/language_server.sh"))
|
||||
(setq lsp-elixir-server-command '("elixir-ls"))
|
||||
:hook
|
||||
(elixir-mode . lsp)
|
||||
(elixir-mode . company-mode)
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
:init
|
||||
(dashboard-setup-startup-hook)
|
||||
(setq initial-buffer-choice (lambda () (get-buffer "*dashboard*"))
|
||||
dashboard-banner-logo-title "Welcome to Your System"
|
||||
dashboard-startup-banner "~/org/data/dashboard-logo.png"
|
||||
dashboard-banner-logo-title "Welcome Home to the Arcology"
|
||||
dashboard-startup-banner "~/org/data/arcology.png"
|
||||
dashboard-center-content t
|
||||
show-week-agenda-p t)
|
||||
(setq dashboard-items '((recents . 5)
|
||||
|
|
|
@ -6,11 +6,14 @@
|
|||
#+filetags: :CCE:Emacs:Code:
|
||||
#+PROPERTY: header-args :mkdirp yes :results none
|
||||
#+PROPERTY: header-args:emacs-lisp :tangle evil-mode.el
|
||||
#+ARROYO_EMACS_MODULE: evil-mode
|
||||
|
||||
#+ARCOLOGY_KEY: cce/evil-mode
|
||||
#+ARROYO_MODULE_WANTS: cce/configure_packaging.org
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
#+ARROYO_EMACS_MODULE: evil-mode
|
||||
#+ARROYO_MODULE_WANTS: cce/diminish.org
|
||||
#+ARROYO_MODULE_WANTS: cce/configure_packaging.org
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(provide 'cce/evil-mode)
|
||||
#+end_src
|
||||
|
@ -60,6 +63,7 @@ Syndicate is evil bindings and support for org-mode.
|
|||
(use-package evil-org
|
||||
:ensure t
|
||||
:after org
|
||||
:diminish
|
||||
:hook (org-mode . (lambda () (evil-org-mode)))
|
||||
:init
|
||||
(fset 'evil-redirect-digit-argument 'ignore)
|
||||
|
@ -102,6 +106,22 @@ In my [[id:cce/text_editing_fundamental_opinions][Text Editing Fundamental Opini
|
|||
(setq evil-respect-visual-line-mode t)
|
||||
#+end_src
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package evil-args
|
||||
|
||||
:bind
|
||||
(:map evil-normal-state-map
|
||||
("L" . evil-forward-arg)
|
||||
("H" . evil-backward-arg))
|
||||
(:map evil-motion-state-map
|
||||
("L" . evil-forward-arg)
|
||||
("H" . evil-backward-arg))
|
||||
(:map evil-inner-text-objects-map
|
||||
("a" . evil-inner-arg))
|
||||
(:map evil-inner-text-objects-map
|
||||
("a" . evil-outer-arg)))
|
||||
#+end_src
|
||||
|
||||
* visual line commands
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
|
|
65
exwm.org
65
exwm.org
|
@ -4,15 +4,13 @@
|
|||
#+TITLE: EXWM
|
||||
#+filetags: :Emacs:CCE:EXWM:Mind:Bending:
|
||||
#+PROPERTY: header-args :mkdirp yes :results none
|
||||
#+PROPERTY: header-args:emacs-lisp :tangle exwm.el
|
||||
|
||||
,#+ARROYO_EMACS_MODULE: exwm
|
||||
#+ARROYO_EMACS_MODULE: exwm
|
||||
|
||||
#+ARCOLOGY_KEY: cce/exwm
|
||||
#+CCE_PREDICATE: (cce/using-exwm)
|
||||
#+CCE_PRIORITY: 20
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
#+begin_src emacs-lisp :tangle ~/org/cce/exwm.el
|
||||
(provide 'cce/exwm)
|
||||
#+end_src
|
||||
|
||||
|
@ -27,13 +25,13 @@ It's configured with some simple quality-of-life improvements, outlined in short
|
|||
- =S-p= brings up a simple shell command runner, I'd like to add =.desktop= support eventually.
|
||||
- EXWM runs in =ido= support mode, which allows it to work with other things that interact with the minibuffer.
|
||||
|
||||
#+begin_src emacs-lisp :noweb yes
|
||||
#+begin_src emacs-lisp :noweb yes :tangle ~/org/cce/exwm.el
|
||||
(use-package exwm
|
||||
:init
|
||||
(setq exwm-debug nil)
|
||||
:commands (exwm-enable)
|
||||
:config
|
||||
(setq exwm-workspace-number 2)
|
||||
(setq exwm-workspace-number 6)
|
||||
;; rename buffers to match window title
|
||||
(defun cce/exwm-rename-buffer ()
|
||||
(interactive)
|
||||
|
@ -51,23 +49,44 @@ It's configured with some simple quality-of-life improvements, outlined in short
|
|||
(exwm-input-set-key (kbd "s-k") #'other-window)
|
||||
(exwm-input-set-key (kbd "s-r") #'exwm-reset)
|
||||
(exwm-input-set-key (kbd "s-w") #'exwm-workspace-switch)
|
||||
(exwm-input-set-key (kbd "s-o") #'evil-window-rotate-downwards)
|
||||
(push (kbd "s-j") exwm-input-prefix-keys)
|
||||
(push (kbd "s-k") exwm-input-prefix-keys)
|
||||
(push (kbd "s-r") exwm-input-prefix-keys)
|
||||
(push (kbd "s-o") exwm-input-prefix-keys)
|
||||
(mapcar (lambda (it)
|
||||
(exwm-input-set-key (kbd (format "s-%d" it))
|
||||
`(lambda ()
|
||||
(interactive)
|
||||
(exwm-workspace-switch-create ,it))))
|
||||
(number-sequence 0 exwm-workspace-number))
|
||||
;; go to previously selected workspace
|
||||
(defun cce/exwm-record-before-workspace-change (ws &optional force)
|
||||
(setq cce-exwm-last-workspace exwm-workspace--current))
|
||||
(advice-add #'exwm-workspace-switch :before #'cce/exwm-record-before-workspace-change)
|
||||
(defun cce-exwm-workspace-back ()
|
||||
(interactive)
|
||||
(exwm-workspace-switch cce-exwm-last-workspace))
|
||||
(exwm-input-set-key (kbd "s-<tab>") #'cce-exwm-workspace-back)
|
||||
;; switch buffers on different displays
|
||||
(setq exwm-workspace-show-all-buffers t)
|
||||
(setq exwm-layout-show-all-buffers t)
|
||||
;; xrandr
|
||||
<<exwm-xrandr>>
|
||||
(defvar cce-start-exwm t)
|
||||
;; manage configurations
|
||||
<<exwm-manage-configurations>>
|
||||
;; startup handling
|
||||
(defvar cce-start-exwm nil)
|
||||
(defun cce/exwm-init-command-line-args ()
|
||||
"hook for command-line-functions"
|
||||
(if (setq command-line-args (delete command-line-args "--no-exwm"))
|
||||
(setq cce-start-exwm nil)
|
||||
(setq cce-start-exwm t)))
|
||||
(if (setq command-line-args (delete command-line-args "--exwm"))
|
||||
(setq cce-start-exwm t)
|
||||
(setq cce-start-exwm nil)))
|
||||
(add-to-list 'command-line-functions #'cce/exwm-init-command-line-args)
|
||||
(defun cce/exwm-init (&rest args)
|
||||
(when cce-start-exwm
|
||||
(apply #'exwm-init args)))
|
||||
(exwm-input--update-global-prefix-keys)
|
||||
:hook
|
||||
(exwm-update-class . cce/exwm-rename-buffer)
|
||||
(exwm-update-title . cce/exwm-rename-buffer)
|
||||
|
@ -94,11 +113,33 @@ EXWM also supports multiple monitors, using the fairly well supported =XRANDR= p
|
|||
- [[id:cce/exwm_input_simulation][EXWM Input Simulation]]
|
||||
- [[id:cce/exwm_should_ignore_plasma_notifications][EXWM should ignore Plasma notifications]]
|
||||
- [[id:cce/picom][compton on EXWM startup]]
|
||||
- [[id:20230221T102917.352842][Consult Buffer Source for EXWM Windows]]
|
||||
|
||||
* Rules for new Windows
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref exwm-manage-configurations
|
||||
(unless (boundp 'exwm-manage-configurations) (setq exwm-manage-configurations nil))
|
||||
(mapcar (lambda (it)
|
||||
(add-to-list 'exwm-manage-configurations it))
|
||||
(list
|
||||
'((equal exwm-class-name "Cantata")
|
||||
workspace 3)
|
||||
'((equal exwm-class-name "Signal")
|
||||
workspace 2)
|
||||
'((equal exwm-class-name "Element")
|
||||
workspace 2)
|
||||
'((equal exwm-class-name "virt-manager")
|
||||
workspace 5)
|
||||
'((s-contains? "Computers :(" exwm-title)
|
||||
workspace 2)
|
||||
'((s-contains? "Picture-in-Picture" exwm-title)
|
||||
floating nil)))
|
||||
#+end_src
|
||||
|
||||
* Deeper Web Integration with Emacs
|
||||
|
||||
eventually move this in to the firefox integration page
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
#+begin_src emacs-lisp :tangle ~/org/cce/exwm.el
|
||||
(use-package exwm-edit)
|
||||
#+end_src
|
||||
|
|
|
@ -5,9 +5,12 @@
|
|||
#+filetags: :Emacs:CCE:EXWM:
|
||||
#+PROPERTY: header-args :mkdirp yes :results none
|
||||
#+PROPERTY: header-args:emacs-lisp :tangle exwm-input-simulation.el
|
||||
|
||||
#+ARROYO_EMACS_MODULE: exwm-input-simulation
|
||||
#+ARROYO_MODULE_WANTS: cce/exwm.org
|
||||
|
||||
#+ARCOLOGY_KEY: cce/exwm-input-simulation
|
||||
,#+ARROYO_EMACS_MODULE: exwm-input-simulation
|
||||
,#+ARROYO_MODULE_WANTS: cce/exwm.org
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(provide 'cce/exwm-input-simulation)
|
||||
|
@ -26,6 +29,7 @@
|
|||
(,(kbd "C-n") . down)
|
||||
(,(kbd "C-a") . home)
|
||||
(,(kbd "C-e") . end)
|
||||
(,(kbd "M-y") . ,(kbd "C-c"))
|
||||
(,(kbd "C-y") . ,(kbd "C-v"))
|
||||
(,(kbd "C-M-b") . ,(kbd "C-b"))))
|
||||
|
||||
|
|
|
@ -5,9 +5,12 @@
|
|||
#+filetags: :Emacs:CCE:EXWM:
|
||||
#+PROPERTY: header-args :mkdirp yes :results none
|
||||
#+PROPERTY: header-args:emacs-lisp :tangle exwm-ignore-plasma.el
|
||||
|
||||
#+ARCOLOGY_KEY: cce/exwm-ignore-plasma
|
||||
,#+ARROYO_EMACS_MODULE: exwm-ignore-plasma
|
||||
,#+ARROYO_MODULE_WANTS: cce/exwm.org
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
#+ARROYO_EMACS_MODULE: exwm-ignore-plasma
|
||||
#+ARROYO_MODULE_WANTS: cce/exwm.org
|
||||
|
||||
#+begin_src emacs-lisp :exports none
|
||||
(provide 'cce/exwm-ignore-plasma)
|
||||
|
@ -20,10 +23,12 @@ work. They don't really do much to identify themselves, =exwm--ewmh-state= is up
|
|||
floating and management check in =exwm-manage--manage-window=.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(setq exwm-manage-configurations
|
||||
'(((and (equal exwm-class-name "plasmashell")
|
||||
(memq xcb:Atom:_NET_WM_WINDOW_TYPE_NOTIFICATION exwm-window-type))
|
||||
managed nil)
|
||||
((and (equal exwm-class-name "plasmashell")
|
||||
(memq xcb:Atom:_NET_WM_STATE_ABOVE exwm-window-type)))))
|
||||
(unless (boundp 'exwm-manage-configurations) (setq exwm-manage-configurations nil))
|
||||
(add-to-list 'exwm-manage-configurations
|
||||
'((and (equal exwm-class-name "plasmashell")
|
||||
(memq xcb:Atom:_NET_WM_WINDOW_TYPE_NOTIFICATION exwm-window-type))
|
||||
managed nil))
|
||||
(add-to-list 'exwm-manage-configurations
|
||||
'((and (equal exwm-class-name "plasmashell")
|
||||
(memq xcb:Atom:_NET_WM_STATE_ABOVE exwm-window-type))))
|
||||
#+end_src
|
||||
|
|
|
@ -3,11 +3,14 @@
|
|||
:ROAM_ALIASES: feed2toot
|
||||
:ROAM_REFS: https://gitlab.com/chaica/feed2toot https://feed2toot.readthedocs.io/en/latest/
|
||||
:END:
|
||||
#+TITLE: Posting Arcology Feeds to the Fediverse Automatically
|
||||
#+TITLE: Posting Arcology Feeds to the Fediverse Automatically with feed2toot (deprecated)
|
||||
#+filetags: :Project:CCE:Fediverse:
|
||||
|
||||
#+ARCOLOGY_KEY: arcology/feed2toot
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
#+AUTO_TANGLE: t
|
||||
|
||||
#+begin_quote
|
||||
Feed2toot automatically parses rss feeds, identifies new posts and posts them on the +Mastodon+ [[id:62538db5-d94a-47c3-9998-086ded91fd88][Fediverse]] social network.
|
||||
#+end_quote
|
||||
|
@ -60,7 +63,7 @@ buildPythonPackage rec {
|
|||
So I have a few [[id:20211219T144255.001827][Arcology Sites]], each of these needs its own configuration file passed to the =feed2toot= invocation. This queries [[id:arcology/arroyo-page][Arroyo Arcology Generator]]'s [[id:arcology/arroyo/feed][arcology.arroyo.Feed]] to generate a file with each group of =(site, visibility)= of feeds in the database.
|
||||
|
||||
#+NAME: site-filter
|
||||
#+begin_src emacs-lisp :var site-filter="lionsrear" :var site-domain="https://thelionsrear.com/" :results raw
|
||||
#+begin_src emacs-lisp :var site-filter="lionsrear" :var site-domain="https://thelionsrear.com/" :results drawer
|
||||
(setq arcology-sites '(("lionsrear" . "https://thelionsrear.com/")
|
||||
("garden" . "https://arcology.garden/")
|
||||
("cce" . "https://cce.whatthefuck.computer/")
|
||||
|
@ -100,11 +103,14 @@ So I have a few [[id:20211219T144255.001827][Arcology Sites]], each of these nee
|
|||
#+end_src
|
||||
|
||||
#+results: site-filter
|
||||
:results:
|
||||
~/arroyo-nix/files/feed2toot-uris-garden-private.txt
|
||||
~/arroyo-nix/files/feed2toot-uris-lionsrear-public.txt
|
||||
~/arroyo-nix/files/feed2toot-uris-garden-public.txt
|
||||
~/arroyo-nix/files/feed2toot-uris-arcology-public.txt
|
||||
~/arroyo-nix/files/feed2toot-uris-garden-public.txt
|
||||
~/arroyo-nix/files/feed2toot-uris-lionsrear-unlisted.txt
|
||||
~/arroyo-nix/files/feed2toot-uris-lionsrear-public.txt
|
||||
~/arroyo-nix/files/feed2toot-uris-cce-public.txt
|
||||
:end:
|
||||
|
||||
* INPROGRESS deploy to [[id:20211120T220054.226284][The Wobserver]]
|
||||
:LOGBOOK:
|
||||
|
@ -113,8 +119,8 @@ So I have a few [[id:20211219T144255.001827][Arcology Sites]], each of these nee
|
|||
|
||||
=feed2toot= operates with [[https://feed2toot.readthedocs.io/en/latest/configure.html#create-feed2toot-configuration][INI configuration files]] and luckily enough =nixpkgs= includes a way to convert =attrsets= to =ini= files in =lib.generators.toINI=; this is wrapped in a function which takes the basic per-instance configuration details including the uri-list which are generated above and then creates a [[roam:SystemD]] service manifest and timer to poll the site and post the toots. Easy peazy.
|
||||
|
||||
#+ARROYO_NIXOS_MODULE: nixos/feed2toot.nix
|
||||
#+ARROYO_NIXOS_ROLE: server
|
||||
,#+ARROYO_NIXOS_MODULE: nixos/feed2toot.nix
|
||||
,#+ARROYO_NIXOS_ROLE: server
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/feed2toot.nix :noweb yes
|
||||
{ pkgs, lib, config, ... }:
|
||||
|
@ -137,13 +143,18 @@ let
|
|||
cache.cachefile = "/var/cache/feed2toot/${instance}.db";
|
||||
lock.lock_file = "/run/feed2toot/${instance}.lock";
|
||||
rss.uri_list = builtins.path { path = uriList; };
|
||||
rss.toot = "NEW: {link} \\n {summary}";
|
||||
rss.toot = "NEW by @rrix@notes.whatthefuck.computer: {link} \\n {summary}";
|
||||
rss.toot_max_len = 10000;
|
||||
hashtaglist.several_words_hashtags_list = tagListFile;
|
||||
feedparser.accept_bozo_exceptions = true;
|
||||
});
|
||||
|
||||
feeds = [
|
||||
(mkFeed2TootIni {
|
||||
instance = "garden";
|
||||
visibility = "public";
|
||||
uriList = ../files/feed2toot-uris-cce-public.txt;
|
||||
})
|
||||
(mkFeed2TootIni {
|
||||
instance = "garden";
|
||||
visibility = "public";
|
||||
|
@ -194,12 +205,22 @@ in {
|
|||
description = "Feeds to Toots";
|
||||
after = ["pleroma.service"];
|
||||
wantedBy = ["default.target"];
|
||||
script = "${pkgs.feed2toot}/bin/feed2toot" +
|
||||
(lib.concatMapStrings (feed: " -c " + feed) feeds);
|
||||
# "-c ${gardenIni} -c ${lionsrearIni} -c ${engineIni}" ;
|
||||
serviceConfig.User = "feed2toot";
|
||||
serviceConfig.WorkingDirectory = "/srv/feed2toot";
|
||||
startAt = "30min";
|
||||
script =
|
||||
lib.concatMapStrings
|
||||
(feed: "\n${pkgs.feed2toot}/bin/feed2toot -c " + feed)
|
||||
feeds;
|
||||
serviceConfig = {
|
||||
User = "feed2toot";
|
||||
WorkingDirectory = "/srv/feed2toot";
|
||||
};
|
||||
};
|
||||
systemd.timers.feed2toot = {
|
||||
description = "Start feed2toot on the quarter-hour";
|
||||
timerConfig = {
|
||||
OnUnitActiveSec = "15 minutes";
|
||||
OnStartupSec = "15 minutes";
|
||||
};
|
||||
wantedBy = [ "default.target" ];
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
|
|
@ -0,0 +1,348 @@
|
|||
:PROPERTIES:
|
||||
:ID: 20230125T143144.011175
|
||||
:ROAM_REFS: https://github.com/edsu/feediverse/
|
||||
:ROAM_ALIASES: Feediverse
|
||||
:END:
|
||||
#+TITLE: Posting Arcology Feeds to the Fediverse Automatically with Feediverse
|
||||
#+filetags: :Project:CCE:Fediverse:
|
||||
|
||||
#+ARCOLOGY_KEY: arcology/feediverse
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
#+AUTO_TANGLE: t
|
||||
|
||||
#+begin_quote
|
||||
feediverse will read RSS/Atom feeds and send the messages as Mastodon posts. It's meant to add a little bit of spice to your timeline from other places. Please use it responsibly.
|
||||
#+end_quote
|
||||
|
||||
I was not convinced that [[id:20221227T164309.780458][feed2toot]] was the right way to go about this and in trying to extend it, I found myself frustrated. Well, here's a simpler single-file solution. I extended [[id:1d917282-ecf4-4d4c-ba49-628cbb4bb8cc][The Arcology Project]] to expose a JSON list of feeds and their metadata and with my modified version of =feediverse= I can post all of my sites' toots with one command.
|
||||
|
||||
* =feediverse.py=
|
||||
|
||||
This is a lightly modified version of the referenced =feediverse.py= above, with my modifications distributed under the [[id:20220116T143655.499306][Hey Smell This]] license.
|
||||
|
||||
This thing is, basically, simple to operate. it's driven by a YAML configuration file:
|
||||
|
||||
#+begin_src yaml :tangle ~/Code/feediverse/config.yml.sample
|
||||
tokens:
|
||||
lionsrear: *lionsrear-creds
|
||||
garden: *garden-creds
|
||||
cce: *garden-creds
|
||||
arcology: *garden-creds
|
||||
|
||||
feeds_index: https://thelionsrear.com/feeds.json
|
||||
post_template: >-
|
||||
NEW by @rrix@notes.whatthefuck.computer: {summary}
|
||||
|
||||
{url} {hashtags}
|
||||
updated: '2023-01-25T06:13:50.343361+00:00'
|
||||
url: https://notes.whatthefuck.computer
|
||||
#+end_src
|
||||
|
||||
This file will be created the first time you run this command; in my case it's generated locally and then copied to my [[id:20211120T220054.226284][Wobserver]] in the NixOS declarations below.
|
||||
|
||||
#+begin_src python :noweb-ref config-load-save
|
||||
def save_config(config, config_file):
|
||||
copy = dict(config)
|
||||
with open(config_file, 'w') as fh:
|
||||
fh.write(yaml.dump(copy, default_flow_style=False))
|
||||
|
||||
def read_config(config_file):
|
||||
config = {
|
||||
'updated': datetime(MINYEAR, 1, 1, 0, 0, 0, 0, timezone.utc)
|
||||
}
|
||||
with open(config_file) as fh:
|
||||
cfg = yaml.load(fh, yaml.SafeLoader)
|
||||
if 'updated' in cfg:
|
||||
cfg['updated'] = dateutil.parser.parse(cfg['updated'])
|
||||
config.update(cfg)
|
||||
return config
|
||||
#+end_src
|
||||
|
||||
So the =/feeds.json= in the [[id:20220225T175638.482695][Arcology Router]] returns a list of objects, in here it's re-key'd to be a per-site dictionary and returned:
|
||||
|
||||
#+begin_src python :noweb-ref fetch-feeds
|
||||
def fetch_dynamic_feeds(feeds_url):
|
||||
feeds = requests.get(feeds_url,
|
||||
headers={"User-Agent": "feediverse 0.0.1"}).json()
|
||||
|
||||
feeds_by_site = dict()
|
||||
for feed in feeds:
|
||||
feeds_by_site[feed['site']] = feeds_by_site.get(feed['site'], []) + [feed]
|
||||
return feeds_by_site
|
||||
#+end_src
|
||||
|
||||
With that loaded, it's possible to just loop over the sites, and then loop over each feed in the site to post new entries from them:
|
||||
|
||||
#+begin_src python :noweb-ref inner-loop
|
||||
newest_post = config['updated']
|
||||
per_site_feeds = fetch_dynamic_feeds(config['feeds_index'])
|
||||
|
||||
for site, feeds in per_site_feeds.items():
|
||||
masto = Mastodon(
|
||||
api_base_url=config['url'],
|
||||
feature_set='pleroma',
|
||||
client_id=config['tokens'][site]['client_id'],
|
||||
client_secret=config['tokens'][site]['client_secret'],
|
||||
access_token=config['tokens'][site]['access_token']
|
||||
)
|
||||
|
||||
for feed in feeds:
|
||||
if args.verbose:
|
||||
print(f"fetching {feed['url']} entries since {config['updated']}")
|
||||
for entry in get_feed(feed['url'], config['updated']):
|
||||
newest_post = max(newest_post, entry['updated'])
|
||||
if args.verbose:
|
||||
print(entry)
|
||||
if args.dry_run:
|
||||
print("trial run, not tooting ", entry["title"][:50])
|
||||
continue
|
||||
masto.status_post(config['post_template'].format(**entry),
|
||||
content_type='text/html',
|
||||
visibility=feed['visibility'])
|
||||
if not args.dry_run:
|
||||
config['updated'] = newest_post.isoformat()
|
||||
save_config(config, config_file)
|
||||
#+end_src
|
||||
|
||||
All the feed-parsing stuff is more or less lifted directly from the original =feediverse=, but modified to just post the HTML directly to [[id:20221202T122135.502628][+Akkoma+ Pleroma]].
|
||||
|
||||
#+begin_src python :noweb-ref feed-parsing
|
||||
def get_feed(feed_url, last_update):
|
||||
feed = feedparser.parse(feed_url)
|
||||
if last_update:
|
||||
entries = [e for e in feed.entries
|
||||
if dateutil.parser.parse(e['updated']) > last_update]
|
||||
else:
|
||||
entries = feed.entries
|
||||
entries.sort(key=lambda e: e.updated_parsed)
|
||||
for entry in entries:
|
||||
yield get_entry(entry)
|
||||
|
||||
def get_entry(entry):
|
||||
hashtags = []
|
||||
for tag in entry.get('tags', []):
|
||||
t = tag['term'].replace(' ', '_').replace('.', '').replace('-', '')
|
||||
hashtags.append('#{}'.format(t))
|
||||
summary = entry.get('summary', '')
|
||||
content = entry.get('content', '') or ''
|
||||
url = entry.id
|
||||
return {
|
||||
'url': url,
|
||||
'link': entry.link,
|
||||
'title': cleanup(entry.title),
|
||||
'summary': cleanup(summary, strip_html=False),
|
||||
'content': content,
|
||||
'hashtags': ' '.join(hashtags),
|
||||
'updated': dateutil.parser.parse(entry['updated'])
|
||||
}
|
||||
|
||||
def cleanup(text, strip_html=True):
|
||||
if strip_html:
|
||||
html = BeautifulSoup(text, 'html.parser')
|
||||
text = html.get_text()
|
||||
text = re.sub('\xa0+', ' ', text)
|
||||
text = re.sub(' +', ' ', text)
|
||||
text = re.sub(' +\n', '\n', text)
|
||||
text = re.sub('(\w)\n(\w)', '\\1 \\2', text)
|
||||
text = re.sub('\n\n\n+', '\n\n', text, flags=re.M)
|
||||
return text.strip()
|
||||
#+end_src
|
||||
|
||||
Setting up the config file is a bit different than the upstream stuff because my version supports setting up multiple accounts on a single instance. I made the design decision to only support one fedi instance per feedi instance, if you want to run this on multiple fedi servers, you'll need to run more than one config file or just don't.
|
||||
|
||||
#+begin_src python :noweb-ref setup-config
|
||||
def yes_no(question):
|
||||
res = input(question + ' [y/n] ')
|
||||
return res.lower() in "y1"
|
||||
|
||||
def setup(config_file):
|
||||
url = input('What is your Fediverse Instance URL? ')
|
||||
feeds_index = input("What is the arcology feed index URL? ")
|
||||
tokens = dict()
|
||||
for site in fetch_dynamic_feeds(feeds_index).keys():
|
||||
print(f"Configuring for {site}...")
|
||||
print("I'll need a few things in order to get your access token")
|
||||
name = input('app name (e.g. feediverse): ') or "feediverse"
|
||||
client_id, client_secret = Mastodon.create_app(
|
||||
api_base_url=url,
|
||||
client_name=name,
|
||||
#scopes=['read', 'write'],
|
||||
website='https://github.com/edsu/feediverse'
|
||||
)
|
||||
username = input('mastodon username (email): ')
|
||||
password = input('mastodon password (not stored): ')
|
||||
m = Mastodon(client_id=client_id, client_secret=client_secret, api_base_url=url)
|
||||
access_token = m.log_in(username, password)
|
||||
|
||||
tokens[site] = {
|
||||
'client_id': client_id,
|
||||
'client_secret': client_secret,
|
||||
'access_token': access_token,
|
||||
}
|
||||
|
||||
old_posts = yes_no('Shall already existing entries be tooted, too?')
|
||||
config = {
|
||||
'name': name,
|
||||
'url': url,
|
||||
'feeds_index': feeds_index,
|
||||
'tokens': tokens,
|
||||
'post_template': '{title} {summary} {url}'
|
||||
}
|
||||
if not old_posts:
|
||||
config['updated'] = datetime.now(tz=timezone.utc).isoformat()
|
||||
save_config(config, config_file)
|
||||
print("")
|
||||
print("Your feediverse configuration has been saved to {}".format(config_file))
|
||||
print("Add a line line this to your crontab to check every 15 minutes:")
|
||||
print("*/15 * * * * /usr/local/bin/feediverse")
|
||||
print("")
|
||||
#+end_src
|
||||
|
||||
All of that is assembled together in to a single command which takes a =--dry-run=, =--verbose= and =--config= argument to operate:
|
||||
|
||||
#+begin_src python :tangle ~/Code/feediverse/feediverse.py :noweb yes :shebang #!/usr/bin/env python3
|
||||
# Make sure to edit this in cce/feediverse.org !!!
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import yaml
|
||||
import argparse
|
||||
import dateutil
|
||||
import feedparser
|
||||
|
||||
import requests
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
from mastodon import Mastodon
|
||||
from datetime import datetime, timezone, MINYEAR
|
||||
|
||||
DEFAULT_CONFIG_FILE = os.path.join("~", ".feediverse")
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-n", "--dry-run", action="store_true",
|
||||
help=("perform a trial run with no changes made: "
|
||||
"don't toot, don't save config"))
|
||||
parser.add_argument("-v", "--verbose", action="store_true",
|
||||
help="be verbose")
|
||||
parser.add_argument("-c", "--config",
|
||||
help="config file to use",
|
||||
default=os.path.expanduser(DEFAULT_CONFIG_FILE))
|
||||
|
||||
args = parser.parse_args()
|
||||
config_file = args.config
|
||||
|
||||
if args.verbose:
|
||||
print("using config file", config_file)
|
||||
|
||||
if not os.path.isfile(config_file):
|
||||
setup(config_file)
|
||||
|
||||
config = read_config(config_file)
|
||||
|
||||
<<inner-loop>>
|
||||
|
||||
<<fetch-feeds>>
|
||||
|
||||
<<feed-parsing>>
|
||||
|
||||
<<config-load-save>>
|
||||
|
||||
<<setup-config>>
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
#+end_src
|
||||
|
||||
* Packaging =feediverse= in [[id:20221021T121120.541960][rixpkgs]]
|
||||
|
||||
This is pretty easy to get running; if you do this yourself, you'll want to override =src= to point to [[https://code.rix.si/rrix/feediverse]], but I don't like remembering to push my changes 😇
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/pkgs/feediverse.nix
|
||||
{ lib,
|
||||
buildPythonPackage,
|
||||
fetchPypi,
|
||||
beautifulsoup4,
|
||||
feedparser,
|
||||
python-dateutil,
|
||||
requests,
|
||||
mastodon-py,
|
||||
pyyaml,
|
||||
python,
|
||||
}:
|
||||
|
||||
buildPythonPackage rec {
|
||||
pname = "feediverse";
|
||||
version = "0.0.1";
|
||||
|
||||
src = /home/rrix/Code/feediverse;
|
||||
|
||||
propagatedBuildInputs = [
|
||||
beautifulsoup4
|
||||
feedparser
|
||||
python-dateutil
|
||||
requests
|
||||
pyyaml
|
||||
mastodon-py
|
||||
];
|
||||
|
||||
meta = with lib; {
|
||||
homepage = "https://code.rix.si/rrix/feediverse";
|
||||
description = "feediverse will read RSS/Atom feeds and send the messages as Mastodon posts.";
|
||||
license = licenses.mit;
|
||||
maintainers = with maintainers; [ rrix ];
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
* Running =feediverse= on [[id:20211120T220054.226284][The Wobserver]]
|
||||
|
||||
Okay, with the configuration file generated and then copied on to the server (since it's mutated by the script...), I shove it in to the [[id:20221021T150631.404359][Arroyo Nix]] index and then set up an [[id:arroyo/nixos][Arroyo NixOS]] module to set up a service account and run it with a SystemD timer. This will be pretty straightforward if you've seen NixOS before.
|
||||
|
||||
#+ARROYO_NIXOS_MODULE: nixos/feediverse.nix
|
||||
#+ARROYO_NIXOS_ROLE: server
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/feediverse.nix
|
||||
{ pkgs, lib, config, ... }:
|
||||
|
||||
{
|
||||
ids.uids.feediverse = 902;
|
||||
ids.gids.bots = 902;
|
||||
|
||||
users.groups.bots = {
|
||||
gid = config.ids.gids.bots;
|
||||
};
|
||||
|
||||
users.users.feediverse = {
|
||||
home = "/srv/feediverse";
|
||||
group = "bots";
|
||||
uid = config.ids.uids.feediverse;
|
||||
isSystemUser = true;
|
||||
};
|
||||
|
||||
systemd.services.feediverse = {
|
||||
description = "Feeds to Toots";
|
||||
after = ["pleroma.service"];
|
||||
wantedBy = ["default.target"];
|
||||
script =
|
||||
''
|
||||
${pkgs.feediverse}/bin/feediverse -c ${config.users.users.feediverse.home}/feediverse.yml
|
||||
'';
|
||||
serviceConfig = {
|
||||
User = "feediverse";
|
||||
WorkingDirectory = config.users.users.feediverse.home;
|
||||
};
|
||||
};
|
||||
systemd.timers.feediverse = {
|
||||
description = "Start feediverse on the quarter-hour";
|
||||
timerConfig = {
|
||||
OnUnitActiveSec = "15 minutes";
|
||||
OnStartupSec = "15 minutes";
|
||||
};
|
||||
wantedBy = [ "default.target" ];
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
* NEXT Consider making the config file immutable by storing the update timestamp in a different location
|
|
@ -44,6 +44,7 @@ This [[id:09779ac0-4d5f-40db-a340-49595c717e03][noweb]] document constructs a cu
|
|||
"privacy.trackingprotection.enabled" = true;
|
||||
"privacy.donottrackheader.enabled" = true;
|
||||
"privacy.globalprivacycontrol.enabled" = true;
|
||||
"privacy.globalprivacycontrol.functionality_enabled" = true;
|
||||
|
||||
"reader.color_scheme" = "dark";
|
||||
|
||||
|
@ -59,6 +60,10 @@ This [[id:09779ac0-4d5f-40db-a340-49595c717e03][noweb]] document constructs a cu
|
|||
"browser.aboutConfig.showWarning" = false;
|
||||
"browser.sessionstore.warnOnQuit" = true;
|
||||
|
||||
|
||||
"browser.newtabpage.activity-stream.showSponsored" = false;
|
||||
"browser.newtabpage.activity-stream.showSponsoredTopSites" = false;
|
||||
|
||||
"toolkit.legacyUserProfileCustomizations.stylesheets" = true; # for userchrome and usercontent
|
||||
"layout.css.prefers-color-scheme.content-override" = 2; # (ref:content-override)
|
||||
};
|
||||
|
|
32
gitea.org
32
gitea.org
|
@ -31,28 +31,24 @@ in {
|
|||
appName = "rrix's code with a cup of tea";
|
||||
stateDir = "/srv/gitea";
|
||||
|
||||
domain = "code.rix.si";
|
||||
rootUrl = "https://code.rix.si";
|
||||
|
||||
httpAddress = "127.0.0.1";
|
||||
httpPort = 3009;
|
||||
|
||||
settings = {
|
||||
server = {
|
||||
DISABLE_REGISTRATION = true;
|
||||
START_SSH_SERVER = true;
|
||||
SSH_LISTEN_PORT = 2222;
|
||||
SSH_PORT = 2222;
|
||||
ENABLE_GZIP = true;
|
||||
LANDING_PAGE = "explore";
|
||||
};
|
||||
ui.DEFAULT_THEME = "arc-green";
|
||||
session.COOKIE_SECURE = true;
|
||||
server.DOMAIN = "code.rix.si";
|
||||
server.ENABLE_GZIP = true;
|
||||
server.HTTP_ADDRESS = "127.0.0.1";
|
||||
server.HTTP_PORT = 3009;
|
||||
server.LANDING_PAGE = "explore";
|
||||
server.ROOT_URL = "https://code.rix.si";
|
||||
server.SSH_LISTEN_PORT = 2222;
|
||||
server.SSH_PORT = 2222;
|
||||
server.START_SSH_SERVER = true;
|
||||
service.DISABLE_REGISTRATION = true;
|
||||
federation.ENABLED = true;
|
||||
metrics.ENABLED = true;
|
||||
packages.ENABLED = false;
|
||||
picture.ENABLE_FEDERATED_AVATAR = true;
|
||||
session.COOKIE_SECURE = true;
|
||||
time.DEFAULT_UI_LOCATION = config.time.timeZone;
|
||||
ui.DEFAULT_THEME = "arc-green";
|
||||
};
|
||||
|
||||
database = {
|
||||
|
@ -64,13 +60,13 @@ in {
|
|||
services.prometheus.scrapeConfigs = [
|
||||
{
|
||||
job_name = "gitea";
|
||||
static_configs = [{ targets = ["${cfg.httpAddress}:${toString cfg.httpPort}"]; }];
|
||||
static_configs = [{ targets = ["${cfg.settings.server.HTTP_ADDRESS}:${toString cfg.settings.server.HTTP_PORT}"]; }];
|
||||
}
|
||||
];
|
||||
|
||||
services.nginx.virtualHosts."code.rix.si" = {
|
||||
locations."/" = {
|
||||
proxyPass = "http://${cfg.httpAddress}:${toString cfg.httpPort}";
|
||||
proxyPass = "http://${cfg.settings.server.HTTP_ADDRESS}:${toString cfg.settings.server.HTTP_PORT}";
|
||||
extraConfig = ''
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
|
|
|
@ -29,7 +29,8 @@ I use =gpg2= everywhere, including in Emacs.
|
|||
This is for [[id:cce/home-manager][home-manager]]:
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/hm/gnupg.nix
|
||||
{pkgs, ...}:
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
programs.gpg.enable = true;
|
||||
programs.gpg.settings = {
|
||||
|
@ -55,6 +56,7 @@ This is for PAM in [[id:cce/my_nixos_configuration][My NixOS configuration]]:
|
|||
#+ARROYO_NIXOS_EXCLUDE: waterboy
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/gnupg-pam.nix
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
environment.systemPackages = [ pkgs.gnupg ];
|
||||
security.pam.services.login.gnupg.enable = true;
|
||||
|
|
30
gnus.org
30
gnus.org
|
@ -11,7 +11,7 @@
|
|||
#+ARCOLOGY_KEY: cce/gnus
|
||||
#+CCE_ANSIBLE: gnus
|
||||
#+CCE_PRIORITY: 70
|
||||
#+filetags: :CCE:
|
||||
#+filetags: :Project:CCE:
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
From the Gnus website:
|
||||
|
@ -180,21 +180,21 @@ in {
|
|||
|
||||
home.activation = {
|
||||
gnus-newsrc =
|
||||
pkgs.lib.mkActivationLocalLink (builtins.trace config)
|
||||
pkgs.lib.mkActivationLocalLink config
|
||||
"~/sync/private-files/.newsrc"
|
||||
".newsrc";
|
||||
gnus-newsrc_eld =
|
||||
pkgs.lib.mkActivationLocalLink config
|
||||
"~/sync/private-files/.newsrc.eld"
|
||||
".newsrc.eld";
|
||||
gnus-feeds =
|
||||
pkgs.lib.mkActivationLocalLink config
|
||||
"~/Maildir/endpoint/feeds"
|
||||
"Maildir/feeds";
|
||||
gnus-fastmail =
|
||||
pkgs.lib.mkActivationLocalLink config
|
||||
"~/Maildir/endpoint/fastmail"
|
||||
"Maildir/fastmail";
|
||||
# gnus-feeds =
|
||||
# pkgs.lib.mkActivationLocalLink config
|
||||
# "~/Maildir/endpoint/feeds"
|
||||
# "Maildir/feeds";
|
||||
# gnus-fastmail =
|
||||
# pkgs.lib.mkActivationLocalLink config
|
||||
# "~/Maildir/endpoint/fastmail"
|
||||
# "Maildir/fastmail";
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
@ -214,9 +214,17 @@ Finally, this ugly function and sharp-quoted =setq= tries to find an IMAP which
|
|||
"gmail/Inbox")
|
||||
(t "fastmail/INBOX")))
|
||||
(nnir-search-engine imap)
|
||||
(nnimap-shell-program ,(cce/find-dovecot)))))
|
||||
(nnimap-shell-program ,(cce/find-dovecot)))
|
||||
;; (nnttrss "tt"
|
||||
;; (nnttrss-address "https://feeds.whatthefuck.computer/api")
|
||||
;; (nnttrss-user "rrix")
|
||||
;; (nnttrss-password "NOPASSWORD")
|
||||
;; )
|
||||
))
|
||||
#+end_src
|
||||
|
||||
* NEXT move [[id:cce/mbsync][mbsync]] here
|
||||
* NEXT move [[id:cce/sending_mail_in_gnus][msmtp]] here
|
||||
* Put All Together With Noweb
|
||||
|
||||
All of the code presented above is inserted in to a =use-package= block[fn:1:[[id:cce/configure_packaging][Configure Packaging]]].
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
:PROPERTIES:
|
||||
:ID: 20230404T153703.708523
|
||||
:END:
|
||||
#+TITLE: GPD Pocket 3
|
||||
#+filetags: :Project:
|
||||
|
||||
#+ARCOLOGY_KEY: cce/gpd-pocket-3
|
||||
|
||||
#+AUTO_TANGLE: t
|
||||
|
||||
These small 7-8 inch display laptops have been the most promising mobile [[id:0d968a4d-3c9d-4104-a158-e4982be6d28e][Linux]] devices for me, each with some fatal flaw that made it unlikely to survive a long time. But maybe this one is different. I own the [[id:6834cb8f-319f-4dd9-bade-2521417f584b][GPD Pocket]] which could not go in to deep sleep in linux, so it would always have a dead battery when I wanted to use it and the touchscreen did not function on it. I own the [[id:20230420T203015.828439][GPD Pocket 2]] which runs NixOS but has a soldered in eMMC chip that is just slightly too small to be useful for me. The GPD Pocket 3 is a convertable touch screen laptop which is maybe versatile enough and full of upgradable storage with m.2 nvme.
|
||||
|
||||
The lads at GPD are at it again. This one has a 360° rotating screen and active stylus support. It has a proprietary IO port at the back of the device that can have an extra USB port, or an HDMI capture card and USB gadget hub, or an RS232 serial device. Maybe even a [[https://p3-lte.wulige.com/#%E7%A1%AC%E4%BB%B6][4G cell card??]] one can hope...
|
||||
|
||||
Having a performant Emacs environment in a light form-factor is a thing I've been chasing for a decade or more, and this is the latest step. It fits in my 8" camera messenger bag and my bike basket. It's an ebook reader and a programming environment and a shitposting machine.
|
||||
|
||||
* NixOS on the GPD Pocket 3
|
||||
:PROPERTIES:
|
||||
:ID: 20230404T153725.517911
|
||||
:END:
|
||||
|
||||
This thing has kind of been a pain to run Linux on, especially after I had a real deep [[roam:Brain-o]] moment where I had to wipe the disk. I'd rather not talk about it lol.
|
||||
|
||||
Things were working well before then, like the thing worked quite nicely, but installing the very same system build I had just deployed early in the week would cause the machine to panick when modesetting occurred. I had to downgrade the kernel to 5.15 to get it to boot reliably but there was a bunch of weird display behavior, this was a bit worrying. 6.2 works but ZFS support is still labeled "unstable" so I'll have to be careful to not jog this thing too hard until 6.2 stabilizes lol.
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/gpd-pocket-3.nix
|
||||
{ lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
#+END_SRC
|
||||
|
||||
Forcing 6.2 kernel and (unfortunately) ZFS Unstable will get everything working but I'm confused how it worked last week. Kernel 6.1 and 6.2 have working deep sleep, and 5.15 had some backlight control problems. Unless I am far from home, I can bootstrap a new system quickly enough in theory with [[id:cce/morph][Morph]] and [[id:cce/syncthing][Syncthing]], in theory. I sort of just played out that scenario I suppose. 5.15 is still a fuck and 6.2 is EOL, so I am carrying [[https://github.com/NixOS/nixpkgs/pull/236637][this open backport commit]] which bumps ZFS stable to a version which supports 6.3
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/gpd-pocket-3.nix
|
||||
# === gpd pocket 3 specific hax
|
||||
# boot.zfs.enableUnstable = true;
|
||||
# boot.kernelPackages = lib.mkForce pkgs.zfsUnstable.latestCompatibleLinuxPackages;
|
||||
# git cherry-pick 900c093
|
||||
boot.zfs.enableUnstable = false;
|
||||
boot.kernelPackages = lib.mkForce pkgs.linuxPackages_6_3;
|
||||
#+END_SRC
|
||||
|
||||
The display, as with all GPD Pockets is an 8 inch tablet display rotated 90° counter-clockwise, and so some work has to be done to rotate all of this, and the stylus coordinates and the accelerometer and whatnot. I had some real problems getting X11 to look decently without fractional scaling and I was having trouble getting the X11 config working, so this is my first machine running Wayland. I have a few things commented here for if upgrading my kernel or whatever breaks the display again during modesetting or whatever..
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/gpd-pocket-3.nix
|
||||
boot.kernelParams = [
|
||||
"mem_sleep_default=deep"
|
||||
"fbcon=rotate:1"
|
||||
"video=DSI-1:panel_orientation=right_side_up"
|
||||
];
|
||||
|
||||
services.udev.extraRules = ''
|
||||
ACTION=="add|change", KERNEL=="event[0-9]*", ATTRS{name}=="GXTP7380:00 27C6:0113", ENV{LIBINPUT_CALIBRATION_MATRIX}="1 0 0 0 1 0"
|
||||
ACTION=="add|change", KERNEL=="event[0-9]*", ATTRS{name}=="GXTP7380:00 27C6:0113 Stylus", ENV{LIBINPUT_CALIBRATION_MATRIX}="1 0 0 0 1 0"
|
||||
'';
|
||||
services.udev.extraHwdb = ''
|
||||
sensor:modalias:*
|
||||
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 1, 0, 0
|
||||
'';
|
||||
hardware.sensor.iio.enable = true;
|
||||
|
||||
services.xserver.videoDrivers = ["modesetting" "intel"];
|
||||
|
||||
services.xserver.displayManager.defaultSession = lib.mkForce "plasmawayland";
|
||||
# services.xserver.displayManager.lightdm.enable = lib.mkForce false;
|
||||
# services.xserver.displayManager.lightdm.enable = true;
|
||||
# services.xserver.displayManager.autoLogin.enable = lib.mkForce false;
|
||||
# systemd.defaultUnit = lib.mkForce "multi-user.target";
|
||||
#+END_SRC
|
||||
|
||||
Make the sound work and the console legible.
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/gpd-pocket-3.nix
|
||||
boot.extraModprobeConfig = ''
|
||||
options snd-intel-dspcfg dsp_driver=1
|
||||
'';
|
||||
hardware.enableRedistributableFirmware = true;
|
||||
|
||||
console.font = "solar24x32.psfu";
|
||||
console.earlySetup = true;
|
||||
#+END_SRC
|
||||
|
||||
Gotta have the soft keyboard since I'm actually goign to use this as a tablet for light web browsing. It still has to be enabled in System Settings, I need to automate the declarative setup of KDE and Plasma...
|
||||
|
||||
#+begin_src
|
||||
environment.systemPackages = [
|
||||
pkgs.maliit-framework
|
||||
pkgs.maliit-keyboard
|
||||
pkgs.wl-clipboard
|
||||
];
|
||||
#+END_SRC
|
||||
|
||||
Include the rotate script below:
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/gpd-pocket-3.nix
|
||||
imports = [ <arroyo/nixos/gpd-pocket-3-rotate.nix> ];
|
||||
}
|
||||
#+end_src
|
||||
|
||||
** Rotate Script
|
||||
|
||||
One of the side-effects of moving to Wayland is that the "Custom Shortcuts" system in [[id:cce/kde_is_a_base_for_my_emacs_desktop][KDE]] is not functional. There is a limited version of it in the main Shortcuts UI which lets you choose a =.desktop= file or shell script to run without arguments, so here I am writing a =.desktop= file.
|
||||
|
||||
I don't do a full rotation, and i use a neat little [[id:cce/kde_is_a_base_for_my_emacs_desktop][KDE]] command lie utility called =kscreen-doctor= to handle rotating the display on =kwin_wayland=: These numbers that come out of the first =CUR_ROT= pipeline are probably a bitfield or something, they're all base-2 even maybe? Who can say? They also differ depending on which KScreen backend you use...
|
||||
|
||||
#+begin_src shell :tangle ~/arroyo-nix/files/gpd-pocket-3-rotate.sh
|
||||
STATUS_KSKB=QScreen
|
||||
CUR_ROT=$(KSCREEN_BACKEND=$STATUS_KSKB kscreen-doctor --json | jq '.outputs[]|select(.name == "DSI-1").rotation')
|
||||
|
||||
# KWayland and QScreen don't return the same bitfield lol
|
||||
|
||||
case $STATUS_KSKB in
|
||||
QScreen)
|
||||
case $CUR_ROT in
|
||||
8) # normal
|
||||
kscreen-doctor output.DSI-1.rotation.right
|
||||
;;
|
||||
1) # 90 ccw
|
||||
kscreen-doctor output.DSI-1.rotation.inverted
|
||||
;;
|
||||
# 8) # normal
|
||||
# kscreen-doctor output.DSI-1.rotation.inverted
|
||||
# ;;
|
||||
# 4) # 90 ccw
|
||||
# kscreen-doctor output.DSI-1.rotation.right
|
||||
# ;;
|
||||
esac
|
||||
;;
|
||||
KWayland)
|
||||
case $CUR_ROT in
|
||||
8) # normal
|
||||
kscreen-doctor output.DSI-1.rotation.inverted
|
||||
;;
|
||||
4) # 90 ccw
|
||||
kscreen-doctor output.DSI-1.rotation.right
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
#+end_src
|
||||
|
||||
Packaging this up is kind of ugly, i'm sure there is a more idiomatic way to ship a shell script with a desktop file. I should at least move this to [[id:20221021T121120.541960][rixpkgs]] eventually...
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/gpd-pocket-3-rotate.nix
|
||||
{ pkgs, ... }:
|
||||
|
||||
let
|
||||
gpd-rotate-display = pkgs.writeShellApplication {
|
||||
name = "gpd-rotate-display";
|
||||
runtimeInputs = with pkgs; [ plasma5Packages.libkscreen jq ];
|
||||
|
||||
text = builtins.readFile <arroyo/files/gpd-pocket-3-rotate.sh>;
|
||||
};
|
||||
desktopItem = pkgs.makeDesktopItem {
|
||||
name = "gpd-rotate-display";
|
||||
desktopName = "Rotate Display";
|
||||
categories = ["Utility"];
|
||||
exec = "gpd-rotate-display";
|
||||
};
|
||||
gpd-rotate-display' = pkgs.stdenv.mkDerivation {
|
||||
name = "gpd-rotate-display";
|
||||
src = gpd-rotate-display;
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin
|
||||
cp $src/bin/gpd-rotate-display $out/bin/
|
||||
cp --recursive "${desktopItem}/share" "$out/"
|
||||
'';
|
||||
};
|
||||
in {
|
||||
environment.systemPackages = [
|
||||
gpd-rotate-display'
|
||||
];
|
||||
}
|
||||
#+end_src
|
||||
|
||||
* NEXT consider swap back to Xorg
|
||||
|
||||
scaling the touch and wacom when i run xinput --scale command
|
101
home-manager.org
101
home-manager.org
|
@ -135,8 +135,9 @@ I also should define program modules for a lot of these over the long term so th
|
|||
home.username = "rrix";
|
||||
home.homeDirectory = "/home/rrix";
|
||||
|
||||
home.language.base = "en_US";
|
||||
home.language.time = "en_GB";
|
||||
# set to UTF-8 or python shit breaks
|
||||
home.language.base = "en_US.UTF-8";
|
||||
home.language.time = "en_GB.UTF-8";
|
||||
|
||||
# for KDE
|
||||
# https://userbase.kde.org/Session_Environment_Variables
|
||||
|
@ -192,53 +193,59 @@ This uses [[id:arroyo/home-manager][Arroyo Home Manager]].
|
|||
|
||||
#+results: generate_imports
|
||||
#+begin_example
|
||||
hm/prompt.nix
|
||||
hm/qud.nix
|
||||
hm/smac.nix
|
||||
hm/msmtp.nix
|
||||
hm/emacs-helpers.nix
|
||||
hm/direnv.nix
|
||||
hm/applications.nix
|
||||
hm/tabfs.nix
|
||||
hm/firefox.nix
|
||||
hm/contacts.nix
|
||||
hm/ruby.nix
|
||||
hm/defexpr.nix
|
||||
hm/xmonad.nix
|
||||
hm/git.nix
|
||||
hm/python.nix
|
||||
hm/gnupg.nix
|
||||
hm/syncthing.nix
|
||||
hm/pass.nix
|
||||
hm/org-protocol.nix
|
||||
hm/ssh_client.nix
|
||||
hm/kde-config-basics.nix
|
||||
hm/vsketch.nix
|
||||
hm/mbsync-endpoint.nix
|
||||
hm/fehbg.nix
|
||||
hm/org-roam.nix
|
||||
hm/beets.nix
|
||||
hm/dovecot-shell-access.nix
|
||||
hm/mpd.nix
|
||||
hm/emacs-pager.nix
|
||||
hm/shell-helpers.nix
|
||||
hm/kde-config-appearance.nix
|
||||
hm/i3wm.nix
|
||||
hm/spell-check.nix
|
||||
hm/deadgrep.nix
|
||||
hm/3d-printing.nix
|
||||
hm/pantalaimon.nix
|
||||
hm/profile.nix
|
||||
hm/supercollider.nix
|
||||
hm/axidraw.nix
|
||||
hm/datasette.nix
|
||||
hm/morph.nix
|
||||
hm/emacs.nix
|
||||
hm/occluded_files.nix
|
||||
hm/nix-update.nix
|
||||
hm/cogmind.nix
|
||||
hm/picom.nix
|
||||
hm/applications.nix
|
||||
hm/atuin.nix
|
||||
hm/axidraw.nix
|
||||
hm/bandcamp-dl.nix
|
||||
hm/beets.nix
|
||||
hm/bitwarden.nix
|
||||
hm/cogmind.nix
|
||||
hm/contacts.nix
|
||||
hm/cpmtools.nix
|
||||
hm/datasette.nix
|
||||
hm/deadgrep.nix
|
||||
hm/defexpr.nix
|
||||
hm/direnv.nix
|
||||
hm/dovecot-shell-access.nix
|
||||
hm/drawingbot.nix
|
||||
hm/emacs-helpers.nix
|
||||
hm/emacs-pager.nix
|
||||
hm/emacs.nix
|
||||
hm/fehbg.nix
|
||||
hm/firefox.nix
|
||||
hm/git.nix
|
||||
hm/gnupg.nix
|
||||
hm/i3wm.nix
|
||||
hm/kde-config-appearance.nix
|
||||
hm/kde-config-basics.nix
|
||||
hm/mbsync-endpoint.nix
|
||||
hm/morph.nix
|
||||
hm/mpd.nix
|
||||
hm/msmtp.nix
|
||||
hm/nix-update.nix
|
||||
hm/occluded_files.nix
|
||||
hm/org-fc.nix
|
||||
hm/org-protocol.nix
|
||||
hm/org-roam.nix
|
||||
hm/pantalaimon.nix
|
||||
hm/pass.nix
|
||||
hm/picom.nix
|
||||
hm/profile.nix
|
||||
hm/prompt.nix
|
||||
hm/python.nix
|
||||
hm/qud.nix
|
||||
hm/ruby.nix
|
||||
hm/shell-helpers.nix
|
||||
hm/smac.nix
|
||||
hm/spell-check.nix
|
||||
hm/ssh_client.nix
|
||||
hm/supercollider.nix
|
||||
hm/syncthing-tray.nix
|
||||
hm/syncthing.nix
|
||||
hm/tabfs.nix
|
||||
hm/vsketch.nix
|
||||
hm/xmonad.nix
|
||||
#+end_example
|
||||
|
||||
* Task list to port =CCE_ANSIBLE= to =CCE_HOME_MODULE=
|
||||
|
|
|
@ -27,3 +27,4 @@ Welcome to the Complete Computing Environment.
|
|||
- [[id:arroyo/emacs][Arroyo Emacs]]
|
||||
- [[id:cce/my_nixos_configuration][My NixOS configuration]]
|
||||
- [[id:20220116T143655.499306][Hey Smell This]]
|
||||
- [[id:20230111T140523.582960][CCE and Emacs Update Feed]]
|
||||
|
|
|
@ -10,8 +10,7 @@
|
|||
#+PROPERTY: header-args:emacs-lisp :tangle ivy-config.el
|
||||
|
||||
,#+ARROYO_EMACS_MODULE: ivy-config
|
||||
#+CCE_PREDICATE: (not t)
|
||||
#+CCE_PRIORITY: 10
|
||||
#+ARROYO_MODULE_WANTS: cce/diminish.org
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(provide 'cce/ivy-config)
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
:PROPERTIES:
|
||||
:ID: 20230220T204453.685476
|
||||
:END:
|
||||
#+TITLE: Jellyfin on the Wobserver
|
||||
|
||||
#+ARROYO_NIXOS_MODULE: nixos/jellyfin.nix
|
||||
#+ARROYO_NIXOS_ROLE: server
|
||||
#+AUTO_TANGLE: t
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/jellyfin.nix
|
||||
{ lib, ... }:
|
||||
|
||||
{
|
||||
services.jellyfin.enable = true;
|
||||
# so that metadata etc are legible to syncthing and others; consider adding jellyfin user to a service group...
|
||||
systemd.services.jellyfin.serviceConfig.UMask = lib.mkForce "0002";
|
||||
services.nginx.virtualHosts."media.whatthefuck.computer" = {
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:8096";
|
||||
};
|
||||
};
|
||||
}
|
||||
#+end_src
|
|
@ -63,6 +63,7 @@ I customize my KDE installation a fair bit both within [[id:cce/home-manager][ho
|
|||
|
||||
environment.systemPackages = (with pkgs.libsForQt5; [
|
||||
breeze-gtk
|
||||
kde-gtk-config
|
||||
breeze-qt5
|
||||
kdesu
|
||||
|
||||
|
@ -86,6 +87,7 @@ I customize my KDE installation a fair bit both within [[id:cce/home-manager][ho
|
|||
partition-manager
|
||||
gparted
|
||||
plasma5Packages.kamoso
|
||||
plasma5Packages.bismuth
|
||||
]);
|
||||
|
||||
# auto login
|
||||
|
|
|
@ -1,30 +1,41 @@
|
|||
:PROPERTIES:
|
||||
:ID: cce/keyboardio_atreus
|
||||
:ROAM_REFS: https://shop.keyboard.io/pages/atreus
|
||||
:ROAM_ALIASES: "Keyboardio Atreus"
|
||||
:END:
|
||||
#+TITLE: Keyboardio Atreus
|
||||
#+PROPERTY: header-args :mkdirp yes :results none
|
||||
#+PROPERTY: header-args:yaml :tangle roles/endpoint/tasks/atreus.yml
|
||||
#+TITLE: What the hell is that keyboard on my laptop? The Keyboardio Atreus
|
||||
|
||||
#+ARCOLOGY_KEY: cce/atreus
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
#+filetags: :CCE:
|
||||
|
||||
* The Keyboardio Atreus :ATTACH:
|
||||
:PROPERTIES:
|
||||
:ID: 690d03f5-abe7-4b0e-be94-086008b7fd7b
|
||||
:END:
|
||||
|
||||
[[file:../data/69/0d03f5-abe7-4b0e-be94-086008b7fd7b/IMG_20201013_172314.jpg][file:~/org/data/69/0d03f5-abe7-4b0e-be94-086008b7fd7b/IMG_20201013_172314.jpg]]
|
||||
|
||||
The Keyboardio Atreus is a 44-key minimalist keyboard that is sculpted to fit the natural length of the fingers in a way that minimalist keyboards like the Planck can't. it has just enough keys to work with my weird layout, and i intend to use it as such. :) This one is equipped with Kailh BOX Brown switches and Laser GMK keycaps, I like the tactile bump and this thing can *crush* prose writing.
|
||||
The Keyboardio Atreus is a minimalist 44-key keyboard that is sculpted to fit the natural length of the fingers in a way that minimalist keyboards like the Planck can't. it has just enough keys to be able to express most of the keys on a "full-sized" keyboard with a "phone tree" of layers. It's based on a keyboard designed by [[roam:Technomancy]], FOSS lisp extraordinaire and itinerant [[id:62538db5-d94a-47c3-9998-086ded91fd88][Fediverse]] shitposter.
|
||||
|
||||
I work my fingers like I expect to type QWERTY with much less finger-travel and much less risk of RSI. to get to numbers, symbols, and "action keys" like function keys, navigation, etc, by entering key-chords like you would with Ctrl, Alt, and the Windows or Super key. My right thumb's resting key gets me to a layer where I have a ten-key and access to common punctuation and braces, and it is close to Ctrl and Escape and Space. The left thumb is my shift key, and is close to Alt/Meta/Option, Super/Windows, and backspace. Other buttons take me to arrow keys, function keys, etc. One of my [[id:109_mental_models_explained][Mental Models]] for computing is fundamentally about modes and navigate through them (as in [[id:cce/emacs][Emacs]] major and minor modes). This is a hardware extension of this mental model which melds nicely when working in Emacs and using a [[roam:Tiling Window Manager]].
|
||||
|
||||
It sucks when I travel sometimes because I obviously don't have it built in to a laptop and it's not as comfortable or as smooth to use than sitting at my desk at home. So this keyboard layout is a sort of local-minima I've dug myself in to. It's also [[roam:Hashtag Aesthetic]] as frick and is fun to type on, and represents nearly the "end game" sort of build for the =/r/battlestations= ❌ =/r/mechanicalkeyboards= Reddit Consumerist Poster I may have been in my 20s. Maybe this is just that exact kind of post. [[id:cce/cce][CCE]] and [[id:1d917282-ecf4-4d4c-ba49-628cbb4bb8cc][The Arcology Project]] are that exact kind of "post".
|
||||
|
||||
This Atreus is equipped with Kailh BOX Brown switches and Laser GMK keycaps, I can type on "tactile" keyboard switches without bottoming out, and this thing can *crush* prose writing while looking rad as hell, both of which acting as a huge multiplier of my descent in to [[id:1fb8fb45-fac5-4449-a347-d55118bb377e][org-mode]] and using this digital journal to think well.
|
||||
|
||||
In that sense, it is a physical representation of my folly. Some people learn DVORAK or COLEMAK and give up on using =vim=-style navigation vocabulary. Most people don't ever consider =vim=-style navigation vocabulary to be a threat and store their thoughts organized chronologically in Apple Notes or Google Docs. This is not a place of honor.
|
||||
|
||||
* The Keyboard and Layout :ATTACH:
|
||||
:PROPERTIES:
|
||||
:ID: 287ba93e-a2af-4093-a74b-85172edb2ab2
|
||||
:END:
|
||||
|
||||
I use QWERTY, a custom symbol layer, and a mouse layer which I may not use. These screenshots were taken out of Chrysalis, the Keyboardio configurator on [2020-10-13].
|
||||
I use QWERTY, a custom symbol layer, and a mouse layer which I may not use much.
|
||||
|
||||
Mostly this works on any computer, except I have to apply some [[id:20210814224010-my_custom_keyboard_layout][Xmodmap Hacks]] to set up matching braces on the left hand for =<>= and changing shifted version of =,./= to be much more useful =!?\=. ZMK might be able to handle this better, but that's not an option with most of my keyboards.
|
||||
|
||||
|
||||
These screenshots were taken out of Chrysalis, the Keyboardio configurator on [2020-10-13].
|
||||
|
||||
There have been some minor changes since then but I am using QMK now so getting nice labelled images of the layout is not so simple.
|
||||
|
||||
(My [[id:20220523T234413.114460][site engine]] currently does not support image uploads, sorry.)
|
||||
|
||||
#+ATTR_ORG: :width 800
|
||||
[[file:../data/28/7ba93e-a2af-4093-a74b-85172edb2ab2/Screenshot_20201013_164724.png][file:~/org/data/28/7ba93e-a2af-4093-a74b-85172edb2ab2/Screenshot_20201013_164724.png]]
|
||||
|
@ -35,28 +46,21 @@ I use QWERTY, a custom symbol layer, and a mouse layer which I may not use. Thes
|
|||
#+ATTR_ORG: :width 800
|
||||
[[file:../data/28/7ba93e-a2af-4093-a74b-85172edb2ab2/Screenshot_20201013_164926.png][file:~/org/data/28/7ba93e-a2af-4093-a74b-85172edb2ab2/Screenshot_20201013_164926.png]]
|
||||
|
||||
[[id:20210814224010-my_custom_keyboard_layout][My Xmodmap Hacks]] are overlayed on this to create a full brace pair cluster on the left hand with the right hand entering symbol layer.
|
||||
* So what is my endgame?
|
||||
|
||||
* Hardware Support
|
||||
This thing with either a trackpoint or trackball.
|
||||
|
||||
This =UDEV= rule makes sure that the device can be accessed by users, this allows me to program the device without needing to become root. This "just works" on [[id:cce/my_nixos_configuration][My NixOS configuration]], though.
|
||||
This thing except I have re-habitualized my typing so that my hands travel less "across" the keyboard, even this one i sometimes manage to play like a piano.
|
||||
|
||||
#+begin_src text :comments none :tangle cce/udev/90-keyboardio.rules
|
||||
SUBSYSTEM=="tty", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="230[0-3]", TAG+="uaccess"
|
||||
#+end_src
|
||||
This thing but it has little legs that fold out so that it can sit in my lap and still be small enough to travel with or use with my laptop.
|
||||
|
||||
#+begin_src yaml
|
||||
- name: udev rule installed
|
||||
copy:
|
||||
src: udev/90-keyboardio.rules
|
||||
dest: /etc/udev/rules.d/90-keyboardio.rules
|
||||
tags:
|
||||
- udev
|
||||
- atreus
|
||||
register: keyboardio_udev
|
||||
This but it's bluetooth and battery powered, running ZMK.
|
||||
|
||||
- name: udev refreshed
|
||||
shell: udevadm trigger
|
||||
when: keyboardio_udev.changed
|
||||
#+end_src
|
||||
This but the keys are aligned to match my finger-lengths based on my own measurements.
|
||||
|
||||
One of these days I'm going to teach myself enough PCB design and KiCad and Machining to produce this.
|
||||
|
||||
* File holder :noexport:
|
||||
:PROPERTIES:
|
||||
:ID: 690d03f5-abe7-4b0e-be94-086008b7fd7b
|
||||
:END:
|
||||
|
|
|
@ -10,10 +10,11 @@
|
|||
#+PROPERTY: header-args:emacs-lisp :tangle literate-programming.el
|
||||
|
||||
#+ARCOLOGY_KEY: cce/literate-programming
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
#+ARROYO_EMACS_MODULE: literate-programming
|
||||
#+ARROYO_MODULE_WANTS: cce/org_mode_installation.org
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
#+ARROYO_MODULE_WANTS: cce/diminish.org
|
||||
|
||||
=org-tempo=[fn:1] provides easy templating in org-mode buffers and I use them to make it easier to write code for the [[id:cce/cce][CCE]]. I can tab across =<s= and =<q= to expand to source and quote blocks, along with many others (and it's customisable of course through =org-tempo-keywords-alist=.)
|
||||
|
||||
|
@ -58,6 +59,7 @@ Configure what languages I want to use for org-babel:
|
|||
(gnuplot . t)
|
||||
(shell . t)
|
||||
(org . t)
|
||||
(plantuml . t)
|
||||
(js . t)))
|
||||
#+end_src
|
||||
|
||||
|
@ -87,9 +89,14 @@ Finally, =org-edit-src= simply cannot steal my window configuration from me.
|
|||
#+begin_src emacs-lisp
|
||||
(use-package org-auto-tangle
|
||||
:defer t
|
||||
:diminish
|
||||
:hook (org-mode . org-auto-tangle-mode))
|
||||
#+end_src
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(setq org-plantuml-executable-path "/nix/store/gyznjv622jqc8d1x56r7c4wp2rq8md7m-plantuml-1.2023.1/bin/plantuml")
|
||||
#+end_src
|
||||
|
||||
* Footnotes
|
||||
|
||||
[fn:1] https://orgmode.org/org.html#Structure-Templates
|
||||
|
|
|
@ -0,0 +1,504 @@
|
|||
:PROPERTIES:
|
||||
:ID: 20230331T181418.903306
|
||||
:ROAM_ALIASES: "Matrix Feedbot"
|
||||
:END:
|
||||
#+TITLE: RSS Feed Bot Posting to Matrix.org
|
||||
#+filetags: :Project:
|
||||
|
||||
#+ARCOLOGY_KEY: cce/matrix-feedbot
|
||||
#+ARDCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
#+ARROYO_NIXOS_MODULE: nixos/feedbot.nix
|
||||
#+ARROYO_NIXOS_ROLE: server
|
||||
|
||||
This is the sibling of [[id:20230125T143144.011175][Feediverse]], it's a small [[id:matrix_org_ecosystem][Matrix.org]] client which uses [[id:cce/python][Python]]'s =feedparser= library to post RSS and Atom feeds to a Matrix room. I used to run this myself and a few years ago I moved to Matrix's hosted "Neb" Bot solution since it could be configured by others. Well, they went and [[https://github.com/matrix-org/matrix-hookshot/issues/686][goofed it up]] and rather than make every feed I care about adhere 100% to a brittle parser, we'll go back to a known-working solution.
|
||||
|
||||
This is a [[id:cce/literate_programming][Literate Programming]] version of my old [[https://code.rix.si/rrix/matrix-feedbot][matrix-feedbot]] with some features added to it like being able to load some feeds from the =feeds.json= endpoint in the [[id:arcology/routing][Arcology Routing Logic]]/[[id:arroyo/feed-cache][Arroyo Feed Cache Generator]].
|
||||
|
||||
* Feeds to Post
|
||||
:PROPERTIES:
|
||||
:ID: 20230417T105045.604988
|
||||
:END:
|
||||
|
||||
This is embedded in the configuration.nix which deploys the feed bot... As always, I am up to [[id:cce/literate_programming][Literate Programming]] shenanigans.
|
||||
|
||||
#+name: urls
|
||||
| URL | Owner |
|
||||
|------------------------------------------------------------------------------+---------|
|
||||
| https://iliana.fyi/atom.xml | [[id:ab3f017f-062b-405d-a46e-f0ac338ebeb0][iliana]] |
|
||||
| https://faust.land/all/feed.atom | [[id:7f451675-1db0-4093-9d8e-28cc5d597545][Maya]] |
|
||||
| https://maya.land/feed.xml | [[id:7f451675-1db0-4093-9d8e-28cc5d597545][Maya]] |
|
||||
| https://occult.institute/@faustland.rss | [[id:7f451675-1db0-4093-9d8e-28cc5d597545][Maya]] |
|
||||
| https://dammit.nl/feeds/all.atom.xml | [[id:michiel_scholten][Michiel]] |
|
||||
| https://data.bff.fm/shows/pulse-width-mornings.rss | [[roam:Torrie Fischer][Torrie]] |
|
||||
| https://www.youtube.com/feeds/videos.xml?channel_id=UCvpCqRSI-9rPyT431QkRKig | [[roam:Torrie Fischer][Torrie]] |
|
||||
| https://makerspacemanagers.com/?format=rss | [[id:99ad3cf8-1a38-422f-8107-0d6617bf2636][Will]] |
|
||||
| https://willbradley.name/feed/ | [[id:99ad3cf8-1a38-422f-8107-0d6617bf2636][Will]] |
|
||||
| https://christine.website/blog.rss | [[roam:Xe Iaso][Xe]] |
|
||||
| https://blog.yaelwrites.com/rss/ | [[id:80e62a41-eb55-4141-acfa-3fe248dcdd7e][Yael]] |
|
||||
| https://yaelwrites.com/index.xml | [[id:80e62a41-eb55-4141-acfa-3fe248dcdd7e][Yael]] |
|
||||
|
||||
#+NAME: mkFeeds
|
||||
#+begin_src emacs-lisp :var tbl=urls :noweb-ref mkFeeds
|
||||
(->> tbl
|
||||
(--map (first it))
|
||||
(--map (format "\"%s\"" it))
|
||||
(s-join "\n"))
|
||||
#+end_src
|
||||
|
||||
* The Script Itself
|
||||
|
||||
** The Worker Class and Loop
|
||||
|
||||
Look, this thing is pretty un-exciting. It's a =while= loop with a bunch of scaffolding to persist configuration, fetch feeds, and send messages. Each of those functionalities is broken out below with the core logical loop remaining in place here.
|
||||
|
||||
#+begin_src python :tangle ~/Code/feedbot2/matrix_feedbot/feedbot.py :noweb yes :mkdirp yes
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import feedparser
|
||||
import os
|
||||
from typing import Dict
|
||||
import datetime
|
||||
import time # i hate python!!
|
||||
|
||||
from nio import AsyncClient, MatrixRoom, RoomMessageText
|
||||
|
||||
<<YamlBackedDict>>
|
||||
|
||||
class Worker():
|
||||
def __init__(self):
|
||||
path = os.environ.get("FEEDBOT_CONFIG", "./cfg.yaml")
|
||||
cred_path = os.environ.get("FEEDBOT_CREDENTIALS_CONFIG", "./creds.yaml")
|
||||
cache_path = os.environ.get("FEEDBOT_CACHE", "./cache.yaml")
|
||||
|
||||
self.config = YamlBackedDict(path, self.stub_config)
|
||||
self.credentials = YamlBackedDict(cred_path, self.stub_creds)
|
||||
|
||||
cache = { feed: set() for feed in self.config["feeds"] }
|
||||
self.cache = YamlBackedDict(cfg_path=cache_path, stub_fn=self.stub_cache)
|
||||
self.cache._dict = {**cache, **self.cache._dict}
|
||||
|
||||
self.client = AsyncClient(self.credentials["homeserver"],
|
||||
self.credentials["username"])
|
||||
self.last_fetch = datetime.datetime.fromtimestamp(0)
|
||||
|
||||
|
||||
async def main(self) -> None:
|
||||
await self.login()
|
||||
self.client.add_event_callback(self.message_callback, RoomMessageText)
|
||||
|
||||
while True:
|
||||
td = datetime.datetime.now() - self.last_fetch
|
||||
if td > datetime.timedelta(hours=1):
|
||||
print("refreshing...")
|
||||
await self.maybe_fetch_feeds()
|
||||
await self.maybe_fetch_dynamic_feeds()
|
||||
self.cache.save()
|
||||
self.last_fetch = datetime.datetime.now()
|
||||
print("ahh...")
|
||||
await self.client.sync(timeout=30*1000)
|
||||
|
||||
|
||||
<<stub-functions>>
|
||||
<<message>>
|
||||
<<feed-fetch>>
|
||||
|
||||
|
||||
async def login(self) -> None:
|
||||
if self.credentials.get("access_token") is None:
|
||||
login_resp = await self.client.login(self.credentials["password"])
|
||||
self.credentials["access_token"] = login_resp.access_token
|
||||
self.credentials["device_id"] = login_resp.device_id
|
||||
self.credentials.save()
|
||||
else:
|
||||
self.client.access_token = self.credentials["access_token"]
|
||||
self.client.device_id = self.credentials["device_id"]
|
||||
|
||||
for room_id in self.config["rooms"]:
|
||||
await self.client.join(room_id)
|
||||
|
||||
|
||||
def run():
|
||||
w = Worker()
|
||||
asyncio.get_event_loop().run_until_complete(w.main())
|
||||
#+end_src
|
||||
|
||||
** Fetch and Parse Feeds Asynchronously
|
||||
|
||||
These functions, starting with =fetch_feed_url= create an =async= function which will handle feed parsing and whatnot all the way through sending the message. =maybe_fetch_dynamic_feeds= will reach out to the Arcology's feeds.json endpoint and iterate over each of those, and =maybe_fetch_feeds= will iterate over the statically defined ones.
|
||||
|
||||
#+begin_src python :noweb-ref feed-fetch
|
||||
async def maybe_fetch_feeds(self):
|
||||
feedurls = self.config["feeds"]
|
||||
|
||||
for feed in feedurls:
|
||||
await self.fetch_feed_url(feed)
|
||||
|
||||
|
||||
async def maybe_fetch_dynamic_feeds(self):
|
||||
for feed_config in self.config['dynamic_urls']:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
data = await self.fetch(session, feed_config)
|
||||
data = yaml.safe_load(data) # it's json and json is yaml so hahaha
|
||||
for feed in data:
|
||||
self.cache[feed['url']] = self.cache.get(feed['url'], set())
|
||||
await self.fetch_feed_url(feed['url'])
|
||||
|
||||
async def fetch_feed_url(self, feed):
|
||||
"""
|
||||
greetz to https://stackoverflow.com/questions/23847555/asynchronous-feedparser-requests
|
||||
"""
|
||||
async with aiohttp.ClientSession() as session:
|
||||
data = await self.fetch(session, feed)
|
||||
rss = feedparser.parse(data)
|
||||
|
||||
print(f"got {feed} w/ {len(rss['entries'])}")
|
||||
def filter_old_entries(entry):
|
||||
if entry['updated_parsed'].tm_year > 1969:
|
||||
entry_time = datetime.datetime.fromtimestamp(time.mktime(entry['updated_parsed']))
|
||||
if datetime.datetime.now() - entry_time < datetime.timedelta(hours=24) and entry['link'] not in self.cache[feed]:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
entries_filtered = filter(filter_old_entries, rss['entries'])
|
||||
entries_sorted = sorted(entries_filtered, key=lambda entry: entry['updated_parsed'])
|
||||
for entry in entries_sorted:
|
||||
await self.send_message(rss, entry)
|
||||
self.cache[feed].add(str(entry['link']))
|
||||
# if a post is made, we need to save the cache so that we don't spam our friends
|
||||
self.cache.save()
|
||||
|
||||
|
||||
async def fetch(self, session, url):
|
||||
async with session.get(url) as response:
|
||||
return await response.text()
|
||||
#+end_src
|
||||
|
||||
** Message Formatting and Sending
|
||||
|
||||
#+begin_src python :noweb-ref message
|
||||
async def message_callback(self, room: MatrixRoom, event: RoomMessageText) -> None:
|
||||
pass
|
||||
|
||||
async def send_message(self, feed, entry):
|
||||
# construct message
|
||||
html = ''.join([
|
||||
'New in <a href="', feed['feed']['link'], '">',
|
||||
feed['feed']['title'],
|
||||
'</a>: <a href="', entry['link'], '">', entry.get('title', entry.get('link')), '</a>'
|
||||
])
|
||||
text = ''.join([
|
||||
'New in', feed['feed']['title'],
|
||||
': ', entry['link'], " - ", entry.get('title', entry.get('link'))
|
||||
])
|
||||
|
||||
print(text)
|
||||
print(html)
|
||||
# TKTKTK configure which rooms a feed goes tooo.
|
||||
# TKTKTK configure how often to scrape a feed
|
||||
for room_id in self.config['rooms']:
|
||||
print(await self.client.room_send(
|
||||
room_id=room_id,
|
||||
message_type="m.room.message",
|
||||
|
||||
content={"msgtype": "m.text",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": html,
|
||||
"body": text },
|
||||
))
|
||||
#+end_src
|
||||
|
||||
** =YamlBackedDict=
|
||||
|
||||
I have this stupid config structure i made which is just used to load and persist a YAML file:
|
||||
|
||||
#+begin_src python :noweb-ref YamlBackedDict
|
||||
import yaml
|
||||
|
||||
class YamlBackedDict():
|
||||
def __init__(self, cfg_path: str, stub_fn):
|
||||
self.path = cfg_path
|
||||
self.stub_generator = stub_fn
|
||||
self._dict = self.load()
|
||||
|
||||
def __setitem__(self, k, v):
|
||||
self._dict[k] = v
|
||||
|
||||
def __getitem__(self, k):
|
||||
return self._dict[k]
|
||||
|
||||
def __str__(self):
|
||||
return str(self._dict)
|
||||
|
||||
def get(self, k, default=None):
|
||||
return self._dict.get(k, default)
|
||||
|
||||
def stub(self):
|
||||
cfg = self.stub_generator()
|
||||
|
||||
with open(self.path, 'w') as f:
|
||||
yaml.dump(cfg, f)
|
||||
|
||||
return cfg
|
||||
|
||||
def load(self):
|
||||
if not os.path.exists(self.path):
|
||||
cfg = self.stub()
|
||||
else:
|
||||
with open(self.path, 'r') as f:
|
||||
cfg = yaml.safe_load(f)
|
||||
|
||||
return cfg
|
||||
|
||||
def save(self):
|
||||
with open(self.path, 'w') as f:
|
||||
return yaml.safe_dump(self._dict, f)
|
||||
#+end_src
|
||||
|
||||
The YAML files each have an un-documented schema because I am an asshole; because I am not an asshole, there is a function which will stub each of them when they are not existing, these are passed in to the constructor to =YamlBackedDict= and listed as part of the =Worker= class but if I do more work on this it should probably be sub-classes..
|
||||
|
||||
#+begin_src python :noweb-ref stub-functions
|
||||
def stub_creds(ybd) -> Dict:
|
||||
return dict(
|
||||
username=input("Enter the Matrix username: "),
|
||||
password=input("Enter the Matrix password: "),
|
||||
homeserver=input("Enter the Matrix homserver URL: "),
|
||||
)
|
||||
|
||||
|
||||
def stub_config(ybd) -> Dict:
|
||||
return dict(
|
||||
rooms=[
|
||||
input("Enter the first room ID to join (starts with ! not #): "),
|
||||
],
|
||||
feeds=[],
|
||||
dynamic_urls=[],
|
||||
)
|
||||
|
||||
|
||||
def stub_cache(ybd) -> Dict:
|
||||
# would be nice if this could include the set() logic in __init__ but...
|
||||
return dict()
|
||||
#+end_src
|
||||
|
||||
** To-do :noexport:
|
||||
*** NEXT integrate =click=
|
||||
*** INPROGRESS detangle
|
||||
:LOGBOOK:
|
||||
- State "INPROGRESS" from "NEXT" [2023-04-11 Tue 12:15]
|
||||
:END:
|
||||
|
||||
*** NEXT feed -> roomlist mappings? so that my dev feeds can also go to my devlog rooms
|
||||
|
||||
*** NEXT commands in message_callback
|
||||
|
||||
*** INPROGRESS tag feeds based on fetch recency rather than using a sleep so that the commands don't block
|
||||
:LOGBOOK:
|
||||
- State "INPROGRESS" from "NEXT" [2023-04-01 Sat 00:23]
|
||||
:END:
|
||||
|
||||
*** DONE store access_token in config
|
||||
:LOGBOOK:
|
||||
- State "DONE" from "NEXT" [2023-04-11 Tue 12:14]
|
||||
:END:
|
||||
|
||||
*** DONE register bot user
|
||||
:LOGBOOK:
|
||||
- Note taken on [2023-04-11 Tue 10:50] \\
|
||||
=docker exec -it matrix-synapse /opt/synapse/bin/python /opt/synapse/bin/register_new_matrix_user -c /data/homeserver.yaml= on fontkeming
|
||||
- State "DONE" from "NEXT" [2023-04-11 Tue 10:50]
|
||||
:END:
|
||||
|
||||
*** DONE split out the credentials loading from the configuration so that i don't commit those to the nix store
|
||||
:LOGBOOK:
|
||||
- State "DONE" from "NEXT" [2023-04-11 Tue 12:35]
|
||||
:END:
|
||||
* pyproject/poetry definition
|
||||
|
||||
I'll be a fool and use poetry for this even though I don't really need to.
|
||||
|
||||
#+begin_src toml :tangle ~/Code/feedbot2/pyproject.toml
|
||||
[tool.poetry]
|
||||
name = "matrix-feedbot"
|
||||
version = "0.0.0"
|
||||
description = "Send RSS feeds to a Matrix room"
|
||||
license = "GPL-3.0-only"
|
||||
authors = [
|
||||
"Ryan Rix <code@whatthefuck.computer>"
|
||||
]
|
||||
|
||||
packages = [
|
||||
{ include = "matrix_feedbot" }
|
||||
]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.10"
|
||||
matrix-nio = "^0.20"
|
||||
feedparser = "^6.0.10"
|
||||
pyyaml = "^6.0"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
feedbot = 'matrix_feedbot.feedbot:run'
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
#+end_src
|
||||
|
||||
** NEXT In theory this could support e2e but lol, it's fine. Maybe later.
|
||||
|
||||
* Deploy to [[id:20211120T220054.226284][The Wobserver]]
|
||||
:PROPERTIES:
|
||||
:ID: 20230411T153058.351319
|
||||
:END:
|
||||
:LOGBOOK:
|
||||
- State "DONE" from "INPROGRESS" [2023-04-17 Mon 10:58]
|
||||
- State "INPROGRESS" from "NEXT" [2023-04-11 Tue 14:50]
|
||||
:END:
|
||||
|
||||
** Nix Shell setup
|
||||
|
||||
#+begin_src nix :tangle ~/Code/feedbot2/shell.nix :mkdirp yes
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
|
||||
let
|
||||
myPython = pkgs.python3.withPackages (ppkgs:
|
||||
with ppkgs; [
|
||||
feedparser
|
||||
click
|
||||
pyyaml
|
||||
matrix-nio
|
||||
]);
|
||||
in
|
||||
pkgs.mkShell {
|
||||
packages = [
|
||||
pkgs.poetry
|
||||
myPython
|
||||
];
|
||||
}
|
||||
#+end_src
|
||||
|
||||
** Package feedbot in [[id:20221021T121120.541960][rixpkgs]]
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/pkgs/feedbot.nix
|
||||
{ lib,
|
||||
fetchFromGitHub,
|
||||
python3Packages,
|
||||
callPackage,
|
||||
}:
|
||||
|
||||
python3Packages.buildPythonPackage {
|
||||
pname = "matrix-feedbot";
|
||||
|
||||
version = "0.0.1";
|
||||
src = /home/rrix/Code/feedbot2;
|
||||
|
||||
format = "pyproject";
|
||||
|
||||
propagatedBuildInputs = with python3Packages; [ matrix-nio feedparser pyyaml ];
|
||||
buildInputs = with python3Packages; [ poetry-core ];
|
||||
|
||||
# checkInputs = with python3Packages; [];
|
||||
|
||||
meta = {
|
||||
homepage = "https://cce.whatthefuck.computer/matrix-feedbot";
|
||||
description = "Post RSS/Atom feeds to Matrix";
|
||||
license = lib.licenses.agpl3Only;
|
||||
maintainers = with lib.maintainers; [ rrix ];
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
** Deploy in [[id:arroyo/nixos][Arroyo NixOS]]
|
||||
|
||||
This is set up to take options; in theory some day someone else could use this... but for now it's mostly for my own benefit.
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/feedbot.nix :noweb yes
|
||||
{ lib, pkgs, config, ... }:
|
||||
|
||||
with lib; {
|
||||
options.services.feedbot = {
|
||||
enabled = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.matrix-feedbot;
|
||||
};
|
||||
|
||||
workDir = mkOption {
|
||||
type = types.str;
|
||||
default = "/srv/feedbot";
|
||||
};
|
||||
|
||||
credentialsFileLocation = mkOption {
|
||||
type = types.path;
|
||||
default = "/srv/feedbot/creds.yaml";
|
||||
};
|
||||
|
||||
cacheFileLocation = mkOption {
|
||||
type = types.path;
|
||||
default = "/srv/feedbot/cache.yaml";
|
||||
};
|
||||
|
||||
rooms = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ "!THQSEcCQbqCZqLGUbG:kickass.systems" ];
|
||||
};
|
||||
|
||||
dynamicFeedUrls = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ "https://thelionsrear.com/feeds.json" ];
|
||||
};
|
||||
|
||||
feedUrls = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [
|
||||
<<mkFeeds()>>
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
users.groups.feedbot = {};
|
||||
users.users.feedbot = {
|
||||
createHome = true;
|
||||
home = config.services.feedbot.workDir;
|
||||
group = "feedbot";
|
||||
isSystemUser = true;
|
||||
};
|
||||
systemd.services.feedbot = mkIf config.services.feedbot.enabled {
|
||||
enable = true;
|
||||
description = "Post RSS and Atom feeds to a Matrix room.";
|
||||
after = [ "network.target" ];
|
||||
script = "${config.services.feedbot.package}/bin/feedbot";
|
||||
wantedBy = [ "default.target" ];
|
||||
|
||||
environment = {
|
||||
FEEDBOT_CONFIG = pkgs.writeTextFile {
|
||||
name = "feedbot.config.yaml";
|
||||
text = generators.toYAML {} {
|
||||
feeds = config.services.feedbot.feedUrls;
|
||||
dynamic_urls = config.services.feedbot.dynamicFeedUrls;
|
||||
rooms = config.services.feedbot.rooms;
|
||||
};
|
||||
};
|
||||
FEEDBOT_CREDENTIALS_CONFIG = config.services.feedbot.credentialsFileLocation;
|
||||
FEEDBOT_CACHE = config.services.feedbot.cacheFileLocation;
|
||||
};
|
||||
|
||||
serviceConfig = {
|
||||
RestartSec = 5;
|
||||
Restart = "on-failure";
|
||||
User = "feedbot";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
114
mbsync.org
114
mbsync.org
|
@ -39,90 +39,55 @@ Here's the one for getting things from my server to my laptop. Most folks who se
|
|||
{
|
||||
programs.mbsync.enable = true;
|
||||
accounts.email.maildirBasePath = "/home/rrix/Maildir";
|
||||
accounts.email.accounts.endpoint = {
|
||||
accounts.email.accounts.fastmail = {
|
||||
address = "ryan@whatthefuck.computer";
|
||||
realName = "Ryan Rix (rrix)";
|
||||
|
||||
aliases = [ "ry@n.rix.si" "rrix@fastmail.com" ];
|
||||
# aliases = [ "ry@n.rix.si" "rrix@fastmail.com" ];
|
||||
userName = "rrix@fastmail.com";
|
||||
passwordCommand = "${pkgs.rbw}/bin/rbw get fastmail_email_app";
|
||||
maildir.path = "fastmail";
|
||||
|
||||
primary = false; # outbox goes through fastmail smtp
|
||||
|
||||
passwordCommand = "pass show fastmail_email_app";
|
||||
|
||||
imap.host = "fontkeming.fail";
|
||||
imap.tls.enable = false;
|
||||
imap = {
|
||||
host = "mail.messagingengine.com";
|
||||
};
|
||||
|
||||
mbsync = {
|
||||
enable = true;
|
||||
subFolders = "Verbatim";
|
||||
groups = {
|
||||
endpoint = {
|
||||
channels = {
|
||||
high-priority = {
|
||||
extraConfig.Create = "near";
|
||||
patterns = [
|
||||
"fastmail/INBOX"
|
||||
"fastmail/github"
|
||||
"fastmail/Sent\\ Mail"
|
||||
"fastmail/fedora/bugs"
|
||||
];
|
||||
};
|
||||
low-priority = {
|
||||
extraConfig = {
|
||||
MaxMessages = 1000;
|
||||
MaxSize = "10m";
|
||||
Create = "near";
|
||||
ExpireUnread = "no";
|
||||
};
|
||||
patterns = [
|
||||
"fastmail/newsletters"
|
||||
"fastmail/social"
|
||||
"fastmail/emacsconf"
|
||||
"fastmail/phoenix-lug"
|
||||
"fastmail/RecruitingSpam"
|
||||
"fastmail/Junk Mail"
|
||||
];
|
||||
};
|
||||
feeds = {
|
||||
patterns = [
|
||||
"feeds/Art"
|
||||
"feeds/Blogs"
|
||||
"feeds/Brain"
|
||||
"feeds/Motorsports"
|
||||
"feeds/News"
|
||||
"feeds/Self"
|
||||
"feeds/Software"
|
||||
"feeds/Tea"
|
||||
"feeds/Tech"
|
||||
"feeds/Videos"
|
||||
"feeds/Longreads"
|
||||
];
|
||||
extraConfig = {
|
||||
MaxSize = "10m";
|
||||
Create = "near";
|
||||
ExpireUnread = "no";
|
||||
};
|
||||
};
|
||||
work = {
|
||||
patterns = [
|
||||
"crdigital/INBOX"
|
||||
"crdigital/[Gmail]/Sent Mail"
|
||||
];
|
||||
extraConfig = {
|
||||
MaxMessages = 1000;
|
||||
MaxSize = "10m";
|
||||
Create = "near";
|
||||
ExpireUnread = "no";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
extraConfig = {
|
||||
account = {
|
||||
Timeout = 120;
|
||||
Tunnel = "ssh -q fontkeming /usr/libexec/dovecot/imap";
|
||||
};
|
||||
};
|
||||
|
||||
groups = {
|
||||
all = {
|
||||
channels = {
|
||||
top = {
|
||||
extraConfig.Create = "near";
|
||||
patterns = [
|
||||
"INBOX"
|
||||
"1ml"
|
||||
"1ml/bcz"
|
||||
"1ml/friendsofsecurityplanner"
|
||||
"Junk Mail"
|
||||
"RecruitingSpam"
|
||||
"Sent Mail"
|
||||
"emacsconf"
|
||||
"fedora/bugs"
|
||||
"github"
|
||||
"newsletters"
|
||||
"phoenix-lug"
|
||||
"social"
|
||||
];
|
||||
};
|
||||
rest = {
|
||||
extraConfig.Create = "near";
|
||||
patterns = [
|
||||
"*"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -131,3 +96,4 @@ Here's the one for getting things from my server to my laptop. Most folks who se
|
|||
#+end_src
|
||||
|
||||
The last time I used =mbsync=, I experienced issues with mail IDs in my =newsrc.eld= file, which Gnus uses to store which lists I am subscribed too, and also functions as a cache for message and folder states. The latter caching was what caused these issues, I believe, but it was really difficult to debug it. If this happens again, I may switch to [[id:fa7e9d10-a98d-4036-a668-889bd1d3ea29][offlineimap]].
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ This is a simple [[id:cce/cce][CCE]] [[id:cce/home-manager][home-manager]] helpe
|
|||
config: src: dest:
|
||||
|
||||
config.lib.dag.entryAfter ["writeBoundary"] ''
|
||||
mkdir -p $(dirname ${dest})
|
||||
$DRY_RUN_CMD test -e $HOME/${dest} || \
|
||||
$DRY_RUN_CMD ln -s $VERBOSE_ARG \
|
||||
${src} $HOME/${dest}
|
||||
|
|
|
@ -0,0 +1,224 @@
|
|||
:PROPERTIES:
|
||||
:ID: 20230530T120958.265094
|
||||
:ROAM_ALIASES: "Morph Command Wrapper"
|
||||
:END:
|
||||
#+TITLE: Wrapping Morph commands for more ergonomic deployment
|
||||
|
||||
#+ARCOLOGY_KEY: cce/morph-wrapper
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
#+ARROYO_DIRENV_DIR: ~/Code/morph-wrapper/
|
||||
#+AUTO_TANGLE: t
|
||||
|
||||
After [[id:20230529T205533.092875][I tried setting up deploy-rs and it (and flakes) is kind of not very good for what I am doing with my computers]] yesterday, I found that I still want to simplify my deploy tooling to make it easier to ship updates of my Nix systems to their hosts.
|
||||
|
||||
#+ATTR_HTML: :width 40em
|
||||
#+CAPTION: a dogshit vince mcmahon meme i made showing the progression from morph, to flake experiments, and back to morph
|
||||
[[https://files.fontkeming.fail/s/74KK77RDgfHQyLD/download/terrible-meme-morph-wrapper.png]]
|
||||
|
||||
I landed on a solution inspired by [[roam:Xe Iaso]]'s [[https://github.com/Xe/nixos-configs/blob/master/ops/metadata/hosts.toml][hosts.toml]] setup. See [[id:20230530T120902.994787][Deploying from my =hosts.toml= ]] for how this file is created, structured, and used in the =morph= commands themselves.
|
||||
|
||||
This page outlines a very simple script which ingests that =hosts.toml= file and provides a handful of options to make it easy for me to just specify hostnames and have the system figure out which manifest they should apply to and what to do with them.
|
||||
|
||||
We use =toml= and =click= and some builtins.
|
||||
|
||||
#+begin_src python :mkdirp yes :tangle ~/Code/morph-wrapper/morph_wrapper/wrapper.py
|
||||
import toml
|
||||
import click
|
||||
|
||||
import os
|
||||
import socket
|
||||
|
||||
import subprocess
|
||||
#+end_src
|
||||
|
||||
Short help options are good imo, [[https://click.palletsprojects.com/en/8.1.x/documentation/#help-parameter-customization][customize that]].
|
||||
|
||||
#+begin_src python :mkdirp yes :tangle ~/Code/morph-wrapper/morph_wrapper/wrapper.py
|
||||
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
|
||||
#+end_src
|
||||
|
||||
=deploy-targets= will print out the hostnames of all the hosts in the =hosts.toml= file suitable for using in [[id:20211130T215142.470274][arroyo-flood]] or so to interactively pick hostnames to deploy to.
|
||||
|
||||
#+begin_src
|
||||
Usage: deploy-targets [OPTIONS]
|
||||
|
||||
print a list of all the hosts in the hosts.toml
|
||||
|
||||
Options:
|
||||
-f FILENAME hosts.toml file path
|
||||
-h, --help Show this message and exit.
|
||||
#+end_src
|
||||
|
||||
#+begin_src python :mkdirp yes :tangle ~/Code/morph-wrapper/morph_wrapper/wrapper.py
|
||||
@click.command(context_settings=CONTEXT_SETTINGS)
|
||||
@click.option('-f', 'hosts_file',
|
||||
envvar="HOSTS_TOML", type=click.File('r'),
|
||||
help="hosts.toml file path",
|
||||
default="/home/rrix/arroyo-nix/networks/hosts.toml")
|
||||
def list_hosts(hosts_file):
|
||||
"""
|
||||
print a list of all the hosts in the hosts.toml
|
||||
"""
|
||||
network = toml.load(hosts_file)
|
||||
for netname, host in get_all_hosts(network):
|
||||
print(host)
|
||||
#+end_src
|
||||
|
||||
=deploy= does the thing. If you try to deploy to a host which cannot be pinged, it will be skipped. This doesn't read =targetHost= from the Morph network file, but those are lined up for me. =-f= will override this behavior, this is useful to me when I am bootstrapping a node.
|
||||
|
||||
#+begin_src
|
||||
Usage: deploy [OPTIONS] [HOSTS]...
|
||||
|
||||
build or deploy one or more hosts
|
||||
|
||||
Options:
|
||||
-f FILENAME hosts.toml file path
|
||||
--all deploy to all hosts in the manifest
|
||||
--deploy / -b, --build choose whether to deploy or just build.
|
||||
-a, --action TEXT choose the deploy action
|
||||
-c, --confirm / -C, --no-confirm
|
||||
ask before running morph commands
|
||||
-h, --help Show this message and exit.
|
||||
#+end_src
|
||||
|
||||
#+begin_src python :mkdirp yes :tangle ~/Code/morph-wrapper/morph_wrapper/wrapper.py
|
||||
@click.command(context_settings=CONTEXT_SETTINGS)
|
||||
@click.option('-f', 'hosts_file',
|
||||
envvar="HOSTS_TOML",
|
||||
help="hosts.toml file path",
|
||||
type=click.File('r'),
|
||||
default="/home/rrix/arroyo-nix/networks/hosts.toml")
|
||||
@click.option('--all', 'deploy_all', is_flag=True, default=False,
|
||||
help="deploy to all hosts in the manifest")
|
||||
@click.option(' /-b', '--deploy/--build', 'do_deploy',
|
||||
help="choose whether to deploy or just build.", is_flag=True, default=True)
|
||||
@click.option('-a', '--action', 'deploy_action',
|
||||
help="choose the deploy action", default="switch")
|
||||
@click.option('-c/-C', '--confirm/--no-confirm', 'confirm',
|
||||
help="ask before running morph commands", is_flag=True, default=False)
|
||||
@click.option('-f', '--force/--no-force', 'force',
|
||||
help="Don't skip unavailable hosts", is_flag=True, default=False)
|
||||
@click.argument('hosts', nargs=-1)
|
||||
def wrap(hosts_file, deploy_all, hosts, do_deploy, deploy_action, confirm, force):
|
||||
"""
|
||||
build or deploy one or more hosts
|
||||
"""
|
||||
network = toml.load(hosts_file)
|
||||
|
||||
if deploy_all:
|
||||
hosts = [h for net,h in get_all_hosts(network)]
|
||||
elif len(hosts) == 0:
|
||||
hosts = (socket.gethostname(),)
|
||||
|
||||
subnets_to_deploy = get_pairs(network, hosts)
|
||||
|
||||
for network, host in subnets_to_deploy:
|
||||
|
||||
if do_deploy:
|
||||
if force or host_available(host):
|
||||
cmd = f"morph deploy --on={host} --passwd ~/arroyo-nix/networks/{network}.nix {deploy_action}"
|
||||
else:
|
||||
click.echo(f"{host} is unavailable, skipping...")
|
||||
continue
|
||||
else:
|
||||
cmd = f"morph build --on={host} ~/arroyo-nix/networks/{network}.nix"
|
||||
|
||||
click.echo(f"Prepared to run '{cmd}'")
|
||||
if confirm:
|
||||
input("or hit ctrl-c... ")
|
||||
os.system(cmd)
|
||||
|
||||
def host_available(hostname: str) -> bool:
|
||||
proc = subprocess.run(f"ping -w 1 -c 1 {hostname}", shell=True, capture_output=True)
|
||||
return proc.returncode == 0
|
||||
#+end_src
|
||||
|
||||
And these ugly list-comprehensions help to munge the TOML file in to a form the python commands here would like to use.
|
||||
|
||||
#+begin_src python :mkdirp yes :tangle ~/Code/morph-wrapper/morph_wrapper/wrapper.py
|
||||
def get_all_hosts(network):
|
||||
return [
|
||||
(name, host)
|
||||
for name, net in network.items()
|
||||
for host in net['hosts'].keys()
|
||||
]
|
||||
|
||||
def get_pairs(network, hosts):
|
||||
return [
|
||||
(netname, hostname)
|
||||
for netname, subnet in network.items()
|
||||
for hostname in hosts
|
||||
if hostname in subnet['hosts'].keys()
|
||||
]
|
||||
#+end_src
|
||||
|
||||
This is made available to my system builds in my [[id:20221021T121120.541960][rixpkgs]] overlay, and added like this:
|
||||
|
||||
#+ARROYO_NIXOS_MODULE: nixos/morph-wrapper.nix
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/morph-wrapper.nix
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
environment.systemPackages = [ pkgs.morph-wrapper ];
|
||||
}
|
||||
#+end_src
|
||||
|
||||
So now when I make changes I can type =deploy -b= in to my nearest terminal to see my local system's build come together, then =deploy= to deploy it to this machine, then =deploy $hostnames= to deploy it to any number of my hostnames or =deploy --all= to deploy it everywhere.
|
||||
|
||||
* Shell Environment and Pyproject manifest
|
||||
|
||||
This uses =poetry= and =poetry2nix= to generate a python application and nix derivation for use in my systems, a =shell.nix= is provided as well:
|
||||
|
||||
#+begin_src toml :mkdirp yes :tangle ~/Code/morph-wrapper/pyproject.toml
|
||||
[tool.poetry]
|
||||
name = "morph-wrapper"
|
||||
version = "0.1.0"
|
||||
description = ""
|
||||
authors = ["Ryan Rix <code@whatthefuck.computer>"]
|
||||
|
||||
include = []
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.10"
|
||||
toml = "^0.10.2"
|
||||
click = "^8.1.3"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
deploy = 'morph_wrapper.wrapper:wrap'
|
||||
deploy-targets = 'morph_wrapper.wrapper:list_hosts'
|
||||
#+end_src
|
||||
|
||||
#+begin_src nix :tangle ~/Code/morph-wrapper/shell.nix
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
let
|
||||
python-with-my-packages = pkgs.python3.withPackages (p: with p; [
|
||||
toml
|
||||
click
|
||||
]);
|
||||
in
|
||||
pkgs.mkShell {
|
||||
packages = [
|
||||
python-with-my-packages
|
||||
pkgs.poetry
|
||||
];
|
||||
}
|
||||
#+end_src
|
||||
|
||||
#+begin_src nix :tangle ~/Code/morph-wrapper/default.nix
|
||||
{ pkgs ? import <nixpkgs> {},
|
||||
poetry2nix ? pkgs.poetry2nix,
|
||||
stdenv ? pkgs.stdenv,
|
||||
python ? pkgs.python3 }:
|
||||
|
||||
poetry2nix.mkPoetryApplication {
|
||||
inherit python;
|
||||
projectDir = ./.;
|
||||
propagatedBuildInputs = [];
|
||||
}
|
||||
#+end_src
|
616
morph.org
616
morph.org
|
@ -16,38 +16,316 @@ Morph is a tool for managing existing NixOS hosts - basically a fancy wrapper ar
|
|||
|
||||
Interestingly, it seems like I can just use my [[id:cce/nixops][NixOps]] laptop profile...? stealin' it! that's nice.
|
||||
|
||||
* Deploying My Laptops
|
||||
In the embeds you'll learn how I pick the hostnames for my computers.
|
||||
|
||||
* Deploying from my =hosts.toml=
|
||||
:PROPERTIES:
|
||||
:ID: 20230530T120902.994787
|
||||
:END:
|
||||
|
||||
Morph is fine to use, but it's a little bit unergonomic, especially if i want to blast out builds to a bunch of hosts. I am taking a cue from [[https://xeiaso.net/][Xe Iaso]] and moving toward defining my host configurations in a =hosts.toml= file. For now, it only has the bare necessities to generate deployment networks for each of my roles, but it could be extended with other things like SSH host keys, or encrypted secrets in the near future. I'm also planning to write a little python script so that I can type to my computer =deploy virtuous-cassette= and have that roll out rather than the complicated [[id:20220912T114451.341788][Shell Spell]] =morph deploy --on=virtuous-cassette --passwd ~/arroyo-nix/networks/laptops.nix switch=.
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/networks/mkNetwork.nix
|
||||
{ pkgs, networks }:
|
||||
|
||||
let
|
||||
mkHost = rollConfig: hostname: config:
|
||||
let hostConfig = ./. + "/../hosts/${hostname}";
|
||||
in
|
||||
{
|
||||
imports = [ rollConfig hostConfig ];
|
||||
deployment.targetHost = (if config ? target then config.target else hostname);
|
||||
deployment.targetUser = (if config ? user then config.user else "rrix");
|
||||
} // (if config ? stateVersion then {
|
||||
system.stateVersion = config.stateVersion;
|
||||
} else {});
|
||||
|
||||
mkNetwork = subnet:
|
||||
let
|
||||
network = networks."${subnet}";
|
||||
roleConfig = ./. + "/${network.config}";
|
||||
mkHost' = mkHost roleConfig;
|
||||
in
|
||||
{
|
||||
network.pkgs = pkgs;
|
||||
network.description = network.description;
|
||||
network.enableRollback = (if network ? enableRollback then network.enableRollback else true);
|
||||
} // builtins.mapAttrs mkHost' network.hosts;
|
||||
in mkNetwork
|
||||
#+end_src
|
||||
|
||||
this =mkNetwork= function is easy to operate as you can see below; it provides reasonable defaults so that my Tailscale-backed hosts can just be added to the network with a single line. Bootstrapping hosts is as simple as adding the local DHCP address as the =target= key and setting the =user= for the first SSH.
|
||||
|
||||
* Deploying My Laptops and Desktop
|
||||
:PROPERTIES:
|
||||
:ID: cce/morph-laptops
|
||||
:END:
|
||||
|
||||
My laptops are installed through my [[id:cce/nixos_automatic_partitioning_installer][NixOS Automatic Partitioning Installer]] and carry [[id:cce/my_nixos_configuration][My NixOS configuration for laptops]], the "endpoint configuration".
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/networks/laptops.nix :mkdirp yes
|
||||
#+begin_src nix :tangle ~/arroyo-nix/networks/endpoints.nix
|
||||
let
|
||||
endpointCfg = ../roles/endpoint;
|
||||
# nixpkgsPin = (import ../versions.nix {}).nixpkgs;
|
||||
# pkgs = import (builtins.fetchTarball nixpkgsPin) {};
|
||||
pkgs = import <nixpkgs> {};
|
||||
in {
|
||||
network.pkgs = pkgs;
|
||||
network.description = "my laptops";
|
||||
network.enableRollback = true;
|
||||
allNetworks = pkgs.lib.importTOML ./hosts.toml;
|
||||
mkNetwork = import ./mkNetwork.nix { inherit pkgs; networks = allNetworks; };
|
||||
in mkNetwork "endpoints"
|
||||
#+end_src
|
||||
|
||||
meadow-crush = {config, pkgs, ...}:
|
||||
{
|
||||
imports = [ endpointCfg ../hosts/meadow-crush ];
|
||||
deployment.targetHost = "meadow-crush";
|
||||
deployment.targetUser = "root";
|
||||
system.stateVersion = "22.05";
|
||||
#+begin_src toml :tangle ~/arroyo-nix/networks/hosts.toml
|
||||
[endpoints]
|
||||
description = "my laptops and desktop"
|
||||
enableRollback = true
|
||||
config = "../roles/endpoint"
|
||||
#+end_src
|
||||
|
||||
** Rose Quine
|
||||
:PROPERTIES:
|
||||
:ID: 20230328T191051.959009
|
||||
:END:
|
||||
|
||||
#+begin_export html
|
||||
<iframe style="border: 0; width: 200px; height: 200px;" src="https://bandcamp.com/EmbeddedPlayer/album=1563537773/size=large/bgcol=ffffff/linkcol=2ebd35/minimal=true/track=1268670717/transparent=true/" seamless><a href="https://theflashbulb.bandcamp.com/album/our-simulacra">Our Simulacra by The Flashbulb</a></iframe>
|
||||
#+end_export
|
||||
|
||||
Rose Quine is my [[id:20230404T153703.708523][GPD Pocket 3]].
|
||||
|
||||
#+begin_src toml :tangle ~/arroyo-nix/networks/hosts.toml
|
||||
[endpoints.hosts.rose-quine]
|
||||
# target = "rose-quine"
|
||||
# stateVersion = "23.05"
|
||||
#+end_src
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/hosts/rose-quine/default.nix :mkdirp yes
|
||||
{ config, pkgs, lib, ... }:
|
||||
{
|
||||
imports = [ <arroyo/nixos/gpd-pocket-3.nix> ];
|
||||
|
||||
networking.hostName = "rose-quine";
|
||||
system.stateVersion = "23.05";
|
||||
|
||||
services.xserver.dpi = 280;
|
||||
|
||||
services.tailscale.authKey = "tskey-auth-knLBN35CNTRL-ignbakuis45bC5m5mrvX95o4DW9JHoRV8";
|
||||
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
boot.loader.grub.efiSupport = true;
|
||||
boot.loader.grub.device = "nodev";
|
||||
boot.loader.grub.enable = true;
|
||||
boot.loader.grub.gfxmodeBios = "1200x1920x32";
|
||||
boot.loader.systemd-boot.enable = lib.mkForce false;
|
||||
# boot.loader.systemd-boot.consoleMode = "max";
|
||||
|
||||
networking.hostId = "3f5dbbf9"; # required for zfs use
|
||||
boot.zfs.devNodes = "/dev/mapper"; # (ref:devNodes)
|
||||
boot.initrd.luks.devices = {
|
||||
"swap" = { name = "swap"; device = "/dev/nvme0n1p2"; preLVM = true; };
|
||||
"root" = { name = "root"; device = "/dev/nvme0n1p3"; preLVM = true; };
|
||||
};
|
||||
|
||||
# === from hardware-configuration.nix
|
||||
|
||||
boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" "nvme" "usbhid" "usb_storage" "sd_mod" ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ "kvm-intel" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
fileSystems."/" =
|
||||
{ device = "tank/root";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
virtuous-cassette = {config, pkgs, ...}:
|
||||
{
|
||||
imports = [ endpointCfg ../hosts/virtuous-cassette ];
|
||||
deployment.targetHost = "virtuous-cassette";
|
||||
system.stateVersion = "22.05";
|
||||
fileSystems."/home" =
|
||||
{ device = "tank/home";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/nix" =
|
||||
{ device = "tank/nix";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/boot" =
|
||||
{ device = "/dev/disk/by-uuid/9FDC-2C40";
|
||||
fsType = "vfat";
|
||||
};
|
||||
|
||||
swapDevices =
|
||||
[ { device = "/dev/disk/by-uuid/455bbc40-e01c-4137-b593-a05b6220ce6b"; }
|
||||
];
|
||||
|
||||
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
|
||||
# (the default) this is the recommended approach. When using systemd-networkd it's
|
||||
# still possible to use this option, but it's recommended to use it in conjunction
|
||||
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
|
||||
networking.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.enp175s0.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.wlp174s0.useDHCP = lib.mkDefault true;
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
|
||||
}
|
||||
#+end_src
|
||||
|
||||
*** NEXT derivation for [[https://github.com/wimpysworld/umpc-ubuntu/blob/master/data/umpc-display-rotate.c][umpc-display-rotate.c]]
|
||||
*** NEXT split and document all this out in to an import on [[roam:GPD Pocket 3 Support]] page
|
||||
|
||||
** Window Smoke
|
||||
:PROPERTIES:
|
||||
:ID: 20230225T145612.522017
|
||||
:END:
|
||||
|
||||
#+begin_export html
|
||||
<iframe style="border: 0; width: 200px; height: 200px;" src="https://bandcamp.com/EmbeddedPlayer/album=1436740419/size=large/bgcol=ffffff/linkcol=2ebd35/minimal=true/track=130097483/transparent=true/" seamless><a href="https://theflashbulb.bandcamp.com/album/seven-quarantine-poems">Seven Quarantine Poems by The Flashbulb</a></iframe>
|
||||
#+end_export
|
||||
|
||||
#+begin_src toml :tangle ~/arroyo-nix/networks/hosts.toml
|
||||
[endpoints.hosts.window-smoke]
|
||||
# target = "window-smoke"
|
||||
# stateVersion = "22.11"
|
||||
# user = "rrix"
|
||||
#+end_src
|
||||
|
||||
Window Smoke is my desktop. It runs my [[id:cce/my_nixos_configuration][Endpoint Configuration]] and some of [[id:20230225T150449.622645][My NixOS Tower Customizations]]
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/hosts/window-smoke/default.nix :mkdirp yes
|
||||
{ lib, config, ... }:
|
||||
{
|
||||
imports = [ ./hardware-configuration.nix ../../roles/desktop ];
|
||||
|
||||
boot.enableVFIO = true;
|
||||
|
||||
networking.hostName = "window-smoke";
|
||||
system.stateVersion = "22.11"; #
|
||||
# boot.loader.grub.efiInstallAsRemovable = true;
|
||||
# boot.loader.grub.efiSupport = true;
|
||||
# boot.loader.grub.device = "nodev";
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
services.xserver.dpi = 110;
|
||||
|
||||
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod" "sr_mod" ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ "kvm-intel" "wl" ];
|
||||
boot.extraModulePackages = [ config.boot.kernelPackages.broadcom_sta ];
|
||||
|
||||
services.tailscale.authKey = "tskey-auth-k38z9b3CNTRL-DeWdeU2Zt4ccxM2RqHduzbu9h2D7mmP74";
|
||||
|
||||
networking.hostId = "141e1b4f"; # required for zfs use
|
||||
boot.zfs.devNodes = lib.mkForce "/dev/disk/by-id/";
|
||||
boot.initrd.luks.devices = {
|
||||
"swap" = { name = "swap"; device = "/dev/nvme0n1p2"; preLVM = true; };
|
||||
"root" = { name = "root"; device = "/dev/nvme0n1p3"; preLVM = true; };
|
||||
};
|
||||
|
||||
fileSystems."/" =
|
||||
{ device = "window-smoke/root";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/home" =
|
||||
{ device = "window-smoke/home";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/nix" =
|
||||
{ device = "window-smoke/nix";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/boot" =
|
||||
{ device = "/dev/disk/by-uuid/12CA-451F";
|
||||
fsType = "vfat";
|
||||
};
|
||||
|
||||
fileSystems."/media" =
|
||||
{ device = "tank/media";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
|
||||
swapDevices =
|
||||
[ { device = "/dev/disk/by-uuid/26776a6d-4e53-4e39-b0e5-5a540ce78406"; }
|
||||
];
|
||||
}
|
||||
#+end_src
|
||||
|
||||
** Virtuous Cassette
|
||||
:PROPERTIES:
|
||||
:ID: 20211029T115928.954970
|
||||
:END:
|
||||
|
||||
#+begin_export html
|
||||
<iframe style="border: 0; width: 200px; height: 200px;" src="https://bandcamp.com/EmbeddedPlayer/album=3533678702/size=large/bgcol=ffffff/linkcol=2ebd35/minimal=true/track=1697170446/transparent=true/" seamless><a href="https://theflashbulb.bandcamp.com/album/love-as-a-dark-hallway">Love As A Dark Hallway by The Flashbulb</a></iframe>
|
||||
#+end_export
|
||||
|
||||
Virtuous Cassette is my [[roam:Framework Laptop]].
|
||||
|
||||
#+begin_src toml :tangle ~/arroyo-nix/networks/hosts.toml
|
||||
[endpoints.hosts.virtuous-cassette]
|
||||
stateVersion = "23.05"
|
||||
target = "192.168.69.71"
|
||||
user = "root"
|
||||
#+end_src
|
||||
|
||||
=hosts/tres-ebow/default.nix= replaces the =generated.nix=, basically, for my [[id:6834cb8f-319f-4dd9-bade-2521417f584b][GPD Pocket]]:
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/hosts/virtuous-cassette/default.nix :mkdirp yes
|
||||
{
|
||||
imports = [ <arroyo/nixos/framework-laptop.nix> ];
|
||||
|
||||
networking.hostName = "virtuous-cassette";
|
||||
|
||||
boot.loader.grub.efiSupport = true;
|
||||
boot.loader.grub.device = "nodev";
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
boot.loader.grub.enable = true;
|
||||
boot.loader.systemd-boot.enable = false;
|
||||
|
||||
boot.initrd.luks.devices = {
|
||||
"swap" = { name = "swap"; device = "/dev/nvme0n1p2"; preLVM = true; };
|
||||
"root" = { name = "root"; device = "/dev/nvme0n1p3"; preLVM = true; };
|
||||
};
|
||||
|
||||
boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" "nvme" "usb_storage" "sd_mod" ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ "kvm-intel" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
powerManagement.cpuFreqGovernor = "powersave";
|
||||
|
||||
# ===8<--- everything below here will change if i ever reinitialize the host!
|
||||
services.tailscale.authKey = "tskey-auth-k1WxJ97CNTRL-6Rp5sqDZxM1yAH7mvKp9T1dj1Ps4iKYDY";
|
||||
|
||||
networking.hostId = "291fe33d"; # required for zfs use
|
||||
|
||||
fileSystems."/" =
|
||||
{ device = "host/root";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/home" =
|
||||
{ device = "host/home";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/media" =
|
||||
{ device = "host/landfill";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/nix" =
|
||||
{ device = "host/nix";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/boot" =
|
||||
{ device = "/dev/disk/by-uuid/CD54-B840";
|
||||
fsType = "vfat";
|
||||
};
|
||||
|
||||
swapDevices =
|
||||
[ { device = "/dev/disk/by-uuid/ddfce221-2d29-4882-9c66-1669ea60bc49"; }
|
||||
];
|
||||
}
|
||||
#+end_src
|
||||
|
||||
|
@ -56,7 +334,17 @@ in {
|
|||
:ID: cce/morph-meadow-crush
|
||||
:END:
|
||||
|
||||
=hosts/meadow-crush/default.nix= replaces the =generated.nix=, basically, for my [[id:6834cb8f-319f-4dd9-bade-2521417f584b][GPD Pocket]]:
|
||||
Meadow Crush is my [[id:6834cb8f-319f-4dd9-bade-2521417f584b][GPD Pocket 2]]; I don't use this right now but it's still running a viable NixOS if I need it in a Situation.
|
||||
|
||||
#+begin_export html
|
||||
<iframe style="border: 0; width: 200px; height: 200px;" src="https://bandcamp.com/EmbeddedPlayer/album=1889307725/size=large/bgcol=ffffff/linkcol=2ebd35/minimal=true/track=1231014309/transparent=true/" seamless><a href="https://theflashbulb.bandcamp.com/album/arboreal">Arboreal by The Flashbulb</a></iframe>
|
||||
#+end_export
|
||||
|
||||
#+begin_src toml :tangle ~/arroyo-nix/networks/hosts.toml
|
||||
# [endpoints.hosts.meadow-crush]
|
||||
# target = "meadow-crush"
|
||||
# stateVersion = "22.05"
|
||||
#+end_src
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/hosts/meadow-crush/default.nix :mkdirp yes
|
||||
{
|
||||
|
@ -68,11 +356,6 @@ in {
|
|||
|
||||
services.tailscale.authKey = "tskey-kqvV5P3CNTRL-K3bdvSJcUreG8nrGcDKXCh";
|
||||
|
||||
# networking.wireguard.interfaces.wg0 = {
|
||||
# privateKeyFile = "/etc/wireguard-key/meadow-crush.key";
|
||||
# ips = ["10.10.10.4/32"];
|
||||
# };
|
||||
|
||||
networking.hostId = "c9ec7cad"; # required for zfs use
|
||||
boot.initrd.luks.devices = {
|
||||
"swap" = { name = "swap"; device = "/dev/mmcblk0p2"; preLVM = true; };
|
||||
|
@ -87,57 +370,6 @@ in {
|
|||
}
|
||||
#+end_src
|
||||
|
||||
I pull [[file:nixlib/hosts/meadow-crush/hardware-configuration.nix]] with nixops:
|
||||
|
||||
#+begin_example
|
||||
nixops scp --from meadow-crush /etc/nixos/hardware-configuration.nix nixlib/hosts/meadow-crush/hardware-configuration.nix
|
||||
#+end_example
|
||||
|
||||
I put my Wireguard configuration on the device (for now) using nixops scp
|
||||
|
||||
#+begin_example
|
||||
nixops ssh meadow-crush mkdir -p /etc/wireguard-key/ && \
|
||||
nixops scp --to meadow-crush wireguard/meadow-crush.key /etc/wireguard-key/meadow-crush.key && \
|
||||
nixops ssh meadow-crush chown 400 /etc/wireguard-key/meadow-crush.key
|
||||
#+end_example
|
||||
|
||||
I need to make sure this stays in sync with my [[id:nixos_justdoit][JustDoIt]] script!
|
||||
|
||||
** Virtuous Cassette
|
||||
:PROPERTIES:
|
||||
:ID: 20211029T115928.954970
|
||||
:END:
|
||||
|
||||
Virtuous Cassette is my [[roam:Framework Laptop]].
|
||||
|
||||
=hosts/tres-ebow/default.nix= replaces the =generated.nix=, basically, for my [[id:6834cb8f-319f-4dd9-bade-2521417f584b][GPD Pocket]]:
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/hosts/virtuous-cassette/default.nix :mkdirp yes
|
||||
{
|
||||
imports = [ ./hardware-configuration.nix ];
|
||||
|
||||
networking.hostName = "virtuous-cassette";
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
|
||||
# networking.wg-quick.interfaces.wg0 = {
|
||||
# privateKeyFile = "/etc/wireguard-key/virtuous-cassette.key";
|
||||
# address = ["10.10.10.13/32" "2620:fc:c000:0:1000::d/128"];
|
||||
# };
|
||||
# networking.wg-quick.interfaces.wg1 = {
|
||||
# privateKeyFile = "/etc/wireguard-key/virtuous-cassette.key";
|
||||
# address = ["10.10.10.13/32" "2620:fc:c000:0:1000::d/128"];
|
||||
# };
|
||||
services.tailscale.authKey = "tskey-kMJ8ZX2CNTRL-tDGQZ1dZQLZ9hnuGRgKXS";
|
||||
|
||||
networking.hostId = "754ccef7"; # required for zfs use
|
||||
boot.initrd.luks.devices = {
|
||||
"swap" = { name = "swap"; device = "/dev/nvme0n1p2"; preLVM = true; };
|
||||
"root" = { name = "root"; device = "/dev/nvme0n1p3"; preLVM = true; };
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
** NEXT implement [[https://christine.website/blog/nixos-encrypted-secrets-2021-01-20][nixos encrypted secrets]] and make these safe! maybe [[https://christine.website/blog/my-wireguard-setup-2021-02-06][hosts.toml]] for a lot of this too...
|
||||
|
||||
* Deploying My [[id:20220131T152041.472624][NixOS Set Top Box]]
|
||||
|
@ -147,21 +379,17 @@ Virtuous Cassette is my [[roam:Framework Laptop]].
|
|||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/networks/settop.nix :mkdirp yes
|
||||
let
|
||||
settopCfg = ../roles/settop;
|
||||
# nixpkgsPin = (import ../versions.nix {}).nixpkgs;
|
||||
# pkgs = import (builtins.fetchTarball nixpkgsPin) {};
|
||||
pkgs = import <nixpkgs> {};
|
||||
in {
|
||||
network.pkgs = pkgs;
|
||||
network.description = "my settop";
|
||||
network.enableRollback = true;
|
||||
allNetworks = pkgs.lib.importTOML ./hosts.toml;
|
||||
mkNetwork = import ./mkNetwork.nix { inherit pkgs; networks = allNetworks; };
|
||||
in mkNetwork "settop"
|
||||
#+end_src
|
||||
|
||||
tres-ebow = {config, pkgs, ...}:
|
||||
{
|
||||
imports = [ settopCfg ../hosts/tres-ebow ];
|
||||
deployment.targetHost = "10.0.0.167";
|
||||
};
|
||||
}
|
||||
#+begin_src toml :tangle ~/arroyo-nix/networks/hosts.toml
|
||||
[settop]
|
||||
description = "my kodi box"
|
||||
enableRollback = true
|
||||
config = "../roles/settop"
|
||||
#+end_src
|
||||
|
||||
** Tres Ebow
|
||||
|
@ -169,50 +397,82 @@ in {
|
|||
:ID: cce/morph-tres-ebow
|
||||
:END:
|
||||
|
||||
#+begin_export html
|
||||
<iframe style="border: 0; width: 200px; height: 200px;" src="https://bandcamp.com/EmbeddedPlayer/album=3533678702/size=large/bgcol=ffffff/linkcol=2ebd35/minimal=true/track=1431497952/transparent=true/" seamless><a href="https://theflashbulb.bandcamp.com/album/love-as-a-dark-hallway">Love As A Dark Hallway by The Flashbulb</a></iframe>
|
||||
#+end_export
|
||||
|
||||
#+begin_src toml :tangle ~/arroyo-nix/networks/hosts.toml
|
||||
[settop.hosts.tres-ebow]
|
||||
# target = "tres-ebow"
|
||||
target = "192.168.69.69"
|
||||
user = "root"
|
||||
# will probably reinstall soon
|
||||
stateVersion = "23.05"
|
||||
#+end_src
|
||||
|
||||
Tres Ebow is my Thinkpad Yoga gen 3 -- a decent 2-in-1 with [[id:25942086-23fa-4fff-938d-a7a9c0fa7365][very un-Lenovo serviceability]], and due to ordering error and soldered RAM, only 4 GiB of RAM. awkward. it'll be a fine kodi box.
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/hosts/tres-ebow/default.nix :mkdirp yes
|
||||
{ config, lib, ... }:
|
||||
|
||||
{
|
||||
imports = [ ./hardware-configuration.nix ];
|
||||
|
||||
networking.hostName = "tres-ebow";
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.grub.efiSupport = true;
|
||||
boot.loader.grub.device = "nodev";
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
boot.loader.grub.enable = true;
|
||||
boot.loader.systemd-boot.enable = false;
|
||||
services.xserver.dpi = 207;
|
||||
|
||||
# networking.wg-quick.interfaces.wg0 = {
|
||||
# privateKeyFile = "/etc/wireguard-key/tres-ebow.key";
|
||||
# address = ["10.10.10.2/32" "2620:fc:c000:0:1000::b/128"];
|
||||
# };
|
||||
# networking.wg-quick.interfaces.wg1 = {
|
||||
# privateKeyFile = "/etc/wireguard-key/tres-ebow.key";
|
||||
# address = ["10.10.10.2/32" "2620:fc:c000:0:1000::b/128"];
|
||||
# };
|
||||
services.tailscale.authKey = "tskey-kGxjxy1CNTRL-ZoepgcGatEA78ezQKX5VVb";
|
||||
networking.hostId = "389acda5"; # required for zfs use
|
||||
boot.zfs.devNodes = lib.mkForce "/dev/disk/by-uuid"; # (ref:devNodes)
|
||||
|
||||
networking.hostId = "c9ec7cad"; # required for zfs use
|
||||
boot.initrd.luks.devices = {
|
||||
"swap" = { name = "swap"; device = "/dev/nvme0n1p2"; preLVM = true; };
|
||||
"root" = { name = "root"; device = "/dev/nvme0n1p3"; preLVM = true; };
|
||||
};
|
||||
services.tailscale.authKey = "tskey-auth-kjuYea5CNTRL-YApNAAdxe5aucWNb823g1aNCwTK11pVTA";
|
||||
|
||||
boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ "kvm-intel" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
fileSystems."/" =
|
||||
{ device = "host/root";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/home" =
|
||||
{ device = "host/home";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/nix" =
|
||||
{ device = "host/nix";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/boot" =
|
||||
{ device = "/dev/disk/by-uuid/CB62-8263";
|
||||
fsType = "vfat";
|
||||
};
|
||||
|
||||
swapDevices =
|
||||
[ { device = "/dev/disk/by-uuid/4f1751ef-0ddd-4005-b69c-daafc518e9df"; }
|
||||
];
|
||||
|
||||
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
|
||||
# (the default) this is the recommended approach. When using systemd-networkd it's
|
||||
# still possible to use this option, but it's recommended to use it in conjunction
|
||||
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
|
||||
networking.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.enp0s31f6.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.wlp2s0.useDHCP = lib.mkDefault true;
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||
powerManagement.cpuFreqGovernor = lib.mkDefault "balanced";
|
||||
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||
hardware.enableRedistributableFirmware = true;
|
||||
}
|
||||
#+end_src
|
||||
|
||||
I pull [[file:nixlib/hosts/tres-ebow/hardware-configuration.nix]] with nixops:
|
||||
|
||||
#+begin_example
|
||||
nixops scp --from tres-ebow /etc/nixos/hardware-configuration.nix nixlib/hosts/tres-ebow/hardware-configuration.nix
|
||||
#+end_example
|
||||
|
||||
I put my Wireguard configuration on the device (for now) using nixops scp
|
||||
|
||||
#+begin_example
|
||||
nixops ssh tres-ebow mkdir -p /etc/wireguard-key/ && \
|
||||
nixops scp --to tres-ebow wireguard/tres-ebow.key /etc/wireguard-key/tres-ebow.key && \
|
||||
nixops ssh tres-ebow chown 400 /etc/wireguard-key/tres-ebow.key
|
||||
#+end_example
|
||||
|
||||
I need to make sure this stays in sync with my [[id:nixos_justdoit][JustDoIt]] script!
|
||||
|
||||
* Deploying [[id:20211120T220054.226284][The Wobserver]]
|
||||
:PROPERTIES:
|
||||
:ID: 20221112T153200.008557
|
||||
|
@ -220,20 +480,17 @@ I need to make sure this stays in sync with my [[id:nixos_justdoit][JustDoIt]] s
|
|||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/networks/wobserver.nix :mkdirp yes
|
||||
let
|
||||
serverCfg = ../roles/server;
|
||||
pkgs = import <nixpkgs> {};
|
||||
in {
|
||||
network.pkgs = pkgs;
|
||||
network.description = "my wobserver";
|
||||
network.enableRollback = true;
|
||||
allNetworks = pkgs.lib.importTOML ./hosts.toml;
|
||||
mkNetwork = import ./mkNetwork.nix { inherit pkgs; networks = allNetworks; };
|
||||
in mkNetwork "wobserver"
|
||||
#+end_src
|
||||
|
||||
terra-firma = {config, pkgs, ...}:
|
||||
{
|
||||
imports = [ serverCfg ../hosts/terra-firma ];
|
||||
deployment.targetHost = "terra-firma";
|
||||
system.stateVersion = "22.11";
|
||||
};
|
||||
}
|
||||
#+begin_src toml :tangle ~/arroyo-nix/networks/hosts.toml
|
||||
[wobserver]
|
||||
description = "the wobserver and friends"
|
||||
enableRollback = true
|
||||
config = "../roles/server"
|
||||
#+end_src
|
||||
|
||||
** Terra Firma
|
||||
|
@ -241,12 +498,18 @@ in {
|
|||
:ID: 20221112T130047.292304
|
||||
:END:
|
||||
|
||||
#+begin_export html
|
||||
<iframe style="border: 0; width: 200px; height: 200px;" src="https://bandcamp.com/EmbeddedPlayer/album=78877835/size=large/bgcol=ffffff/linkcol=2ebd35/minimal=true/track=2552183726/transparent=true/" seamless><a href="https://theflashbulb.bandcamp.com/album/opus-at-the-end-of-everything">Opus At The End Of Everything by The Flashbulb</a></iframe>
|
||||
#+end_export
|
||||
|
||||
Terra Firma is my [[id:20211120T220054.226284][Wobserver]] hosted by [[id:7fea3caa-5fa0-415a-96c7-45a1d64512fb][Wobscale Technologies]] in Seattle, WA.
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/hosts/terra-firma/default.nix :mkdirp yes
|
||||
{
|
||||
imports = [ ./hardware-configuration.nix ];
|
||||
|
||||
system.stateVersion = "22.11";
|
||||
|
||||
networking.hostName = "terra-firma";
|
||||
boot.loader.grub.enable = true;
|
||||
# boot.loader.grub.device = "/dev/sde";
|
||||
|
@ -317,3 +580,86 @@ Terra Firma is my [[id:20211120T220054.226284][Wobserver]] hosted by [[id:7fea3c
|
|||
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||
}
|
||||
#+end_src
|
||||
|
||||
** Last Bank
|
||||
:PROPERTIES:
|
||||
:ID: 20230506T010603.522707
|
||||
:END:
|
||||
|
||||
#+begin_export html
|
||||
<iframe style="border: 0; width: 200px; height: 200px;" src="https://bandcamp.com/EmbeddedPlayer/album=4030854985/size=large/bgcol=ffffff/linkcol=2ebd35/minimal=true/track=3639413635/transparent=true/" seamless><a href="https://theflashbulb.bandcamp.com/album/hardscrabble">Hardscrabble by The Flashbulb</a></iframe>
|
||||
#+end_export
|
||||
|
||||
Last Bank is my [[id:20230429T140217.184029][New Homelab Build]], a living-room server that will be proxied through [[id:7fea3caa-5fa0-415a-96c7-45a1d64512fb][Wobscale Technologies]] in Seattle, WA. It's going to replace [[id:20221112T130047.292304][terra-firma]].
|
||||
|
||||
#+begin_src toml :tangle ~/arroyo-nix/networks/hosts.toml
|
||||
[wobserver.hosts.last-bank]
|
||||
#+end_src
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/hosts/last-bank/default.nix :mkdirp yes
|
||||
{ lib, config, ... }:
|
||||
|
||||
{
|
||||
networking.hostName = "last-bank";
|
||||
system.stateVersion = "23.05";
|
||||
|
||||
boot.loader.grub.enable = true;
|
||||
boot.loader.grub.device = "/dev/sda";
|
||||
services.tailscale.authKey = "tskey-auth-kzWZMt1CNTRL-48JC1bwTin5b1crXxBcti5Qru3zf8wC3";
|
||||
|
||||
networking.hostId = "56c334f2"; # required for zfs use
|
||||
boot.zfs.devNodes = "/dev/disk/by-uuid"; # (ref:devNodes)
|
||||
|
||||
boot.initrd.availableKernelModules = [ "ehci_pci" "ahci" "isci" "usbhid" "usb_storage" "sd_mod" ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ "kvm-intel" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
fileSystems."/" =
|
||||
{ device = "host/root";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/nix" =
|
||||
{ device = "host/nix";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/home" =
|
||||
{ device = "tank/home";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/media" =
|
||||
{ device = "tank/media";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/srv" =
|
||||
{ device = "tank/srv";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/boot" =
|
||||
{ device = "/dev/disk/by-uuid/19C9-747A";
|
||||
fsType = "vfat";
|
||||
};
|
||||
|
||||
swapDevices =
|
||||
[ { device = "/dev/disk/by-uuid/554d8e90-f4ea-49dc-b057-c69d0385bbc6"; }
|
||||
];
|
||||
|
||||
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
|
||||
# (the default) this is the recommended approach. When using systemd-networkd it's
|
||||
# still possible to use this option, but it's recommended to use it in conjunction
|
||||
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
|
||||
networking.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.eno1.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.eno2.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.eno3.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.eno4.useDHCP = lib.mkDefault true;
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||
}
|
||||
#+end_src
|
||||
|
|
|
@ -46,10 +46,10 @@ Here the strings are basically just taken out of [[id:arroyo/nixos][Arroyo NixOS
|
|||
../../nixos/boot.nix
|
||||
../../nixos/cachix.nix
|
||||
../../nixos/clight.nix
|
||||
../../nixos/cups.nix
|
||||
../../nixos/direnv.nix
|
||||
../../nixos/emacs.nix
|
||||
../../nixos/fonts.nix
|
||||
../../nixos/framework-laptop.nix
|
||||
../../nixos/gnupg-pam.nix
|
||||
../../nixos/home-manager.nix
|
||||
../../nixos/japanese.nix
|
||||
|
@ -58,6 +58,7 @@ Here the strings are basically just taken out of [[id:arroyo/nixos][Arroyo NixOS
|
|||
../../nixos/laptop.nix
|
||||
../../nixos/location.nix
|
||||
../../nixos/mopidy.nix
|
||||
../../nixos/morph-wrapper.nix
|
||||
../../nixos/nix-path.nix
|
||||
../../nixos/nixos-builder.nix
|
||||
../../nixos/nixpkgs.nix
|
||||
|
@ -69,6 +70,7 @@ Here the strings are basically just taken out of [[id:arroyo/nixos][Arroyo NixOS
|
|||
../../nixos/syncthing.nix
|
||||
../../nixos/tailscale.nix
|
||||
../../nixos/vulfpeck.nix
|
||||
../../nixos/waydroid.nix
|
||||
../../nixos/xmodmap.nix
|
||||
../../nixos/yubikey.nix
|
||||
../../nixos/zfs.nix
|
||||
|
|
12
nginx.org
12
nginx.org
|
@ -115,7 +115,10 @@ I use [[https://letsencrypt.org/][Lets Encrypt]] for my DNS, I really like 'em.
|
|||
}
|
||||
#+end_src
|
||||
|
||||
* INPROGRESS static sites
|
||||
* INPROGRESS wobserver static sites
|
||||
:PROPERTIES:
|
||||
:ID: 20221223T171929.934471
|
||||
:END:
|
||||
:LOGBOOK:
|
||||
- State "INPROGRESS" from "NEXT" [2022-11-12 Sat 19:41]
|
||||
:END:
|
||||
|
@ -139,10 +142,11 @@ I use [[https://letsencrypt.org/][Lets Encrypt]] for my DNS, I really like 'em.
|
|||
|
||||
"kickass.systems".root = "/srv/static-sites/kickass.systems/_site";
|
||||
|
||||
# see akkoma.org
|
||||
"notes.whatthefuck.computer" = {
|
||||
root = "/srv/static-sites/notes.whatthefuck.computer/_site";
|
||||
locations."/atom.xml".proxyPass = "https://granary.io/url?url=http://notes.whatthefuck.computer/&input=html&output=atom&hub=https://bridgy-fed.superfeedr.com/";
|
||||
locations."/rss.xml".proxyPass = "https://granary.io/url?url=http://notes.whatthefuck.computer/&input=html&output=rss&hub=https://bridgy-fed.superfeedr.com/";
|
||||
# root = "/srv/static-sites/notes.whatthefuck.computer/_site"; #
|
||||
# locations."/atom.xml".proxyPass = "https://granary.io/url?url=http://notes.whatthefuck.computer/&input=html&output=atom&hub=https://bridgy-fed.superfeedr.com/";
|
||||
# locations."/rss.xml".proxyPass = "https://granary.io/url?url=http://notes.whatthefuck.computer/&input=html&output=rss&hub=https://bridgy-fed.superfeedr.com/";
|
||||
};
|
||||
|
||||
"whatthefuck.computer" = {
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
:END:
|
||||
#+title: CCE in Nix On Droid
|
||||
|
||||
#+ARCOLOGY_KEY: cce/nix-on-droid
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
I'd like to get parts of my [[id:cce/cce][CCE]] running on [[id:20220817T205401.021191][t184256/nix-on-droid]] so that I can have my [[id:cce/emacs][Emacs]] [[id:a7420bb9-395f-4afa-92fb-8eaa0b8a4cd8][Tools]] like [[id:2e31b385-a003-4369-a136-c6b78c0917e1][SRS]] and [[id:cce/org-roam][org-roam]] running on it.
|
||||
|
||||
* =nix-on-droid.nix=
|
||||
|
@ -16,8 +19,8 @@ This uses [[id:arroyo/home-manager][Arroyo Home Manager]] to generate a list of
|
|||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
environment.packages = [ pkgs.vim ];
|
||||
system.stateVersion = "22.05";
|
||||
environment.packages = with pkgs; [ vim openssh ];
|
||||
system.stateVersion = "22.11";
|
||||
|
||||
nix.nixPath = [
|
||||
"nixpkgs=/data/data/com.termux.nix/files/home/.nix-defexpr/channels/nixpkgs/"
|
||||
|
@ -51,10 +54,20 @@ This uses [[id:arroyo/home-manager][Arroyo Home Manager]] to generate a list of
|
|||
<<home_manager_imports()>>
|
||||
];
|
||||
|
||||
programs.ssh.matchBlocks = {
|
||||
virtuous-cassette = {
|
||||
hostname = "100.96.6.32";
|
||||
user = "builder";
|
||||
identitiesOnly = true;
|
||||
identityFile = "~/.ssh/id_rsa";
|
||||
};
|
||||
|
||||
programs.ssh.matchBlocks.builder = {
|
||||
hostname = "100.96.6.32";
|
||||
user = "builder";
|
||||
window-smoke = {
|
||||
hostname = "100.79.48.59";
|
||||
user = "builder";
|
||||
identitiesOnly = true;
|
||||
identityFile = "~/.ssh/id_rsa";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -68,29 +81,35 @@ This uses [[id:arroyo/home-manager][Arroyo Home Manager]] to generate a list of
|
|||
|
||||
#+results: home_manager_imports
|
||||
#+begin_example
|
||||
hm/prompt.nix
|
||||
hm/emacs-helpers.nix
|
||||
hm/contacts.nix
|
||||
hm/git.nix
|
||||
hm/python.nix
|
||||
hm/gnupg.nix
|
||||
hm/org-roam.nix
|
||||
hm/emacs-pager.nix
|
||||
hm/shell-helpers.nix
|
||||
hm/spell-check.nix
|
||||
hm/deadgrep.nix
|
||||
hm/profile.nix
|
||||
hm/direnv.nix
|
||||
hm/emacs-helpers.nix
|
||||
hm/emacs-pager.nix
|
||||
hm/emacs.nix
|
||||
hm/git.nix
|
||||
hm/gnupg.nix
|
||||
hm/morph.nix
|
||||
hm/nix-update.nix
|
||||
hm/atuin.nix
|
||||
hm/emacs.nix
|
||||
hm/org-fc.nix
|
||||
hm/org-roam.nix
|
||||
hm/profile.nix
|
||||
hm/prompt.nix
|
||||
hm/python.nix
|
||||
hm/shell-helpers.nix
|
||||
hm/spell-check.nix
|
||||
hm/ssh_client.nix
|
||||
#+end_example
|
||||
|
||||
* Using machines running [[id:cce/my_nixos_configuration][My NixOS configuration]] to as builders for nix-on-droid
|
||||
|
||||
Based on the [[https://github.com/t184256/nix-on-droid/wiki/Use-a-remote-builder-with-qemu][Nix On Droid wiki examples]]:
|
||||
|
||||
#+ARROYO_NIXOS_MODULE: nixos/nixos-builder.nix
|
||||
#+ARROYO_NIXOS_ROLE: endpoint
|
||||
#+ARROYO_NIXOS_ROLE: server
|
||||
|
||||
[[id:20211029T115928.954970][Virtuous Cassette]] is set up with a =builder= user and =aarch64= =binfmt= emulation:
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/nixos-builder.nix
|
||||
{ ... }:
|
||||
|
@ -103,6 +122,47 @@ hm/ssh_client.nix
|
|||
initialPassword = "changeme!";
|
||||
};
|
||||
|
||||
nix.trustedUsers = [ "builder" ];
|
||||
nix.settings.trusted-users = [ "builder" ];
|
||||
}
|
||||
#+end_src
|
||||
|
||||
* Bootstrapping the build setup
|
||||
|
||||
On the droid side, it's configured to use this as the builder and SSH to the host over [[id:20220811T124742.042180][Tailscale]]:
|
||||
|
||||
=nix.conf=:
|
||||
|
||||
#+begin_src conf
|
||||
builders-use-substitutes = true
|
||||
builders = ssh://virtuous-cassette;ssh://window-smoke
|
||||
#+end_src
|
||||
|
||||
=.ssh/config=
|
||||
|
||||
#+begin_src conf
|
||||
Host virtuous-cassette
|
||||
HostName 100.96.6.32
|
||||
User builder
|
||||
IdentitiesOnly yes
|
||||
IdentityFile ~/.ssh/id_rsa
|
||||
|
||||
Host window-smoke
|
||||
HostName 100.79.48.59
|
||||
User builder
|
||||
IdentitiesOnly yes
|
||||
IdentityFile ~/.ssh/id_rsa
|
||||
#+end_src
|
||||
|
||||
- set up ssh: =nix-shell -p openssh git= then =ssh-keygen= then =ssh-copy-id builder=; git is used in =nix-on-droid build=
|
||||
- set up directories: =ln -s /storage/emulated/0/org ~/org= then =ln -s /storage/emulated/0/arroyo-nix ~/arroyo-nix=
|
||||
- [[https://nix-community.github.io/home-manager/index.html#sec-install-standalone][install]] home-manager channel (only used for bootstrap, subsequent builds will use [[id:cce/version_pins][Nix Version Pins]])
|
||||
- then finally =nix-on-droid build -f ~/arroyo-nix/nix-on-droid.nix -I arroyo=$HOME/arroyo-nix=
|
||||
|
||||
Termux app properties should be set on the Cosmo and other devices with a hardware keyboard:
|
||||
|
||||
#+begin_src conf
|
||||
# extra-keys-style = none doesn't work...
|
||||
extra-keys = []
|
||||
back-key = escape
|
||||
ctrl-space-workaround = true
|
||||
#+end_src
|
||||
|
|
|
@ -16,12 +16,12 @@ I use [[https://pipewire.org/][PipeWire]] because it implements [[id:jack_audio_
|
|||
#+begin_src nix :tangle ~/arroyo-nix/nixos/audio.nix
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
environment.systemPackages = [ pkgs.qjackctl ];
|
||||
with pkgs; {
|
||||
environment.systemPackages = [ qjackctl easyeffects ];
|
||||
|
||||
hardware.bluetooth = {
|
||||
enable = true;
|
||||
package = pkgs.bluez5;
|
||||
package = bluez5;
|
||||
settings = {
|
||||
General = { Enable = "Source,Sink,Media,Socket"; };
|
||||
};
|
||||
|
|
|
@ -10,19 +10,19 @@ Just use =systemd-boot= and UEFI. Use plymouth.
|
|||
#+ARROYO_NIXOS_ROLE: endpoint
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/boot.nix
|
||||
{ pkgs, ... }:
|
||||
{ lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
vulf_mono = (pkgs.callPackage ../lib/vulfpeck.nix {});
|
||||
in
|
||||
{
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.systemd-boot.enable = lib.mkDefault true;
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
|
||||
boot.plymouth = {
|
||||
enable = true;
|
||||
font = "${vulf_mono}/share/fonts/truetype/Desktop/VulfMono-Regular.otf";
|
||||
logo = /home/rrix/org/data/dashboard-logo.png;
|
||||
logo = /home/rrix/org/data/arcology.png;
|
||||
# TODO: 2021-07 package plymouth-theme-hotdog
|
||||
};
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#+filetags: :Archive:CCE:Hardware:
|
||||
#+ARCOLOGY_KEY: cce/nixos-laptop-framework
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
#+AUTO_TANGLE: t
|
||||
|
||||
[[file:archive.org][Archive]]
|
||||
|
||||
|
@ -18,20 +19,31 @@ I also enable LVFS's testing repository so that i can have LVFS support for Fram
|
|||
|
||||
The only other thing to consider is to make sure the kernel is new enough to support the WiFi 6 chipsets.
|
||||
|
||||
#+ARROYO_NIXOS_MODULE: nixos/framework-laptop.nix
|
||||
#+ARROYO_NIXOS_ROLE: endpoint
|
||||
This can't just be blindly included in all my endpoints since it defines kernel params, but here's how it could be:
|
||||
|
||||
: #+ARROYO_NIXOS_MODULE: nixos/framework-laptop.nix
|
||||
: #+ARROYO_NIXOS_ROLE: endpoint
|
||||
|
||||
It's actually just included directly in the [[id:20211029T115928.954970][Virtuous Cassette]] morph host manifest.
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/framework-laptop.nix
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
boot.kernelParams = [ "mem_sleep_default=deep" ];
|
||||
boot.kernelPackages = pkgs.linuxPackages_5_15;
|
||||
services.fwupd.enable = true;
|
||||
services.fwupd.enableTestRemote = true;
|
||||
# boot.kernelPackages = pkgs.linuxPackages_5_15;
|
||||
services.fwupd = {
|
||||
enable = true;
|
||||
extraRemotes = ["lvfs-testing"];
|
||||
# per Frame.work LVFS docs
|
||||
uefiCapsuleSettings = {
|
||||
DisableCapsuleUpdateOnDisk = true;
|
||||
};
|
||||
};
|
||||
hardware.rasdaemon.enable = true;
|
||||
boot.loader.systemd-boot.memtest86.enable = true;
|
||||
# services.fprintd.enable = true;
|
||||
|
||||
services.xserver.dpi = 204;
|
||||
}
|
||||
#+end_src
|
||||
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
Bits and Bobbins not worth showing anywhere else. This will need a =mkIf= if I ever support my desktop or server!
|
||||
|
||||
#+ARROYO_NIXOS_MODULE: nixos/laptop.nix
|
||||
#+AUTO_TANGLE: t
|
||||
#+ARROYO_NIXOS_ROLE: endpoint
|
||||
#+ARROYO_NIXOS_ROLE: settop
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/laptop.nix
|
||||
{ pkgs, ... }:
|
||||
{ lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
powerManagement.enable = true;
|
||||
|
@ -20,16 +22,23 @@ Bits and Bobbins not worth showing anywhere else. This will need a =mkIf= if I e
|
|||
};
|
||||
services.resolved = {
|
||||
enable = true;
|
||||
fallbackDns = [ "10.10.10.1" "209.251.245.117" "8.8.8.8" ];
|
||||
fallbackDns = [ "100.89.170.115" "100.100.100.100" "8.8.8.8" ];
|
||||
};
|
||||
|
||||
hardware.mcelog.enable = true;
|
||||
|
||||
hardware.cpu.intel.updateMicrocode = true;
|
||||
hardware.video.hidpi.enable = true;
|
||||
|
||||
# each machine in my morph file sets config.services.xserver.dpi too
|
||||
# fonts.optimizeForVeryHighDPI = lib.mkDefault false;
|
||||
services.xserver.upscaleDefaultCursor = lib.mkDefault true;
|
||||
|
||||
services.xserver.videoDrivers = [ "modesetting" ];
|
||||
|
||||
hardware.opengl.extraPackages32 = [ pkgs.pkgsi686Linux.vaapiIntel ];
|
||||
|
||||
# these aren't laptop...
|
||||
|
||||
# use trackpoint with wheel emulation
|
||||
hardware.trackpoint = {
|
||||
enable = true;
|
||||
|
@ -51,8 +60,6 @@ Bits and Bobbins not worth showing anywhere else. This will need a =mkIf= if I e
|
|||
];
|
||||
};
|
||||
|
||||
hardware.opengl.extraPackages32 = [ pkgs.pkgsi686Linux.vaapiIntel ];
|
||||
|
||||
virtualisation.docker = {
|
||||
enable = true;
|
||||
autoPrune.enable = true;
|
||||
|
@ -64,6 +71,7 @@ Bits and Bobbins not worth showing anywhere else. This will need a =mkIf= if I e
|
|||
|
||||
boot.binfmt.emulatedSystems = [ "aarch64-linux" "armv6l-linux" ];
|
||||
hardware.rtl-sdr.enable = true;
|
||||
boot.supportedFilesystems = [ "ntfs" ];
|
||||
}
|
||||
#+end_src
|
||||
|
||||
|
|
|
@ -0,0 +1,264 @@
|
|||
:PROPERTIES:
|
||||
:ID: 20230225T150449.622645
|
||||
:ROAM_ALIASES: "NixOS Tower Customizations"
|
||||
:END:
|
||||
#+TITLE: My NixOS Tower
|
||||
#+filetags: :Project:
|
||||
|
||||
#+AUTO_TANGLE: t
|
||||
|
||||
#+ARCOLOGY_KEY: cce/nixos-tower
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
Window Smoke is a run of the mill [[id:cce/my_nixos_configuration][Endpoint]] managed within [[id:arroyo/arroyo][Arroyo Systems Management]], with a small wrinkle: it has an Nvidia GTX 1060 graphics card attached to it and a 2tb SATA SSD with Windows 10. For the longest time, this machine has primarily booted to Windows and served as a gaming machine.
|
||||
|
||||
Well, I want to put the CPU cycles to use in more ways especially now that I am building the Git edge-version of [[id:cce/emacs][Emacs]] within [[id:arroyo/emacs][Arroyo Emacs]] for both =amd64= and =aarch64= every time I bump my [[id:cce/version_pins][Nix Version Pins]]. I have also been having some somewhat annoying reliability issues cropping up with [[id:20211029T115928.954970][Virtuous Cassette]] so having a backup environment will feel alright.
|
||||
|
||||
This page isn't an [[id:arroyo/arroyo][Arroyo Module]] per se, but a NixOS morph role which is included in to [[id:20230225T145612.522017][Window Smoke]], my desktop tower.
|
||||
|
||||
My desktop setup is very much inspired by my good friend [[id:ff7b41c0-3bab-47f3-aba6-08527f95e319][kalessin]]'s: A long USB cable, a long display cable, and long power cord connect a monitor and USB hub attached to a sit/stand desktop on casters to my desktop tower sitting in the corner of the room. The desk is spacious and easy to move while still having a full size display and a powerful machine attached to it. This has served me really well, especially considering that my monitor, a [[https://www.rtings.com/monitor/reviews/dell/u3818dw][Dell U3818DW wide-screen display]], has a USB-C input with alt-mode Display Port support. I can plug [[id:20211029T115928.954970][Virtuous Cassette]] in to the display and it swaps over my display *and* the USB hub attached to it. This plug-and-play setup has served me really well for the last few years.
|
||||
|
||||
* El 🅱lan
|
||||
|
||||
**This is disabled right now because =vfio-pci= was not robust enough. See [[id:20230527T132537.128761][Okay maybe I was wrong about 6.x]]**
|
||||
|
||||
|
||||
How much farther could I take it though?
|
||||
|
||||
The last time I visited kalessin he showed me something that I thought was quite remarkable: his desktop would virtualize Windows 10 with his graphics card directly forwarded to the VM so that his entire Steam library would run without having to consider any Proton shenanigans[fn:1]. I thought that was pretty impressive and it's got my brain going in this direction. His machine is an AMD threadripper and AMD GPU and the host runs Arch, but in theory this should work well enough with Intel, Nvidia, and NixOS, right? And if it is good, maybe I'll finally get around to refreshing my desktop with a bit more ram and a bit better GPU... As long as I don't have to deal with the Nvidia X11 drivers or Nouveau ever again.
|
||||
|
||||
#+begin_src plantuml :file data/20/230225T150449.622645/desktop-diagram.png
|
||||
skinparam linetype polyline
|
||||
package "Tower" {
|
||||
[Intel iGPU]
|
||||
[RTX 1060]
|
||||
|
||||
cloud "NixOS" {
|
||||
[libvirtd windows10 domain] --> "gamer mode"
|
||||
[plasma desktop] --> "goblin mode"
|
||||
}
|
||||
|
||||
[Motherboard USB Controller] -> [plasma desktop]
|
||||
[Intel iGPU] -> [plasma desktop]
|
||||
[PCIe USB Controller] -> [libvirtd windows10 domain]
|
||||
[RTX 1060] -> [libvirtd windows10 domain]
|
||||
[1tb NVMe] -> [plasma desktop]
|
||||
[2tb SATA SSD] -> [libvirtd windows10 domain]
|
||||
}
|
||||
|
||||
package "Desk" {
|
||||
node "Dell U3818DW" {
|
||||
interface HDMI2
|
||||
interface "USB in 1"
|
||||
interface DP
|
||||
interface "USB in 2"
|
||||
interface "Type-C DP"
|
||||
|
||||
"USB out" --> "USB in 1" : when HDMI2 active
|
||||
"USB out" --> "USB in 2" : when DP active
|
||||
}
|
||||
|
||||
"Type-C DP" --> [laptop] : forwards USB out when active
|
||||
|
||||
"USB out" <-- [keyboard, mouse, etc]
|
||||
HDMI2 --> [Intel iGPU]
|
||||
DP --> [RTX 1060]
|
||||
"USB in 1" --> [Motherboard USB Controller]
|
||||
"USB in 2" --> [PCIe USB Controller]
|
||||
|
||||
}
|
||||
|
||||
' hidden lines for node ordering/positioning
|
||||
[keyboard, mouse, etc] -[hidden]d- [Motherboard USB Controller]
|
||||
[keyboard, mouse, etc] -[hidden]d- "USB out"
|
||||
[Type-C DP] -[hidden]l- [laptop]
|
||||
[RTX 1060] -[hidden]d- [libvirtd windows10 domain]
|
||||
[PCIe USB Controller] -[hidden]d- [libvirtd windows10 domain]
|
||||
[Motherboard USB Controller] -[hidden]d- [plasma desktop]
|
||||
[Intel iGPU] -[hidden]d- [plasma desktop]
|
||||
[1tb NVMe] -[hidden]d- [plasma desktop]
|
||||
[2tb SATA SSD] -[hidden]d- [plasma desktop]
|
||||
' [HDMI2] -[hidden]l- [USB out]
|
||||
[Intel iGPU] -[hidden]r- [1tb NVMe]
|
||||
#+end_src
|
||||
|
||||
#+results:
|
||||
[[attachment:desktop-diagram.png]]
|
||||
|
||||
The four cables between the Tower and Desk are cable-tied together with a power cable which drives the monitor, peripherals, etc. With proper nudging, I can move my Windows 10 installation in to =QEMU-KVM= and have access to gamer mode and goblin mode side by side, rather than dual-booting and dealing with Nvidia-X11.
|
||||
|
||||
* Setting up VFIO PCI Passthrough for virtualizing GPU accelerated Windows
|
||||
:PROPERTIES:
|
||||
:ID: 20230530T001233.513103
|
||||
:END:
|
||||
|
||||
**This is disabled right now because =vfio-pci= was not robust enough. See [[id:20230527T132537.128761][Okay maybe I was wrong about 6.x]]**
|
||||
|
||||
|
||||
I started by reading the [[https://wiki.archlinux.org/title/PCI_passthrough_via_OVMF#Setting_up_IOMMU][Arch Linux docs]] as well as [[https://wiki.gentoo.org/wiki/GPU_passthrough_with_libvirt_qemu_kvm][Gentoo's]] on setting this up.
|
||||
|
||||
Most of the work here came in enabling =VT-d= and =VT-x= in the BIOS, and collating the devices properly. =VT-x= is the general "Intel hardware virtualization" support which lets =qemu-kvm= work, a bunch of CPU instructions and support for entering in to code that thinks it is in *ring 0* when it is not, it's really clear in whether this works or not, and whether it's enabled or not. =VT-d= is the Intel-specific technical name for an virtualization-aware "IOMMU", basically allowing the OS to re-map hardware memory to main-memory addresses and in to the VMs' space. Your motherboard has to support it too, but if they do your VM can have PCI devices attached to it. My Intel i7-7700k and Asus 270AR motherboard both claimed to support VT-d but it was a bear to find that it was under a different firmware configuration menu than the VT-x feature was.[fn:2] I spent quite some time trying to debug this after mistaking the generic "intel virtualization" option to only by =VT-x=, looking in ARK whether my motherboard chipset and CPU supported VT-d, spelunking the menu, eating dinner, getting lost in the woods, etc etc.
|
||||
|
||||
but with that enabled, it should be possible to see which *IOMMU groups* your hardware is set in to, hopefully the groupings make sense. =qemu-kvm= can only forward an entire IOMMU group, so maybe move some stuff around in the chassis if they group oddly. Here we see IOMMU group 1 has my Nvidia card in it, and the PCIe Controller it's plugged in to.
|
||||
|
||||
#+begin_src shell :results drawer :session *piss*
|
||||
nix-shell -p pciutils
|
||||
for g in $(find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V);
|
||||
do
|
||||
echo "IOMMU Group ${g##*/}:";
|
||||
for d in $g/devices/*;
|
||||
do
|
||||
echo -e "\t$(lspci -k -nns ${d##*/})";
|
||||
done;
|
||||
done | grep -A15 "IOMMU Group 1:"
|
||||
#+end_src
|
||||
|
||||
#+results:
|
||||
:results:
|
||||
IOMMU Group 1:
|
||||
00:01.0 PCI bridge [0604]: Intel Corporation 6th-10th Gen Core Processor PCIe Controller (x16) [8086:1901] (rev 05)
|
||||
Subsystem: ASUSTeK Computer Inc. Device [1043:872f]
|
||||
Kernel driver in use: pcieport
|
||||
01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GP106 [GeForce GTX 1060 6GB] [10de:1c03] (rev a1)
|
||||
Subsystem: eVga.com. Corp. Device [3842:6267]
|
||||
Kernel driver in use: vfio-pci
|
||||
Kernel modules: nvidiafb, nouveau
|
||||
01:00.1 Audio device [0403]: NVIDIA Corporation GP106 High Definition Audio Controller [10de:10f1] (rev a1)
|
||||
Subsystem: eVga.com. Corp. Device [3842:6267]
|
||||
Kernel driver in use: vfio-pci
|
||||
Kernel modules: snd_hda_intel
|
||||
IOMMU Group 2:
|
||||
00:02.0 VGA compatible controller [0300]: Intel Corporation HD Graphics 630 [8086:5912] (rev 04)
|
||||
DeviceName: Onboard IGD
|
||||
Subsystem: ASUSTeK Computer Inc. Device [1043:872f]
|
||||
:end:
|
||||
|
||||
You can see that I have already instructed the system to use =vfio-pci= as the kernel driver to use for them. This is done below.
|
||||
|
||||
Start out making sure this nvidia thing has no chance of loading:
|
||||
|
||||
#+begin_src nix :noweb-ref nouveau
|
||||
boot.blacklistedKernelModules = [
|
||||
"nouveau"
|
||||
];
|
||||
#+end_src
|
||||
|
||||
With this terminal output, the following NixOS configuration can be created. It will 1) tell the Linux kernel to refuse loading the =nouveau= graphics driver for my X11 session 2) enable the IOMMU in the kernel 3) configure the "stub" =vfio-pci= module to attach to the devices I want forwarded to the VM 4) modify my =initrd= to load =vfio-pci= and attach it to my Nvidia driver early in the boot process before [[roam:UDEV]] can auto-configure anything. I only needed to do this last part on the graphics card, the ethernet controller and USB controller do not need this treatment. You'll notice these IDs in the IOMMU Groups script-let or in the output of =lspci -k -nn=
|
||||
|
||||
#+begin_src nix :noweb-ref vfio
|
||||
boot.kernelParams = [
|
||||
"intel_iommu=on"
|
||||
# nvidia gtx 1060, realtek pcie ethernet controller
|
||||
"vfio-pci.ids=10de:1c03,10de:10f1,10ec:8168,1b73:1100"
|
||||
# "efifb=off"
|
||||
];
|
||||
boot.initrd.availableKernelModules = [ "vfio-pci" ];
|
||||
boot.initrd.preDeviceCommands = ''
|
||||
echo "Enabling vfio-pci"
|
||||
# USB controller, GPU, GPU audio, Eth
|
||||
DEVS="0000:02:00.0 0000:01:00.0 0000:01:00.1 0000:06:00.0"
|
||||
for DEV in $DEVS; do
|
||||
echo "vfio-pci" > /sys/bus/pci/devices/$DEV/driver_override
|
||||
done
|
||||
modprobe -i vfio-pci
|
||||
'';
|
||||
boot.kernelPackages = config.boot.zfs.package.latestCompatibleLinuxPackages;
|
||||
#+end_src
|
||||
|
||||
But make sure to see [[id:20230725T140119.217568][the heading below]] where I have to fix this. It's enabled by default on [[id:20230225T145612.522017][Window Smoke]], if I want to disable all the VFIO stuff I just have to go set =config.boot.enableVFIO = false= in the host configuration.
|
||||
|
||||
I make the VFIO stuff optional, and then configure =libvirtd= in a pretty bog-standard way. Instruct NixOS to start the service, install virt-manager to set up the VM by hand ... but I would like to make this declarative some day.
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/roles/desktop/default.nix :mkdirp yes :noweb yes
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
options = {
|
||||
boot.enableVFIO = lib.mkEnableOption {
|
||||
name = "vfio-pci passthrough";
|
||||
};
|
||||
};
|
||||
config = lib.mkIf config.boot.enableVFIO
|
||||
{
|
||||
<<nouveau>>
|
||||
virtualisation.libvirtd = {
|
||||
enable = true;
|
||||
onBoot = "start";
|
||||
onShutdown = "shutdown";
|
||||
};
|
||||
environment.systemPackages = with pkgs; [ virt-manager ];
|
||||
<<vfio>>
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
This is essentially what is happening in Alexander Bakker's [[https://alexbakker.me/post/nixos-pci-passthrough-qemu-vfio.html][Notes on PCI Passthrough on NixOS using QEMU and VFIO]] blog post/literate configuration. I'll have to consider setting up =Looking Glass= and =Scream= soon, though it's not a big concern once I have the USB routing done.
|
||||
|
||||
** Fixing =vfio-pci= after 6.0.4 et al broke it
|
||||
:PROPERTIES:
|
||||
:ID: 20230725T140119.217568
|
||||
:END:
|
||||
|
||||
Sooo, the [[id:20230520T205431.962021][patch which landed in 6.0.4]] which broke =vfio-pci= got backported to 5.15, I'm going to just revert it and let loose the dogs of war, though I am not looking foward to compiling my desktop's kernel for the rest of existence. At least NixOS makes this easy...
|
||||
|
||||
This is included in the optional =boot.enableVFIO= optioned section of the role configuration along with the VFIO configuration itself.
|
||||
|
||||
#+begin_src nix :noweb-ref vfio
|
||||
boot.kernelPatches = [
|
||||
# {
|
||||
# name = "revert-vfio-breakage";
|
||||
# patch = /home/rrix/org/cce/data/20/230530T001233.513103/v3-3-3-vfio-pci-Remove-console-drivers.patch;
|
||||
# }
|
||||
];
|
||||
#+end_src
|
||||
|
||||
This patch reverts [[https://github.com/torvalds/linux/commit/d173780620792c725506b0f3c5ec52c7fbac1db0][torvalds/linux@d173780620792c725506b0f3c5ec52c7fbac1db0]]:
|
||||
|
||||
#+begin_src patch :tangle /home/rrix/org/cce/data/20/230530T001233.513103/v3-3-3-vfio-pci-Remove-console-drivers.patch :comments none
|
||||
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
|
||||
index a0d69ddaf90d..756d049bd9cf 100644
|
||||
--- a/drivers/vfio/pci/vfio_pci_core.c
|
||||
+++ b/drivers/vfio/pci/vfio_pci_core.c
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
-#include <linux/aperture.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/eventfd.h>
|
||||
#include <linux/file.h>
|
||||
@@ -1793,10 +1794,6 @@ static int vfio_pci_vga_init(struct vfio_pci_core_device *vdev)
|
||||
if (!vfio_pci_is_vga(pdev))
|
||||
return 0;
|
||||
|
||||
- ret = aperture_remove_conflicting_pci_devices(pdev, vdev->vdev.ops->name);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
ret = vga_client_register(pdev, vfio_pci_set_decode);
|
||||
if (ret)
|
||||
return ret;
|
||||
#+end_src
|
||||
|
||||
** Running Windows 10 in =libvirtd=
|
||||
|
||||
Instruct it to use /dev/sda or something in /dev/disk/by-uuid/ as the "system image" but be careful if you delete the domain that you don't let =libvirtd= try to =rm /dev/sda= ... it offered to, i'm not sure it actually would have, but that is spooky action.
|
||||
|
||||
UEFI boot support via OVMF is installed by default in the =virtualisation.libvirt= module, but the =virt-manager= GUI will BIOS boot by default. Change the boot mode in "overview configuration" in the *install/setup phase*, it's not editable once the VM is created in =libvirtd=..
|
||||
|
||||
Then attach PCI devices for the Nvidia card, a USB-3 PCIe card, an Ethernet PCIe card. The virtualized Windows will have its own USB ports exposed on the back of my case, it won't need to rely on bridge networking but will be connected directly to my switch, and the desktop will be displayed in front of me through the GPU and not the SPICE virtual display.
|
||||
|
||||
Forwarding USB devices one by one is fine during setup and fiddling around, but the USB controller will allow me to run another USB cable to my display and use the display as a KVM+USB switch between the host OS and the guest OS. I am waiting on the cables and controller to be delivered, it's been snowy this month.
|
||||
|
||||
** NEXT record video of boot + swapover + art of rally @ 60FPS + swap back
|
||||
** NEXT Investigate declarative libvirtd domains
|
||||
* NEXT what else should only be installed here?
|
||||
|
||||
- CUDA toolkit
|
||||
- kind of want to play with stable diffusion on local GPU
|
||||
|
||||
* Footnotes
|
||||
|
||||
[fn:1] That said, since I have been using the [[id:20220810T163745.293071][SteamDeck]] I am much less concerned with Proton compatibility in general... Worth not having to consider it all the time though and having a Windows machine at my finger tips.
|
||||
|
||||
[fn:2] I should write down which menu since it was a PITA to find but woops i'm typing on this machine right now!
|
|
@ -37,7 +37,7 @@ The Wobserver in this equation is the "social hub" of an Arroyo System. [[id:c75
|
|||
This is a [[id:c75d20e6-8888-4c5a-ac97-5997e2f1c711][NixOS]] configuration which is dynamically extended with [[id:arroyo/arroyo][Arroyo Systems Management]] modules. It behaves like [[id:cce/my_nixos_configuration][My NixOS configuration]] and is pushed to machines using [[id:cce/morph][Morph]]. It can also be built [[id:20220218T213149.100848][in QEMU]] below.
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/roles/server/default.nix :noweb yes :mkdirp yes
|
||||
{ pkgs, lib, ... }:
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
rec {
|
||||
imports = [
|
||||
|
@ -47,12 +47,17 @@ rec {
|
|||
home-manager.users.rrix.imports = [
|
||||
<<arroyo_home-manager_imports()>>
|
||||
];
|
||||
home-manager.users.rrix.home.stateVersion = "22.11";
|
||||
|
||||
system.stateVersion = lib.mkDefault "22.11";
|
||||
|
||||
home-manager.users.rrix = {
|
||||
home.stateVersion = config.system.stateVersion;
|
||||
# don't ship pinentry-qt
|
||||
services.gpg-agent.pinentryFlavor = lib.mkForce "curses";
|
||||
};
|
||||
|
||||
services.openssh.enable = true;
|
||||
|
||||
home-manager.users.rrix.services.syncthing.tray.enable = lib.mkForce false;
|
||||
|
||||
boot = {
|
||||
kernelParams = [ "console=ttyS0" "boot.shell_on_fail" ];
|
||||
loader.timeout = 5;
|
||||
|
@ -73,24 +78,35 @@ rec {
|
|||
|
||||
#+results: arroyo_nixos_imports
|
||||
#+begin_example
|
||||
../../nixos/akkoma.nix
|
||||
../../nixos/arcology-config.nix
|
||||
../../nixos/cachix.nix
|
||||
../../nixos/cups.nix
|
||||
../../nixos/emacs.nix
|
||||
../../nixos/feedbot.nix
|
||||
../../nixos/feediverse.nix
|
||||
../../nixos/gitea.nix
|
||||
../../nixos/gnupg-pam.nix
|
||||
../../nixos/home-manager.nix
|
||||
../../nixos/jellyfin.nix
|
||||
../../nixos/location.nix
|
||||
../../nixos/morph-wrapper.nix
|
||||
../../nixos/nextcloud.nix
|
||||
../../nixos/nginx.nix
|
||||
../../nixos/nix-path.nix
|
||||
../../nixos/nixos-builder.nix
|
||||
../../nixos/nixpkgs.nix
|
||||
../../nixos/postgresql.nix
|
||||
../../nixos/restic.nix
|
||||
../../nixos/rixpkgs.nix
|
||||
../../nixos/rrix.nix
|
||||
../../nixos/ssh_client.nix
|
||||
../../nixos/syncthing.nix
|
||||
../../nixos/tailscale.nix
|
||||
../../nixos/ttrss.nix
|
||||
../../nixos/vaultwarden.nix
|
||||
../../nixos/wobservability.nix
|
||||
../../nixos/zfs.nix
|
||||
../../nixos/wobserver-docker.nix
|
||||
#+end_example
|
||||
|
||||
#+NAME: arroyo_home-manager_imports
|
||||
|
@ -151,6 +167,17 @@ NixOS modules:
|
|||
- [[id:20220210T155158.671084][From Wireguard to Tailscale]]
|
||||
- [[id:20220526T143555.660133]["The manual appears to depend on the location of Nixpkgs"]]
|
||||
- [[id:20221021T115008.329657][Arroyo Nix Support]]
|
||||
- [[id:20221106T113721.266425][CCE in Nix On Droid]]
|
||||
- [[id:20221130T103851.207871][Gitea on NixOS]]
|
||||
- [[id:20221202T122017.620403][Self-Hosting on the Fediverse with Akkoma]]
|
||||
- [[id:20221202T124113.404212][Docker Containers on the Wobserver]]
|
||||
- [[id:20230125T143144.011175][Posting Arcology Feeds to the Fediverse Automatically with Feediverse]]
|
||||
- [[id:20230201T121604.003311][Storing passwords securely with vaultwarden]]
|
||||
- [[id:20230220T204453.685476][Jellyfin on the Wobserver]]
|
||||
- [[id:20230310T155744.804329][Tiny-Tiny RSS]]
|
||||
- [[id:20230321T143139.441973][My Brother Printer and CUPS Setup]]
|
||||
- [[id:20230331T181418.903306][RSS Feed Bot Posting to Matrix.org]]
|
||||
- [[id:20230530T120958.265094][Wrapping Morph commands for more ergonomic deployment]]
|
||||
- [[id:47ff77f9-3eae-43eb-886c-7513d05f047f][Secure Backup Infrastructure]]
|
||||
- [[id:arcology/poetry][Arcology Poetry Pyproject]]
|
||||
- [[id:arroyo/emacs][Arroyo Emacs Generator]]
|
||||
|
|
59
nixos.org
59
nixos.org
|
@ -9,7 +9,7 @@
|
|||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
#+PROPERTY: header-args :mkdirp yes :results none
|
||||
#+PROPERTY: header-args:emacs-lisp :tangle cce/nixos.el
|
||||
#+PROPERTY: header-args:emacs-lisp
|
||||
#+PROPERTY: header-args:yaml :tangle cce/roles/endpoint/tasks/nixos.yml
|
||||
|
||||
#+ARROYO_MODULE_WANTS: cce/company_code_completion.org
|
||||
|
@ -18,7 +18,7 @@
|
|||
|
||||
Nix is a [[id:a7420bb9-395f-4afa-92fb-8eaa0b8a4cd8][Tool]] for building [[id:0d968a4d-3c9d-4104-a158-e4982be6d28e][Linux]] systems in a declarative idempotent method and is a good fit for the [[id:cce/cce][CCE]], I think when moving past [[id:fedora_linux][Fedora Linux]].
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
#+begin_src emacs-lisp :tangle nixos.el
|
||||
(provide 'cce/nixos)
|
||||
(use-package nix-mode)
|
||||
(use-package nixpkgs-fmt)
|
||||
|
@ -42,6 +42,8 @@ Nix is a [[id:a7420bb9-395f-4afa-92fb-8eaa0b8a4cd8][Tool]] for building [[id:0d9
|
|||
(find-file)))
|
||||
#+end_src
|
||||
|
||||
* Installing Nix on non-NixOS machines
|
||||
|
||||
#+begin_src yaml
|
||||
- name: /nix exists
|
||||
file:
|
||||
|
@ -76,17 +78,62 @@ if [ -e /home/rrix/.nix-profile/etc/profile.d/nix.sh ]; then . /home/rrix/.nix-p
|
|||
|
||||
#+ARROYO_NIXOS_MODULE: nixos/nixpkgs.nix
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/nixpkgs.nix
|
||||
{ ... }:
|
||||
{ pkgs, config, ... }:
|
||||
|
||||
{
|
||||
# less nix crap
|
||||
nix.gc.automatic = true;
|
||||
nix.gc.dates = "23:30";
|
||||
nix.gc.options = "--delete-older-than 30d";
|
||||
nix.gc = {
|
||||
automatic = true;
|
||||
dates = "03:30";
|
||||
options = "--delete-older-than 30d";
|
||||
persistent = true;
|
||||
};
|
||||
|
||||
nix.distributedBuilds = true;
|
||||
nix.buildMachines = builtins.filter (e: e.hostName != config.networking.hostName) [
|
||||
# { hostName = "virtuous-cassette";
|
||||
# maxJobs = 6;
|
||||
# sshUser = "builder";
|
||||
# systems = [
|
||||
# "x86_64-linux"
|
||||
# "aarch64-linux"
|
||||
# ];
|
||||
# }
|
||||
{ hostName = "window-smoke";
|
||||
maxJobs = 6;
|
||||
sshUser = "builder";
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"i686-linux"
|
||||
"aarch64-linux"
|
||||
];
|
||||
}
|
||||
{ hostName = "last-bank";
|
||||
maxJobs = 32;
|
||||
sshUser = "builder";
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"i686-linux"
|
||||
"aarch64-linux"
|
||||
];
|
||||
}
|
||||
] ;
|
||||
nix.settings.trusted-users = ["rrix" "root" "@wheel"];
|
||||
nix.settings.extra-experimental-features = [ "flakes" "nix-command" ];
|
||||
|
||||
# hahaha! yes
|
||||
nixpkgs.config = { allowUnfree = true; };
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
nix-tree
|
||||
nix-du
|
||||
nurl
|
||||
];
|
||||
}
|
||||
#+end_src
|
||||
|
||||
** DONE remove the nixpkgs.config.permittedInsecurePackages from =nix.conf=..
|
||||
SCHEDULED: <2022-12-27 Tue>
|
||||
:LOGBOOK:
|
||||
- State "DONE" from "NEXT" [2023-01-09 Mon 18:41]
|
||||
:END:
|
||||
|
|
|
@ -43,7 +43,7 @@ My =org-roam= configuration is basically pedestrian, I can hit =<SPC>r= to get t
|
|||
|
||||
#+ARROYO_EMACS_MODULE: org-roam
|
||||
#+begin_src emacs-lisp
|
||||
(use-package emacsql-sqlite3)
|
||||
; (use-package emacsql-sqlite3)
|
||||
(use-package buttercup)
|
||||
(defun cce/org-roam-mode-hook ()
|
||||
(setq-local completion-at-point-functions
|
||||
|
|
|
@ -5,12 +5,13 @@
|
|||
#+filetags: :Emacs:CCE:Org:
|
||||
#+PROPERTY: header-args :mkdirp yes :results none
|
||||
#+PROPERTY: header-args:emacs-lisp :tangle org-mode.el
|
||||
#+ARROYO_EMACS_MODULE: org-mode
|
||||
|
||||
#+ARCOLOGY_KEY: cce/org-mode
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
#+CCE_PREDICATE: t
|
||||
#+CCE_PRIORITY: 40
|
||||
|
||||
#+ARROYO_EMACS_MODULE: org-mode
|
||||
#+ARROYO_MODULE_WANTS: cce/configure_packaging.org
|
||||
#+ARROYO_MODULE_WANTS: cce/diminish.org
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(provide 'cce/org-mode)
|
||||
|
|
10
pam_u2f.org
10
pam_u2f.org
|
@ -4,17 +4,13 @@
|
|||
:ROAM_ALIASES: pam-u2f
|
||||
:END:
|
||||
#+TITLE: Unlock Computer With Yubikey
|
||||
#+ARCOLOGY_KEY: cce/pam-u2f
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
#+filetags: :Project:CCE:
|
||||
#+filetags: :CCE:
|
||||
|
||||
#+PROPERTY: header-args :mkdirp yes :results none
|
||||
#+PROPERTY: header-args:yaml :tangle roles/endpoint/tasks/pam-u2f.yml
|
||||
|
||||
#+CCE_ANSIBLE: pam-u2f
|
||||
#+CCE_ROLES: endpoint
|
||||
#+CCE_PRIORITY: 20
|
||||
#+CCE_PREDICATE: (not (cce/using-termux))
|
||||
,#+ARCOLOGY_KEY: cce/pam-u2f
|
||||
,#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
I can use =pam-u2f= to unlock my computer with a Yubikey that I keep on my belt.
|
||||
|
||||
|
|
28
picom.org
28
picom.org
|
@ -10,7 +10,7 @@
|
|||
#+PROPERTY: header-args:emacs-lisp :tangle exwm-xcompmgr.el
|
||||
|
||||
#+ARROYO_EMACS_MODULE: exwm-xcompmgr
|
||||
,#+ARROYO_MODULE_WANTS: cce/exwm.org
|
||||
#+ARROYO_MODULE_WANTS: cce/exwm.org
|
||||
#+ARROYO_HOME_MODULE: hm/picom.nix
|
||||
#+ARROYO_NIXOS_ROLE: endpoint
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
@ -24,27 +24,39 @@ First commit to xcompmgr was in 2003 and there are still people running non-comp
|
|||
#+end_quote
|
||||
([[https://twitter.com/mjg59/status/1205679548127272960][Matthew Garrett on Twitter]])
|
||||
|
||||
* Starting =picom= in Emacs
|
||||
|
||||
i use picom, a simple X11 compositor that works with [[id:cce/exwm][EXWM]] or [[id:20211206T133651.674012][i3wm]] or [[id:20220421T100313.402598][XMonad]], and have it start after EXWM does, rather than through [[id:cce/home-manager][home-manager]] because KDE's kwin doesn't like to compete for the compositor. I provide a custom backend to prevent =mpv= from tearing.[fn:1]
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(defun cce/run-picom ()
|
||||
(interactive)
|
||||
(when (executable-find "picom")
|
||||
(start-process "picom" " *picom*" "picom" "--vsync" "--backend=glx" "-i 0.9")))
|
||||
; (add-hook 'exwm-init-hook #'cce/run-picom)
|
||||
(add-hook 'after-init-hook #'cce/run-picom)
|
||||
(start-process "picom" " *picom*" "picom" "--vsync" "--backend=glx")))
|
||||
;; "-i 0.9"
|
||||
(add-hook 'exwm-init-hook #'cce/run-picom)
|
||||
; (add-hook 'after-init-hook #'cce/run-picom)
|
||||
#+end_src
|
||||
|
||||
=picom= comes from [[id:cce/home-manager][home-manager]] and needs a working [[id:cce/nixgl][NixGL]].
|
||||
* Starting =picom= on login with systemd
|
||||
|
||||
=picom= comes from [[id:cce/home-manager][home-manager]] and needs a working [[id:cce/nixgl][NixGL]] on non-nixos desktops. Rather than manage it with Emacs, let's just use home-manager now that I am running [[id:20220421T100313.402598][XMonad]].
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/hm/picom.nix
|
||||
{ pkgs, ... }:
|
||||
|
||||
let mkNixGLWrapper = pkgs.lib.mkNixGLWrapper;
|
||||
let
|
||||
myPicom = pkgs.lib.mkNixGLWrapper { name="picom"; pkg=pkgs.picom; };
|
||||
in
|
||||
{
|
||||
home.packages = [(mkNixGLWrapper { name="picom"; pkg=pkgs.picom; })];
|
||||
systemd.user.services.picom.serviceConfig.enable = false;
|
||||
home.packages = [ myPicom ];
|
||||
services.picom = {
|
||||
enable = false;
|
||||
package = myPicom;
|
||||
backend = "glx";
|
||||
# inactiveOpacity = 0.9;
|
||||
vSync = true;
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
|
|
|
@ -5,21 +5,27 @@
|
|||
#+title: PostgreSQL on the Wobserver
|
||||
#+FILETAGS: :Project:Wobserver:CCE:
|
||||
|
||||
My go-to multi-write database server is postgres. I like how it has JSON columns and indexes in a (somewhat) ergonomic form.
|
||||
#+ARCOLOGY_KEY: cce/postgres
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
My go-to multi-write database server is postgres. I like how it has JSON columns and indexes in a (somewhat) ergonomic form. This is a pretty basic setup.
|
||||
|
||||
#+ARROYO_NIXOS_MODULE: nixos/postgresql.nix
|
||||
#+ARROYO_NIXOS_ROLE: server
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/postgresql.nix
|
||||
{ ... }:
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
package = pkgs.postgresql_14;
|
||||
settings = {
|
||||
wal_level = "replica";
|
||||
archive_mode = "on";
|
||||
archive_command = "test ! -f /srv/pgsql/archive/wal/%f && cp %p /srv/pgsql/archive/wal/%f";
|
||||
|
||||
statement_timeout = 60*1000;
|
||||
};
|
||||
};
|
||||
# backup weekly
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
:PROPERTIES:
|
||||
:ID: configuring_profile_variables
|
||||
:END:
|
||||
#+TITLE: Configuring Profile Variables
|
||||
#+filetags: :Emacs:CCE:Shells:
|
||||
|
||||
#+PROPERTY: header-args :mkdirp yes :results none
|
||||
#+PROPERTY: header-args:nix :tangle ~/arroyo-nix/hm/profile.nix
|
||||
#+AUTO_TANGLE: t
|
||||
|
||||
#+ARROYO_HOME_MODULE: hm/profile.nix
|
||||
#+CCE_PREDICATE: nil
|
||||
#+CCE_PRIORITY: 40
|
||||
|
||||
#+begin_src nix
|
||||
{ ... }:
|
||||
{
|
||||
home.sessionVariables = {
|
||||
#+end_src
|
||||
|
||||
I live in [[id:20211120T145109.615732][Eugene, OR]], USA, Earth. This used to be a UTC setup, but it's really hard to make that work sanely, so I don't.
|
||||
|
||||
#+begin_src nix :tangle no
|
||||
TZ = "America/Los_Angeles";
|
||||
# TODO: make this conditional on "normal linux";
|
||||
# TZDIR = "/usr/share/zoneinfo";
|
||||
#+end_src
|
||||
|
||||
The =PATH= environment variable is important to a Linux desktop -- if it's set in the =bash_profile= loading stage, it's used by various process/command execution tools to resolve binary names. If it's a thing that I want to run often, its executable files should be in =PATH=. A lot of these are explored in their own modules more thoroughly, visible by running [[elisp:(deadgrep "cce/bash")]] from here.
|
||||
|
||||
#+BEGIN_SRC nix
|
||||
PATH = "~/.npm/bin:~/.local/bin:~/bin:$PATH";
|
||||
#+END_SRC
|
||||
|
||||
I use =emacsclient= as my =EDITOR= value, a common idiom variable which shell scripts and simple command-line programs use to open a user's preferred editor. Setting it as =emacsclient= especially from within EXWM and =shell-mode= is nice, because the file signaled to be editied is just opened up in the current Emacs window.
|
||||
|
||||
#+BEGIN_SRC nix
|
||||
EDITOR = "emacsclient";
|
||||
#+END_SRC
|
||||
|
||||
#+begin_src nix
|
||||
};
|
||||
}
|
||||
#+end_src
|
|
@ -7,15 +7,18 @@
|
|||
#+PROPERTY: header-args :mkdirp yes :results none
|
||||
#+PROPERTY: header-args:emacs-lisp :tangle lisp-core.el
|
||||
#+ARROYO_EMACS_MODULE: lisp-core
|
||||
|
||||
#+ARCOLOGY_KEY: cce/lisp-core
|
||||
#+CCE_PRIORITY: 62
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
#+ARROYO_MODULE_WANTS: cce/evil_mode.org
|
||||
#+ARROYO_MODULE_WANTS: cce/code_formatting_aggressively.org
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
#+ARROYO_MODULE_WANTS: cce/diminish.org
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(provide 'cce/lisp-core)
|
||||
(use-package evil-lispy)
|
||||
(use-package evil-lispy
|
||||
:diminish)
|
||||
(defun cce/lisp-like-mode-hook ()
|
||||
(aggressive-indent-mode -1)
|
||||
(evil-lispy-mode))
|
||||
|
|
|
@ -26,6 +26,12 @@ high-chaos organization here... replacing [[id:cce/ivy_and_counsel][Ivy and Coun
|
|||
(use-package vertico
|
||||
:init
|
||||
(vertico-mode)
|
||||
(setq completion-in-region-function
|
||||
(lambda (&rest args)
|
||||
(apply (if vertico-mode
|
||||
#'consult-completion-in-region
|
||||
#'completion--in-region)
|
||||
args)))
|
||||
:bind
|
||||
("C-x C-z" . 'vertico-repeat))
|
||||
|
||||
|
|
|
@ -43,8 +43,6 @@ I use =msmtp= in the meantime, it is a forwarding mail agent which can be config
|
|||
|
||||
primary = true;
|
||||
|
||||
passwordCommand = "pass show fastmail_email_app";
|
||||
|
||||
msmtp = {
|
||||
enable = true;
|
||||
extraConfig = {logfile = "/tmp/msmtp.log";};
|
||||
|
@ -56,28 +54,6 @@ I use =msmtp= in the meantime, it is a forwarding mail agent which can be config
|
|||
tls = { useStartTls = true; };
|
||||
};
|
||||
};
|
||||
accounts.email.accounts.crdig = {
|
||||
address = "ryan.rix.consultant@consumer.org";
|
||||
realName = "Ryan Rix (rrix)";
|
||||
|
||||
aliases = [];
|
||||
userName = "ryan.rix.consultant@consumer.org";
|
||||
|
||||
primary = false;
|
||||
|
||||
passwordCommand = "pass show crdigital/email_app_passwd";
|
||||
|
||||
msmtp = {
|
||||
enable = true;
|
||||
extraConfig = {logfile = "/tmp/msmtp.log";};
|
||||
};
|
||||
|
||||
smtp = {
|
||||
host = "smtp.gmail.com";
|
||||
port = 587;
|
||||
tls = { useStartTls = true; };
|
||||
};
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
:PROPERTIES:
|
||||
:ID: 9ce3cedf-7f1b-45e0-aa12-e1bd7d739cbb
|
||||
:END:
|
||||
#+TITLE: Configuring Shell Variables
|
||||
#+filetags: :Emacs:CCE:Shells:
|
||||
#+PROPERTY: header-args :mkdirp yes :results none
|
||||
#+PROPERTY: header-args:emacs-lisp :tangle shell-vars.el
|
||||
#+PROPERTY: header-args:nix :tangle ~/arroyo-nix/hm/prompt.nix
|
||||
#+ARROYO_MODULE_WANTS: cce/emacs_shell_mode_is_good_enough.org
|
||||
|
||||
#+ARROYO_EMACS_MODULE: shell-vars
|
||||
#+CCE_PREDICATE: nil
|
||||
#+CCE_PRIORITY: 40
|
||||
#+AUTO_TANGLE: t
|
||||
|
||||
While [[id:configuring_profile_variables][Configuring Profile Variables]] concerns itself primarily with some basic configurations that goes in to =~/.bash_profile=, this document concerns itself with things that go in my =~/.bashrc=, things which are run by every new interactive bash shell process, rather than being run by the system once and inherited by sub-processes.
|
||||
|
||||
#+ARROYO_HOME_MODULE: hm/prompt.nix
|
||||
|
||||
#+begin_src nix :noweb yes
|
||||
{ ... }:
|
||||
{
|
||||
programs.bash.enable = true;
|
||||
#+end_src
|
||||
|
||||
I use [[id:20220906T101932.011701][Atuin]] for shell search history right now.
|
||||
|
||||
I cribbed my =PS1= from [[id:f4d0be16-1f68-4598-a02c-0327759e034c][Tor]] a long time ago, it is a simple on that simply puts a smiley-face if the previous command returned successfully, and a frown-face if the previous command returned an error-code.
|
||||
|
||||
#+begin_src nix :noweb yes
|
||||
home.sessionVariables = {
|
||||
PS1 = ''\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w \[\033[00m\]\`if [ \$? == 0 ]; then echo \:\); else echo \:\(; fi\` $ '';
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
That =PS1= will prevent [[id:cce/emacs][Emacs]]'s command-interpreter ("comint") from working properly. One must set [[help:comint-prompt-regexp][comint-prompt-regexp]] to make it behave properly:
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(defun cce/fixup-comint ()
|
||||
(interactive)
|
||||
(setq-local comint-prompt-regexp "^[^#$%>)(\n]*[#$%>)(] +"))
|
||||
(add-hook 'shell-mode-hook #'cce/fixup-comint)
|
||||
(provide 'cce/shell-vars)
|
||||
#+end_src
|
||||
|
||||
Eshell "smart" mode
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(require 'em-smart)
|
||||
(setq eshell-where-to-jump 'begin)
|
||||
(setq eshell-review-quick-commands nil)
|
||||
(setq eshell-smart-space-goes-to-end t)
|
||||
|
||||
(evil-define-key 'insert 'eshell-mode-map (kbd "M-a") #'eshell-bol)
|
||||
|
||||
(defun eshell/lcd (&optional directory)
|
||||
(if (file-remote-p default-directory)
|
||||
(with-parsed-tramp-file-name default-directory nil
|
||||
(eshell/cd (tramp-make-tramp-file-name
|
||||
(tramp-file-name-method v)
|
||||
(tramp-file-name-user v)
|
||||
nil
|
||||
(tramp-file-name-host v)
|
||||
nil
|
||||
(or directory "")
|
||||
(tramp-file-name-hop v))))
|
||||
(eshell/cd directory)))
|
||||
#+end_src
|
||||
|
||||
Eshell can now "emulate a terminal"
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package eat
|
||||
:hook
|
||||
(eshell-load . eat-eshell-mode)
|
||||
(eshell-load . eat-eshell-visual-command-mode))
|
||||
#+end_src
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package which-key
|
||||
:diminish
|
||||
:config
|
||||
(which-key-mode))
|
||||
(defhydra hydra-help (:columns 4)
|
||||
|
|
|
@ -31,10 +31,14 @@ Anki is the go-to digital solution for general study these days, I use org-drill
|
|||
:custom
|
||||
(org-fc-directories '("~/org/"))
|
||||
(org-fc-review-history-file (expand-file-name "~/org/org-fc-reviews.tsv"))
|
||||
(org-fc-shuffle-positions nil)
|
||||
<<org-fc-contexts>>
|
||||
:config
|
||||
(require 'org-fc-hydra)
|
||||
(defalias 'srs #'org-fc-dashboard)
|
||||
|
||||
<<org-fc-customization>>
|
||||
|
||||
(evil-define-minor-mode-key '(normal insert emacs) 'org-fc-review-flip-mode
|
||||
(kbd "RET") 'org-fc-review-flip
|
||||
(kbd "n") 'org-fc-review-flip
|
||||
|
@ -50,6 +54,8 @@ Anki is the go-to digital solution for general study these days, I use org-drill
|
|||
(kbd "q") 'org-fc-review-quit))
|
||||
#+end_src
|
||||
|
||||
This gets crammed in =overrides= to be in the =epkgs= "index" in [[id:arroyo/emacs][Arroyo Emacs]] definition:
|
||||
|
||||
#+ARROYO_HOME_EPKGS: overrides/org-fc.nix
|
||||
#+begin_src nix :tangle ~/arroyo-nix/overrides/org-fc.nix
|
||||
org-fc = let
|
||||
|
@ -77,6 +83,8 @@ in epkgs.melpaBuild {
|
|||
};
|
||||
#+end_src
|
||||
|
||||
This probably doesn't need to be here...
|
||||
|
||||
#+ARROYO_HOME_MODULE: hm/org-fc.nix
|
||||
#+begin_src nix :tangle ~/arroyo-nix/hm/org-fc.nix
|
||||
{ pkgs, ... }:
|
||||
|
@ -87,6 +95,9 @@ in epkgs.melpaBuild {
|
|||
#+end_src
|
||||
|
||||
* Some Custom SRS contexts
|
||||
:PROPERTIES:
|
||||
:ID: 20230508T223733.992116
|
||||
:END:
|
||||
|
||||
Sometimes it's nice to focus on one thing at a time. =org-fc= gives us custom contexts and here's how I use it:
|
||||
|
||||
|
@ -96,12 +107,43 @@ Sometimes it's nice to focus on one thing at a time. =org-fc= gives us custom co
|
|||
(setq org-fc-custom-contexts
|
||||
'((japanese . (:filter (and (tag "japanese")
|
||||
(tag "vocabulary"))))
|
||||
(buddhism . (:filter (tag "Buddhism")))
|
||||
(buddhism . (:filter (and (not (tag "vocabulary"))
|
||||
(tag "Buddhism"))))
|
||||
(trivia . (:filter (tag "trivia")))
|
||||
(kanji . (:filter (or (tag "jokugo") (tag "kanji"))))
|
||||
(poetry . (:filter (tag "poem")))
|
||||
(tokipona . (:filter (tag "tokipona")))
|
||||
(row . (:filter (not (tag "vocabulary"))))))
|
||||
(row . (:filter (and
|
||||
(not (tag "Buddhism"))
|
||||
(not (tag "vocabulary")))))))
|
||||
#+end_src
|
||||
|
||||
* Some =org-fc= hacks
|
||||
|
||||
I have a =node_modules= directory with a Node package used for some of my [[id:cce/literate_programming][Literate Programming]] shenanigans and it includes a directory with a =.org= suffix. This modifies the find command to exclude those.
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref org-fc-customization
|
||||
(defun org-fc-awk--find (paths)
|
||||
"Generate shell code to search PATHS for org files.
|
||||
Matches all .org files ignoring ones with names don't start with
|
||||
a '.' to exclude temporary / backup files.
|
||||
With the '-L' option, 'find' follows symlinks."
|
||||
(format
|
||||
"find -L %s -type f -name \"*.org\" -not -name \".*\" -print0"
|
||||
(mapconcat
|
||||
(lambda (path) (shell-quote-argument (expand-file-name path)))
|
||||
paths " ")))
|
||||
#+end_src
|
||||
|
||||
I add a customization option which allows me to do my reviews in smaller bursts. it makes it easier to come back to things which I have forgotten; if i have a stack I haven't touched in Too Long, it'll take a really long time to retain because i will get through 40 or 80 or them and the ones i have to repeat will be at the bottom of the pile. Adjusting this down lets me get through my stacks faster.
|
||||
|
||||
#+begin_src emacs-lisp :noweb-ref org-fc-customization
|
||||
(defcustom org-fc-review-count 30
|
||||
"if numeric, truncate reviews to this many positions")
|
||||
|
||||
(defun org-fc--truncate-reviews (oldfn &rest args)
|
||||
(take org-fc-review-count (apply oldfn args)))
|
||||
(advice-add 'org-fc-index-positions :around 'org-fc--truncate-reviews)
|
||||
#+end_src
|
||||
|
||||
* Cards to Add
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#+ARCOLOGY_KEY: cce/super-p
|
||||
#+ARROYO_EMACS_MODULE: super-p
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
,#+ARROYO_MODULE_WANTS: cce/exwm.org
|
||||
#+ARROYO_MODULE_WANTS: cce/exwm.org
|
||||
|
||||
#+begin_src emacs-lisp :exports none
|
||||
(provide 'cce/super-p)
|
||||
|
@ -27,6 +27,6 @@ Super-p to run commands without dumping output to a buffer. Super-Shift-P calls
|
|||
(interactive (list (read-shell-command "Run: $ ")))
|
||||
(async-shell-command command (generate-new-buffer " *async command*")))
|
||||
|
||||
; (exwm-input-set-key (kbd "s-p") #'background-shell-command)
|
||||
(exwm-input-set-key (kbd "s-p") #'background-shell-command)
|
||||
(global-set-key (kbd "s-p") #'background-shell-command)
|
||||
#+END_SRC
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
:PROPERTIES:
|
||||
:ID: 20230220T220556.588418
|
||||
:ROAM_ALIASES: syncthingtray syncthing-tray "Syncthing Tray"
|
||||
:END:
|
||||
#+TITLE: Controlling Syncthing on my Endpoints
|
||||
|
||||
#+ARCOLOGY_KEY: cce/syncthing-tray
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
|
||||
A shortcoming of the [[id:arroyo/arroyo][Arroyo Systems Management]] data model is that I can't have modules in the same file with different roles: If I were to install [[id:cce/syncthing][Syncthing]]'s tray files in the Syncthing page, it pulls in a whole Qt and KDE Plasma environment on to my server! So I define it here. [[id:09fa0674-ad3b-43c5-8d7c-6b532346a772][open threads]]
|
||||
|
||||
So this is the tray module for [[id:cce/syncthing][Syncthing]] which is installed in [[id:cce/my_nixos_configuration][My NixOS configuration]] for endpoints.
|
||||
|
||||
#+ARROYO_HOME_MODULE: hm/syncthing-tray.nix
|
||||
#+ARROYO_NIXOS_ROLE: endpoint
|
||||
#+AUTO_TANGLE: t
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/hm/syncthing-tray.nix
|
||||
{ lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
services.syncthing.tray.enable = true;
|
||||
systemd.user.services.syncthingtray.Service.ExecStart = lib.mkForce "${pkgs.syncthingtray}/bin/syncthingtray --wait";
|
||||
systemd.user.services.syncthingtray.Unit.After = lib.mkForce ["graphical-session-pre.target"];
|
||||
systemd.user.services.syncthingtray.Unit.Requires = lib.mkForce [];
|
||||
home.packages = [ pkgs.syncthingtray ];
|
||||
}
|
||||
#+end_src
|
||||
|
||||
I modify the =systemd= configuration to wait for the Plasma tray to become available since there is no =tray.target= which the default configuration relies on.
|
|
@ -17,7 +17,7 @@ I have a lot of data exposed in my Syncthing; this laptop, with my entire Music
|
|||
|
||||
Syncthing is installed with [[id:cce/home-manager][home-manager]], and bootstrapped manually, copying IDs around in some way. it's a bit of a pain and i'd like to have a better configuration generator some day, or at least documentation of this bootstrap process...
|
||||
|
||||
This is straightforward:
|
||||
This is straightforward; [[id:20230220T220556.588418][Syncthing Tray]] is installed elsewhere.
|
||||
|
||||
#+ARROYO_HOME_MODULE: hm/syncthing.nix
|
||||
#+begin_src nix :tangle ~/arroyo-nix/hm/syncthing.nix
|
||||
|
@ -25,11 +25,6 @@ This is straightforward:
|
|||
{
|
||||
services.syncthing.enable = true;
|
||||
services.syncthing.extraOptions = ["--gui-address=http://0.0.0.0:8384"];
|
||||
services.syncthing.tray.enable = true;
|
||||
home.packages = [ pkgs.syncthingtray ];
|
||||
systemd.user.services.syncthingtray.Service.ExecStart = lib.mkForce "${pkgs.syncthingtray}/bin/syncthingtray --wait";
|
||||
systemd.user.services.syncthingtray.Unit.After = lib.mkForce ["graphical-session-pre.target"];
|
||||
systemd.user.services.syncthingtray.Unit.Requires = lib.mkForce [];
|
||||
}
|
||||
#+end_src
|
||||
|
||||
|
@ -45,18 +40,26 @@ I poke a hole in the firewall in [[id:cce/my_nixos_configuration][My NixOS confi
|
|||
}
|
||||
#+end_src
|
||||
|
||||
* Dealing with Syncthing Conflicts
|
||||
:PROPERTIES:
|
||||
:ID: 20230111T141211.153590
|
||||
:END:
|
||||
|
||||
I have some functions which help deal with conflicts:
|
||||
|
||||
#+ARROYO_EMACS_MODULE: syncthing
|
||||
#+begin_src emacs-lisp :tangle ~/org/cce/syncthing.el
|
||||
(defun cce/syncthing-deconflict--possible-pairs (dir)
|
||||
(->> (f-directories dir)
|
||||
(append (list dir))
|
||||
(--map (f-glob "*sync-conflict*.org" it))
|
||||
(-flatten)
|
||||
(--map (list it (replace-regexp-in-string (rx (seq (literal ".sync-conflict") (one-or-more (not ".")) )) "" it)))))
|
||||
|
||||
(defun cce/syncthing-deconflict (&optional dir)
|
||||
(interactive "D")
|
||||
(let* ((dir (or dir org-roam-directory))
|
||||
(possible-pairs
|
||||
(->> (f-directories org-roam-directory)
|
||||
(--map (f-glob "*sync-conflict*.org" it))
|
||||
(-flatten)
|
||||
(--map (list it (replace-regexp-in-string (rx (seq (literal ".sync-conflict") (one-or-more (not ".")) )) "" it)))))
|
||||
(possible-pairs (cce/syncthing-deconflict--possible-pairs dir))
|
||||
(stale-conflict-files ; source doesn't exist or was moved elsewhere.
|
||||
(--remove (file-exists-p (second it)) possible-pairs))
|
||||
(ediff-candidates ; source does exist and should be ediff'd
|
||||
|
|
|
@ -5,12 +5,13 @@
|
|||
#+filetags: :Emacs:CCE:
|
||||
#+PROPERTY: header-args :mkdirp yes :results none
|
||||
#+PROPERTY: header-args:emacs-lisp :tangle text-editing.el
|
||||
#+ARROYO_EMACS_MODULE: text-editing
|
||||
|
||||
#+ARCOLOGY_KEY: cce/text-editing
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
#+CCE_PREDICATE: t
|
||||
#+CCE_PRIORITY: 10
|
||||
|
||||
#+ARROYO_EMACS_MODULE: text-editing
|
||||
#+ARROYO_MODULE_WANTS: cce/configure_packaging.org
|
||||
#+ARROYO_MODULE_WANTS: cce/diminish.org
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(provide 'cce/text-editing)
|
||||
|
@ -35,6 +36,7 @@ really what I need is an [[id:39e7910b-1ab2-47e3-ad0e-f6680f6a362b][Emacs 'data-
|
|||
(visual-line-mode 1)
|
||||
(auto-fill-mode -1))
|
||||
(add-hook 'text-mode-hook #'cce/text-mode-hook)
|
||||
(diminish 'visual-line-mode)
|
||||
#+end_src
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#+CCE_PRIORITY: 30
|
||||
#+AUTO_TANGLE: t
|
||||
|
||||
(These days I use [[id:20230201T121135.988658][Bitwarden]] and [[id:20230201T121604.003311][vaultwarden]] but maintain this until I'm confident that I won't need any of my "deprecated" passwords.)
|
||||
|
||||
#+ARROYO_EMACS_MODULE: pass
|
||||
#+ARROYO_HOME_MODULE: hm/pass.nix
|
||||
#+ARROYO_NIXOS_EXCLUDE: waterboy
|
||||
|
|
|
@ -16,8 +16,8 @@ Those code could really use a re-factor already, and I just wrote it! toggles li
|
|||
|
||||
#+begin_src emacs-lisp :tangle toggle-theme.el :mkdirp yes :results none
|
||||
(provide 'cce/toggle-theme)
|
||||
(setq cce/light-theme 'ef-spring)
|
||||
(setq cce/dark-theme 'ef-autumn)
|
||||
(setq cce/light-theme 'ef-cyprus)
|
||||
(setq cce/dark-theme 'ef-bio)
|
||||
(defun cce/switch-dark-theme ()
|
||||
"Enable dark theme in Firefox, KDE and Emacs"
|
||||
(interactive)
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
:PROPERTIES:
|
||||
:ID: 20230310T155744.804329
|
||||
:ROAM_ALIASES: ttrss tt-rss
|
||||
:END:
|
||||
#+TITLE: Tiny-Tiny RSS
|
||||
|
||||
#+ARROYO_NIXOS_MODULE: nixos/ttrss.nix
|
||||
#+ARROYO_NIXOS_ROLE: server
|
||||
#+AUTO_TANGLE: t
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/ttrss.nix
|
||||
{ pkgs, ... }:
|
||||
|
||||
let
|
||||
wallabag = pkgs.stdenv.mkDerivation rec {
|
||||
pname = "tt-rss-plugin-wallabag";
|
||||
version = "2.0.0";
|
||||
|
||||
src = pkgs.callPackage pkgs.lib.pkgVersions.ttrss_wallabag {};
|
||||
installPhase = ''
|
||||
mkdir -p $out/wallabag_v2
|
||||
cp -r wallabag_v2/* $out/wallabag_v2/
|
||||
'';
|
||||
};
|
||||
|
||||
large_apod = pkgs.stdenv.mkDerivation rec {
|
||||
pname = "tt-rss-plugin-large-apod";
|
||||
version = "0.0.1";
|
||||
src = pkgs.callPackage pkgs.lib.pkgVersions.large_apod {};
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/large_apod
|
||||
cp -r large_apod/* $out/large_apod
|
||||
'';
|
||||
};
|
||||
|
||||
readability = pkgs.stdenv.mkDerivation rec {
|
||||
pname = "tt-rss-plugin-af_readability";
|
||||
version = "0.0.1";
|
||||
src = pkgs.callPackage pkgs.lib.pkgVersions.ttrss_readability {};
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/af_readability
|
||||
cp -r ./* $out/af_readability
|
||||
'';
|
||||
};
|
||||
in {
|
||||
services.tt-rss = {
|
||||
enable = true;
|
||||
database = {
|
||||
type = "pgsql";
|
||||
};
|
||||
logDestination = "syslog";
|
||||
root = "/srv/tt-rss";
|
||||
selfUrlPath = "https://feeds.whatthefuck.computer";
|
||||
virtualHost = "feeds.whatthefuck.computer";
|
||||
pluginPackages = [
|
||||
wallabag
|
||||
large_apod
|
||||
readability
|
||||
];
|
||||
plugins = [
|
||||
"auth_internal"
|
||||
"note"
|
||||
"wallabag_v2"
|
||||
"large_apod"
|
||||
"af_readability"
|
||||
];
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
#+ARROYO_EMACS_MODULE: ttrss
|
||||
|
||||
#+begin_src emacs-lisp :tangle ~/org/cce/ttrss.el
|
||||
(use-package elfeed)
|
||||
|
||||
(use-package elfeed-protocol
|
||||
:config
|
||||
(setq elfeed-use-curl t)
|
||||
(elfeed-set-timeout 36000)
|
||||
(setq elfeed-protocol-ttrss-maxsize 200)
|
||||
; (setq elfeed-feeds '("ttrss+https://user:pass@feeds.whatthefuck.computer" ))
|
||||
(elfeed-protocol-enable)
|
||||
)
|
||||
#+end_src
|
||||
|
|
@ -2,14 +2,16 @@
|
|||
:ID: cce/undo_tree
|
||||
:ROAM_ALIASES: undo-tree
|
||||
:END:
|
||||
#+TITLE: Undo and Redo with a tree
|
||||
#+TITLE: Emacs Undo and Redo with a tree
|
||||
#+PROPERTY: header-args :mkdirp yes :results none
|
||||
#+PROPERTY: header-args:emacs-lisp :tangle undo-tree.el
|
||||
|
||||
#+ARROYO_EMACS_MODULE: undo-tree
|
||||
#+ARROYO_MODULE_WANTS: cce/configure_packaging.org
|
||||
#+ARROYO_MODULE_WANTS: cce/diminish.org
|
||||
|
||||
#+ARCOLOGY_KEY: cce/undo-tree
|
||||
#+ARCOLOGY_ALLOW_CRAWL: t
|
||||
#+CCE_PREDICATE: t
|
||||
#+CCE_PRIORITY: 10
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(provide 'cce/undo-tree)
|
||||
|
@ -34,7 +36,6 @@ It's simple and having it around is cheap and easy.
|
|||
#+CAPTION: a text-visualization of undo-tree's tree view. Four events sprout from a single point where I did multiple undo actions and I am partway down a new timeline.
|
||||
[[file:../data/11/b9070e-f1ab-44b5-a204-9662cc146ace/undo-tree.png][file:data/11/b9070e-f1ab-44b5-a204-9662cc146ace/undo-tree.png]]
|
||||
|
||||
#+ARROYO_MODULE_WANTS: cce/configure_packaging.org
|
||||
* Screenshots :ATTACH:
|
||||
:PROPERTIES:
|
||||
:ID: 11b9070e-f1ab-44b5-a204-9662cc146ace
|
||||
|
|
|
@ -65,6 +65,8 @@ handled a little bit differently due to one having a process filter and the othe
|
|||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package xterm-color
|
||||
:commands xterm-color-colorize-buffer xterm-color-test
|
||||
:autoload xterm-color-filter
|
||||
:config
|
||||
(setenv "TERM" "xterm-256color")
|
||||
(setq compilation-environment '("TERM=xterm-256color"))
|
||||
|
@ -80,5 +82,5 @@ handled a little bit differently due to one having a process filter and the othe
|
|||
(shell-mode . (lambda ()
|
||||
(add-hook 'comint-preoutput-filter-functions
|
||||
'xterm-color-filter nil t)))
|
||||
(compilation-start . #'cce/compilation-start-hook))
|
||||
(compilation-start . cce/compilation-start-hook))
|
||||
#+END_SRC
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
:PROPERTIES:
|
||||
:ID: 20230201T121604.003311
|
||||
:ROAM_ALIASES: vaultwarden
|
||||
:END:
|
||||
#+TITLE: Storing passwords securely with vaultwarden
|
||||
|
||||
#+ARCOLOGY_KEY: cce/vaultwarden
|
||||
#+ARCOLOG_ALLOW_CRAWL: t
|
||||
|
||||
Running Vaultwarden on [[id:20211120T220054.226284][The Wobserver]] isn't so hard thanks to [[id:c75d20e6-8888-4c5a-ac97-5997e2f1c711][Nixpkgs]]. This is a self-hosted [[id:20230201T121135.988658][Bitwarden]] server.
|
||||
|
||||
This is all pretty basic, set up a [[id:cce/wobserver/postgres][PostgreSQL]] DB, setup the service, set up an [[id:e4998eda-d14a-48ee-9661-3d7d1bead53c][Nginx Frontend]] -- if you set =DATA_FOLDER= to something custom, however, you need to override the =systemd= service definition to allow writing to that directory. It'll be pretty upset and difficult to debug if you don't do this, ask me how I know...
|
||||
|
||||
I also had to set up =SMTP= configuration to activate my user ... Eventually [[id:20211120T220054.226284][The Wobserver]] needs to support sending mails like this through AWS or SendGrid or something, but for now I just set up a [[roam:Fastmail]] app-password for my account and shoved those in the DB. Yikes.
|
||||
|
||||
#+ARROYO_NIXOS_MODULE: nixos/vaultwarden.nix
|
||||
#+ARROYO_NIXOS_ROLE: server
|
||||
#+AUTO_TANGLE: t
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/vaultwarden.nix
|
||||
{ pkgs, config, ... }:
|
||||
|
||||
let
|
||||
cfg = config.services.vaultwarden;
|
||||
in
|
||||
{
|
||||
services.postgresql.ensureDatabases = ["vaultwarden"];
|
||||
services.postgresql.ensureUsers = [
|
||||
{
|
||||
name = "vaultwarden";
|
||||
ensurePermissions = {
|
||||
"DATABASE vaultwarden" = "ALL PRIVILEGES";
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
services.vaultwarden = {
|
||||
enable = true;
|
||||
# backupDir = "/srv/vaultwarden/backup"; # only for sqlite
|
||||
dbBackend = "postgresql";
|
||||
config = {
|
||||
DATABASE_URL = "postgresql://vaultwarden@%2Frun%2Fpostgresql/vaultwarden";
|
||||
DATA_FOLDER = "/srv/vaultwarden/data";
|
||||
SIGNUPS_ALLOWED = false;
|
||||
SIGNUPS_DOMAINS_WHITELIST = "whatthefuck.computer,rix.si";
|
||||
DOMAIN = "https://vault.whatthefuck.computer";
|
||||
ROCKET_ADDRESS = "127.0.0.1";
|
||||
ROCKET_PORT = 8222;
|
||||
};
|
||||
environmentFile = "/srv/vaultwarden/private.env";
|
||||
};
|
||||
systemd.services.vaultwarden.serviceConfig.ReadWritePaths = [ cfg.config.DATA_FOLDER ];
|
||||
|
||||
services.nginx.virtualHosts."vault.whatthefuck.computer" = {
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:${toString cfg.config.ROCKET_PORT}";
|
||||
};
|
||||
};
|
||||
}
|
||||
#+end_src
|
158
version_pins.org
158
version_pins.org
|
@ -14,7 +14,7 @@
|
|||
To update this document:
|
||||
|
||||
- Call [[id:20220526T160150.431487][cce/update-nixpkgs-checkout]] to update nixpkgs and then possibly resolve merge conflicts myself.
|
||||
- =M-o i= will call =nix-update-branch-revs= to fetch the latest revision for modules using =builtins.fetchGit=.[fn:1]
|
||||
- =M-o i= will call =nix-update-branch-revs= to fetch the latest revision for modules using =builtins.fetchGit=.[fn:1:This is required because I couldn't get =nix-update-decls= to update the revs of these without also populating a =sha256= key which will not be valid in a =builtins.fetchGit= invocation. Both [[id:nix_community_emacs_overlay][nix-community/emacs-overlay]] and [[id:cce/home-manager][home-manager]] are loaded in situations where there is no pre-existing [[id:c75d20e6-8888-4c5a-ac97-5997e2f1c711][nixpkgs]] to invoke, so they have to use this "impure" invocation.]
|
||||
- =C-u M-o o= will call =nix-update-decls= to update the =rev= and =sha256= for the rest. Note the prefix argument which will force =nix-prefetch-git= to fetch the latest revisions of the default (or specified) branch.
|
||||
|
||||
To understand why/how read on:
|
||||
|
@ -66,14 +66,18 @@ homeManager = _: builtins.fetchGit {
|
|||
|
||||
By structuring these invocations like this it is possible to write a function contained in my [[id:20220913T104837.013589][nix-update]] page which will iterate over all the call sections and update the =builtins.fetchGit= entities, and then update the revisions and =sha256= of the rest of the document, and safely tangle the new values out on save. This is probably a useful pattern in developing [[id:128ab0e8-a1c7-48bf-9efe-0c23ce906a48][Hypermedia]] in org-mode.
|
||||
|
||||
[fn:1] This is required because I couldn't get =nix-update-decls= to update the revs of these without also populating a =sha256= key which will not be valid in a =builtins.fetchGit= invocation. Both [[id:nix_community_emacs_overlay][nix-community/emacs-overlay]] and [[id:cce/home-manager][home-manager]] are loaded in situations where there is no pre-existing [[id:c75d20e6-8888-4c5a-ac97-5997e2f1c711][nixpkgs]] to invoke, so they have to use this "impure" invocation.
|
||||
|
||||
* NEXT update my [[id:c75d20e6-8888-4c5a-ac97-5997e2f1c711][NixOS]] version pins and deploy
|
||||
SCHEDULED: <2023-01-03 Tue .+2w>
|
||||
SCHEDULED: <2023-08-10 Thu .+2w>
|
||||
:PROPERTIES:
|
||||
:LAST_REPEAT: [2022-12-20 Tue 13:15]
|
||||
:LAST_REPEAT: [2023-07-27 Thu 15:37]
|
||||
:END:
|
||||
:LOGBOOK:
|
||||
- State "DONE" from "NEXT" [2023-07-27 Thu 15:37]
|
||||
- State "DONE" from "INPROGRESS" [2023-06-20 Tue 08:07]
|
||||
- State "INPROGRESS" from "NEXT" [2023-06-19 Mon 15:42]
|
||||
- State "DONE" from "NEXT" [2023-05-29 Mon 12:54]
|
||||
- State "DONE" from "NEXT" [2023-04-18 Tue 10:39]
|
||||
- State "DONE" from "NEXT" [2023-03-29 Wed 10:33]
|
||||
- State "DONE" from "NEXT" [2022-12-20 Tue 13:15]
|
||||
CLOCK: [2022-12-20 Tue 10:26]--[2022-12-20 Tue 13:15] => 2:49
|
||||
- State "DONE" from "NEXT" [2022-11-07 Mon 12:15]
|
||||
|
@ -86,29 +90,33 @@ CLOCK: [2022-12-20 Tue 10:26]--[2022-12-20 Tue 13:15] => 2:49
|
|||
{ ... }:
|
||||
|
||||
{
|
||||
# fetchGit
|
||||
<<homeManager>>
|
||||
<<emacsOverlay>>
|
||||
# fetchTarball
|
||||
<<nixpkgs>>
|
||||
# github
|
||||
|
||||
<<nixgl>>
|
||||
<<mastodon>>
|
||||
# tabfs
|
||||
<<tabfs>>
|
||||
|
||||
|
||||
# org libraries
|
||||
<<consult-org-roam>>
|
||||
<<ox-rss>>
|
||||
<<org-fc>>
|
||||
<<delve>>
|
||||
|
||||
<<tabfs>>
|
||||
<<cpmtools>>
|
||||
<<tuhc>>
|
||||
|
||||
# pythons
|
||||
<<beetcamp>>
|
||||
<<bandcamp-dl>>
|
||||
<<mopidy-bandcamp>>
|
||||
<<jisho-api>>
|
||||
|
||||
<<twitter-to-sqlite>>
|
||||
<<inaturalist-to-sqlite>>
|
||||
|
||||
<<ttrss>>
|
||||
}
|
||||
#+end_src
|
||||
|
||||
|
@ -118,17 +126,18 @@ Right now I am running off a branch of [[id:c75d20e6-8888-4c5a-ac97-5997e2f1c711
|
|||
|
||||
** Update [[id:cce/home-manager][home-manager]] by hand
|
||||
|
||||
#+CALL: prefetch-git-rev(REPO="nix-community/home-manager", BRANCH="master")
|
||||
#+CALL: prefetch-git-rev(REPO="nix-community/home-manager", BRANCH="release-23.05")
|
||||
|
||||
#+NAME: prefetch-hm
|
||||
#+results:
|
||||
: "e7eba9cc46547ae86642ad3c6a9a4fb22c07bc26"
|
||||
: "07c347bb50994691d7b0095f45ebd8838cf6bc38"
|
||||
|
||||
#+begin_src nix :noweb-ref homeManager :noweb yes
|
||||
homeManager = _: builtins.fetchGit {
|
||||
url = "https://github.com/nix-community/home-manager.git";
|
||||
allRefs = true;
|
||||
rev =
|
||||
<<prefetch-hm()>>
|
||||
<<prefetch-hm()>>
|
||||
;
|
||||
};
|
||||
#+end_src
|
||||
|
@ -139,7 +148,7 @@ homeManager = _: builtins.fetchGit {
|
|||
|
||||
#+NAME: prefetch-em
|
||||
#+results:
|
||||
: "a201dcf3d712cf6d3934b396d523041781ff9589"
|
||||
: "01c076bb6f9fd34630f4c87cfab18ea4e85ef819"
|
||||
|
||||
#+NAME: emacsOverlay
|
||||
#+begin_src nix :noweb yes
|
||||
|
@ -164,9 +173,9 @@ builds from https://codeberg.org/martianh/mastodon.el/commits/branch/main
|
|||
#+begin_src nix :noweb-ref mastodon
|
||||
mastodon = { pkgs, ... }: pkgs.fetchgit {
|
||||
url = "https://codeberg.org/martianh/mastodon.el";
|
||||
rev = "d9c0d7eeea02c27173ed000af7c560ca978125ea";
|
||||
sha256 = "1fsbpfdssjwfgx8cpl512y6x29q9660v6p0s51r0w2bvdqbqqm92";
|
||||
# date = "2022-12-11T21:30:28+00:00";
|
||||
rev = "20dec8871c9bb5f5e418bfc197e7533b5e3065e3";
|
||||
sha256 = "15cfjny99yw5frdp8nlyazlwgscvfvbinsj0fbdfprxf50k2zjs6";
|
||||
# date = "2023-07-25T14:17:18+02:00";
|
||||
};
|
||||
#+end_src
|
||||
|
||||
|
@ -176,9 +185,9 @@ mastodon = { pkgs, ... }: pkgs.fetchgit {
|
|||
nixGL = { pkgs, ... }: pkgs.fetchFromGitHub {
|
||||
owner = "guibou";
|
||||
repo = "nixGL";
|
||||
rev = "7165ffbccbd2cf4379b6cd6d2edd1620a427e5ae";
|
||||
sha256 = "1wc85xqnq2wb008y9acb29jbfkc242m9697g2b8j6q3yqmfhrks1";
|
||||
# date = "2022-08-24T20:56:02+02:00";
|
||||
rev = "489d6b095ab9d289fe11af0219a9ff00fe87c7c5";
|
||||
sha256 = "03kwsz8mf0p1v1clz42zx8cmy6hxka0cqfbfasimbj858lyd930k";
|
||||
# date = "2023-06-04T21:57:57+02:00";
|
||||
};
|
||||
#+end_src
|
||||
|
||||
|
@ -189,9 +198,9 @@ tabfs-rev = "09d57f94b507f68ec5e16f53b1cc868fbaf6cceb";
|
|||
tabfs-fetch = {pkgs, ...}: pkgs.fetchFromGitHub {
|
||||
owner = "osnr";
|
||||
repo = "TabFS";
|
||||
rev = "09d57f94b507f68ec5e16f53b1cc868fbaf6cceb";
|
||||
sha256 = "0pnzq44plbs358l8lzxzlx35p2c5izvjaqbff5f1fj093wk92wiw";
|
||||
# date = "2022-02-02T00:56:15-05:00";
|
||||
rev = "e056ff9073470192ef4c8498aaa7e722edae87c2";
|
||||
sha256 = "1xbnx30m6dcd10i5xrma5q0azky5w6hgas500ginqg9s9skgciiw";
|
||||
# date = "2023-03-02T15:45:33-05:00";
|
||||
};
|
||||
#+end_src
|
||||
|
||||
|
@ -202,9 +211,9 @@ consult-org-roam-rev = "268f436858e1ea3b263782af466a54e4d603a7d2";
|
|||
consult-org-roam = {pkgs, ...}: pkgs.fetchFromGitHub {
|
||||
owner = "jgru";
|
||||
repo = "consult-org-roam";
|
||||
rev = "96c95e5a14378cc6fc9c22981f5bfd9e18c419f6";
|
||||
sha256 = "1mjz73sv2hkirlsr3hmjfivknwydb4yjf90kk5a4zwmhcs3vlh8q";
|
||||
# date = "2022-11-20T08:18:09+01:00";
|
||||
rev = "2ca42a1c1641a29f1447d35be01bd1fda368a9e2";
|
||||
sha256 = "142fra7wap6dfwd4c82j7z3nk1yw78slrwhjx6vkiql8ylbiw5fi";
|
||||
# date = "2023-05-28T10:55:47+02:00";
|
||||
};
|
||||
#+end_src
|
||||
|
||||
|
@ -216,10 +225,10 @@ ox-rss = rec {
|
|||
rev = "83dc898fa5493925b01716e5dd495d5e07c3d41a";
|
||||
url = "https://gitlab.com/nsavage/ox-rss.git/";
|
||||
src = { pkgs, ... }: pkgs.fetchgit {
|
||||
rev = "83dc898fa5493925b01716e5dd495d5e07c3d41a";
|
||||
rev = "3b8bbe8a392bbb04f17bf426400c53283fd3647a";
|
||||
url = "https://gitlab.com/nsavage/ox-rss.git/";
|
||||
sha256 = "0513kixv9bgkignmji95m3rskn6px6c0fack4zdl61qq09fg8w6h";
|
||||
# date = "2021-06-06T07:25:35-04:00";
|
||||
sha256 = "02k9mbi3shjzpmc2z6w5ypjvxq9mlnw6qjkrs8bi10fqsw6fjkpq";
|
||||
# date = "2023-01-22T11:36:35+00:00";
|
||||
};
|
||||
};
|
||||
#+end_src
|
||||
|
@ -232,9 +241,9 @@ org-fc = rec {
|
|||
src = { pkgs, ... }: pkgs.fetchFromGitHub {
|
||||
owner = "l3kn";
|
||||
repo = "org-fc";
|
||||
rev = "973a16a9561f1ed2fd7e4c5c614b5e5d15715b12";
|
||||
sha256 = "07cjswmfwc1r11m77pp58rcpbxi3hayv2pnfrqz4zk4kvyb2zw2i";
|
||||
# date = "2022-09-27T20:31:27+02:00";
|
||||
rev = "7ab1791dfa6aa6ca252a69d8f43d5b5e8c841190";
|
||||
sha256 = "0hq11kp4l5qs0jgcvjfhggdr31jyl6mcgaj5c8dwr9x7b8awnh6j";
|
||||
# date = "2023-05-14T13:41:04+02:00";
|
||||
};
|
||||
};
|
||||
#+end_src
|
||||
|
@ -248,7 +257,8 @@ cpmtools = {
|
|||
owner = "lipro-cpm4l";
|
||||
repo = "cpmtools";
|
||||
rev = "e534e20c15973a9559e981efb498a102020e5db7";
|
||||
sha256 = "sha256-jKC0uh3sGVUJsiTrOa28h+fF4Ja6Yiwzw5Tqfj9oik4=";
|
||||
sha256 = "0klad0zpxsllqcrjqqmsjvhcbrw7pjnkksr4n84ma6gc3nxb984c";
|
||||
# date = "2020-07-26T12:24:37+02:00";
|
||||
};
|
||||
};
|
||||
#+end_src
|
||||
|
@ -262,8 +272,9 @@ beetcamp = {
|
|||
src = { pkgs, ... }: pkgs.fetchFromGitHub {
|
||||
repo = "beetcamp";
|
||||
owner = "snejus";
|
||||
rev = "118d4239bd570a59997f13ac0920e6e92890ac67";
|
||||
sha256 = "sha256-yrlpgLdNEzlWMY7Cns0UE93oEbpkOoYZHGLpui6MfC0=";
|
||||
rev = "a3b6e7417982a8e68cba8e3e9323924bb8f0bc82";
|
||||
sha256 = "03s7iffrvgmdnrbvb403hnfky13i0ia3phh08c8bqn84y4lq065q";
|
||||
# date = "2023-05-20T12:35:13+01:00";
|
||||
};
|
||||
};
|
||||
#+end_src
|
||||
|
@ -277,7 +288,7 @@ mopidy-bandcamp = {
|
|||
src = { python3Packages, ... }: python3Packages.fetchPypi {
|
||||
version = "1.1.5";
|
||||
pname = "Mopidy-Bandcamp";
|
||||
sha256 = "sha256-wg9zcOKfZQRhpyA1Cu5wvdwKpmrlcr2m9mrqBHgUXAQ=";
|
||||
sha256 = "012w2iw09skayskbswp5dak0mp5xf3p0ld90lxhh8rczw9q763y2";
|
||||
};
|
||||
};
|
||||
#+end_src
|
||||
|
@ -292,8 +303,9 @@ delve = {
|
|||
src = { pkgs, ... }: pkgs.fetchFromGitHub {
|
||||
owner = "publicimageltd";
|
||||
repo = "delve";
|
||||
rev = "9a3e2675ef76865e9ffd95bb49ae1c8307cbfcc1";
|
||||
sha256 = "sha256-gZcSHJnLW8/IYIdGIsU2vnzZFpyTLk3TxLr0dxR0O0Q=";
|
||||
rev = "f06bd7b1d8759a041601a2b8a870e60151cb750c";
|
||||
sha256 = "1b9wf45y600vcf9747d36mnb9mrkaqbn6dwsqr5mik41dgxcw13l";
|
||||
# date = "2023-03-27T09:59:51+02:00";
|
||||
};
|
||||
};
|
||||
#+end_src
|
||||
|
@ -306,8 +318,9 @@ jisho-api = {
|
|||
src = { pkgs, ... }: pkgs.fetchFromGitHub {
|
||||
owner = "pedroallenrevez";
|
||||
repo = "jisho-api";
|
||||
rev = "b80bff460a0f6826232cafce68cb75ef83543a23";
|
||||
sha256 = "sha256-3oEhr/kXesxp5vnELlciaizq88Jwzw2ahTgooA946Pc=";
|
||||
rev = "9d52dcd8a3fab23d1fadd2c9305008705b3bdb7f";
|
||||
sha256 = "1sdjs640dxwxxxrg76pkrq8gvk5nf220dl39r7ljk6rkc9w64ljz";
|
||||
# date = "2022-01-12T00:31:34+00:00";
|
||||
};
|
||||
};
|
||||
#+end_src
|
||||
|
@ -321,7 +334,8 @@ inaturalist-to-sqlite = {
|
|||
owner = "dogsheep";
|
||||
repo = "inaturalist-to-sqlite";
|
||||
rev = "d888c7c2f02aa0dfb1559603f02357cd0089da11";
|
||||
sha256 = "sha256-2YKGGzkRJJ68kj1h8Di8weY0cDGTnOkI1DZ2aqNsy0c=";
|
||||
sha256 = "0iybdjinlxinsh4fk74k65q39rn1phwg0q9xjay9w90i74dqd0nr";
|
||||
# date = "2020-10-21T17:08:29-07:00";
|
||||
};
|
||||
};
|
||||
#+end_src
|
||||
|
@ -335,10 +349,68 @@ twitter-to-sqlite = {
|
|||
owner = "dogsheep";
|
||||
repo = "twitter-to-sqlite";
|
||||
rev = "f09d611782a8372cfb002792dfa727325afb4db6";
|
||||
sha256 = "sha256-ICAs/DOcyMA0DBEaMk/KG2tsMIDl3MKfP1CdtVXQIls=";
|
||||
sha256 = "0nr2s1avb7ah7ygw5p75h0q6qsqvr97k46hi1hsc1j4w6gy2q810";
|
||||
# date = "2021-12-26T10:08:40-08:00";
|
||||
};
|
||||
};
|
||||
#+end_src
|
||||
|
||||
** [[id:20230205T132148.236178][bandcamp-dl]]
|
||||
|
||||
#+begin_src nix :noweb-ref bandcamp-dl
|
||||
bandcamp-dl = {
|
||||
version = "0.0.1";
|
||||
src = { pkgs, ... }: pkgs.fetchFromGitHub {
|
||||
owner = "iliana";
|
||||
repo = "bandcamp-dl";
|
||||
rev = "5b434a8401f51397e4cc7c9bce87f6f137d3ec90";
|
||||
sha256 = "1kqjnsmdpw4mv4f68fxfyclcimn4r6n4fxp5gz838l0dyc7kzqmv";
|
||||
# date = "2023-04-08T22:16:38+00:00";
|
||||
};
|
||||
};
|
||||
#+end_src
|
||||
|
||||
** NEXT [[id:20220506T155905.773161][vsketch and vpype]] dependencies
|
||||
** NEXT automate fetchFromPyPi or move to GH fetchers
|
||||
** [[id:20230310T155744.804329][tt-rss]] plugins
|
||||
|
||||
#+begin_src nix :noweb-ref ttrss
|
||||
large_apod = { pkgs, ... }: pkgs.fetchFromGitHub {
|
||||
owner = "joshp23";
|
||||
repo = "TTRSS-APOD-Fix";
|
||||
rev = "d6233f7a9031eaa07649d6b4777525524827f9de";
|
||||
sha256 = "11vi81vha3sv9nq36ipxisrnrk5y38582f2nk7qg057d6jm9jw0f";
|
||||
# date = "2017-06-25T13:52:41-04:00";
|
||||
};
|
||||
|
||||
ttrss_wallabag = { pkgs, ... }: pkgs.fetchFromGitHub {
|
||||
owner = "joshp23";
|
||||
repo = "ttrss-to-wallabag-v2";
|
||||
rev = "49ade5a1a216de74e42c4942ffa9cbf1bf426bec";
|
||||
sha256 = "09rspawg0by5fk1x5b3b3smzqp4zw93h8c7zdxr63z6wjs41ba0j";
|
||||
# date = "2021-03-14T01:26:43-05:00";
|
||||
};
|
||||
|
||||
# https://gitlab.tt-rss.org/tt-rss/plugins/ttrss-af-readability
|
||||
ttrss_readability = { pkgs, ... }: pkgs.fetchgit {
|
||||
url= "https://gitlab.tt-rss.org/tt-rss/plugins/ttrss-af-readability";
|
||||
rev = "cdc97d886cb7085f9c44a1796ee4bbbf57534d06";
|
||||
sha256 = "sha256-Pbwp+s4G+mOwjseiejb0gbHpInc2lvR+sv85sRP/DVg=";
|
||||
# date = "2021-03-14T01:26:43-05:00";
|
||||
};
|
||||
#+end_src
|
||||
|
||||
** [[id:20230629T103219.772151][Unofficial Homestuck Collection in NixOS]]
|
||||
|
||||
#+begin_src nix :noweb-ref tuhc
|
||||
homestuck = rec {
|
||||
pname = "unofficial-homestuck-collection";
|
||||
version = "2.0.7";
|
||||
src = { ... }: builtins.fetchurl {
|
||||
url = "https://github.com/Bambosh/unofficial-homestuck-collection/releases/download/v${version}/The-Unofficial-Homestuck-Collection-${version}.AppImage";
|
||||
sha256 = "sha256:00xcc020wn25fw4r2pdr4llljbckm52nv2hw3ihf1kx2fvrqc7y9";
|
||||
name = "${pname}-${version}.AppImage";
|
||||
};
|
||||
};
|
||||
#+end_src
|
||||
|
||||
|
|
|
@ -131,6 +131,7 @@ buildPythonPackage rec {
|
|||
] ++ plugins;
|
||||
|
||||
postPatch = ''
|
||||
substituteInPlace pyproject.toml --replace 'matplotlib = { version = ">=3.3.2,<3.6.0", optional = true }' 'matplotlib = { version = ">=3.3.2,<3.8.0", optional = true }'
|
||||
substituteInPlace pyproject.toml --replace 'pnoise = "^0.1.0"' 'pnoise = "^0.2.0"'
|
||||
substituteInPlace pyproject.toml --replace 'setuptools = "^51.0.0"' 'setuptools = "^61.0.0"'
|
||||
'';
|
||||
|
@ -392,7 +393,7 @@ buildPythonPackage rec {
|
|||
|
||||
postPatch = ''
|
||||
substituteInPlace pyproject.toml --replace 'vpype = {extras = ["all"], git = "https://github.com/abey79/vpype", rev = "${vpype-rev}"}' 'vpype = "^1.11.0a0"' \
|
||||
--replace 'Shapely = {extras = ["vectorized"], version = "1.8.2"}' 'Shapely = {extras = ["vectorized"], version = "1.8.4"}'
|
||||
--replace 'Shapely = {extras = ["vectorized"], version = "1.8.2"}' 'Shapely = {extras = ["vectorized"], version = "^2.0"}'
|
||||
|
||||
sed -i '/PySide2/d' pyproject.toml # no idea why there isnt a dist-info written...
|
||||
'';
|
||||
|
@ -522,7 +523,7 @@ buildPythonPackage rec {
|
|||
|
||||
propagatedBuildInputs = [ numpy scipy ];
|
||||
|
||||
checkInputs = [ pytest ];
|
||||
nativeCheckInputs = [ pytest ];
|
||||
checkPhase = ''
|
||||
pytest test
|
||||
'';
|
||||
|
@ -595,6 +596,8 @@ buildPythonPackage rec {
|
|||
, anyio
|
||||
, buildPythonPackage
|
||||
, fetchFromGitHub
|
||||
, rustc
|
||||
, cargo
|
||||
, rustPlatform
|
||||
, setuptools-rust
|
||||
, pythonOlder
|
||||
|
@ -634,11 +637,11 @@ buildPythonPackage rec {
|
|||
'';
|
||||
|
||||
nativeBuildInputs = [
|
||||
cargo
|
||||
rustc
|
||||
] ++ (with rustPlatform; [
|
||||
cargoSetupHook
|
||||
maturinBuildHook
|
||||
rust.cargo
|
||||
rust.rustc
|
||||
]);
|
||||
|
||||
propagatedBuildInputs = [
|
||||
|
@ -649,7 +652,7 @@ buildPythonPackage rec {
|
|||
rm -rf watchfiles
|
||||
'';
|
||||
|
||||
checkInputs = [
|
||||
nativeCheckInputs = [
|
||||
dirty-equals
|
||||
pytest-mock
|
||||
pytest-timeout
|
||||
|
|
|
@ -100,8 +100,8 @@ let
|
|||
in
|
||||
{
|
||||
fonts = {
|
||||
fontconfig.defaultFonts.monospace = ["Vulf Mono" "Deja Vu Sans Mono"];
|
||||
fontconfig.defaultFonts.sansSerif = ["Vulf Sans" "Deja Vu Sans"];
|
||||
fontconfig.defaultFonts.monospace = ["Vulf Mono" "Deja Vu Sans Mono" "Noto Color Emoji" ];
|
||||
fontconfig.defaultFonts.sansSerif = ["Vulf Sans" "Deja Vu Sans" "Noto Color Emoji" ];
|
||||
fonts = [ vulf_mono vulf_sans ];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
:PROPERTIES:
|
||||
:ID: 20230526T152316.126977
|
||||
:ROAM_ALIASES: Waydroid
|
||||
:ROAM_REFS: https://nixos.wiki/wiki/WayDroid
|
||||
:END:
|
||||
#+TITLE: Waydroid on NixOS is pretty simple
|
||||
|
||||
#+ARROYO_NIXOS_MODULE: nixos/waydroid.nix
|
||||
#+ARROYO_NIXOS_ROLE: endpoint
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/waydroid.nix
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
imports = [ ./waydroid-passthroughbrowser.nix ];
|
||||
|
||||
virtualisation = {
|
||||
waydroid.enable = true;
|
||||
lxd.enable = true;
|
||||
};
|
||||
environment.systemPackages = [ pkgs.wl-clipboard ];
|
||||
}
|
||||
#+end_src
|
||||
|
||||
Then in an shell:
|
||||
|
||||
#+begin_src shell
|
||||
sudo waydroid init -s GAPPS
|
||||
sudo systemctl start waydroid-container
|
||||
waydroid session start
|
||||
#+end_src
|
||||
|
||||
Download latest F-droid from https://f-droid.org/ and install it
|
||||
|
||||
#+begin_src shell
|
||||
waydroid app install ~/Downloads/F-Droid.apk
|
||||
#+end_src
|
||||
|
||||
#+begin_src shell
|
||||
waydroid prop set persist.waydroid.multi_windows false
|
||||
#+end_src
|
||||
|
||||
#+results:
|
||||
|
||||
* Waydroid Passthrough Browser
|
||||
:PROPERTIES:
|
||||
:ID: 20230607T162645.250968
|
||||
:END:
|
||||
|
||||
[[https://git.kj7rrv.com/kj7rrv/passthroughbrowser][passthroughbrowser]] is a simple solution to opening links from Android apps in the system browser by setting up a small HTTP server. I'll use it in waydroid configurations in a custom derivation:
|
||||
|
||||
#+AUTO_TANGLE: t
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/pkgs/passthroughbrowser.nix
|
||||
# https://git.kj7rrv.com/kj7rrv/passthroughbrowser.git
|
||||
{ lib, stdenv,
|
||||
makeDesktopItem,
|
||||
fetchFromGitea,
|
||||
buildPythonPackage,
|
||||
flask,
|
||||
... }:
|
||||
|
||||
let
|
||||
|
||||
desktopItem = makeDesktopItem {
|
||||
name = "passthroughbrowser";
|
||||
desktopName = "Waydroid Passthrough Browser";
|
||||
categories = ["Utility"];
|
||||
exec = "passthrough_browser";
|
||||
};
|
||||
in buildPythonPackage {
|
||||
name = "passthroughbrowser";
|
||||
version = "0.0.1";
|
||||
format = "simple";
|
||||
|
||||
src = fetchFromGitea {
|
||||
domain = "git.kj7rrv.com";
|
||||
owner = "kj7rrv";
|
||||
repo = "passthroughbrowser";
|
||||
rev = "11ab0f695b6dae4ebee06fa75d6e2796713add98";
|
||||
sha256 = "sha256-JSbGsWL3kEYw4uUIUgXi7XuXYFQ0Nxkz+fZbvxfpn1o=";
|
||||
};
|
||||
|
||||
propagatedBuildInputs = [
|
||||
flask
|
||||
];
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin $out/share/passthroughbrowser
|
||||
cp $src/server.py $out/bin/passthrough_browser
|
||||
cp $src/PassThroughBrowser.apk $out/share/passthroughbrowser
|
||||
cp --recursive "${desktopItem}/share" "$out/"
|
||||
|
||||
substituteInPlace $out/bin/passthrough_browser \
|
||||
--replace "app.run(host='192.168.250.1', port=8888)" \
|
||||
"import os; app.run(host=os.environ.get('PASSTHROUGH_HOST', '192.168.240.1'), port=8888)"
|
||||
'';
|
||||
}
|
||||
#+end_src
|
||||
|
||||
#+begin_src nix :tangle ~/arroyo-nix/nixos/waydroid-passthroughbrowser.nix
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
home-manager.users.rrix = {
|
||||
home.packages = [
|
||||
pkgs.passthroughbrowser
|
||||
];
|
||||
home.sessionVariables = {
|
||||
PASSTHROUGH_HOST = "192.168.240.1";
|
||||
};
|
||||
};
|
||||
}
|
||||
#+end_src
|
10
xmonad.org
10
xmonad.org
|
@ -217,7 +217,7 @@ rec {
|
|||
|
||||
config = ../files/xmonad.hs;
|
||||
};
|
||||
<<plasma-xmonad>>
|
||||
# <<plasma-xmonad>>
|
||||
}
|
||||
#+end_src
|
||||
|
||||
|
@ -239,9 +239,11 @@ systemd.user.services.plasma-xmonad = {
|
|||
Service.Restart="on-failure";
|
||||
};
|
||||
home.activation.plasma-xmonad = ''
|
||||
systemctl --user mask plasma-kwin_x11.service
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable plasma-xmonad.service
|
||||
# systemctl --user mask plasma-kwin_x11.service
|
||||
# systemctl --user daemon-reload
|
||||
# back to kwin ...
|
||||
systemctl --user unmask plasma-kwin_x11.service
|
||||
systemctl --user disable plasma-xmonad.service
|
||||
'';
|
||||
#+end_src
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#+ARROYO_EMACS_MODULE: yasnippet
|
||||
#+ARROYO_MODULE_WANTS: cce/company_code_completion.org
|
||||
#+ARROYO_MODULE_WANTS: cce/diminish.org
|
||||
|
||||
I need to put my =~/.emacs.d/snippets/= in here so that it's reproduceable. but for now, this minimal setup is good enough.
|
||||
|
||||
|
@ -20,6 +21,7 @@ I need to put my =~/.emacs.d/snippets/= in here so that it's reproduceable. but
|
|||
(use-package yasnippet-snippets :demand)
|
||||
(use-package yasnippet
|
||||
:after company
|
||||
:diminish
|
||||
:config
|
||||
(add-to-list 'company-backends 'company-yasnippet t)
|
||||
(yas-global-mode))
|
||||
|
|
Loading…
Reference in New Issue