33 Commits

Author SHA1 Message Date
dengsgo
585f6e4389 增加 Copyright 2020-12-03 21:21:35 +08:00
dengsgo
600275f4a4 增加 changelog 2020-12-03 21:14:36 +08:00
dengsgo
a31bf71c1c 修改 进程退出清理日志 2020-12-03 21:11:00 +08:00
dengsgo
da54305188 增加 1.16 2020-10-17 10:29:33 +08:00
dengsgo
9e651d3023 优化 代码 2020-10-17 10:24:37 +08:00
dengsgo
605914d1e1 增加 1.16 2020-08-23 16:22:08 +08:00
dengsgo
86cf40564b 优化 文件扫描性能 2020-08-23 16:17:18 +08:00
dengsgo
819297118c 更新 changelog 2020-07-19 18:10:34 +08:00
dengsgo
a76d4cfe6c 增加 对信号的处理 2020-07-19 18:06:24 +08:00
dengsgo
14ba79c2b3 更新 README 2020-06-27 15:15:29 +08:00
dengsgo
c5f0649ab5 增加 pid文件进程感知 2020-06-27 15:11:55 +08:00
dengsgo
7c6f8f910b 增加 snap config 2020-04-22 15:40:09 +08:00
dengsgo
d07616bde9 rename 2020-03-16 11:19:13 +08:00
dengsgo
4f81692954 typo deamon->daemon 2020-03-16 11:16:14 +08:00
Deng.Liu
588af5143f Update README.md 2020-03-15 21:10:11 +08:00
Deng.Liu
2d8924b7fe Update go.yml 2020-03-15 21:02:32 +08:00
Deng.Liu
08fb7aabf8 Update go.yml 2020-03-15 20:56:56 +08:00
Deng.Liu
9f0a51ce0e Update go.yml 2020-03-15 20:55:31 +08:00
Deng.Liu
8a3a2d570b Update go.yml 2020-03-15 20:53:42 +08:00
Deng.Liu
e5405f4fa9 Update go.yml 2020-03-15 20:46:58 +08:00
Deng.Liu
9d9cce0f31 Create go.yml 2020-03-15 20:43:56 +08:00
dengsgo
c0364a62bc 发行 v1.15 2020-03-08 13:26:38 +08:00
dengsgo
a9758653ba 修改 changelog 2020-03-08 13:24:49 +08:00
dengsgo
b1c5f7da39 修改 readme mod 2020-03-05 15:37:36 +08:00
dengsgo
29fc62de90 更改 mod管理依赖 2020-03-05 15:31:47 +08:00
dengsgo
2d409fbce0 修改 log 2020-03-04 13:41:02 +08:00
dengsgo
550dc01dfb 修改 readme 2020-03-04 11:18:21 +08:00
dengsgo
d0492bad8c 更新 readme 2020-03-03 15:01:08 +08:00
dengsgo
55625d51bc 增加 支持 2020-03-03 14:57:35 +08:00
dengsgo
8ddc124f89 增加 支持 2020-03-03 14:54:12 +08:00
dengsgo
8b7042411c 修改 rekeased 2020-03-03 11:39:15 +08:00
dengsgo
b72caedcbb 重构 指令 2020-03-03 11:37:20 +08:00
dengsgo
f989590d14 修改 文案 2020-03-03 11:12:08 +08:00
18 changed files with 307 additions and 145 deletions

45
.github/workflows/go.yml vendored Normal file
View File

@@ -0,0 +1,45 @@
name: Go
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.13
uses: actions/setup-go@v1
with:
go-version: 1.13
id: go
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Get dependencies
run: |
export GO111MODULE=on
go env -w GOPROXY=https://goproxy.io,direct
go get
- name: Build
run: go build
- name: Use
run: |
export PATH=/home/runner/work/fileboy/fileboy:$PATH
fileboy version
fileboy help
fileboy init
cat filegirl.yaml
fileboy exec
fileboy daemon
ls -al .fileboy.pid
ps aux | grep fileboy
fileboy stop

View File

@@ -20,7 +20,7 @@ script:
- fileboy init
- cat filegirl.yaml
- fileboy exec
- fileboy deamon
- fileboy daemon
- ls -al .fileboy.pid
- ps aux | grep fileboy
- fileboy stop

View File

