181 lines
4.2 KiB
Go
181 lines
4.2 KiB
Go
package haunt
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"go/build"
|
|
"log"
|
|
"os"
|
|
"os/signal"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/fsnotify/fsnotify"
|
|
)
|
|
|
|
var (
|
|
// RPrefix tool name
|
|
RPrefix = "haunt"
|
|
// RExt file extension
|
|
RExt = ".yaml"
|
|
// RFile config file name
|
|
RFile = "." + RPrefix + RExt
|
|
// RExtWin windows extension
|
|
RExtWin = ".exe"
|
|
)
|
|
|
|
type (
|
|
// LogWriter used for all log
|
|
LogWriter struct{}
|
|
|
|
// Haunt main struct
|
|
Haunt struct {
|
|
Settings Settings `yaml:"settings" json:"settings"`
|
|
Server Server `yaml:"server,omitempty" json:"server,omitempty"`
|
|
Schema `yaml:",inline" json:",inline"`
|
|
Sync chan string `yaml:"-" json:"-"`
|
|
Err Func `yaml:"-" json:"-"`
|
|
After Func `yaml:"-" json:"-"`
|
|
Before Func `yaml:"-" json:"-"`
|
|
Change Func `yaml:"-" json:"-"`
|
|
Reload Func `yaml:"-" json:"-"`
|
|
}
|
|
|
|
// Context is used as argument for func
|
|
Context struct {
|
|
Path string
|
|
Project *Project
|
|
Stop <-chan bool
|
|
Watcher FileWatcher
|
|
Event fsnotify.Event
|
|
}
|
|
|
|
// Func is used instead haunt func
|
|
Func func(Context)
|
|
)
|
|
|
|
func NewHaunt() *Haunt {
|
|
return &Haunt{
|
|
Sync: make(chan string),
|
|
}
|
|
}
|
|
|
|
// init check
|
|
func init() {
|
|
// custom log
|
|
log.SetFlags(0)
|
|
log.SetOutput(LogWriter{})
|
|
if build.Default.GOPATH == "" {
|
|
log.Fatal("$GOPATH isn't set properly")
|
|
}
|
|
path := filepath.SplitList(build.Default.GOPATH)
|
|
if err := os.Setenv("GOBIN", filepath.Join(path[len(path)-1], "bin")); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func (r *Haunt) SetDefaults() {
|
|
r.Server = Server{Parent: r, Status: true, Open: false, Port: Port}
|
|
r.Settings.FileLimit = 0
|
|
r.Settings.Legacy.Interval = 100 * time.Millisecond
|
|
r.Settings.Legacy.Force = false
|
|
r.Settings.Files.Errors = Resource{Name: FileErr, Status: false}
|
|
r.Settings.Files.Errors = Resource{Name: FileOut, Status: false}
|
|
r.Settings.Files.Errors = Resource{Name: FileLog, Status: false}
|
|
if _, err := os.Stat("main.go"); err == nil {
|
|
log.Println(r.Prefix(Green.Bold("Adding: " + filepath.Base(Wdir()))))
|
|
r.Schema.Projects = append(r.Schema.Projects, Project{
|
|
Name: filepath.Base(Wdir()),
|
|
Path: Wdir(),
|
|
Tools: Tools{
|
|
Install: Tool{
|
|
Status: true,
|
|
},
|
|
Run: Tool{
|
|
Status: true,
|
|
},
|
|
},
|
|
Watcher: Watch{
|
|
Exts: []string{"go"},
|
|
Paths: []string{"/"},
|
|
},
|
|
})
|
|
} else {
|
|
log.Println(r.Prefix(Magenta.Bold("Skipping: " + filepath.Base(Wdir()) + " no main.go file in root")))
|
|
}
|
|
subDirs, err := os.ReadDir("cmd")
|
|
if err != nil {
|
|
log.Println(r.Prefix("cmd directory not found, skipping"))
|
|
return
|
|
}
|
|
for _, dir := range subDirs {
|
|
if dir.IsDir() {
|
|
log.Println(r.Prefix(Green.Bold("Adding: " + dir.Name())))
|
|
r.Schema.Projects = append(r.Schema.Projects, Project{
|
|
Name: dir.Name(),
|
|
Path: "cmd/" + dir.Name(),
|
|
Tools: Tools{
|
|
Install: Tool{
|
|
Status: true,
|
|
},
|
|
Run: Tool{
|
|
Status: true,
|
|
},
|
|
},
|
|
Watcher: Watch{
|
|
Exts: []string{"go"},
|
|
Paths: []string{"cmd/" + dir.Name()},
|
|
},
|
|
})
|
|
} else {
|
|
log.Println(r.Prefix(Magenta.Bold("Skipping: " + dir.Name() + " not a directory")))
|
|
}
|
|
}
|
|
}
|
|
|
|
// Stop haunt workflow
|
|
func (r *Haunt) Stop() error {
|
|
for k := range r.Schema.Projects {
|
|
if r.Schema.Projects[k].exit != nil {
|
|
close(r.Schema.Projects[k].exit)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Start haunt workflow
|
|
func (r *Haunt) Start() error {
|
|
if len(r.Schema.Projects) > 0 {
|
|
var wg sync.WaitGroup
|
|
wg.Add(len(r.Schema.Projects))
|
|
for k := range r.Schema.Projects {
|
|
r.Schema.Projects[k].exit = make(chan os.Signal, 1)
|
|
signal.Notify(r.Schema.Projects[k].exit, os.Interrupt)
|
|
r.Schema.Projects[k].parent = r
|
|
go r.Schema.Projects[k].Watch(&wg)
|
|
}
|
|
wg.Wait()
|
|
} else {
|
|
return errors.New("there are no projects")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Prefix a given string with tool name
|
|
func (r *Haunt) Prefix(input string) string {
|
|
if len(input) > 0 {
|
|
return fmt.Sprint(Yellow.Bold("["), strings.ToUpper(RPrefix), Yellow.Bold("]"), ": ", input)
|
|
}
|
|
return input
|
|
}
|
|
|
|
// Rewrite the layout of the log timestamp
|
|
func (w LogWriter) Write(bytes []byte) (int, error) {
|
|
if len(bytes) > 0 {
|
|
return fmt.Fprint(Output, Yellow.Regular("["), time.Now().Format("15:04:05"), Yellow.Regular("]"), string(bytes))
|
|
}
|
|
return 0, nil
|
|
}
|