nix

configuration files that power my machines
Log | Files | Refs | README | LICENSE

commit d3e03c499e83a3a785d23feca09395686e946b9a
parent 7f02f0571d95d4cea909b6fbdf4c43187c9dda80
Author: mtmn <miro@haravara.org>
Date:   Mon, 25 May 2026 22:48:47 +0200

chore: add tarsnap backup target

Diffstat:
Mhosts/void/overlays/config/magdalena/config.json.nix | 0
Dmodules/mixins/dotfiles/bin/git-annex-init | 189-------------------------------------------------------------------------------
Mmodules/mixins/dotfiles/bin/habitual | 1+
Mmodules/mixins/dotfiles/bin/khal_notifier | 1+
Mmodules/mixins/dotfiles/config/shell/rc/functions | 10+++++-----
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