119 lines
3.2 KiB
Go
119 lines
3.2 KiB
Go
package watchmanager
|
|
|
|
import (
|
|
"io"
|
|
"strings"
|
|
|
|
"github.com/microsoft/typescript-go/internal/fswatch"
|
|
"github.com/microsoft/typescript-go/internal/tspath"
|
|
)
|
|
|
|
// WatchBackend abstracts fswatch.Watcher for testing
|
|
type WatchBackend interface {
|
|
WatchDirectory(dir string, fn fswatch.WatchCallback, recursive bool, ignore func(string) bool) (io.Closer, error)
|
|
WatchDirectories(requests []WatchDirectoryRequest) ([]io.Closer, error)
|
|
}
|
|
|
|
type WatchDirectoryRequest struct {
|
|
Dir string
|
|
Callback fswatch.WatchCallback
|
|
Recursive bool
|
|
Ignore func(string) bool
|
|
}
|
|
|
|
// CommandLineTestingWithWatchBackend is an optional extension of
|
|
// [CommandLineTesting] that supplies a [WatchBackend] for test mode
|
|
type CommandLineTestingWithWatchBackend interface {
|
|
WatchBackend() WatchBackend
|
|
}
|
|
|
|
type FSWatchBackend struct{ Inner fswatch.Watcher }
|
|
|
|
func (b *FSWatchBackend) WatchDirectory(dir string, fn fswatch.WatchCallback, recursive bool, ignore func(string) bool) (io.Closer, error) {
|
|
closers, err := b.WatchDirectories([]WatchDirectoryRequest{{
|
|
Dir: dir,
|
|
Callback: fn,
|
|
Recursive: recursive,
|
|
Ignore: ignore,
|
|
}})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return closers[0], nil
|
|
}
|
|
|
|
func (b *FSWatchBackend) WatchDirectories(requests []WatchDirectoryRequest) ([]io.Closer, error) {
|
|
fswatchRequests := make([]fswatch.WatchDirectoryRequest, len(requests))
|
|
for i, request := range requests {
|
|
var opts []fswatch.WatchOption
|
|
if request.Recursive {
|
|
opts = append(opts, fswatch.WithRecursive())
|
|
}
|
|
if request.Ignore != nil {
|
|
opts = append(opts, fswatch.WithIgnore(request.Ignore))
|
|
}
|
|
fswatchRequests[i] = fswatch.WatchDirectoryRequest{
|
|
Dir: request.Dir,
|
|
Callback: request.Callback,
|
|
Options: opts,
|
|
}
|
|
}
|
|
watches, err := b.Inner.WatchDirectories(fswatchRequests)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
closers := make([]io.Closer, len(watches))
|
|
for i, watch := range watches {
|
|
closers[i] = watch
|
|
}
|
|
return closers, nil
|
|
}
|
|
|
|
func ShouldIgnoreWatchPath(path string) bool {
|
|
p := tspath.NormalizeSlashes(path)
|
|
return strings.HasSuffix(p, "/.git") ||
|
|
strings.Contains(p, "/.git/") ||
|
|
strings.Contains(p, "/node_modules/.") ||
|
|
strings.Contains(p, "/.#")
|
|
}
|
|
|
|
func CanWatchDirectory(dir string) bool {
|
|
components := tspath.GetPathComponents(dir, "")
|
|
length := len(components)
|
|
if length <= 2 {
|
|
return false
|
|
}
|
|
rootLength := PerceivedOsRootLengthForWatching(components)
|
|
return length > rootLength+1
|
|
}
|
|
|
|
func PerceivedOsRootLengthForWatching(components []string) int {
|
|
length := len(components)
|
|
if length <= 1 {
|
|
return 1
|
|
}
|
|
root := components[0]
|
|
indexAfterOsRoot := 1
|
|
isDosStyle := len(root) >= 2 && tspath.IsVolumeCharacter(root[0]) && root[1] == ':'
|
|
|
|
if root != "/" && !isDosStyle && len(components) > 1 {
|
|
if len(components[1]) >= 2 && tspath.IsVolumeCharacter(components[1][0]) && strings.HasSuffix(components[1], "$") {
|
|
if length == 2 {
|
|
return 2
|
|
}
|
|
indexAfterOsRoot = 2
|
|
isDosStyle = true
|
|
}
|
|
}
|
|
|
|
if isDosStyle && (indexAfterOsRoot >= length || !strings.EqualFold(components[indexAfterOsRoot], "users")) {
|
|
return indexAfterOsRoot
|
|
}
|
|
|
|
if indexAfterOsRoot < length && strings.EqualFold(components[indexAfterOsRoot], "workspaces") {
|
|
return indexAfterOsRoot + 1
|
|
}
|
|
|
|
return indexAfterOsRoot + 2
|
|
}
|