diff --git a/Dockerfile b/Dockerfile index 76f0fe7514..f48ec117d8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,8 +4,8 @@ FROM docker.elastic.co/package-registry/distribution:production AS production FROM docker.elastic.co/package-registry/distribution:staging AS staging -FROM docker.elastic.co/package-registry/package-registry:v0.7.1 -LABEL package-registry=v0.7.1 +FROM docker.elastic.co/package-registry/package-registry:v0.9.0 +LABEL package-registry=v0.9.0 COPY --from=production /packages/production /packages/production COPY --from=staging /packages/staging /packages/staging diff --git a/go.mod b/go.mod index d51ce2b378..1d0d17bfe1 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,10 @@ module github.com/elastic/package-storage go 1.12 require ( - github.com/elastic/package-registry v0.7.0 + github.com/elastic/package-registry v0.9.0 github.com/magefile/mage v1.9.0 github.com/pkg/errors v0.9.1 + github.com/radovskyb/watcher v1.0.7 // indirect github.com/stretchr/testify v1.4.0 gopkg.in/yaml.v2 v2.3.0 // indirect ) diff --git a/go.sum b/go.sum index e279f4ca9d..ad092509e2 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,8 @@ github.com/elastic/go-ucfg v0.8.4-0.20200415140258-1232bd4774a6 h1:Ehbr7du4rSSEy github.com/elastic/go-ucfg v0.8.4-0.20200415140258-1232bd4774a6/go.mod h1:iaiY0NBIYeasNgycLyTvhJftQlQEUO2hpF+FX0JKxzo= github.com/elastic/package-registry v0.7.0 h1:32fAVDQNNJ+mE/8zVNXfUCPX99Z6DLghmPkI4YZBhRA= github.com/elastic/package-registry v0.7.0/go.mod h1:ERTTIxAsQOCVZJDqR4LJbDDAtxV+pz4wdPPrKheiAUc= +github.com/elastic/package-registry v0.9.0 h1:bfVF5k6w43zjYaF+0t3fRCU1IguRhwqeY1wjG1LMA6k= +github.com/elastic/package-registry v0.9.0/go.mod h1:oQx3Tg9ynuC6APd0o0OHud9kyPX6S6IzdJp/R4Hj1HY= github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= diff --git a/vendor/github.com/elastic/package-registry/util/dataset.go b/vendor/github.com/elastic/package-registry/util/dataset.go index a5395a77d1..f28f0e390a 100644 --- a/vendor/github.com/elastic/package-registry/util/dataset.go +++ b/vendor/github.com/elastic/package-registry/util/dataset.go @@ -136,10 +136,11 @@ func NewDataset(basePath string, p *Package) (*Dataset, error) { for i, _ := range d.Streams { if d.Streams[i].Enabled == nil { d.Streams[i].Enabled = &trueValue - // TODO: validate that the template path actually exists - if d.Streams[i].TemplatePath == "" { - d.Streams[i].TemplatePath = "stream.yml.hbs" - } + } + + // TODO: validate that the template path actually exists + if d.Streams[i].TemplatePath == "" { + d.Streams[i].TemplatePath = "stream.yml.hbs" } } @@ -304,9 +305,9 @@ func (d *Dataset) validateRequiredFields() error { } // Verify required keys - err = requireField(allFields, "dataset.type", "constant_keyword", err) - err = requireField(allFields, "dataset.name", "constant_keyword", err) - err = requireField(allFields, "dataset.namespace", "constant_keyword", err) + err = requireField(allFields, "datastream.type", "constant_keyword", err) + err = requireField(allFields, "datastream.dataset", "constant_keyword", err) + err = requireField(allFields, "datastream.namespace", "constant_keyword", err) err = requireField(allFields, "@timestamp", "date", err) return err } diff --git a/vendor/github.com/elastic/package-registry/util/package_watcher.go b/vendor/github.com/elastic/package-registry/util/package_watcher.go deleted file mode 100644 index 634532f0d4..0000000000 --- a/vendor/github.com/elastic/package-registry/util/package_watcher.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one -// or more contributor license agreements. Licensed under the Elastic License; -// you may not use this file except in compliance with the Elastic License. - -package util - -import ( - "log" - "os" - "time" - - "github.com/pkg/errors" - "github.com/radovskyb/watcher" -) - -const watcherPollingPeriod = 2 * time.Second - -var ( - w *watcher.Watcher -) - -func MustUsePackageWatcher(packagePaths []string) { - log.Println("Use package watcher") - - var err error - packageList, err = getPackagesFromFilesystem(packagePaths) - if err != nil { - log.Println(errors.Wrap(err, "watcher error: reading packages failed")) - } - - w = watcher.New() - w.SetMaxEvents(1) - - for _, p := range packagePaths { - err = w.AddRecursive(p) - if err != nil && !os.IsNotExist(err) { - log.Fatal(errors.Wrapf(err, "watching directory failed (path: %s)", p)) - } - } - - go w.Start(watcherPollingPeriod) - - go func() { - for { - select { - case _, ok := <-w.Event: - if !ok { - log.Println("Package watcher is stopped") - return // channel is closed - } - - time.Sleep(watcherPollingPeriod) // reload at the end of watch frame - log.Println("Reloading packages...") - packageList, err = getPackagesFromFilesystem(packagePaths) - if err != nil { - log.Println(errors.Wrap(err, "watcher error: reading packages failed")) - } - case err, ok := <-w.Error: - if !ok { - log.Println("Package watcher is stopped") - return // channel is closed - } - log.Println(errors.Wrap(err, "watcher error")) - } - } - }() -} - -func ClosePackageWatcher() { - if !packageWatcherEnabled() { - return - } - w.Close() -} - -func packageWatcherEnabled() bool { - return w != nil -} diff --git a/vendor/github.com/radovskyb/watcher/.travis.yml b/vendor/github.com/radovskyb/watcher/.travis.yml deleted file mode 100644 index 3f478f10f3..0000000000 --- a/vendor/github.com/radovskyb/watcher/.travis.yml +++ /dev/null @@ -1,4 +0,0 @@ -language: go -go: - - 1.7 - - tip \ No newline at end of file diff --git a/vendor/github.com/radovskyb/watcher/LICENSE b/vendor/github.com/radovskyb/watcher/LICENSE deleted file mode 100644 index 92ef0e9115..0000000000 --- a/vendor/github.com/radovskyb/watcher/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2016, Benjamin Radovsky. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of watcher nor the names of its contributors may be used to - endorse or promote products derived from this software without specific prior - written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/radovskyb/watcher/README.md b/vendor/github.com/radovskyb/watcher/README.md deleted file mode 100644 index 1c822e20ad..0000000000 --- a/vendor/github.com/radovskyb/watcher/README.md +++ /dev/null @@ -1,181 +0,0 @@ -# watcher - -[![Build Status](https://travis-ci.org/radovskyb/watcher.svg?branch=master)](https://travis-ci.org/radovskyb/watcher) - -`watcher` is a Go package for watching for files or directory changes (recursively or non recursively) without using filesystem events, which allows it to work cross platform consistently. - -`watcher` watches for changes and notifies over channels either anytime an event or an error has occurred. - -Events contain the `os.FileInfo` of the file or directory that the event is based on and the type of event and file or directory path. - -[Installation](#installation) -[Features](#features) -[Example](#example) -[Contributing](#contributing) -[Watcher Command](#command) - -# Update -- Event.OldPath has been added [Aug 17, 2019] -- Added new file filter hooks (Including a built in regexp filtering hook) [Dec 12, 2018] -- Event.Path for Rename and Move events is now returned in the format of `fromPath -> toPath` - -#### Chmod event is not supported under windows. - -# Installation - -```shell -go get -u github.com/radovskyb/watcher/... -``` - -# Features - -- Customizable polling interval. -- Filter Events. -- Watch folders recursively or non-recursively. -- Choose to ignore hidden files. -- Choose to ignore specified files and folders. -- Notifies the `os.FileInfo` of the file that the event is based on. e.g `Name`, `ModTime`, `IsDir`, etc. -- Notifies the full path of the file that the event is based on or the old and new paths if the event was a `Rename` or `Move` event. -- Limit amount of events that can be received per watching cycle. -- List the files being watched. -- Trigger custom events. - -# Todo - -- Write more tests. -- Write benchmarks. - -# Example - -```go -package main - -import ( - "fmt" - "log" - "time" - - "github.com/radovskyb/watcher" -) - -func main() { - w := watcher.New() - - // SetMaxEvents to 1 to allow at most 1 event's to be received - // on the Event channel per watching cycle. - // - // If SetMaxEvents is not set, the default is to send all events. - w.SetMaxEvents(1) - - // Only notify rename and move events. - w.FilterOps(watcher.Rename, watcher.Move) - - // Only files that match the regular expression during file listings - // will be watched. - r := regexp.MustCompile("^abc$") - w.AddFilterHook(watcher.RegexFilterHook(r, false)) - - go func() { - for { - select { - case event := <-w.Event: - fmt.Println(event) // Print the event's info. - case err := <-w.Error: - log.Fatalln(err) - case <-w.Closed: - return - } - } - }() - - // Watch this folder for changes. - if err := w.Add("."); err != nil { - log.Fatalln(err) - } - - // Watch test_folder recursively for changes. - if err := w.AddRecursive("../test_folder"); err != nil { - log.Fatalln(err) - } - - // Print a list of all of the files and folders currently - // being watched and their paths. - for path, f := range w.WatchedFiles() { - fmt.Printf("%s: %s\n", path, f.Name()) - } - - fmt.Println() - - // Trigger 2 events after watcher started. - go func() { - w.Wait() - w.TriggerEvent(watcher.Create, nil) - w.TriggerEvent(watcher.Remove, nil) - }() - - // Start the watching process - it'll check for changes every 100ms. - if err := w.Start(time.Millisecond * 100); err != nil { - log.Fatalln(err) - } -} -``` - -# Contributing -If you would ike to contribute, simply submit a pull request. - -# Command - -`watcher` comes with a simple command which is installed when using the `go get` command from above. - -# Usage - -``` -Usage of watcher: - -cmd string - command to run when an event occurs - -dotfiles - watch dot files (default true) - -ignore string - comma separated list of paths to ignore - -interval string - watcher poll interval (default "100ms") - -keepalive - keep alive when a cmd returns code != 0 - -list - list watched files on start - -pipe - pipe event's info to command's stdin - -recursive - watch folders recursively (default true) - -startcmd - run the command when watcher starts -``` - -All of the flags are optional and watcher can also be called by itself: -```shell -watcher -``` -(watches the current directory recursively for changes and notifies any events that occur.) - -A more elaborate example using the `watcher` command: -```shell -watcher -dotfiles=false -recursive=false -cmd="./myscript" main.go ../ -``` -In this example, `watcher` will ignore dot files and folders and won't watch any of the specified folders recursively. It will also run the script `./myscript` anytime an event occurs while watching `main.go` or any files or folders in the previous directory (`../`). - -Using the `pipe` and `cmd` flags together will send the event's info to the command's stdin when changes are detected. - -First create a file called `script.py` with the following contents: -```python -import sys - -for line in sys.stdin: - print (line + " - python") -``` - -Next, start watcher with the `pipe` and `cmd` flags enabled: -```shell -watcher -cmd="python script.py" -pipe=true -``` - -Now when changes are detected, the event's info will be output from the running python script. diff --git a/vendor/github.com/radovskyb/watcher/ishidden.go b/vendor/github.com/radovskyb/watcher/ishidden.go deleted file mode 100644 index 0f242e8aec..0000000000 --- a/vendor/github.com/radovskyb/watcher/ishidden.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build !windows - -package watcher - -import ( - "path/filepath" - "strings" -) - -func isHiddenFile(path string) (bool, error) { - return strings.HasPrefix(filepath.Base(path), "."), nil -} diff --git a/vendor/github.com/radovskyb/watcher/ishidden_windows.go b/vendor/github.com/radovskyb/watcher/ishidden_windows.go deleted file mode 100644 index 306c6b7111..0000000000 --- a/vendor/github.com/radovskyb/watcher/ishidden_windows.go +++ /dev/null @@ -1,21 +0,0 @@ -// +build windows - -package watcher - -import ( - "syscall" -) - -func isHiddenFile(path string) (bool, error) { - pointer, err := syscall.UTF16PtrFromString(path) - if err != nil { - return false, err - } - - attributes, err := syscall.GetFileAttributes(pointer) - if err != nil { - return false, err - } - - return attributes&syscall.FILE_ATTRIBUTE_HIDDEN != 0, nil -} diff --git a/vendor/github.com/radovskyb/watcher/samefile.go b/vendor/github.com/radovskyb/watcher/samefile.go deleted file mode 100644 index 5968bb6fe2..0000000000 --- a/vendor/github.com/radovskyb/watcher/samefile.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build !windows - -package watcher - -import "os" - -func sameFile(fi1, fi2 os.FileInfo) bool { - return os.SameFile(fi1, fi2) -} diff --git a/vendor/github.com/radovskyb/watcher/samefile_windows.go b/vendor/github.com/radovskyb/watcher/samefile_windows.go deleted file mode 100644 index 7785a129b7..0000000000 --- a/vendor/github.com/radovskyb/watcher/samefile_windows.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build windows - -package watcher - -import "os" - -func sameFile(fi1, fi2 os.FileInfo) bool { - return fi1.ModTime() == fi2.ModTime() && - fi1.Size() == fi2.Size() && - fi1.Mode() == fi2.Mode() && - fi1.IsDir() == fi2.IsDir() -} diff --git a/vendor/github.com/radovskyb/watcher/watcher.go b/vendor/github.com/radovskyb/watcher/watcher.go deleted file mode 100644 index 4da4dfe3b9..0000000000 --- a/vendor/github.com/radovskyb/watcher/watcher.go +++ /dev/null @@ -1,715 +0,0 @@ -package watcher - -import ( - "errors" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "regexp" - "strings" - "sync" - "time" -) - -var ( - // ErrDurationTooShort occurs when calling the watcher's Start - // method with a duration that's less than 1 nanosecond. - ErrDurationTooShort = errors.New("error: duration is less than 1ns") - - // ErrWatcherRunning occurs when trying to call the watcher's - // Start method and the polling cycle is still already running - // from previously calling Start and not yet calling Close. - ErrWatcherRunning = errors.New("error: watcher is already running") - - // ErrWatchedFileDeleted is an error that occurs when a file or folder that was - // being watched has been deleted. - ErrWatchedFileDeleted = errors.New("error: watched file or folder deleted") - - // ErrSkip is less of an error, but more of a way for path hooks to skip a file or - // directory. - ErrSkip = errors.New("error: skipping file") -) - -// An Op is a type that is used to describe what type -// of event has occurred during the watching process. -type Op uint32 - -// Ops -const ( - Create Op = iota - Write - Remove - Rename - Chmod - Move -) - -var ops = map[Op]string{ - Create: "CREATE", - Write: "WRITE", - Remove: "REMOVE", - Rename: "RENAME", - Chmod: "CHMOD", - Move: "MOVE", -} - -// String prints the string version of the Op consts -func (e Op) String() string { - if op, found := ops[e]; found { - return op - } - return "???" -} - -// An Event describes an event that is received when files or directory -// changes occur. It includes the os.FileInfo of the changed file or -// directory and the type of event that's occurred and the full path of the file. -type Event struct { - Op - Path string - OldPath string - os.FileInfo -} - -// String returns a string depending on what type of event occurred and the -// file name associated with the event. -func (e Event) String() string { - if e.FileInfo == nil { - return "???" - } - - pathType := "FILE" - if e.IsDir() { - pathType = "DIRECTORY" - } - return fmt.Sprintf("%s %q %s [%s]", pathType, e.Name(), e.Op, e.Path) -} - -// FilterFileHookFunc is a function that is called to filter files during listings. -// If a file is ok to be listed, nil is returned otherwise ErrSkip is returned. -type FilterFileHookFunc func(info os.FileInfo, fullPath string) error - -// RegexFilterHook is a function that accepts or rejects a file -// for listing based on whether it's filename or full path matches -// a regular expression. -func RegexFilterHook(r *regexp.Regexp, useFullPath bool) FilterFileHookFunc { - return func(info os.FileInfo, fullPath string) error { - str := info.Name() - - if useFullPath { - str = fullPath - } - - // Match - if r.MatchString(str) { - return nil - } - - // No match. - return ErrSkip - } -} - -// Watcher describes a process that watches files for changes. -type Watcher struct { - Event chan Event - Error chan error - Closed chan struct{} - close chan struct{} - wg *sync.WaitGroup - - // mu protects the following. - mu *sync.Mutex - ffh []FilterFileHookFunc - running bool - names map[string]bool // bool for recursive or not. - files map[string]os.FileInfo // map of files. - ignored map[string]struct{} // ignored files or directories. - ops map[Op]struct{} // Op filtering. - ignoreHidden bool // ignore hidden files or not. - maxEvents int // max sent events per cycle -} - -// New creates a new Watcher. -func New() *Watcher { - // Set up the WaitGroup for w.Wait(). - var wg sync.WaitGroup - wg.Add(1) - - return &Watcher{ - Event: make(chan Event), - Error: make(chan error), - Closed: make(chan struct{}), - close: make(chan struct{}), - mu: new(sync.Mutex), - wg: &wg, - files: make(map[string]os.FileInfo), - ignored: make(map[string]struct{}), - names: make(map[string]bool), - } -} - -// SetMaxEvents controls the maximum amount of events that are sent on -// the Event channel per watching cycle. If max events is less than 1, there is -// no limit, which is the default. -func (w *Watcher) SetMaxEvents(delta int) { - w.mu.Lock() - w.maxEvents = delta - w.mu.Unlock() -} - -// AddFilterHook -func (w *Watcher) AddFilterHook(f FilterFileHookFunc) { - w.mu.Lock() - w.ffh = append(w.ffh, f) - w.mu.Unlock() -} - -// IgnoreHiddenFiles sets the watcher to ignore any file or directory -// that starts with a dot. -func (w *Watcher) IgnoreHiddenFiles(ignore bool) { - w.mu.Lock() - w.ignoreHidden = ignore - w.mu.Unlock() -} - -// FilterOps filters which event op types should be returned -// when an event occurs. -func (w *Watcher) FilterOps(ops ...Op) { - w.mu.Lock() - w.ops = make(map[Op]struct{}) - for _, op := range ops { - w.ops[op] = struct{}{} - } - w.mu.Unlock() -} - -// Add adds either a single file or directory to the file list. -func (w *Watcher) Add(name string) (err error) { - w.mu.Lock() - defer w.mu.Unlock() - - name, err = filepath.Abs(name) - if err != nil { - return err - } - - // If name is on the ignored list or if hidden files are - // ignored and name is a hidden file or directory, simply return. - _, ignored := w.ignored[name] - - isHidden, err := isHiddenFile(name) - if err != nil { - return err - } - - if ignored || (w.ignoreHidden && isHidden) { - return nil - } - - // Add the directory's contents to the files list. - fileList, err := w.list(name) - if err != nil { - return err - } - for k, v := range fileList { - w.files[k] = v - } - - // Add the name to the names list. - w.names[name] = false - - return nil -} - -func (w *Watcher) list(name string) (map[string]os.FileInfo, error) { - fileList := make(map[string]os.FileInfo) - - // Make sure name exists. - stat, err := os.Stat(name) - if err != nil { - return nil, err - } - - fileList[name] = stat - - // If it's not a directory, just return. - if !stat.IsDir() { - return fileList, nil - } - - // It's a directory. - fInfoList, err := ioutil.ReadDir(name) - if err != nil { - return nil, err - } - // Add all of the files in the directory to the file list as long - // as they aren't on the ignored list or are hidden files if ignoreHidden - // is set to true. -outer: - for _, fInfo := range fInfoList { - path := filepath.Join(name, fInfo.Name()) - _, ignored := w.ignored[path] - - isHidden, err := isHiddenFile(path) - if err != nil { - return nil, err - } - - if ignored || (w.ignoreHidden && isHidden) { - continue - } - - for _, f := range w.ffh { - err := f(fInfo, path) - if err == ErrSkip { - continue outer - } - if err != nil { - return nil, err - } - } - - fileList[path] = fInfo - } - return fileList, nil -} - -// AddRecursive adds either a single file or directory recursively to the file list. -func (w *Watcher) AddRecursive(name string) (err error) { - w.mu.Lock() - defer w.mu.Unlock() - - name, err = filepath.Abs(name) - if err != nil { - return err - } - - fileList, err := w.listRecursive(name) - if err != nil { - return err - } - for k, v := range fileList { - w.files[k] = v - } - - // Add the name to the names list. - w.names[name] = true - - return nil -} - -func (w *Watcher) listRecursive(name string) (map[string]os.FileInfo, error) { - fileList := make(map[string]os.FileInfo) - - return fileList, filepath.Walk(name, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - for _, f := range w.ffh { - err := f(info, path) - if err == ErrSkip { - return nil - } - if err != nil { - return err - } - } - - // If path is ignored and it's a directory, skip the directory. If it's - // ignored and it's a single file, skip the file. - _, ignored := w.ignored[path] - - isHidden, err := isHiddenFile(path) - if err != nil { - return err - } - - if ignored || (w.ignoreHidden && isHidden) { - if info.IsDir() { - return filepath.SkipDir - } - return nil - } - // Add the path and it's info to the file list. - fileList[path] = info - return nil - }) -} - -// Remove removes either a single file or directory from the file's list. -func (w *Watcher) Remove(name string) (err error) { - w.mu.Lock() - defer w.mu.Unlock() - - name, err = filepath.Abs(name) - if err != nil { - return err - } - - // Remove the name from w's names list. - delete(w.names, name) - - // If name is a single file, remove it and return. - info, found := w.files[name] - if !found { - return nil // Doesn't exist, just return. - } - if !info.IsDir() { - delete(w.files, name) - return nil - } - - // Delete the actual directory from w.files - delete(w.files, name) - - // If it's a directory, delete all of it's contents from w.files. - for path := range w.files { - if filepath.Dir(path) == name { - delete(w.files, path) - } - } - return nil -} - -// RemoveRecursive removes either a single file or a directory recursively from -// the file's list. -func (w *Watcher) RemoveRecursive(name string) (err error) { - w.mu.Lock() - defer w.mu.Unlock() - - name, err = filepath.Abs(name) - if err != nil { - return err - } - - // Remove the name from w's names list. - delete(w.names, name) - - // If name is a single file, remove it and return. - info, found := w.files[name] - if !found { - return nil // Doesn't exist, just return. - } - if !info.IsDir() { - delete(w.files, name) - return nil - } - - // If it's a directory, delete all of it's contents recursively - // from w.files. - for path := range w.files { - if strings.HasPrefix(path, name) { - delete(w.files, path) - } - } - return nil -} - -// Ignore adds paths that should be ignored. -// -// For files that are already added, Ignore removes them. -func (w *Watcher) Ignore(paths ...string) (err error) { - for _, path := range paths { - path, err = filepath.Abs(path) - if err != nil { - return err - } - // Remove any of the paths that were already added. - if err := w.RemoveRecursive(path); err != nil { - return err - } - w.mu.Lock() - w.ignored[path] = struct{}{} - w.mu.Unlock() - } - return nil -} - -// WatchedFiles returns a map of files added to a Watcher. -func (w *Watcher) WatchedFiles() map[string]os.FileInfo { - w.mu.Lock() - defer w.mu.Unlock() - - files := make(map[string]os.FileInfo) - for k, v := range w.files { - files[k] = v - } - - return files -} - -// fileInfo is an implementation of os.FileInfo that can be used -// as a mocked os.FileInfo when triggering an event when the specified -// os.FileInfo is nil. -type fileInfo struct { - name string - size int64 - mode os.FileMode - modTime time.Time - sys interface{} - dir bool -} - -func (fs *fileInfo) IsDir() bool { - return fs.dir -} -func (fs *fileInfo) ModTime() time.Time { - return fs.modTime -} -func (fs *fileInfo) Mode() os.FileMode { - return fs.mode -} -func (fs *fileInfo) Name() string { - return fs.name -} -func (fs *fileInfo) Size() int64 { - return fs.size -} -func (fs *fileInfo) Sys() interface{} { - return fs.sys -} - -// TriggerEvent is a method that can be used to trigger an event, separate to -// the file watching process. -func (w *Watcher) TriggerEvent(eventType Op, file os.FileInfo) { - w.Wait() - if file == nil { - file = &fileInfo{name: "triggered event", modTime: time.Now()} - } - w.Event <- Event{Op: eventType, Path: "-", FileInfo: file} -} - -func (w *Watcher) retrieveFileList() map[string]os.FileInfo { - w.mu.Lock() - defer w.mu.Unlock() - - fileList := make(map[string]os.FileInfo) - - var list map[string]os.FileInfo - var err error - - for name, recursive := range w.names { - if recursive { - list, err = w.listRecursive(name) - if err != nil { - if os.IsNotExist(err) { - w.mu.Unlock() - if name == err.(*os.PathError).Path { - w.Error <- ErrWatchedFileDeleted - w.RemoveRecursive(name) - } - w.mu.Lock() - } else { - w.Error <- err - } - } - } else { - list, err = w.list(name) - if err != nil { - if os.IsNotExist(err) { - w.mu.Unlock() - if name == err.(*os.PathError).Path { - w.Error <- ErrWatchedFileDeleted - w.Remove(name) - } - w.mu.Lock() - } else { - w.Error <- err - } - } - } - // Add the file's to the file list. - for k, v := range list { - fileList[k] = v - } - } - - return fileList -} - -// Start begins the polling cycle which repeats every specified -// duration until Close is called. -func (w *Watcher) Start(d time.Duration) error { - // Return an error if d is less than 1 nanosecond. - if d < time.Nanosecond { - return ErrDurationTooShort - } - - // Make sure the Watcher is not already running. - w.mu.Lock() - if w.running { - w.mu.Unlock() - return ErrWatcherRunning - } - w.running = true - w.mu.Unlock() - - // Unblock w.Wait(). - w.wg.Done() - - for { - // done lets the inner polling cycle loop know when the - // current cycle's method has finished executing. - done := make(chan struct{}) - - // Any events that are found are first piped to evt before - // being sent to the main Event channel. - evt := make(chan Event) - - // Retrieve the file list for all watched file's and dirs. - fileList := w.retrieveFileList() - - // cancel can be used to cancel the current event polling function. - cancel := make(chan struct{}) - - // Look for events. - go func() { - w.pollEvents(fileList, evt, cancel) - done <- struct{}{} - }() - - // numEvents holds the number of events for the current cycle. - numEvents := 0 - - inner: - for { - select { - case <-w.close: - close(cancel) - close(w.Closed) - return nil - case event := <-evt: - if len(w.ops) > 0 { // Filter Ops. - _, found := w.ops[event.Op] - if !found { - continue - } - } - numEvents++ - if w.maxEvents > 0 && numEvents > w.maxEvents { - close(cancel) - break inner - } - w.Event <- event - case <-done: // Current cycle is finished. - break inner - } - } - - // Update the file's list. - w.mu.Lock() - w.files = fileList - w.mu.Unlock() - - // Sleep and then continue to the next loop iteration. - time.Sleep(d) - } -} - -func (w *Watcher) pollEvents(files map[string]os.FileInfo, evt chan Event, - cancel chan struct{}) { - w.mu.Lock() - defer w.mu.Unlock() - - // Store create and remove events for use to check for rename events. - creates := make(map[string]os.FileInfo) - removes := make(map[string]os.FileInfo) - - // Check for removed files. - for path, info := range w.files { - if _, found := files[path]; !found { - removes[path] = info - } - } - - // Check for created files, writes and chmods. - for path, info := range files { - oldInfo, found := w.files[path] - if !found { - // A file was created. - creates[path] = info - continue - } - if oldInfo.ModTime() != info.ModTime() { - select { - case <-cancel: - return - case evt <- Event{Write, path, path, info}: - } - } - if oldInfo.Mode() != info.Mode() { - select { - case <-cancel: - return - case evt <- Event{Chmod, path, path, info}: - } - } - } - - // Check for renames and moves. - for path1, info1 := range removes { - for path2, info2 := range creates { - if sameFile(info1, info2) { - e := Event{ - Op: Move, - Path: path2, - OldPath: path1, - FileInfo: info1, - } - // If they are from the same directory, it's a rename - // instead of a move event. - if filepath.Dir(path1) == filepath.Dir(path2) { - e.Op = Rename - } - - delete(removes, path1) - delete(creates, path2) - - select { - case <-cancel: - return - case evt <- e: - } - } - } - } - - // Send all the remaining create and remove events. - for path, info := range creates { - select { - case <-cancel: - return - case evt <- Event{Create, path, "", info}: - } - } - for path, info := range removes { - select { - case <-cancel: - return - case evt <- Event{Remove, path, path, info}: - } - } -} - -// Wait blocks until the watcher is started. -func (w *Watcher) Wait() { - w.wg.Wait() -} - -// Close stops a Watcher and unlocks its mutex, then sends a close signal. -func (w *Watcher) Close() { - w.mu.Lock() - if !w.running { - w.mu.Unlock() - return - } - w.running = false - w.files = make(map[string]os.FileInfo) - w.names = make(map[string]bool) - w.mu.Unlock() - // Send a close signal to the Start method. - w.close <- struct{}{} -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 39abac6714..2142cbe7c2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -11,7 +11,7 @@ github.com/davecgh/go-spew/spew github.com/elastic/go-ucfg github.com/elastic/go-ucfg/parse github.com/elastic/go-ucfg/yaml -# github.com/elastic/package-registry v0.7.0 +# github.com/elastic/package-registry v0.9.0 github.com/elastic/package-registry/util # github.com/magefile/mage v1.9.0 github.com/magefile/mage/mg @@ -20,8 +20,6 @@ github.com/magefile/mage/sh github.com/pkg/errors # github.com/pmezard/go-difflib v1.0.0 github.com/pmezard/go-difflib/difflib -# github.com/radovskyb/watcher v1.0.7 -github.com/radovskyb/watcher # github.com/stretchr/testify v1.4.0 github.com/stretchr/testify/assert # gopkg.in/yaml.v2 v2.3.0