flake-update-20260505
1#!/usr/bin/env python3
2"""List git repositories under ~/src/ for raffi script filter.
3
4Outputs Alfred Script Filter JSON format.
5Results are cached for 2 hours.
6Usage: lazyworktree-raffi [query]
7"""
8
9import json
10import os
11import sys
12import tempfile
13import time
14
15CACHE_MAX_AGE = 7200 # 2 hours
16SRC_DIR = os.path.expanduser("~/src")
17
18
19def cache_paths():
20 cache_home = os.environ.get("XDG_CACHE_HOME", os.path.expanduser("~/.cache"))
21 cache_dir = os.path.join(cache_home, "lazyworktree-raffi")
22 os.makedirs(cache_dir, exist_ok=True)
23 return cache_dir, os.path.join(cache_dir, "repos.json")
24
25
26def needs_rebuild(cache_file):
27 try:
28 age = time.time() - os.path.getmtime(cache_file)
29 return age > CACHE_MAX_AGE
30 except FileNotFoundError:
31 return True
32
33
34def find_repos():
35 repos = []
36 for root, dirs, _files in os.walk(SRC_DIR):
37 # Skip worktree internal directories
38 if "worktrees" in root.split(os.sep):
39 dirs.clear()
40 continue
41 if ".git" in dirs or ".git" in _files:
42 repos.append(root)
43 dirs.clear() # Don't descend into nested repos
44 repos.sort()
45 return [
46 {
47 "title": os.path.relpath(r, SRC_DIR),
48 "subtitle": r,
49 "arg": r,
50 }
51 for r in repos
52 ]
53
54
55def rebuild_cache(cache_dir, cache_file):
56 repos = find_repos()
57 fd, tmpfile = tempfile.mkstemp(suffix=".json", dir=cache_dir)
58 try:
59 with os.fdopen(fd, "w") as f:
60 json.dump(repos, f)
61 os.replace(tmpfile, cache_file)
62 except BaseException:
63 os.unlink(tmpfile)
64 raise
65
66
67def load_cache(cache_file):
68 try:
69 with open(cache_file) as f:
70 data = f.read()
71 if not data:
72 return []
73 return json.loads(data)
74 except (FileNotFoundError, json.JSONDecodeError):
75 return []
76
77
78def main():
79 cache_dir, cache_file = cache_paths()
80
81 if needs_rebuild(cache_file):
82 rebuild_cache(cache_dir, cache_file)
83
84 items = load_cache(cache_file)
85
86 query = " ".join(sys.argv[1:]).strip().lower()
87 if query:
88 items = [i for i in items if query in i["title"].lower()]
89
90 json.dump({"items": items}, sys.stdout)
91
92
93if __name__ == "__main__":
94 main()