Commit 319af684da5e

Vincent Demeester <vincent@sbr.pm>
2025-03-07 17:59:20
refactor: improve XDG Base Directory compliance
This commit moves several user configuration files to follow the XDG Base Directory Specification by setting proper XDG environment variables for various tools. It also enables Nix's XDG compliance setting, reorganizes age-related packages, and improves shell configuration with proper XDG paths for wget, z, tldr cache, Cargo, Go, NPM, and Python history. Signed-off-by: Vincent Demeester <vincent@sbr.pm>
1 parent 2ccc849
systems/hosts/aomi.nix
@@ -196,10 +196,6 @@ in
     catt
     go-org-readwise
     vscode
-    # move to its own
-    passage
-    age
-    age-plugin-yubikey
     age-plugin-tpm
   ];
 
systems/hosts/wakasu.nix
@@ -158,11 +158,6 @@ in
     virt-manager
     catt
     go-org-readwise
-    aerc # move it on its own
-    # move to its own
-    passage
-    age
-    age-plugin-yubikey
     age-plugin-tpm
   ];
 
systems/modules/core/default.nix
@@ -11,6 +11,7 @@
   ];
 
   environment.systemPackages = with pkgs; [
+    age
     cachix
     file
     htop
systems/modules/core/nix.nix
@@ -96,6 +96,8 @@ in
         sandbox = true;
         allowed-users = [ "@wheel" ];
         trusted-users = [ "root" "@wheel" ];
+        # See https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-use-xdg-base-directories
+        use-xdg-base-directories = true;
       };
     };
 
systems/modules/hardware/yubikey.nix
@@ -26,6 +26,7 @@ in
           yubico-piv-tool
           yubikey-personalization
           yubikey-manager
+          age-plugin-yubikey
         ];
       };
       services = {
users/vincent/core/shell.nix
@@ -10,9 +10,9 @@
     la = ''ls -a'';
     l = ''ls -lah'';
     # t = ''exa --tree --level=2'';
-    wget = ''wget -c'';
     map = ''xargs -n1'';
     k = ''kubectl'';
+    wget = ''wget -c --hsts-file=${config.xdg.dataHome}/wget-hsts'';
   };
 
   env = ''
@@ -23,6 +23,8 @@
     if [ -d $HOME/.krew/bin ]; then
       export PATH=$HOME/.krew/bin:$PATH
     fi
+    # TODO Move somewhere else
+    export TLDR_CACHE_DIR="$XDG_CACHE_HOME"/tldr 
   '';
 
   historySize = 10000;
users/vincent/core/zsh.nix
@@ -33,55 +33,57 @@ in
     };
     envExtra = shellConfig.env;
     initExtra = ''
