Browse Source
Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin into gva_workflow
Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin into gva_workflow
Conflicts: server/cmd/datas/init.gomain
pixel
4 years ago
22 changed files with 532 additions and 123 deletions
-
50server/api/v1/sys_auto_code.go
-
5server/cmd/datas/AuthorityMenu.go
-
10server/cmd/datas/apis.go
-
10server/cmd/datas/authorities.go
-
10server/cmd/datas/authority_Ids.go
-
10server/cmd/datas/authority_menus.go
-
10server/cmd/datas/casbins.go
-
10server/cmd/datas/customers.go
-
10server/cmd/datas/dictionaries.go
-
10server/cmd/datas/dictionary_details.go
-
11server/cmd/datas/files.go
-
32server/cmd/datas/init.go
-
10server/cmd/datas/menus.go
-
10server/cmd/datas/users.go
-
53server/cmd/gva/run.go
-
2server/config.yaml
-
2server/go.mod
-
22server/service/sys_api.go
-
65server/service/sys_auto_code.go
-
164server/utils/cmd_Task.go
-
138server/utils/cmd_monitor.go
-
11web/src/style/main.scss
@ -0,0 +1,53 @@ |
|||
/* |
|||
Copyright © 2020 NAME HERE <EMAIL ADDRESS> |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
*/ |
|||
package gva |
|||
|
|||
import ( |
|||
"gin-vue-admin/utils" |
|||
"github.com/spf13/cobra" |
|||
"os" |
|||
) |
|||
|
|||
// runCmd represents the run command
|
|||
var runCmd = &cobra.Command{ |
|||
Use: "run", |
|||
Short: "running go codes with hot-compiled-like feature", |
|||
Long: ` |
|||
The "run" command is used for running go codes with hot-compiled-like feature, |
|||
which compiles and runs the go codes asynchronously when codes change. |
|||
`, |
|||
Run: func(cmd *cobra.Command, args []string) { |
|||
w := utils.NewWatch() |
|||
t := utils.NewT() |
|||
path, _ := os.Getwd() |
|||
go w.Watch(path, t) |
|||
t.RunTask() |
|||
}, |
|||
} |
|||
|
|||
func init() { |
|||
rootCmd.AddCommand(runCmd) |
|||
|
|||
// Here you will define your flags and configuration settings.
|
|||
|
|||
// Cobra supports Persistent Flags which will work for this command
|
|||
// and all subcommands, e.g.:
|
|||
// runCmd.PersistentFlags().String("foo", "", "A help for foo")
|
|||
|
|||
// Cobra supports local flags which will only run when this command
|
|||
// is called directly, e.g.:
|
|||
// runCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
|||
} |
@ -0,0 +1,164 @@ |
|||
package utils |
|||
|
|||
import ( |
|||
"bytes" |
|||
"fmt" |
|||
"io" |
|||
"os" |
|||
"os/exec" |
|||
"path/filepath" |
|||
"runtime" |
|||
"sync" |
|||
) |
|||
|
|||
type RunTask interface { |
|||
AddTask() |
|||
RunTask() |
|||
} |
|||
|
|||
// T: Task任务
|
|||
type T struct { |
|||
sync.Mutex |
|||
|
|||
// ch: 获取事件channel
|
|||
ch chan struct{} |
|||
|
|||
closeChan chan struct{} |
|||
|
|||
// 记录process对象
|
|||
p *os.Process |
|||
|
|||
// f: 执行任务
|
|||
f func(chan struct{}) error |
|||
} |
|||
|
|||
// NewT: 实例化方法
|
|||
func NewT() *T { |
|||
return newT(nil) |
|||
} |
|||
func newT(f func(chan struct{}) error) *T { |
|||
t := &T{ |
|||
Mutex: sync.Mutex{}, |
|||
ch: make(chan struct{}, 1), |
|||
closeChan: make(chan struct{}), |
|||
f: f, |
|||
} |
|||
if f == nil { |
|||
t.f = t.DefaultF |
|||
} |
|||
return t |
|||
} |
|||
|
|||
func (t *T) AddTask() { |
|||
if len(t.ch) == 1 { |
|||
return |
|||
} |
|||
t.Lock() |
|||
defer t.Unlock() |
|||
if len(t.ch) == 1 { |
|||
// 代表已经有任务了
|
|||
// 直接丢弃这次任务
|
|||
return |
|||
} |
|||
fmt.Println("::::发送任务->>>>>>>>") |
|||
t.ch <- struct{}{} |
|||
} |
|||
|
|||
func (t *T) RunTask() { |
|||
fmt.Println("进入") |
|||
// 这里做的make 是用于关闭上一个执行的任务
|
|||
ch := make(chan struct{}) |
|||
// 先run服务
|
|||
go t.f(ch) |
|||
for { |
|||
_, ok := <-t.ch |
|||
ch <- struct{}{} |
|||
if !ok { |
|||
return |
|||
} |
|||
// 等待上一个关闭
|
|||
<-t.closeChan |
|||
go t.f(ch) |
|||
} |
|||
|
|||
} |
|||
|
|||
// DefaultF: 默认的StartFunction
|
|||
func (t *T) DefaultF(ch chan struct{}) error { |
|||
|
|||
var buildCmd *exec.Cmd |
|||
var cmd *exec.Cmd |
|||
|
|||
// 判断是否有makefile
|
|||
_, err := os.Stat(filepath.Join("Makefile")) |
|||
if runtime.GOOS != "windows" && err == nil { |
|||
_, err := exec.LookPath("make") |
|||
if err == nil { |
|||
cmd = exec.Command("make", "run") |
|||
goto makefile |
|||
} |
|||
} |
|||
// 检测系统是否有编译环境
|
|||
_, err = exec.LookPath("go") |
|||
if err != nil { |
|||
return err |
|||
} |
|||
// build
|
|||
|
|||
switch runtime.GOOS { |
|||
case "windows": |
|||
buildCmd = exec.Command("go", "build", "-o", "gva.exe", "main.go") |
|||
default: |
|||
buildCmd = exec.Command("go", "build", "-o", "gva", "main.go") |
|||
} |
|||
err = buildCmd.Run() |
|||
if err != nil { |
|||
return err |
|||
} |
|||
fmt.Println("build 执行完成") |
|||
|
|||
// 执行
|
|||
|
|||
switch runtime.GOOS { |
|||
case "windows": |
|||
cmd = exec.Command("gva.exe") |
|||
default: |
|||
cmd = exec.Command("./gva") |
|||
} |
|||
makefile: |
|||
// 开始执行任务
|
|||
t.echo(cmd) |
|||
<-ch |
|||
// 回收资源
|
|||
err = cmd.Process.Kill() |
|||
fmt.Println("kill err", err) |
|||
// 发送关闭完成信号
|
|||
t.closeChan <- struct{}{} |
|||
return err |
|||
} |
|||
|
|||
// echo: 封装回显
|
|||
func (t *T) echo(cmd *exec.Cmd) error { |
|||
var stdoutBuf bytes.Buffer |
|||
stdoutIn, _ := cmd.StdoutPipe() |
|||
var errStdout, errStderr error |
|||
stdout := io.MultiWriter(os.Stdout, &stdoutBuf) |
|||
err := cmd.Start() |
|||
if err != nil { |
|||
return err |
|||
} |
|||
go func() { |
|||
_, errStdout = io.Copy(stdout, stdoutIn) |
|||
}() |
|||
t.p = cmd.Process |
|||
fmt.Println("pid", t.p.Pid) |
|||
go func() { |
|||
_ = cmd.Wait() |
|||
if errStdout != nil || errStderr != nil { |
|||
fmt.Printf("failed to capture stdout or stderr\n") |
|||
} |
|||
outStr := string(stdoutBuf.Bytes()) |
|||
fmt.Printf("\nout:\n%s\n", outStr) |
|||
}() |
|||
return nil |
|||
} |
@ -0,0 +1,138 @@ |
|||
package utils |
|||
|
|||
import ( |
|||
"errors" |
|||
"fmt" |
|||
"github.com/fsnotify/fsnotify" |
|||
"io/ioutil" |
|||
"os" |
|||
"path/filepath" |
|||
) |
|||
|
|||
// Watch: 监控对象
|
|||
type Watch struct { |
|||
*fsnotify.Watcher |
|||
} |
|||
|
|||
func NewWatch() *Watch { |
|||
obj, _ := fsnotify.NewWatcher() |
|||
return &Watch{obj} |
|||
} |
|||
|
|||
// Watch: 监控对象
|
|||
func (w *Watch) Watch(path string, t *T) error { |
|||
// 先转化为绝对路径
|
|||
path, err := filepath.Abs(path) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
// 判断是单个文件还是目录文件
|
|||
fileInfo, err := os.Stat(path) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
// 判断是否是目录 添加监控
|
|||
if fileInfo.IsDir() { |
|||
// dir
|
|||
err = w.watchDir(path) |
|||
|
|||
} else { |
|||
err = w.watchFile(path) |
|||
|
|||
} |
|||
if err != nil { |
|||
return err |
|||
} |
|||
c := make(chan error) |
|||
// 启动监控
|
|||
go func() { |
|||
for { |
|||
select { |
|||
case even, ok := <-w.Events: |
|||
if !ok { |
|||
// close
|
|||
fmt.Println("Errors close") |
|||
c <- errors.New("errors close") |
|||
return |
|||
} |
|||
// 判断事件
|
|||
switch { |
|||
case even.Op&fsnotify.Create == fsnotify.Create: |
|||
//这里获取新创建文件的信息,如果是目录,则加入监控中
|
|||
fmt.Println("创建文件 : ", even.Name) |
|||
//t.AddTask()
|
|||
_ = w.Add(even.Name) |
|||
case even.Op&fsnotify.Write == fsnotify.Write: |
|||
fmt.Println("修改文件 : ", even.Name) |
|||
w.addTask(t, even.Name) |
|||
case even.Op&fsnotify.Remove == fsnotify.Remove || even.Op&fsnotify.Rename == fsnotify.Rename: |
|||
fmt.Println("删除或重命名文件 : ", even.Name) |
|||
_ = w.Remove(even.Name) |
|||
w.addTask(t, even.Name) |
|||
} |
|||
case err = <-w.Errors: |
|||
fmt.Println("even Error:", err) |
|||
c <- err |
|||
return |
|||
} |
|||
} |
|||
}() |
|||
return <-c |
|||
|
|||
} |
|||
|
|||
// watchDir: 处理监控目录
|
|||
func (w *Watch) watchDir(path string) error { |
|||
// 先将自己添加到监控
|
|||
err := w.Add(path) |
|||
|
|||
if err != nil { |
|||
return err |
|||
} |
|||
fileSlice, err := ioutil.ReadDir(path) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
for _, f := range fileSlice { |
|||
fPath := filepath.Join(path, f.Name()) |
|||
if !f.IsDir() { |
|||
// 判断是否可监控的文件
|
|||
if chickPower(fPath) { |
|||
err = w.watchFile(fPath) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
} |
|||
} else { |
|||
err := w.watchDir(fPath) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
} |
|||
} |
|||
return err |
|||
} |
|||
|
|||
// watchDir: 处理监控单文件
|
|||
func (w *Watch) watchFile(path string) error { |
|||
var err error |
|||
if chickPower(path) { |
|||
err = w.Add(path) |
|||
} |
|||
return err |
|||
} |
|||
|
|||
// chickPower: 判断是否在可控范围内
|
|||
func chickPower(name string) bool { |
|||
name = filepath.Ext(name) |
|||
fmt.Println(name) |
|||
return name == ".go" || name == ".yaml" |
|||
} |
|||
|
|||
// addTask: 偏函数 简化发送任务
|
|||
func (w *Watch) addTask(t *T, name string) { |
|||
if chickPower(name) { |
|||
fmt.Println("Add Task->>>>>>") |
|||
t.AddTask() |
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue