53 lines
1.3 KiB
Go
53 lines
1.3 KiB
Go
|
package cache
|
||
|
|
||
|
import (
|
||
|
"sync"
|
||
|
|
||
|
"github.com/evanw/esbuild/internal/fs"
|
||
|
)
|
||
|
|
||
|
// This cache uses information from the "stat" syscall to try to avoid re-
|
||
|
// reading files from the file system during subsequent builds if the file
|
||
|
// hasn't changed. The assumption is reading the file metadata is faster than
|
||
|
// reading the file contents.
|
||
|
|
||
|
type FSCache struct {
|
||
|
mutex sync.Mutex
|
||
|
entries map[string]*fsEntry
|
||
|
}
|
||
|
|
||
|
type fsEntry struct {
|
||
|
contents string
|
||
|
modKey fs.ModKey
|
||
|
isModKeyUsable bool
|
||
|
}
|
||
|
|
||
|
func (c *FSCache) ReadFile(fs fs.FS, path string) (contents string, canonicalError error, originalError error) {
|
||
|
entry := func() *fsEntry {
|
||
|
c.mutex.Lock()
|
||
|
defer c.mutex.Unlock()
|
||
|
return c.entries[path]
|
||
|
}()
|
||
|
|
||
|
// If the file's modification key hasn't changed since it was cached, assume
|
||
|
// the contents of the file are also the same and skip reading the file.
|
||
|
modKey, modKeyErr := fs.ModKey(path)
|
||
|
if entry != nil && entry.isModKeyUsable && modKeyErr == nil && entry.modKey == modKey {
|
||
|
return entry.contents, nil, nil
|
||
|
}
|
||
|
|
||
|
contents, err, originalError := fs.ReadFile(path)
|
||
|
if err != nil {
|
||
|
return "", err, originalError
|
||
|
}
|
||
|
|
||
|
c.mutex.Lock()
|
||
|
defer c.mutex.Unlock()
|
||
|
c.entries[path] = &fsEntry{
|
||
|
contents: contents,
|
||
|
modKey: modKey,
|
||
|
isModKeyUsable: modKeyErr == nil,
|
||
|
}
|
||
|
return contents, nil, nil
|
||
|
}
|