-            # c.f. https://wiki.gnupg.org/AgentForwarding
-            gpgconf --create-socketdir &!
-            path+="$HOME/${config.programs.zsh.dotDir}/functions"
-            fpath+="$HOME/.nix-profile/share/zsh/site-functions"
-            fpath+="$HOME/${config.programs.zsh.dotDir}/functions"
-            for func ($HOME/${config.programs.zsh.dotDir}/functions) autoload -U $func/*(x:t)
-            autoload -Uz select-word-style; select-word-style bash
-            if [ -e /home/vincent/.nix-profile/etc/profile.d/nix.sh ]; then . /home/vincent/.nix-profile/etc/profile.d/nix.sh; fi
-            #if [ -n "$INSIDE_EMACS" ]; then
-            #  chpwd() { print -P "\033AnSiTc %d" }
-            #  print -P "\033AnSiTu %n"
-            #  print -P "\033AnSiTc %d"
-            #fi
-            if [[ "$TERM" == "dumb" || "$TERM" == "emacs" ]]
-            then
-              TERM=eterm-color
-              unsetopt zle
-              unsetopt prompt_cr
-              unsetopt prompt_subst
-              unfunction precmd
-              unfunction preexec
-              PS1='$ '
-              return
-            fi
-      			# eval "$(${config.programs.atuin.package}/bin/atuin init zsh)"
-            # make sure navigation using emacs keybindings works on all non-alphanumerics
-            # syntax highlighting
-            source $HOME/${config.programs.zsh.dotDir}/plugins/zsh-nix-shell/nix-shell.plugin.zsh
-            source ${pkgs.zsh-syntax-highlighting}/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
-            ZSH_HIGHLIGHT_PATTERNS+=('rm -rf *' 'fg=white,bold,bg=red')
-            ZSH_HIGHLIGHT_PATTERNS+=('rm -fR *' 'fg=white,bold,bg=red')
-            ZSH_HIGHLIGHT_PATTERNS+=('rm -fr *' 'fg=white,bold,bg=red')
-            source $HOME/${config.programs.zsh.dotDir}/completion.zsh
-            source $HOME/${config.programs.zsh.dotDir}/plugins/powerlevel10k/powerlevel10k.zsh-theme
-            source $HOME/${config.programs.zsh.dotDir}/prompt.zsh
-            source $HOME/${config.programs.zsh.dotDir}/plugins/kubectl-config-switcher/kubectl-config-switcher.plugin.zsh
-            setopt HIST_IGNORE_SPACE
-            alias -g L="|less"
-            alias -g EEL=' 2>&1 | less'
-            alias -g GB='`git rev-parse --abbrev-ref HEAD`'
-            alias -g GR='`git rev-parse --show-toplevel`'
-            alias -s {ape,avi,flv,m4a,mkv,mov,mp3,mp4,mpeg,mpg,ogg,ogm,wav,webm}=mpv
-            alias -s org=emacs
-            (( $+commands[jq] )) && alias -g MJ="| jq -C '.'"  || alias -g MJ="| ${pkgs.python3}/bin/python -mjson.tool"
-            (( $+functions[zshz] )) && compdef _zshz j
-            [[ -n $INSIDE_EMACS ]] && \
-            function ff () {
-              print "\e]51;Efind-file $(readlink -f $1)\e\\"
-            }
+      # c.f. https://wiki.gnupg.org/AgentForwarding
+      gpgconf --create-socketdir &!
+      path+="$HOME/${config.programs.zsh.dotDir}/functions"
+      fpath+="$HOME/.nix-profile/share/zsh/site-functions"
+      fpath+="$HOME/${config.programs.zsh.dotDir}/functions"
+      for func ($HOME/${config.programs.zsh.dotDir}/functions) autoload -U $func/*(x:t)
+      autoload -Uz select-word-style; select-word-style bash
+      if [ -e /home/vincent/.nix-profile/etc/profile.d/nix.sh ]; then . /home/vincent/.nix-profile/etc/profile.d/nix.sh; fi
+      #if [ -n "$INSIDE_EMACS" ]; then
+      #  chpwd() { print -P "\033AnSiTc %d" }
+      #  print -P "\033AnSiTu %n"
+      #  print -P "\033AnSiTc %d"
+      #fi
+      if [[ "$TERM" == "dumb" || "$TERM" == "emacs" ]]
+      then
+        TERM=eterm-color
+        unsetopt zle
+        unsetopt prompt_cr
+        unsetopt prompt_subst
+        unfunction precmd
+        unfunction preexec
+        PS1='$ '
+        return
+      fi
+      # eval "$(${config.programs.atuin.package}/bin/atuin init zsh)"
+      # make sure navigation using emacs keybindings works on all non-alphanumerics
+      # syntax highlighting
+      source $HOME/${config.programs.zsh.dotDir}/plugins/zsh-nix-shell/nix-shell.plugin.zsh
+      source ${pkgs.zsh-syntax-highlighting}/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
+      ZSH_HIGHLIGHT_PATTERNS+=('rm -rf *' 'fg=white,bold,bg=red')
+      ZSH_HIGHLIGHT_PATTERNS+=('rm -fR *' 'fg=white,bold,bg=red')
+      ZSH_HIGHLIGHT_PATTERNS+=('rm -fr *' 'fg=white,bold,bg=red')
+      source $HOME/${config.programs.zsh.dotDir}/completion.zsh
+      source $HOME/${config.programs.zsh.dotDir}/plugins/powerlevel10k/powerlevel10k.zsh-theme
+      source $HOME/${config.programs.zsh.dotDir}/prompt.zsh
+      source $HOME/${config.programs.zsh.dotDir}/plugins/kubectl-config-switcher/kubectl-config-switcher.plugin.zsh
+      setopt HIST_IGNORE_SPACE
+      alias -g L="|less"
+      alias -g EEL=' 2>&1 | less'
+      alias -g GB='`git rev-parse --abbrev-ref HEAD`'
+      alias -g GR='`git rev-parse --show-toplevel`'
+      alias -s {ape,avi,flv,m4a,mkv,mov,mp3,mp4,mpeg,mpg,ogg,ogm,wav,webm}=mpv
+      alias -s org=emacs
+      (( $+commands[jq] )) && alias -g MJ="| jq -C '.'"  || alias -g MJ="| ${pkgs.python3}/bin/python -mjson.tool"
+      (( $+functions[zshz] )) && compdef _zshz j
+      [[ -n $INSIDE_EMACS ]] && \
+      function ff () {
+        print "\e]51;Efind-file $(readlink -f $1)\e\\"
+      }
+
+      export _Z_DATA="${config.xdg.dataHome}/z" 
     '';
     loginExtra = ''
       if [[ -z $DISPLAY && $TTY = /dev/tty1 ]]; then
users/vincent/desktop/passwordstore.nix
@@ -1,12 +1,17 @@
-{ pkgs, ... }:
+{ config, pkgs, ... }:
 
 {
-  # Migrate to passage
+  home.sessionVariables = {
+    "PASSAGE_DIR" = "${config.xdg.dataHome}/passage";
+    "PASSAGE_IDENTITIES_FILE" = "${config.xdg.dataHome}/passage/identities";
+  };
+  # TODO Migrate to passage
   programs.password-store = {
     enable = true;
     package = pkgs.pass-wayland.withExtensions (exts: [ exts.pass-otp exts.pass-genphrase exts.pass-update ]);
   };
   home.packages = with pkgs; [
     wofi-pass
+    passage
   ];
 }
users/vincent/dev/default.nix
@@ -1,4 +1,4 @@
-{ pkgs, ... }:
+{ config, pkgs, ... }:
 
 {
   imports = [
@@ -13,6 +13,9 @@
 
   home.extraOutputsToInstall = [ "doc" "info" "devdoc" ];
 
+  home.sessionVariables = {
+    CARGO_HOME = "${config.xdg.dataHome}/cargo";
+  };
   home.packages = with pkgs; [
     binutils
     cmake
users/vincent/dev/go.nix
@@ -3,6 +3,7 @@
 {
   home.sessionVariables = {
     # GOPATH = "${config.home.homeDirectory}";
+    GOPATH = "${config.xdg.dataHome}/go";
   };
   home.packages = with pkgs; [
     gcc
users/vincent/dev/js.nix
@@ -1,11 +1,18 @@
 { config, pkgs, ... }:
-{
-  home.file.".npmrc".text = ''
-    prefix = ${config.home.homeDirectory}/.local/npm
-  '';
 
+{
+  # config.xdg.configFile."npm/npmrc ".text = ''
+  #   prefix = ${config.home.homeDirectory}/.local/npm
+  # '';
+  home.sessionVariables = {
+    NPM_CONFIG_INIT_MODULE = "${config.xdg.configHome}/npm/config/npm-init.js";
+    NPM_CONFIG_CACHE = "${config.xdg.cacheHome}/npm";
+    NPM_CONFIG_TMP = "$CONFIG.XDG_RUNTIME_DIR/npm";
+    NPM_CONFIG_USERCONFIG = "${config.xdg.configHome}/npm/npmrc";
+  };
   home.packages = with pkgs; [
     # javascript-typescript-langserver
     # vscode-langservers-extracted
   ];
 }
+
users/vincent/dev/python.nix
@@ -1,10 +1,55 @@
-{ pkgs, ... }:
+{ config, pkgs, ... }:
 
 {
+  xdg.configFile."python/pythonrc".text = ''
+    #!/usr/bin/env python3                                                                                            
+    # This entire thing is unnecessary post v3.13.0a3                                                                 
+    # https://github.com/python/cpython/issues/73965                                                                  
+                                                                                                                  
+    def is_vanilla() -> bool:                                                                                         
+        """ :return: whether running "vanilla" Python <3.13 """                                                       
+        import sys                                                                                                    
+        return not hasattr(__builtins__, '__IPYTHON__') and 'bpython' not in sys.argv[0] and sys.version_info < (3, 13)                                                                                        
+                                                                                                                  
+                                                                                                                  
+    def setup_history():                                                                                              
+        """ read and write history from state file """                                                                
+        import os                                                                                                     
+        import atexit                                                                                                 
+        import readline                                                                                               
+        from pathlib import Path                                                                                      
+                                                                                                                  
+        # Check PYTHON_HISTORY for future-compatibility with Python 3.13                                              
+        if history := os.environ.get('PYTHON_HISTORY'):                                                               
+            history = Path(history)                                                                                   
+        # https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables                      
+        elif state_home := os.environ.get('XDG_STATE_HOME'):                                                          
+            state_home = Path(state_home)                                                                             
+        else:                                                                                                         
+            state_home = Path.home() / '.local' / 'state'                                                             
+                                                                                                                  
+        history: Path = history or state_home / 'python_history'                                                      
+                                                                                                                  
+        # https://github.com/python/cpython/issues/105694                                                             
+        if not history.is_file():                                                                                     
+            readline.write_history_file(str(history)) # breaks on macos + python3 without this.                       
+                                                                                                                  
+        readline.read_history_file(history)                                                                           
+        atexit.register(readline.write_history_file, history)                                                         
+                                                                                                                  
+                                                                                                                  
+        if is_vanilla():                                                                                                  
+            setup_history()
+  '';
   home.packages = with pkgs; [
-    python3
     pipenv
+    python3
     python3Packages.python-lsp-server
     uv
   ];
+  home.sessionVariables = {
+    PYTHONSTARTUP = "${config.xdg.configHome}/python/pythonrc";
+  };
 }
+
+