Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions devel/0054.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# [0054] gf fmt 添加基于文件系统的缓存机制

## 相关文档
- [dddd.md](dddd.md) - 任务文档模板

## 任务相关的代码文件
- tools/fmt/liii/goldfmt.scm

## 如何测试
```bash
xmake b goldfish
bin/gf fmt goldfish/liii/os.scm
# 第二次运行应显示 Files cached: 1 且无逐行 Cached 输出
bin/gf fmt goldfish/liii/os.scm
```

## 2026-05-20 gf fmt 缓存命中时静默处理
### What
1. 去掉缓存命中时的逐行 `Cached: <file>` 输出
2. 缓存命中改为静默跳过,仅在汇总行显示 cached 数量

## 2026-05-20 gf fmt 添加基于文件系统的缓存机制
### What
1. 添加基于 sha256 文件哈希的缓存机制
2. 缓存目录位于 `~/.cache/goldfish/fmt/<version>/`
3. 格式化文件时先检查缓存,命中则跳过
4. 格式化完成后更新缓存标记

### Why
gf fmt 对大量文件递归格式化时,每次都重新扫描和格式化未变更的文件,性能较差。通过文件哈希缓存已格式化过的文件,避免重复处理。

### How
- 使用 `sha256-by-file` 计算文件内容的 SHA256 哈希
- 缓存路径采用两级目录结构:`<base>/<hash前2位>/<hash剩余部分>`
- 缓存命中判断:检查缓存路径对应的文件是否存在
- 格式化后通过 `path-touch` 创建缓存标记文件
191 changes: 119 additions & 72 deletions tools/fmt/liii/goldfmt.scm
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
(liii path)
(liii string)
(liii argparse)
(liii hashlib)
(liii goldtool-changed)
(srfi srfi-13)
(liii raw-string)
Expand All @@ -50,6 +51,38 @@
(export main format-datum format-datum+node format-node format-string)
(begin

;; ; 缓存工具函数
(define (fmt-cache-base-dir)
(path->string (path-join (path-home) ".cache" "goldfish" "fmt" (version)))
) ;define

(define (fmt-cache-path file-path)
(let* ((hash (sha256-by-file file-path))
(prefix (substring hash 0 2))
(rest (substring hash 2))
(base (fmt-cache-base-dir))
) ;
(path->string (path-join base prefix rest))
) ;let*
) ;define

(define (fmt-cache-hit? file-path)
(let ((cache (fmt-cache-path file-path)))
(file-exists? cache)
) ;let
) ;define

(define (fmt-cache-touch file-path)
(let* ((cache (fmt-cache-path file-path))
(cache-dir (path->string (path-parent (path cache))))
) ;
(unless (path-dir? (path cache-dir))
(g_mkdir cache-dir)
) ;unless
(path-touch (path cache))
) ;let*
) ;define

;; ; 显示帮助文档
(define (display-help)
(display "Usage: gf fmt [options] [path]")
Expand Down Expand Up @@ -100,47 +133,62 @@
) ;define

;; ; 格式化单个文件(覆盖原文件)
;; ; 返回值: 如果文件有变更返回 #t,否则返回 #f
(define (format-file path-str)
(let* ((p (path path-str))
(original-content (path-read-text p))
(nodes (scan-file path-str))
(formatted (format-nodes nodes))
) ;
(if (string=? original-content formatted)
#f
(begin
(path-write-text p formatted)
#t
) ;begin
) ;if
) ;let*
) ;define
;; ; 返回值: 'cached (缓存命中), #t (文件有变更), #f (无变更)
(define* (format-file path-str (use-cache? #t))
(if (and use-cache? (fmt-cache-hit? path-str))
'cached
(let* ((p (path path-str))
(original-content (path-read-text p))
(nodes (scan-file path-str))
(formatted (format-nodes nodes))
) ;
(if (string=? original-content formatted)
(begin
(when use-cache?
(fmt-cache-touch path-str)
) ;when
#f
) ;begin
(begin
(path-write-text p formatted)
(when use-cache?
(fmt-cache-touch path-str)
) ;when
#t
) ;begin
) ;if
) ;let*
) ;if
) ;define*

;; ; 递归格式化指定文件列表
;; ; 返回值: (values total updated) - 处理的文件总数和更新的文件数
;; ; 返回值: (values total updated cached) - 处理的文件总数、更新数、缓存命中数
(define (format-file-list files dry-run)
(let loop
((remaining files) (total 0) (updated 0))
((remaining files) (total 0) (updated 0) (cached 0))
(if (null? remaining)
(values total updated)
(values total updated cached)
(let ((file (car remaining)))
(display (string-append "Formatting: " file))
(newline)
(if dry-run
(begin
(display (string-append "Formatting: " file))
(newline)
(format-file-dry-run file)
(loop (cdr remaining) (+ total 1) updated)
(loop (cdr remaining) (+ total 1) updated cached)
) ;begin
(let ((changed? (format-file file)))
(if changed?
(begin
(display (string-append " Updated: " file))
(newline)
(loop (cdr remaining) (+ total 1) (+ updated 1))
) ;begin
(loop (cdr remaining) (+ total 1) updated)
) ;if
(let ((result (format-file file)))
(cond ((eq? result 'cached)
(loop (cdr remaining) (+ total 1) updated (+ cached 1))
) ;
(result (display (string-append " Updated: " file))
(newline)
(loop (cdr remaining) (+ total 1) (+ updated 1) cached)
) ;result
(else (display (string-append "Formatting: " file))
(newline)
(loop (cdr remaining) (+ total 1) updated cached)
) ;else
) ;cond
) ;let
) ;if
) ;let
Expand Down Expand Up @@ -168,11 +216,13 @@
#t
) ;begin
(call-with-values (lambda () (format-file-list files dry-run))
(lambda (total updated)
(lambda (total updated cached)
(display (string-append "Total files formatted: "
(number->string total)
", Files updated: "
(number->string updated)
", Files cached: "
(number->string cached)
) ;string-append
) ;display
(newline)
Expand All @@ -187,43 +237,43 @@
) ;define

;; ; 递归格式化目录
;; ; 返回值: (values total updated) - 处理的文件总数和更新的文件数
;; ; 返回值: (values total updated cached) - 处理的文件总数、更新数、缓存命中数
(define (format-directory dir-path)
(let ((entries (path-list-path (path dir-path))))
(let loop
((i 0) (total 0) (updated 0))
((i 0) (total 0) (updated 0) (cached 0))
(if (>= i (vector-length entries))
(values total updated)
(values total updated cached)
(let ((entry (vector-ref entries i)))
(cond ((path-file? entry)
(let ((entry-str (path->string entry)))
(if (string-suffix? ".scm" entry-str)
(begin
(display (string-append "Formatting: " entry-str))
(newline)
(let ((changed? (format-file entry-str)))
(if changed?
(begin
(display (string-append " Updated: " entry-str))
(newline)
(loop (+ i 1) (+ total 1) (+ updated 1))
) ;begin
(loop (+ i 1) (+ total 1) updated)
) ;if
) ;let
) ;begin
(loop (+ i 1) total updated)
(let ((result (format-file entry-str)))
(cond ((eq? result 'cached)
(loop (+ i 1) (+ total 1) updated (+ cached 1))
) ;
(result (display (string-append " Updated: " entry-str))
(newline)
(loop (+ i 1) (+ total 1) (+ updated 1) cached)
) ;result
(else (display (string-append "Formatting: " entry-str))
(newline)
(loop (+ i 1) (+ total 1) updated cached)
) ;else
) ;cond
) ;let
(loop (+ i 1) total updated cached)
) ;if
) ;let
) ;
((path-dir? entry)
(call-with-values (lambda () (format-directory (path->string entry)))
(lambda (sub-total sub-updated)
(loop (+ i 1) (+ total sub-total) (+ updated sub-updated))
(lambda (sub-total sub-updated sub-cached)
(loop (+ i 1) (+ total sub-total) (+ updated sub-updated) (+ cached sub-cached))
) ;lambda
) ;call-with-values
) ;
(else (loop (+ i 1) total updated))
(else (loop (+ i 1) total updated cached))
) ;cond
) ;let
) ;if
Expand Down Expand Up @@ -273,25 +323,20 @@
((path-file? (path path-str))
(if dry-run
(format-file-dry-run path-str)
(begin
(display (string-append "Formatting: " path-str))
(let ((result (format-file path-str)))
(cond ((eq? result 'cached) #f)
(result (display (string-append " Updated: " path-str)) (newline))
(else (display (string-append "Formatting: " path-str)) (newline))
) ;cond
(display (string-append "Total files formatted: 1, Files updated: "
(if (eq? result #t) "1" "0")
", Files cached: "
(if (eq? result 'cached) "1" "0")
) ;string-append
) ;display
(newline)
(let ((changed? (format-file path-str)))
(if changed?
(begin
(display (string-append " Updated: " path-str))
(newline)
) ;begin
'()
) ;if
(display (string-append "Total files formatted: 1, Files updated: "
(if changed? "1" "0")
) ;string-append
) ;display
(newline)
#t
) ;let
) ;begin
#t
) ;let
) ;if
) ;
((path-dir? (path path-str))
Expand All @@ -302,11 +347,13 @@
(exit 1)
) ;begin
(call-with-values (lambda () (format-directory path-str))
(lambda (total updated)
(lambda (total updated cached)
(display (string-append "Total files formatted: "
(number->string total)
", Files updated: "
(number->string updated)
", Files cached: "
(number->string cached)
) ;string-append
) ;display
(newline)
Expand Down
Loading