增加 1.0版本

This commit is contained in:
dengsgo 2018-09-10 16:23:27 +08:00
commit c03372f76e
8 changed files with 423 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.idea/*
fileboy
fileboy.exe
filegirl.yaml

8
build-darwin.bat Normal file
View File

@ -0,0 +1,8 @@
@echo off
echo build start...
SET CGO_ENABLED=0
SET GOOS=darwin
SET GOARCH=amd64
go build -ldflags "-s -w"
echo build success
pause

8
build-linux.bat Normal file
View File

@ -0,0 +1,8 @@
@echo off
echo build start...
SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=amd64
go build -ldflags "-s -w"
echo build success
pause

8
build-windows.bat Normal file
View File

@ -0,0 +1,8 @@
@echo off
echo build start...
SET CGO_ENABLED=0
SET GOOS=windows
SET GOARCH=amd64
go build -ldflags "-s -w"
echo build success
pause

240
fileboy.go Normal file
View File

@ -0,0 +1,240 @@
package main
import (
"bufio"
"fmt"
"gopkg.in/fsnotify/fsnotify.v1"
"gopkg.in/yaml.v2"
"io"
"io/ioutil"
"log"
"math/rand"
"os"
"os/exec"
"path"
"sync"
"time"
)
const (
Version = 1
)
var (
projectFolder string = "."
cfg *FileGirl
watcher *fsnotify.Watcher
cmd *exec.Cmd
runLock sync.Mutex
)
type wDirState struct {
Name string
Recursive bool
}
func parseConfig() {
cfg = new(FileGirl)
fc, err := ioutil.ReadFile(projectFolder + "/filegirl.yaml")
if err != nil {
log.Panicln("read filegirl.yaml file err: ", err)
}
err = yaml.Unmarshal(fc, cfg)
if err != nil {
log.Panicln("parsed filegirl.yaml failed: ", err)
}
if cfg.Core.Version > Version {
log.Panicln("current fileboy support max version : ", Version)
}
log.Println(cfg)
}
func eventDispatcher(event fsnotify.Event) {
ext := path.Ext(event.Name)
if len(cfg.Monitor.Types) > 0 &&
cfg.Monitor.Types[0] != ".*" &&
!inStringArray(ext, cfg.Monitor.Types) {
//log.Println(ext, cfg.Monitor.Types, inStringArray(ext, cfg.Monitor.Types))
return
}
switch event.Op {
case fsnotify.Create:
case fsnotify.Write:
log.Println("event write : ", event.Name)
if cmd != nil {
err := cmd.Process.Kill()
if err != nil {
log.Println("err: ", err)
}
log.Println("stop old process ")
}
go run()
case fsnotify.Remove:
case fsnotify.Rename:
}
}
func run() {
runLock.Lock()
defer runLock.Unlock()
for i := 0; i < len(cfg.Command.Exec); i++ {
carr := cmdParse2Array(cfg.Command.Exec[i])
cmd = exec.Command(carr[0], carr[1:]...)
//cmd.SysProcAttr = &syscall.SysProcAttr{CreationFlags: syscall.CREATE_UNICODE_ENVIRONMENT}
cmd.Stdin = os.Stdin
//cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
stdout, err := cmd.StdoutPipe()
if err != nil {
log.Println("error=>", err.Error())
return
}
cmd.Start()
reader := bufio.NewReader(stdout)
for {
line, err2 := reader.ReadString('\n')
if err2 != nil || io.EOF == err2 {
break
}
log.Print(line)
}
err = cmd.Wait()
if err != nil {
log.Println("cmd wait err ", err)
break
}
err = cmd.Process.Kill()
if err != nil {
log.Println("cmd cannot kill ", err)
}
}
log.Println("end ")
}
func addWatcher() {
dirs := make([]string, 0)
for i := 0; i < len(cfg.Monitor.IncludeDirs); i++ {
darr := dirParse2Array(cfg.Monitor.IncludeDirs[i])
if len(darr) < 1 || len(darr) > 2 {
log.Fatalln("filegirl section monitor dirs is error. ", cfg.Monitor.IncludeDirs[i])
}
if darr[0] == "." {
if len(darr) == 2 && darr[1] == "*" {
dirs = make([]string, 0)
dirs = append(dirs, ".")
listFile(projectFolder, func(d string) {
dirs = arrayUniqueAdd(dirs, d)
})
} else {
dirs = arrayUniqueAdd(dirs, projectFolder)
}
break
} else {
if len(darr) == 2 && darr[1] == "*" {
listFile(projectFolder+"/"+darr[0], func(d string) {
dirs = arrayUniqueAdd(dirs, d)
})
} else {
dirs = arrayUniqueAdd(dirs, projectFolder+"/"+darr[0])
}
}
}
for i := 0; i < len(cfg.Monitor.ExceptDirs); i++ {
p := projectFolder + "/" + cfg.Monitor.ExceptDirs[i]
dirs = arrayRemoveElement(dirs, p)
listFile(p, func(d string) {
dirs = arrayRemoveElement(dirs, d)
})
}
for _, dir := range dirs {
log.Println("watcher add -> ", dir)
err := watcher.Add(dir)
if err != nil {
log.Fatalln(err)
}
}
log.Println("fileboy is ready.")
}
func initWatcher() {
parseConfig()
var err error
watcher, err = fsnotify.NewWatcher()
if err != nil {
log.Fatalln(err)
}
defer watcher.Close()
done := make(chan bool)
go func() {
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
eventDispatcher(event)
case err, ok := <-watcher.Errors:
if !ok {
return
}
log.Println("error:", err)
}
}
}()
addWatcher()
<-done
}
func parseArgs() {
l := len(os.Args)
if l == 1 {
initWatcher()
return
}
if l == 2 {
c := os.Args[1]
switch c {
case "init":
err := ioutil.WriteFile(projectFolder+"/filegirl.yaml", []byte(exampleFileGirl), 0644)
if err != nil {
log.Println("error create filegirl.yaml config! ", err)
return
}
log.Println("create filegirl.yaml ok")
return
case "exec":
parseConfig()
run()
return
default:
fmt.Print(helpStr)
}
return
}
}
func show() {
fmt.Print(logo)
rand.Seed(time.Now().UnixNano())
fmt.Println(englishSay[rand.Intn(len(englishSay))], "\r\n")
fmt.Println("Version: ", Version, " Author: deng@yoytang.com")
}
func main() {
log.SetPrefix("[FileBoy]: ")
log.SetFlags(2)
show()
var err error
projectFolder, err = os.Getwd()
if err != nil {
log.Fatalln(err)
}
parseArgs()
}

17
filegirl.go Normal file
View File

@ -0,0 +1,17 @@
package main
type FileGirl struct {
Core struct {
Version int `yaml:"version"`
}
Monitor struct {
Types []string `yaml:"types"`
IncludeDirs []string `yaml:"includeDirs"`
ExceptDirs []string `yaml:"exceptDirs"`
}
Command struct {
//BeforeExec string `yaml:"beforeExec"`
Exec []string `yaml:"exec"`
//AfterExec string `yaml:"afterExec"`
}
}

72
raw.go Normal file
View File

@ -0,0 +1,72 @@
package main
var exampleFileGirl string = `# 主配置
core:
# 配置版本号
version: 1
# 监控配置
monitor:
# 要监听的目录
# test1 监听当前目录下 test1 目录
# test1/test2 监听当前目录下 test1/test2 目录
# test1,* 监听当前目录下 test1 目录及其所有子目录递归
# .,* 监听当前目录及其所有子目录递归
includeDirs:
- .,*
# 不监听的目录
# .idea 忽略.idea目录及其所有子目录的监听
exceptDirs:
- .idea
- .git
- .vscode
# 监听文件的格式此类文件更改会执行 commend 中的命令
# .go 后缀为 .go 的文件更改会执行 commend 中的命令
# .* 所有的文件更改都会执行 commend 中的命令
types:
- .go
# 命令
command:
# 监听的文件有更改会执行的命令
# 可以有多条命令会依次执行
# 如有多条命令每条命令都会等待上一条命令执行完毕后才会执行
# 如遇交互式命令允许外部获取输入
exec:
- go version
- go env
`
var helpStr = `fileboy [option]
Usage of fileboy:
无参数
读取当前目录下的 filegirl.yaml 配置开始监听并工作
init
初始化 fileboy, 在当前目录生成 filegirl.yaml 配置文件
exec
尝试运行定义的 commend 命令
`
var englishSay = []string{
` Have you, the darkness is no darkness.`,
` Why do the good girls always love bad boys?`,
` If love is not madness.`,
` This world is so lonely without you.`,
` You lie. Silence in front of me.`,
` I need him like I need the air to breathe.`,
` Happiness is when the desolated soul meets love.`,
` What I can lose, but do not want to lose you.`,
` The same words, both miss, is also missed.`,
` Each bathed in the love of the people is a poet.`,
}
var logo = `
_______ _____ _ _______ ______ _____ _ _
(_______|_____) | (_______|____ \ / ___ \| | | |
_____ _ | | _____ ____) ) | | | |___| |
| ___) | | | | | ___) | __ (| | | |\_____/
| | _| |_| |_____| |_____| |__) ) |___| | ___
|_| (_____)_______)_______)______/ \_____/ (___)
`

66
util.go Normal file
View File

@ -0,0 +1,66 @@
package main
import (
"io/ioutil"
"strings"
)
func inStringArray(value string, arr []string) bool {
for _, v := range arr {
if value == v {
return true
}
}
return false
}
func cmdParse2Array(s string) []string {
a := strings.Split(s, " ")
r := make([]string, 0)
for i := 0; i < len(a); i++ {
if ss := strings.Trim(a[i], " "); ss != "" {
r = append(r, ss)
}
}
return r
}
func dirParse2Array(s string) []string {
a := strings.Split(s, ",")
r := make([]string, 0)
for i := 0; i < len(a); i++ {
if ss := strings.Trim(a[i], " "); ss != "" {
r = append(r, ss)
}
}
return r
}
func listFile(folder string, fun func(string)) {
files, _ := ioutil.ReadDir(folder)
for _, file := range files {
if file.IsDir() {
d := folder + "/" + file.Name()
fun(d)
listFile(d, fun)
}
}
}
func arrayUniqueAdd(a []string, add string) []string {
if inStringArray(add, a) {
return a
}
return append(a, add)
}
func arrayRemoveElement(a []string, r string) []string {
i := 0
for k, v := range a {
if v == r {
i = k
break
}
}
return append(a[:i], a[i+1:]...)
}