Compare commits

..

3 Commits

98 changed files with 1792 additions and 4443 deletions

22
TODO.md
View File

@@ -1,10 +1,7 @@
## BUGS ## BUGS
- mpv UI is sometimes blank for audio/podcasts?
- i think it's when the audio file has no thumbnail?
- why i need to manually restart `wireguard-wg-ovpns` on servo periodically - why i need to manually restart `wireguard-wg-ovpns` on servo periodically
- else DNS fails - else DNS fails
- fix epiphany URL bar input on moby - fix epiphany URL bar input on moby
- sxmo: wvkbd: missing font for icons on the 3rd page
## REFACTORING: ## REFACTORING:
@@ -26,10 +23,6 @@
- REVIEW/integrate jellyfin dataDir config: <https://github.com/NixOS/nixpkgs/pull/233617> - REVIEW/integrate jellyfin dataDir config: <https://github.com/NixOS/nixpkgs/pull/233617>
- remove `libsForQt5.callPackage` broadly: <https://github.com/NixOS/nixpkgs/issues/180841> - remove `libsForQt5.callPackage` broadly: <https://github.com/NixOS/nixpkgs/issues/180841>
#### upstreaming to non-nixpkgs repos
- gtk: build schemas even on cross compilation: <https://github.com/NixOS/nixpkgs/pull/247844>
- sxmo: add new app entries
## IMPROVEMENTS: ## IMPROVEMENTS:
### security/resilience ### security/resilience
@@ -51,13 +44,6 @@
- integrate `nix check` into Gitea actions? - integrate `nix check` into Gitea actions?
### user experience ### user experience
- moby: sxmo: fix youtube scripts (package youtube-cli)
- moby: tune GPS
- run only geoclue, and not gpsd, to save power?
- tune QGPS setting in eg25-control, for less jitter?
- direct mepo to prefer gpsd, with fallback to geoclue, for better accuracy?
- configure geoclue to do some smoothing?
- manually do smoothing, as some layer between mepo and geoclue/gpsd?
- neovim: set up language server (lsp; rnix-lsp; nvim-lspconfig) - neovim: set up language server (lsp; rnix-lsp; nvim-lspconfig)
- Helix: make copy-to-system clipboard be the default - Helix: make copy-to-system clipboard be the default
- firefox/librewolf: persist history - firefox/librewolf: persist history
@@ -76,12 +62,6 @@
- email: fix so that local mail doesn't go to junk - email: fix so that local mail doesn't go to junk
- git sendmail flow adds the DKIM signatures, but gets delivered locally w/o having the sig checked, so goes into Junk - git sendmail flow adds the DKIM signatures, but gets delivered locally w/o having the sig checked, so goes into Junk
- could change junk filter from "no DKIM success" to explicit "DKIM failed" - could change junk filter from "no DKIM success" to explicit "DKIM failed"
- sxmo: don't put all deps on PATH
- maybe: use resholve to hard-code them
- this is the most "correct", but least patchable
- maybe: express each invocation as a function in sxmo_common.sh
- this will require some patching to handle `exec <foo>` style
- maybe: save original PATH and reset it before invoking user files
### perf ### perf
- add `pkgs.impure-cached.<foo>` package set to build things with ccache enabled - add `pkgs.impure-cached.<foo>` package set to build things with ccache enabled
@@ -98,6 +78,4 @@
## NEW FEATURES: ## NEW FEATURES:
- migrate MAME cabinet to nix - migrate MAME cabinet to nix
- boot it from PXE from servo? - boot it from PXE from servo?
- deploy to new server, and use it as a remote builder
- enable IPv6 - enable IPv6
- package lemonade lemmy app: <https://linuxphoneapps.org/apps/ml.mdwalters.lemonade/>

18
flake.lock generated
View File

