watchfs

package
v0.60.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 1, 2025 License: BSD-3-Clause Imports: 9 Imported by: 0

Documentation

Overview

Package watchfs implement naive file and directory watcher.

This package is deprecated, we keep it here for historical only. The new implementation should use "watchfs/v2".

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type DirWatcher

type DirWatcher struct {
	// C channel on which the changes are delivered to user.
	C <-chan NodeState

	Options DirWatcherOptions
	// contains filtered or unexported fields
}

DirWatcher is a naive implementation of directory change notification.

Example
package main

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"time"

	"git.sr.ht/~shulhan/pakakeh.go/lib/watchfs"
)

func main() {
	var (
		rootDir string
		err     error
	)

	rootDir, err = os.MkdirTemp(``, `ExampleDirWatcher`)
	if err != nil {
		log.Fatal(err)
	}

	// In this example, we watch sub directory "assets" and its
	// contents, including only files with ".adoc" extension and
	// excluding files with ".html" extension.
	var dw = &watchfs.DirWatcher{
		Options: watchfs.DirWatcherOptions{
			Root: rootDir,
			Includes: []string{
				`assets/.*`,
				`.*\.adoc$`,
			},
			Excludes: []string{
				`.*\.html$`,
			},
			Delay: 100 * time.Millisecond,
		},
	}

	err = dw.Start()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(`Deleting the root directory:`)
	err = os.Remove(rootDir)
	if err != nil {
		log.Fatal(err)
	}

	var ns = <-dw.C
	fmt.Println(`--`, ns.State, ns.Node.Path)

	// Create the root directory back with sub directory
	// This will trigger one FileStateCreated event, for "/".
	fmt.Println(`Re-create root directory with sub-directory:`)
	var dirAssets = filepath.Join(rootDir, `assets`)
	err = os.MkdirAll(dirAssets, 0770)
	if err != nil {
		log.Fatal(err)
	}

	ns = <-dw.C
	fmt.Println(`--`, ns.State, ns.Node.Path)

	// Modify the permission on root directory
	fmt.Println(`Chmod on root directory:`)
	err = os.Chmod(rootDir, 0700)
	if err != nil {
		log.Fatal(err)
	}
	ns = <-dw.C
	fmt.Println(`--`, ns.State, ns.Node.Path, ns.Node.Mode())

	fmt.Println(`Create new file on root directory: /new.adoc`)
	var newFile = filepath.Join(rootDir, `new.adoc`)
	err = os.WriteFile(newFile, nil, 0600)
	if err != nil {
		log.Fatal(err)
	}
	ns = <-dw.C
	fmt.Println(`--`, ns.State, ns.Node.Path, ns.Node.Mode())

	fmt.Println(`Remove file on root directory: /new.adoc`)
	err = os.Remove(newFile)
	if err != nil {
		log.Fatal(err)
	}
	ns = <-dw.C
	fmt.Println(`--`, ns.State, ns.Node.Path, ns.Node.Mode())

	fmt.Println(`Create new sub-directory: /subdir`)
	var subDir = filepath.Join(rootDir, `subdir`)
	err = os.Mkdir(subDir, 0770)
	if err != nil {
		log.Fatal(err)
	}
	ns = <-dw.C
	fmt.Println(`--`, ns.State, ns.Node.Path, ns.Node.Mode())

	// Add new file in sub directory.
	newFile = filepath.Join(subDir, `new.adoc`)
	fmt.Println(`Create new file in sub directory: /subdir/new.adoc`)
	err = os.WriteFile(newFile, nil, 0600)
	if err != nil {
		log.Fatal(err)
	}
	ns = <-dw.C
	fmt.Println(`--`, ns.State, ns.Node.Path, ns.Node.Mode())

	fmt.Println(`Remove file in sub directory: /subdir/new.adoc`)
	err = os.Remove(newFile)
	if err != nil {
		log.Fatal(err)
	}
	ns = <-dw.C
	fmt.Println(`--`, ns.State, ns.Node.Path, ns.Node.Mode())

	// Creating file that is excluded should not trigger event.
	fmt.Println(`Create excluded file in sub directory: /subdir/new.html`)
	newFile = filepath.Join(subDir, `new.html`)
	err = os.WriteFile(newFile, nil, 0600)
	if err != nil {
		log.Fatal(err)
	}

	// Create file without extension in directory "assets" should trigger
	// event.
	newFile = filepath.Join(dirAssets, `new`)
	fmt.Println(`Create new file under assets: /assets/new`)
	err = os.WriteFile(newFile, nil, 0600)
	if err != nil {
		log.Fatal(err)
	}
	ns = <-dw.C
	fmt.Println(`--`, ns.State, ns.Node.Path, ns.Node.Mode())

	// TODO: fix data race.
	//dw.Stop()

}
Output:

