Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
06fb9f6a97
12
.gitpod.Dockerfile
vendored
Normal file
12
.gitpod.Dockerfile
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
FROM gitpod/workspace-full
|
||||
|
||||
USER root
|
||||
|
||||
# Install custom tools, runtime, etc. using apt-get
|
||||
# For example, the command below would install "bastet" - a command line tetris clone:
|
||||
#
|
||||
# RUN apt-get update \
|
||||
# && apt-get install -y bastet \
|
||||
# && apt-get clean && rm -rf /var/cache/apt/* && rm -rf /var/lib/apt/lists/* && rm -rf /tmp/*
|
||||
#
|
||||
# More information: https://www.gitpod.io/docs/42_config_docker/
|
7
.gitpod.yml
Normal file
7
.gitpod.yml
Normal file
@ -0,0 +1,7 @@
|
||||
image:
|
||||
file: .gitpod.Dockerfile
|
||||
|
||||
# List the start up tasks. You can start them in parallel in multiple terminals. See https://www.gitpod.io/docs/44_config_start_tasks/
|
||||
tasks:
|
||||
- init: go get -d -v ./...
|
||||
command: go build
|
15
.travis.yml
Normal file
15
.travis.yml
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.13.x
|
||||
- master
|
||||
|
||||
script:
|
||||
- go build
|
||||
- ./fileboy version
|
||||
- ./fileboy help
|
||||
- ./fileboy init
|
||||
- cat filegirl.yaml
|
||||
- ./fileboy exec
|
||||
|
@ -1,5 +1,7 @@
|
||||
## 项目说明
|
||||
|
||||
[![Build Status](https://travis-ci.org/dengsgo/fileboy.svg?branch=master)](https://travis-ci.org/dengsgo/fileboy) [![Go Report Card](https://goreportcard.com/badge/github.com/dengsgo/fileboy)](https://goreportcard.com/report/github.com/dengsgo/fileboy)
|
||||
|
||||
fileboy,文件变更监听通知系统,使用 Go 编写。
|
||||
适用于 Hot Reload (典型的如开发go项目,无需每次手动执行 go build;又比如前端 node 打包) 或者 系统监控的场景。
|
||||
___
|
||||
|
95
fileboy.go
95
fileboy.go
@ -29,12 +29,21 @@ var (
|
||||
watcher *fsnotify.Watcher
|
||||
|
||||
taskMan *TaskMan
|
||||
|
||||
ioeventMapStr = map[fsnotify.Op]string{
|
||||
fsnotify.Write: "write",
|
||||
fsnotify.Rename: "rename",
|
||||
fsnotify.Remove: "remove",
|
||||
fsnotify.Create: "create",
|
||||
fsnotify.Chmod: "chmod",
|
||||
}
|
||||
)
|
||||
|
||||
type changedFile struct {
|
||||
Name string
|
||||
Changed int64
|
||||
Ext string
|
||||
Event string
|
||||
}
|
||||
|
||||
func parseConfig() {
|
||||
@ -56,6 +65,7 @@ func parseConfig() {
|
||||
cfg.Monitor.TypesMap = map[string]bool{}
|
||||
cfg.Monitor.IncludeDirsMap = map[string]bool{}
|
||||
cfg.Monitor.ExceptDirsMap = map[string]bool{}
|
||||
cfg.Monitor.IncludeDirsRec = map[string]bool{}
|
||||
// convert to map
|
||||
for _, v := range cfg.Monitor.Types {
|
||||
cfg.Monitor.TypesMap[v] = true
|
||||
@ -70,26 +80,23 @@ func eventDispatcher(event fsnotify.Event) {
|
||||
!keyInMonitorTypesMap(ext, cfg) {
|
||||
return
|
||||
}
|
||||
switch event.Op {
|
||||
case
|
||||
fsnotify.Write,
|
||||
fsnotify.Rename:
|
||||
log.Println("EVENT", event.Op.String(), ":", event.Name)
|
||||
taskMan.Put(&changedFile{
|
||||
Name: relativePath(projectFolder, event.Name),
|
||||
Changed: time.Now().UnixNano(),
|
||||
Ext: ext,
|
||||
})
|
||||
case fsnotify.Remove:
|
||||
case fsnotify.Create:
|
||||
|
||||
op := ioeventMapStr[event.Op]
|
||||
if len(cfg.Monitor.Events) != 0 && !inStrArray(op, cfg.Monitor.Events) {
|
||||
return
|
||||
}
|
||||
log.Println("EVENT", event.Op.String(), ":", event.Name)
|
||||
taskMan.Put(&changedFile{
|
||||
Name: relativePath(projectFolder, event.Name),
|
||||
Changed: time.Now().UnixNano(),
|
||||
Ext: ext,
|
||||
Event: op,
|
||||
})
|
||||
}
|
||||
|
||||
func addWatcher() {
|
||||
log.Println("collecting directory information...")
|
||||
dirsMap := map[string]bool{
|
||||
projectFolder: true,
|
||||
}
|
||||
dirsMap := map[string]bool{}
|
||||
for _, dir := range cfg.Monitor.IncludeDirs {
|
||||
darr := dirParse2Array(dir)
|
||||
if len(darr) < 1 || len(darr) > 2 {
|
||||
@ -107,6 +114,7 @@ func addWatcher() {
|
||||
listFile(projectFolder, func(d string) {
|
||||
dirsMap[d] = true
|
||||
})
|
||||
cfg.Monitor.IncludeDirsRec[projectFolder] = true
|
||||
break
|
||||
} else {
|
||||
dirsMap[projectFolder] = true
|
||||
@ -118,6 +126,7 @@ func addWatcher() {
|
||||
listFile(md, func(d string) {
|
||||
dirsMap[d] = true
|
||||
})
|
||||
cfg.Monitor.IncludeDirsRec[md] = true
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,7 +145,7 @@ func addWatcher() {
|
||||
log.Println("watcher add -> ", dir)
|
||||
err := watcher.Add(dir)
|
||||
if err != nil {
|
||||
logAndExit(err)
|
||||
logAndExit(PreError, err)
|
||||
}
|
||||
}
|
||||
log.Println("total monitored dirs: " + strconv.Itoa(len(dirsMap)))
|
||||
@ -161,6 +170,9 @@ func initWatcher() {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
// directory structure changes, dynamically add, delete and monitor according to rules
|
||||
// TODO // this method cannot be triggered when the parent folder of the change folder is not monitored
|
||||
go watchChangeHandler(event)
|
||||
eventDispatcher(event)
|
||||
case err, ok := <-watcher.Errors:
|
||||
if !ok {
|
||||
@ -173,6 +185,56 @@ func initWatcher() {
|
||||
addWatcher()
|
||||
}
|
||||
|
||||
func watchChangeHandler(event fsnotify.Event) {
|
||||
if event.Op != fsnotify.Create && event.Op != fsnotify.Rename {
|
||||
return
|
||||
}
|
||||
_, err := ioutil.ReadDir(event.Name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
do := false
|
||||
for rec := range cfg.Monitor.IncludeDirsRec {
|
||||
if !strings.HasPrefix(event.Name, rec) {
|
||||
continue
|
||||
}
|
||||
// check exceptDirs
|
||||
has := false
|
||||
for _, v := range cfg.Monitor.ExceptDirs {
|
||||
if strings.HasPrefix(event.Name, projectFolder+"/"+v) {
|
||||
has = true
|
||||
}
|
||||
}
|
||||
if has {
|
||||
continue
|
||||
}
|
||||
|
||||
_ = watcher.Remove(event.Name)
|
||||
err := watcher.Add(event.Name)
|
||||
if err == nil {
|
||||
do = true
|
||||
log.Println("watcher add -> ", event.Name)
|
||||
} else {
|
||||
log.Println(PreWarn, "watcher add faild:", event.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
if do {
|
||||
return
|
||||
}
|
||||
|
||||
// check map
|
||||
if _, ok := cfg.Monitor.DirsMap[event.Name]; ok {
|
||||
_ = watcher.Remove(event.Name)
|
||||
err := watcher.Add(event.Name)
|
||||
if err == nil {
|
||||
log.Println("watcher add -> ", event.Name)
|
||||
} else {
|
||||
log.Println(PreWarn, "watcher add faild:", event.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parseArgs() {
|
||||
switch len(os.Args) {
|
||||
case 1:
|
||||
@ -219,6 +281,7 @@ func show() {
|
||||
func main() {
|
||||
log.SetPrefix("[FileBoy]: ")
|
||||
log.SetFlags(2)
|
||||
log.SetOutput(os.Stdout)
|
||||
show()
|
||||
var err error
|
||||
projectFolder, err = os.Getwd()
|
||||
|
@ -8,11 +8,14 @@ type FileGirl struct {
|
||||
Types []string `yaml:"types"`
|
||||
IncludeDirs []string `yaml:"includeDirs"`
|
||||
ExceptDirs []string `yaml:"exceptDirs"`
|
||||
Events []string `yaml:"events"`
|
||||
// convert to
|
||||
TypesMap map[string]bool `yaml:"-"`
|
||||
IncludeDirsMap map[string]bool `yaml:"-"`
|
||||
ExceptDirsMap map[string]bool `yaml:"-"`
|
||||
DirsMap map[string]bool `yaml:"-"`
|
||||
|
||||
IncludeDirsRec map[string]bool `yaml:"-"`
|
||||
}
|
||||
Command struct {
|
||||
Exec []string `yaml:"exec"`
|
||||
|
@ -14,6 +14,7 @@ type postParams struct {
|
||||
File string `json:"file"`
|
||||
Changed int64 `json:"changed"`
|
||||
Ext string `json:"ext"`
|
||||
Event string `json:"event"`
|
||||
}
|
||||
|
||||
type NetNotifier struct {
|
||||
@ -42,6 +43,7 @@ func (n *NetNotifier) Put(cf *changedFile) {
|
||||
File: cf.Name,
|
||||
Changed: cf.Changed,
|
||||
Ext: cf.Ext,
|
||||
Event: cf.Event,
|
||||
})
|
||||
}
|
||||
|
||||
|
14
raw.go
14
raw.go
@ -32,6 +32,20 @@ monitor:
|
||||
types:
|
||||
- .go
|
||||
|
||||
# 监听的事件类型,发生此类事件才执行 command 中的命令
|
||||
# 没有该配置默认监听所有事件
|
||||
# write 写入文件事件
|
||||
# rename 重命名文件事件
|
||||
# remove 移除文件事件
|
||||
# create 创建文件事件
|
||||
# chmod 更新文件权限事件(类unix)
|
||||
events:
|
||||
- write
|
||||
- rename
|
||||
- remove
|
||||
- create
|
||||
- chmod
|
||||
|
||||
# 命令
|
||||
command:
|
||||
# 监听的文件有更改会执行的命令
|
||||
|
22
util.go
22
util.go
@ -25,12 +25,15 @@ func cmdParse2Array(s string, cf *changedFile) []string {
|
||||
}
|
||||
|
||||
func strParseRealStr(s string, cf *changedFile) string {
|
||||
return strings.Replace(
|
||||
strings.Replace(
|
||||
strings.Replace(s, "{{file}}", cf.Name, -1),
|
||||
"{{ext}}", cf.Ext, -1,
|
||||
return strings.ReplaceAll(
|
||||
strings.ReplaceAll(
|
||||
strings.ReplaceAll(
|
||||
strings.ReplaceAll(s, "{{file}}", cf.Name),
|
||||
"{{ext}}", cf.Ext,
|
||||
),
|
||||
"{{changed}}", strconv.FormatInt(cf.Changed, 10),
|
||||
),
|
||||
"{{changed}}", strconv.FormatInt(cf.Changed, 10), -1,
|
||||
"{{event}}", cf.Event,
|
||||
)
|
||||
}
|
||||
|
||||
@ -64,6 +67,15 @@ func relativePath(folder, p string) string {
|
||||
return s
|
||||
}
|
||||
|
||||
func inStrArray(s string, arr []string) bool {
|
||||
for _, v := range arr {
|
||||
if s == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func logAndExit(v ...interface{}) {
|
||||
log.Println(v...)
|
||||
os.Exit(0)
|
||||
|
Loading…
Reference in New Issue
Block a user