@@ -69,11 +69,11 @@
}, },
"nixpkgs-stable": { "nixpkgs-stable": {
"locked": { "locked": {
"lastModified": 1693097136, "lastModified": 1690066826,
"narHash": "sha256-fBZSMdBaoZ0INFbyZ5s0DOF7zDNcLsLxgkwdDh3l9Pc=", "narHash": "sha256-6L2qb+Zc0BFkh72OS9uuX637gniOjzU6qCDBpjB2LGY=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "9117c4e9dc117a6cd0319cca40f2349ed333669d", "rev": "ce45b591975d070044ca24e3003c830d26fea1c8",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -85,11 +85,11 @@
}, },
"nixpkgs-unpatched": { "nixpkgs-unpatched": {
"locked": { "locked": {
"lastModified": 1693377291, "lastModified": 1691006197,
"narHash": "sha256-vYGY9bnqEeIncNarDZYhm6KdLKgXMS+HA2mTRaWEc80=", "narHash": "sha256-DbtxVWPt+ZP5W0Usg7jAyTomIM//c3Jtfa59Ht7AV8s=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "e7f38be3775bab9659575f192ece011c033655f0", "rev": "66aedfd010204949cb225cf749be08cb13ce1813",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -116,11 +116,11 @@
"nixpkgs-stable": "nixpkgs-stable" "nixpkgs-stable": "nixpkgs-stable"
}, },
"locked": { "locked": {
"lastModified": 1693404499, "lastModified": 1690199016,
"narHash": "sha256-cx/7yvM/AP+o/3wPJmA9W9F+WHemJk5t+Xcr+Qwkqhg=", "narHash": "sha256-yTLL72q6aqGmzHq+C3rDp3rIjno7EJZkFLof6Ika7cE=",
"owner": "Mic92", "owner": "Mic92",
"repo": "sops-nix", "repo": "sops-nix",
"rev": "d9c5dc41c4b1f74c77f0dbffd0f3a4ebde447b7a", "rev": "c36df4fe4bf4bb87759b1891cab21e7a05219500",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -298,26 +298,6 @@
program = ''${deployScript "servo" "servo" "switch"}''; program = ''${deployScript "servo" "servo" "switch"}'';
}; };
sync-moby = {
# copy music from the current device to moby
# TODO: should i actually sync from /mnt/servo-media/Music instead of the local drive?
type = "app";
program = builtins.toString (pkgs.writeShellScript "sync-to-moby" ''
sudo mount /mnt/moby-home
${pkgs.sane-scripts.sync-music}/bin/sane-sync-music ~/Music /mnt/moby-home/Music
'');
};
sync-lappy = {
# copy music from servo to lappy
# can run this from any device that has ssh access to lappy
type = "app";
program = builtins.toString (pkgs.writeShellScript "sync-to-lappy" ''
sudo mount /mnt/lappy-home
${pkgs.sane-scripts.sync-music}/bin/sane-sync-music /mnt/servo-media/Music /mnt/lappy-home/Music
'');
};
check-nur = { check-nur = {
# `nix run '.#check-nur'` # `nix run '.#check-nur'`
# validates that my repo can be included in the Nix User Repository # validates that my repo can be included in the Nix User Repository

View File

@@ -28,7 +28,7 @@
# see <repo:mil/sxmo-utils:scripts/deviceprofiles> # see <repo:mil/sxmo-utils:scripts/deviceprofiles>
# SXMO_DEVICE_NAME = "pine64,pinephone-1.2"; # SXMO_DEVICE_NAME = "pine64,pinephone-1.2";
}; };
package = pkgs.sxmo-utils-latest.overrideAttrs (base: { package = pkgs.sxmo-utils.overrideAttrs (base: {
postPatch = (base.postPatch or "") + '' postPatch = (base.postPatch or "") + ''
# after volume-button navigation mode, restore full keyboard functionality # after volume-button navigation mode, restore full keyboard functionality
cp ${./xkb_mobile_normal_buttons} ./configs/xkb/xkb_mobile_normal_buttons cp ${./xkb_mobile_normal_buttons} ./configs/xkb/xkb_mobile_normal_buttons

View File

@@ -44,7 +44,6 @@
sane.programs.tuiApps.enableFor.user.colin = false; # visidata, others, don't compile well sane.programs.tuiApps.enableFor.user.colin = false; # visidata, others, don't compile well
# disabled for faster deploys # disabled for faster deploys
sane.programs.soundconverter.enableFor.user.colin = false; sane.programs.soundconverter.enableFor.user.colin = false;
sane.programs.eg25-control.enableFor.user.colin = true;
# sane.programs.firefox.mime.priority = 300; # prefer other browsers when possible # sane.programs.firefox.mime.priority = 300; # prefer other browsers when possible
# HACK/TODO: make `programs.P.env.VAR` behave according to `mime.priority` # HACK/TODO: make `programs.P.env.VAR` behave according to `mime.priority`
@@ -113,15 +112,6 @@
services.pipewire.environment.ALSA_CONFIG_UCM2 = ucm-env; services.pipewire.environment.ALSA_CONFIG_UCM2 = ucm-env;
services.pipewire-pulse.environment.ALSA_CONFIG_UCM2 = ucm-env; services.pipewire-pulse.environment.ALSA_CONFIG_UCM2 = ucm-env;
services.wireplumber.environment.ALSA_CONFIG_UCM2 = ucm-env; services.wireplumber.environment.ALSA_CONFIG_UCM2 = ucm-env;
# TODO: move elsewhere...
services.ModemManager.serviceConfig = {
# N.B.: the extra "" in ExecStart serves to force upstream ExecStart to be ignored
ExecStart = [ "" "${pkgs.modemmanager}/bin/ModemManager --debug" ];
# --debug sets DEBUG level logging: so reset
ExecStartPost = [ "${pkgs.modemmanager}/bin/mmcli --set-logging=INFO" ];
};
}; };
services.udev.extraRules = let services.udev.extraRules = let
@@ -137,4 +127,37 @@
''; '';
hardware.opengl.driSupport = true; hardware.opengl.driSupport = true;
services.xserver.displayManager.job.preStart = let
dmesg = "${pkgs.util-linux}/bin/dmesg";
grep = "${pkgs.gnugrep}/bin/grep";
modprobe = "${pkgs.kmod}/bin/modprobe";
in ''
# common boot failure:
# blank screen (no backlight even), with the following log:
# ```syslog
# sun8i-dw-hdmi 1ee0000.hdmi: Couldn't get the HDMI PHY
# ...
# sun4i-drm display-engine: Couldn't bind all pipelines components
# ...
# sun8i-dw-hdmi: probe of 1ee0000.hdmi failed with error -17
# ```
#
# in particular, that `probe ... failed` occurs *only* on failed boots
# (the other messages might sometimes occur even on successful runs?)
#
# reloading the sun8i hdmi driver usually gets the screen on, showing boot text.
# then restarting display-manager.service gets us to the login.
#
# NB: the above log is default level. though less specific, there's a `err` level message that also signals this:
# sun4i-drm display-engine: failed to bind 1ee0000.hdmi (ops sun8i_dw_hdmi_ops [sun8i_drm_hdmi]): -17
if (${dmesg} --kernel --level err --color=never --notime | ${grep} -q 'sun4i-drm display-engine: failed to bind 1ee0000.hdmi')
then
echo "reprobing sun8i_drm_hdmi"
# if a command here fails it errors the whole service, so prefer to log instead
${modprobe} -r sun8i_drm_hdmi || echo "failed to unload sun8i_drm_hdmi"
${modprobe} sun8i_drm_hdmi || echo "failed to load sub8i_drm_hdmi"
fi
'';
} }

View File

@@ -15,28 +15,10 @@
# #
# geoclue somehow fits in here as a geospatial provider that leverages GPS and also other sources like radio towers # geoclue somehow fits in here as a geospatial provider that leverages GPS and also other sources like radio towers
{ lib, ... }: { ... }:
{ {
# test gpsd with `gpspipe -w -n 10 2> /dev/null | grep -m 1 TPV | jq '.lat, .lon' | tr '\n' ' '`
# ^ should return <lat> <long>
services.gpsd.enable = true; services.gpsd.enable = true;
services.gpsd.devices = [ "/dev/ttyUSB1" ]; services.gpsd.devices = [ "/dev/ttyUSB1" ];
# test geoclue2 by building `geoclue2-with-demo-agent` # TODO: enable eg25-manager, and bring online both the modem and GPS on boot
# and running "${geoclue2-with-demo-agent}/libexec/geoclue-2/demos/where-am-i"
services.geoclue2.enable = true;
services.geoclue2.appConfig.where-am-i = {
# this is the default "agent", shipped by geoclue package: allow it to use location
isAllowed = true;
isSystem = false;
# XXX: setting users != [] might be causing `where-am-i` to time out
# users = [
# # restrict to only one set of users. empty array (default) means "allow any user to access geolocation".
# (builtins.toString config.users.users.colin.uid)
# ];
};
systemd.services.geoclue.after = lib.mkForce []; #< defaults to network-online, but not all my sources require network
sane.services.eg25-control.enable = true;
} }

View File

@@ -1,56 +1,71 @@
{ pkgs, ... }: { lib, pkgs, ... }:
let let
dmesg = "${pkgs.util-linux}/bin/dmesg"; # use the last commit on the 5.18 branch (5.18.14)
grep = "${pkgs.gnugrep}/bin/grep"; # manjaro's changes between kernel patch versions tend to be minimal if any.
modprobe = "${pkgs.kmod}/bin/modprobe"; manjaroBase = "https://gitlab.manjaro.org/manjaro-arm/packages/core/linux/-/raw/25bd828cd47b1c6e09fcbcf394a649b89d2876dd";
ensureHWReady = '' manjaroPatch = name: sha256: {
# common boot failure: inherit name;
# blank screen (no backlight even), with the following log: patch = pkgs.fetchpatch {
# ```syslog inherit name;
# sun8i-dw-hdmi 1ee0000.hdmi: Couldn't get the HDMI PHY url = "${manjaroBase}/${name}?inline=false";
# ... inherit sha256;
# sun4i-drm display-engine: Couldn't bind all pipelines components };
# ... };
# sun8i-dw-hdmi: probe of 1ee0000.hdmi failed with error -17
# ```
#
# in particular, that `probe ... failed` occurs *only* on failed boots
# (the other messages might sometimes occur even on successful runs?)
#
# reloading the sun8i hdmi driver usually gets the screen on, showing boot text.
# then restarting display-manager.service gets us to the login.
#
# NB: the above log is default level. though less specific, there's a `err` level message that also signals this:
# sun4i-drm display-engine: failed to bind 1ee0000.hdmi (ops sun8i_dw_hdmi_ops [sun8i_drm_hdmi]): -17
# NB: this is the most common, but not the only, failure mode for `display-manager`.
# another error seems characterized by these dmesg logs, in which reprobing sun8i_drm_hdmi does not fix:
# ```syslog
# sun6i-mipi-dsi 1ca0000.dsi: Couldn't get the MIPI D-PHY
# sun4i-drm display-engine: Couldn't bind all pipelines components
# sun6i-mipi-dsi 1ca0000.dsi: Couldn't register our component
# ```
if (${dmesg} --kernel --level err --color=never --notime | ${grep} -q 'sun4i-drm display-engine: failed to bind 1ee0000.hdmi') # the idea for patching off Manjaro's kernel comes from jakewaksbaum:
then # - https://git.sr.ht/~jakewaksbaum/pi/tree/af20aae5653545d6e67a459b59ee3e1ca8a680b0/item/kernel/default.nix
echo "reprobing sun8i_drm_hdmi" # - he later abandoned this, i think because he's using the Pinephone Pro which received mainline support.
# if a command here fails it errors the whole service, so prefer to log instead manjaroPatches = [
${modprobe} -r sun8i_drm_hdmi || echo "failed to unload sun8i_drm_hdmi" (manjaroPatch
${modprobe} sun8i_drm_hdmi || echo "failed to load sub8i_drm_hdmi" "1001-arm64-dts-allwinner-add-hdmi-sound-to-pine-devices.patch"
fi "sha256-DApd791A+AxB28Ven/MVAyuyVphdo8KQDx8O7oxVPnc="
''; )
# these patches below are critical to enable wifi (RTL8723CS)
# - the alternative is a wholly forked kernel by megi/megous:
# - https://xnux.eu/howtos/build-pinephone-kernel.html#toc-how-to-build-megi-s-pinehpone-kernel
# - i don't know if these patches are based on megi's or original
(manjaroPatch
"2001-Bluetooth-Add-new-quirk-for-broken-local-ext-features.patch"
"sha256-CExhJuUWivegxPdnzKINEsKrMFx/m/1kOZFmlZ2SEOc="
)
(manjaroPatch
"2002-Bluetooth-btrtl-add-support-for-the-RTL8723CS.patch"
"sha256-dDdvOphTcP/Aog93HyH+L9m55laTgtjndPSE4/rnzUA="
)
(manjaroPatch
"2004-arm64-dts-allwinner-enable-bluetooth-pinetab-pinepho.patch"
"sha256-o43P3WzXyHK1PF+Kdter4asuyGAEKO6wf5ixcco2kCQ="
)
# XXX: this one has a Makefile, which hardcodes /sbin/depmod:
# - drivers/staging/rtl8723cs/Makefile
# - not sure if this is problematic?
(manjaroPatch
"2005-staging-add-rtl8723cs-driver.patch"
"sha256-6ywm3dQQ5JYl60CLKarxlSUukwi4QzqctCj3tVgzFbo="
)
];
in in
{ {
# use Megi's kernel:
# even with the Manjaro patches, stock 5.18 has a few issues on Pinephone:
# - no battery charging
# - phone rotation sensor is off by 90 degrees
# - ambient light sensor causes screen brightness to be shakey
# - phosh greeter may not appear after wake from sleep
boot.kernelPackages = pkgs.linuxPackagesFor pkgs.linux-megous; boot.kernelPackages = pkgs.linuxPackagesFor pkgs.linux-megous;
# boot.kernelPackages = pkgs.linuxPackagesFor pkgs.linux-manjaro;
# boot.kernelPackages = pkgs.linuxPackagesFor pkgs.linux_latest;
# alternatively, apply patches directly to stock nixos kernel: # alternatively, use nixos' kernel and add the stuff we want:
# # cross-compilation optimization:
# boot.kernelPackages =
# let p = (import nixpkgs { localSystem = "x86_64-linux"; });
# in p.pkgsCross.aarch64-multiplatform.linuxPackages_5_18;
# # non-cross:
# # boot.kernelPackages = pkgs.linuxPackages_5_18;
# boot.kernelPatches = manjaroPatches ++ [ # boot.kernelPatches = manjaroPatches ++ [
# (patchDefconfig kernelConfig) # (patchDefconfig kernelConfig)
# ]; # ];
# configure nixos to build a compressed kernel image, since it doesn't usually do that for aarch64 target.
# without this i run out of /boot space in < 10 generations
nixpkgs.hostPlatform.linux-kernel = { nixpkgs.hostPlatform.linux-kernel = {
# defaults: # defaults:
name = "aarch64-multiplatform"; name = "aarch64-multiplatform";
@@ -65,7 +80,4 @@ in
target = "Image.gz"; # <-- compress the kernel image target = "Image.gz"; # <-- compress the kernel image
# target = "zImage"; # <-- confuses other parts of nixos :-( # target = "zImage"; # <-- confuses other parts of nixos :-(
}; };
services.xserver.displayManager.job.preStart = ensureHWReady;
systemd.services.greetd.preStart = ensureHWReady;
} }

View File

@@ -167,7 +167,7 @@ in
WVKBD_LANDSCAPE_LAYERS = "landscape,special,emoji"; WVKBD_LANDSCAPE_LAYERS = "landscape,special,emoji";
WVKBD_LAYERS = "full,special,emoji"; WVKBD_LAYERS = "full,special,emoji";
}; };
package = pkgs.sxmo-utils-latest.overrideAttrs (base: { package = pkgs.sxmo-utils.overrideAttrs (base: {
postPatch = (base.postPatch or "") + '' postPatch = (base.postPatch or "") + ''
cat <<EOF >> ./configs/default_hooks/sxmo_hook_start.sh cat <<EOF >> ./configs/default_hooks/sxmo_hook_start.sh
# rotate UI based on physical display angle by default # rotate UI based on physical display angle by default

View File

@@ -2,9 +2,6 @@
{ {
sane.persist.root-on-tmpfs = true; sane.persist.root-on-tmpfs = true;
# increase /tmp space (defaults to 50% of RAM) for building large nix things.
# even the stock `nixpkgs.linux` consumes > 16 GB of tmp
fileSystems."/tmp".options = [ "size=32G" ];
fileSystems."/nix" = { fileSystems."/nix" = {
device = "/dev/disk/by-uuid/cc81cca0-3cc7-4d82-a00c-6243af3e7776"; device = "/dev/disk/by-uuid/cc81cca0-3cc7-4d82-a00c-6243af3e7776";

View File

@@ -7,7 +7,7 @@
./email ./email
./ejabberd.nix ./ejabberd.nix
./freshrss.nix ./freshrss.nix
./export ./ftp
./gitea.nix ./gitea.nix
./goaccess.nix ./goaccess.nix
./ipfs.nix ./ipfs.nix
@@ -18,6 +18,7 @@
./lemmy.nix ./lemmy.nix
./matrix ./matrix
./navidrome.nix ./navidrome.nix
./nfs.nix
./nixserve.nix ./nixserve.nix
./nginx.nix ./nginx.nix
./pict-rs.nix ./pict-rs.nix

View File

@@ -17,86 +17,73 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
# XXX: avatar support works in MUCs but not DMs # XXX: avatar support works in MUCs but not DMs
let # lib.mkIf false
# TODO: this range could be larger, but right now that's costly because each element is its own UPnP forward
# TURN port range (inclusive)
turnPortLow = 49152;
turnPortHigh = 49167;
turnPortRange = lib.range turnPortLow turnPortHigh;
in
{ {
sane.persist.sys.plaintext = [ sane.persist.sys.plaintext = [
{ user = "ejabberd"; group = "ejabberd"; path = "/var/lib/ejabberd"; } { user = "ejabberd"; group = "ejabberd"; path = "/var/lib/ejabberd"; }
]; ];
sane.ports.ports = lib.mkMerge ([ sane.ports.ports."3478" = {
{
"3478" = {
protocol = [ "tcp" "udp" ]; protocol = [ "tcp" "udp" ];
visibleTo.lan = true; visibleTo.lan = true;
visibleTo.wan = true; visibleTo.wan = true;
description = "colin-xmpp-stun-turn"; description = "colin-xmpp-stun-turn";
}; };
"5222" = { sane.ports.ports."5222" = {
protocol = [ "tcp" ]; protocol = [ "tcp" ];
visibleTo.lan = true; visibleTo.lan = true;
visibleTo.wan = true; visibleTo.wan = true;
description = "colin-xmpp-client-to-server"; description = "colin-xmpp-client-to-server";
}; };
"5223" = { sane.ports.ports."5223" = {
protocol = [ "tcp" ]; protocol = [ "tcp" ];
visibleTo.lan = true; visibleTo.lan = true;
visibleTo.wan = true; visibleTo.wan = true;
description = "colin-xmpps-client-to-server"; # XMPP over TLS description = "colin-xmpps-client-to-server"; # XMPP over TLS
}; };
"5269" = { sane.ports.ports."5269" = {
protocol = [ "tcp" ]; protocol = [ "tcp" ];
visibleTo.wan = true; visibleTo.wan = true;
description = "colin-xmpp-server-to-server"; description = "colin-xmpp-server-to-server";
}; };
"5270" = { sane.ports.ports."5270" = {
protocol = [ "tcp" ]; protocol = [ "tcp" ];
visibleTo.wan = true; visibleTo.wan = true;
description = "colin-xmpps-server-to-server"; # XMPP over TLS description = "colin-xmpps-server-to-server"; # XMPP over TLS
}; };
"5280" = { sane.ports.ports."5280" = {
protocol = [ "tcp" ]; protocol = [ "tcp" ];
visibleTo.lan = true; visibleTo.lan = true;
visibleTo.wan = true; visibleTo.wan = true;
description = "colin-xmpp-bosh"; description = "colin-xmpp-bosh";
}; };
"5281" = { sane.ports.ports."5281" = {
protocol = [ "tcp" ]; protocol = [ "tcp" ];
visibleTo.lan = true; visibleTo.lan = true;
visibleTo.wan = true; visibleTo.wan = true;
description = "colin-xmpp-bosh-https"; description = "colin-xmpp-bosh-https";
}; };
"5349" = { sane.ports.ports."5349" = {
protocol = [ "tcp" ]; protocol = [ "tcp" ];
visibleTo.lan = true; visibleTo.lan = true;
visibleTo.wan = true; visibleTo.wan = true;
description = "colin-xmpp-stun-turn-over-tls"; description = "colin-xmpp-stun-turn-over-tls";
}; };
"5443" = { sane.ports.ports."5443" = {
protocol = [ "tcp" ]; protocol = [ "tcp" ];
visibleTo.lan = true; visibleTo.lan = true;
visibleTo.wan = true; visibleTo.wan = true;
description = "colin-xmpp-web-services"; # file uploads, websockets, admin description = "colin-xmpp-web-services"; # file uploads, websockets, admin
}; };
}
] ++ (builtins.map # TODO: forward these TURN ports!
(port: { networking.firewall.allowedTCPPortRanges = [{
"${builtins.toString port}" = let from = 49152; # TURN
count = port - turnPortLow + 1; to = 49408;
numPorts = turnPortHigh - turnPortLow + 1; }];
in { networking.firewall.allowedUDPPortRanges = [{
protocol = [ "tcp" "udp" ]; from = 49152; # TURN
visibleTo.lan = true; to = 49408;
visibleTo.wan = true; }];
description = "colin-xmpp-turn-${builtins.toString count}-of-${builtins.toString numPorts}";
};
})
turnPortRange
));
# provide access to certs # provide access to certs
# TODO: this should just be `acme`. then we also add nginx to the `acme` group. # TODO: this should just be `acme`. then we also add nginx to the `acme` group.
@@ -285,8 +272,8 @@ in
module: ejabberd_stun module: ejabberd_stun
transport: tcp transport: tcp
use_turn: true use_turn: true
turn_min_port: ${builtins.toString turnPortLow} turn_min_port: 49152
turn_max_port: ${builtins.toString turnPortHigh} turn_max_port: 65535
turn_ipv4_address: %ANATIVE% turn_ipv4_address: %ANATIVE%
- -
# STUN+TURN UDP # STUN+TURN UDP
@@ -294,8 +281,8 @@ in
module: ejabberd_stun module: ejabberd_stun
transport: udp transport: udp
use_turn: true use_turn: true
turn_min_port: ${builtins.toString turnPortLow} turn_min_port: 49152
turn_max_port: ${builtins.toString turnPortHigh} turn_max_port: 65535
turn_ipv4_address: %ANATIVE% turn_ipv4_address: %ANATIVE%
- -
# STUN+TURN TLS over TCP # STUN+TURN TLS over TCP
@@ -305,8 +292,8 @@ in
tls: true tls: true
certfile: /var/lib/acme/uninsane.org/full.pem certfile: /var/lib/acme/uninsane.org/full.pem
use_turn: true use_turn: true
turn_min_port: ${builtins.toString turnPortLow} turn_min_port: 49152
turn_max_port: ${builtins.toString turnPortHigh} turn_max_port: 65535
turn_ipv4_address: %ANATIVE% turn_ipv4_address: %ANATIVE%
# TODO: enable mod_fail2ban # TODO: enable mod_fail2ban

View File

@@ -1,42 +0,0 @@
{ config, ... }:
{
imports = [
./nfs.nix
./sftpgo.nix
];
fileSystems."/var/export/media" = {
# everything in here could be considered publicly readable (based on the viewer's legal jurisdiction)
device = "/var/lib/uninsane/media";
options = [ "rbind" ];
};
fileSystems."/var/export/playground" = {
device = config.fileSystems."/mnt/persist/ext".device;
fsType = "btrfs";
options = [
"subvol=export-playground"
"compress=zstd"
"defaults"
];
};
sane.fs."/var/export/README.md" = {
wantedBy = [ "nfs.service" "sftpgo.service" ];
file.text = ''
- media/ read-only: Videos, Music, Books, etc
- playground/ read-write: use it to share files with other users of this server
'';
};
# sane.fs."/var/lib/sftpgo/export/playground/README.md" = {
# wantedBy = [ "nfs.service" "sftpgo.service" ];
# file.text = ''
# this directory is intentionally read+write by anyone.
# there are no rules, except a server-level quota:
# - share files
# - write poetry
# - be a friendly troll
# '';
# };
}

View File

@@ -1,193 +0,0 @@
# docs:
# - <https://github.com/drakkan/sftpgo>
# - config options: <https://github.com/drakkan/sftpgo/blob/main/docs/full-configuration.md>
# - config defaults: <https://github.com/drakkan/sftpgo/blob/main/sftpgo.json>
# - nixos options: <repo:nixos/nixpkgs:nixos/modules/services/web-apps/sftpgo.nix>
# - nixos example: <repo:nixos/nixpkgs:nixos/tests/sftpgo.nix>
#
# sftpgo is a FTP server that also supports WebDAV, SFTP, and web clients.
#
# TODO: change umask so sftpgo-created files default to 644.
# - it does indeed appear that the 600 is not something sftpgo is explicitly doing.
#
# TODO: enforce a "quota" by placing /playground on a btrfs subvolume
# - sane.persist API could expose a `subvolume` option to make this feel natural
{ config, lib, pkgs, sane-lib, ... }:
let
# user permissions:
# - see <repo:drakkan/sftpgo:internal/dataprovider/user.go>
# - "*" = grant all permissions
# - read-only perms:
# - "list" = list files and directories
# - "download"
# - rw perms:
# - "upload"
# - "overwrite" = allow uploads to replace existing files
# - "delete" = delete files and directories
# - "delete_files"
# - "delete_dirs"
# - "rename" = rename files and directories
# - "rename_files"
# - "rename_dirs"
# - "create_dirs"
# - "create_symlinks"
# - "chmod"
# - "chown"
# - "chtimes" = change atime/mtime (access and modification times)
#
# home_dir:
# - it seems (empirically) that a user can't cd above their home directory.
# though i don't have a reference for that in the docs.
authResponseSuccess = {
status = 1;
username = "anonymous";
expiration_date = 0;
home_dir = "/var/export";
# uid/gid 0 means to inherit sftpgo uid.
# - i.e. users can't read files which Linux user `sftpgo` can't read
# - uploaded files belong to Linux user `sftpgo`
# other uid/gid values aren't possible for localfs backend, unless i let sftpgo use `sudo`.
uid = 0;
gid = 0;
# uid = 65534;
# gid = 65534;
max_sessions = 0;
# quota_*: 0 means to not use SFTP's quota system
quota_size = 0;
quota_files = 0;
permissions = {
"/" = [ "list" "download" ];
"/playground" = [
# read-only:
"list"
"download"
# write:
"upload"
"overwrite"
"delete"
"rename"
"create_dirs"
"create_symlinks"
# intentionally omitted:
# "chmod"
# "chown"
# "chtimes"
];
};
upload_bandwidth = 0;
download_bandwidth = 0;
filters = {
allowed_ip = [];
denied_ip = [];
};
public_keys = [];
# other fields:
# ? groups
# ? virtual_folders
};
authResponseFail = {
username = "";
};
authSuccessJson = pkgs.writeText "sftp-auth-success.json" (builtins.toJSON authResponseSuccess);
authFailJson = pkgs.writeText "sftp-auth-fail.json" (builtins.toJSON authResponseFail);
unwrappedAuthProgram = pkgs.static-nix-shell.mkBash {
pname = "sftpgo_external_auth_hook";
src = ./.;
pkgs = [ "coreutils" ];
};
authProgram = pkgs.writeShellScript "sftpgo-auth-hook" ''
${unwrappedAuthProgram}/bin/sftpgo_external_auth_hook ${authFailJson} ${authSuccessJson}
'';
in
{
# Client initiates a FTP "control connection" on port 21.
# - this handles the client -> server commands, and the server -> client status, but not the actual data
# - file data, directory listings, etc need to be transferred on an ephemeral "data port".
# - 50000-50100 is a common port range for this.
sane.ports.ports = {
"21" = {
protocol = [ "tcp" ];
visibleTo.lan = true;
description = "colin-FTP server";
};
} // (sane-lib.mapToAttrs
(port: {
name = builtins.toString port;
value = {
protocol = [ "tcp" ];
visibleTo.lan = true;
description = "colin-FTP server data port range";
};
})
(lib.range 50000 50100)
);
services.sftpgo = {
enable = true;
settings = {
ftpd = {
bindings = [
{
# binding this means any wireguard client can connect
address = "10.0.10.5";
port = 21;
debug = true;
}
{
# binding this means any LAN client can connect
address = "10.78.79.51";
port = 21;
debug = true;
}
];
# active mode is susceptible to "bounce attacks", without much benefit over passive mode
disable_active_mode = true;
hash_support = true;
passive_port_range = {
start = 50000;
end = 50100;
};
banner = ''
Welcome, friends, to Colin's read-only FTP server! Also available via NFS on the same host.
Username: "anonymous"
Password: "anonymous"
CONFIGURE YOUR CLIENT FOR "PASSIVE" mode, e.g. `ftp --passive uninsane.org`
Please let me know if anything's broken or not as it should be. Otherwise, browse and DL freely :)
'';
};
data_provider = {
driver = "memory";
external_auth_hook = "${authProgram}";
# track_quota:
# - 0: disable quota tracking
# - 1: quota is updated on every upload/delete, even if user has no quota restriction
# - 2: quota is updated on every upload/delete, but only if user/folder has a quota restriction (default, i think)
# track_quota = 2;
};
};
};
# fileSystems."/var/lib/sftpgo/export/media" = {
# # everything in here could be considered publicly readable (based on the viewer's legal jurisdiction)
# device = "/var/lib/uninsane/media";
# options = [ "rbind" ];
# };
# sane.persist.sys.plaintext = [
# { user = "sftpgo"; group = "sftpgo"; path = "/var/lib/sftpgo/export/playground"; }
# ];
# sane.fs."/var/lib/sftpgo/export/playground/README.md" = {
# wantedBy = [ "sftpgo.service" ];
# file.text = ''
# this directory is intentionally read+write by anyone.
# there are no rules, except a server-level quota:
# - share files
# - write poetry
# - be a friendly troll
# '';
# };
}

View File

@@ -1,23 +0,0 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p coreutils
# vim: set filetype=bash :
#
# available environment variables:
# - SFTPGO_AUTHD_USERNAME
# - SFTPGO_AUTHD_USER
# - SFTPGO_AUTHD_IP
# - SFTPGO_AUTHD_PROTOCOL = { "DAV", "FTP", "HTTP", "SSH" }
# - SFTPGO_AUTHD_PASSWORD
# - SFTPGO_AUTHD_PUBLIC_KEY
# - SFTPGO_AUTHD_KEYBOARD_INTERACTIVE
# - SFTPGO_AUTHD_TLS_CERT
#
#
# call with <script_name> /path/to/fail/response.json /path/to/success/response.json
if [ "$SFTPGO_AUTHD_USERNAME" = "anonymous" ]; then
cat "$2"
else
cat "$1"
fi

View File

@@ -0,0 +1,70 @@
# docs:
# - <https://github.com/drakkan/sftpgo>
# - config options: <https://github.com/drakkan/sftpgo/blob/main/docs/full-configuration.md>
# - config defaults: <https://github.com/drakkan/sftpgo/blob/main/sftpgo.json>
# - nixos options: <repo:nixos/nixpkgs:nixos/modules/services/web-apps/sftpgo.nix>
#
# sftpgo is a FTP server that also supports WebDAV, SFTP, and web clients.
{ lib, pkgs, sane-lib, ... }:
let
authProgram = pkgs.static-nix-shell.mkBash {
pname = "sftpgo_external_auth_hook";
src = ./.;
};
in
{
# Client initiates a FTP "control connection" on port 21.
# - this handles the client -> server commands, and the server -> client status, but not the actual data
# - file data, directory listings, etc need to be transferred on an ephemeral "data port".
# - 50000-50100 is a common port range for this.
sane.ports.ports = {
"21" = {
protocol = [ "tcp" ];
visibleTo.lan = true;
description = "colin-FTP server";
};
} // (sane-lib.mapToAttrs
(port: {
name = builtins.toString port;
value = {
protocol = [ "tcp" ];
visibleTo.lan = true;
description = "colin-FTP server data port range";
};
})
(lib.range 50000 50100)
);
services.sftpgo = {
enable = true;
settings = {
ftpd = {
bindings = [{
address = "10.0.10.5";
port = 21;
debug = true;
}];
# active mode is susceptible to "bounce attacks", without much benefit over passive mode
disable_active_mode = true;
hash_support = true;
passive_port_range = {
start = 50000;
end = 50100;
};
banner = ''
Welcome, friends, to Colin's read-only FTP server! Also available via NFS on the same host.
Please let me know if anything's broken or not as it should be. Otherwise, browse and DL freely :)
'';
};
data_provider = {
driver = "memory";
external_auth_hook = "${authProgram}/bin/sftpgo_external_auth_hook";
};
};
};
}

View File

@@ -0,0 +1,55 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash
# vim: set filetype=bash :
#
# available environment variables:
# - SFTPGO_AUTHD_USERNAME
# - SFTPGO_AUTHD_USER
# - SFTPGO_AUTHD_IP
# - SFTPGO_AUTHD_PROTOCOL = { "DAV", "FTP", "HTTP", "SSH" }
# - SFTPGO_AUTHD_PASSWORD
# - SFTPGO_AUTHD_PUBLIC_KEY
# - SFTPGO_AUTHD_KEYBOARD_INTERACTIVE
# - SFTPGO_AUTHD_TLS_CERT
#
# user permissions:
# - see <repo:drakkan/sftpgo:internal/dataprovider/user.go>
# - "*" = grant all permissions
# - read-only perms:
# - "list" = list files and directories
# - "download"
# - rw perms:
# - "upload"
# - "overwrite" = allow uploads to replace existing files
# - "delete" = delete files and directories
# - "delete_files"
# - "delete_dirs"
# - "rename" = rename files and directories
# - "rename_files"
# - "rename_dirs"
# - "create_dirs"
# - "create_symlinks"
# - "chmod"
# - "chown"
# - "chtimes" = change atime/mtime (access and modification times)
#
# home_dir:
# - it seems (empirically) that a user can't cd above their home directory.
# though i don't have a reference for that in the docs.
# TODO: don't reuse /var/nfs/export here. formalize this some other way.
if [ "$SFTPGO_AUTHD_USERNAME" = "anonymous" ]; then
echo '{'
echo ' "status":1,'
echo ' "username":"anonymous","expiration_date":0,'
echo ' "home_dir":"/var/nfs/export","uid":65534,"gid":65534,"max_sessions":0,"quota_size":0,"quota_files":100000,'
echo ' "permissions":{'
echo ' "/":["list", "download"]'
echo ' },'
echo ' "upload_bandwidth":0,"download_bandwidth":0,'
echo ' "filters":{"allowed_ip":[],"denied_ip":[]},"public_keys":[]'
echo '}'
else
echo '{"username":""}'
fi

View File

@@ -3,23 +3,13 @@
# - <repo:LemmyNet/lemmy:docker/nginx.conf> # - <repo:LemmyNet/lemmy:docker/nginx.conf>
# - <repo:LemmyNet/lemmy-ansible:templates/nginx.conf> # - <repo:LemmyNet/lemmy-ansible:templates/nginx.conf>
{ config, lib, pkgs, ... }: { config, lib, ... }:
let let
inherit (builtins) toString; inherit (builtins) toString;
inherit (lib) mkForce; inherit (lib) mkForce;
uiPort = 1234; # default ui port is 1234 uiPort = 1234; # default ui port is 1234
backendPort = 8536; # default backend port is 8536 backendPort = 8536; # default backend port is 8536
#^ i guess the "backend" port is used for federation? # - i guess the "backend" port is used for federation?
pict-rs = pkgs.pict-rs.overrideAttrs (upstream: {
# as of v 0.4.2, all non-GIF video is forcibly transcoded.
# that breaks lemmy, because of the request latency.
# and it eats up hella CPU.
# pict-rs is iffy around video altogether: mp4 seems the best supported.
postPatch = (upstream.postPatch or "") + ''
substituteInPlace src/validate.rs \
--replace 'if transcode_options.needs_reencode() {' 'if false {'
'';
});
in { in {
services.lemmy = { services.lemmy = {
enable = true; enable = true;
@@ -66,20 +56,4 @@ in {
}; };
sane.dns.zones."uninsane.org".inet.CNAME."lemmy" = "native"; sane.dns.zones."uninsane.org".inet.CNAME."lemmy" = "native";
#v DO NOT REMOVE: defaults to 0.3, instead of latest, so always need to explicitly set this.
services.pict-rs.package = pict-rs;
# pict-rs configuration is applied in this order:
# - via toml
# - via env vars (overrides everything above)
# - via CLI flags (overrides everything above)
# some of the CLI flags have defaults, making it the only actual way to configure certain things even when docs claim otherwise.
# CLI args: <https://git.asonix.dog/asonix/pict-rs#user-content-running>
systemd.services.pict-rs.serviceConfig.ExecStart = lib.mkForce (lib.concatStringsSep " " [
"${lib.getBin pict-rs}/bin/pict-rs run"
"--media-max-frame-count" (builtins.toString (30*60*60))
"--media-process-timeout 120"
"--media-enable-full-video true" # allow audio
]);
} }

View File

@@ -56,6 +56,12 @@
# #
# 10.0.0.0/8 to export (readonly) both to LAN (unencrypted) and wg vpn (encrypted) # 10.0.0.0/8 to export (readonly) both to LAN (unencrypted) and wg vpn (encrypted)
services.nfs.server.exports = '' services.nfs.server.exports = ''
/var/export 10.78.79.0/22(ro,crossmnt,fsid=0,subtree_check) 10.0.10.0/24(rw,no_root_squash,crossmnt,fsid=0,subtree_check) /var/nfs/export 10.78.79.0/22(ro,crossmnt,fsid=0,subtree_check) 10.0.10.0/24(rw,no_root_squash,crossmnt,fsid=0,subtree_check)
''; '';
fileSystems."/var/nfs/export/media" = {
# everything in here could be considered publicly readable (based on the viewer's legal jurisdiction)
device = "/var/lib/uninsane/media";
options = [ "rbind" ];
};
} }

View File

@@ -63,7 +63,6 @@ in
database: "pleroma", database: "pleroma",
hostname: "localhost", hostname: "localhost",
pool_size: 10, pool_size: 10,
prepare: :named,
parameters: [ parameters: [
plan_cache_mode: "force_custom_plan" plan_cache_mode: "force_custom_plan"
] ]

View File

@@ -1,39 +1,12 @@
{ pkgs, ... }: { ... }:
let
GiB = n: MiB 1024*n;
MiB = n: KiB 1024*n;
KiB = n: 1024*n;
in
{ {
sane.persist.sys.plaintext = [ sane.persist.sys.plaintext = [
# TODO: mode? # TODO: mode?
{ user = "postgres"; group = "postgres"; path = "/var/lib/postgresql"; } { user = "postgres"; group = "postgres"; path = "/var/lib/postgresql"; }
]; ];
services.postgresql.enable = true; services.postgresql.enable = true;
# services.postgresql.dataDir = "/opt/postgresql/13";
# HOW TO UPDATE:
# postgres version updates are manual and require intervention.
# - `sane-stop-all-servo`
# - `systemctl start postgresql`
# - as `sudo su postgres`:
# - `cd /var/log/postgresql`
# - `pg_dumpall > state.sql`
# - `echo placeholder > <new_version>` # to prevent state from being created earlier than we want
# - then, atomically:
# - update the `services.postgresql.package` here
# - `dataDir` is atomically updated to match package; don't touch
# - `nixos-rebuild --flake . switch ; sane-stop-all-servo`
# - `sudo rm -rf /var/lib/postgresql/<new_version>`
# - `systemctl start postgresql`
# - as `sudo su postgres`:
# - `cd /var/lib/postgreql`
# - `psql -f state.sql`
# - restart dependent services (maybe test one at a time)
services.postgresql.package = pkgs.postgresql_15;
# XXX colin: for a proper deploy, we'd want to include something for Pleroma here too. # XXX colin: for a proper deploy, we'd want to include something for Pleroma here too.
# services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" '' # services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" ''
# CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD '<password goes here>'; # CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD '<password goes here>';
@@ -44,33 +17,10 @@ in
# LC_CTYPE = "C"; # LC_CTYPE = "C";
# ''; # '';
# perf tuning # TODO: perf tuning
# - for recommended values see: <https://pgtune.leopard.in.ua/> # - for recommended values see: <https://pgtune.leopard.in.ua/>
# - for official docs (sparse), see: <https://www.postgresql.org/docs/11/config-setting.html#CONFIG-SETTING-CONFIGURATION-FILE> # - for official docs (sparse), see: <https://www.postgresql.org/docs/11/config-setting.html#CONFIG-SETTING-CONFIGURATION-FILE>
services.postgresql.settings = { # services.postgresql.settings = { ... }
# DB Version: 15
# OS Type: linux
# DB Type: web
# Total Memory (RAM): 32 GB
# CPUs num: 12
# Data Storage: ssd
max_connections = 200;
shared_buffers = "8GB";
effective_cache_size = "24GB";
maintenance_work_mem = "2GB";
checkpoint_completion_target = 0.9;
wal_buffers = "16MB";
default_statistics_target = 100;
random_page_cost = 1.1;
effective_io_concurrency = 200;
work_mem = "10485kB";
min_wal_size = "1GB";
max_wal_size = "4GB";
max_worker_processes = 12;
max_parallel_workers_per_gather = 4;
max_parallel_workers = 12;
max_parallel_maintenance_workers = 4;
};
# daily backups to /var/backup # daily backups to /var/backup
services.postgresqlBackup.enable = true; services.postgresqlBackup.enable = true;

View File

@@ -1,5 +1,4 @@
# where to find good stuff? # where to find good stuff?
# - podcasts w/ a community: <https://lemmyverse.net/communities?query=podcast>
# - podcast rec thread: <https://lemmy.ml/post/1565858> # - podcast rec thread: <https://lemmy.ml/post/1565858>
# #
# candidates: # candidates:
@@ -68,12 +67,7 @@ let
(fromDb "craphound.com" // pol) (fromDb "craphound.com" // pol)
## Maggie Killjoy -- referenced by Cory Doctorow ## Maggie Killjoy -- referenced by Cory Doctorow
(fromDb "omny.fm/shows/cool-people-who-did-cool-stuff" // pol) (fromDb "omny.fm/shows/cool-people-who-did-cool-stuff" // pol)
## also Maggie Killjoy
(fromDb "feeds.megaphone.fm/behindthebastards" // pol)
## Jennifer Briney
(fromDb "congressionaldish.libsyn.com" // pol) (fromDb "congressionaldish.libsyn.com" // pol)
(fromDb "werenotwrong.fireside.fm" // pol)
(fromDb "usefulidiots.substack.com" // pol)
# (mkPod "https://podcasts.la.utexas.edu/this-is-democracy/feed/podcast/" // pol // weekly) # (mkPod "https://podcasts.la.utexas.edu/this-is-democracy/feed/podcast/" // pol // weekly)
## Civboot -- https://anchor.fm/civboot ## Civboot -- https://anchor.fm/civboot
(fromDb "anchor.fm/s/34c7232c/podcast/rss" // tech) (fromDb "anchor.fm/s/34c7232c/podcast/rss" // tech)
@@ -131,10 +125,6 @@ let
(fromDb "feeds.simplecast.com/82FI35Px" // pol) (fromDb "feeds.simplecast.com/82FI35Px" // pol)
## Wireshark Podcast o_0 ## Wireshark Podcast o_0
(fromDb "sharkbytes.transistor.fm" // tech) (fromDb "sharkbytes.transistor.fm" // tech)
## 3/4 German; 1/4 eps are English
(fromDb "omegataupodcast.net" // tech)
## Lateral with Tom Scott
(mkPod "https://audioboom.com/channels/5097784.rss" // tech)
]; ];
texts = [ texts = [

View File

@@ -1,10 +1,9 @@
# docs # docs
# - x-systemd options: <https://www.freedesktop.org/software/systemd/man/systemd.mount.html> # - x-systemd options: <https://www.freedesktop.org/software/systemd/man/systemd.mount.html>
{ lib, pkgs, sane-lib, ... }: { pkgs, sane-lib, ... }:
let let fsOpts = rec {
fsOpts = rec {
common = [ common = [
"_netdev" "_netdev"
"noatime" "noatime"
@@ -56,17 +55,7 @@ let
"nofail" # don't fail remote-fs.target when this mount fails (not an option for sshfs else would be common) "nofail" # don't fail remote-fs.target when this mount fails (not an option for sshfs else would be common)
]; ];
}; };
remoteHome = host: {
fileSystems."/mnt/${host}-home" = {
device = "colin@${host}:/home/colin";
fsType = "fuse.sshfs";
options = fsOpts.sshColin ++ fsOpts.noauto;
noCheck = true;
};
sane.fs."/mnt/${host}-home" = sane-lib.fs.wantedDir;
};
in in
lib.mkMerge [
{ {
# some services which use private directories error if the parent (/var/lib/private) isn't 700. # some services which use private directories error if the parent (/var/lib/private) isn't 700.
sane.fs."/var/lib/private".dir.acl.mode = "0700"; sane.fs."/var/lib/private".dir.acl.mode = "0700";
@@ -119,6 +108,21 @@ lib.mkMerge [
# }; # };
sane.fs."/mnt/servo-media" = sane-lib.fs.wantedSymlinkTo "/mnt/servo-nfs/media"; sane.fs."/mnt/servo-media" = sane-lib.fs.wantedSymlinkTo "/mnt/servo-nfs/media";
fileSystems."/mnt/desko-home" = {
device = "colin@desko:/home/colin";
fsType = "fuse.sshfs";
options = fsOpts.sshColin ++ fsOpts.noauto;
noCheck = true;
};
sane.fs."/mnt/desko-home" = sane-lib.fs.wantedDir;
fileSystems."/mnt/desko-root" = {
device = "colin@desko:/";
fsType = "fuse.sshfs";
options = fsOpts.sshRoot ++ fsOpts.noauto;
noCheck = true;
};
sane.fs."/mnt/desko-root" = sane-lib.fs.wantedDir;
environment.pathsToLink = [ environment.pathsToLink = [
# needed to achieve superuser access for user-mounted filesystems (see optionsRoot above) # needed to achieve superuser access for user-mounted filesystems (see optionsRoot above)
# we can only link whole directories here, even though we're only interested in pkgs.openssh # we can only link whole directories here, even though we're only interested in pkgs.openssh
@@ -130,8 +134,3 @@ lib.mkMerge [
]; ];
} }
(remoteHome "desko")
(remoteHome "lappy")
(remoteHome "moby")
]

View File

@@ -1,24 +0,0 @@
# alacritty terminal emulator
# - config options: <https://github.com/alacritty/alacritty/blob/master/extra/man/alacritty.5.scd>
# - `man 5 alacritty`
# - defaults: <https://github.com/alacritty/alacritty/releases> -> alacritty.yml
# - irc: #alacritty on libera.chat
{ lib, ... }:
{
sane.programs.alacritty = {
env.TERMINAL = lib.mkDefault "alacritty";
# note: alacritty will switch to .toml config in 13.0 release
# - run `alacritty migrate` to convert the yaml to toml
fs.".config/alacritty/alacritty.yml".symlink.text = ''
font:
size: 14
key_bindings:
- { key: N, mods: Control, action: CreateNewWindow }
- { key: PageUp, mods: Control, action: ScrollPageUp }
- { key: PageDown, mods: Control, action: ScrollPageDown }
- { key: PageUp, mods: Control|Shift, action: ScrollPageUp }
- { key: PageDown, mods: Control|Shift, action: ScrollPageDown }
'';
};
}

View File

@@ -51,7 +51,6 @@ in
]; ];
"sane-scripts.sys-utils" = declPackageSet [ "sane-scripts.sys-utils" = declPackageSet [
"sane-scripts.ip-port-forward" "sane-scripts.ip-port-forward"
"sane-scripts.sync-music"
]; ];
@@ -127,7 +126,7 @@ in
# "gopass" # "gopass"
# "gopass-jsonapi" # "gopass-jsonapi"
"helix" # text editor "helix" # text editor
# "kitty" # XXX needs to be in consolueUtils because `ssh servo` from kitty sets `TERM=xterm-kitty` in the remote and breaks things "kitty" # TODO: move to GUI, but `ssh servo` from kitty sets `TERM=xterm-kitty` in the remove and breaks things
"libsecret" # for managing user keyrings. TODO: what needs this? lift into the consumer "libsecret" # for managing user keyrings. TODO: what needs this? lift into the consumer
"lm_sensors" # for sensors-detect. TODO: what needs this? lift into the consumer "lm_sensors" # for sensors-detect. TODO: what needs this? lift into the consumer
"lshw" "lshw"
@@ -201,6 +200,8 @@ in
# INDIVIDUAL PACKAGE DEFINITIONS # INDIVIDUAL PACKAGE DEFINITIONS
dino.persist.private = [ ".local/share/dino" ];
# creds, but also 200 MB of node modules, etc # creds, but also 200 MB of node modules, etc
discord.persist.private = [ ".config/discord" ]; discord.persist.private = [ ".config/discord" ];

View File

@@ -1,36 +0,0 @@
# cantata is a mpd frontend.
# before launching it, run `mopidy` in some tab
# TODO: auto-launch mopidy when cantata launches?
{ ... }:
{
sane.programs.cantata = {
persist.plaintext = [
".cache/cantata" # album art
".local/share/cantata/library" # library index (?)
];
fs.".config/cantata/cantata.conf".symlink.text = ''
[General]
fetchCovers=true
storeCoversInMpdDir=false
version=2.5.0
[Connection]
allowLocalStreaming=true
applyReplayGain=true
autoUpdate=false
dir=~/Music
host=localhost
partition=
passwd=
port=6600
replayGain=off
streamUrl=
[LibraryPage]
artist\gridZoom=100
artist\searchActive=false
artist\viewMode=detailedtree
'';
suggestedPrograms = [ "mopidy" ];
};
}

View File

@@ -38,9 +38,7 @@ in
suggestedPrograms = [ "gnome-keyring" ]; suggestedPrograms = [ "gnome-keyring" ];
persist.private = [ persist.private = [
".local/share/chatty" # matrix avatars and files ".local/share/chatty" # matrix avatars and files
# not just XMPP; without this Chatty will regenerate its device-id every boot. # ".purple" # XMPP stuff
# .purple/ contains XMPP *and* Matrix auth, logs, avatar cache, and a bit more
".purple"
]; ];
}; };
} }

View File

@@ -3,12 +3,9 @@
{ {
imports = [ imports = [
./aerc.nix ./aerc.nix
./alacritty.nix
./assorted.nix ./assorted.nix
./cantata.nix
./chatty.nix ./chatty.nix
./cozy.nix ./cozy.nix
./dino.nix
./element-desktop.nix ./element-desktop.nix
./epiphany.nix ./epiphany.nix
./evince.nix ./evince.nix
@@ -16,11 +13,9 @@
./fontconfig.nix ./fontconfig.nix
./fractal.nix ./fractal.nix
./fwupd.nix ./fwupd.nix
./g4music.nix
./git.nix ./git.nix
./gnome-feeds.nix ./gnome-feeds.nix
./gnome-keyring.nix ./gnome-keyring.nix
./gnome-weather.nix
./gpodder.nix ./gpodder.nix
./gthumb.nix ./gthumb.nix
./helix.nix ./helix.nix
@@ -33,7 +28,6 @@
./lemoa.nix ./lemoa.nix
./megapixels.nix ./megapixels.nix
./mepo.nix ./mepo.nix
./mopidy.nix
./mpv.nix ./mpv.nix
./msmtp.nix ./msmtp.nix
./neovim.nix ./neovim.nix
@@ -42,7 +36,6 @@
./nix-index.nix ./nix-index.nix
./obsidian.nix ./obsidian.nix
./offlineimap.nix ./offlineimap.nix
./rhythmbox.nix
./ripgrep.nix ./ripgrep.nix
./sfeed.nix ./sfeed.nix
./splatmoji.nix ./splatmoji.nix

View File

@@ -1,15 +0,0 @@
# usage:
# - start a DM with a rando via
# - '+' -> 'start conversation'
# - add a user to your roster via
# - '+' -> 'start conversation' -> '+' (opens the "add contact" dialog)
# - this triggers a popup on the remote side asking them for confirmation
# - after the remote's confirmation there will be a local popup for you to allow them to add you to their roster
# - to make a call:
# - ensure the other party is in your roster
# - open a DM with the party
# - click the phone icon at top (only visible if other party is in your roster)
{ ... }:
{
sane.programs.dino.persist.private = [ ".local/share/dino" ];
}

View File

@@ -1,16 +0,0 @@
# N.B.: requires first-run setup on moby:
# - UI will render transparent
# - click the hamburger (top-right: immediately left from close button)
# > Preferences
# > Background-blur mode: change from "Always" to "Never"
#
# the background blur is probably some dconf setting somewhere.
{ ... }:
{
sane.programs.g4music = {
persist.plaintext = [
# index?
".cache/com.github.neithern.g4music"
];
};
}

View File

@@ -1,10 +0,0 @@
# preferences are saved via dconf; see `dconf dump /`
# cache dir is just for weather data (or maybe a http cache)
{ ... }:
{
sane.programs.gnome-weather = {
persist.plaintext = [
".cache/libgweather"
];
};
}

View File

@@ -4,12 +4,10 @@
# compile without webservices to avoid the expensive webkitgtk dependency # compile without webservices to avoid the expensive webkitgtk dependency
package = pkgs.gthumb.override { withWebservices = false; }; package = pkgs.gthumb.override { withWebservices = false; };
mime.associations = { mime.associations = {
"image/gif" = "org.gnome.gThumb.desktop";
"image/heif" = "org.gnome.gThumb.desktop"; # apple codec "image/heif" = "org.gnome.gThumb.desktop"; # apple codec
"image/png" = "org.gnome.gThumb.desktop"; "image/png" = "org.gnome.gThumb.desktop";
"image/jpeg" = "org.gnome.gThumb.desktop"; "image/jpeg" = "org.gnome.gThumb.desktop";
"image/svg+xml" = "org.gnome.gThumb.desktop"; "image/svg+xml" = "org.gnome.gThumb.desktop";
"image/webp" = "org.gnome.gThumb.desktop";
}; };
}; };
} }

View File

@@ -1,56 +0,0 @@
# chat: <https://mopidy.zulipchat.com/>
# config docs: <https://docs.mopidy.com/en/latest/config/>
# web client: <http://localhost:6680>
# mpd: hosted on `localhost:6600`, no password`
#
# dump config:
# - `mopidy config`
# update local file index with
# - `mopidy local scan`
#
# if running as service, those commands are `mopidy --config ... <command>`
# and config path is found by `systemctl cat mopidy`
{ config, lib, pkgs, ... }:
let
# TODO: upstream this as `mopidy.withExtensions`
# this is borrowed from the nixos mopidy service
mopidyWithExtensions = extensions: with pkgs; buildEnv {
name = "mopidy-with-extensions-${mopidy.version}";
paths = lib.closePropagation extensions;
pathsToLink = [ "/${mopidyPackages.python.sitePackages}" ];
nativeBuildInputs = [ makeWrapper ];
postBuild = ''
makeWrapper ${mopidy}/bin/mopidy $out/bin/mopidy \
--prefix PYTHONPATH : $out/${mopidyPackages.python.sitePackages}
'';
};
in
{
sane.programs.mopidy = {
package = mopidyWithExtensions (with pkgs; [
mopidy-iris # web client: <https://github.com/jaedb/Iris>
mopidy-jellyfin
mopidy-local
mopidy-mpd
mopidy-mpris
mopidy-spotify
# TODO: mopidy-podcast, mopidy-youtube
# alternate web clients:
# mopidy-moped: <https://github.com/martijnboland/moped>
# mopidy-muse: <https://github.com/cristianpb/muse>
]);
persist.plaintext = [
".local/share/mopidy/local" # thumbs, library db
];
persist.private = [
".local/share/mopidy/http" # cookie
];
secrets.".config/mopidy/mopidy.conf" = ../../../secrets/common/mopidy.conf.bin;
# other folders:
# - .cache/mopidy
# - .config/mopidy
};
}

View File

@@ -14,29 +14,6 @@
# uosc # uosc
pkgs.mpv-uosc-latest pkgs.mpv-uosc-latest
]; ];
extraMakeWrapperArgs = [
# 2023/08/29: fixes an error where mpv on moby launches with the message
# "DRM_IOCTL_MODE_CREATE_DUMB failed: Cannot allocate memory"
# audio still works, and controls, screenshotting, etc -- just not the actual rendering
# this is likely a regression for mpv 0.36.0.
# the actual error message *appears* to come from the mesa library, but it's tough to trace.
# run with `--vo=help` to see a list of all output options.
# non-exhaustive (F=fails, W=works)
# ? libmpv render API for libmpv
# ? gpu Shader-based GPU Renderer
# ? gpu-next Video output based on libplacebo
# ? vdpau VDPAU with X11
# ? wlshm Wayland SHM video output (software scaling)
# ? xv X11/Xv
# W sdl SDL 2.0 Renderer
# F dmabuf-wayland Wayland dmabuf video output
# ? vaapi VA API with X11
# ? x11 X11 (software scaling)
# ? null Null video output
# ? caca libcaca
# F drm Direct Rendering Manager (software scaling)
"--add-flags" "--vo=sdl"
];
}; };
persist.plaintext = [ ".config/mpv/watch_later" ]; persist.plaintext = [ ".config/mpv/watch_later" ];
fs.".config/mpv/input.conf".symlink.text = '' fs.".config/mpv/input.conf".symlink.text = ''
@@ -49,10 +26,6 @@
save-position-on-quit=yes save-position-on-quit=yes
keep-open=yes keep-open=yes
# force GUI, even for tracks w/o album art
# see: <https://www.reddit.com/r/mpv/comments/rvrrpt/oscosdgui_and_arch_linux/>
player-operation-mode=pseudo-gui
# use uosc instead (for On Screen Controls) # use uosc instead (for On Screen Controls)
osc=no osc=no
# uosc provides its own seeking/volume indicators, so you also don't need this # uosc provides its own seeking/volume indicators, so you also don't need this

View File

@@ -1,11 +0,0 @@
{ ... }:
{
sane.programs.rhythmbox = {
persist.plaintext = [
# playlists; index
".local/share/rhythmbox"
# album art
".cache/rhythmbox"
];
};
}

View File

@@ -7,7 +7,6 @@
# - $ZDOTDIR/.zprofile # - $ZDOTDIR/.zprofile
# - if interactive: # - if interactive:
# - /etc/zshrc # - /etc/zshrc
# -> /etc/zinputrc
# - $ZDOTDIR/.zshrc # - $ZDOTDIR/.zshrc
# - if login (again): # - if login (again):
# - /etc/zlogin # - /etc/zlogin
@@ -80,18 +79,6 @@ in
hash -d tmp="/home/colin/tmp" hash -d tmp="/home/colin/tmp"
hash -d uninsane="/home/colin/dev/uninsane" hash -d uninsane="/home/colin/dev/uninsane"
hash -d Videos="/home/colin/Videos" hash -d Videos="/home/colin/Videos"
# emulate bash keybindings
bindkey -e
# or manually recreate what i care about...
# key[Left]=''${terminfo[kcub1]}
# key[Right]=''${terminfo[kcuf1]}
# bindkey '^R' history-incremental-search-backward
# bindkey '^A' beginning-of-line
# bindkey '^E' end-of-line
# bindkey "^''${key[Left]}" backward-word
# bindkey "^''${key[Right]}" forward-word
''; '';
}; };
}) })

View File

@@ -83,7 +83,7 @@
fs."Books/servo".symlink.target = "/mnt/servo-media/Books"; fs."Books/servo".symlink.target = "/mnt/servo-media/Books";
fs."Videos/servo".symlink.target = "/mnt/servo-media/Videos"; fs."Videos/servo".symlink.target = "/mnt/servo-media/Videos";
fs."Videos/servo-incomplete".symlink.target = "/mnt/servo-media/incomplete"; fs."Videos/servo-incomplete".symlink.target = "/mnt/servo-media/incomplete";
# fs."Music/servo".symlink.target = "/mnt/servo-media/Music"; fs."Music/servo".symlink.target = "/mnt/servo-media/Music";
fs."Pictures/servo-macros".symlink.target = "/mnt/servo-media/Pictures/macros"; fs."Pictures/servo-macros".symlink.target = "/mnt/servo-media/Pictures/macros";
# used by password managers, e.g. unix `pass` # used by password managers, e.g. unix `pass`

View File

@@ -16,7 +16,6 @@
# package sets # package sets
"tuiApps" "tuiApps"
] ++ [ ] ++ [
"alacritty" # terminal emulator
# "celluloid" # mpv frontend # "celluloid" # mpv frontend
"chatty" # matrix/xmpp/irc client "chatty" # matrix/xmpp/irc client
"cozy" # audiobook player "cozy" # audiobook player
@@ -26,7 +25,6 @@
"firefox" "firefox"
# "foliate" # e-book reader # "foliate" # e-book reader
# "fractal" # matrix client # "fractal" # matrix client
"g4music" # local music player
# "gnome.cheese" # "gnome.cheese"
# "gnome-feeds" # RSS reader (with claimed mobile support) # "gnome-feeds" # RSS reader (with claimed mobile support)
# "gnome.file-roller" # "gnome.file-roller"
@@ -34,16 +32,16 @@
# "gnome-podcasts" # "gnome-podcasts"
# "gnome.gnome-system-monitor" # "gnome.gnome-system-monitor"
# "gnome.gnome-terminal" # works on phosh # "gnome.gnome-terminal" # works on phosh
"gnome.gnome-weather" # "gnome.gnome-weather"
"gpodder" "gpodder"
"gthumb" "gthumb"
"komikku" "komikku"
"koreader" "koreader"
"lemoa" # lemmy app "lemoa" # lemmy app
# "lollypop" # "lollypop"
"mate.engrampa" # archive manager
"mepo" # maps viewer "mepo" # maps viewer
"mpv" "mpv"
"nheko"
# "networkmanagerapplet" # "networkmanagerapplet"
# "newsflash" # "newsflash"
"pavucontrol" "pavucontrol"
@@ -66,31 +64,28 @@
"audacity" "audacity"
"blanket" # ambient noise generator "blanket" # ambient noise generator
"brave" # for the integrated wallet -- as a backup "brave" # for the integrated wallet -- as a backup
"cantata" # music player (mpd frontend)
# "chromium" # chromium takes hours to build. brave is chromium-based, distributed in binary form, so prefer it. # "chromium" # chromium takes hours to build. brave is chromium-based, distributed in binary form, so prefer it.
"dino" # XMPP client # "dino" # XMPP client
"electrum" "electrum"
"element-desktop" "element-desktop"
# "font-manager" #< depends on webkitgtk4_0 (expensive to build) # "font-manager" #< depends on webkitgtk4_0 (expensive to build)
# "gajim" # XMPP client # "gajim" # XMPP client
"gimp" # broken on phosh "gimp" # broken on phosh
"gnome.dconf-editor" "gnome.dconf-editor"
# "gnome.file-roller" "gnome.file-roller"
"gnome.gnome-disk-utility" "gnome.gnome-disk-utility"
"gnome.nautilus" # file browser "gnome.nautilus" # file browser
# "gnome.totem" # video player, supposedly supports UPnP # "gnome.totem" # video player, supposedly supports UPnP
"handbrake" "handbrake"
"hase" "hase"
"inkscape" "inkscape"
# "jellyfin-media-player" "jellyfin-media-player"
"kdenlive" "kdenlive"
"kid3" # audio tagging "kid3" # audio tagging
"krita" "krita"
"libreoffice" # TODO: replace with an office suite that uses saner packaging? "libreoffice" # TODO: replace with an office suite that uses saner packaging?
"mumble" "mumble"
"nheko"
"obsidian" "obsidian"
"rhythmbox" # local music player
"slic3r" "slic3r"
"steam" "steam"
"vlc" "vlc"

View File

@@ -5,15 +5,11 @@ https://nixos.org/manual/nix/stable/language/builtins.html
https://github.com/nixos/nixpkgs/pulls?q= https://github.com/nixos/nixpkgs/pulls?q=
https://nur.nix-community.org/ https://nur.nix-community.org/
https://nix-community.github.io/home-manager/options.html https://nix-community.github.io/home-manager/options.html
https://lists.sr.ht/~mil/sxmo-devel
https://w.uninsane.org/viewer#search?books.name=wikipedia_en_all_maxi_2022-05&pattern= https://w.uninsane.org/viewer#search?books.name=wikipedia_en_all_maxi_2022-05&pattern=
https://jackett.uninsane.org/UI/Dashboard#search= https://jackett.uninsane.org/UI/Dashboard#search=
https://lemmy.uninsane.org
https://fed.uninsane.org https://fed.uninsane.org
https://jelly.uninsane.org
https://bt.uninsane.org https://bt.uninsane.org
https://sci-hub.se https://sci-hub.se
https://archive.is https://archive.is
https://news.ycombinator.com https://news.ycombinator.com
http://10.78.79.1 # router/firewall http://10.78.79.1 # Router/Firewall
https://jochen-hoenicke.de/queue # johoe's mempool (bitcoin/ethereum)

View File

@@ -3,8 +3,9 @@ let
fuzzel = "${pkgs.fuzzel}/bin/fuzzel"; fuzzel = "${pkgs.fuzzel}/bin/fuzzel";
sed = "${pkgs.gnused}/bin/sed"; sed = "${pkgs.gnused}/bin/sed";
wtype = "${pkgs.wtype}/bin/wtype"; wtype = "${pkgs.wtype}/bin/wtype";
kitty = "${pkgs.kitty}/bin/kitty";
launcher-cmd = fuzzel; launcher-cmd = fuzzel;
terminal-cmd = "${pkgs.xdg-terminal-exec}/bin/xdg-terminal-exec"; terminal-cmd = kitty;
lock-cmd = "${pkgs.swaylock}/bin/swaylock --indicator-idle-visible --indicator-radius 100 --indicator-thickness 30"; lock-cmd = "${pkgs.swaylock}/bin/swaylock --indicator-idle-visible --indicator-radius 100 --indicator-thickness 30";
vol-up-cmd = "${pkgs.pulsemixer}/bin/pulsemixer --change-volume +5"; vol-up-cmd = "${pkgs.pulsemixer}/bin/pulsemixer --change-volume +5";
vol-down-cmd = "${pkgs.pulsemixer}/bin/pulsemixer --change-volume -5"; vol-down-cmd = "${pkgs.pulsemixer}/bin/pulsemixer --change-volume -5";

View File

@@ -1,3 +1,5 @@
-- configversion: 737cb1de0389cee32a04785691a446a2
-- docs: <https://conky.cc/variables> -- docs: <https://conky.cc/variables>
-- color names are X11 colors: <https://en.wikipedia.org/wiki/X11_color_names#Color_name_chart> -- color names are X11 colors: <https://en.wikipedia.org/wiki/X11_color_names#Color_name_chart>
-- - can also use #rrggbb syntax -- - can also use #rrggbb syntax
@@ -35,14 +37,12 @@ conky.config = {
color2 = '404040', color2 = '404040',
} }
-- texeci <interval_sec> <cmd>: run the command periodically, _in a separate thread_ so as not to block rendering
conky.text = [[ conky.text = [[
${color1}${shadecolor 707070}${font Sxmo:size=50:style=Bold}${alignc}${exec date +"%H:%M"}${font} ${color1}${shadecolor 707070}${font Sxmo:size=50:style=Bold}${alignc}${exec date +"%H:%M"}${font}
${color2}${shadecolor a4d7d0}${font Sxmo:size=20}${alignc}${exec date +"%a %d %b"}${font} ${color2}${shadecolor a4d7d0}${font Sxmo:size=20}${alignc}${exec date +"%a %d %b"}${font}
${color1}${shadecolor}${font Sxmo:size=22:style=Bold}${alignc}${exec @bat@ }${font} ${color1}${shadecolor}${font Sxmo:size=22:style=Bold}${alignc}${exec @bat@ }${font}
${color1}${shadecolor}${font Sxmo:size=20:style=Bold}${alignc}${texeci 600 @weather@ }${font}
${color2}${shadecolor a4d7d0}${font Sxmo:size=16}${alignc}⇅ ${downspeedf wlan0}K/s${font} ${color2}${shadecolor a4d7d0}${font Sxmo:size=16}${alignc}⇅ ${downspeedf wlan0}K/s${font}

View File

@@ -37,7 +37,7 @@
# - live in ~/.local/state/sxmo.log # - live in ~/.local/state/sxmo.log
# - ~/.local/state/superd.log # - ~/.local/state/superd.log
# - ~/.local/state/superd/logs/<daemon>.log # - ~/.local/state/superd/logs/<daemon>.log
# - `journalctl --user --boot` (lightdm redirects the sxmo session stdout => systemd) # - `journalctl --user --boot` (lightm redirects the sxmo session stdout => systemd)
# #
# - default components: # - default components:
# - DE: sway (if wayland), dwm (if X) # - DE: sway (if wayland), dwm (if X)
@@ -57,12 +57,6 @@ let
knownTerminals = { knownTerminals = {
vte = "vte-2.91"; vte = "vte-2.91";
}; };
systemd-cat = "${pkgs.systemd}/bin/systemd-cat";
runWithLogger = identifier: cmd: pkgs.writeShellScript identifier ''
echo "launching ${identifier}..." | ${systemd-cat} --identifier=${identifier}
${cmd} 2>&1 | ${systemd-cat} --identifier=${identifier}
'';
in in
{ {
options = with lib; { options = with lib; {
@@ -71,31 +65,17 @@ in
type = types.bool; type = types.bool;
}; };
sane.gui.sxmo.greeter = mkOption { sane.gui.sxmo.greeter = mkOption {
type = types.enum [ type = types.enum [ "lightdm-mobile" "sway" ];
"greetd-phog" default = "lightdm-mobile";
"greetd-sway-phog"
"greetd-sxmo"
"lightdm-mobile"
"sway-gtkgreet"
];
# default = "lightdm-mobile";
default = "greetd-sway-phog";
description = '' description = ''
which greeter to use. which greeter to use.
"greetd-phog" => phosh-based greeter. keypad (0-9) with option to open an on-screen keyboard.
"greetd-sway-phog" => phog, but uses sway as the compositor instead of phoc.
requires a patched phog, since sway doesn't provide the Wayland global "zphoc_layer_shell_effects_v1".
"greetd-sxmo" => launch sxmo directly from greetd, no auth.
this means no keychain unlocked or encrypted home mounted.
"lightdm-mobile" => keypad style greeter. can only enter digits 0-9 as password. "lightdm-mobile" => keypad style greeter. can only enter digits 0-9 as password.
"sway-gtkgreet" => layered sway greeter. behaves as if you booted to swaylock. "sway" => layered sway greeter. behaves as if you booted to swaylock.
this isn't practically usable on mobile because of keyboard input.
also, it takes literally 6 minutes to appear
''; '';
}; };
sane.gui.sxmo.package = mkOption { sane.gui.sxmo.package = mkOption {
type = types.package; type = types.package;
default = pkgs.sxmo-utils-latest; default = pkgs.sxmo-utils;
description = '' description = ''
sxmo base scripts and hooks collection. sxmo base scripts and hooks collection.
consider overriding the outputs under /share/sxmo/default_hooks consider overriding the outputs under /share/sxmo/default_hooks
@@ -136,7 +116,6 @@ in
}; };
in { in {
SXMO_BAR_SHOW_BAT_PER = mkSettingsOpt "1" "show battery percentage in statusbar"; SXMO_BAR_SHOW_BAT_PER = mkSettingsOpt "1" "show battery percentage in statusbar";
SXMO_DISABLE_CONFIGVERSION_CHECK = mkSettingsOpt "1" "allow omitting the configversion line from user-provided sxmo dotfiles";
SXMO_UNLOCK_IDLE_TIME = mkSettingsOpt "300" "how many seconds of inactivity before locking the screen"; # lock -> screenoff happens 8s later, not configurable SXMO_UNLOCK_IDLE_TIME = mkSettingsOpt "300" "how many seconds of inactivity before locking the screen"; # lock -> screenoff happens 8s later, not configurable
}; };
}; };
@@ -196,8 +175,6 @@ in
hardware.bluetooth.enable = true; hardware.bluetooth.enable = true;
services.blueman.enable = true; services.blueman.enable = true;
hardware.opengl.enable = true;
# TODO: nerdfonts is 4GB. it accepts an option to ship only some fonts: probably want to use that. # TODO: nerdfonts is 4GB. it accepts an option to ship only some fonts: probably want to use that.
fonts.packages = [ pkgs.nerdfonts ]; fonts.packages = [ pkgs.nerdfonts ];
@@ -227,10 +204,7 @@ in
# TODO: only need the share/sxmo directly linked # TODO: only need the share/sxmo directly linked
"${cfg.package}/share" "${cfg.package}/share"
]; ];
} // (lib.filterAttrs # certain settings are read before the `profile` is sourced };
(k: v: k == "SXMO_DISABLE_CONFIGVERSION_CHECK")
cfg.settings
);
systemd.services."sxmo-set-permissions" = { systemd.services."sxmo-set-permissions" = {
description = "configure specific /sys and /dev nodes to be writable by sxmo scripts"; description = "configure specific /sys and /dev nodes to be writable by sxmo scripts";
@@ -274,8 +248,14 @@ in
}; };
sane.user.fs.".config/sxmo/profile".symlink.text = let sane.user.fs.".config/sxmo/profile".symlink.text = let
mkKeyValue = key: value: ''export ${key}="${value}"''; mkKeyValue = key: value: ''export ${key}="${value}"'';
in userConfig = lib.generators.toKeyValue { inherit mkKeyValue; } cfg.settings;
lib.generators.toKeyValue { inherit mkKeyValue; } cfg.settings; in ''
# configversion: 4284f96d91e9550ff8f3b25823e402ad
# ^ upstream adds new options every now and then, expects user config file
# to include the md5sum of the template it's based on.
# see `setup_config_version.sh`
${userConfig}
'';
sane.user.fs.".config/sxmo/sway".symlink.target = pkgs.substituteAll { sane.user.fs.".config/sxmo/sway".symlink.target = pkgs.substituteAll {
src = ./sway-config; src = ./sway-config;
@@ -299,7 +279,6 @@ in
in pkgs.substituteAll { in pkgs.substituteAll {
src = ./conky-config; src = ./conky-config;
bat = "${battery_estimate}/bin/battery_estimate"; bat = "${battery_estimate}/bin/battery_estimate";
weather = "timeout 20 ${pkgs.sane-weather}/bin/sane-weather";
}; };
} }
@@ -334,14 +313,16 @@ in
}; };
}) })
(lib.mkIf (cfg.greeter == "sway-gtkgreet") { (lib.mkIf (cfg.greeter == "sway") {
services.greetd = { services.greetd = {
enable = true; enable = true;
# borrowed from gui/sway # borrowed from gui/sway
settings.default_session.command = settings.default_session.command =
let let
# start sway and have it construct the gtkgreeter # start sway and have it construct the gtkgreeter
sway-as-greeter = runWithLogger "sway-as-greeter" "${pkgs.sway}/bin/sway --debug --config ${sway-config-into-gtkgreet}"; sway-as-greeter = pkgs.writeShellScriptBin "sway-as-greeter" ''
${pkgs.sway}/bin/sway --debug --config ${sway-config-into-gtkgreet} > /var/log/sway/sway-as-greeter.log 2>&1
'';
# (config file for the above) # (config file for the above)
sway-config-into-gtkgreet = pkgs.writeText "greetd-sway-config" '' sway-config-into-gtkgreet = pkgs.writeText "greetd-sway-config" ''
exec "${gtkgreet-launcher}" exec "${gtkgreet-launcher}"
@@ -352,60 +333,12 @@ in
# so that command must exist on the specific user's path who is logging in. it doesn't need to exist system-wide. # so that command must exist on the specific user's path who is logging in. it doesn't need to exist system-wide.
${pkgs.greetd.gtkgreet}/bin/gtkgreet --layer-shell --command sxmo_winit.sh ${pkgs.greetd.gtkgreet}/bin/gtkgreet --layer-shell --command sxmo_winit.sh
''; '';
in "${sway-as-greeter}"; in "${sway-as-greeter}/bin/sway-as-greeter";
}; };
})
(lib.mkIf (cfg.greeter == "greetd-sway-phog") { sane.fs."/var/log/sway" = {
services.greetd = { dir.acl.mode = "0777";
enable = true; wantedBeforeBy = [ "greetd.service" "display-manager.service" ];
# borrowed from gui/sway
settings.default_session.command =
let
# start sway and have it construct the greeter
sway-as-greeter = runWithLogger "sway-as-greeter" "${pkgs.sway}/bin/sway --debug --config ${sway-config-into-phog}";
# (config file for the above)
sway-config-into-phog = pkgs.writeText "greetd-sway-config" ''
exec "${pkgs.phog}/libexec/phog"
'';
in "${sway-as-greeter}";
};
# phog locates sxmo_winit.sh via <env>/share/wayland-sessions
environment.pathsToLink = [ "/share/wayland-sessions" ];
# persisting fontconfig & mesa_shader_cache improves start time from like 6 minutes to 1 minute
# TODO: this should apply to any greetd implementation
users.users.greeter.home = "/var/lib/greeter";
sane.persist.sys.plaintext = [
{ user = "greeter"; group = "greeter"; path = "/var/lib/greeter/.cache/fontconfig"; }
{ user = "greeter"; group = "greeter"; path = "/var/lib/greeter/.cache/mesa_shader_cache"; }
];
})
(lib.mkIf (cfg.greeter == "greetd-phog") {
services.greetd = {
enable = true;
# launch directly: but stdout/stderr gets dropped
# settings.default_session.command = "${pkgs.phog}/bin/phog";
# wrapper to launch phog and redirect logs to system journal.
settings.default_session.command = let
launch-phog = runWithLogger "phog" "${pkgs.phog}/bin/phog";
in "${launch-phog}";
};
environment.pathsToLink = [ "/share/wayland-sessions" ];
})
(lib.mkIf (cfg.greeter == "greetd-sxmo") {
services.greetd = {
enable = true;
settings.default_session = {
command = let
launch-sxmo = runWithLogger "sxmo" "${cfg.package}/bin/sxmo_winit.sh";
in "${launch-sxmo}";
user = "colin";
};
}; };
}) })
@@ -419,6 +352,16 @@ in
# ''; # '';
# }]; # }];
# services.xserver.enable = true; # services.xserver.enable = true;
# services.greetd = {
# enable = true;
# settings = {
# default_session = {
# command = "${cfg.package}/bin/sxmo_winit.sh";
# user = "colin";
# };
# };
# };
])) ]))
]; ];
} }

