From 25c06ea136e6ecace433525615640bd08f3170f8 Mon Sep 17 00:00:00 2001 From: Stephanie Date: Tue, 15 Feb 2022 12:24:44 -0500 Subject: [PATCH] update the filesystem Signed-off-by: Stephanie --- go.mod | 1 + pkg/testingutil/filesystem/default_fs.go | 18 +++++ pkg/testingutil/filesystem/fake_fs.go | 13 ++++ pkg/testingutil/filesystem/filesystem.go | 3 + pkg/testingutil/filesystem/singleton.go | 10 +++ pkg/testingutil/filesystem/watcher.go | 88 ++++++++++++++++++++++++ 6 files changed, 133 insertions(+) create mode 100644 pkg/testingutil/filesystem/singleton.go create mode 100644 pkg/testingutil/filesystem/watcher.go diff --git a/go.mod b/go.mod index df40e094..59f8d54b 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.15 require ( github.com/devfile/api/v2 v2.0.0-20220117162434-6e6e6a8bc14c github.com/fatih/color v1.7.0 + github.com/fsnotify/fsnotify v1.4.9 github.com/gobwas/glob v0.2.3 github.com/golang/mock v1.5.0 github.com/google/go-cmp v0.5.5 diff --git a/pkg/testingutil/filesystem/default_fs.go b/pkg/testingutil/filesystem/default_fs.go index 5e5b7101..9eea63fc 100644 --- a/pkg/testingutil/filesystem/default_fs.go +++ b/pkg/testingutil/filesystem/default_fs.go @@ -92,6 +92,11 @@ func (DefaultFs) Remove(name string) error { return os.Remove(name) } +// Getwd via os.Getwd +func (DefaultFs) Getwd() (dir string, err error) { + return os.Getwd() +} + // ReadFile via ioutil.ReadFile func (DefaultFs) ReadFile(filename string) ([]byte, error) { return ioutil.ReadFile(filename) @@ -126,6 +131,11 @@ func (DefaultFs) Walk(root string, walkFn filepath.WalkFunc) error { return filepath.Walk(root, walkFn) } +// Chmod via os.Chmod +func (f DefaultFs) Chmod(name string, mode os.FileMode) error { + return os.Chmod(name, mode) +} + // defaultFile implements File using same-named functions from "os" type defaultFile struct { file *os.File @@ -159,3 +169,11 @@ func (file *defaultFile) Close() error { func (file *defaultFile) Readdir(n int) ([]os.FileInfo, error) { return file.file.Readdir(n) } + +func (file *defaultFile) Read(b []byte) (n int, err error) { + return file.file.Read(b) +} + +func (file *defaultFile) Chmod(name string, mode os.FileMode) error { + return file.file.Chmod(mode) +} diff --git a/pkg/testingutil/filesystem/fake_fs.go b/pkg/testingutil/filesystem/fake_fs.go index 85aafa86..fbf016dc 100644 --- a/pkg/testingutil/filesystem/fake_fs.go +++ b/pkg/testingutil/filesystem/fake_fs.go @@ -125,11 +125,20 @@ func (fs *fakeFs) RemoveAll(path string) error { return fs.a.RemoveAll(path) } +func (fs *fakeFs) Getwd() (dir string, err error) { + return ".", nil +} + // Remove via afero.RemoveAll func (fs *fakeFs) Remove(name string) error { return fs.a.Remove(name) } +// Chmod via afero.Chmod +func (fs *fakeFs) Chmod(name string, mode os.FileMode) error { + return fs.a.Chmod(name, mode) +} + // fakeFile implements File; for use with fakeFs type fakeFile struct { file afero.File @@ -163,3 +172,7 @@ func (file *fakeFile) Close() error { func (file *fakeFile) Readdir(n int) ([]os.FileInfo, error) { return file.file.Readdir(n) } + +func (file *fakeFile) Read(b []byte) (n int, err error) { + return file.file.Read(b) +} diff --git a/pkg/testingutil/filesystem/filesystem.go b/pkg/testingutil/filesystem/filesystem.go index aee6b16d..e71b6ffc 100644 --- a/pkg/testingutil/filesystem/filesystem.go +++ b/pkg/testingutil/filesystem/filesystem.go @@ -39,6 +39,8 @@ type Filesystem interface { Chtimes(name string, atime time.Time, mtime time.Time) error RemoveAll(path string) error Remove(name string) error + Chmod(name string, mode os.FileMode) error + Getwd() (dir string, err error) // from "io/ioutil" ReadFile(filename string) ([]byte, error) @@ -58,5 +60,6 @@ type File interface { WriteString(s string) (n int, err error) Sync() error Close() error + Read(b []byte) (n int, err error) Readdir(n int) ([]os.FileInfo, error) } diff --git a/pkg/testingutil/filesystem/singleton.go b/pkg/testingutil/filesystem/singleton.go new file mode 100644 index 00000000..a8dcea8f --- /dev/null +++ b/pkg/testingutil/filesystem/singleton.go @@ -0,0 +1,10 @@ +package filesystem + +var singleFs Filesystem + +func Get() Filesystem { + if singleFs == nil { + singleFs = &DefaultFs{} + } + return singleFs +} diff --git a/pkg/testingutil/filesystem/watcher.go b/pkg/testingutil/filesystem/watcher.go new file mode 100644 index 00000000..af93ffbb --- /dev/null +++ b/pkg/testingutil/filesystem/watcher.go @@ -0,0 +1,88 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + This package is a FORK of https://github.com/kubernetes/kubernetes/blob/master/pkg/util/filesystem/watcher.go + See above license +*/ + +package filesystem + +import ( + "github.com/fsnotify/fsnotify" +) + +// FSWatcher is a callback-based filesystem watcher abstraction for fsnotify. +type FSWatcher interface { + // Initializes the watcher with the given watch handlers. + // Called before all other methods. + Init(FSEventHandler, FSErrorHandler) error + + // Starts listening for events and errors. + // When an event or error occurs, the corresponding handler is called. + Run() + + // Add a filesystem path to watch + AddWatch(path string) error +} + +// FSEventHandler is called when a fsnotify event occurs. +type FSEventHandler func(event fsnotify.Event) + +// FSErrorHandler is called when a fsnotify error occurs. +type FSErrorHandler func(err error) + +type fsnotifyWatcher struct { + watcher *fsnotify.Watcher + eventHandler FSEventHandler + errorHandler FSErrorHandler +} + +var _ FSWatcher = &fsnotifyWatcher{} + +func (w *fsnotifyWatcher) AddWatch(path string) error { + return w.watcher.Add(path) +} + +func (w *fsnotifyWatcher) Init(eventHandler FSEventHandler, errorHandler FSErrorHandler) error { + var err error + w.watcher, err = fsnotify.NewWatcher() + if err != nil { + return err + } + + w.eventHandler = eventHandler + w.errorHandler = errorHandler + return nil +} + +func (w *fsnotifyWatcher) Run() { + go func() { + defer w.watcher.Close() + for { + select { + case event := <-w.watcher.Events: + if w.eventHandler != nil { + w.eventHandler(event) + } + case err := <-w.watcher.Errors: + if w.errorHandler != nil { + w.errorHandler(err) + } + } + } + }() +}