summaryrefslogtreecommitdiff
path: root/internal/liturgy
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-07-24 09:15:40 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-07-24 09:15:40 +0200
commitb93de95dd24ff2a1d3126e6d7d00cd77530a03bf (patch)
tree483a0901a20274152ba3f03f272f8098be4f49c0 /internal/liturgy
parentc1b954ad517cef00bf480d5229b253a8c6524be7 (diff)
downloadlectio-b93de95dd24ff2a1d3126e6d7d00cd77530a03bf.tar.gz
lectio-b93de95dd24ff2a1d3126e6d7d00cd77530a03bf.zip
tradlit: offline caching + read; update pre-caches traditional; --clean prunes it; v0.2.0
Diffstat (limited to 'internal/liturgy')
-rw-r--r--internal/liturgy/clean_test.go31
-rw-r--r--internal/liturgy/fetch.go32
-rw-r--r--internal/liturgy/fetch_test.go2
-rw-r--r--internal/liturgy/store.go2
4 files changed, 38 insertions, 29 deletions
diff --git a/internal/liturgy/clean_test.go b/internal/liturgy/clean_test.go
index 4dbe0d9..d9ab4fc 100644
--- a/internal/liturgy/clean_test.go
+++ b/internal/liturgy/clean_test.go
@@ -7,12 +7,13 @@ import (
"time"
)
-// TestCleanCache exercises CleanCache's file-selection rules: only
-// "<YYYY-MM-DD>.html"/".json" pairs older than the cutoff are removed; a
-// recent pair and a non-matching file are left untouched. The cutoff is a
-// fixed literal (not time.Now-derived) so the test is deterministic; only
-// the "recent" fixture is anchored to today, and only to make sure it lands
-// safely on the "keep" side of that fixed cutoff.
+// TestCleanCache exercises CleanCache's file-selection rules: date-prefixed
+// cache files (modern ".html"/".json" and traditional ".trad.<lang>.json")
+// older than the cutoff are removed; recent files and a non-matching file
+// are left untouched. The cutoff is a fixed literal (not time.Now-derived)
+// so the test is deterministic; only the "recent" fixtures are anchored to
+// today, and only to make sure they land safely on the "keep" side of that
+// fixed cutoff.
func TestCleanCache(t *testing.T) {
dir := t.TempDir()
t.Setenv("XDG_CACHE_HOME", dir)
@@ -23,10 +24,12 @@ func TestCleanCache(t *testing.T) {
recent := time.Now().Format("2006-01-02")
files := map[string]string{
- "2020-01-01.html": "<html>old</html>",
- "2020-01-01.json": `[{"Heading":"old"}]`,
- recent + ".html": "<html>recent</html>",
- "notes.txt": "not a cache file",
+ "2020-01-01.html": "<html>old</html>",
+ "2020-01-01.json": `[{"Heading":"old"}]`,
+ "2020-01-01.trad.pl.json": `[{"info":{},"sections":[]}]`,
+ recent + ".html": "<html>recent</html>",
+ recent + ".trad.pl.json": `[{"info":{},"sections":[]}]`,
+ "notes.txt": "not a cache file",
}
for name, content := range files {
if err := os.WriteFile(filepath.Join(cacheDir, name), []byte(content), 0o644); err != nil {
@@ -39,19 +42,19 @@ func TestCleanCache(t *testing.T) {
if err != nil {
t.Fatalf("CleanCache: %v", err)
}
- if removed != 2 {
- t.Errorf("removed = %d, want 2", removed)
+ if removed != 3 {
+ t.Errorf("removed = %d, want 3", removed)
}
if freed <= 0 {
t.Errorf("freed = %d, want > 0", freed)
}
- for _, gone := range []string{"2020-01-01.html", "2020-01-01.json"} {
+ for _, gone := range []string{"2020-01-01.html", "2020-01-01.json", "2020-01-01.trad.pl.json"} {
if _, err := os.Stat(filepath.Join(cacheDir, gone)); !os.IsNotExist(err) {
t.Errorf("%s still exists after CleanCache, want removed", gone)
}
}
- for _, kept := range []string{recent + ".html", "notes.txt"} {
+ for _, kept := range []string{recent + ".html", recent + ".trad.pl.json", "notes.txt"} {
if _, err := os.Stat(filepath.Join(cacheDir, kept)); err != nil {
t.Errorf("%s missing after CleanCache, want kept: %v", kept, err)
}
diff --git a/internal/liturgy/fetch.go b/internal/liturgy/fetch.go
index f4f6992..8c887f4 100644
--- a/internal/liturgy/fetch.go
+++ b/internal/liturgy/fetch.go
@@ -41,11 +41,13 @@ var publishedRe = regexp.MustCompile(`id="\w*0all"`)
// validate its own input first.
var dateRe = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}$`)
-// cacheFileRe matches the cache file names Load/Harvest write into
-// cacheDir(): "<YYYY-MM-DD>.html" or "<YYYY-MM-DD>.json". CleanCache uses it
-// to tell cache entries apart from anything else that might be sitting in
-// the directory.
-var cacheFileRe = regexp.MustCompile(`^(\d{4}-\d{2}-\d{2})\.(html|json)$`)
+// cacheFileRe matches the date-prefixed cache file names Load/Harvest/tradlit
+// write into CacheDir(): "<YYYY-MM-DD>.html", "<YYYY-MM-DD>.json", and
+// "<YYYY-MM-DD>.trad.<lang>.json" (the traditional-lectionary cache; see
+// internal/tradlit). CleanCache uses it to tell cache entries apart from
+// anything else that might be sitting in the directory, and to recover the
+// date (group 1) for the age check regardless of which cache file it is.
+var cacheFileRe = regexp.MustCompile(`^(\d{4}-\d{2}-\d{2})\.[a-z0-9.]+$`)
// Options controls how Load resolves a day's readings.
type Options struct {
@@ -58,9 +60,11 @@ type Options struct {
Offline bool
}
-// cacheDir is where the HTML/JSON cache layers live:
+// CacheDir is where the HTML/JSON cache layers live:
// ${XDG_CACHE_HOME:-~/.cache}/lectio/
-func cacheDir() string {
+// Exported so internal/tradlit shares the same cache root for the
+// traditional lectionary's propers.
+func CacheDir() string {
base := os.Getenv("XDG_CACHE_HOME")
if base == "" {
home, err := os.UserHomeDir()
@@ -93,7 +97,7 @@ func Load(opts Options) ([]Section, error) {
return LoadOffline(opts.Date)
}
- dir := cacheDir()
+ dir := CacheDir()
jsonPath := filepath.Join(dir, opts.Date+".json")
htmlPath := filepath.Join(dir, opts.Date+".html")
@@ -142,12 +146,14 @@ func Load(opts Options) ([]Section, error) {
}
// CleanCache removes cached readings whose date is before `before` from
-// cacheDir(). It matches only files named "<YYYY-MM-DD>.html"/".json";
-// anything else in the directory (e.g. a stray notes.txt, or the sigla
-// store, which lives elsewhere entirely) is left alone. A missing cache dir
-// is not an error -- it just means there is nothing to clean yet.
+// CacheDir(). It matches only date-prefixed cache files (see cacheFileRe:
+// "<YYYY-MM-DD>.html", ".json", or the traditional lectionary's
+// ".trad.<lang>.json"); anything else in the directory (e.g. a stray
+// notes.txt, or the sigla store, which lives elsewhere entirely) is left
+// alone. A missing cache dir is not an error -- it just means there is
+// nothing to clean yet.
func CleanCache(before time.Time) (removed int, freed int64, err error) {
- dir := cacheDir()
+ dir := CacheDir()
entries, err := os.ReadDir(dir)
if err != nil {
if os.IsNotExist(err) {
diff --git a/internal/liturgy/fetch_test.go b/internal/liturgy/fetch_test.go
index 1cebb86..738126d 100644
--- a/internal/liturgy/fetch_test.go
+++ b/internal/liturgy/fetch_test.go
@@ -37,7 +37,7 @@ func TestLoadCaches(t *testing.T) {
// before it ever builds a filesystem path from it, so every caller (web,
// cli, tui) is protected even if a future caller forgets to validate.
//
-// The planted "passwd.json" sits one level *above* cacheDir() -- reachable
+// The planted "passwd.json" sits one level *above* CacheDir() -- reachable
// only via a "../" date -- so if Load ever built jsonPath from the raw date
// unchecked, loadJSONCache would read it back and return its section instead
// of an error.
diff --git a/internal/liturgy/store.go b/internal/liturgy/store.go
index cc176e8..69e45f2 100644
--- a/internal/liturgy/store.go
+++ b/internal/liturgy/store.go
@@ -127,7 +127,7 @@ func Harvest(fromDate string, maxDays int) (added int, furthest string, err erro
return 0, "", err
}
- dir := cacheDir()
+ dir := CacheDir()
day := start
var harvestErr error
for i := 0; maxDays == 0 || i < maxDays; i++ {