View File

@@ -1,8 +1,10 @@
# Default config for sway
# configversion: 5eff902ecca36b4e75567322335cc81c
#
# Copy this to ~/.config/sway/config and edit it to your liking.
#
# Read `man 5 sway` for a complete reference. # Read `man 5 sway` for a complete reference.
# TODO: use stock sxmo config & override via /etc/sway/config.d/*
# especially, this will let me avoid issues around `configversion`
### Variables ### Variables
# #
# Mod4 = Logo key # Mod4 = Logo key
@@ -45,33 +47,25 @@ titlebar_border_thickness 1
titlebar_padding 12 1 titlebar_padding 12 1
title_align center title_align center
# tabbed windows by default
workspace_layout tabbed
### tab colors (#border #background #text [#indicator #childBorder]) ### tab colors (#border #background #text [#indicator #childBorder])
# focused & unfocused are the main interest # fucused & unfocused are the main interest
# urgent is used when an inactive window wants attention (e.g. terminal rings a bell)
# colors are synchronized with waybar and mpv
client.focused #1f5e54 #418379 #ffffff client.focused #1f5e54 #418379 #ffffff
client.focused_inactive #1f5e54 #5f676a #ffffff client.focused_inactive #1f5e54 #5f676a #ffffff
client.unfocused #1f5e54 #1f554c #b4b4b4 client.unfocused #1f5e54 #1f554c #b4b4b4
client.urgent #ff8080 #ff8080 #ffffff client.urgent #e64291 #e64291 #ffffff
### Key bindings ### Key bindings
# #
# Basics: # Basics:
# #
input * xkb_options compose:ralt
# Start a terminal # Start a terminal
bindsym $mod+Return exec $term bindsym $mod+Return exec $term
# Launch appmenu # Launch appmenu
bindsym $mod+p exec sxmo_appmenu.sh bindsym $mod+p exec sxmo_appmenu.sh
bindsym $mod+Shift+p exec sxmo_appmenu.sh sys
# Wm menu switcher # Launch scripts menu
bindsym $mod+i exec sxmo_wmmenu.sh windowswitcher bindsym $mod+i exec sxmo_appmenu.sh scripts
# Kill focused window # Kill focused window
bindsym $mod+Shift+q kill bindsym $mod+Shift+q kill
@@ -163,7 +157,7 @@ client.urgent #ff8080 #ff8080 #ffffff
bindsym $mod+e layout toggle split bindsym $mod+e layout toggle split
# Make the current focus fullscreen # Make the current focus fullscreen
bindsym $mod+f fullscreen # bindsym $mod+f fullscreen
# Toggle the current focus between tiling and floating mode # Toggle the current focus between tiling and floating mode
bindsym $mod+Shift+space floating toggle bindsym $mod+Shift+space floating toggle
@@ -173,12 +167,6 @@ client.urgent #ff8080 #ff8080 #ffffff
# Move focus to the parent container # Move focus to the parent container
bindsym $mod+a focus parent bindsym $mod+a focus parent
# Manual locker
bindsym $mod+g exec sxmo_hook_locker.sh
# Shutdown
bindsym $mod+t exec sxmo_appmenu.sh power
# #
# Scratchpad: # Scratchpad:
# #
@@ -199,16 +187,16 @@ mode "resize" {
# right will grow the containers width # right will grow the containers width
# up will shrink the containers height # up will shrink the containers height
# down will grow the containers height # down will grow the containers height
bindsym $left resize shrink width 30px bindsym $left resize shrink width 10px
bindsym $down resize grow height 30px bindsym $down resize grow height 10px
bindsym $up resize shrink height 30px bindsym $up resize shrink height 10px
bindsym $right resize grow width 30px bindsym $right resize grow width 10px
# Ditto, with arrow keys # Ditto, with arrow keys
bindsym Left resize shrink width 30px bindsym Left resize shrink width 10px
bindsym Down resize grow height 30px bindsym Down resize grow height 10px
bindsym Up resize shrink height 30px bindsym Up resize shrink height 10px
bindsym Right resize grow width 30px bindsym Right resize grow width 10px
# Return to default mode # Return to default mode
bindsym Return mode "default" bindsym Return mode "default"
@@ -234,31 +222,13 @@ bar {
statusline #ffffff statusline #ffffff
background #323232 background #323232
inactive_workspace #32323200 #32323200 #5c5c5c inactive_workspace #32323200 #32323200 #5c5c5c
font "Sxmo 10" font "Sxmo"
} }
} }
for_window [app_id="pinentry-.*"] floating true
for_window [app_id="foot" title=".*sxmo/modem/.*/draft.txt.*"] resize set height 25 for_window [app_id="foot" title=".*sxmo/modem/.*/draft.txt.*"] resize set height 25
for_window [title="megapixels"] inhibit_idle open for_window [title="megapixels"] inhibit_idle open
# Need playerctl installed and running
bindsym XF86AudioPlay exec playerctl play-pause
bindsym XF86AudioStop exec playerctl stop
bindsym XF86AudioNext exec playerctl next
bindsym XF86AudioPrev exec playerctl previous
bindsym XF86MonBrightnessUp exec sxmo_brightness.sh up
bindsym XF86MonBrightnessDown exec sxmo_brightness.sh down
bindsym Print exec sxmo_screenshot.sh
bindsym button2 kill
bindswitch lid:on exec sxmo_wm.sh dpms on
bindswitch lid:off exec sxmo_wm.sh dpms off
include /etc/sway/config.d/* include /etc/sway/config.d/*
exec 'printf %s "$SWAYSOCK" > "$XDG_RUNTIME_DIR"/sxmo.swaysock' exec 'printf %s "$SWAYSOCK" > "$XDG_RUNTIME_DIR"/sxmo.swaysock'

View File

@@ -24,7 +24,8 @@ in
(mkIf cfg { (mkIf cfg {
sane.programs.docsets.enableFor.system = true; sane.programs.docsets.enableFor.system = true;
sane.programs.ldd-aarch64.enableFor.user.colin = true; sane.programs.ldd-aarch64.enableFor.user.colin = true;
# sane.programs.zeal.enableFor.user.colin = true; # TODO: migrate this to `sane.user.programs.zeal.enable = true`
sane.programs.zeal.enableFor.user.colin = true;
}) })
]; ];
} }

View File

@@ -1,21 +0,0 @@
{
"bozo": 0,
"content_length": 3520653,
"content_type": "application/xml; charset=utf-8",
"description": "There\u2019s a reason the History Channel has produced hundreds of documentaries about Hitler but only a few about Dwight D. Eisenhower. Bad guys (and gals) are eternally fascinating. Behind the Bastards dives in past the Cliffs Notes of the worst humans in history and exposes the bizarre realities of their lives. Listeners will learn about the young adult novels that helped Hitler form his monstrous ideology, the founder of Blackwater\u2019s insane quest to build his own Air Force, the bizarre lives of the sons and daughters of dictators and Saddam Hussein\u2019s side career as a trashy romance novelist.",
"favicon": "",
"favicon_data_uri": "",
"hubs": [],
"is_podcast": true,
"is_push": false,
"item_count": 689,
"last_updated": "2023-08-15T04:00:00+00:00",
"score": 8,
"self_url": "https://www.omnycontent.com/d/playlist/e73c998e-6e60-432f-8610-ae210140c5b1/e5f91208-cc7e-4726-a312-ae280140ad11/d64f756d-6d5e-4fae-b24f-ae280140ad36/podcast.rss",
"site_name": "",
"site_url": "",
"title": "Behind the Bastards",
"url": "https://omnycontent.com/d/playlist/e73c998e-6e60-432f-8610-ae210140c5b1/E5F91208-CC7E-4726-A312-AE280140AD11/D64F756D-6D5E-4FAE-B24F-AE280140AD36/podcast.rss",
"velocity": 0.35,
"version": "rss20"
}

View File

@@ -1,21 +0,0 @@
{
"bozo": 0,
"content_length": 805006,
"content_type": "application/rss+xml; charset=utf-8",
"description": "Wissenschaft und Technik im Kopfhoerer / Science and Engineering in your Headphones",
"favicon": "http://omegataupodcast.net/omegatau_fav.png",
"favicon_data_uri": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAAsTAAALEwEAmpwYAAACC2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx0aWZmOlJlc29sdXRpb25Vbml0PjI8L3RpZmY6UmVzb2x1dGlvblVuaXQ+CiAgICAgICAgIDx0aWZmOkNvbXByZXNzaW9uPjE8L3RpZmY6Q29tcHJlc3Npb24+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb24+CiAgICAgICAgIDx0aWZmOlBob3RvbWV0cmljSW50ZXJwcmV0YXRpb24+MjwvdGlmZjpQaG90b21ldHJpY0ludGVycHJldGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KD0UqkwAAB2BJREFUWAmdV1tvVFUU/ubMmQud0k6vUzrTUsq1twSMmKI+idBIJJFECPAACS9NTLzwYkzwof/BoC8QE30xITHSSIgQVEyEUsDUVkRgqC200HtnmPvd9e1hD6cNmOpuTvc+a6+9Lt9ea501tmPHjhXwH4dpmpiamsKePXvQ29urThcKBdhsNqRSKfT19WF8fBzl5eXIZrOKblVBXj6GYcCMRqPWvZIwLihQP1Ymp9OJJ0+eKOFWul7TiFgsBrvdrnieKbQhny/A6XDA5XYrGeKMqayhIu0FaXzP5/PI5XKKroVog2gEPXjeoGLK4JwXT52yRiaFnKBBmeUuD1ZXVWFmdhYGBXNwQx8KhUJ4/PgxpqenEQ6HkUgkkE6nlTfJZFLRL1y4gOehR1lzc3O4desWJh89wq3hYeSEFqnyYcTmxl1HOUYNF/I0LpeH7dChQ2JDAQ6BhbBR6IYNG9Dc3Iza2lp1j/RWI0WvGhsbkclkUFFRgS1btlBnCT0iNjIyogxWCBFZ4U390o9CLAyBDXaHC8OOOlz+MwiTyik8Eomgrq4OBw4cQCAQQFlZmaITcj2IksvlwubNmzWpNGs+Grh169YSXS0EfvxwAkj8KIFVB5S14nb4FXzz+z2YPECIGxoacPDgQdTU1Kh7pzLCrq+IgkjjO73XiDwvDsjHUZDZEOfSiSRs6RQcCaEZcu/2ekQliDEVgknL4/E4enp6FOQ0hkN7pGetiDNpmq6Yl/3TvMKkdvhuFMQICTdFKcRRyGaAcBomoec9NjU1qRzWwukpD2pP6RX3iBhpKxmS7aJQYkDOpau3wXRWSww4YXdXoMzux47dEvj0eP369WCgEXIqoXIq4vudO3cwMTGhgpMBxthgkdm+fbtCjLxWNHjm9OnTWFhYUPGSkfcKrxfhRBOiERamnFxxAe4KJ1o8Lpj0sr6+XjlEYRwUSGXnz5/HuXPnlCLSNP3UqVPo7OzEyZMnVcASHQ07ZQwNDWFwcFBly/z8PDo6OpCX85NT07gZnESDtxId6/w4c+ZnmPSI6aSV0wCm5NjYGC5fvqwOc08HFo1obW3FwMAALl26hKNHj5ZQ00YykDdu3IjKykr1VFdXIytIzEjet3jc8NdXoVz0dnYGiga4pSxSCQXoMStViilHxSyt1j2WYaasLkTcszrALOHVrlq1Ss38HsSkgN2fmGHaIZnJKoQTKQlCMtFjqwCuqcTqtdUAwr3cKG04Z/JqfvJyHQpFpfJJbDnkvcgEQ+gGvWTAWQcNYGqSbjXMykOhL9pbzheNxZFKZ+AwjSVnGHGSUaYKIKswrgmjDiyrwJWuKYMOhMIROJxSVe2G+jAtcVUsEB1FiLRg7RmzQK/13kpnrTyZTCH49xRsRhEt0vnHoaNNVcKVCl4pH51KC+ShyDyyTFFbsaCtckveC+LsB5RzYkzpc7xcOBk49Lx8/9/eGbx/BSeQSWfhcrAnyKsClErJV1HSMSNZQTSowSTUfNGDa3pAS3UW6L2VzDw/vxDG9GIMgUafKJdT8kzNzOL2H9eViGTbS6ivqynqYbBRkdVTrlma/48BPMOo95a7lRNj98bx7jtv4dMTn5TaM5dcRX//9/j6qy9hMp9ZKJiOetAAVsjlhul9PVuN1jQioM4JwS6RD4SkqfGgvb1Ns6j515orajZYsZanHAWvXr16ydUsOS0vvKYXIcQ+oKi8eEo7x+vmx4gjK9WQw2AbxqJDpdZYYD2nAtKYz1TIh3x8Zxn2eDxKiPUcy7rf34gH92eV52RobgoovuLZYiNL1DkMNpksu9bBzTVr1qC7uxtj8lGiMvYN+mGz6vP5sGnTptIxCqfBNHL3rp1Cn8J3315U+907upfw8SX+tPFRPSEFtre3K++0IGbB3r171VdtcnJSNaxUQDj5IWJf6JXvPK9Pf0t4lqOnZzfOnu3H3XtB7HpzJ1rXrVNI6n3KmZ6eEc5y2Pbt21fw+/04cuSIgpZwkpEzvWE2EBHeHwdpOkWJXltbWyle9DmtSB2Qf1omf5QYUhUXFxfxxq63izr48ykYDKouh/dH6/hQCGcGKQ3gu6ZRsb7DmRl6UmxY9Tkq5FrP+lwuV7z3gYFrGLp5RRCsgL2rq6uPHrHtamlpQVVVtSh6JpDCtSAtVNOIBtOYGUPjqUgXNrFBzhW7Y/KTl8E7OjqK3vc+gm9Nk/BKtki71Mc7ZCASCfYHjG4K5H1zjw+N1Gtei14TiRs3bmJOWq/GRr/iozLrQ8PYK167NogPj3+MB5OzqK/1Ii3xYzt8+DCbVnUwGo1JMxlCTW2dtF3r0BTww1vlRZkYZYoR/KgQBQpjZkwL/MHgKC7+dAXjwWG8/8FxvP7aq/AHGuVMsZBFohE8fDiBq1ev4YvPP0NTaxfWBnyIxhOwi6G2/fv3F5LSGsXjKdU0RGIJzMzJb8OHIbmHuIDnRlmtBxVl8vNMIMxIIVmIJJGRDgfyq89d48XmtT4F72/Xh4W2NKWF8HRUY9vLbYKqU1IwqbohbvwDi4As2ZCohrEAAAAASUVORK5CYII=",
"hubs": [],
"is_podcast": true,
"is_push": false,
"item_count": 100,
"last_updated": "2023-06-16T09:08:08+00:00",
"score": 10,
"self_url": "https://omegataupodcast.net/feed/mp3/",
"site_name": "omega tau science & engineering podcast",
"site_url": "https://omegataupodcast.net",
"title": "omega tau science & engineering podcast",
"url": "https://omegataupodcast.net/feed/mp3/",
"velocity": 0.062,
"version": "rss20"
}

View File

@@ -1,21 +0,0 @@
{
"bozo": 0,
"content_length": 87719,
"content_type": "application/xml; charset=utf-8",
"description": "Useful Idiots is an informative and irreverent politics podcast.",
"favicon": "",
"favicon_data_uri": "",
"hubs": [],
"is_podcast": true,
"is_push": false,
"item_count": 20,
"last_updated": "2023-08-15T14:54:32+00:00",
"score": 14,
"self_url": "https://usefulidiots.substack.com/feed",
"site_name": "Useful Idiots | Substack",
"site_url": "https://usefulidiots.substack.com",
"title": "Useful Idiots",
"url": "https://usefulidiots.substack.com/feed",
"velocity": 0.655,
"version": "rss20"
}

View File

@@ -1,21 +0,0 @@
{
"bozo": 0,
"content_length": 232527,
"content_type": "application/xml; charset=utf-8",
"description": "Not wrong political opinions.",
"favicon": "",
"favicon_data_uri": "",
"hubs": [],
"is_podcast": true,
"is_push": false,
"item_count": 67,
"last_updated": "2023-08-09T21:26:55+00:00",
"score": -10,
"self_url": "https://feeds.acast.com/public/shows/6490a2ce7ded6b001126fa5b",
"site_name": "",
"site_url": "",
"title": "We're Not Wrong",
"url": "https://feeds.acast.com/public/shows/6490a2ce7ded6b001126fa5b",
"velocity": 0.145,
"version": "rss20"
}

View File

@@ -9,10 +9,6 @@ let
pname = "ensure-dir"; pname = "ensure-dir";
src = ./.; src = ./.;
}; };
ensure-file = pkgs.static-nix-shell.mkBash {
pname = "ensure-file";
src = ./.;
};
ensure-symlink = pkgs.static-nix-shell.mkBash { ensure-symlink = pkgs.static-nix-shell.mkBash {
pname = "ensure-symlink"; pname = "ensure-symlink";
src = ./.; src = ./.;
@@ -37,10 +33,6 @@ let
type = types.nullOr dirEntry; type = types.nullOr dirEntry;
default = null; default = null;
}; };
file = mkOption {
type = types.nullOr (fileEntryFor name);
default = null;
};
symlink = mkOption { symlink = mkOption {
type = types.nullOr (symlinkEntryFor name); type = types.nullOr (symlinkEntryFor name);
default = null; default = null;
@@ -89,8 +81,6 @@ let
default-acl default-acl
(lib.mkIf (config.dir != null) (lib.mkIf (config.dir != null)
(sane-lib.filterNonNull config.dir.acl)) (sane-lib.filterNonNull config.dir.acl))
(lib.mkIf (config.file != null)
(sane-lib.filterNonNull config.file.acl))
(lib.mkIf (config.symlink != null) (lib.mkIf (config.symlink != null)
(sane-lib.filterNonNull config.symlink.acl)) (sane-lib.filterNonNull config.symlink.acl))
]; ];
@@ -98,7 +88,6 @@ let
# actually generate the item # actually generate the item
generated.command = lib.mkMerge [ generated.command = lib.mkMerge [
(lib.mkIf (config.dir != null) [ "${ensure-dir}/bin/ensure-dir" name ]) (lib.mkIf (config.dir != null) [ "${ensure-dir}/bin/ensure-dir" name ])
(lib.mkIf (config.file != null) [ "${ensure-file}/bin/ensure-file" name config.file.copyFrom ])
(lib.mkIf (config.symlink != null) [ "${ensure-symlink}/bin/ensure-symlink" name config.symlink.target ]) (lib.mkIf (config.symlink != null) [ "${ensure-symlink}/bin/ensure-symlink" name config.symlink.target ])
]; ];
@@ -135,26 +124,6 @@ let
# takes no special options # takes no special options
dirEntry = types.submodule propagatedGenerateMod; dirEntry = types.submodule propagatedGenerateMod;
fileEntryFor = path: types.submodule ({ config, ... }: {
options = {
inherit (propagatedGenerateMod.options) acl;
text = mkOption {
type = types.nullOr types.lines;
default = null;
description = "create a file with this text, overwriting anything that was there before.";
};
copyFrom = mkOption {
type = types.coercedTo types.package toString types.str;
description = "populate the file based on the content at this provided path";
};
};
config = {
copyFrom = lib.mkIf (config.text != null) (
pkgs.writeText (path-lib.leaf path) config.text
);
};
});
symlinkEntryFor = path: types.submodule ({ config, ...}: { symlinkEntryFor = path: types.submodule ({ config, ...}: {
options = { options = {
inherit (propagatedGenerateMod.options) acl; inherit (propagatedGenerateMod.options) acl;

View File

@@ -1,16 +0,0 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash
set -e
cpto="$1"
cpfrom="$2"
# -f flag in case the destination perms were set to 000
# --no-dereference in case the destination already exists as a symlink
# however, "no-dereference" has the edge case of copying `cpfrom` to `cpto`
# when `cpto` already exists as a symlink to `cpfom`:
# "cp: <cpto> and <cpfrom> are the same file"
# use `--remove-destination` for that
cp --no-dereference -f "$cpfrom" "$cpto" \
|| cp --no-dereference --remove-destination "$cpfrom" "$cpto"

View File

@@ -46,15 +46,15 @@ let
upnpServiceForPort = port: portCfg: upnpServiceForPort = port: portCfg:
lib.mkIf portCfg.visibleTo.wan { lib.mkIf portCfg.visibleTo.wan {
"upnp-forward-${port}" = { "upnp-forward-${port}" = {
description = "forward port ${port} (${portCfg.description}) from upstream gateway to this host"; description = "forward port ${port} from upstream gateway to this host";
restartTriggers = [(builtins.toJSON portCfg)]; restartTriggers = [(builtins.toJSON portCfg)];
serviceConfig = { serviceConfig.Type = "oneshot";
Type = "oneshot"; serviceConfig.TimeoutSec = "6min";
TimeoutSec = "6min";
Restart = "on-failure"; after = [ "network.target" ];
RestartSec = "3min"; wantedBy = [ "upnp-forwards.target" ];
ExecStart = script =
let let
portFwd = "${pkgs.sane-scripts.ip-port-forward}/bin/sane-ip-port-forward"; portFwd = "${pkgs.sane-scripts.ip-port-forward}/bin/sane-ip-port-forward";
forwards = lib.flatten [ forwards = lib.flatten [
@@ -66,10 +66,6 @@ let
${lib.escapeShellArgs forwards} ${lib.escapeShellArgs forwards}
''; '';
}; };
after = [ "network.target" ];
wantedBy = [ "upnp-forwards.target" ];
};
}; };
in in
{ {

View File

@@ -231,7 +231,6 @@ in
(lib.mapAttrs' (pkgName: _pkg: { name = "cacert.${pkgName}"; value = {}; }) pkgs.cacert) (lib.mapAttrs' (pkgName: _pkg: { name = "cacert.${pkgName}"; value = {}; }) pkgs.cacert)
(lib.mapAttrs' (pkgName: _pkg: { name = "gnome.${pkgName}"; value = {}; }) pkgs.gnome) (lib.mapAttrs' (pkgName: _pkg: { name = "gnome.${pkgName}"; value = {}; }) pkgs.gnome)
(lib.mapAttrs' (pkgName: _pkg: { name = "libsForQt5.${pkgName}"; value = {}; }) pkgs.libsForQt5) (lib.mapAttrs' (pkgName: _pkg: { name = "libsForQt5.${pkgName}"; value = {}; }) pkgs.libsForQt5)
(lib.mapAttrs' (pkgName: _pkg: { name = "mate.${pkgName}"; value = {}; }) pkgs.mate)
(lib.mapAttrs' (pkgName: _pkg: { name = "plasma5Packages.${pkgName}"; value = {}; }) pkgs.plasma5Packages) (lib.mapAttrs' (pkgName: _pkg: { name = "plasma5Packages.${pkgName}"; value = {}; }) pkgs.plasma5Packages)
(lib.mapAttrs' (pkgName: _pkg: { name = "python3Packages.${pkgName}"; value = {}; }) pkgs.python3Packages) (lib.mapAttrs' (pkgName: _pkg: { name = "python3Packages.${pkgName}"; value = {}; }) pkgs.python3Packages)
(lib.mapAttrs' (pkgName: _pkg: { name = "sane-scripts.${pkgName}"; value = {}; }) pkgs.sane-scripts) (lib.mapAttrs' (pkgName: _pkg: { name = "sane-scripts.${pkgName}"; value = {}; }) pkgs.sane-scripts)

View File

@@ -2,8 +2,6 @@
{ {
imports = [ imports = [
./dyn-dns.nix ./dyn-dns.nix
./eg25-control.nix
./eg25-manager.nix
./kiwix-serve.nix ./kiwix-serve.nix
./mautrix-signal.nix ./mautrix-signal.nix
./nixserve.nix ./nixserve.nix

View File

@@ -1,27 +0,0 @@
{ config, lib, pkgs, ... }:
let
cfg = config.sane.services.eg25-control;
in
{
options.sane.services.eg25-control = with lib; {
enable = mkEnableOption "Quectel EG25 modem configuration scripts. alternative to eg25-manager";
package = mkOption {
type = types.package;
default = pkgs.eg25-control;
};
};
config = lib.mkIf cfg.enable {
systemd.services.eg25-control = {
serviceConfig = {
Type = "simple";
ExecStart = "${cfg.package}/bin/eg25-control --power-on --enable-gps --dump-debug-info --verbose";
Restart = "on-failure";
RestartSec = "60s";
};
after = [ "ModemManager.service" ];
wants = [ "ModemManager.service" ];
wantedBy = [ "multi-user.target" ];
};
};
}

View File

@@ -1,69 +0,0 @@
# eg25-manager: <https://gitlab.com/mobian1/eg25-manager>
# - used by sxmo, in <configs/default_hooks/sxmo_hook_restart_modem_daemons.sh>
# - requires modemmanager (ModemManager.service)
{ config, lib, pkgs, ... }:
let
cfg = config.sane.services.eg25-manager;
eg25-config-toml = pkgs.writeText "eg25-manager-config.toml" ''
# config here is applied *on top of* the per-device configs shipped by eg25-manager.
# these values take precedence, but there's no need to redefine things if we don't want them changed
[at]
uart = "/dev/ttyUSB2"
'';
in
{
options.sane.services.eg25-manager = with lib; {
enable = mkEnableOption "Quectel EG25 modem manager service";
package = mkOption {
type = types.package;
default = pkgs.eg25-manager;
};
};
config = lib.mkIf cfg.enable {
# eg25-manager package ships udev rules *and* a systemd service.
# for that reason, i think it needs to be on the system path for the systemd service to be enabled.
services.udev.packages = [ cfg.package ];
# but actually, let's define our own systemd service so that we can control config
systemd.services.eg25-manager = {
serviceConfig = {
Type = "simple";
ExecStart = "${cfg.package}/bin/eg25-manager --config ${eg25-config-toml}";
ExecStartPre = pkgs.writeShellScript "unload-modem-power" ''
# see issue: <https://gitlab.com/mobian1/eg25-manager/-/issues/38>
${pkgs.kmod}/bin/modprobe -r modem_power && echo "WARNING: kernel configured with CONFIG_MODEM_POWER=y, may be incompatible with eg25-manager" || true
'';
Restart = "on-failure";
RestartSec = "60s"; # can make this more frequent once stable?
# sandboxing (taken from the service file shipped by eg25-manager):
# TODO: this is too strict and breaks access to e.g. /dev/ttyUSB2!
# ProtectControlGroups = true;
# ProtectHome = true;
# ProtectSystem = "strict";
# RestrictSUIDSGID = true;
# PrivateTmp = true;
# MemoryDenyWriteExecute = true;
# PrivateMounts = true;
# NoNewPrivileges = true;
# CapabilityBoundingSet = [ "" ];
# LockPersonality = true;
};
before = [ "ModemManager.service" ];
wantedBy = [ "multi-user.target" ];
};
# systemd.packages = [ pkgs.eg25-manager ];
# systemd.services.eg25-manager.wantedBy = [ "multi-user.target" ];
# systemd.services.prepare-eg25-manager = {
# description = "unload megi's modem_power module to provide gpio access to eg25-manager";
# serviceConfig.Type = "oneshot";
# wantedBy = [ "eg25-manager.service" ];
# before = [ "eg25-manager.service" ];
# script = ''
# ${pkgs.kmod}/bin/modprobe -r modem_power && echo "WARNING: kernel configured with CONFIG_MODEM_POWER=y, may be incompatible with eg25-manager" || true
# '';
# };
};
}

View File

@@ -19,19 +19,6 @@ let
// (if title != null then { name = title; } else {}) // (if title != null then { name = title; } else {})
); );
in [ in [
# (fetchpatch' {
# # disabled, at least until the PR is updated to use `pkg-config` instead of `pkgconfig`.
# # the latter is an alias, which breaks nix-index
# title = "phog: init at 0.1.3";
# prUrl = "https://github.com/NixOS/nixpkgs/pull/251249";
# hash = "sha256-e38Z7sO7xDQHzE9UOfbptc6vJuONE5eP9JFp2Nzx53E=";
# })
(fetchpatch' {
title = "nixos/update-users-groups: fix cross compilation";
prUrl = "https://github.com/NixOS/nixpkgs/pull/251850";
hash = "sha256-uqx9sJ1zkwys9Ur35iXY3gZKVb52wlnBGkhBB5sc6WQ=";
})
# (fetchpatch' { # (fetchpatch' {
# # TODO: check back in on this around 2023-10-01 # # TODO: check back in on this around 2023-10-01
@@ -157,52 +144,12 @@ in [
# hash = "sha256-MNG8C0OgdPnFQ8SF2loiEhXJuP2z4n9pkXr8Zh4X7QU="; # hash = "sha256-MNG8C0OgdPnFQ8SF2loiEhXJuP2z4n9pkXr8Zh4X7QU=";
# }) # })
# 2023-08-06: conky wayland + cross compilation patches.
# nix path-info shows clean
# branch is wip-conky-cross2 on servo
# factoring out those feature abstractions was possibly overkill.
# the manual wayland-scanner patching is unfortunate, but within
# acceptable norms of the existing package.
(fetchpatch' { (fetchpatch' {
title = "conky: factor out an abstraction for feature flags"; title = "conky: support wayland";
saneCommit = "3ddf13038d6df90ad0db36a41d55e4077818a3e9"; # saneCommit = "82978099c3a0d5fb4925351da1b0e2598503dc6c";
hash = "sha256-CjLzndFEH1Ng9CqKX8gxCJ6n/wFv5U/sHnQE0FMYILc="; # hash = "sha256-lnDGEDhmeOIXfFnizEIVUiUzI7nMvpoCERbdjhR+Bto=";
}) saneCommit = "3ad928e20b498444e3a106b182e09317cea9a11f";
(fetchpatch' { hash = "sha256-lvIASvQWVFbjHsQwO2EhEBUTSq1UkHvriaZZ2iS0ulU=";
title = "conky: simplify the features even more";
saneCommit = "1c4aa404743f1ae7d5b95f18a96c4057ca251a96";
hash = "sha256-0zhiw9siIkFgFW4sow+X88NBEa3ggCe1t1HJ5xFH4ac=";
})
(fetchpatch' {
title = "conky: support cross compilation";
saneCommit = "01e607e11c7e5bbbfe6ad132fb72394ec29dab0a";
hash = "sha256-Bm/XFLvE7gEyLPlBWNSAcU3qwwqKLIRdpoe0/1aHUho=";
})
(fetchpatch' {
title = "conky: add wayland support";
saneCommit = "84c51f67e02ebc7f118fd3171bd10f1978d4f1e6";
hash = "sha256-gRYbkzCe3q1R7X/FeOcz/haURQkeAfmED1/ZQlCCdWE=";
})
(fetchpatch' {
title = "conky: remove no-op sed patch";
saneCommit = "e8b19984a2858ca24b7e8f5acd20be8b7dfe1af0";
hash = "sha256-K3mG1kcyB7sQZ7ZRCdlinNsV6mCcl3eIUI2ldSmcbJE=";
})
# (fetchpatch' {
# title = "gtk3: compile schemas even when cross compiling";
# saneCommit = "5ee69670071f583bdffe2718dc46763fa1698f92";
# hash = "sha256-ZX3lY63qUW2XuwCoxffbLYoFxckDImKy+S8mqlYJcvk=";
# })
# (fetchpatch' {
# title = "gtk4: compile schemas even when cross compiling";
# saneCommit = "7a1c5e3a5d1ff82c8afa659c7f903d5309d5de6a";
# hash = "sha256-Tz8NBcIqGE9rCqbOrixgbvApYDEAHWCg4lZbklL/xXc=";
# })
(fetchpatch' {
title = "gtk{3,4}: compile schemas even when cross compiling";
prUrl = "https://github.com/NixOS/nixpkgs/pull/247844";
hash = "sha256-1CsjLgMvX0Lx500UDzal5HZi78hb7zBcb+AlNPF6NvA=";
}) })
# (fetchpatch' { # (fetchpatch' {
@@ -224,7 +171,16 @@ in [
# includes hare-json and hare-ev as pre-reqs # includes hare-json and hare-ev as pre-reqs
title = "bonsai: init at 1.0.0"; title = "bonsai: init at 1.0.0";
prUrl = "https://github.com/NixOS/nixpkgs/pull/233892"; prUrl = "https://github.com/NixOS/nixpkgs/pull/233892";
hash = "sha256-HaTr7GBCfK1I2e7K4k2dUGZ6hZf4PwtEFobLaSz262M="; hash = "sha256-f7tdHz0lFsSJO8C0saMuG8e7VzSx8XDy/UXjbqWHP9M=";
})
# make alsa-project members overridable
(fetchpatch' {
title = "alsa-project: expose the scope as a top-level package to support overrides";
prUrl = "https://github.com/NixOS/nixpkgs/pull/246656";
saneCommit = "28f76deae50cc53f5f6a5e846e04426357b8ce2e";
# hash = "sha256-dBWStotLBa4LN7JmriTzoFX3/SQr/qxGO8glv3MNyZQ=";
hash = "sha256-QvurEnupAdPVVnHYl4DC1OqJronGt31REkTJO/alr60=";
}) })
# pin to a pre-0.17.3 release # pin to a pre-0.17.3 release
@@ -244,12 +200,13 @@ in [
hash = "sha256-38sND/UNRj5WAYYKpzdrRBIOK4UAT14RzbIv49KmNNw="; hash = "sha256-38sND/UNRj5WAYYKpzdrRBIOK4UAT14RzbIv49KmNNw=";
}) })
# (fetchpatch' { (fetchpatch' {
# title = "mepo: 1.1 -> 1.1.2"; # TODO: send this upstream!
# prUrl = "https://github.com/NixOS/nixpkgs/pull/247866"; title = "mepo: 1.1 -> 1.1.2";
# saneCommit = "eee68d7146a6cd985481cdd8bca52ffb204de423"; saneCommit = "eee68d7146a6cd985481cdd8bca52ffb204de423";
# hash = "sha256-uNerTwyFzivTU+o9bEKmNMFceOmy2AKONfKJWI5qkzo="; hash = "sha256-uNerTwyFzivTU+o9bEKmNMFceOmy2AKONfKJWI5qkzo=";
# }) })
(fetchpatch' { (fetchpatch' {
title = "gthumb: make the webservices feature be optional"; title = "gthumb: make the webservices feature be optional";
@@ -264,6 +221,23 @@ in [
hash = "sha256-rD0es4uUbaLMrI9ZB2HzPmRLyu/ixNBLAFyDJtFHNko="; hash = "sha256-rD0es4uUbaLMrI9ZB2HzPmRLyu/ixNBLAFyDJtFHNko=";
}) })
(fetchpatch' {
title = "p11-kit: build with meson";
prUrl = "https://github.com/NixOS/nixpkgs/pull/244633";
hash = "sha256-+z6hosSyt6ynLpUKS0TsHRoLOS8ck/SK9Y7W2zVUnCQ=";
})
(fetchpatch' {
title = "p11-kit: use mesonEmulatorHook for cross compilation";
prUrl = "https://github.com/NixOS/nixpkgs/pull/245124";
hash = "sha256-8NqqLBbjt1fLj4ZYhat7wPqQSv/aez9IwgSK2b4CfW8=";
})
(fetchpatch' {
title = "python310Packages.gssapi: support cross compilation";
prUrl = "https://github.com/NixOS/nixpkgs/pull/247048";
saneCommit = "4766ae46f863734fbe96dc4e537870b6b3894cf4";
hash = "sha256-7JZqAlcNFP6orJZCEqe5eodVxTUHeSLGyniRvw/+PuQ=";
})
# (fetchpatch' { # (fetchpatch' {
# title = "perlPackages.FileBaseDir: 0.08 -> 0.09"; # title = "perlPackages.FileBaseDir: 0.08 -> 0.09";
# saneCommit = "acc990b04bbe8c99587eadccc65f100c326ec204"; # saneCommit = "acc990b04bbe8c99587eadccc65f100c326ec204";
@@ -275,13 +249,10 @@ in [
# hash = "sha256-fAZpduh3JZeFixJ4yX0wkh/GRp0gYKsTT+XkNdpK7CU="; # hash = "sha256-fAZpduh3JZeFixJ4yX0wkh/GRp0gYKsTT+XkNdpK7CU=";
# }) # })
(fetchpatch' { (fetchpatch' {
# TODO: split this apart for easier reviewing:
# - perlPackages.TestFile 1.443 -> 1.993
# - perlPackages.FileBaseDir 0.08 -> 0.09
title = "xdg-utils: enable cross compilation"; title = "xdg-utils: enable cross compilation";
prUrl = "https://github.com/NixOS/nixpkgs/pull/246954"; prUrl = "https://github.com/NixOS/nixpkgs/pull/246954";
saneCommit = "b7aa5e0c1ec06723cf1594de192703a65be21497"; saneCommit = "b7aa5e0c1ec06723cf1594de192703a65be21497";
hash = "sha256-5iYzyjVlye7mhwhlZOHucVod/aPT3OrXolC9jAnB544="; hash = "sha256-jA84RKt4nOEZsBlACaqa0GeBiDdFOBYARgAq4NgTqtY=";
}) })
# (fetchpatch' { # (fetchpatch' {
# # N.B.: duplicates outstanding, merged PR: <https://github.com/NixOS/nixpkgs/pull/246362> # # N.B.: duplicates outstanding, merged PR: <https://github.com/NixOS/nixpkgs/pull/246362>
@@ -290,16 +261,69 @@ in [
# saneCommit = "4dc30718fe01e9dbed4ffc2ff375148da218e86b"; # saneCommit = "4dc30718fe01e9dbed4ffc2ff375148da218e86b";
# hash = "sha256-Nb2LphSyv8Dayqfwqfua0eKtNzsnaf7PC/KYUhIvnT8="; # hash = "sha256-Nb2LphSyv8Dayqfwqfua0eKtNzsnaf7PC/KYUhIvnT8=";
# }) # })
(fetchpatch' {
title = "gupnp: fix cross compilation";
prUrl = "https://github.com/NixOS/nixpkgs/pull/246931";
saneCommit = "3af24c9e517689d048bb62511c6e8acf9bc55684";
# hash = "sha256-6yl6I/zOcUe0TDKEi/vjEzyU4OWoGi0PMht3VOKWmQo=";
hash = "sha256-NYA72+liKZXnUoAGor3MR62YmZNsNPJ3SEfWGhpeiY4=";
})
(fetchpatch' { (fetchpatch' {
title = "blueman: support cross compilation"; title = "blueman: support cross compilation";
saneCommit = "e070195bdf213dffb0164574397b6a7417f81c9e"; saneCommit = "e070195bdf213dffb0164574397b6a7417f81c9e";
hash = "sha256-6JnIJCVBbV4tmFinX7Qv2wO2AThrgxrnyb9T4Ov6p5w="; hash = "sha256-6JnIJCVBbV4tmFinX7Qv2wO2AThrgxrnyb9T4Ov6p5w=";
}) })
# (fetchpatch' {
# # N.B.: duplicates merged PR: <https://github.com/NixOS/nixpkgs/pull/246369>
# title = "tracker: support cross compilation";
# saneCommit = "bea390fd0c4fda96db5b1fad06ee071a10561305";
# hash = "sha256-Y2tVoTvSIIT9ufghqqsXgmqWq9daH+WKj4JHZgWbWwE=";
# })
(fetchpatch' { (fetchpatch' {
title = "tracker-miners: support cross compilation"; title = "tracker-miners: support cross compilation";
saneCommit = "24b062309ea8baa2d8303c0610c9ec7b8c399e8b"; saneCommit = "24b062309ea8baa2d8303c0610c9ec7b8c399e8b";
hash = "sha256-Jj+1z2DeCEY+DqI1J4vYjYJwDDMRcA93CqpZSXzG0wE="; hash = "sha256-Jj+1z2DeCEY+DqI1J4vYjYJwDDMRcA93CqpZSXzG0wE=";
}) })
(fetchpatch' {
# alternate fix for upower; Arturrin
title = "upower: Fix cross";
prUrl = "https://github.com/NixOS/nixpkgs/pull/247031";
hash = "sha256-Skn1dO+SDXbrWYWn8QpSBzYaTis/KUXLEY+pJxO9pWM=";
})
# (fetchpatch' {
# # PR also includes the nativeBuildInputs fix
# title = "upower: fix cross compilation";
# prUrl = "https://github.com/NixOS/nixpkgs/pull/246945";
# saneCommit = "3ab262456acc016c8dc834df1d1f7e61a00e01e3";
# # hash = "sha256-kTFZVu9oDiYH4W4SoQQj0pNuo9hTJk6jUy+hy34HUtA=";
# hash = "sha256-PpC9YRMqg/wPfFgAPNV80mwbZWCKxNi4agxNf0yQutI=";
# })
# (fetchpatch' {
# title = "upower: don't pass unnecessary nativeBuildInputs";
# saneCommit = "e2cbfb1bc81afadc5d31c18d43e774fa9a985f98";
# hash = "sha256-7Q9Fjp7xrw3e887inc5cc01OvuOhThnVYduSLNtv2d0=";
# })
(fetchpatch' {
title = "iio-sensor-proxy: support cross compilation";
prUrl = "https://github.com/NixOS/nixpkgs/pull/246947";
saneCommit = "dc1c3341fef6c64d5fbc983670819cf7932f5be1";
# hash = "sha256-lSVGjNepRLMfLgaAG3zv/BfoEhJg8yX7EqaCgu8/b8I=";
hash = "sha256-0rO+qkWgdrZsuHnoRdQ0SqEEW+PYcJaLixrOgJSOssk=";
})
(fetchpatch' {
title = "mpvScripts.mpris: support cross compilation";
prUrl = "https://github.com/NixOS/nixpkgs/pull/247087";
saneCommit = "f7cd92e2afa26852ccf53f8ca59c13d82bf7bf64";
# hash = "sha256-MB3qloOW4pXZmbCIVsUKP2DnPoePmBf+qRc2x/o+nDw=";
hash = "sha256-uMbnfO0WY2/AFpvvnHQGKVSTE2rPrm3SCef4f04Bt78=";
})
(fetchpatch' {
title = "wvkbd: support cross compilation";
prUrl = "https://github.com/NixOS/nixpkgs/pull/247083";
saneCommit = "34379f5770662b483ab0cbe252cf23dd663d84dc";
# hash = "sha256-Duim5hPBtfGePBte29ZUtojyRAts9lQlbleUsTJNkwI=";
hash = "sha256-aC7zEM4pV4YXh5X0m2nYAkH0vLgVTNq8bgIP8CLZy4I=";
})
(fetchpatch' { (fetchpatch' {
title = "clapper: support cross compilation"; title = "clapper: support cross compilation";
saneCommit = "8a171b49aca406f8220f016e56964b3fae53a3df"; saneCommit = "8a171b49aca406f8220f016e56964b3fae53a3df";
@@ -338,33 +362,24 @@ in [
hash = "sha256-cGhJSby0K+e1hKPdPZjLFRKvwjGaTbq/kb6Fxj2v8g8="; hash = "sha256-cGhJSby0K+e1hKPdPZjLFRKvwjGaTbq/kb6Fxj2v8g8=";
}) })
(fetchpatch' { (fetchpatch' {
# TODO: send for review once thie libgnt patch above is merged
title = "pidgin: support cross compilation"; title = "pidgin: support cross compilation";
saneCommit = "caacbcc54e217f5ee9281422777a7f712765f71a"; saneCommit = "caacbcc54e217f5ee9281422777a7f712765f71a";
hash = "sha256-PDCp4GOm6hWcRob4kz7qXZfxAF6YbYrESx9idoS3e/s="; hash = "sha256-PDCp4GOm6hWcRob4kz7qXZfxAF6YbYrESx9idoS3e/s=";
}) })
(fetchpatch' {
title = "dtrx: 8.5.1 -> 8.5.3";
prUrl = "https://github.com/NixOS/nixpkgs/pull/246282";
saneCommit = "eba9bbc251db942ae27f87824cae643b5f3198c2";
# hash = "sha256-wgpjUXQ/ZnRY5AJ9xOL2BToA7hDaokDiMmPkMt0Y5go=";
hash = "sha256-awUDlibmxcJcdMZeBXcWR1U+P/GCxCH/lalhwZ5Er90=";
})
# (fetchpatch' { # (fetchpatch' {
# # doesn't cleanly apply. TODO: see if this cross compiles now, thanks to <https://github.com/NixOS/nixpkgs/pull/234615> # title = "dtrx: don't double-wrap the binary";
# title = "nixos/dconf: support cross compilation"; # saneCommit = "97a9d12b6c31a58e9067eae7cdcd3f53055c124c";
# prUrl = "https://github.com/NixOS/nixpkgs/pull/249093"; # hash = "sha256-g+p96OrBOQAwwH7nwHBuM/KGeIrnBzh9u9lL0M0sYWo=";
# saneCommit = "08f7cdebc58eeaa62cb349dab57db3be7a0c073d";
# hash = "sha256-gqHUGeTQnr0f99gqEdd+VANLkWO+joLxz5I0RSarznE=";
# }) # })
(fetchpatch' {
title = "playerctl: support cross compilation";
prUrl = "https://github.com/NixOS/nixpkgs/pull/249512";
saneCommit = "67df31a8984ab3067af5b65446d2808b0aedadc6";
hash = "sha256-qY0bjMoFneC5VJ467TeiuOycLYNaVO7Xo/0fCauDZAM=";
})
(fetchpatch' {
title = "libgweather: enable introspection on cross builds";
prUrl = "https://github.com/NixOS/nixpkgs/pull/251956";
saneCommit = "7a2d0a90cc558ea71dfc78356e61b0675b995634";
hash = "sha256-tjO19dXVUrD+V+YpD7z3iWSgNyOirG70HuQ+c+0fZYA=";
})
# (fetchpatch' { # (fetchpatch' {
# # N.B.: compiles, but runtime error on launch suggestive of some module not being shipped # # N.B.: compiles, but runtime error on launch suggestive of some module not being shipped
# title = "matrix-appservice-irc: 0.38.0 -> 1.0.0"; # title = "matrix-appservice-irc: 0.38.0 -> 1.0.0";

File diff suppressed because it is too large Load Diff

View File

@@ -63,19 +63,6 @@ in {
"pyarrow/tests/test_flight.py" "pyarrow/tests/test_flight.py"
]; ];
}); });
# 2023/08/09: unclear why it fails; probably can remove after next nixpkgs update
pillow = py-prev.pillow.overridePythonAttrs (_upstream: {
format = "setuptools";
});
seaborn = py-prev.seaborn.overridePythonAttrs (upstream: {
# 2023/08/09
disabledTestPaths = (upstream.disabledTestPaths or []) ++ [
"tests/test_categorical.py"
"tests/test_core.py"
];
});
}) })
]; ];

View File

@@ -1,45 +1,27 @@
# personal preferences # personal preferences
# prefer to encode these in `sane.programs` # prefer to encode these in `sane.programs`
# resort to this method for e.g. system dependencies, or things which are referenced from too many places. # resort to this method for e.g. system dependencies, or things which are referenced from too many places.
(self: super: with self; { (next: prev: {
gnome = super.gnome.overrideScope' (gself: gsuper: with gself; { pipewire = prev.pipewire.override {
evolution-data-server = gsuper.evolution-data-server.override {
# OAuth depends on webkitgtk_4_1: old, forces an annoying recompilation
enableOAuth2 = false;
gnome-online-accounts = gnome-online-accounts.override {
# avoid webkitgtk_4_1 build
enableBackend = false;
};
};
# gnome-shell = gsuper.gnome-shell.override {
# evolution-data-server-gtk4 = evolution-data-server-gtk4.override {
# # avoid webkitgtk_6_0 build. lol.
# withGtk4 = false;
# };
# };
});
phog = super.phog.override {
# disable squeekboard because it takes 20 minutes to compile when emulated
squeekboard = null;
};
pipewire = super.pipewire.override {
# avoid a dep on python3.10-PyQt5, which has mixed qt5 versions. # avoid a dep on python3.10-PyQt5, which has mixed qt5 versions.
# this means we lose firewire support (oh well..?) # this means we lose firewire support (oh well..?)
ffadoSupport = false; ffadoSupport = false;
}; };
pythonPackagesExtensions = super.pythonPackagesExtensions ++ [ pythonPackagesExtensions = prev.pythonPackagesExtensions ++ [
(pySelf: pySuper: { (pySelf: pySuper: {
# TODO(2023/08/02): cryptography (a dependency of komikku -> keyring -> secretstorage -> cryptography) doesn't cross compile
# so disable it. can be re-enabled in next staging -> master merge.
# see:
# - <https://github.com/NixOS/nixpkgs/pull/245287/files>
# - <https://github.com/NixOS/nixpkgs/pull/244135>
keyring = (pySuper.keyring.override { keyring = (pySuper.keyring.override {
# jaraco-classes doesn't cross compile, but it looks like `keyring` secretstorage = null;
# has some _temporary_ fallback logic for when jaraco-classes isn't jeepney = null;
# installed (i.e. may break in future).
jaraco-classes = null;
}).overrideAttrs (upstream: { }).overrideAttrs (upstream: {
postPatch = (upstream.postPatch or "") + '' postPatch = (upstream.postPatch or "") + ''
sed -i /jaraco.classes/d setup.cfg sed -i /SecretStorage/d setup.cfg
sed -i /jeepney/d setup.cfg
''; '';
}); });
}) })

View File

@@ -18,21 +18,6 @@ stdenv.mkDerivation rec {
hash = "sha256-jOtFUpl2/Aa7f8JMZf6g63ayFOi+Ci+i7Ac63k63znc="; hash = "sha256-jOtFUpl2/Aa7f8JMZf6g63ayFOi+Ci+i7Ac63k63znc=";
}; };
postPatch = ''
substituteInPlace Makefile \
--replace 'hare build' 'hare build $(HARE_TARGET_FLAGS)'
'';
env.HARE_TARGET_FLAGS =
if stdenv.hostPlatform.isAarch64 then
"-t aarch64"
else if stdenv.hostPlatform.isRiscV64 then
"-t riscv64"
else if stdenv.hostPlatform.isx86_64 then
"-t x86_64"
else
"";
nativeBuildInputs = [ nativeBuildInputs = [
hare hare
hare-ev hare-ev
@@ -46,7 +31,7 @@ stdenv.mkDerivation rec {
# export ARFLAGS="-csr" # export ARFLAGS="-csr"
''; '';
installFlags = [ "PREFIX=$(out)" ]; installFlags = [ "PREFIX=" "DESTDIR=$(out)" ];
passthru.updateScript = gitUpdater { passthru.updateScript = gitUpdater {
rev-prefix = "v"; rev-prefix = "v";

View File

@@ -1,6 +0,0 @@
{ static-nix-shell }:
static-nix-shell.mkPython3Bin {
pname = "eg25-control";
src = ./.;
pkgs = [ "curl" "modemmanager" ];
}

View File

@@ -1,429 +0,0 @@
#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ])" -p curl -p modemmanager
# this script should run after ModemManager.service is started.
# typical invocation is `eg25_gps_init.py --enable-power --enable-gps`.
# after running, the user may `cat /dev/ttyUSB1` to view NMEA-encoded GPS information.
# the script attempts to be idempotent, such that it may be run multiple times per boot.
#
# this script downloads assisted GPS (AGPS) data via the system's default gateway (i.e. WiFi)
# and shares that with the modem. this quickens the process of acquiring a GPS fix.
#
# the script may also configure other parts of the modem as `eg25-manager` does.
# these options are less tested: see `--help` for more.
#
# PREREQUISITES/DEPENDENCIES:
# this script expects to run on megi's kernel, with `CONFIG_MODEM_POWER=y`.
# ModemManager must be launched with the `--debug` flag, so that `mmcli --command=...` works.
#
# ModemManager, and by extension this script, REQUIRES A SIM CARD IN YOUR PHONE.
# the sim doesn't need to be "activated". you can buy a $1 SIM and never purchase
# service and that works; it's just needed for ModemManager to boot the modem.
# this isn't a fundamental requirement; if one did everything via serial instead of
# ModemManager the SIM would not be necessary for GPS.
#
# EXPECTATIONS/TIPS:
# - with the right environment, you may get a GPS fix in < 30s.
# - the fix is likely to have a *lot* of jitter, like 10+ meters.
# - indoors, you shouldn't expect to *ever* get a cold-start GPS fix.
# - maybe you'll track 1 satellite if lucky: enough to receive GPS time but not for a GPS fix.
# - get a fix outdoors, then walk indoors: GPS is smart enough to maintain a spotty fix.
# - outdoors in suburbia, a fix might take 10-20 minutes.
# - i have better luck *placing my phone on the roof of my car* than holding it in the air with my hand.
# - maybe a big metal plate opposite the sky acts as a dish/antenna?
# - in Seattle, i track several GLONASS and GPS sats: about an even split.
# - the GPS sats have better SNR.
# - modem seems to not show any BeiDou or Galileo sats even if i enable them.
#
# eg25 modem/GPS docs:
# [GNSS-AP-Note]: https://wiki.pine64.org/images/0/09/Quectel_EC2x%26EG9x%26EG2x-G%26EM05_Series_GNSS_Application_Note_V1.3.pdf
#
# most acronyms are defined inline, particularly near variable/class declarations.
# glossary, for those which aren't:
#
# Global Navigation Satellite Systems (GNSS):
# - GPS (US)
# - GLONASS (RU)
# - Galileo (EU)
# - BeiDou (CN)
# ^ these are all global systems, usable outside the country that owns them
import argparse
import datetime
import logging
import subprocess
import sys
import time
POWER_ENDPOINT = "/sys/class/modem-power/modem-power/device/powered"
# GNSS-AP-Note 1.4:
# also at xtrapath5 and xtrapath6 subdomains.
# the AGPS data here is an almanac good for 7 days.
AGPS_DATA_URI_BASE = "https://xtrapath4.izatcloud.net"
class AgpsDataVariant:
# GNSS-AP-Note 1.4:
gps_glonass = "xtra2.bin"
gps_glonass_beidou = "xtra3grc.bin"
# N.B.: not supported by all Quectel modems
# on stock Pinephone, ModemManager gives "LOC service: general failure"
gps_glonass_beidou_galileo = "xtra3grcej.bin"
logger = logging.getLogger(__name__)
def destructive(fn: callable = None, return_ = None):
""" decorate `fn` so that it becomes a no-op when --dry-run is active """
def wrapped(self, *args, **kwargs):
if self.dry_run:
fmt_args = ", ".join(
[repr(a) for a in args] +
[f"{k}={v}" for k,v in kwargs.items()]
)
logger.info(f"[dry run] {fn.__name__}({fmt_args})")
return return_
else:
return fn(self, *args, **kwargs)
if fn:
return wrapped
else:
return lambda fn: destructive(fn, return_=return_)
def log_scope(at_enter: str, at_exit: str):
""" decorate a function so that it logs at start and end """
def decorator(fn: callable):
def wrapped(*args, **kwargs):
logger.info(at_enter)
ret = fn(*args, **kwargs)
logger.info(at_exit)
return ret
return wrapped
return decorator
class Executor:
def __init__(self, dry_run: bool = False):
self.dry_run = dry_run
@destructive
def write_file(self, path: str, data: bytes) -> None:
logger.debug(f"echo {data!r} > {path}")
with open(path, 'wb') as f:
f.write(data)
@destructive(return_=b'')
def exec(self, cmd: list[str], check: bool = True) -> bytes:
logger.debug(" ".join(cmd))
res = subprocess.run(cmd, capture_output=True)
logger.debug(res.stdout)
if res.stderr:
logger.warning(res.stderr)
if check:
res.check_returncode()
return res.stdout
class GNSSConfig:
# GNSS-AP-Note 2.2.7
# Supported GNSS constellations. GPS is always ON
# 0 GLONASS OFF/BeiDou OFF/Galileo OFF
# 1 GLONASS ON/BeiDou ON/Galileo ON
# 2 GLONASS ON/BeiDou ON/Galileo OFF
# 3 GLONASS ON/BeiDou OFF/Galileo ON
# 4 GLONASS ON/BeiDou OFF/Galileo OFF
# 5 GLONASS OFF/BeiDou ON/Galileo ON
# 6 GLONASS OFF/BeiDou OFF/Galileo ON
# 7 GLONASS OFF/BeiDou ON/Galileo OFF
gps = "0"
gps_glonass_beidou_galileo = "1"
gps_glonass_beidou = "2"
gps_glonass_galilego = "3"
gps_glonass = "4"
gps_beidou_galileo = "5"
gps_galileo = "6"
gps_beidou = "7"
class ODPControl:
# GNSS-AP-Note 2.2.8
# 0 Disable ODP
# 1 Low power mode
# 2 Ready mode
#
# ODP = "On-Demand Positioning"
# Low power mode:
# - low-frequency background GNSS tracking session
# - adjusts interval between 10m (when signal is good) - 60m (when signal is bad)
# Ready mode:
# - 1 Hz positioning
# - keeps GNSS ready so that when application demands position it's immediately ready
# - automatically stops positioning after 60s??
disable = "0"
lower_power_mode = "1"
ready_mode = "2"
class DPOEnable:
# GNSS-AP-Note 2.2.9
# 0 Disable DPO
# 1 Enable the DPO with dynamic duty cycle
#
# DPO = "Dynamic Power Optimization"
# automatically shuts off radio under certain conditions
# more info: <https://sixfab.com/wp-content/uploads/2018/09/Quectel_UC20_GNSS_AT_Commands_Manual_V1.1.pdf> 1.4.1
disable = "0"
enable = "1"
class GPSNMEAType:
# GNSS-AP-Note 2.2.3
# Output type of GPS NMEA sentences in ORed.
disable = 0
gpgga = 1
gprmc = 2
gpgsv = 4
gpgsa = 8
gpvtg = 16
all = 31
class GlonassNmeaType:
# GNSS-AP-Note 2.2.4
# Configure output type of GLONASS NMEA sentences in ORed
disable = 0
glgsv = 1
gngsa = 2
gngns = 4
all = 7
class GalileoNmeaType:
# GNSS-AP-Note 2.2.5
disable = 0
gagsv = 1
all = 1
class BeiDouNmeaType:
# GNSS-AP-Note 2.2.6
disable = 0
pqgsa = 1
pqgsv = 2
all = 3
class AutoGps:
# GNSS-AP-Note 2.2.12
# Enable/disable GNSS to run automatically after the module is powered on.
disable = "0"
enable = "1"
class Sequencer:
AGPS_DATA_URI_BASE = AGPS_DATA_URI_BASE
def __init__(self, executor: Executor, modem: str, power_endpoint: str):
self.executor = executor
self.modem = modem
self.power_endpoint = power_endpoint
def _mmcli(self, args: list[str], check: bool = True) -> str:
return self.executor.exec(
["mmcli", "--modem", self.modem] + args,
check=check
).decode('utf-8')
def _try_mmcli(self, args: list[str]) -> str:
try:
return self._mmcli(args)
except subprocess.CalledProcessError:
return None
def _at_cmd(self, cmd: str, check: bool = True) -> str:
# this returns the mmcli output, which looks like:
# response: 'blah'
# i.e., quoted, and with a `response: ` prefix
return self._mmcli([f"--command=+{cmd}"], check=check)
def _at_structured_cmd(self, cmd: str, subcmd: str | None = None, value: str | None = None, check: bool = True) -> str:
if not subcmd and not value:
return self._at_cmd(cmd, check=check)
elif not subcmd and value:
return self._at_cmd(f"{cmd}={value}", check=check)
elif subcmd and not value:
return self._at_cmd(f"{cmd}=\"{subcmd}\"", check=check)
else:
return self._at_cmd(f"{cmd}=\"{subcmd}\",{value}", check=check)
def _at_gnssconfig(self, cfg: GNSSConfig) -> str:
return self._at_structured_cmd("QGPSCFG", "gnssconfig", cfg)
def _at_odpcontrol(self, control: ODPControl) -> str:
return self._at_structured_cmd("QGPSCFG", "odpcontrol", control)
def _at_dpoenable(self, enable: DPOEnable) -> str:
return self._at_structured_cmd("QGPSCFG", "dpoenable", enable)
def _at_gpsnmeatype(self, ty: GPSNMEAType) -> str:
return self._at_structured_cmd("QGPSCFG", "gpsnmeatype", str(ty))
def _at_glonassnmeatype(self, ty: GlonassNmeaType) -> str:
return self._at_structured_cmd("QGPSCFG", "glonassnmeatype", str(ty))
def _at_galileonmeatype(self, ty: GalileoNmeaType) -> str:
return self._at_structured_cmd("QGPSCFG", "galileonmeatype", str(ty))
def _at_beidounmeatype(self, ty: BeiDouNmeaType) -> str:
self._at_structured_cmd("QGPSCFG", "beidounmeatype", str(ty))
def _at_autogps(self, enable: AutoGps) -> str:
return self._at_structured_cmd("QGPSCFG", "autogps", enable)
def _get_assistance_data(self, variant: AgpsDataVariant) -> str | None:
try:
self.executor.exec(["curl", f"{self.AGPS_DATA_URI_BASE}/{variant}", "-o", variant])
return variant
except subprocess.CalledProcessError as e:
logger.warning(f"AGPS data download failed: {e}")
return None # TODO: could be smarter: return cached AGPS data?
@log_scope("powering modem...", "modem powered")
def power_on(self) -> None:
self.executor.write_file(self.power_endpoint, b'1')
while self._try_mmcli([]) is None:
logger.info("modem hasn't appeared: sleeping for 1s")
time.sleep(1) # wait for modem to appear
def at_check(self) -> None:
""" sanity check that the modem is listening for AT commands and responding reasonably """
hw = self._at_cmd("QGMR")
assert 'EG25GGBR07A08M2G' in hw or self.executor.dry_run, hw
def dump_debug_info(self) -> None:
logger.debug('checking if AGPS is enabled (1) or not (0)')
self._at_structured_cmd('QGPSXTRA?')
# see if the GPS assistance data is still within valid range
logger.debug('QGPSXTRADATA: <valid_duration_minutes>,<start_time_of_agps_data>')
self._at_structured_cmd('QGPSXTRADATA?')
logger.debug('checking what time the modem last synchronized with the network')
self._at_structured_cmd('QLTS')
logger.debug('checking what time the modem thinks it is (extrapolated from sync)')
self._at_structured_cmd('QLTS', value=1)
logger.debug('checking what time the modem thinks it is (from RTC)')
self._at_structured_cmd('CCLK?')
logger.debug('checking if nmea GPS source is enabled')
self._at_structured_cmd('QGPSCFG', 'nmeasrc')
logger.debug('checking if GPS is enabled (1) or not (0)')
self._at_structured_cmd('QGPS?')
logger.debug('checking if GPS has a fix. Error 516 if not')
self._at_structured_cmd('QGPSLOC', value='0', check=False)
logger.debug('dumping AGPS positioning mode bitfield')
self._at_structured_cmd('QGPSCFG', 'agpsposmode')
@log_scope("configuring audio...", "audio configured")
def enable_audio(self) -> None:
# cribbed from eg25-manager; i don't understand these
# QDAI call shouldn't be necessary if using Megi's FW:
# - <https://xnux.eu/devices/feature/modem-pp.html>
self._at_structured_cmd("QDAI", value="1,1,0,1,0,0,1,1")
# RI signaling using physical RI pin
self._at_structured_cmd("QCFG", "risignaltype", "\"physical\"")
# Enable VoLTE support
self._at_structured_cmd("QCFG", "ims", "1")
# Enable APREADY for PP 1.2
self._at_structured_cmd("QCFG", "apready", "1,0,500")
@log_scope("configuring urc...", "urc configured")
def enable_urc(self) -> None:
# cribbed from eg25-manager; i don't even know what URC is
# URC configuration for PP 1.2 (APREADY pin connected):
# * RING URC: normal pulse length
# * Incoming SMS URC: default pulse length
# * Other URC: default length
# * Report URCs on all ports (serial and USB) for FOSS firmware
# * Reporting of URCs without any delay
# * Configure URC pin to UART Ring Indicator
self._at_structured_cmd("QCFG", "urc/ri/ring", "\"pulse\",120,1000,5000,\"off\",1")
self._at_structured_cmd("QCFG", "urc/ri/smsincoming", "\"pulse\",120,1")
self._at_structured_cmd("QCFG", "urc/ri/other", "\"off\",1,1")
self._at_structured_cmd("QCFG", "urc/delay", "0")
self._at_structured_cmd("QCFG", "urc/cache", "0")
self._at_structured_cmd("QCFG", "urc/ri/pin", "uart_ri")
self._at_structured_cmd("QURCCFG", "urcport", "\"all\"")
@log_scope("configuring gps...", "gps configured")
def enable_gps(self) -> None:
# set modem to use UTC time instead of local time.
# modemmanager sends CTZU=3 during init and that causes `AT+CCLK?` to return a timestamp that's off by 600+ days
# see: <https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/issues/360>
self._at_structured_cmd("CTZU", value="1")
# disable GNSS, because it's only configurable while offline
self._at_structured_cmd("QGPSEND", check=False)
# self._at_structured_cmd("QGPS", value="0")
# XXX: ModemManager plugin sets QGPSXTRA=1
# self._at_structured_cmd("QGPSXTRA", value="1")
# now = datetime.datetime.now().strftime('%Y/%m/%d,%H:%M:%S') # UTC
# self._at_structured_cmd("QGPSXTRATIME", value=f"0,\"{now}\"")
locdata = self._get_assistance_data(AgpsDataVariant.gps_glonass_beidou)
if locdata:
self._mmcli([f"--location-inject-assistance-data={locdata}"])
self._at_gnssconfig(GNSSConfig.gps_glonass_beidou_galileo)
self._at_odpcontrol(ODPControl.disable)
self._at_dpoenable(DPOEnable.disable) # N.B.: eg25-manager uses `DPOEnable.enable`
self._at_gpsnmeatype(GPSNMEAType.all)
self._at_glonassnmeatype(GlonassNmeaType.all)
self._at_galileonmeatype(GalileoNmeaType.all)
self._at_beidounmeatype(BeiDouNmeaType.all)
self._at_autogps(AutoGps.disable) #< don't start GPS on modem boot
# configure so GPS output is readable via /dev/ttyUSB1
# self._mmcli(["--location-enable-gps-unmanaged"])
# TODO: tune/document these QGPS values; a smarter setting here might reduce jitter?
self._at_structured_cmd("QGPS", value="1,255,1000,0,1")
@log_scope("configuring powersave...", "powersave configured")
def enable_powersave(self) -> None:
# Allow sleeping for power saving
self._at_structured_cmd("QSCLK", value="1")
# Disable fast poweroff for stability
self._at_structured_cmd("QCFG", "fast/poweroff", "0")
# Configure sleep and wake up pin levels to active low
self._at_structured_cmd("QCFG", "sleepind/level", "0")
self._at_structured_cmd("QCFG", "wakeupin/level", "0,0")
# Do not enter RAMDUMP mode, auto-reset instead
self._at_structured_cmd("QCFG", "ApRstLevel", "1")
self._at_structured_cmd("QCFG", "ModemRstLevel", "1")
def main():
logging.basicConfig()
logging.getLogger().setLevel(logging.INFO)
parser = argparse.ArgumentParser(description="initialize the eg25 Pinephone modem for GPS tracking")
parser.add_argument('--modem', default='any', help='name of modem to configure (see mmcli --list-modems)')
parser.add_argument('--power-endpoint', default='/sys/class/modem-power/modem-power/device/powered', help='sysfs endpoint that can turn the modem on/off')
parser.add_argument("--dry-run", action='store_true', help="print commands instead of executing them")
parser.add_argument("--verbose", action='store_true', help="log each command before executing")
parser.add_argument('--power-on', action='store_true', help="enable power to the modem")
parser.add_argument('--enable-audio', action='store_true', help="configure audio for calling (?)")
parser.add_argument('--enable-urc', action='store_true', help="enable support for Unsolicited Return Codes (?)")
parser.add_argument('--enable-gps', action='store_true', help="enable the GPS and acquire tracking until asked to stop")
parser.add_argument('--enable-powersave', action='store_true', help="configure modem to sleep when possible")
parser.add_argument('--dump-debug-info', action='store_true', help="don't initialize anything, just dump debugging data")
args = parser.parse_args()
if args.verbose or args.dump_debug_info:
logging.getLogger().setLevel(logging.DEBUG)
executor = Executor(args.dry_run)
sequencer = Sequencer(executor, modem=args.modem, power_endpoint=args.power_endpoint)
if args.power_on:
sequencer.power_on()
if args.enable_audio:
sequencer.enable_audio()
if args.enable_urc:
sequencer.enable_urc()
if args.enable_gps:
sequencer.enable_gps()
if args.enable_powersave:
sequencer.enable_powersave()
if args.dump_debug_info:
sequencer.dump_debug_info()
if __name__ == '__main__':
main()

View File

@@ -1,77 +0,0 @@
# package based on:
# - <https://github.com/NixOS/mobile-nixos/pull/573>
{ lib
, stdenv
, callPackage
, fetchFromGitLab
, gnugrep
, meson
, ninja
, pkg-config
, scdoc
, curl
, glib
, libgudev
, libusb1
# if true, build with MMGLIB. if false, eg25-manager won't speak to modemmanager and will be usable standalone
, withModemManager ? true, modemmanager
}:
let
# eg25-manager needs to be made compatible with libgpiod 2.0 API. see:
# - <https://github.com/NixOS/mobile-nixos/pull/573#issuecomment-1666739462>
# - <https://gitlab.com/mobian1/eg25-manager/-/issues/45>
# nixpkgs libgpiod was bumped 2023-07-29:
# - <https://github.com/NixOS/nixpkgs/pull/246018>
libgpiod1 = callPackage ./libgpiod1.nix { };
in
stdenv.mkDerivation rec {
pname = "eg25-manager";
version = "0.4.6";
src = fetchFromGitLab {
owner = "mobian1";
repo = "eg25-manager";
rev = version;
hash = "sha256-2JsdwK1ZOr7ljNHyuUMzVCpl+HV0C5sA5LAOkmELqag=";
};
postPatch = ''
substituteInPlace 'udev/80-modem-eg25.rules' \
--replace '/bin/grep' '${gnugrep}/bin/grep'
'';
depsBuildBuild = [
pkg-config
];
nativeBuildInputs = [
glib # Contains gdbus-codegen program
meson
ninja
pkg-config
scdoc
];
buildInputs = [
curl
glib
libgpiod1
libgudev
libusb1
] ++ lib.optionals withModemManager [
modemmanager
];
passthru = {
inherit libgpiod1;
};
meta = with lib; {
description = "Manager daemon for the Quectel EG25 mobile broadband modem";
homepage = "https://gitlab.com/mobian1/eg25-manager";
license = licenses.gpl3Plus;
platforms = platforms.linux;
};
}

View File

@@ -1,39 +0,0 @@
{ lib, stdenv, fetchurl, autoreconfHook, autoconf-archive, pkg-config, kmod
, enable-tools ? true
, enablePython ? false, python3, ncurses }:
stdenv.mkDerivation rec {
pname = "libgpiod";
version = "1.6.4";
src = fetchurl {
url = "https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/snapshot/libgpiod-${version}.tar.gz";
hash = "sha256-gp1KwmjfB4U2CdZ8/H9HbpqnNssqaKYwvpno+tGXvgo=";
};
buildInputs = [ kmod ] ++ lib.optionals enablePython [ python3 ncurses ];
nativeBuildInputs = [
autoconf-archive
pkg-config
autoreconfHook
];
configureFlags = [
"--enable-tools=${if enable-tools then "yes" else "no"}"
"--enable-bindings-cxx"
"--prefix=${placeholder "out"}"
] ++ lib.optional enablePython "--enable-bindings-python";
meta = with lib; {
description = "C library and tools for interacting with the linux GPIO character device";
longDescription = ''
Since linux 4.8 the GPIO sysfs interface is deprecated. User space should use
the character device instead. This library encapsulates the ioctl calls and
data structures behind a straightforward API.
'';
homepage = "https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/about/";
license = licenses.lgpl2;
maintainers = [ maintainers.expipiplus1 ];
platforms = platforms.linux;
};
}

View File

@@ -1,8 +1,8 @@
{ stdenv { stdenv
, fetchFromGitHub , fetchFromGitHub
, fetchFromGitea , fetchFromGitea
, gnused
, mkYarnModules , mkYarnModules
, nodejs
, zip , zip
}: }:
@@ -25,8 +25,7 @@ let
# sha256 = "sha256-dSRZ2ToEOPhzHNvlG8qdewa7689gT8cNB7nXkN3/Avo="; # sha256 = "sha256-dSRZ2ToEOPhzHNvlG8qdewa7689gT8cNB7nXkN3/Avo=";
# }; # };
browserpass-extension-yarn-modules = mkYarnModules { browserpass-extension-yarn-modules = mkYarnModules {
inherit version; inherit pname version;
pname = "${pname}-modules";
packageJSON = ./package.json; packageJSON = ./package.json;
yarnLock = ./yarn.lock; yarnLock = ./yarn.lock;
# yarnNix is auto-generated. to update: leave unset, then query the package deps and copy it out of the store. # yarnNix is auto-generated. to update: leave unset, then query the package deps and copy it out of the store.
@@ -38,20 +37,9 @@ let
in stdenv.mkDerivation { in stdenv.mkDerivation {
inherit pname version src; inherit pname version src;
nativeBuildInputs = [ nodejs zip ];
postPatch = '' postPatch = ''
# dependencies are built separately: skip the yarn install # dependencies are built separately: skip the yarn install
# prettier, lessc, browserify are made available here via the modules, ${gnused}/bin/sed -i /yarn\ install/d src/Makefile
# which are for the host (even the devDependencies are compiled for the host).
# but we can just run those via the build node.
#
# alternative would be to patchShebangs in the node_modules dir.
substituteInPlace src/Makefile \
--replace "yarn install" "true" \
--replace ' $(PRETTIER)' ' node $(PRETTIER)' \
--replace ' $(LESSC)' ' node $(LESSC)' \
--replace ' $(BROWSERIFY)' ' node $(BROWSERIFY)'
''; '';
preBuild = '' preBuild = ''
@@ -60,12 +48,11 @@ in stdenv.mkDerivation {
installPhase = '' installPhase = ''
pushd firefox pushd firefox
zip -r $out ./* ${zip}/bin/zip -r $out ./*
popd popd
''; '';
passthru = { passthru = {
yarn-modules = browserpass-extension-yarn-modules;
extid = "browserpass@maximbaz.com"; extid = "browserpass@maximbaz.com";
}; };
} }

View File

@@ -20,10 +20,8 @@ stdenv.mkDerivation rec {
./0003-disable-metrics.patch ./0003-disable-metrics.patch
]; ];
nativeBuildInputs = [ zip ];
installPhase = '' installPhase = ''
zip -r $out ./* ${zip}/bin/zip -r $out ./*
''; '';
passthru = { passthru = {

View File

@@ -29,7 +29,7 @@ let
}; };
in (stdenv.mkDerivation ({ in (stdenv.mkDerivation ({
# heavily borrows from <repo:nixos/nixpkgs:pkgs/build-support/fetchfirefoxaddon/default.nix> # heavily borrows from <repo:nixos/nixpkgs:pkgs/build-support/fetchfirefoxaddon/default.nix>
name = "${addon.name}-wrapped"; inherit (addon) name;
unpackPhase = '' unpackPhase = ''
echo "patching firefox addon $name into $out/${extid}.xpi" echo "patching firefox addon $name into $out/${extid}.xpi"
@@ -64,7 +64,7 @@ let
''; '';
} // args')).overrideAttrs (final: upstream: { } // args')).overrideAttrs (final: upstream: {
passthru = (upstream.passthru or {}) // { passthru = (upstream.passthru or {}) // {
withAttrs = attrs: wrapAddon addon (args // attrs); withAttrs = attrs: wrapAddon final.finalPackage attrs;
withPostPatch = postPatch: final.passthru.withAttrs { inherit postPatch; }; withPostPatch = postPatch: final.passthru.withAttrs { inherit postPatch; };
# given an addon, repackage it without some `perm`ission # given an addon, repackage it without some `perm`ission
withoutPermission = perm: final.passthru.withPostPatch '' withoutPermission = perm: final.passthru.withPostPatch ''
@@ -92,9 +92,9 @@ in lib.makeScope newScope (self: with self; {
ether-metamask = fetchAddon "ether-metamask" "webextension@metamask.io" "sha256-UI83wUUc33OlQYX+olgujeppoo2D2PAUJ+Wma5mH2O0="; ether-metamask = fetchAddon "ether-metamask" "webextension@metamask.io" "sha256-UI83wUUc33OlQYX+olgujeppoo2D2PAUJ+Wma5mH2O0=";
i2p-in-private-browsing = fetchAddon "i2p-in-private-browsing" "i2ppb@eyedeekay.github.io" "sha256-dJcJ3jxeAeAkRvhODeIVrCflvX+S4E0wT/PyYzQBQWs="; i2p-in-private-browsing = fetchAddon "i2p-in-private-browsing" "i2ppb@eyedeekay.github.io" "sha256-dJcJ3jxeAeAkRvhODeIVrCflvX+S4E0wT/PyYzQBQWs=";
sidebery = fetchAddon "sidebery" "{3c078156-979c-498b-8990-85f7987dd929}" "sha256-YONfK/rIjlsrTgRHIt3km07Q7KnpIW89Z9r92ZSCc6w="; sidebery = fetchAddon "sidebery" "{3c078156-979c-498b-8990-85f7987dd929}" "sha256-YONfK/rIjlsrTgRHIt3km07Q7KnpIW89Z9r92ZSCc6w=";
sponsorblock = fetchAddon "sponsorblock" "sponsorBlocker@ajay.app" "sha256-kIVx/Yl2IZ0/0RqLMf4+HJojoDA7oOUYwZfFvMt/2XE="; sponsorblock = fetchAddon "sponsorblock" "sponsorBlocker@ajay.app" "sha256-b/OTFmhSEUZ/CYrYCE4rHVMQmY+Y78k8jSGMoR8vsZA=";
ublacklist = fetchAddon "ublacklist" "@ublacklist" "sha256-NZ2FmgJiYnH7j2Lkn0wOembxaEphmUuUk0Ytmb0rNWo="; ublacklist = fetchAddon "ublacklist" "@ublacklist" "sha256-NZ2FmgJiYnH7j2Lkn0wOembxaEphmUuUk0Ytmb0rNWo=";
ublock-origin = fetchAddon "ublock-origin" "uBlock0@raymondhill.net" "sha256-i3NGi8IzoR3SiVIZRmOBeD0ZEjhX3Qtv0WoBgg/KSDQ="; ublock-origin = fetchAddon "ublock-origin" "uBlock0@raymondhill.net" "sha256-EGGAA+cLUow/F5luNzFG055rFfd3rEyh8hTaL/23pbM=";
# TODO: build bypass-paywalls from source? it's mysteriously disappeared from the Mozilla store. # TODO: build bypass-paywalls from source? it's mysteriously disappeared from the Mozilla store.
# bypass-paywalls-clean = fetchAddon "bypass-paywalls-clean" "{d133e097-46d9-4ecc-9903-fa6a722a6e0e}" "sha256-oUwdqdAwV3DezaTtOMx7A/s4lzIws+t2f08mwk+324k="; # bypass-paywalls-clean = fetchAddon "bypass-paywalls-clean" "{d133e097-46d9-4ecc-9903-fa6a722a6e0e}" "sha256-oUwdqdAwV3DezaTtOMx7A/s4lzIws+t2f08mwk+324k=";
@@ -113,8 +113,7 @@ in lib.makeScope newScope (self: with self; {
# XXX: i tried to build sponsorblock from source and patch this *before* it gets webpack'd, # XXX: i tried to build sponsorblock from source and patch this *before* it gets webpack'd,
# but web shit is absolutely cursed and building from source requires a fucking PhD # but web shit is absolutely cursed and building from source requires a fucking PhD
# (if you have one, feel free to share your nix package) # (if you have one, feel free to share your nix package)
substituteInPlace js/background.js \ ${gnused}/bin/sed -i 's/default\.config\.userID)/default.config.userID && false)/' js/background.js
--replace 'default.config.userId)' 'default.config.userID && false)'
''; '';
ublacklist = wrapAddon unwrapped.ublacklist {}; ublacklist = wrapAddon unwrapped.ublacklist {};

View File

@@ -2,7 +2,7 @@
, fetchFromGitHub , fetchFromGitHub
, libhandy , libhandy
}: }:
gpodder.overridePythonAttrs (upstream: rec { gpodder.overrideAttrs (upstream: rec {
pname = "gpodder-adaptive"; pname = "gpodder-adaptive";
version = "3.11.1+1"; version = "3.11.1+1";
src = fetchFromGitHub { src = fetchFromGitHub {
@@ -12,21 +12,6 @@ gpodder.overridePythonAttrs (upstream: rec {
hash = "sha256-pn5sh8CLV2Civ26PL3rrkkUdoobu7SIHXmWKCZucBhw="; hash = "sha256-pn5sh8CLV2Civ26PL3rrkkUdoobu7SIHXmWKCZucBhw=";
}; };
# nixpkgs `gpodder` uses the `format = "other"` Makefile build flow.
# upstream specifies a Makefile, and it's just `setup.py` calls plus a few other deps.
# however, it calls the build Python, which breaks for cross compilation.
# nixpkgs knows how to cross-compile setuptools formats, so use that and only mimic the
# parts of the Makefile that aren't part of that.
# TODO: upstream this into main nixpkgs `gpodder` package.
format = "setuptools";
preBuild = ''
make \
"PREFIX=$(out)" \
"share/applications/gpodder-url-handler.desktop" \
"share/applications/gpodder.desktop" \
"share/dbus-1/services/org.gpodder.service"
'';
buildInputs = upstream.buildInputs ++ [ buildInputs = upstream.buildInputs ++ [
libhandy libhandy
]; ];

File diff suppressed because it is too large Load Diff

View File

@@ -13,13 +13,13 @@
rustPlatform.buildRustPackage rec { rustPlatform.buildRustPackage rec {
pname = "lemoa"; pname = "lemoa";
version = "0.4.0"; version = "0.3.0";
src = fetchFromGitHub { src = fetchFromGitHub {
owner = "lemmy-gtk"; owner = "lemmy-gtk";
repo = pname; repo = pname;
rev = "v${version}"; rev = "v${version}";
hash = "sha256-0xMdshQ12mV93r5UwxRLgYsIj97GgxmDDMEisam29HI="; hash = "sha256-LT+UkjDkKbi327SE4VT+BdrpE6hQywajIZ7xpJPvvCc=";
}; };
cargoLock = { cargoLock = {

View File

@@ -1,37 +0,0 @@
{ linux_6_4
, fetchpatch
, pkgs
# something inside nixpkgs calls `override` on the kernel and passes in extra arguments; we'll forward them
, ...
}@args:
let
# use the latest commit: for linux 6.4.7
# manjaro's changes between kernel patch versions tend to be minimal if any.
manjaroBase = "https://gitlab.manjaro.org/manjaro-arm/packages/core/linux/-/raw/6c64aa18076a7dc75bfd854b27906467f5d95336";
manjaroPatch = args: {
inherit (args) name;
patch = fetchpatch ({
url = "${manjaroBase}/${args.name}?inline=false";
} // args);
};
# the idea for patching off Manjaro's kernel comes from jakewaksbaum:
# - https://git.sr.ht/~jakewaksbaum/pi/tree/af20aae5653545d6e67a459b59ee3e1ca8a680b0/item/kernel/default.nix
# - he later abandoned this, i think because he's using the Pinephone Pro which received mainline support.
manjaroPatches = [
(manjaroPatch {
# this patch is critical to enable wifi (RTL8723CS)
# - the alternative is a wholly forked kernel by megi/megous:
# - https://xnux.eu/howtos/build-pinephone-kernel.html#toc-how-to-build-megi-s-pinehpone-kernel
# - i don't know if this patch is based on megi's or original.
# - it might be possible to build this rtl8723cs out of tree?
name = "2001-staging-add-rtl8723cs-driver.patch";
hash = "sha256-M4MR9Oi90BmaB68kWjezHon/NzXDxu13Hc+TWm3tcjg=";
})
];
in linux_6_4.override (args // {
kernelPatches = (args.kernelPatches or []) ++ [
pkgs.kernelPatches.bridge_stp_helper
pkgs.kernelPatches.request_key_helper
] ++ manjaroPatches;
})

View File

@@ -1,11 +1,11 @@
{ lib { lib
, buildLinux , buildLinux
, fetchpatch , buildPackages
, fetchFromGitHub , fetchFromGitHub
, modDirVersionArg ? null
, nixosTests
, perl
, pkgs , pkgs
# modem_power is incompatible with eg25-manager: <https://gitlab.com/mobian1/eg25-manager/-/issues/38>
, withModemPower ? true
# something inside nixpkgs calls `override` on the kernel and passes in extra arguments
, ... , ...
} @ args: } @ args:
@@ -20,11 +20,11 @@ let
# - orange-pi is listed as the "main integration branch". # - orange-pi is listed as the "main integration branch".
# - this suggests it's NOT a stable branch, only `orange-pi-X.YY-YYYYMMDD-NNNN` tags are "formal" releases # - this suggests it's NOT a stable branch, only `orange-pi-X.YY-YYYYMMDD-NNNN` tags are "formal" releases
# - specific branches like `pp` (pinephone) are dev branches, and probably less stable. # - specific branches like `pp` (pinephone) are dev branches, and probably less stable.
rev = "orange-pi-6.4-20230731-1920"; rev = "orange-pi-6.4-20230619-0323";
hash = "sha256-XHYxFvosa1FMOFuyb3OwRc/orcD98fSi9NKf1f+riCA="; hash = "sha256-il32UQM/8Fc7VHft3+M4TLMxk5+h28C9Suu1kRdZj2M=";
base = "6.4.7"; base = "6.4.0";
# set to empty if not a release candidate, else `-rc<N>` # set to empty if not a release candidate, else `-rc<N>`
rc = ""; rc = "-rc7";
# pinephone uses the linux dtb at arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi # pinephone uses the linux dtb at arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
# - this includes sun50i-a64.dtsi # - this includes sun50i-a64.dtsi
@@ -34,18 +34,6 @@ let
kernelConfig = with lib.kernel; { kernelConfig = with lib.kernel; {
# NB: nix adds the CONFIG_ prefix to each of these. # NB: nix adds the CONFIG_ prefix to each of these.
# if you add the prefix yourself nix will IGNORE YOUR CONFIG. # if you add the prefix yourself nix will IGNORE YOUR CONFIG.
# optimize for faster builds.
# see <repo:kernel.org/linux:Documentation/admin-guide/quickly-build-trimmed-linux.rst>
DEBUG_KERNEL = lib.mkForce no; # option group which seems to just gate the other DEBUG_ opts?
DEBUG_INFO = lib.mkForce no; # for gdb debugging
DEBUG_INFO_BTF = lib.mkForce no; # BPF debug symbols. rec by <https://nixos.wiki/wiki/Linux_kernel#Too_high_ram_usage>
SCHED_DEBUG = lib.mkForce no; # determines /sys/kernel/debug/sched
# SUNRPC_DEBUG = lib.mkForce no; # i use NFS though
MODEM_POWER = lib.mkIf (!withModemPower) no;
# taken from mobile-nixos config?? or upstream megous config??
RTL8723CS = module; RTL8723CS = module;
BT_HCIUART_3WIRE = yes; BT_HCIUART_3WIRE = yes;
BT_HCIUART_RTL = yes; BT_HCIUART_RTL = yes;
@@ -111,46 +99,35 @@ let
extraKernelPatches = [ extraKernelPatches = [
pkgs.kernelPatches.bridge_stp_helper pkgs.kernelPatches.bridge_stp_helper
pkgs.kernelPatches.request_key_helper pkgs.kernelPatches.request_key_helper
# (patchDefconfig kernelConfig) (patchDefconfig kernelConfig)
] ++ lib.optionals (!withModemPower) [
{
# Drop modem-power from DT to allow eg25-manager to have full control.
# source: <https://github.com/NixOS/mobile-nixos/pull/573>
name = "remove-modem-power-from-devicetree";
patch = fetchpatch {
url = "https://gitlab.com/postmarketOS/pmaports/-/raw/164e9f010dcf56642d8e6f422a994b927ae23f38/device/main/linux-postmarketos-allwinner/0007-dts-pinephone-drop-modem-power-node.patch";
sha256 = "nYCoaYj8CuxbgXfy5q43Xb/ebe5DlJ1Px571y1/+lfQ=";
};
}
]; ];
# create a kernelPatch which overrides nixos' defconfig with extra options # create a kernelPatch which overrides nixos' defconfig with extra options
# patchDefconfig = config: { patchDefconfig = config: {
# # defconfig options. this method comes from here: # defconfig options. this method comes from here:
# # - https://discourse.nixos.org/t/the-correct-way-to-override-the-latest-kernel-config/533/9 # - https://discourse.nixos.org/t/the-correct-way-to-override-the-latest-kernel-config/533/9
# name = "linux-megous-defconfig"; name = "linux-megous-defconfig";
# patch = null; patch = null;
# extraStructuredConfig = config; extraStructuredConfig = config;
# }; };
in buildLinux (args // { overridenArgs = args // rec {
version = base + rc; version = base + rc;
# modDirVersion needs to be x.y.z, where `z` could be `Z-rcN` # modDirVersion needs to be x.y.z, will automatically add .0 if needed
# nix kernel build will sanity check us if we get the modDirVersion wrong modDirVersion = if (modDirVersionArg == null) then concatStringsSep "." (take 3 (splitVersion "${version}.0")) + rc else modDirVersionArg;
modDirVersion = base + rc;
# branchVersion needs to be x.y # branchVersion needs to be x.y
extraMeta.branch = versions.majorMinor base; extraMeta.branch = versions.majorMinor version;
src = fetchFromGitHub { src = fetchFromGitHub {
owner = "megous"; owner = "megous";
repo = "linux"; repo = "linux";
inherit rev hash; inherit rev hash;
}; };
} // (args.argsOverride or { });
kernelPatches = (args.kernelPatches or []) ++ extraKernelPatches; finalArgs = overridenArgs // {
kernelPatches = overridenArgs.kernelPatches or [] ++ extraKernelPatches;
structuredExtraConfig = (args.structuredExtraConfig or {}) // kernelConfig; };
}) in buildLinux finalArgs

View File

@@ -1,55 +0,0 @@
{ stdenv
, lib
, desktop-file-utils
, fetchFromGitLab
, gettext
, glib
, gobject-introspection
, gtk3
, meson
, ninja
, python3
, wrapGAppsHook
}:
let
# optional deps: avahi, python-keyring
pythonEnv = python3.withPackages (ps: with ps; [ dateutil pygobject3 ]);
in
stdenv.mkDerivation rec {
pname = "mcg";
version = "3.2.1";
src = fetchFromGitLab {
owner = "coderkun";
repo = "mcg";
rev = "v${version}";
hash = "sha256-awPMXGruCB/2nwfDqYlc0Uu9E6VV1AleEZAw9Xdsbt8=";
};
postPatch = ''
substituteInPlace src/meson.build \
--replace "python.find_installation('python3').full_path()" "'${pythonEnv}/bin/python3'"
'';
nativeBuildInputs = [
gtk3 # for gtk-update-icon-cache
desktop-file-utils # for update-desktop-database
gettext # for msgfmt
glib # for glib-compile-resources
gobject-introspection # needed so wrapGAppsHook includes GI_TYPEPATHS for gtk3
meson
ninja
wrapGAppsHook
];
buildInputs = [
gtk3
];
meta = with lib; {
description = "CoverGrid (mcg) is a client for the Music Player Daemon (MPD), focusing on albums instead of single tracks.";
homepage = "https://www.suruatoel.xyz/codes/mcg";
platforms = platforms.linux;
# license = TODO
maintainers = with maintainers; [ colinsane ];
};
}

View File

@@ -4,7 +4,7 @@
, mpvScripts , mpvScripts
}: }:
mpvScripts.uosc.overrideAttrs (upstream: { mpvScripts.uosc.overrideAttrs (upstream: {
version = "unstable-2023-08-29"; version = "unstable-2023-07-26";
# src = fetchFromGitHub { # src = fetchFromGitHub {
# owner = "tomasklaen"; # owner = "tomasklaen";
# repo = "uosc"; # repo = "uosc";
@@ -15,8 +15,8 @@ mpvScripts.uosc.overrideAttrs (upstream: {
domain = "git.uninsane.org"; domain = "git.uninsane.org";
owner = "colin"; owner = "colin";
repo = "uosc"; repo = "uosc";
rev = "sane-0.2"; rev = "dev/sane";
hash = "sha256-j5hX+lAf7mHx4vqI0shOekmOh4aZsOiRb3rPs8vQ4qo="; hash = "sha256-XOhryppod3zozYrPQlGBw298u+0/eS1MaDepV4p88cM=";
# for version > 4.7.0, we can use nixpkgs src and set `patches` to a fetch of my one custom commit # for version > 4.7.0, we can use nixpkgs src and set `patches` to a fetch of my one custom commit
}; };
passthru = upstream.passthru // { passthru = upstream.passthru // {

View File

@@ -1,102 +0,0 @@
{ lib
, stdenv
, fetchFromGitLab
, meson
, ninja
, pkg-config
, gcr
, glib
, gnome-desktop
, gtk3
, libgudev
, libjson
, json-glib
, libhandy
, networkmanager
, linux-pam
, systemd
, upower
, wayland
, libxkbcommon
, python3
, phoc
, bash
, gnome
, squeekboard ? null
, wayland-scanner
, wrapGAppsHook
}:
stdenv.mkDerivation rec {
pname = "phog";
version = "0.1.3";
src = fetchFromGitLab {
owner = "mobian1";
repo = "phog";
rev = version;
hash = "sha256-zny1FUYKwVXVSBGTh8AFVtMBS7dWZHTKO2gkPNPSL2M=";
};
patches = [
./sway-compat.patch
];
postPatch = ''
patchShebangs build-aux/post_install.py
sed -i /phog_plugins_dir/d build-aux/post_install.py
substituteInPlace src/greetd.c \
--replace '/usr/share/wayland-sessions' '/run/current-system/sw/share/wayland-sessions/' \
--replace '/usr/share/xsessions' '/run/current-system/sw/share/xsessions'
'' + lib.optionalString (squeekboard == null) ''
substituteInPlace data/phog.in \
--replace " & squeekboard" ""
'';
preFixup = ''
gappsWrapperArgs+=(
--prefix PATH : ${lib.makeBinPath [ bash squeekboard ]}
--prefix XDG_DATA_DIRS : "${gnome.gnome-shell}/share/gsettings-schemas/${gnome.gnome-shell.name}"
)
'';
mesonFlags = [ "-Dcompositor=${phoc}/bin/phoc" ];
depsBuildBuild = [
pkg-config
];
buildInputs = [
gcr
glib
gnome-desktop
gtk3
libgudev
libjson
json-glib
libhandy
networkmanager
linux-pam
systemd
upower
wayland
libxkbcommon
];
nativeBuildInputs = [
meson
ninja
pkg-config
python3
glib
wayland-scanner
wrapGAppsHook
];
meta = with lib; {
description = "Greetd-compatible greeter for mobile phones";
homepage = "https://gitlab.com/mobian1/phog/";
license = licenses.gpl3Only;
maintainers = with maintainers; [ matthewcroughan ];
};
}

View File

@@ -1,31 +0,0 @@
commit 86593b754405a194e749e424e27710aa08533853
Author: Colin <colin@uninsane.org>
Date: 2023-08-26 12:26:36 +0000
make phoc-specific wayland interface optional: zphoc_layer_shell_effects_v1
diff --git a/src/drag-surface.c b/src/drag-surface.c
index 0e1a371f..56f7a307 100644
--- a/src/drag-surface.c
+++ b/src/drag-surface.c
@@ -204,6 +204,7 @@ phog_drag_surface_configured (PhogLayerSurface *layer_surface)
return;
/* Configure drag surface if not done yet */
+ g_return_if_fail(priv->layer_shell_effects);
priv->drag_surface = zphoc_layer_shell_effects_v1_get_draggable_layer_surface (priv->layer_shell_effects,
wl_layer_surface);
zphoc_draggable_layer_surface_v1_add_listener (priv->drag_surface, &drag_surface_listener, self);
diff --git a/src/phog-wayland.c b/src/phog-wayland.c
index 99933116..7c2d76ad 100644
--- a/src/phog-wayland.c
+++ b/src/phog-wayland.c
@@ -274,7 +274,7 @@ phog_wayland_constructed (GObject *object)
!self->input_inhibit_manager || !self->xdg_wm_base ||
!self->zxdg_output_manager_v1 ||
!self->zphoc_layer_shell_effects_v1) {
- g_error ("Wayland compositor lacks needed globals\n"
+ g_warning ("Wayland compositor lacks needed globals\n"
"outputs: %d, layer_shell: %p, idle_manager: %p, "
"inhibit: %p, xdg_wm: %p, "
"xdg_output: %p, wlr_output_manager: %p, "

View File

@@ -191,12 +191,6 @@ let
src = ./src; src = ./src;
pkgs = [ "rsync" ]; pkgs = [ "rsync" ];
}; };
sync-music = static-nix-shell.mkPython3Bin {
pname = "sane-sync-music";
src = ./src;
pkgs = [ "ffmpeg" "sox" ];
pyPkgs = [ "unidecode" ];
};
vpn-down = static-nix-shell.mkBash { vpn-down = static-nix-shell.mkBash {
pname = "sane-vpn-down"; pname = "sane-vpn-down";
src = ./src; src = ./src;

View File

@@ -23,13 +23,9 @@ options:
# - Torznab: <https://torznab.github.io/spec-1.3-draft/index.html> # - Torznab: <https://torznab.github.io/spec-1.3-draft/index.html>
# - TorrentPotato: <https://github.com/RuudBurger/CouchPotatoServer/wiki/Couchpotato-torrent-provider> # - TorrentPotato: <https://github.com/RuudBurger/CouchPotatoServer/wiki/Couchpotato-torrent-provider>
# - its own JSON-based API # - its own JSON-based API
#
# about torrent jargon:
# - <https://en.wikipedia.org/wiki/Pirated_movie_release_types>
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime from datetime import datetime
import argparse
import logging import logging
import json import json
import natsort import natsort
@@ -70,31 +66,9 @@ def parse_time(t: str) -> datetime:
return try_parse_time(t).astimezone() or epoch return try_parse_time(t).astimezone() or epoch
# preference, best to worst
TRACKER_RANKS = [
'bakabt',
'nyaa.si',
'yts',
'internet archive',
'the pirate bay',
# haven't sorted these
'1337x',
'kickasstorrents.to',
]
def tracker_rank(tracker: str):
if tracker.lower() in TRACKER_RANKS:
return TRACKER_RANKS.index(tracker.lower())
logger.warn(f"unknown tracker: {tracker!r}")
return len(TRACKER_RANKS)
DROP_CATS = { "dvd", "hd", "misc", "other", "sd", "uhd" } DROP_CATS = { "dvd", "hd", "misc", "other", "sd", "uhd" }
MANGA_CATS = { "books", "comics", "ebook" } MANGA_CATS = { "books", "comics", "ebook" }
VIDEO_CATS = { "anime", "movies", "tv" } KNOWN_CATS = frozenset(list(MANGA_CATS) + ["anime", "audio", "movies", "tv", "xxx"])
KNOWN_CATS = frozenset(
list(MANGA_CATS) +
list(VIDEO_CATS) +
["audio", "xxx"]
)
def clean_cat(c: str) -> str | None: def clean_cat(c: str) -> str | None:
if c in DROP_CATS: return None if c in DROP_CATS: return None
return c return c
@@ -109,38 +83,6 @@ def is_cat(cats: list[str], wanted_cats: list[str], default: bool = False) -> bo
else: else:
return any(c in wanted_cats for c in cats) return any(c in wanted_cats for c in cats)
class Filter:
def __init__(self, h265: bool=False, manga: bool=False, video: bool=False):
self.h265 = h265
self.manga = manga
self.video = video
def filter(self, torrents: list['Torrent']) -> list['Torrent']:
return [t for t in torrents if self.is_match(t)]
def is_match(self, t: 'Torrent', default: bool = False) -> bool:
valid = True
valid = valid and (not self.h265 or self.is_h265(t))
valid = valid and (not self.manga or self.is_manga(t, default))
valid = valid and (not self.video or self.is_video(t, default))
return valid
@staticmethod
def is_h265(t: 'Torrent') -> bool:
meta = t.title.lower()
return "h265" in meta \
or "x265" in meta \
or "HEVC" in meta
@staticmethod
def is_manga(t: 'Torrent', default: bool = False) -> bool:
return is_cat(t.categories, MANGA_CATS, default)
@staticmethod
def is_video(t: 'Torrent', default: bool = False) -> bool:
return is_cat(t.categories, VIDEO_CATS, default)
@dataclass(eq=True, order=True, unsafe_hash=True) @dataclass(eq=True, order=True, unsafe_hash=True)
class Torrent: class Torrent:
seeders: int seeders: int
@@ -209,6 +151,15 @@ class Torrent:
magnet=self.magnet, magnet=self.magnet,
) )
def is_manga(self, default: bool = False) -> bool:
return is_cat(self.categories, MANGA_CATS, default)
def is_h265(self) -> bool:
meta = self.title.lower()
return "h265" in meta \
or "x265" in meta \
or "HEVC" in meta
class Client: class Client:
def __init__(self): def __init__(self):
self.apikey = open("/run/secrets/jackett_apikey").read().strip() self.apikey = open("/run/secrets/jackett_apikey").read().strip()
@@ -231,55 +182,80 @@ class Client:
return sorted(torrents, reverse=True) return sorted(torrents, reverse=True)
def sort_results(torrents: list[Torrent], by: str) -> list[Torrent]:
if by == 'seeders':
return sorted(torrents, key=lambda t: (t.seeders, t), reverse=True)
elif by == 'tracker':
return sorted(torrents, key=lambda t: (-tracker_rank(t.tracker), t), reverse=True)
assert False, f"unknown sort method: {by}"
def format_results(all_results: list[Torrent], filtered_results: list[Torrent], json: bool): def filter_results(results: list[Torrent], full: bool, top: int, manga: bool, h265: bool) -> list[Torrent]:
if json: """
dumpable = [t.to_dict() for t in filtered_results] take the complete query and filter further based on CLI options
print(json.dumps(dumpable)) """
if manga:
results = [t for t in results if t.is_manga(default=True)]
if h265:
results = [t for t in results if t.is_h265()]
if not full:
results = results[:top]
return results
def parse_args(args: list[str]) -> dict:
options = dict(
full=False,
help=False,
json=False,
query="",
top="5",
verbose=False,
manga=False,
h265=False,
)
while args:
arg = args[0]
del args[0]
if arg.startswith('--'):
opt = arg[2:]
if "=" in opt:
name, val = opt.split('=')
else: else:
num_total = len(all_results) name, val = opt, True
num_filtered = len(filtered_results) options[name] = val
print(f"found {num_total} result(s) filtered to {num_filtered}") else:
for r in filtered_results: options["query"] = options["query"] + " " + arg if options["query"] else arg
print(r)
return options
def main(args: list[str]): def main(args: list[str]):
logging.basicConfig() logging.basicConfig()
logging.getLogger().setLevel(logging.WARNING) options = parse_args(args)
full = options.pop("full")
help = options.pop("help")
json = options.pop("json")
query = options.pop("query")
assert options.get("top") is not True, "use `--top=N`, not `--top N`"
top = int(options.pop("top"))
verbose = options.pop("verbose")
manga = options.pop("manga")
h265 = options.pop("h265")
parser = argparse.ArgumentParser(description='search torrent trackers') if options != {}:
parser.add_argument('--full', action='store_true', help='show all results') raise BadCliArgs(f"unexpected options: {options}")
parser.add_argument('--top', help='how many results to show (default: 5)') if help:
parser.add_argument('--sort-by', default='seeders', help='how to rank matches (seeders, tracker)') raise BadCliArgs()
parser.add_argument('--json', action='store_true', help='output results in json')
parser.add_argument('--verbose', action='store_true')
parser.add_argument('--h265', action='store_true', help='show only H.265/HEVC results (might cause false negatives)')
parser.add_argument('--manga', action='store_true', help='show only manga results')
parser.add_argument('--video', action='store_true', help='show only video (tv or film)')
parser.add_argument("query", help="text to search for in torrent titles/descriptions")
args = parser.parse_args() if verbose:
if args.verbose:
logging.getLogger().setLevel(logging.DEBUG) logging.getLogger().setLevel(logging.DEBUG)
client = Client() client = Client()
all_results = client.query(args.query) results = client.query(query)
num_results = len(results)
filter = Filter(h265=args.h265, manga=args.manga, video=args.video) results = filter_results(results, full, top, manga, h265)
filtered_results = filter.filter(all_results)
ordered_results = sort_results(filtered_results, args.sort_by)
if not args.full: if json:
ordered_results = ordered_results[:int(args.top or "5")] dumpable = [t.to_dict() for t in results]
print(json.dumps(dumpable))
format_results(all_results, ordered_results, args.json) else:
print(f"found {num_results} result(s)")
for r in results:
print(r)
if __name__ == "__main__": if __name__ == "__main__":
main(sys.argv[1:]) main(sys.argv[1:])

View File

@@ -1,13 +1,11 @@
#!/usr/bin/env nix-shell #!/usr/bin/env nix-shell
#!nix-shell -i bash -p systemd #!nix-shell -i bash -p systemd
sudo systemctl stop matrix-appservice-irc mx-puppet-discord mautrix-signal signald sudo systemctl stop matrix-appservice-irc mx-puppet-discord
sudo systemctl stop ejabberd gitea lemmy-ui matrix-synapse pict-rs pleroma sudo systemctl stop pleroma gitea matrix-synapse jellyfin transmission jackett
sudo systemctl stop dovecot2 opendkin postfix sudo systemctl stop ejabberd goaccess i2p kiwix-serve navidrome
sudo systemctl stop i2p jackett transmission
sudo systemctl stop jellyfin kiwix-serve komga navidrome
sudo systemctl stop goaccess
# TODO: stop the freshrss timer # TODO: stop the freshrss timer
sudo systemctl stop phpfpm-freshrss sudo systemctl stop phpfpm-freshrss
sudo systemctl stop dovecot2 opendkin postfix
sudo systemctl stop nginx sudo systemctl stop nginx
sudo systemctl stop postgresql sudo systemctl stop postgresql
sudo systemctl stop duplicity.timer sudo systemctl stop duplicity.timer

View File

@@ -1,204 +0,0 @@
#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ps.unidecode ])" -p ffmpeg -p sox
# vim: set filetype=python :
import argparse
import concurrent.futures
import logging
import multiprocessing
import os
import subprocess
from pathlib import Path
from unidecode import unidecode
logger = logging.getLogger(__name__)
MAKE_MP3 = [
'.flac',
'.oga',
'.ogg',
'.opus',
'.wav',
'.wma',
]
COPY_RAW = [
'.aac',
'.bmp',
'.gif',
'.jpeg',
'.jpg',
'.m4a',
'.mp3',
'.png',
]
IGNORE = [
'.DS_Store',
'.avi',
'.cue',
'.inf',
'.log',
'.lyrics',
'.m3u',
'.mov',
'.mp4',
'.nsf_',
'.pdf',
'.toc',
'.txt',
'.webm',
]
class Encoder:
def __init__(self, dry_run: bool = False):
self.dry_run = dry_run
def check_output_no_sideeffect(self, args: list[str]) -> bytes:
return subprocess.check_output(args)
def check_output(self, args: list[str]) -> str:
if self.dry_run:
logger.debug("not invoking because dry run: " + ' '.join(args))
return b""
else:
return subprocess.check_output(args)
def cp(self, source: Path, dest: Path) -> None:
self.check_output(['cp', str(source), str(dest)])
def ensure_dir(self, dir: Path) -> None:
if self.dry_run:
logger.debug(f"not invoking because dry run: os.makedirs({dir!r}, exist_ok=True)")
else:
os.makedirs(str(dir), exist_ok=True)
def remove(self, path: Path) -> None:
if self.dry_run:
logger.debug(f"not invoking because dry run: os.remove({path!r})")
else:
os.remove(path)
def convert(self, source: Path, dest: Path) -> None:
source_samplerate = None
try:
source_samplerate = int(self.check_output_no_sideeffect(['soxi', '-r', str(source)]).decode("utf-8").strip())
except:
if str(source).endswith('.wma'):
logging.debug(f'unsupported extension for samplerate: {source}')
else:
logging.warning(f'unable to obtain samplerate for {source}')
samplerate_map = {
192000: 48000,
96000: 48000,
88200: 44100,
# preserve as-is
48000: 48000,
44100: 44100,
}
target_samplerate = samplerate_map.get(source_samplerate)
if source_samplerate and not target_samplerate:
logging.warning(f'unable to map source sample rate: {source_samplerate}')
samplerate_flags = ['-ar', str(target_samplerate)] if target_samplerate else []
self.check_output([
'ffmpeg',
'-i', str(source),
'-codec:v', 'copy',
'-codec:a', 'libmp3lame',
'-qscale:a', '0'
] + samplerate_flags + [str(dest)])
def clean_name(path: str) -> Path:
'''
transform a path into something which most filesystems/protocols can reliably support
'''
out_path = Path()
for part in path.parts:
blacklisted = '"\'!@#$%^&*()[]{};:,<>?`~|\\/'
part = unidecode(part)
part = ''.join(c for c in part if c not in blacklisted)
out_path /= part
return out_path
def target_name(source_name: str) -> Path:
n = clean_name(source_name)
if n.suffix in MAKE_MP3:
return Path(str(n) + '.mp3')
else:
return n
def calculate_delta(in_dir: str, out_dir: str) -> tuple[set[Path], set[Path]]:
'''
Returns the set of dest files which need to be deleted, followed by the files to copy
'''
in_files = { p.relative_to(in_dir) for p in Path(in_dir).rglob("*") if not p.is_dir() }
logger.info(f'found {len(in_files)} files in source')
existing_out_files = { p.relative_to(out_dir) for p in Path(out_dir).rglob("*") if not p.is_dir() }
logger.info(f'found {len(existing_out_files)} files in dest')
expected_out_files = { target_name(n) for n in in_files }
to_del = { f for f in existing_out_files if f not in expected_out_files }
logger.info(f'found {len(to_del)} files to delete')
to_copy = { f for f in in_files if target_name(f) not in existing_out_files and f.suffix not in IGNORE }
logger.info(f'found {len(to_copy)} files to copy')
return to_del, to_copy
def rm_dest_files(encoder: Encoder, out_dir: str, files: set[Path]) -> None:
for f in files:
logger.info(f'removing {f} because it does not exist on host')
encoder.remove(Path(out_dir) / f)
def copy_one(encoder: Encoder, source: Path, dest: Path) -> None:
encoder.ensure_dir(dest.parent)
if source.suffix in MAKE_MP3:
logger.debug(f'converting {source} -> {dest}')
encoder.convert(source, dest)
elif source.suffix in COPY_RAW:
logger.debug(f'copying {source} -> {dest}')
encoder.cp(source, dest)
else:
logger.warning(f"skipping {source} because I don't know what to do with that file type")
def cp_src_files(encoder: Encoder, in_dir: Path, out_dir: Path, src_names: set[Path], jobs: int):
logger.info(f'using {jobs} jobs to copy {len(src_names)} files')
# Parallel(n_jobs=jobs)(delayed(copy_one)(encoder, in_dir / n, out_dir / target_name(n)) for n in src_names)
with concurrent.futures.ThreadPoolExecutor(max_workers=jobs) as executor:
for n in src_names:
executor.submit(copy_one, encoder, in_dir / n, out_dir / target_name(n))
def sync_all(in_dir: str, out_dir: str, jobs: int = None, dry_run: bool = False) -> None:
encoder = Encoder(dry_run=dry_run)
to_del, to_copy = calculate_delta(in_dir, out_dir)
rm_dest_files(encoder, out_dir, to_del)
cp_src_files(encoder, in_dir, out_dir, to_copy, jobs = jobs or multiprocessing.cpu_count())
def main() -> None:
logging.basicConfig()
logger.setLevel(logging.INFO)
parser = argparse.ArgumentParser(description="synchronize music from one directory to another, possibly compressing it")
parser.add_argument("src", help="source directory")
parser.add_argument("dest", help="destination directory")
parser.add_argument("--jobs", help="number of cores to compress music with (default: all CPU cores)", default=None, type=int)
parser.add_argument("--dry-run", action='store_true', help="don't actually run any commands")
parser.add_argument("--verbose", action='store_true', help="more logging")
parser.add_argument("--quiet", action='store_true', help="less logging")
args = parser.parse_args()
if args.verbose:
logger.setLevel(logging.DEBUG)
if args.quiet:
logger.setLevel(logging.WARN)
sync_all(args.src, args.dest, args.jobs, args.dry_run)
if __name__ == '__main__':
main()

View File

@@ -1,36 +0,0 @@
{ stdenv
, glib-networking
, gobject-introspection
, libgweather
, python3
, wrapGAppsNoGuiHook
}:
let
pyEnv = python3.withPackages (ps: [
ps.pygobject3
]);
in
stdenv.mkDerivation {
pname = "sane-weather";
version = "0.1";
src = ./.;
nativeBuildInputs = [
gobject-introspection
wrapGAppsNoGuiHook
];
buildInputs = [
glib-networking
libgweather
pyEnv
];
installPhase = ''
runHook preInstall
mkdir -p "$out/bin"
cp sane-weather "$out/bin"
runHook postInstall
'';
}

View File

@@ -1,195 +0,0 @@
#!/usr/bin/env python3
# to get GWeather logging, run with
# `G_MESSAGES_DEBUG=GWeather`
# queries weather from public (gov) sources and renders it to stdout.
# primary consumer is conky.
# very limited; libgweather is a little iffy and doesn't expose everything the raw APIs do
# e.g. no precise precipitation predictions.
#
# future work:
# - consider using python-native pynws: <https://github.com/MatthewFlamm/pynws>
# - it's well-factored, exposing a nice interface but letting me dig as deep as i want wherever that's incomplete.
# - render a graph with rain + temperature forecast
# - conky supports graphs with [execgraph](https://conky.cc/variables#execgraph)
import argparse
import code
import gi
import logging
import time
gi.require_version('GWeather', '4.0')
from gi.repository import GLib
from gi.repository import GWeather
logger = logging.getLogger(__name__)
class WeatherSource:
'''
this class abstracts operations which would query a remote weather server
'''
def __init__(self):
self.info = GWeather.Info()
self.info.set_application_id('org.uninsane.sane-weather')
self.info.set_contact_info('contact@uninsane.org')
self.info.set_enabled_providers(
# defaults to METAR | IWIN.
# options are:
# - IWIN # graphical.weather.gov; provides daily min/max temp, precipitation
# - METAR # aviationweather.gov; provides current time, wind, visibility, conditions, clouds, temperature, pressure
# - MET_NO
# - NWS # api.weather.gov; provides hourly temperature, dewpoint, humidity, sky cover, wind, precipitation, snow; daily min/max temp,
# - OWM
# METAR, if you only want immediate conditions
GWeather.Provider.METAR
# METAR + NWS, if you want a forecast
# GWeather.Provider.METAR | GWeather.Provider.NWS
)
self.world = GWeather.Location.get_world()
def query_loc(self, loc: GWeather.Location) -> None:
'''
query the weather for some location, asynchronously.
after calling, poll the `try_...` methods to check for results.
'''
logger.debug(f"querying: {loc.get_coords()}")
self.info.set_location(loc)
self.info.update()
def try_get_celcius(self) -> float | None:
valid, temp = self.info.get_value_temp(GWeather.TemperatureUnit.CENTIGRADE)
logger.debug(f"try_get_celcius: valid={valid}, temp={temp}")
if not valid: temp = None
return temp
# potentially interesting methods on GWeather.Info:
# - get_conditions # returns '-'
# - get_forecast_list # forecast as a list of GWeather.Info instances (daily if IWIN; hourly if NWS)
# - get_sky # like 'Clear sky'
# - get_sunrise, get_sunset # like '1310', '0304' (utc time)
# - get_symbolic_icon_name # like 'weather-clear-night-symbolic'
# - get_temp_min, get_temp_max # returns '-'
# - get_temp_summary() # same as get_temp()
# - get_update() # like 'Thu, Aug 24 / 1300'
# - get_wind() # like 'North / 13.0 km/h'
# - get_visibility() # like '16093m'
# - get_weather_summary() # like 'Seattle-Tacoma International Airport: Clear sky'
class TopLevel:
"""
this class acts as the "event loop" which glib apps expect.
caller sets up a "work queue" of everything they want to do, then calls `run`.
glib calls `poll` in a loop, and each time we try to work through another item in the work_queue.
when the work_queue is empty, exit glib's main loop & return to the caller (from `run`).
"""
def __init__(self):
self._loop = GLib.MainLoop()
self.source = WeatherSource()
self.work_queue = []
def enqueue(self, op) -> None:
self.work_queue.append(op)
def run(self) -> None:
self.enqueue(ExitOp())
GLib.idle_add(self.poll)
self._loop.run()
def poll(self) -> bool:
work = self.work_queue[0]
if isinstance(work, QueryOp):
del self.work_queue[0]
self.source.query_loc(work.loc)
elif isinstance(work, PrintTempOp):
temp = self.source.try_get_celcius()
if temp is not None:
del self.work_queue[0]
print(f"{int(temp)}°C")
elif isinstance(work, DiagnosticsOp):
del self.work_queue[0]
# GWeather does transparent caching so that we don't usually hit the web
last_update = self.source.info.get_update()
logger.debug(f"last update: {last_update}")
elif isinstance(work, ExitOp):
logger.debug("quitting GLib MainLoop")
self.source.info.store_cache()
self._loop.quit()
elif isinstance(work, IdleOp):
del self.work_queue[0]
logger.debug("micro sleep")
time.sleep(0.1)
else:
assert False, f"unknown work: {work}"
# micro sleep so we don't peg CPU
# TODO: i'm sure there's a better way than all of this
time.sleep(0.05)
# re-queue this idle fn
return True
# operations:
# think of these as public methods on the `TopLevel` class,
# except abstracted as values for the sake of glib's event loop.
class QueryOp:
def __init__(self, loc: GWeather.Location):
self.loc = loc
class PrintTempOp:
pass
class DiagnosticsOp:
pass
class IdleOp:
pass
class ExitOp:
pass
def main():
logging.basicConfig()
parser = argparse.ArgumentParser(description="acquire weather information for user display")
parser.add_argument(
'--station-code',
default='KSEA',
help='4-letter METAR weather station code for where we want to know weather\n '
'to find your station see here: <https://aviationweather.gov/metar>'
)
parser.add_argument('--break-before', action='store_true', help='drop into a REPL before do anything (for debugging)')
parser.add_argument('--break-after', action='store_true', help='drop into a REPL after completing the work (for debugging)')
parser.add_argument('--verbose', action='store_true', help='enable verbose logging')
args = parser.parse_args()
if args.verbose:
logger.setLevel(logging.DEBUG)
GLib.log_set_debug_enabled(True)
toplevel = TopLevel()
here = GWeather.Location.find_by_station_code(toplevel.source.world, args.station_code)
if args.break_before:
code.interact(local=dict(**globals(), **locals()))
toplevel.enqueue(QueryOp(here))
toplevel.enqueue(PrintTempOp())
toplevel.enqueue(DiagnosticsOp())
# for _ in range(300): # for debugging...
# toplevel.enqueue(IdleOp())
toplevel.run()
if args.break_after:
code.interact(local=dict(**globals(), **locals()))
if __name__ == '__main__':
main()

View File

@@ -1,19 +1,14 @@
{ pkgs { pkgs
, bash
, lib , lib
, makeWrapper , makeWrapper
, python3 , python3
, stdenv , stdenv
, zsh
}: }:
let let
inherit (builtins) attrNames attrValues concatStringsSep foldl' map typeOf; inherit (builtins) attrNames attrValues concatStringsSep foldl' map typeOf;
inherit (lib) concatMapAttrs; inherit (lib) concatMapAttrs;
bash' = bash;
pkgs' = pkgs; pkgs' = pkgs;
python3' = python3;
zsh' = zsh;
# create an attrset of # create an attrset of
# <name> = expected string in the nix-shell invocation # <name> = expected string in the nix-shell invocation
# <value> = package to provide # <value> = package to provide
@@ -79,33 +74,33 @@ in rec {
); );
# `mkShell` specialization for `nix-shell -i bash` scripts. # `mkShell` specialization for `nix-shell -i bash` scripts.
mkBash = { pname, pkgs ? {}, srcPath ? pname, bash ? bash', ...}@attrs: mkBash = { pname, pkgs ? {}, srcPath ? pname, ...}@attrs:
let let
pkgsAsAttrs = pkgsToAttrs "" pkgs' pkgs; pkgsAsAttrs = pkgsToAttrs "" pkgs' pkgs;
pkgsEnv = attrValues pkgsAsAttrs; pkgsEnv = attrValues pkgsAsAttrs;
pkgExprs = attrNames pkgsAsAttrs; pkgExprs = attrNames pkgsAsAttrs;
in mkShell ({ in mkShell ({
inherit pkgsEnv pkgExprs; inherit pkgsEnv pkgExprs;
interpreter = "${bash}/bin/bash"; interpreter = "${pkgs'.bash}/bin/bash";
} // (removeAttrs attrs [ "bash" "pkgs" ]) } // (removeAttrs attrs [ "pkgs" ])
); );
# `mkShell` specialization for `nix-shell -i zsh` scripts. # `mkShell` specialization for `nix-shell -i zsh` scripts.
mkZsh = { pname, pkgs ? {}, srcPath ? pname, zsh ? zsh', ...}@attrs: mkZsh = { pname, pkgs ? {}, srcPath ? pname, ...}@attrs:
let let
pkgsAsAttrs = pkgsToAttrs "" pkgs' pkgs; pkgsAsAttrs = pkgsToAttrs "" pkgs' pkgs;
pkgsEnv = attrValues pkgsAsAttrs; pkgsEnv = attrValues pkgsAsAttrs;
pkgExprs = attrNames pkgsAsAttrs; pkgExprs = attrNames pkgsAsAttrs;
in mkShell ({ in mkShell ({
inherit pkgsEnv pkgExprs; inherit pkgsEnv pkgExprs;
interpreter = "${zsh}/bin/zsh"; interpreter = "${pkgs'.zsh}/bin/zsh";
} // (removeAttrs attrs [ "pkgs" "zsh" ]) } // (removeAttrs attrs [ "pkgs" ])
); );
# `mkShell` specialization for invocations of `nix-shell -p "python3.withPackages (...)"` # `mkShell` specialization for invocations of `nix-shell -p "python3.withPackages (...)"`
# pyPkgs argument is parsed the same as pkgs, except that names are assumed to be relative to `"ps"` if specified in list form. # pyPkgs argument is parsed the same as pkgs, except that names are assumed to be relative to `"ps"` if specified in list form.
# TODO: rename to `mkPython3` for consistency with e.g. `mkBash` # TODO: rename to `mkPython3` for consistency with e.g. `mkBash`
mkPython3Bin = { pname, pkgs ? {}, pyPkgs ? {}, srcPath ? pname, python3 ? python3', ... }@attrs: mkPython3Bin = { pname, pkgs ? {}, pyPkgs ? {}, srcPath ? pname, ... }@attrs:
let let
pyEnv = python3.withPackages (ps: attrValues ( pyEnv = python3.withPackages (ps: attrValues (
pkgsToAttrs "ps." ps pyPkgs pkgsToAttrs "ps." ps pyPkgs
@@ -123,6 +118,6 @@ in rec {
inherit pkgsEnv pkgExprs; inherit pkgsEnv pkgExprs;
interpreter = pyEnv.interpreter; interpreter = pyEnv.interpreter;
interpreterName = "python3"; interpreterName = "python3";
} // (removeAttrs attrs [ "pkgs" "pyPkgs" "python3" ]) } // (removeAttrs attrs [ "pkgs" "pyPkgs" ])
); );
} }

View File

@@ -0,0 +1,24 @@
diff --git a/setup_config_version.sh b/setup_config_version.sh
index fde40c1..6386014 100755
--- a/setup_config_version.sh
+++ b/setup_config_version.sh
@@ -8,7 +8,7 @@ case "$1" in
exit
esac
-case "$(busybox head -n1 "$1")" in
+case "$(head -n1 "$1")" in
"#"*)
comment="#"
;;
@@ -23,7 +23,7 @@ case "$(busybox head -n1 "$1")" in
;;
esac
-busybox md5sum "$1" | \
- busybox cut -d" " -f1 | \
- busybox xargs -I{} busybox sed -i "2i$comment configversion: {}" \
+md5sum "$1" | \
+ cut -d" " -f1 | \
+ xargs -I{} sed -i "2i$comment configversion: {}" \
"$1"

View File

@@ -0,0 +1,58 @@
commit bf0057011777b91ef5af005fb4e984b4b9b71c7b
Author: Colin <colin@uninsane.org>
Date: 2023-07-15 21:35:45 +0000
sxmo_wmmenu: respect SXMO_WORKSPACE_WRAPPING
sxmo_wm.sh uses the `SXMO_WORKSPACE_WRAPPING` variable to control
relative movements. for example, set this to "5" and then the "Next
Workspace" option in the switch menu will cycle WS 1 -> 2 ... -> 5 -> 1.
same for one- and two-finger left/right swipe to switch/move workspaces.
however, absolute movements (via the move menu) only allowed moving to
WS 1-4. a user with non-default `SXMO_WORKSPACE_WRAPPING` could move a
window from WS 5 to WS 4 with this menu, but not from WS 4 back to WS 5.
this patch brings consistency by using `SXMO_WORKSPACE_WRAPPING`
anywhere we would otherwise assume the number of possible workspaces.
diff --git a/scripts/core/sxmo_wmmenu.sh b/scripts/core/sxmo_wmmenu.sh
index 3d40b31..d3c1db6 100755
--- a/scripts/core/sxmo_wmmenu.sh
+++ b/scripts/core/sxmo_wmmenu.sh
@@ -12,6 +12,12 @@
set -e
+_movetowssubmenu() {
+ for ws in $(seq "${SXMO_WORKSPACE_WRAPPING:-4}"); do
+ printf "%s Move to WS %s\n" "$ws" "$ws"
+ done
+}
+
# A menu which allows to move windows or toggle floating.
swaymovemenu() {
CHOICES="$(cat <<EOF
@@ -22,10 +28,7 @@ $icon_arl Move Left
$icon_arr Move Right
$icon_wn2 Toggle Floating
$icon_ac1 Move Scratchpad
-1 Move to WS 1
-2 Move to WS 2
-3 Move to WS 3
-4 Move to WS 4
+$(_movetowssubmenu)
EOF
)"
@@ -125,10 +128,7 @@ dwmwmmenu() {
CHOICES="$(
cat <<EOF
$icon_cls Close Menu
-1 Move to WS 1
-2 Move to WS 2
-3 Move to WS 3
-4 Move to WS 4
+$(_movetowssubmenu)
$icon_rld Shift stack
$icon_grd Toggle Layout
EOF

View File

@@ -0,0 +1,56 @@
diff --git a/configs/default_hooks/sxmo_hook_apps.sh b/configs/default_hooks/sxmo_hook_apps.sh
index ba70a31..9f5a129 100755
--- a/configs/default_hooks/sxmo_hook_apps.sh
+++ b/configs/default_hooks/sxmo_hook_apps.sh
@@ -31,6 +31,7 @@ write_line_app audacity "$icon_mic Audacity" "audacity"
write_line_app gnome-calculator "$icon_clc Calculator" "gnome-calculator"
write_line_app calcurse "$icon_clk Calcurse" "sxmo_terminal.sh calcurse"
write_line_app cmus "$icon_mus Cmus" "sxmo_terminal.sh cmus"
+write_line_app cozy "$icon_mus Cozy" "com.github.geigi.cozy"
write_line_app dino "$icon_msg Dino" "GDK_SCALE=1 dino"
write_line_app dolphin "$icon_dir Dolphin" "dolphin"
write_line_app emacs "$icon_edt Emacs (Terminal)" "sxmo_terminal.sh emacs -nw"
@@ -54,19 +55,25 @@ write_line_app giara "$icon_red Giara" "giara"
write_line_app gnome-chess "$icon_chs Gnome Chess" "gnome-chess"
write_line_app gomuks "$icon_msg Gomuks" "sxmo_terminal.sh gomuks"
write_line_app gpodder "$icon_rss gPodder" "gpodder"
+write_line_app gthumb "$icon_img gThumb" "gthumb"
write_line_app gucharmap "$icon_inf Gucharmap" "gucharmap"
write_line_app hexchat "$icon_msg Hexchat" "hexchat"
write_line_app htop "$icon_cfg Htop" "sxmo_terminal.sh htop"
write_line_app irssi "$icon_msg Irssi" "sxmo_terminal.sh irssi"
write_line_app ii "$icon_msg Ii" "sxmo_terminal.sh ii"
write_line_app ipython "$icon_trm IPython" "sxmo_terminal.sh ipython"
+write_line_app jellyfinmediaplayer "$icon_mvi Jellyfin" "jellyfinmediaplayer"
write_line_app kasts "$icon_rss Kasts" "kasts"
write_line_app kmail "$icon_eml KMail" "kmail"
+write_line_app komikku "$icon_bok Komikku" "komikku"
write_line_app kontact "$icon_msg Kontact" "kontact"
write_line_app konversation "$icon_msg Konversation" "konversation"
+write_line_app koreader "$icon_bok KOReader" "koreader"
write_line_app kwrite "$icon_edt Kwrite" "kwrite"
write_line_app lagrange "$icon_glb Lagrange" "lagrange"
+write_line_app lemoa "$icon_grp Lemoa" "lemoa"
write_line_app lf "$icon_dir Lf" "sxmo_terminal.sh lf"
+write_line_app librewolf "$icon_glb Librewolf" "librewolf"
write_line_app lollypop "$icon_mus Lollypop" "lollypop"
write_line_app luakit "$icon_glb Luakit" "luakit"
write_line_app marble "$icon_map Marble" "marble"
@@ -97,6 +104,7 @@ write_line_app senpai "$icon_msg Senpai" "sxmo_terminal.sh senpai"
write_line_app sic "$icon_msg Sic" "sxmo_terminal.sh sic"
([ "$SXMO_WM" = dwm ] && command -v st >/dev/null) && \
write_line "$icon_trm St" "st -e $SHELL"
+write_line_app sublime-music "$icon_mus Sublime Music" "sublime-music"
write_line_app surf "$icon_glb Surf" "surf"
write_line_app syncthing "$icon_rld Syncthing" "syncthing"
write_line_app telegram-desktop "$icon_tgm Telegram" "telegram-desktop"
@@ -104,7 +112,9 @@ write_line_app termite "$icon_trm Termite" "termite -e $SHELL"
write_line_app thunar "$icon_dir Thunar" "sxmo_terminal.sh thunar"
write_line_app thunderbird "$icon_eml Thunderbird" "thunderbird"
write_line_app com.github.bleakgrey.tootle "$icon_msg Tootle" "com.github.bleakgrey.tootle"
+write_line_app re.sonny.Tangram "$icon_glb Tangram" "re.sonny.Tangram"
write_line_app totem "$icon_mvi Totem" "totem"
+write_line_app dev.geopjr.Tuba "$icon_grp Tuba" "dev.geopjr.Tuba"
write_line_app tuir "$icon_red Tuir" "sxmo_terminal.sh tuir"
write_line_app tut "$icon_msg Tut" "sxmo_terminal.sh tut"
write_line_app waydroid "$icon_and Waydroid" "waydroid show-full-ui"

View File

@@ -1,182 +0,0 @@
{ stdenv
, bash
, bc
, bemenu
, bonsai
, brightnessctl
, buildPackages
, busybox
, conky
, coreutils
, curl
, dbus
, fetchgit
, fetchpatch
, gitUpdater
, gnugrep
, gojq
, grim
, inotify-tools
, j4-dmenu-desktop
, jq
, lib
, libnotify
, libxml2
, lisgd
, makeBinaryWrapper
, mako
, mepo
, modemmanager
, nettools
, playerctl
, procps
, pulseaudio
, rsync
, scdoc
, sfeed
, slurp
, superd
, sway
, swayidle
, wob
, wl-clipboard
, wtype
, wvkbd
, xdg-user-dirs
, xdotool
, xrdb
, version
, rev ? version
, hash ? ""
, patches ? []
}:
let
# anything which any sxmo script or default hook in this package might invoke
runtimeDeps = [
bc # also in busybox
bemenu
bonsai
brightnessctl
conky
curl
dbus
# dmenu # or dmenu-wayland? only used on x11?
gnugrep # also in busybox
gojq
grim
inotify-tools
j4-dmenu-desktop
jq
libnotify
libxml2.bin # for xmllint; sxmo_weather.sh, sxmo_surf_linkset.sh
lisgd
mako
mepo # mepo_ui_central_menu.sh
modemmanager # mmcli
nettools # netstat
playerctl
procps # pgrep
pulseaudio # pactl
sfeed
slurp # for sxmo_screenshot.sh
superd
sway
swayidle
wl-clipboard # for wl-copy; sxmo_screenshot.sh
wob
wtype # for sxmo_type
wvkbd
xdg-user-dirs
xrdb # for sxmo_xinit AND sxmo_winit
# X11 only?
xdotool
];
in
stdenv.mkDerivation rec {
pname = "sxmo-utils";
inherit version;
src = fetchgit {
url = "https://git.sr.ht/~mil/sxmo-utils";
inherit rev hash;
};
inherit patches;
postPatch = ''
# allow sxmo to source its init file
sed -i "s@/etc/profile\.d/sxmo_init.sh@$out/etc/profile.d/sxmo_init.sh@" scripts/core/*.sh
# remove absolute paths
substituteInPlace scripts/core/sxmo_version.sh \
--replace "/usr/bin/" ""
# let superd find sxmo service binaries at runtime via PATH
# TODO: replace with fully-qualified paths
sed -i 's:ExecStart=/usr/bin/:ExecStart=/usr/bin/env :' configs/superd/services/*.service
# install udev rules to where nix expects
substituteInPlace Makefile \
--replace "/usr/lib/udev/rules.d" "/etc/udev/rules.d"
# avoid relative paths in udev rules
substituteInPlace configs/udev/90-sxmo.rules \
--replace "/bin/chgrp" "${coreutils}/bin/chgrp" \
--replace "/bin/chmod" "${coreutils}/bin/chmod"
'';
nativeBuildInputs = [
makeBinaryWrapper
scdoc
];
buildInputs = [ bash ]; # needed here so stdenv's `patchShebangsAuto` hook sets the right interpreter
makeFlags = [
"PREFIX=${placeholder "out"}"
"SYSCONFDIR=${placeholder "out"}/etc"
"DESTDIR="
"OPENRC=0"
];
preInstall = ''
# busybox is used by setup_config_version.sh, but placing it in nativeBuildInputs breaks the nix builder
PATH="$PATH:${buildPackages.busybox}/bin"
'';
# we don't wrap sxmo_common.sh or sxmo_init.sh
# which is unfortunate, for non-sxmo-utils files that might source those.
# if that's a problem, could inject a PATH=... line into them with sed.
postInstall = ''
for f in \
$out/bin/*.sh \
$out/share/sxmo/default_hooks/desktop/sxmo_hook_*.sh \
$out/share/sxmo/default_hooks/one_button_e_reader/sxmo_hook_*.sh \
$out/share/sxmo/default_hooks/three_button_touchscreen/sxmo_hook_*.sh \
$out/share/sxmo/default_hooks/sxmo_hook_*.sh \
; do
case $(basename $f) in
(sxmo_common.sh|sxmo_deviceprofile_*.sh|sxmo_hook_icons.sh|sxmo_init.sh)
# these are sourced by other scripts: don't wrap them else the `exec` in the wrapper breaks the outer script
;;
(*)
wrapProgram "$f" \
--prefix PATH : "${lib.makeBinPath runtimeDeps}"
;;
esac
done
'';
passthru = {
providedSessions = [ "sxmo" "swmo" ];
updateScript = gitUpdater { };
};
meta = {
homepage = "https://git.sr.ht/~mil/sxmo-utils";
description = "Contains the scripts and small C programs that glues the sxmo enviroment together";
license = lib.licenses.mit;
maintainers = with lib.maintainers; [ colinsane ];
platforms = lib.platforms.linux;
};
}

View File

@@ -1,9 +1,90 @@
{ callPackage { stdenv
, bc
, bemenu
, bonsai
, conky
, coreutils
, dbus
, fetchgit
, fetchpatch , fetchpatch
, gitUpdater
, gnugrep
, gojq
, grim
, inotify-tools
, j4-dmenu-desktop
, jq
, lib
, libnotify
, lisgd
, makeBinaryWrapper
, mako
, mepo
, modemmanager
, nettools
, playerctl
, procps
, pulseaudio
, rsync
, scdoc
, sfeed
, superd
, sway
, swayidle
, wob
, wvkbd
, xdg-user-dirs
, xdotool
}: }:
let let
patches = { # anything which any sxmo script or default hook in this package might invoke
merged = [ runtimeDeps = [
bc
bemenu
bonsai
conky
dbus
# dmenu # or dmenu-wayland? only used on x11?
gnugrep
gojq
grim
inotify-tools
j4-dmenu-desktop
jq
libnotify
lisgd
mako
mepo # mepo_ui_central_menu.sh
modemmanager # mmcli
nettools # netstat
playerctl
procps # pgrep
pulseaudio # pactl
sfeed
superd
sway
swayidle
wob
wvkbd
xdg-user-dirs
# X11 only?
xdotool
];
in
stdenv.mkDerivation rec {
pname = "sxmo-utils";
version = "1.14.2";
src = fetchgit {
url = "https://git.sr.ht/~mil/sxmo-utils";
rev = version;
hash = "sha256-1bGCUhf/bt9I8BjG/G7sjYBzLh28iZSC20ml647a3J4=";
};
patches = [
# needed for basic use:
(fetchpatch { (fetchpatch {
# merged post 1.14.2 # merged post 1.14.2
# [1/2] sxmo_init: behave well when user's primary group differs from their name # [1/2] sxmo_init: behave well when user's primary group differs from their name
@@ -22,44 +103,21 @@ let
# i only care about patch no. 2 # i only care about patch no. 2
# [1/2] suspend toggle: silence rm failure noise # [1/2] suspend toggle: silence rm failure noise
# [2/2] config: fix keyboard files location # [2/2] config: fix keyboard files location
name = "multipatch: 42880";
url = "https://lists.sr.ht/~mil/sxmo-devel/patches/42880/mbox"; url = "https://lists.sr.ht/~mil/sxmo-devel/patches/42880/mbox";
hash = "sha256-tAMPBb6vwzj1dFMTEaqrcCJU6FbQirwZgB0+tqW3rQA="; hash = "sha256-tAMPBb6vwzj1dFMTEaqrcCJU6FbQirwZgB0+tqW3rQA=";
}) })
./0004-no-busybox.patch
# wanted to fix/silence some non-fatal errors
./0005-system-audio.patch
./0007-workspace-wrapping.patch
# personal (but upstreamable) preferences:
(fetchpatch { (fetchpatch {
# merged post 1.14.2 # merged post 1.14.2
name = "Switch from light to brightnessctl"; # sxmo_hook_lock: allow configuration of auto-screenoff timeout v1
url = "https://git.sr.ht/~mil/sxmo-utils/commit/d0384a7caed036d25228fa3279c36c0230795e4a.patch";
hash = "sha256-/UlcuEI5cJnsqRuZ1zWWzR4dyJw/zYeB1rtJWFeSGEE=";
})
(fetchpatch {
# merged post 1.14.2
name = "sxmo_hook_lock: allow configuration of auto-screenoff timeout v1";
url = "https://lists.sr.ht/~mil/sxmo-devel/patches/42443/mbox"; url = "https://lists.sr.ht/~mil/sxmo-devel/patches/42443/mbox";
hash = "sha256-c4VySbVJgsbh2h+CnCgwWWe5WkAregpYFqL8n3WRXwY="; hash = "sha256-c4VySbVJgsbh2h+CnCgwWWe5WkAregpYFqL8n3WRXwY=";
}) })
(fetchpatch {
# merged post 1.14.2
name = "sxmo_wmmenu: respect SXMO_WORKSPACE_WRAPPING";
url = "https://lists.sr.ht/~mil/sxmo-devel/patches/42698/mbox";
hash = "sha256-TrTlrthrpYdIMC8/RCMNaB8PcGQgtya/h2/uLNQDeWs=";
})
(fetchpatch {
# merged ~2023/08/22
name = "Make config gesture toggle persistent";
url = "https://lists.sr.ht/~mil/sxmo-devel/patches/42876/mbox";
hash = "sha256-Oa0MI0Kt9Xgl5L1KarHI6Yn4+vpRxUSujB1iY4hlK9c=";
})
(fetchpatch {
# merged ~2023/08/29
# [1/2] Makefile: obey PREFIX when installing udev rules
# [2/2] Makefile: use SYSCONFDIR instead of hardcoding /etc
name = "44110-multipatch-makefile-nixos";
url = "https://lists.sr.ht/~mil/sxmo-devel/patches/44110/mbox";
hash = "sha256-jXtwgOVGSjwWj7a36F6P+e63lKvk4OmFIzxTkf9yZMs=";
})
];
unmerged = [
# (fetchpatch { # (fetchpatch {
# XXX: doesn't apply cleanly to 1.14.2 release # XXX: doesn't apply cleanly to 1.14.2 release
# # Don't wait for led or status bar in state change hooks # # Don't wait for led or status bar in state change hooks
@@ -67,41 +125,80 @@ let
# url = "https://lists.sr.ht/~mil/sxmo-devel/patches/43109/mbox"; # url = "https://lists.sr.ht/~mil/sxmo-devel/patches/43109/mbox";
# hash = "sha256-4uR2u6pa62y6SaRHYRn15YGDPILAs7py0mPbAjsgwM4="; # hash = "sha256-4uR2u6pa62y6SaRHYRn15YGDPILAs7py0mPbAjsgwM4=";
# }) # })
(fetchpatch { (fetchpatch {
name = "sxmo_migrate: add option to disable configversion checks"; # Make config gesture toggle persistent
url = "https://lists.sr.ht/~mil/sxmo-devel/patches/44155/mbox"; url = "https://lists.sr.ht/~mil/sxmo-devel/patches/42876/mbox";
hash = "sha256-ZcUD2UWPM8PxGM9TBnGe8JCJgMC72OZYzctDf2o7Ub0="; hash = "sha256-Oa0MI0Kt9Xgl5L1KarHI6Yn4+vpRxUSujB1iY4hlK9c=";
}) })
## these might or might not be upstream-worthy
./0104-full-auto-rotate.patch ./0104-full-auto-rotate.patch
./0105-more-apps.patch
# ./0106-no-restart-lisgd.patch # ./0106-no-restart-lisgd.patch
];
## not upstreamable postPatch = ''
# let NixOS manage the audio daemons (pulseaudio/pipewire) # allow sxmo to source its init file
./0005-system-audio.patch sed -i "s@/etc/profile\.d/sxmo_init.sh@$out/etc/profile.d/sxmo_init.sh@" scripts/core/*.sh
# remove absolute paths
substituteInPlace scripts/core/sxmo_version.sh \
--replace "/usr/bin/" ""
# let superd find sxmo service binaries at runtime via PATH
# TODO: replace with fully-qualified paths
sed -i 's:ExecStart=/usr/bin/:ExecStart=/usr/bin/env :' configs/superd/services/*.service
# install udev rules to where nix expects
substituteInPlace Makefile \
--replace "/usr/lib/udev/rules.d" "/etc/udev/rules.d"
# avoid relative paths in udev rules
substituteInPlace configs/udev/90-sxmo.rules \
--replace "/bin/chgrp" "${coreutils}/bin/chgrp" \
--replace "/bin/chmod" "${coreutils}/bin/chmod"
'';
nativeBuildInputs = [
makeBinaryWrapper
scdoc
]; ];
# these don't apply cleanly to the stable release; only to latest
unmerged-tip-only = [ installFlags = [
# TODO: send these upstream "OPENRC=0"
(fetchpatch { "DESTDIR=$(out)"
name = "sxmo_hook_apps: add a few"; "PREFIX="
url = "https://git.uninsane.org/colin/sxmo-utils/commit/d6c17a89e1b7bc74d0ba34629fd5db393e5f560b.patch";
hash = "sha256-b12p7RTnAqTVfHpYLkNTwuo12KDznYCYJUEJAIES/1I=";
})
]; ];
# we don't wrap sxmo_common.sh or sxmo_init.sh
# which is unfortunate, for non-sxmo-utils files that might source though.
# if that's a problem, could inject a PATH=... line into them with sed.
postInstall = ''
for f in \
$out/bin/*.sh \
$out/share/sxmo/default_hooks/desktop/sxmo_hook_*.sh \
$out/share/sxmo/default_hooks/one_button_e_reader/sxmo_hook_*.sh \
$out/share/sxmo/default_hooks/three_button_touchscreen/sxmo_hook_*.sh \
$out/share/sxmo/default_hooks/sxmo_hook_*.sh \
; do
case $(basename $f) in
(sxmo_common.sh|sxmo_deviceprofile_*.sh|sxmo_hook_icons.sh|sxmo_init.sh)
# these are sourced by other scripts: don't wrap them else the `exec` in the wrapper breaks the outer script
;;
(*)
wrapProgram "$f" \
--prefix PATH : "${lib.makeBinPath runtimeDeps}"
;;
esac
done
'';
passthru = {
providedSessions = [ "sxmo" "swmo" ];
updateScript = gitUpdater { };
}; };
in {
stable = callPackage ./common.nix { meta = {
version = "1.14.2"; homepage = "https://git.sr.ht/~mil/sxmo-utils";
hash = "sha256-1bGCUhf/bt9I8BjG/G7sjYBzLh28iZSC20ml647a3J4="; description = "Contains the scripts and small C programs that glues the sxmo enviroment together";
patches = patches.merged ++ patches.unmerged; license = lib.licenses.mit;
}; maintainers = with lib.maintainers; [ colinsane ];
latest = callPackage ./common.nix { platforms = lib.platforms.linux;
version = "unstable-2023-08-29";
rev = "871caa7394d2deda6aaff89af0fea9f6de773c2e";
hash = "sha256-TnRit0W/Racm92AwoEuSIJiOtu2XBUd3IsQoPrtshvk=";
patches = patches.unmerged ++ patches.unmerged-tip-only;
}; };
} }

View File

@@ -21,14 +21,10 @@ let
### ADDITIONAL PACKAGES ### ADDITIONAL PACKAGES
alsa-ucm-conf-sane = callPackage ./additional/alsa-ucm-conf-sane { }; alsa-ucm-conf-sane = callPackage ./additional/alsa-ucm-conf-sane { };
# TODO: move target flags to upstream PR and re-enable this bonsai bonsai = unpatched.bonsai or (callPackage ./additional/bonsai { });
# bonsai = unpatched.bonsai or (callPackage ./additional/bonsai { });
bonsai = callPackage ./additional/bonsai { };
bootpart-uefi-x86_64 = callPackage ./additional/bootpart-uefi-x86_64 { }; bootpart-uefi-x86_64 = callPackage ./additional/bootpart-uefi-x86_64 { };
cargoDocsetHook = callPackage ./additional/cargo-docset/hook.nix { }; cargoDocsetHook = callPackage ./additional/cargo-docset/hook.nix { };
chatty-latest = callPackage ./additional/chatty-latest { }; chatty-latest = callPackage ./additional/chatty-latest { };
eg25-control = callPackage ./additional/eg25-control { };
eg25-manager = callPackage ./additional/eg25-manager { };
feeds = lib.recurseIntoAttrs (callPackage ./additional/feeds { }); feeds = lib.recurseIntoAttrs (callPackage ./additional/feeds { });
lemoa = callPackage ./additional/lemoa { }; lemoa = callPackage ./additional/lemoa { };
jellyfin-media-player-qt6 = callPackage ./additional/jellyfin-media-player-qt6 { }; jellyfin-media-player-qt6 = callPackage ./additional/jellyfin-media-player-qt6 { };
@@ -44,20 +40,14 @@ let
koreader-from-src = callPackage ./additional/koreader-from-src { }; koreader-from-src = callPackage ./additional/koreader-from-src { };
ldd-aarch64 = callPackage ./additional/ldd-aarch64 { }; ldd-aarch64 = callPackage ./additional/ldd-aarch64 { };
lightdm-mobile-greeter = callPackage ./additional/lightdm-mobile-greeter { }; lightdm-mobile-greeter = callPackage ./additional/lightdm-mobile-greeter { };
linux-manjaro = callPackage ./additional/linux-manjaro { };
linux-megous = callPackage ./additional/linux-megous { }; linux-megous = callPackage ./additional/linux-megous { };
mcg = callPackage ./additional/mcg { };
mpv-uosc-latest = callPackage ./additional/mpv-uosc-latest { }; mpv-uosc-latest = callPackage ./additional/mpv-uosc-latest { };
mx-sanebot = callPackage ./additional/mx-sanebot { }; mx-sanebot = callPackage ./additional/mx-sanebot { };
phog = callPackage ./additional/phog { };
rtl8723cs-firmware = callPackage ./additional/rtl8723cs-firmware { }; rtl8723cs-firmware = callPackage ./additional/rtl8723cs-firmware { };
sane-scripts = lib.recurseIntoAttrs (callPackage ./additional/sane-scripts { }); sane-scripts = lib.recurseIntoAttrs (callPackage ./additional/sane-scripts { });
sane-weather = callPackage ./additional/sane-weather { };
static-nix-shell = callPackage ./additional/static-nix-shell { }; static-nix-shell = callPackage ./additional/static-nix-shell { };
sublime-music-mobile = callPackage ./additional/sublime-music-mobile { }; sublime-music-mobile = callPackage ./additional/sublime-music-mobile { };
sxmo-utils' = lib.recurseIntoAttrs (callPackage ./additional/sxmo-utils { }); sxmo-utils = callPackage ./additional/sxmo-utils { };
sxmo-utils = sxmo-utils'.stable;
sxmo-utils-latest = sxmo-utils'.latest;
tow-boot-pinephone = callPackage ./additional/tow-boot-pinephone { }; tow-boot-pinephone = callPackage ./additional/tow-boot-pinephone { };
tree-sitter-nix-shell = callPackage ./additional/tree-sitter-nix-shell { }; tree-sitter-nix-shell = callPackage ./additional/tree-sitter-nix-shell { };
unftp = callPackage ./additional/unftp { }; unftp = callPackage ./additional/unftp { };
@@ -114,13 +104,12 @@ let
helix = callPackage ./patched/helix { inherit (unpatched) helix; }; helix = callPackage ./patched/helix { inherit (unpatched) helix; };
ibus = callPackage ./patched/ibus { inherit (unpatched) ibus; };
# jackett doesn't allow customization of the bind address: this will probably always be here. # jackett doesn't allow customization of the bind address: this will probably always be here.
jackett = callPackage ./patched/jackett { inherit (unpatched) jackett; }; jackett = callPackage ./patched/jackett { inherit (unpatched) jackett; };
libgweather = callPackage ./patched/libgweather { inherit (unpatched) libgweather; };
# modemmanager = callPackage ./patched/modemmanager { inherit (unpatched) modemmanager; }; komikku = callPackage ./patched/komikku { inherit (unpatched) komikku; };
phoc = callPackage ./patched/phoc { inherit (unpatched) phoc; };
### PYTHON PACKAGES ### PYTHON PACKAGES

View File

@@ -11,15 +11,12 @@ let
}; };
in in
helix.overrideAttrs (upstream: { helix.overrideAttrs (upstream: {
nativeBuildInputs = (upstream.nativeBuildInputs or []) ++ [
rsync
];
configurePhase = (upstream.configurePhase or "") + '' configurePhase = (upstream.configurePhase or "") + ''
cat ${languages} >> languages.toml cat ${languages} >> languages.toml
substituteAllInPlace languages.toml substituteAllInPlace languages.toml
rsync -arv ${tree-sitter-nix-shell.generated}/ runtime/grammars/sources/nix-shell/ ${rsync}/bin/rsync -arv ${tree-sitter-nix-shell.generated}/ runtime/grammars/sources/nix-shell/
rsync -arv ${tree-sitter-nix-shell}/queries/ runtime/queries/nix-shell/ ${rsync}/bin/rsync -arv ${tree-sitter-nix-shell}/queries/ runtime/queries/nix-shell/
# helix tries to delete the sources during installPhase # helix tries to delete the sources during installPhase
chmod -R +w runtime/grammars/sources/nix-shell chmod -R +w runtime/grammars/sources/nix-shell

View File

@@ -1,21 +0,0 @@
diff --git a/data/dconf/make-dconf-override-db.sh b/data/dconf/make-dconf-override-db.sh
index 32cb1530..4ce36bc1 100755
--- a/data/dconf/make-dconf-override-db.sh
+++ b/data/dconf/make-dconf-override-db.sh
@@ -12,10 +12,6 @@ export XDG_CACHE_HOME="$TMPDIR/cache"
export GSETTINGS_SCHEMA_DIR="$TMPDIR/schemas"
mkdir -p $XDG_CONFIG_HOME $XDG_CACHE_HOME $GSETTINGS_SCHEMA_DIR
-eval `dbus-launch --sh-syntax`
-
-trap cleanup EXIT
-
cleanup() {
test $? -eq 0 && exit
rm -rf $TMPDIR; kill $DBUS_SESSION_BUS_PID
@@ -57,5 +53,3 @@ if [ -d $TMPDIR/cache/gvfs ] ; then
umount $TMPDIR/cache/gvfs
fi
rm -rf $TMPDIR
-
-kill $DBUS_SESSION_BUS_PID

View File

@@ -1,18 +0,0 @@
diff --git a/configure.ac b/configure.ac
index 392cc581..6d5750dc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -345,11 +345,7 @@ fi
AC_SUBST(X11_PREFIX)
# Check locale dir for Compose files.
-AC_CHECK_FILE($X11_PREFIX/share/X11/locale/locale.dir,
- X11_LOCALEDATADIR="$X11_PREFIX/share/X11/locale",
- [AC_CHECK_FILE($X11_PREFIX/lib/X11/locale/locale.dir,
- X11_LOCALEDATADIR="$X11_PREFIX/lib/X11/locale",
- X11_LOCALEDATADIR="$(datadir)/X11/locale")])
+X11_LOCALEDATADIR="$X11_PREFIX/share/X11/locale"
AC_SUBST(X11_LOCALEDATADIR)
if test x"$enable_wayland" = x"yes"; then

View File

@@ -1,58 +0,0 @@
{ ibus
, buildPackages
, fetchFromGitHub
, gobject-introspection
, lib
, libdbusmenu-gtk3
, pkg-config
, pkgs
, stdenv
, ...
}@attrs:
let
isCross = !(stdenv.buildPlatform.canExecute stdenv.hostPlatform);
in
(ibus.override
(removeAttrs attrs [ "ibus" "libdbusmenu-gtk3" "pkgs" ] )
).overrideAttrs (upstream: rec {
# compared to 1.5.28, this version supports better cross compilation
version = "1.5.29-rc1";
src = fetchFromGitHub {
owner = "ibus";
repo = "ibus";
rev = version;
hash = "sha256-stUWAGtsQRq+g/68OKuYqHgNxZBGzGC6VgJ+IwuAkx8=";
};
patches = [(builtins.head upstream.patches)] ++ [
# this patch is in nixpkgs 1.5.28, but doesn't cleanly apply to this current version
./build-without-dbus-launch.patch
# AC_CHECK_FILE has an explicit guard against cross compiling, which is silly if you think about it for more than a second.
./configure-no-ac-check-file.patch
];
# vapigen (vala) is nativeBuildInputs, so fix the PKG_CONFIG ibus uses to find it.
# ibus does an extra sanity check with `PKG_CHECK_EXISTS`, but that doesn't support
# PKG_CONFIG_FOR_BUILD, so turn its error into just a warning.
postPatch = (upstream.postPatch or "") + lib.optionalString isCross ''
substituteInPlace m4/vapigen.m4 \
--replace PKG_PROG_PKG_CONFIG PKG_PROG_PKG_CONFIG_FOR_BUILD \
--replace 'PKG_CONFIG ' 'PKG_CONFIG_FOR_BUILD ' \
--replace 'AC_MSG_ERROR([$vapigen_pkg not found])' 'AC_MSG_WARN([$vapigen_pkg not found])'
'';
configureFlags = upstream.configureFlags ++ [
"--enable-vala"
];
# to debug:
# makeFlags = upstream.makeFlags ++ [ "V=1" ];
depsBuildBuild = (upstream.depsBuildBuild or []) ++ [
buildPackages.stdenv.cc
pkg-config
];
buildInputs = upstream.buildInputs ++ [
libdbusmenu-gtk3
];
})

View File

@@ -0,0 +1,19 @@
{ komikku
, fetchFromGitLab
, fetchpatch2
}:
komikku.overrideAttrs (upstream: {
# src = fetchFromGitLab {
# owner = "valos";
# repo = "Komikku";
# rev = "7dcf2b3d0ba685396872780b1ce75d01cbe02ebe";
# hash = "sha256-LzgHPuIpxy0ropiNycdxZP6onjK2JpMRqkkdmJGA4nE=";
# };
patches = (upstream.patches or []) ++ [
(fetchpatch2 {
url = "https://git.uninsane.org/colin/mirror-komikku/commit/318fc0c975ba84ca4dcff405bc1bb8f5895bc5a6.diff";
hash = "sha256-mn81hCt5xrypJMOOiCOg8NthLjglXntTDsYpcdCg0E8=";
})
];
passthru.unpatched = komikku;
})

View File

@@ -1,18 +0,0 @@
{ lib
, libgweather
, fetchpatch
, ...
}@attrs:
(libgweather.override
(removeAttrs attrs [ "fetchpatch" "libgweather" ])
).overrideAttrs (upstream: {
patches = lib.unique (
(upstream.patches or []) ++ [
(fetchpatch {
url = "https://gitlab.gnome.org/GNOME/libgweather/-/merge_requests/282.patch";
name = "nws: fix null string comparison when reading visibility";
hash = "sha256-yQncWfJJmXOTw8Kvxutjjlenjv1g5QR5JnLU4QhMXSo=";
})
]
);
})

View File

@@ -1,6 +0,0 @@
{ modemmanager }: modemmanager.overrideAttrs (upstream: {
patches = (upstream.patches or []) ++ [
# don't go into the "fail" state just because we can't figure out if the SIM is unlocked
./missing-sim-not-fatal.patch
];
})

View File

@@ -1,41 +0,0 @@
commit bf4b81671e9bd073efc95a2fa4d4c05c3174104f
Author: Colin <colin@uninsane.org>
Date: 2023-08-17 07:50:32 +0000
don't enter failed state due to missing sim
diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c
index 911c139d..c6550ccd 100644
--- a/src/mm-iface-modem.c
+++ b/src/mm-iface-modem.c
@@ -3773,7 +3773,8 @@ internal_load_unlock_required_ready (MMIfaceModem *self,
} else {
mm_obj_dbg (self, "couldn't check if unlock required: %s", error->message);
g_error_free (error);
- ctx->lock = MM_MODEM_LOCK_UNKNOWN;
+ mm_obj_info(self, "faking unlock state (Colin patch)");
+ ctx->lock = MM_MODEM_LOCK_NONE;
}
}
@@ -5177,13 +5178,13 @@ modem_update_lock_info_ready (MMIfaceModem *self,
/* NOTE: we already propagated the lock state, no need to do it again */
mm_iface_modem_update_lock_info_finish (self, res, &ctx->fatal_error);
if (ctx->fatal_error) {
- g_prefix_error (&ctx->fatal_error,
- "Couldn't check unlock status: ");
- /* Jump to the last step */
- ctx->step = INITIALIZATION_STEP_LAST;
- } else
- /* Go on to next step */
- ctx->step++;
+ mm_obj_info (self, "ignoring 'couldnt check unlock status' error (sane patch)");
+ g_error_free (ctx->fatal_error);
+ ctx->fatal_error = NULL;
+ }
+
+ /* Go on to next step */
+ ctx->step++;
interface_initialization_step (task);
}

View File

@@ -0,0 +1,11 @@
{ fetchpatch, phoc }:
phoc.overrideAttrs (super: {
patches = super.patches or [] ++ [
(fetchpatch {
# this patch fixes some screen-blanking issues.
# not 100% necessary, but does give a better experience.
url = "https://gitlab.gnome.org/World/Phosh/phoc/-/merge_requests/428.diff";
hash = "sha256-XaSpcjtAFbGpqSLOUvjFU84TRmjKhL0NPIDvEK4VUD4=";
})
];
})

View File

@@ -1,48 +0,0 @@
{
"data": "ENC[AES256_GCM,data:DQLyt84vTpMrWhi4PfTUNw5hma1OZxfP7gHhyhCjwAnKKtTjWh2Ew2k7PWDRhpvw57UP4vRktt8hdV6Lx5pcApwdnO73C6rO5gKzzN4lINJj7mnP7RW5yhgJey09qzm0fzmr6rEtuhTnuT6klnUE2Minlv3yV0WjuGADZR1me1AVe6UWrEmd57nx4PEh6zwL87n6ea/AK5DqSRL1De3pGC0deRd7C2hKsemklaAN7NKclgI51Qs+9Z509GlbC1CSZ1c23sBeFBxMfvaWWYBsuIbTnHi/e3WWrO4Xvx0A+Xwl4Kj1EbNWa0CguOJqgD8HNG7bHNDtJd5DuE2m1Ts6UM3Iepo1aSh7uLRCox1Em7S2zWHCGovGw5Dj4W6jhsUOHJKCBxFzZ/nh1Ltt7rc8Gc6S+p3HEXNeuRILwUGVkMl+qR3b/T5hTp1NXTEx2FkpbEWAsmrw1OnF85e5OQbWLeqLbSa2KxWEyTHZlxB20JbfRUvM4UOsy0vi4Otcl4z1O+1CiH/pmesQEWPZr0XQFJ8aG/gHakWEtlg7qPJolQh7KjSooPF6Mj62aeyjuMSe9tOdLeWQ23Qov4PY61+nRoSHb8t6DbmHM1N9kTkZsZcCvIyBE0UZTQLkekmg7FZhgn+TN1Q1LthRBTo9SYr7PfcvvTKnz/nT7yH4G6nR1CVLxPeJVPx3shUEMvDcaelR3Rt9+eXoJTab1ChhUPajtaNMSaDWrn5XcfUL1NQfxcOeiZOUBwDKPg3Por4h949pN47/OQtexUuw+ks91uYL3MdIbPh5f2VYMHX11jMl6EY9y5PIBWlmZeEdcb6EPYm0cHLwBJk+pQTYDMSXkVFCvYMMFfIKuhcw6nEcrBZJUNfH8z75eTMj7mCXX5GNrANfYrUAxNGubYBqbMQhXv4kO2NhGfKp2GDV6Zz1iXM4Vy8WXeBa/frGBkj3Q3ya/1G2EyseOwFzPNxhfqJ1tUfJ2+NDYbsruPWgyXrSvy1/McM5PiRFeQBaVUyhF5GQbmuiVDgFFdnHaPudD4NAu3juWUu0tnCuEpj5cnR7jaFrIrutf7mwHJXi9ipXE1Go2nX7yQT4jhQtQv2Rt3v9kQOV9xfIPgdaP0jd7iPyuOam3nSK4GlsSzG6B8GYw7yUtRDKU//Vi2s/roXzc2ADeXRS3GqJNeHkrPIvhku6JyTZH9vLx7co8IC5ZP+ziMTBcAbpUH0RjlugGuzzDQUz+mv+OJMVr+kXyzxFjBNvF1COweXACJD0A+9KMStUPXZlCZDd5a61nw61yQyVf2UK+SFkPEL80C61ZWbuLDuBc6V0h48vEiw/07/MIcpnhLzLggCpoyXYLlZH,iv:q2agBEI1tvVMPc4TYJJpwkJvrENBVP4LrtAmlKT+wwo=,tag:oj8Bope12LHUvJl4vB6lxg==,type:str]",
"sops": {
"kms": null,
"gcp_kms": null,
"azure_kv": null,
"hc_vault": null,
"age": [
{
"recipient": "age1tnl4jfgacwkargzeqnhzernw29xx8mkv73xh6ufdyde6q7859slsnzf24x",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQSGNFU00rSERHQXJJTnpL\nRXNoYm4xazN6Z3dvMDZ1OTA2Q1g3OURrRFdjCkgxaUZaN3k5RHFGM0hTWkRybFBV\ncnVZVkFiV0NWeXJoWGloV0c5Um01cncKLS0tIGZFODFxeXVpNmkyRFN0SE1ZK2J3\nTkd6dzFNT0F5dTJ6VGVVYTJwY2xCL2MKTDHVtRp1uojeHJ2dILTvjQTXtWU0A2ZT\n6KEe5pkoadVoI3lu70RLyGGQuImGgc/ZsEJiV2CHIuKG17J3bexBBw==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1j2pqnl8j0krdzk6npe93s4nnqrzwx978qrc0u570gzlamqpnje9sc8le2g",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2TWYwdmQxVzRESGR4Q0J1\nN0JXK2V3SXB1SWJxeHJKNjFpOXI3ZkFTbFNJCmNQeHRiM281MXliNDVHNExVMGtX\nR3FZcmtTdWhtaU1NSmlwbjdkcUJtVGcKLS0tIEtJaXBsZXVBSFRnZjRWRGdVcVBQ\nQ0RqQmhMZEJ5cXBkVk1CdWZsMFROSTAKx+uAnbpXblkJi8zSiyJXO3UtHTydGbM4\naSN58lAR3yCuSuNHdUlDXr9TQfF4rTHEBGMBFh0ey/CmX8hzoJXiDQ==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1z8fauff34cdecr6sjkre260luzxcca05kpcwvhx988d306tpcejsp63znu",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpZllMSHRDN0tUajdwdzR6\nOTdadjN3L2JFR2RNcVVob0NLWGlycFdMNm5RCk5XbTExc09leGpsMUxUTWFBYjhy\nMnNDazI5WHprMFRNWVc1QkdKTkppZmsKLS0tIEJWRzhBb2lKeDc5bHl6OXdvMDZD\nS0UxSXM5R2xOUU1Ud2s2UmRkVE5uNlkKAHjY/gUahrkgAbb+2Q43asvVrgdaKfWC\nO5JPHo+krBydvNZ2k4261lBF8zwJ++D+qZK396WxChMH/RhiiPUBSQ==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1zsrsvd7j6l62fjxpfd2qnhqlk8wk4p8r0dtxpe4sdgnh2474095qdu7xj9",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAxYVJYL3pmVjRmczJjaTlF\nUW9OOGU5dzdWTHg1bzh2OHR5d0tNTGF0NmdRClQxNVF4b0Z6ZzF0YndvWmZoMlBD\nQXB0dmZhQ3N6S2VjRFh5bko1LzJYR3MKLS0tIEgxS3kzWHJSUStUcDRDRG84bGJ3\nYmRNeEMybDB3b1dFV1QxNmhJeTNCM2MKywwuf2TNR0VuEQcaZB4uYdxSyG6dzNiy\nX2/ke2xG8yApIKW5WIrOO+UgGB9i7ZdiGKUx73YUKgm/4IECfbHxSg==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1vnw7lnfpdpjn62l3u5nyv5xt2c965k96p98kc43mcnyzpetrts9q54mc9v",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLdmtEWXJDUUdKdjF6QmNY\nUGd3dW5BNXY0NnB3WE9aSWF3RWxiNi9TMDJnCmhxaDBEVHRWelpLdEgvT2d5Uy9Y\nOUFBK1ZNdHl1Mi9kZ0dZSmpVUVJyQzAKLS0tIFNpeDBFa25wNmhqZk5vT0dOYk1B\nSWhKV2JKMmh4RllQWC9EQ08wVmZ4UmsKQVCwHKBSFOTrG7z3njR7HV1CC/ijQksT\nB4iYhs8Vt91QPLvVte7P9PYk5yNu3cjeV65h4jHn9G/RzfUnnNyfPw==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1w7mectcjku6x3sd8plm8wkn2qfrhv9n6zhzlf329e2r2uycgke8qkf9dyn",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBBRm9PMWpxMjlsTHpnMVk1\nRmFNclNqdFRPc1N0bU12VEpPcjhDS2JIbXpVCmo1TDdKYTZrNW8vSUdScnRSQnVP\nMENQUGg4Nm1ocEpYS2JGaCtsdloxc28KLS0tIHNjaWE4dFFyU1FBakhoa0VMZFBT\nTG1FODZGYUQwb2w5Z1pvV2tuS0xFajAKAADHxS6UTmdsAxtbR7ioemPLmxVqTEd/\nD1rhXomfMQ7NSkb5SUh8z7axGxY8BziVheQJWGwdIn6+u2KiI8b1ow==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1tzlyex2z6t88tg9h82943e39shxhmqeyr7ywhlwpdjmyqsndv3qq27x0rf",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBYYUp4VjV5d05xQWFXRjR2\nd1crNVZyRmtuM05aZHAzNE02NC9zVER4SVRFCjN2c0VlZjh6NUJheEFuSFE1cVlW\nTUhTdjhRNXJXanJFTEhlbGhaRUczVWsKLS0tIGlwRTZBWEhQSzFhY1BYQXdyMVVk\nRUFZcHQ5c1MyaVp5ZVJNamxuc1pXOUEKTsSzOuNOReMPZ99ICOW8/TCQBt8jjP6a\nO9DnwjImazq0i3HKjT+dgNYNlwG+MaUqUNdqIixjbE7s7pskSZlgjw==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age18vq5ktwgeaysucvw9t67drqmg5zd5c5k3le34yqxckkfj7wqdqgsd4ejmt",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMUGlWNkg3aVpwZnppTUpY\nVzdaeXlHWUhFeTZsTDNkY1B2a1RRajQ5YUJvCmI1a0pOTjlnai91MjIrM1I2d3hI\nd0ZkOGk2WWo0U0hOdnRmaW1FQm8zR3cKLS0tIHBYdnFqdHRHbTM2OHpRcXFNN3Bz\nQUZVNnZSQkUxZGhRM2liSXZTRVRHcWsKGMhYTWmtcRy/WjxD9uWe+iQCEMncebzr\nnkOmOPHOdnvJY+WynTAbHs7nYKKRLizchN7WHLxWah39C5KzmTSQyg==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2023-08-13T10:17:15Z",
"mac": "ENC[AES256_GCM,data:O3X0JKl6Q8JZxeTR+Zxhd8Ys7ujJM3OP/xLen7eG/cq+/MJgUxoLrRVjnKI5JuNemwcQIdsbOl9aWHB9zP1WXSyvK5mmPtt1OUi5dF27qLhRyDm0aqR8JGboI9LRDuAxXVhqNTpj0iBK5WKpHsAJNwfurkWig2tlfcH2Obgqy0Q=,iv:kAl3VLfMLmkHh7vQAA9xkBmbbYwQcUzJYeTJRl9agz0=,tag:M7UWMdL09WWJhJ/9tvDwxw==,type:str]",
"pgp": null,
"unencrypted_suffix": "_unencrypted",
"version": "3.7.3"
}
}