Files
audio-library-manager/private/file-walker.rkt
T
2026-06-25 21:52:17 +02:00

149 lines
5.2 KiB
Racket

#lang racket/base
(require racket/sequence
racket/generator
racket/string
racket/path
file/glob)
(provide make-file-walker
make-file-admin
fw-add-filter
os-path
)
(define (os-path str)
(let ((delim (if (eq? (system-path-convention-type) 'windows) "\\" "/")))
(string-replace str "/" delim)))
(define (make-file-walker base-path glob-pattern filter-func)
(let* ((gen (sequence->generator
(sequence-filter
(λ (p)
(let ((basename (file-name-from-path p)))
(glob-match? glob-pattern basename)))
(in-directory base-path))))
(str-base-path* (format "~a" (normalize-path base-path)))
(delim (if (eq? (system-path-convention-type) 'windows) "\\" "/"))
(str-base-path (if (string-suffix? str-base-path* delim)
str-base-path*
(string-append str-base-path* delim)))
(base-path-len (string-length str-base-path))
(result #f)
)
(λ ()
(let ((path (gen)))
(if (void? path)
(values #f #f #f)
(let* ((str-path (path->string path))
(ext* (path-get-extension path))
(ext (string->symbol
(substring
(if (eq? ext* #f)
"."
(let ((e (string-downcase (bytes->string/utf-8 ext*))))
(if (string-contains? e " ")
"."
e))) 1)))
(path-part (substring str-path base-path-len))
(str-n-path (string-replace path-part "\\" "/"))
(info (let ((h (make-hash (list
(cons 'type 'dir)
(cons 'path str-n-path)
(cons 'ext ext)))))
(when (file-exists? path)
(hash-set! h 'type 'file)
(hash-set! h 'size (file-size path))
(hash-set! h 'mtime (file-or-directory-modify-seconds path))
)
h))
)
(filter-func base-path path info)))
)
)
)
)
(define (make-file-admin base-path db-hash)
(define (file-info-equal? i1 i2)
(if (eq? (hash-ref i1 'type) (hash-ref i2 'type))
(if (eq? (hash-ref i1 'type) 'file)
(and
(string=? (hash-ref i1 'path) (hash-ref i2 'path))
(= (hash-ref i1 'size) (hash-ref i2 'size))
(= (hash-ref i1 'mtime) (hash-ref i2 'mtime)))
(string=? (hash-ref i1 'path) (hash-ref i2 'path))
)
#f))
(define (file-admin base-path path info)
(let* ((normalized-sub-path (hash-ref info 'path))
(in-db (hash-ref db-hash normalized-sub-path #f))
)
(cond
((eq? in-db #f)
(hash-set! info 'file-db 'new)
(hash-set! db-hash normalized-sub-path info)
)
(else
(if (file-info-equal? info in-db)
(hash-set! info 'file-db 'unchanged)
(hash-set! info 'file-db 'changed))
(hash-set! db-hash normalized-sub-path info)
)
)
(values base-path path info)
))
(define (init-db-sweep)
(hash-for-each db-hash
(λ (key value)
(if (eq? (hash-ref value 'file-db #f) 'deleted)
(hash-remove! db-hash key)
(hash-set! value 'file-db 'unknown)))))
(define (get-deleted)
(let ((keys (hash-keys db-hash)))
(map (λ (key)
(let ((info (hash-ref db-hash key)))
(hash-set! info 'file-db 'deleted)
info))
(filter (λ (key)
(let ((v (hash-ref db-hash key)))
(eq? (hash-ref v 'file-db) 'unknown)))
keys))))
(let* ((fw (make-file-walker base-path "*" file-admin))
(deleted #f))
(init-db-sweep)
(letrec ((f (λ ()
(if (list? deleted)
(if (null? deleted)
(values #f #f #f)
(let ((r (car deleted)))
(set! deleted (cdr deleted))
(values base-path (build-path base-path (os-path (hash-ref r 'path))) r))
)
(let-values (((base-path path info) (fw)))
(if (eq? info #f)
(begin
(set! deleted (get-deleted))
(f))
(values base-path path info))
)
)
)
))
f))
)
(define (fw-add-filter fw filter-func)
(λ ()
(let-values (((base-path path info) (fw)))
(if (eq? info #f)
(values #f #f #f)
(filter-func base-path path info))))
)