Commit Diff


commit - ae5aa9a50db15820fc8a70f7c4df959e3a0f2f55
commit + a8faa655182c99eec22474577824865e01708bfb
blob - 6c7ed502dfa7df4856480decf61552578cf1c502
blob + bf941187f75ba213ef501ba2d0060ef2de7ae638
--- flake.lock
+++ flake.lock
@@ -180,11 +180,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1785269816,
-        "narHash": "sha256-6JkNDlJ18NY1iAuoSYCPDO7O+yYN/vPwpFmHOHNpVvY=",
+        "lastModified": 1785306346,
+        "narHash": "sha256-DScBkW0fOgpGPK2trNoX3ryLTlaC14+gglFo/BhGJ4g=",
         "owner": "nix-community",
         "repo": "home-manager",
-        "rev": "3d25fa94cf355cf7da64c77bb9c3c15806486329",
+        "rev": "e705714e918c3b11affcdd15db2cbe3a070420a0",
         "type": "github"
       },
       "original": {
@@ -250,11 +250,11 @@
     },
     "nixpkgs_2": {
       "locked": {
-        "lastModified": 1785141334,
-        "narHash": "sha256-kh35kIx7el4Jk8Ki3BH9/Pn1eZYSYLJ6LMALos0zOy0=",
+        "lastModified": 1785301185,
+        "narHash": "sha256-eoS3KQTO0aPWXZvIaRbRAzSSHW3l5wdMFXtT1ISfoKA=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "38a4887411571457d700c51c64a6e49ead2ed5ab",
+        "rev": "9bc02893134c733dd85de46ee4fb2fac696b5529",
         "type": "github"
       },
       "original": {
blob - d95e7427ef7f93d3a4b2d8412b0109392631746c
blob + 53c6001b06e0b961375207a918c7208746425808
--- hosts/void/default.nix
+++ hosts/void/default.nix
@@ -183,6 +183,7 @@
       ollama
       codex
       opencode
+      snip
     ];
 
     gui = [
blob - aa39ddb4f9deb8945f96157a7a8de93f38f6bf08
blob + 3ec368b17031d06c75994965fbece8e984aeec8f
Binary files hosts/void/overlays/config/magdalena/config.json.nix and hosts/void/overlays/config/magdalena/config.json.nix differ
blob - 8902e1157561d9a63e3a029058b919dfdaf7613f
blob + 02c99c2bdc8b10d8c571fc4ca15da433faaa9f43
Binary files hosts/void/overlays/config/shell/rc/void and hosts/void/overlays/config/shell/rc/void differ
blob - 7c902d4266cc04338302f85490c4f1a07d2b6acb
blob + ea7c3a39956379384783cd91d73f7f725819480b
--- modules/mixins/dotfiles/bin/backup
+++ modules/mixins/dotfiles/bin/backup
@@ -222,13 +222,13 @@ module Backup
     log("Done plakar/#{store}/#{source}")
   end
 
-  def self.plakar_store(verbose:, store:)
+  def self.plakar_store(verbose:, store:, exclude: [])
     fatal("Unknown plakar store: #{store}") unless plakar_stores_list.include?(store)
-    plakar_sources_list.each { |src| plakar_source(verbose: verbose, store: store, source: src) }
+    (plakar_sources_list - exclude).each { |src| plakar_source(verbose: verbose, store: store, source: src) }
   end
 
-  def self.backup_plakar(verbose:)
-    plakar_stores_list.each { |store| plakar_store(verbose: verbose, store: store) }
+  def self.backup_plakar(verbose:, exclude: [])
+    plakar_stores_list.each { |store| plakar_store(verbose: verbose, store: store, exclude: exclude) }
   end
 
   def self.list_flat(name, dirs)
@@ -253,11 +253,12 @@ module Backup
     puts("  #{RCLONE_REMOTE}")
   end
 
-  def self.git_run(verbose:, push:, fetch:, parts:)
+  def self.git_run(verbose:, push:, fetch:, parts:, exclude:)
     if parts.empty?
-      GIT_DIRS.each { |n, d| sync_repo(verbose: verbose, push: push, fetch: fetch, name: n, dir: d) }
+      GIT_DIRS.except(*exclude).each { |n, d| sync_repo(verbose: verbose, push: push, fetch: fetch, name: n, dir: d) }
     else
       name = parts.first
+      return if exclude.include?(name)
       sync_repo(
         verbose: verbose,
         push: push,
@@ -268,11 +269,12 @@ module Backup
     end
   end
 
-  def self.tarsnap_run(verbose:, parts:)
+  def self.tarsnap_run(verbose:, parts:, exclude:)
     if parts.empty?
-      TARSNAP_DIRS.each { |n, d| tarsnap_archive(verbose: verbose, name: n, dir: d) }
+      TARSNAP_DIRS.except(*exclude).each { |n, d| tarsnap_archive(verbose: verbose, name: n, dir: d) }
     else
       name = parts.first
+      return if exclude.include?(name)
       tarsnap_archive(
         verbose: verbose,
         name: name,
@@ -281,11 +283,12 @@ module Backup
     end
   end
 
-  def self.rclone_run(verbose:, parts:)
+  def self.rclone_run(verbose:, parts:, exclude:)
     if parts.empty?
-      plakar_source_dirs.each { |n, d| rclone_backup(verbose: verbose, name: n, dir: d) }
+      plakar_source_dirs.except(*exclude).each { |n, d| rclone_backup(verbose: verbose, name: n, dir: d) }
     else
       name = parts.first
+      return if exclude.include?(name)
       rclone_backup(
         verbose: verbose,
         name: name,
@@ -294,14 +297,15 @@ module Backup
     end
   end
 
-  def self.plakar_run(verbose:, parts:)
+  def self.plakar_run(verbose:, parts:, exclude:)
     if parts.empty?
-      backup_plakar(verbose: verbose)
+      backup_plakar(verbose: verbose, exclude: exclude)
     elsif parts.size == 1
-      plakar_store(verbose: verbose, store: parts.first)
+      plakar_store(verbose: verbose, store: parts.first, exclude: exclude)
     else
       store = parts[0]
-      parts[1].split(",").each do |source|
+      selected = parts[1].split(",") - exclude
+      selected.each do |source|
         plakar_source(verbose: verbose, store: store, source: source)
       end
     end
@@ -310,19 +314,19 @@ module Backup
   BACKENDS = {
     "git" => Backend.new(
       list: -> { list_flat("git", GIT_DIRS) },
-      run: ->(verbose:, push:, fetch:, parts:) { git_run(verbose: verbose, push: push, fetch: fetch, parts: parts) }
+      run: ->(verbose:, push:, fetch:, exclude:, parts:) { git_run(verbose: verbose, push: push, fetch: fetch, exclude: exclude, parts: parts) }
     ),
     "tarsnap" => Backend.new(
       list: -> { list_flat("tarsnap", TARSNAP_DIRS) },
-      run: ->(verbose:, push:, fetch:, parts:) { tarsnap_run(verbose: verbose, parts: parts) }
+      run: ->(verbose:, push:, fetch:, exclude:, parts:) { tarsnap_run(verbose: verbose, exclude: exclude, parts: parts) }
     ),
     "plakar" => Backend.new(
       list: -> { list_plakar },
-      run: ->(verbose:, push:, fetch:, parts:) { plakar_run(verbose: verbose, parts: parts) }
+      run: ->(verbose:, push:, fetch:, exclude:, parts:) { plakar_run(verbose: verbose, exclude: exclude, parts: parts) }
     ),
     "rclone" => Backend.new(
       list: -> { list_rclone },
-      run: ->(verbose:, push:, fetch:, parts:) { rclone_run(verbose: verbose, parts: parts) }
+      run: ->(verbose:, push:, fetch:, exclude:, parts:) { rclone_run(verbose: verbose, exclude: exclude, parts: parts) }
     )
   }.freeze
 
@@ -330,11 +334,11 @@ module Backup
     BACKENDS.each_value { |b| b.list.call }
   end
 
-  def self.backup_target(verbose:, push:, fetch:, target:)
+  def self.backup_target(verbose:, push:, fetch:, exclude:, target:)
     parts = target.split(":")
     bname = parts.shift
     backend = BACKENDS[bname] || fatal("Unknown target: #{target}")
-    backend.run.call(verbose: verbose, push: push, fetch: fetch, parts: parts)
+    backend.run.call(verbose: verbose, push: push, fetch: fetch, exclude: exclude, parts: parts)
   end
 
   def self.main(args)
@@ -353,21 +357,22 @@ module Backup
             end
           end
         rescue Errno::ESRCH
-          # process already gone
         end
       end
       exit(130)
     end
 
-    options = {verbose: true, push: false, fetch: false, list: false}
+    options = {verbose: true, push: false, fetch: false, list: false, exclude: []}
     parser = OptionParser.new do |o|
       o.banner = "Usage: backup [options] [target]\n" \
         "  target: git, plakar, tarsnap, rclone, <backend>:<name>\n" \
-        "  plakar sources may be comma-separated: plakar:<store>:<src1,src2,...>"
+        "  plakar sources may be comma-separated: plakar:<store>:<src1,src2,...>\n" \
+        "  -e may exclude sources: backup plakar:<store> -e <src1,src2,...>"
       o.on("-p", "--push", "Fetch and push changes after commit") { options[:push] = true }
       o.on("-f", "--fetch", "Run git pull for git targets before backup") { options[:fetch] = true }
       o.on("-q", "--quiet", "Suppress command output") { options[:verbose] = false }
       o.on("-l", "--list", "List all configured backup targets") { options[:list] = true }
+      o.on("-e", "--exclude LIST", "Comma-separated list of sources/targets to skip") { |v| options[:exclude].concat(v.split(",").map(&:strip)) }
       o.on("-h", "--help") do
         puts(o)
         exit(0)
@@ -385,7 +390,7 @@ module Backup
 
     list_targets if options[:list]
     if target
-      backup_target(verbose: options[:verbose], push: options[:push], fetch: options[:fetch], target: target)
+      backup_target(verbose: options[:verbose], push: options[:push], fetch: options[:fetch], exclude: options[:exclude], target: target)
     end
 
     fatal("#{@failures.size} backup target(s) failed") unless @failures.empty?
blob - b62ba0a4f132ec5a1a0fb8d57706613216d7a6b0
blob + 129cdbe34731bd3eccd99b70601c1b9dae3571ae
--- modules/mixins/dotfiles/config/newsraft/feeds
+++ modules/mixins/dotfiles/config/newsraft/feeds
@@ -237,7 +237,6 @@ https://www.youtube.com/feeds/videos.xml?channel_id=UC
 https://www.youtube.com/feeds/videos.xml?channel_id=UC_ML5xP23TOWKUcc-oAE_Eg Hussein Nasser
 https://www.youtube.com/feeds/videos.xml?channel_id=UCQoOmu6mKZkXTnwZcpD8Ciw Jason Schreier
 https://www.youtube.com/feeds/videos.xml?channel_id=UCAwT-7B6StW_xzXPku6v7MQ Mo Bitar
-https://www.youtube.com/feeds/videos.xml?channel_id=UC_mYaQAE6-71rjSN6CeCA-g NeetCode
 https://www.youtube.com/feeds/videos.xml?channel_id=UCsBjURrPoezykLs9EqgamOA Fireship
 https://www.youtube.com/feeds/videos.xml?channel_id=UCnbKOlm6H9njgmN-Yil90Rg Heather Cox Richardson
 https://www.youtube.com/feeds/videos.xml?channel_id=UC7UukP_hxrOsrwHrcHxOxxg Kay Lack
@@ -269,3 +268,4 @@ https://www.youtube.com/feeds/videos.xml?channel_id=UC
 https://www.youtube.com/feeds/videos.xml?channel_id=UCm_dHxrHKK_fmoUgj9YnYqw Truttle1
 https://www.youtube.com/feeds/videos.xml?channel_id=UCPIt7i7t3qCKVob-3dWrYjw NCOT Technology
 https://www.youtube.com/feeds/videos.xml?channel_id=UC0uTPqBCFIpZxlz_Lv1tk_g Protesilaos
+https://www.youtube.com/feeds/videos.xml?channel_id=UChzRJQ-MbpcIxFT5YLW1R9w Juniper Dev