diff options
Diffstat (limited to 'internal/extract')
| -rw-r--r-- | internal/extract/extract.go | 26 | ||||
| -rw-r--r-- | internal/extract/tools_test.go | 24 |
2 files changed, 50 insertions, 0 deletions
diff --git a/internal/extract/extract.go b/internal/extract/extract.go index aa3ae93..9768db1 100644 --- a/internal/extract/extract.go +++ b/internal/extract/extract.go @@ -7,12 +7,18 @@ package extract import ( "context" "errors" + "fmt" "os" "path/filepath" "strings" "time" ) +// Version is the version of the text this package extracts. Bump it +// whenever a change could make any format's text differ, so every keyword +// cache built from the old text is discarded (Fingerprint). +const Version = 1 + var ( // ErrUnsupported is returned when the format carries no text krino // knows how to extract. @@ -111,6 +117,26 @@ func newWithPath(path string) *Extractor { return &Extractor{tools: tools, Timeout: 30 * time.Second} } +// Fingerprint identifies what text this Extractor would produce: Version, +// and each external tool found with its path, size and modification time. +// A keyword cache built under another fingerprint is discarded, so +// installing, removing or upgrading a tool invalidates it. +func (e *Extractor) Fingerprint() string { + var b strings.Builder + fmt.Fprintf(&b, "v%d", Version) + for _, name := range toolNames { + p := e.tools[name] + if p == "" { + continue + } + fmt.Fprintf(&b, " %s=%s", name, p) + if fi, err := os.Stat(p); err == nil { + fmt.Fprintf(&b, ":%d:%d", fi.Size(), fi.ModTime().UnixNano()) + } + } + return b.String() +} + // Tools reports every external tool Extractor knows about, in a fixed // order, with the path it was found at or "" if it was not found. func (e *Extractor) Tools() []Tool { diff --git a/internal/extract/tools_test.go b/internal/extract/tools_test.go index 4a03f1b..b481e8a 100644 --- a/internal/extract/tools_test.go +++ b/internal/extract/tools_test.go @@ -237,3 +237,27 @@ func TestMaxReadCapsToolOutput(t *testing.T) { t.Fatalf("got %v, want ErrTooLarge (max-read 1024 should have capped a 200000-byte tool output)", err) } } + +// TestFingerprintFollowsTools: the fingerprint changes when a tool is +// installed or replaced, and not otherwise. +func TestFingerprintFollowsTools(t *testing.T) { + bin := t.TempDir() + none := newWithPath(bin).Fingerprint() + if none != newWithPath(bin).Fingerprint() { + t.Fatal("fingerprint not stable") + } + tool := filepath.Join(bin, "pdftotext") + if err := os.WriteFile(tool, []byte("#!/bin/sh\n"), 0o755); err != nil { + t.Fatal(err) + } + installed := newWithPath(bin).Fingerprint() + if installed == none { + t.Error("installing pdftotext did not change the fingerprint") + } + if err := os.WriteFile(tool, []byte("#!/bin/sh\nexit 0\n"), 0o755); err != nil { + t.Fatal(err) + } + if newWithPath(bin).Fingerprint() == installed { + t.Error("replacing pdftotext did not change the fingerprint") + } +} |