Deleting the root directory:
-- FileStateDeleted /
Re-create root directory with sub-directory:
-- FileStateCreated /
Chmod on root directory:
-- FileStateUpdateMode / drwx------
Create new file on root directory: /new.adoc
-- FileStateCreated /new.adoc -rw-------
Remove file on root directory: /new.adoc
-- FileStateDeleted /new.adoc -rw-------
Create new sub-directory: /subdir
-- FileStateCreated /subdir drwxr-x---
Create new file in sub directory: /subdir/new.adoc
-- FileStateCreated /subdir/new.adoc -rw-------
Remove file in sub directory: /subdir/new.adoc
-- FileStateDeleted /subdir/new.adoc -rw-------
Create excluded file in sub directory: /subdir/new.html
Create new file under assets: /assets/new
-- FileStateCreated /assets/new -rw-------

func (*DirWatcher) Start

func (dw *DirWatcher) Start() (err error)

Start watching changes in directory and its content.

func (*DirWatcher) Stop

func (dw *DirWatcher) Stop()

Stop watching changes on directory.

type DirWatcherOptions

type DirWatcherOptions struct {
	// The Root field define the directory that we want to watch.
	Root string

	// Includes contains list of regex to filter file names that we want
	// to be notified.
	Includes []string

	// Excludes contains list of regex to filter file names that we did
	// not want to be notified.
	Excludes []string

	// Delay define a duration when the new changes will be fetched from
	// system.
	// This field is optional, minimum is 100 milli second and default
	// is 5 seconds.
	Delay time.Duration
}

DirWatcherOptions to create and initialize DirWatcher.

The includes and excludes pattern applied relative to the system path. The Excludes patterns will be applied first before the Includes. If the path is not excluded and Includes is empty, it will be assumed as included.

type FileState

type FileState byte

FileState define the state of file. There are four states of file: created, updated on mode, updated on content or deleted.

const (
	// FileStateCreated when new file is created.
	FileStateCreated FileState = iota
	// FileStateUpdateContent when the content of file is modified.
	FileStateUpdateContent
	// FileStateUpdateMode when the mode of file is modified.
	FileStateUpdateMode
	// FileStateDeleted when the file has been deleted.
	FileStateDeleted
)

func (FileState) String

func (fs FileState) String() (s string)

String return the string representation of FileState.

type Node

type Node = memfs.Node

Node represent single file or directory.

type NodeState

type NodeState struct {
	// Node represent the file information.
	Node Node
	// State of file, its either created, modified, or deleted.
	State FileState
}

NodeState contains the information about the file and its state.

type WatchCallback

type WatchCallback func(*NodeState)

WatchCallback is a function that will be called when Watcher or DirWatcher detect any changes on its file or directory. The watcher will pass the file information and its state.

type Watcher

type Watcher struct {
	// The channel on which the changes are delivered.
	C <-chan NodeState
	// contains filtered or unexported fields
}

Watcher is a naive implementation of file event change notification.

func NewWatcher

func NewWatcher(path string, d time.Duration) (w *Watcher, err error)

NewWatcher return a new file watcher that will inspect the file for changes for `path` with period specified by duration `d` argument.

If duration is less or equal to 100 millisecond, it will be set to default duration (5 seconds).

The changes can be consumed from the channel C. If the consumer is slower, channel is full, the changes will be dropped.

Example
package main

import (
	"fmt"
	"log"
	"os"
	"time"

	"git.sr.ht/~shulhan/pakakeh.go/lib/watchfs"
)

func main() {
	var (
		content = `Content of file`

		f       *os.File
		watcher *watchfs.Watcher
		ns      watchfs.NodeState
		err     error
	)

	// Create a file to be watched.
	f, err = os.CreateTemp(``, `watcher`)
	if err != nil {
		log.Fatal(err)
	}

	watcher, err = watchfs.NewWatcher(f.Name(), 150*time.Millisecond)
	if err != nil {
		log.Fatal(err)
	}

	// Update file mode.
	err = f.Chmod(0700)
	if err != nil {
		log.Fatal(err)
	}

	ns = <-watcher.C
	fmt.Printf("State: %s\n", ns.State)
	fmt.Printf("File mode: %s\n", ns.Node.Mode())
	fmt.Printf("File size: %d\n", ns.Node.Size())

	// Update content of file.
	_, err = f.WriteString(content)
	if err != nil {
		log.Fatal(err)
	}
	ns = <-watcher.C
	fmt.Printf("State: %s\n", ns.State)
	fmt.Printf("File mode: %s\n", ns.Node.Mode())
	fmt.Printf("File size: %d\n", ns.Node.Size())

	err = f.Close()
	if err != nil {
		log.Fatal(err)
	}

	// Remove the file.
	err = os.Remove(f.Name())
	if err != nil {
		log.Fatal(err)
	}
	ns = <-watcher.C
	fmt.Printf("State: %s\n", ns.State)
	fmt.Printf("File mode: %s\n", ns.Node.Mode())
	fmt.Printf("File size: %d\n", ns.Node.Size())

}
Output:

State: FileStateUpdateMode
File mode: -rwx------
File size: 0
State: FileStateUpdateContent
File mode: -rwx------
File size: 15
State: FileStateDeleted
File mode: -rwx------
File size: 15

func (*Watcher) Stop

func (w *Watcher) Stop()

Stop watching the file.

Directories

Path Synopsis
Package watchfs implement naive file and directory watcher.
Package watchfs implement naive file and directory watcher.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL