Back to godoc.org
github.com/vrongmeal/leaf

Package leaf

v1.3.0
Latest Go to latest

The latest major version is .

Published: Sep 12, 2020 | License: MIT | Module: github.com/vrongmeal/leaf

Overview

Package leaf provides with utilities to create the leaf CLI tool. It includes watcher, filters and commander which watch files for changes, filter out required results and execute external commands respectively.

The package comes with utilities that can aid in creating a hot-reloader with a simple go program.

Let's look at an example where the watcher watches the `src/` directory for changes and for any changes builds the project.

package main

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

	"github.com/vrongmeal/leaf"
)

func main() {
	// Use a context that cancels when program is interrupted.
	ctx := leaf.NewCmdContext(func(os.Signal) {
		log.Println("Shutting down.")
	})

	cwd, err := os.Getwd()
	if err != nil {
		log.Fatalln(err)
	}

	// Root is <cwd>/src
	root := filepath.Join(cwd, "src")

	// Exclude "src/index.html" from results.
	filters := []leaf.Filter{
		{Include: false, Pattern: "src/index.html"},
	}

	filterCollection := leaf.NewFilterCollection(
		filters,
		// Matches directory or filepath.Match expressions
		leaf.StandardFilterMatcher,
		// Definitely excludes and shows only includes (if any)
		leaf.StandardFilterHandler)

	watcher, err := leaf.NewWatcher(
		root,
		// Standard paths to exclude, like vendor, .git,
		// node_modules, venv etc.
		leaf.DefaultExcludePaths,
		filterCollection)
	if err != nil {
		log.Fatalln(err)
	}

	cmd, err := leaf.NewCommand("npm run build")
	if err != nil {
		log.Fatalln(err)
	}

	log.Printf("Watching: %s\n", root)

	for change := range watcher.Watch(ctx) {
		if change.Err != nil {
			log.Printf("ERROR: %v", change.Err)
			continue
		}
		// If no error run the command
		log.Printf("Running: %s\n", cmd.String())
		cmd.Execute(ctx)
	}
}

Index

Variables

var (
	// DefaultExcludePathsKeyword is used to include all
	// default excludes.
	DefaultExcludePathsKeyword = "DEFAULTS"

	// CWD is the current working directory or ".".
	CWD string

	// DefaultConfPath is the default path for app config.
	DefaultConfPath string

	// DefaultExcludePaths are the paths that should be
	// generally excluded while watching a project.
	DefaultExcludePaths = []string{
		".git/",
		"node_modules/",
		"vendor/",
		"venv/",
	}
	// ImportPath is the import path for leaf package.
	ImportPath = "github.com/vrongmeal/leaf"
)

func GoModuleInfo

func GoModuleInfo() (*debug.Module, error)

GoModuleInfo returns the go module information which includes the build info (version etc.).

func NewCmdContext

func NewCmdContext(onInterrupt func(os.Signal)) context.Context

NewCmdContext returns a context which cancels on an OS interrupt, i.e., cancels when process is killed.

func StandardFilterHandler

func StandardFilterHandler(fc *FilterCollection, path string) bool

StandardFilterHandler returns true if the path should be included and returns false if path should not be included in result.

func StandardFilterMatcher

func StandardFilterMatcher(pattern, path string) bool

StandardFilterMatcher matches the pattern with the path and returns true if the path either starts with (in absolute terms) or matches like the path regex.

type Command

type Command struct {
	Name string
	Args []string
	// contains filtered or unexported fields
}

Command is an external command that can be executed.

func NewCommand

func NewCommand(cmd string) (*Command, error)

NewCommand creates a new command from the string.

func (*Command) Execute

func (c *Command) Execute(ctx context.Context) error

Execute runs the commands and exits elegantly when the context is canceled.

This doesn't use the exec.CommandContext because we just don't want to kill the parent process but all the child processes too.

func (*Command) String

func (c *Command) String() string