@@ -1,5 +1,32 @@
### Release v1.16
2020.12.03
- 修改 进程退出清理日志级别
- 增加 MIT Copyright
2020.08.23
- 优化 文件扫描性能
2020.07.19
- 增加 pid 文件处理
- 增加 信息处理
2020.03.16
- typo deamon->daemon
### Release v1.15
2020.03.08
- 优化 指令模式
- 使用 mod 管理依赖
- go version >= 1.13
- 优化 一些细节
2020.01.02
- 增加 指令配置项 `instruction`, 可以通过预定义的指令来控制 command 的行为

View File

@@ -10,8 +10,7 @@
# make build-start-mac 编译+启动
init:
go get -u gopkg.in/yaml.v2
go get -u gopkg.in/fsnotify/fsnotify.v1
go get -u
build-mac: ;@echo "编译-mac版";
CGO_ENABLED=0 GOARCH=amd64 GOOS=darwin go build -ldflags "-s -w" -o ./bin/fileboy-darwin-amd64.bin

View File

@@ -1,10 +1,10 @@
## 项目说明
[![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)
![Go](https://github.com/dengsgo/fileboy/workflows/Go/badge.svg?branch=master) [![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)
[简体中文](README.md) | [ENGLISH](README_EN.md)
fileboy文件变更监听通知系统,使用 Go 编写。
fileboy文件变更监听通知工具,使用 Go 编写。
适用于 Hot Reload 典型的如开发go项目无需每次手动执行 go build又比如前端 node 打包) 或者 系统监控的场景。
## 特性
@@ -17,11 +17,12 @@ fileboy文件变更监听通知系统使用 Go 编写。
- 命令支持变量占位符
- 支持冗余任务丢弃,自定义冗余任务范围
- 支持 http 通知
- 高级指令用法
- 更多...
## 编译环境
go version 1.13
Go >= 1.13
## 更新日志
@@ -39,10 +40,12 @@ Gitee: [dowmload v1.15](https://gitee.com/dengsgo/fileboy/releases)
### 源码编译
clone 该项目,进入主目录,运行命令:
```shell
```bash
## 确保本地 Go 启用 modules
export GO111MODULE=on
go env -w GOPROXY=https://goproxy.io,direct
## 安装依赖
go get -u gopkg.in/fsnotify/fsnotify.v1
go get -u gopkg.in/yaml.v2
go get -u
## 编译
go build
## 运行
@@ -130,19 +133,6 @@ command:
# 如果不需要该特性,设置为 0
delayMillSecond: 2000
# 特殊指令
# 可以通过预定义的指令来控制 command 的行为,指令可以有多个
# exec-when-start fileboy启动就绪后自动执行一次 'exec' 定义的命令
# should-finish 触发执行 'exec' 时(C),如果上一次的命令(L)未退出(还在执行),会等待 L 退出,直到有明确 exit code 才会开始执行本次命令。
# 在等待 L 退出时,又有新事件触发了命令执行(N),则 C 执行取消,只会保留最后一次的 N 执行
# ignore-stdout 执行 'exec' 产生的 stdout 会被丢弃
# ignore-warn fileboy 自身的 warn 信息会被丢弃
# ignore-info fileboy 自身的 info 信息会被丢弃
# ignore-exec-error 执行 'exec' 出错仍继续执行下面的命令而不退出
instruction:
#- should-finish
#- exec-when-start
# 通知器
notifier:
# 文件更改会向该 url 发送请求POST 一段 json 文本数据)
@@ -150,45 +140,49 @@ notifier:
# 请求超时 15 秒
# POST 格式:
# Content-Type: application/json;charset=UTF-8
# User-Agent: FileBoy Net Notifier v1.15
# User-Agent: FileBoy Net Notifier v1.16
# Body: {"project_folder":"/project/path","file":"main.go","changed":1576567861913824940,"ext":".go","event":"write"}
# 例: http://example.com/notifier/fileboy-listener
# 不启用通知,请留空 ""
callUrl: ""
# 特殊指令
instruction:
# 可以通过特殊的指令选项来控制 command 的行为,指令可以有多个
# 指令选项解释:
# exec-when-start fileboy启动就绪后自动执行一次 'exec' 定义的命令
# should-finish 触发执行 'exec' 时(C),如果上一次的命令(L)未退出(还在执行),会等待 L 退出(而不是强制 kill ),直到 L 有明确 exit code 才会开始执行本次命令。
# 在等待 L 退出时,又有新事件触发了命令执行(N),则 C 执行取消,只会保留最后一次的 N 执行
# ignore-stdout 执行 'exec' 产生的 stdout 会被丢弃
# ignore-warn fileboy 自身的 warn 信息会被丢弃
# ignore-info fileboy 自身的 info 信息会被丢弃
# ignore-exec-error 执行 'exec' 出错仍继续执行下面的命令而不退出
#- should-finish
#- exec-when-start
- ignore-warn
```
### TODO
- [x] 命令支持变量占位符
- [x] 支持多命令
- [x] 支持监听指定文件夹
- [x] 支持不监听指定文件夹
- [x] 支持监听指定后缀文件
- [x] 支持自定事件监听
- [x] 支持 http 通知
- [x] 支持冗余任务丢弃
- [ ] 支持 http 合并任务的通知
## QA
#### 很多框架都自带了 hot reload 的功能,为什么还要单独写个 fileboy 呢?
### 很多框架都自带了 hot reload 的功能,为什么还要单独写个 fileboy 呢?
这个是一款通用的 hot reload 的软件,理论上适用于任何需要 hot reload 的场景,并不局限于语言层面上。只要灵活的配置 `filegirl.yaml`文件就行了。
#### fileboy 可以应用在那些具体的场景?
### fileboy 可以应用在那些具体的场景?
在开发中,我们很需要一款可以帮助我们自动打包编译的工具,那 fileboy 就非常适合这样的场景。比如 go 项目的热编译,让我们可以边修改代码边运行得到反馈。又比如 PHP Swoole 框架由于常驻进程的原因无法更改代码立即reload使用 fileboy 就可以辅助做到传统 PHP 开发的体验。
对于一些需要监控文件日志或者配置变动的场景, fileboy 同样适合。你可以事先编写好相应的通知报警脚本,然后定义`filegirl.yaml`中的`command`命令,交由 fileboy 自动运行监控报警。
#### 通知器在什么时候会发送 http 请求 ?
### 通知器在什么时候会发送 http 请求 ?
通知器发送 http 通知的前提是在配置文件中设置了 `callUrl` 参数(不为空即为已设置)。触发请求的时机和执行 command 命令是一致的,`command -> delayMillSecond` 参数对于触发器同样有效。请求超时默认15秒.
#### idea 下更改文件,为什么会执行两次或者多次 command ?
### idea 下更改文件,为什么会执行两次或者多次 command ?
由于 idea 系列软件特殊的文件保存策略他会自动创建一些临时文件并且在需要时多次重写文件所以有时反映在文件上就是有多次的更改所以会出现这种情况。1.5之后的版本增加了 `delayMillSecond` 参数,可以解决这个问题。
#### filegirl.yaml 里面的 command 如何配置复杂命令?
### filegirl.yaml 里面的 command 如何配置复杂命令?
fileboy 目前支持 `命令 + 参数`这种形式的 command而且 参数中不能有""符号或者有空格。如:
`go build`:支持;
@@ -197,19 +191,21 @@ fileboy 目前支持 `命令 + 参数`这种形式的 command而且 参数中
`cat a.txt | grep "q" | wc -l`:不支持
对于不支持的命令,可以把它写到一个文件里,然后在 command 中执行这个文件来解决。
#### 为什么起名为 fileboy又把配置名叫做 filegirl
### 为什么起名为 fileboy又把配置名叫做 filegirl
因为爱情~~ (◡ᴗ◡✿)
### 贡献者
## 贡献者
> 排名不分先后
| | | |
| ------------ | ------------ | ------------ |
| <a href="https://github.com/dengsgo"><img src="https://avatars1.githubusercontent.com/u/7929002?s=460&v=4" width=64 style="border-radius:45px;" /></a> | <a href="https://github.com/jason-gao"><img src="https://avatars1.githubusercontent.com/u/9896574?s=460&v=4" width=64 style="border-radius:45px;" /></a> | <a href="https://github.com/itwesley"><img src="https://avatars1.githubusercontent.com/u/1928721?s=460&v=4" width=64 style="border-radius:45px;" /></a> |
[@dengsgo](https://www.yoytang.com) <dengsgo@gmail.com>
## 感谢支持
[@itwesley](https://github.com/itwesley) <wcshen1126@gmail.com>
[@jason-gao](https://github.com/jason-gao) <3048789891@qq.com>
| |
| ------------ |
| <a href="https://www.jetbrains.com/?from=fileboy"><img src="./resources/jetbrains.png" width=140 /></a> |

View File

@@ -4,7 +4,7 @@
[简体中文](README.md) | [ENGLISH](README_EN.md)
Fileboy, File Change Monitoring Notification System, written with Go.
Fileboy, File Change Monitoring Notification Tool Software, written with Go.
For Hot Reload scenarios (typically for developing go projects without having to perform go build manually every time; for example, front-end node packaging) or system monitoring.
## FEATURES
@@ -17,11 +17,12 @@ For Hot Reload scenarios (typically for developing go projects without having to
- Command support variable placeholders
- Supporting redundant task discarding and customizing redundant task scope
- Supporting HTTP notifications
- Advanced instruction usage
- more...
## COMPILE
go version 1.13
Go >= 1.13
## CHANGELOG
@@ -41,9 +42,9 @@ Download the compiled binary file of the corresponding platform, rename it `file
Clone project, enter the project directory, run the command:
```shell
export GO111MODULE=on
## installation dependency
go get-u gopkg.in/fsnotify/fsnotify.v1
go get-u gopkg.in/yaml.v2
go get-u
## compile
go build
## run
@@ -127,37 +128,46 @@ command:
# If this feature is not required, set to 0
delayMillSecond: 2000
# 特殊指令
# 可以通过预定义的指令来控制 command 的行为,指令可以有多个
# exec-when-start fileboy启动就绪后自动执行一次 'exec' 定义的命令
# should-finish 触发执行 'exec' 时(C),如果上一次的命令(L)未退出(还在执行),会等待 L 退出,直到有明确 exit code 才会开始执行本次命令。
# 在等待 L 退出时,又有新事件触发了命令执行(N),则 C 执行取消,只会保留最后一次的 N 执行
# ignore-stdout 执行 'exec' 产生的 stdout 会被丢弃
# ignore-warn fileboy 自身的 warn 信息会被丢弃
# ignore-info fileboy 自身的 info 信息会被丢弃
# ignore-exec-error 执行 'exec' 出错仍继续执行下面的命令而不退出
instruction:
#- should-finish
#- exec-when-start
notifier:
# file changes send requests to the URL (POST JSON text data)
# the timing of triggering the request is consistent with executing the command command
# timeout 15 second
# POST :
# Content-Type: application/json;charset=UTF-8
# User-Agent: FileBoy Net Notifier v1.15
# User-Agent: FileBoy Net Notifier v1.16
# Body: {"project_folder":"/project/path","file":"main.go","changed":1576567861913824940,"ext":".go","event":"write"}
# e.g: http://example.com/notifier/fileboy-listener
# no notice is enabled. Please leave it blank. ""
callUrl: ""
instruction:
# command behavior can be controlled by special command options. there can be multiple instructions
# options:
# exec-when-start when fileboy is ready to start, execute the command defined by 'exec' once automatically
# should-finish when the execution of 'exec' is triggered (C), if the last command (L) does not exit (still executing),
# it will wait for L to exit (instead of forcing kill), and the execution of this command will not start until L has an explicit exit code.
# when waiting for L to exit, and a new event triggers command execution (n), C execution is cancelled, and only the last N execution is retained
# ignore-stdout stdout generated by executing 'exec' will be discarded
# ignore-warn the warn information of fileboy itself will be discarded
# ignore-info the info information of fileboy itself will be discarded
# ignore-exec-error error executing 'exec' continue to execute the following command without exiting
#- should-finish
#- exec-when-start
- ignore-warn
```
### CONTRIBUTOR
## CONTRIBUTOR
[@dengsgo](https://www.yoytang.com) <dengsgo@gmail.com>
| | | |
| ------------ | ------------ | ------------ |
| <a href="https://github.com/dengsgo"><img src="https://avatars1.githubusercontent.com/u/7929002?s=460&v=4" width=64 style="border-radius:45px;" /></a> | <a href="https://github.com/jason-gao"><img src="https://avatars1.githubusercontent.com/u/9896574?s=460&v=4" width=64 style="border-radius:45px;" /></a> | <a href="https://github.com/itwesley"><img src="https://avatars1.githubusercontent.com/u/1928721?s=460&v=4" width=64 style="border-radius:45px;" /></a> |
[@itwesley](https://github.com/itwesley) <wcshen1126@gmail.com>
[@jason-gao](https://github.com/jason-gao) <3048789891@qq.com>
## THANKS
| |
| ------------ |
| <a href="https://www.jetbrains.com/?from=fileboy"><img src="./resources/jetbrains.png" width=140></a> |

View File

@@ -12,11 +12,11 @@ func getPidFile() string {
return projectFolder + "/.fileboy.pid"
}
func runAsDeamon() (int, error) {
func runAsDaemon() (int, error) {
if runtime.GOOS == "windows" {
logAndExit("daemons mode cannot run on windows.")
}
err := stopDeamon()
err := stopDaemon()
if err != nil {
logAndExit(err)
}
@@ -24,22 +24,22 @@ func runAsDeamon() (int, error) {
if err != nil {
logAndExit("cannot found `fileboy` command in the PATH")
}
deamon := exec.Command("fileboy")
deamon.Dir = projectFolder
deamon.Env = os.Environ()
deamon.Stdout = os.Stdout
err = deamon.Start()
daemon := exec.Command("fileboy")
daemon.Dir = projectFolder
daemon.Env = os.Environ()
daemon.Stdout = os.Stdout
err = daemon.Start()
if err != nil {
logAndExit(err)
}
pid := deamon.Process.Pid
pid := daemon.Process.Pid
if pid != 0 {
ioutil.WriteFile(getPidFile(), []byte(strconv.Itoa(pid)), 0644)
}
return pid, nil
}
func stopDeamon() error {
func stopDaemon() error {
bs, err := ioutil.ReadFile(getPidFile())
if err != nil {
return nil
@@ -48,3 +48,9 @@ func stopDeamon() error {
os.Remove(getPidFile())
return nil
}
func stopSelf() {
pid := os.Getpid()
os.Remove(getPidFile())
_ = exec.Command("kill", strconv.Itoa(pid)).Run()
}

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2018-2020 Author dengsgo<dengsgo@yoytang.com> [https://github.com/dengsgo/fileboy]
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
package main
import (
@@ -6,9 +10,11 @@ import (
"log"
"math/rand"
"os"
"os/signal"
"path"
"strconv"
"strings"
"syscall"
"time"
"gopkg.in/fsnotify/fsnotify.v1"
@@ -57,29 +63,29 @@ func parseConfig() {
cfg = new(FileGirl)
fc, err := ioutil.ReadFile(getFileGirlPath())
if err != nil {
logError("The filegirl.yaml file in", projectFolder, "is not exist! ", err)
logError("the filegirl.yaml file in", projectFolder, "is not exist! ", err)
fmt.Print(firstRunHelp)
logAndExit("Fileboy unable to run.")
logAndExit("fileboy unable to run.")
}
err = yaml.Unmarshal(fc, cfg)
if err != nil {
logAndExit("Parsed filegirl.yaml failed: ", err)
logAndExit("parsed filegirl.yaml failed: ", err)
}
if cfg.Core.Version > Version {
logAndExit("Current fileboy support max version : ", Version)
logAndExit("current fileboy support max version : ", Version)
}
// init map
cfg.Monitor.TypesMap = map[string]bool{}
cfg.Monitor.IncludeDirsMap = map[string]bool{}
cfg.Monitor.ExceptDirsMap = map[string]bool{}
cfg.Monitor.IncludeDirsRec = map[string]bool{}
cfg.Command.InstructionMap = map[string]bool{}
cfg.InstructionMap = map[string]bool{}
// convert to map
for _, v := range cfg.Monitor.Types {
cfg.Monitor.TypesMap[v] = true
}
for _, v := range cfg.Command.Instruction {
cfg.Command.InstructionMap[v] = true
for _, v := range cfg.Instruction {
cfg.InstructionMap[v] = true
}
log.Printf("%+v", cfg)
}
@@ -111,6 +117,11 @@ func eventDispatcher(event fsnotify.Event) {
func addWatcher() {
logInfo("collecting directory information...")
dirsMap := map[string]bool{}
for _, dir := range cfg.Monitor.ExceptDirs {
if dir == "." {
logAndExit("exceptDirs must is not project root path ! err path:", dir)
}
}
for _, dir := range cfg.Monitor.IncludeDirs {
darr := dirParse2Array(dir)
if len(darr) < 1 || len(darr) > 2 {
@@ -145,16 +156,7 @@ func addWatcher() {
}
}
for _, dir := range cfg.Monitor.ExceptDirs {
if dir == "." {
logAndExit("exceptDirs must is not project root path ! err path:", dir)
}
p := projectFolder + "/" + dir
delete(dirsMap, p)
listFile(p, func(d string) {
delete(dirsMap, d)
})
}
for dir := range dirsMap {
logInfo("watcher add -> ", dir)
err := watcher.Add(dir)
@@ -200,6 +202,15 @@ func initWatcher() {
}
func watchChangeHandler(event fsnotify.Event) {
// stop the fileboy daemon process when the .fileboy.pid file is changed
if event.Name == getPidFile() &&
(event.Op == fsnotify.Remove ||
event.Op == fsnotify.Write ||
event.Op == fsnotify.Rename) {
logUInfo("exit daemon process")
stopSelf()
return
}
if event.Op != fsnotify.Create && event.Op != fsnotify.Rename {
return
}
@@ -213,13 +224,7 @@ func watchChangeHandler(event fsnotify.Event) {
continue
}
// check exceptDirs
has := false
for _, v := range cfg.Monitor.ExceptDirs {
if strings.HasPrefix(event.Name, projectFolder+"/"+v) {
has = true
}
}
if has {
if hitDirs(event.Name, &cfg.Monitor.ExceptDirs) {
continue
}
@@ -265,8 +270,8 @@ func parseArgs() {
case len(os.Args) > 1:
c := os.Args[1]
switch c {
case "deamon":
pid, err := runAsDeamon()
case "deamon", "daemon":
pid, err := runAsDaemon()
if err != nil {
logAndExit(err)
}
@@ -274,7 +279,7 @@ func parseArgs() {
logUInfo("fileboy is ready. the main process will run as a daemons")
return
case "stop":
err := stopDeamon()
err := stopDaemon()
if err != nil {
logAndExit(err)
}
@@ -283,15 +288,15 @@ func parseArgs() {
case "init":
_, err := ioutil.ReadFile(getFileGirlPath())
if err == nil {
logError("Profile filegirl.yaml already exists.")
logAndExit("If you want to regenerate filegirl.yaml, delete it first")
logError("profile filegirl.yaml already exists.")
logAndExit("delete it first when you want to regenerate filegirl.yaml")
}
err = ioutil.WriteFile(getFileGirlPath(), []byte(exampleFileGirl), 0644)
if err != nil {
logError("Profile filegirl.yaml create failed! ", err)
logError("profile filegirl.yaml create failed! ", err)
return
}
logUInfo("Profile filegirl.yaml created ok")
logUInfo("profile filegirl.yaml created ok")
return
case "exec":
parseConfig()
@@ -302,14 +307,28 @@ func parseArgs() {
case "help", "--help", "--h", "-h":
fmt.Print(helpStr)
default:
logAndExit("Unknown parameter, use 'fileboy help' to view available commands")
logAndExit("unknown parameter, use 'fileboy help' to view available commands")
}
return
default:
logAndExit("Unknown parameters, use `fileboy help` show help info.")
logAndExit("unknown parameters, use `fileboy help` show help info.")
}
}
func signalHandler() {
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
if taskMan != nil && taskMan.cmd != nil && taskMan.cmd.Process != nil {
if err := taskMan.cmd.Process.Kill(); err != nil {
logWarn("stopping the process failed: PID:", taskMan.cmd.ProcessState.Pid(), ":", err)
}
}
os.Exit(0)
}()
}
func getFileGirlPath() string {
return projectFolder + "/" + filegirlYamlName
}
@@ -332,5 +351,6 @@ func main() {
if err != nil {
logAndExit(err)
}
signalHandler()
parseArgs()
}

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2018-2020 Author dengsgo<dengsgo@yoytang.com> [https://github.com/dengsgo/fileboy]
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
package main
type FileGirl struct {
@@ -18,14 +22,14 @@ type FileGirl struct {
IncludeDirsRec map[string]bool `yaml:"-"`
}
Command struct {
Instruction []string `yaml:"instruction"`
Exec []string `yaml:"exec"`
DelayMillSecond int `yaml:"delayMillSecond"`
// convert to
InstructionMap map[string]bool `yaml:"-"`
}
Notifier struct {
CallUrl string `yaml:"callUrl"`
}
Instruction []string `yaml:"instruction"`
// convert to
InstructionMap map[string]bool `yaml:"-"`
}

9
go.mod Normal file
View File

@@ -0,0 +1,9 @@
module fileboy
go 1.13
require (
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211 // indirect
gopkg.in/fsnotify/fsnotify.v1 v1.4.7
gopkg.in/yaml.v2 v2.3.0
)

13
go.sum Normal file
View File

@@ -0,0 +1,13 @@
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200408040146-ea54a3c99b9b h1:h03Ur1RlPrGTjua4koYdpGl8W0eYo8p1uI9w7RPlkdk=
golang.org/x/sys v0.0.0-20200408040146-ea54a3c99b9b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211 h1:9UQO31fZ+0aKQOFldThf7BKPMJTiBfWycGh/u3UoO88=
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 h1:XNNYLJHt73EyYiCZi6+xjupS9CpvmiDgjPTAjrBlQbo=
gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2018-2020 Author dengsgo<dengsgo@yoytang.com> [https://github.com/dengsgo/fileboy]
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
package main
import (
@@ -61,7 +65,7 @@ func (n *NetNotifier) dispatch(params *postParams) {
return
}
req.Header.Set("Content-Type", "application/json;charset=UTF-8")
req.Header.Set("User-Agent", "FileBoy Net Notifier v1.15")
req.Header.Set("User-Agent", "FileBoy Net Notifier v1.16")
resp, err := client.Do(req)
if err != nil {
logError("notifier call failed. err:", err)

39
raw.go
View File

@@ -69,19 +69,6 @@ command:
# 如果不需要该特性,设置为 0
delayMillSecond: 2000
# 特殊指令
# 可以通过预定义的指令来控制 command 的行为,指令可以有多个
# exec-when-start fileboy启动就绪后自动执行一次 'exec' 定义的命令
# should-finish 触发执行 'exec' 时(C),如果上一次的命令(L)未退出(还在执行),会等待 L 退出,直到有明确 exit code 才会开始执行本次命令。
# 在等待 L 退出时,又有新事件触发了命令执行(N),则 C 执行取消,只会保留最后一次的 N 执行
# ignore-stdout 执行 'exec' 产生的 stdout 会被丢弃
# ignore-warn fileboy 自身的 warn 信息会被丢弃
# ignore-info fileboy 自身的 info 信息会被丢弃
# ignore-exec-error 执行 'exec' 出错仍继续执行下面的命令而不退出
instruction:
#- should-finish
#- exec-when-start
# 通知器
notifier:
# 文件更改会向该 url 发送请求POST 一段 json 文本数据)
@@ -89,11 +76,27 @@ notifier:
# 请求超时 15 秒
# POST 格式:
# Content-Type: application/json;charset=UTF-8
# User-Agent: FileBoy Net Notifier v1.15
# User-Agent: FileBoy Net Notifier v1.16
# Body: {"project_folder":"/project/path","file":"main.go","changed":1576567861913824940,"ext":".go","event":"write"}
# 例: http://example.com/notifier/fileboy-listener
# 不启用通知,请留空 ""
callUrl: ""
# 特殊指令
instruction:
# 可以通过特殊的指令选项来控制 command 的行为,指令可以有多个
# 指令选项解释:
# exec-when-start fileboy启动就绪后自动执行一次 'exec' 定义的命令
# should-finish 触发执行 'exec' 时(C),如果上一次的命令(L)未退出(还在执行),会等待 L 退出(而不是强制 kill ),直到 L 有明确 exit code 才会开始执行本次命令。
# 在等待 L 退出时,又有新事件触发了命令执行(N),则 C 执行取消,只会保留最后一次的 N 执行
# ignore-stdout 执行 'exec' 产生的 stdout 会被丢弃
# ignore-warn fileboy 自身的 warn 信息会被丢弃
# ignore-info fileboy 自身的 info 信息会被丢弃
# ignore-exec-error 执行 'exec' 出错仍继续执行下面的命令而不退出
#- should-finish
#- exec-when-start
- ignore-warn
`
var firstRunHelp = `第一次运行 fileboy ?
@@ -109,7 +112,7 @@ Usage of fileboy:
初始化 fileboy, 在当前目录生成 filegirl.yaml 配置文件
exec
尝试运行定义的 command 命令
deamon
daemon
读取当前目录下的 filegirl.yaml 配置,以守护进程的方式运行在后台
stop
停止守护进程
@@ -136,13 +139,13 @@ var logo = `
_____ _ | | _____ ____) ) | | | |___| |
| ___) | | | | | ___) | __ (| | | |\_____/
| | _| |_| |_____| |_____| |__) ) |___| | ___
|_| (_____)_______)_______)______/ \_____/ (___) V1.15
|_| (_____)_______)_______)______/ \_____/ (___) V1.16
`
var statement = `Dengsgo [dengsgo@gmail.com] Open Source with MIT License`
var versionDesc = `
Version fileboy: v1.15 filegirl: v` + strconv.Itoa(Version) + `
Released 2020.01.05
Version fileboy: v1.16 filegirl: v` + strconv.Itoa(Version) + `
Released 2020.10.17
Licence MIT
Author dengsgo [dengsgo@gmail.com]
Website https://github.com/dengsgo/fileboy

BIN
resources/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

BIN
resources/jetbrains.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

8
snapcraft.yaml Normal file
View File

@@ -0,0 +1,8 @@
name: fileboy
vendor: dengsgo, https://github.com/dengsgo, <dengsgo@yoytang.com>
summary: File Change Monitoring Notification Tools.
description: File Change Monitoring Notification Tools. Please Visit https://github.com/dengsgo/fileboy
version: 1.15
icon: resources/icon.png
base: core18
grade: stable

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2018-2020 Author dengsgo<dengsgo@yoytang.com> [https://github.com/dengsgo/fileboy]
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
package main
import (
@@ -30,14 +34,15 @@ func newTaskMan(delay int, callUrl string) *TaskMan {
go func() {
for {
<-t.waitChan
if len(t.waitQueue) > 0 {
cf := t.waitQueue[len(t.waitQueue)-1]
if len(t.waitQueue) > 1 {
logInfo("Number of redundant tasks dropped:", len(t.waitQueue)-1)
}
t.waitQueue = []*changedFile{}
go t.preRun(cf)
if len(t.waitQueue) < 1 {
return
}
cf := t.waitQueue[len(t.waitQueue)-1]
if len(t.waitQueue) > 1 {
logInfo("redundant tasks dropped:", len(t.waitQueue)-1)
}
t.waitQueue = []*changedFile{}
go t.preRun(cf)
}
}()
}
@@ -69,8 +74,8 @@ func (t *TaskMan) dispatcher(cf *changedFile) {
t.waitChan <- true
return
}
logInfo("Waitting for the last task to finish")
logInfo("Number of waiting tasks:", len(t.waitQueue))
logInfo("waitting for the last task to finish")
logInfo("waiting tasks:", len(t.waitQueue))
} else {
t.preRun(cf)
}
@@ -113,7 +118,7 @@ func (t *TaskMan) run(cf *changedFile) {
}
err = t.cmd.Wait()
if err != nil {
logWarn("command exec failed:", carr, err)
logError("command exec failed:", carr, err)
if keyInInstruction(InstIgnoreExecError) {
continue
}

15
util.go
View File

@@ -14,7 +14,7 @@ func keyInMonitorTypesMap(k string, cfg *FileGirl) bool {
}
func keyInInstruction(k string) bool {
_, ok := cfg.Command.InstructionMap[k]
_, ok := cfg.InstructionMap[k]
return ok
}
@@ -53,11 +53,24 @@ func dirParse2Array(s string) []string {
return r
}
func hitDirs(d string, dirs *[]string) bool {
d += "/"
for _, v := range *dirs {
if strings.HasPrefix(d, projectFolder+"/"+v+"/") {
return true
}
}
return false
}
func listFile(folder string, fun func(string)) {
files, _ := ioutil.ReadDir(folder)
for _, file := range files {
if file.IsDir() {
d := folder + "/" + file.Name()
if hitDirs(d, &cfg.Monitor.ExceptDirs) {
continue
}
fun(d)
listFile(d, fun)
}