commit d3e03c499e83a3a785d23feca09395686e946b9a
parent 7f02f0571d95d4cea909b6fbdf4c43187c9dda80
Author: mtmn <miro@haravara.org>
Date: Mon, 25 May 2026 22:48:47 +0200
chore: add tarsnap backup target
Diffstat:
5 files changed, 7 insertions(+), 194 deletions(-)
diff --git a/hosts/void/overlays/config/magdalena/config.json.nix b/hosts/void/overlays/config/magdalena/config.json.nix
Binary files differ.
diff --git a/modules/mixins/dotfiles/bin/git-annex-init b/modules/mixins/dotfiles/bin/git-annex-init
@@ -1,189 +0,0 @@
-#!/usr/bin/env python3
-"""
-Initialize git-annex with an S3 special remote
-
-Usage:
- git-annex-init <name> <prefix> [options]
-
-Env overrides:
- BUCKET, REGION, HOST, AWS_PROFILE, LARGE_FILES_THRESHOLD
-"""
-
-import argparse
-import logging
-import os
-import subprocess
-import sys
-from pathlib import Path
-
-DEFAULTS = {
- "bucket": "mine",
- "region": "us-east-1",
- "host": "estri.haravara.org",
- "large_files_threshold": "100kb",
- "aws_profile": "default",
-}
-
-log = logging.getLogger("git-annex-init")
-
-
-def run(
- cmd: list[str], check: bool = True, capture: bool = False
-) -> subprocess.CompletedProcess:
- log.debug("$ %s", " ".join(cmd))
- return subprocess.run(cmd, check=check, capture_output=capture, text=True)
-
-
-def run_ok(cmd: list[str]) -> bool:
- return run(cmd, check=False, capture=True).returncode == 0
-
-
-def aws_credential(key: str, profile: str) -> str:
- result = run(["aws", "configure", "get", key, "--profile", profile], capture=True)
- value = result.stdout.strip()
- if not value:
- log.error("AWS credential '%s' not found in profile '%s'", key, profile)
- sys.exit(1)
- return value
-
-
-def main() -> None:
- parser = argparse.ArgumentParser(
- description="Initialize git-annex with an S3 special remote",
- formatter_class=argparse.RawDescriptionHelpFormatter,
- epilog=(
- "examples:\n"
- " git-annex-init my-project annex/my-project/\n"
- " git-annex-init my-project annex/my-project/ --dry-run\n"
- " git-annex-init my-project annex/my-project/ --bucket other --region eu-west-1\n"
- " BUCKET=other git-annex-init my-project annex/my-project/\n"
- ),
- )
- parser.add_argument("name", help="annex description (e.g. my-project)")
- parser.add_argument("prefix", help="path inside bucket (e.g. annex/my-project/)")
- parser.add_argument(
- "--bucket",
- default=os.environ.get("BUCKET", DEFAULTS["bucket"]),
- help=f"S3 bucket name (env: BUCKET, default: {DEFAULTS['bucket']})",
- )
- parser.add_argument(
- "--region",
- default=os.environ.get("REGION", DEFAULTS["region"]),
- help=f"S3 region (env: REGION, default: {DEFAULTS['region']})",
- )
- parser.add_argument(
- "--host",
- default=os.environ.get("HOST", DEFAULTS["host"]),
- help=f"S3-compatible endpoint host (env: HOST, default: {DEFAULTS['host']})",
- )
- parser.add_argument(
- "--large-files",
- default=os.environ.get(
- "LARGE_FILES_THRESHOLD", DEFAULTS["large_files_threshold"]
- ),
- metavar="THRESHOLD",
- help=f"size threshold for annex (env: LARGE_FILES_THRESHOLD, default: {DEFAULTS['large_files_threshold']})",
- )
- parser.add_argument(
- "--aws-profile",
- default=os.environ.get("AWS_PROFILE", DEFAULTS["aws_profile"]),
- help=f"AWS credentials profile (env: AWS_PROFILE, default: {DEFAULTS['aws_profile']})",
- )
- parser.add_argument(
- "--dry-run",
- action="store_true",
- help="print what would happen without executing",
- )
- parser.add_argument(
- "-v", "--verbose", action="store_true", help="show each command as it runs"
- )
- args = parser.parse_args()
-
- logging.basicConfig(
- level=logging.DEBUG if args.verbose else logging.INFO,
- format="%(message)s",
- )
-
- if args.dry_run:
- log.info("Dry run — no changes will be made")
-
- cwd = Path.cwd()
-
- # Credentials
- log.info("Fetching AWS credentials from profile '%s'", args.aws_profile)
- os.environ["AWS_ACCESS_KEY_ID"] = aws_credential(
- "aws_access_key_id", args.aws_profile
- )
- os.environ["AWS_SECRET_ACCESS_KEY"] = aws_credential(
- "aws_secret_access_key", args.aws_profile
- )
-
- if args.dry_run:
- log.info(
- "Would initialize git-annex for '%s' at s3://%s/%s",
- args.name,
- args.bucket,
- args.prefix,
- )
- sys.exit(0)
-
- # git init
- if not (cwd / ".git").exists():
- log.info("Initializing git repository...")
- run(["git", "init"])
-
- # git-annex init
- if not run_ok(["git", "annex", "status"]):
- log.info("Initializing git-annex")
- run(["git", "annex", "init", args.name])
- run(
- [
- "git",
- "annex",
- "config",
- "--set",
- "annex.largefiles",
- f"largerthan={args.large_files}",
- ]
- )
-
- # Stage and commit
- log.info("Staging files...")
- run(["git", "add", "."])
- run(["git", "annex", "add", "."])
- if not run_ok(["git", "diff", "--cached", "--quiet"]):
- run(["git", "commit", "-m", "Initial commit"])
-
- # S3 remote
- if not run_ok(["git", "annex", "info", "s3"]):
- log.info("Initializing S3 remote")
- run(
- [
- "git",
- "annex",
- "initremote",
- "s3",
- "type=S3",
- f"bucket={args.bucket}",
- f"region={args.region}",
- f"host={args.host}",
- "requeststyle=path",
- "encryption=none",
- "storageclass=STANDARD_IA",
- f"fileprefix={args.prefix}",
- ]
- )
- else:
- log.info("Enabling existing S3 remote")
- run(["git", "annex", "enableremote", "s3"])
-
- # Push
- log.info("Copying files to S3")
- run(["git", "annex", "copy", "--to", "s3", "."])
- run(["git", "annex", "sync", "s3"])
-
- log.info("%s → s3://%s/%s", args.name, args.bucket, args.prefix)
-
-
-if __name__ == "__main__":
- main()
diff --git a/modules/mixins/dotfiles/bin/habitual b/modules/mixins/dotfiles/bin/habitual
@@ -1,4 +1,5 @@
#!/usr/bin/env bb
+;; vim: ft=clojure
(ns habitual
(:require [clojure.string :as str]
diff --git a/modules/mixins/dotfiles/bin/khal_notifier b/modules/mixins/dotfiles/bin/khal_notifier
@@ -1,4 +1,5 @@
#!/usr/bin/env bb
+;; vim: ft=clojure
(ns khal-notifier
(:require [clojure.string :as str]
diff --git a/modules/mixins/dotfiles/config/shell/rc/functions b/modules/mixins/dotfiles/config/shell/rc/functions
@@ -65,16 +65,16 @@ tracklist() {
done
}
-tarsnap_stamp() {
- : "${1?name required}" "${2?path required}"
- tarsnap -c -f "$1-$(date +%Y-%m-%d_%H:%M:%S)" "$2"
-}
-
fetch_rss() {
url="${1?}"
curl -s "$url" | xmllint --html --xpath "//link[@type='application/rss+xml' or @type='application/atom+xml']/@href" - 2>/dev/null
}
+tarstamp() {
+ : "${1?name required}" "${2?path required}"
+ tarsnap -c -f "$1-$(date +%Y-%m-%d_%H:%M:%S)" "$2"
+}
+
tempfox() {
profile_dir=$(mktemp -d)
trap 'rm -rf $profile_dir' EXIT