String returns the command in a human-readable format.

type Commander

type Commander struct {
	Commands []string

	OnStart func(*Command)
	OnError func(error)
	OnExit  func()

	ExitOnError bool
	// contains filtered or unexported fields
}

Commander has a set of commands that run in order and exit when the context is canceled.

func NewCommander

func NewCommander(commander Commander) *Commander

NewCommander creates a new commander.

func (*Commander) Done

func (c *Commander) Done() <-chan bool

Done signals that the commander is done running the commands.

func (*Commander) Run

func (c *Commander) Run(ctx context.Context)

Run executes the commands in order. It stops when the context is canceled.

type Config

type Config struct {
	// Root directory to watch.
	Root string `mapstructure:"root"`

	// Exclude these directories from watch.
	Exclude []string `mapstructure:"exclude"`

	// Filters to apply to the watch.
	Filters []string `mapstructure:"filters"`

	// Exec these commads after changes detected.
	Exec []string `mapstructure:"exec"`

	// ExitOnErr breaks the chain of command if any command returnns an error.
	ExitOnErr bool `mapstructure:"exit_on_err"`

	// Delay after which commands should be executed.
	Delay time.Duration `mapstructure:"delay"`
}

Config represents the conf file for the runner.

type Filter

type Filter struct {
	Include bool // whether to include pattern
	Pattern string
}

Filter can be used to Filter out watch results.

func NewFilter

func NewFilter(pattern string) (Filter, error)

NewFilter creates a filter from the pattern string. The pattern either starts with '+' or '-' to include or exclude the directory from results.

type FilterCollection

type FilterCollection struct {
	Includes []string
	Excludes []string
	// contains filtered or unexported fields
}

A FilterCollection contains a bunch of includes and excludes.

func NewFCFromPatterns

func NewFCFromPatterns(patterns []string, mf FilterMatchFunc, hf FilterHandleFunc) (*FilterCollection, error)

NewFCFromPatterns creates a filter collection from a list of string format filters, like `+ /path/to/some/dir`.

func NewFilterCollection

func NewFilterCollection(filters []Filter, mf FilterMatchFunc, hf FilterHandleFunc) *FilterCollection

NewFilterCollection creates a filter collection from a bunch of filter patterns.

func (*FilterCollection) HasExclude

func (fc *FilterCollection) HasExclude(path string) bool

HasExclude tells if the collection matches the path with one of its excludes.

func (*FilterCollection) HasInclude

func (fc *FilterCollection) HasInclude(path string) bool

HasInclude tells if the collection matches the path with one of its includes.

func (*FilterCollection) ShouldHandlePath

func (fc *FilterCollection) ShouldHandlePath(path string) bool

ShouldHandlePath returns the result of the path handler for the filter collection.

type FilterHandleFunc

type FilterHandleFunc func(fc *FilterCollection, path string) bool

FilterHandleFunc is a function that checks if for the filter collection, should the path be handled or not, i.e., should the notifier tick for change in path or not.

type FilterMatchFunc

type FilterMatchFunc func(pattern, path string) bool

FilterMatchFunc compares the pattern with the path of the file changed and returns true if the path resembles the given pattern.

type WatchResult

type WatchResult struct {
	File string
	Err  error
}

WatchResult has the file changed or the error that occurred during watching.

type Watcher

type Watcher struct {
	// contains filtered or unexported fields
}

Watcher watches a directory for changes and updates the stream when a file change (valid by filters) is updated.

func NewWatcher

func NewWatcher(root string, exclude []string, fc *FilterCollection) (*Watcher, error)

NewWatcher returns a watcher from the given options.

func (*Watcher) Watch

func (w *Watcher) Watch(ctx context.Context) <-chan WatchResult

Watch executes the watching of files. Exits on cancellation of the context.

Package Files

Documentation was rendered with GOOS=linux and GOARCH=amd64.

Jump to identifier

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to identifier