Browse Source

Hotreload

Hotreload1
songzhibin97 4 years ago
parent
commit
3b0baf4e7e
3 changed files with 248 additions and 0 deletions
  1. 47 0
      server/cmd/gva/run.go
  2. 83 0
      server/utils/cmd_Task.go
  3. 118 0
      server/utils/cmd_monitor.go

+ 47 - 0
server/cmd/gva/run.go

@@ -0,0 +1,47 @@
+/*
+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 (
+	"github.com/spf13/cobra"
+)
+
+// 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) {
+		// todo 未实现
+	},
+}
+
+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")
+}

+ 83 - 0
server/utils/cmd_Task.go

@@ -0,0 +1,83 @@
+package utils
+
+import (
+	"os"
+	"os/exec"
+	"strings"
+	"sync"
+)
+
+type RunTask interface {
+	AddTask()
+	RunTask()
+}
+
+// T: Task任务
+type T struct {
+	sync.Mutex
+
+	// ch: 获取时间channel
+	ch chan struct{}
+
+	// 记录pid 用于kill
+	pid int
+
+	// 执行shell命令
+	exec.Cmd
+}
+
+// NewT: 实例化方法
+func NewT(path string, args []string, environment ...[]string) *T {
+	env := os.Environ()
+	if len(environment) > 0 {
+		for k, v := range environment[0] {
+			env[k] = v
+		}
+	}
+	t := &T{
+		Mutex: sync.Mutex{},
+		ch:    make(chan struct{}),
+		Cmd: exec.Cmd{
+			Path:       path,
+			Args:       []string{path},
+			Env:        env,
+			Stdin:      os.Stdin,
+			Stdout:     os.Stdout,
+			Stderr:     os.Stderr,
+			ExtraFiles: make([]*os.File, 0),
+		},
+		pid: os.Getpid(),
+	}
+	t.Dir, _ = os.Getwd()
+	if len(args) > 0 {
+		// Exclude of current binary path.
+		start := 0
+		if strings.EqualFold(path, args[0]) {
+			start = 1
+		}
+		t.Args = append(t.Args, args[start:]...)
+	}
+	return t
+}
+
+func (t *T) AddTask() {
+	t.Lock()
+	defer t.Unlock()
+	if len(t.ch) == 1 {
+		// 代表已经有任务了
+		// 直接丢弃这次任务
+		return
+	}
+	t.ch <- struct{}{}
+}
+
+func (t *T) RunTask() {
+	for {
+		_, ok := <-t.ch
+		if !ok {
+			return
+		}
+		// todo 执行任务
+
+	}
+}

+ 118 - 0
server/utils/cmd_monitor.go

@@ -0,0 +1,118 @@
+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) 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
+				}
+				// 判断时间
+				fmt.Println("even", even)
+				switch {
+				// todo 待处理
+				case even.Op&fsnotify.Create == fsnotify.Create:
+					//这里获取新创建文件的信息,如果是目录,则加入监控中
+					fmt.Println("创建文件 : ", even.Name)
+					_ = w.Add(even.Name)
+				case even.Op&fsnotify.Write == fsnotify.Write:
+					fmt.Println("修改 : ", even.Name)
+				case even.Op&fsnotify.Remove == fsnotify.Remove:
+					fmt.Println("删除 : ", even.Name)
+					_ = w.Remove(even.Name)
+				case even.Op&fsnotify.Rename == fsnotify.Rename:
+					fmt.Println("重命名 : ", even.Name)
+					_ = w.Remove(even.Name)
+				}
+			case err = <-w.Errors:
+				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() {
+			// todo 这里加一些条件筛选添加监控的内容
+			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 {
+	return w.Add(path)
+}