Skip to content
This repository was archived by the owner on Jun 8, 2022. It is now read-only.
This repository was archived by the owner on Jun 8, 2022. It is now read-only.

Proposed API Changes #64

@nathany

Description

@nathany

I'm currently working on an internal event processing pipeline that will replace purgeEvents(), calling a series of functions to handle recursive watches (#56), throttling (#62), along with basic filtering and logging. I would prefer to keep the pipeline itself internal, at least initially, but there are still some API changes.

  • improve testability
  • surface new options
  • aesthetics

fsnotify.Event interface

In order to unit test pipeline steps, I would like to fake the event being passed in, which can be accomplished with an interface:

type Event interface {
    IsCreate() bool
    IsDelete() bool
    IsModify() bool
    IsRename() bool
    Path() string
}

As an interface cannot contain a field, the pipeline expects a Path() method, rather than a Name field.

The Watcher API still provides a concrete Event chan *FileEvent that contains a Name field in addition to Path(). Even so, I think it would be good to export the Event interface and to mark the Name field as deprecated.

New Options

These options don't necessarily correspond one-to-one with the steps in the pipeline, but they do represent the configuration those steps need.

type Options struct {
    Recursive        bool
    Hidden      bool
    Pattern          string
    Throttle         bool
    ThrottleDuration time.Duration
    Triggers         Triggers
    Verbose          bool
}

In order to specify these options, a new WatchPath method is introduced. The options have reasonable defaults, mostly using zero-initialization, though ThrottleDuration and Triggers don't have zero value defaults.

err = watcher.WatchPath("./", &fsnotify.Options{
    Recursive:        true,
    WatchHidden:      false,
    Pattern:          "*.go,*.c",
    Triggers:         fsnotify.Create | fsnotify.Modify,
    Throttle:         true,
    ThrottleDuration: 1 * time.Second, // default
    Verbose:          true,
})

Watch & WatchFlags work as before, but are marked as deprecated. Of note, they continue to watch hidden files/directories (WatchHidden: true).

It may be more appropriate if some of these options were specified at a "global" level rather than per-Watch, but I would rather not change the NewWatcher() API. I suppose we could add some accessors to the Watcher instead?

A number of options don't really make sense when watching a single file. I wonder if anyone is using fsnotify for that purpose, and whether or not FSEvents (#54) supports single file watches. If so, I'm sure we can come up with a solution beyond "don't use these options in this case", perhaps a WatchFile() method?

Triggers type

When looking through the Go standard library, I've seen constants in ALL_CAPS and TitleCase. I'm not aware of an official reason to choose one over the other, but I find the following looks a little nicer on a page than FSN_CREATE, etc.

type Triggers uint32

const (
    Create Triggers = 1 << iota
    Modify
    Delete
    Rename

    allEvents Triggers = Modify | Delete | Rename | Create // default
)

Outside of introducing a type for the constants, this is mostly an aesthetic change. The internal representation is exactly the same.

Comments

While working away on a first pull request, I would appreciate any early feedback on the naming and approach described here. Thanks!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions