149 lines
3.1 KiB
Go
149 lines
3.1 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/otiai10/copy"
|
|
"github.com/radovskyb/watcher"
|
|
"github.com/tidwall/gjson"
|
|
)
|
|
|
|
func link(from, to string) chan struct{} {
|
|
requestBuildCh := make(chan struct{})
|
|
|
|
// Load package.json in destination.
|
|
destPkg := readFileContent(filepath.Join(to, "package.json"))
|
|
depsRaw := gjson.Get(destPkg, "dependencies").Map()
|
|
deps := map[string]bool{}
|
|
for k := range depsRaw {
|
|
deps[k] = true
|
|
}
|
|
|
|
packages := map[string]string{}
|
|
packageFiles := findFiles(from, "package.json")
|
|
|
|
for i := range packageFiles {
|
|
content := readFileContent(packageFiles[i])
|
|
name := gjson.Get(content, "name").String()
|
|
|
|
if deps[name] {
|
|
pp, err := filepath.Abs(filepath.Dir(packageFiles[i]))
|
|
if err == nil {
|
|
packages[name] = pp
|
|
}
|
|
}
|
|
}
|
|
|
|
fmt.Printf("Found %d npm packages to monitor for changes.\n", len(packages))
|
|
|
|
go func() {
|
|
w := watcher.New()
|
|
w.SetMaxEvents(1)
|
|
w.FilterOps(watcher.Write, watcher.Rename, watcher.Move, watcher.Create, watcher.Remove)
|
|
w.IgnoreHiddenFiles(true)
|
|
|
|
if err := w.AddRecursive(from); err != nil {
|
|
fmt.Println(err.Error())
|
|
os.Exit(1)
|
|
}
|
|
|
|
go func() {
|
|
for {
|
|
select {
|
|
case event := <-w.Event:
|
|
fmt.Printf("File %s changed\n", event.Path)
|
|
for k, v := range packages {
|
|
if strings.HasPrefix(event.Path, v) {
|
|
src := filepath.Dir(event.Path)
|
|
subPath, _ := filepath.Rel(v, src)
|
|
dest := filepath.Join(to, "node_modules", k, subPath)
|
|
fmt.Printf("Copying %s to %s\n", src, dest)
|
|
err := copy.Copy(src, dest, copy.Options{
|
|
Skip: func(stat fs.FileInfo, src, dest string) (bool, error) {
|
|
if !isExcludedPath(src, "node_modules", ".git") && (stat.IsDir() || isIncludedExt(filepath.Base(src), "*.js", "*.ts")) {
|
|
return false, nil
|
|
}
|
|
|
|
return true, nil
|
|
},
|
|
Sync: true,
|
|
})
|
|
|
|
if err != nil {
|
|
fmt.Printf("Failed to copy %s: %v\n", k, err)
|
|
}
|
|
|
|
requestBuildCh <- struct{}{}
|
|
}
|
|
}
|
|
case err := <-w.Error:
|
|
fmt.Println(err.Error())
|
|
case <-w.Closed:
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
fmt.Printf("Watching packages in %s\n", from)
|
|
|
|
if err := w.Start(time.Millisecond * 100); err != nil {
|
|
fmt.Println(err.Error())
|
|
}
|
|
}()
|
|
|
|
return requestBuildCh
|
|
}
|
|
|
|
func isExcludedPath(srcPath string, exPaths ...string) bool {
|
|
for _, exP := range exPaths {
|
|
if strings.Contains(srcPath, exP) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func isIncludedExt(srcPath string, extensions ...string) bool {
|
|
for _, ext := range extensions {
|
|
if ok, _ := filepath.Match(ext, srcPath); ok {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func findFiles(root, name string) []string {
|
|
paths := []string{}
|
|
|
|
filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
if !d.IsDir() && filepath.Base(path) == name && !strings.Contains(path, "node_modules") {
|
|
paths = append(paths, path)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
return paths
|
|
}
|
|
|
|
func readFileContent(path string) string {
|
|
pkgData, err := os.ReadFile(path)
|
|
|
|
if err != nil {
|
|
fmt.Printf("%+v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
return string(pkgData)
|
|
}
|