diff options
| -rw-r--r-- | Makefile | 9 | ||||
| -rw-r--r-- | go.mod | 2 | ||||
| -rw-r--r-- | go.sum | 4 | ||||
| -rw-r--r-- | internal/cmd/trunks-example/main.go | 180 | ||||
| -rw-r--r-- | internal/memfs-embed/main.go | 46 | ||||
| -rw-r--r-- | trunks.go | 107 |
6 files changed, 187 insertions, 161 deletions
@@ -4,14 +4,9 @@ .PHONY: all run embed tsc -all: embed +all: + go run ./internal/cmd/trunks-example build go test -v -race ./... run: go run ./internal/cmd/trunks-example - -embed: tsc - go run ./internal/memfs-embed - -tsc: - tsc -p _www/tsconfig.json @@ -3,7 +3,7 @@ module git.sr.ht/~shulhan/trunks go 1.16 require ( - git.sr.ht/~shulhan/ciigo v0.6.1-0.20211010143228-56488e32c04c + git.sr.ht/~shulhan/ciigo v0.6.1-0.20211017121420-36d729c71dd0 github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 // indirect github.com/influxdata/tdigest v0.0.1 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -1,7 +1,7 @@ git.sr.ht/~shulhan/asciidoctor-go v0.1.1-0.20211004182124-1c48dfa11a1b h1:LrKeNE5urwiAZcuv1ACKwStbXpxWIaXNKrL4aCsN2EE= git.sr.ht/~shulhan/asciidoctor-go v0.1.1-0.20211004182124-1c48dfa11a1b/go.mod h1:fGzLvcEmRkdfo9mg7sp7fQHQHquCUJ4+6nRfWi6I7B0= -git.sr.ht/~shulhan/ciigo v0.6.1-0.20211010143228-56488e32c04c h1:+XHHQitIznJFH9vQJMfR/+DQfVFED/ls1p81FExlJAg= -git.sr.ht/~shulhan/ciigo v0.6.1-0.20211010143228-56488e32c04c/go.mod h1:mmvVAFWJ14Y3qrI0MPNrslAf6QKxtEiXpmERaBYk7LY= +git.sr.ht/~shulhan/ciigo v0.6.1-0.20211017121420-36d729c71dd0 h1:aScDnq5u5DnQ2XGwGXCmcdZzfpyyPFvGZxnkFbWtMCM= +git.sr.ht/~shulhan/ciigo v0.6.1-0.20211017121420-36d729c71dd0/go.mod h1:mmvVAFWJ14Y3qrI0MPNrslAf6QKxtEiXpmERaBYk7LY= github.com/alecthomas/jsonschema v0.0.0-20180308105923-f2c93856175a/go.mod h1:qpebaTNSsyUn5rPSJMsfqEtDw71TTggXM6stUDI16HA= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b h1:AP/Y7sqYicnjGDfD5VcY4CIfh1hRXBUavxrvELjTiOE= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= diff --git a/internal/cmd/trunks-example/main.go b/internal/cmd/trunks-example/main.go index 9c340e5..1746209 100644 --- a/internal/cmd/trunks-example/main.go +++ b/internal/cmd/trunks-example/main.go @@ -8,21 +8,50 @@ package main import ( + "flag" "os" "os/signal" + "strings" "syscall" + "time" + "github.com/shuLhan/share/lib/io" + "github.com/shuLhan/share/lib/memfs" "github.com/shuLhan/share/lib/mlog" + "github.com/shuLhan/share/lib/os/exec" + "git.sr.ht/~shulhan/ciigo" + "git.sr.ht/~shulhan/trunks" "git.sr.ht/~shulhan/trunks/example" ) +const ( + subCommandBuild = "build" + cmdTsc = "tsc -b _www" +) + func main() { + flag.Parse() + subcmd := strings.ToLower(flag.Arg(0)) + + if subcmd == subCommandBuild { + workerBuild(true) + return + } + + err := os.Setenv(trunks.EnvDevelopment, "1") + if err != nil { + mlog.Fatalf("%s\n", err) + } + ex, err := example.New() if err != nil { mlog.Fatalf("%s\n", err) } + go workerBuild(false) + go workerDocs() + go func() { c := make(chan os.Signal, 1) signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM) @@ -35,3 +64,154 @@ func main() { mlog.Fatalf("%s\n", err) } } + +// +// workerBuild watch update on .ts and .js files inside _www directory. +// +// Every 5 seconds, it will recompile TypeScript to JavaScript, by running +// tsc, if only if there is at least one .ts file being. +// After that, if there is an update to .js files, it will run scripts that +// embed them into Go source code. +// +// If oneTime parameter is true, it will recompile the .ts and embed the .js +// files only, without watching updates. +// +func workerBuild(oneTime bool) { + var ( + logp = "workerBuild" + tsCount = 0 + embedCount = 0 + changeq = make(chan *io.NodeState, 64) + ) + + mfsOpts := &memfs.Options{ + Root: "_www", + Includes: []string{ + `.*\.(js|ico|png|html)$`, + }, + Excludes: []string{ + `.*\.adoc`, + `.*\.git`, + `.*\.ts`, + `/wui/.*/example.js$`, + `/wui/.*/index.html$`, + `/wui/index\.html$`, + `/wui\.bak`, + `/wui\.local`, + }, + } + + mfsWww, err := memfs.New(mfsOpts) + if err != nil { + mlog.Fatalf("%s: %s", logp, err) + } + + if oneTime { + err = doRunTsc(logp) + if err != nil { + os.Exit(1) + } + err = doGoEmbed(logp, mfsWww) + if err != nil { + os.Exit(1) + } + return + } + + dirWatchWww := io.DirWatcher{ + Options: memfs.Options{ + Root: "_www", + Includes: []string{ + `.*\.(js|ts)$`, + `_www/tsconfig.json`, + }, + Excludes: []string{ + `.*\.d\.ts$`, + `.*\.git/.*`, + `docs`, + `wui\.bak`, + `wui\.local`, + }, + }, + Callback: func(ns *io.NodeState) { + changeq <- ns + }, + } + + err = dirWatchWww.Start() + if err != nil { + mlog.Fatalf("%s: %s", logp, err) + } + + mlog.Outf("%s: started ...\n", logp) + + ticker := time.NewTicker(5 * time.Second) + for { + select { + case ns := <-changeq: + if strings.HasSuffix(ns.Node.SysPath, ".ts") { + mlog.Outf("%s: update %s\n", logp, ns.Node.SysPath) + tsCount++ + } else if strings.HasSuffix(ns.Node.SysPath, ".json") { + mlog.Outf("%s: update %s\n", logp, ns.Node.SysPath) + tsCount++ + } else if strings.HasSuffix(ns.Node.SysPath, ".js") { + embedCount++ + mlog.Outf("%s: update %s\n", logp, ns.Node.SysPath) + err = ns.Node.Update(nil, 0) + if err != nil { + mlog.Errf("%s: %s", logp, err) + } + } else { + mlog.Outf("%s: unknown file updated %s\n", logp, ns.Node.SysPath) + } + case <-ticker.C: + if tsCount > 0 { + tsCount = 0 + _ = doRunTsc(logp) + } + if embedCount > 0 { + embedCount = 0 + _ = doGoEmbed(logp, mfsWww) + } + } + } +} + +// +// workerDocs a goroutine that watch any changes to .adoc files inside +// "_www/docs" directory and convert them into HTML files. +// +func workerDocs() { + logp := "workerDocs" + + mlog.Outf("%s: started ...\n", logp) + + opts := &ciigo.ConvertOptions{ + Root: "_www/docs", + } + err := ciigo.Watch(opts) + if err != nil { + mlog.Errf("%s: %s", logp, err) + } +} + +func doRunTsc(logp string) (err error) { + mlog.Outf("%s: execute %s\n", logp, cmdTsc) + err = exec.Run(cmdTsc, nil, nil) + if err != nil { + mlog.Errf("%s: %s", logp, err) + return err + } + return nil +} + +func doGoEmbed(logp string, mfs *memfs.MemFS) (err error) { + mlog.Outf("%s: generate memfs_www_embed.go\n", logp) + err = mfs.GoEmbed("trunks", "memfsWWW", "memfs_www_embed.go", "") + if err != nil { + mlog.Errf("%s: %s", logp, err) + return err + } + return nil +} diff --git a/internal/memfs-embed/main.go b/internal/memfs-embed/main.go deleted file mode 100644 index 04de67f..0000000 --- a/internal/memfs-embed/main.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2021, Shulhan <ms@kilabit.info>. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "log" - "os" - - "github.com/shuLhan/share/lib/memfs" - "github.com/shuLhan/share/lib/mlog" -) - -func main() { - log.SetPrefix(os.Args[0]) - - opts := &memfs.Options{ - Root: "_www", - Excludes: []string{ - `.*\.adoc`, - `.*\.git`, - `.*\.ts`, - `/wui/.*/example.js$`, - `/wui/.*/index.html$`, - `/wui/LICENSE$`, - `/wui/Makefile$`, - `/wui/NOTES$`, - `/wui/README.adoc$`, - `/wui/index\.html$`, - `/wui/tsconfig\.json$`, - `/wui\.bak`, - `/wui\.local`, - }, - } - - mfs, err := memfs.New(opts) - if err != nil { - log.Fatalf("%s\n", err) - } - - err = mfs.GoEmbed("trunks", "memfsWWW", "memfs_www_embed.go", "") - if err != nil { - mlog.Fatalf("%s\n", err) - } -} @@ -11,15 +11,11 @@ import ( "strings" "time" - "git.sr.ht/~shulhan/ciigo" vegeta "github.com/tsenart/vegeta/v12/lib" liberrors "github.com/shuLhan/share/lib/errors" libhttp "github.com/shuLhan/share/lib/http" - "github.com/shuLhan/share/lib/io" - "github.com/shuLhan/share/lib/memfs" "github.com/shuLhan/share/lib/mlog" - "github.com/shuLhan/share/lib/os/exec" "github.com/shuLhan/share/lib/websocket" ) @@ -35,7 +31,7 @@ const ( // Setting this environment variable will enable trunks development // mode. - envDevelopment = "TRUNKS_DEV" + EnvDevelopment = "TRUNKS_DEV" // List of HTTP parameters. paramNameName = "name" @@ -66,7 +62,7 @@ type Trunks struct { func New(env *Environment) (trunks *Trunks, err error) { var ( logp = "trunks.New" - isDevelopment = len(os.Getenv(envDevelopment)) > 0 + isDevelopment = len(os.Getenv(EnvDevelopment)) > 0 ) err = env.init() @@ -90,11 +86,6 @@ func New(env *Environment) (trunks *Trunks, err error) { return nil, fmt.Errorf("%s: %w", logp, err) } - if isDevelopment { - go watchDocs() - go watchWww() - } - return trunks, nil } @@ -503,97 +494,3 @@ func (trunks *Trunks) workerAttackQueue() { trunks.Env.AttackRunning = nil } } - -// -// watchDocs a goroutine that watch any changes to .adoc files inside -// "_www/docs" directory and convert them into HTML files. -// -func watchDocs() { - logp := "watchDocs" - opts := &ciigo.ConvertOptions{ - Root: "_www/docs", - } - err := ciigo.Watch(opts) - if err != nil { - mlog.Errf("%s: %s", logp, err) - } -} - -// -// watchWww a goroutine that watch any changes to TypeScript, HTML, and -// tsconfig files inside the _www, and when there is an update it will execute -// "tsc -p" to recompile and "go run ./internal/generate-memfs" to embed them -// into Go source. -// -func watchWww() { - var ( - logp = "watchWww" - changeq = make(chan struct{}, 64) - ) - - go recompile(changeq) - - dirWatcher := &io.DirWatcher{ - Options: memfs.Options{ - Root: "_www", - Includes: []string{ - `\.*.ts$`, - `_www/index.html$`, - `_www/tsconfig.json$`, - }, - Excludes: []string{ - `\.*.d.ts$`, - `\.git`, - `\.wui.bak`, - `\.wui.local`, - }, - }, - Callback: func(ns *io.NodeState) { - mlog.Outf("--- %s: %s: %d\n", logp, ns.Node.SysPath, ns.State) - changeq <- struct{}{} - }, - } - err := dirWatcher.Start() - if err != nil { - mlog.Errf("%s: %s", logp, err) - } -} - -func recompile(changeq chan struct{}) { - var ( - logp = "recompile" - count int - changeTicker = time.NewTicker(3 * time.Second) - commands = []string{ - "tsc -p _www/tsconfig.json", - "go run ./internal/generate-memfs", - } - draining bool - ) - for range changeTicker.C { - draining = true - for draining { - select { - case <-changeq: - count++ - default: - if count == 0 { - // No changes. - draining = false - } else { - // All changes has been drained, execute all - // commands. - for _, cmd := range commands { - mlog.Outf("%s: %s\n", logp, cmd) - err := exec.Run(cmd, nil, nil) - if err != nil { - mlog.Errf("%s: %s", logp, err) - } - } - count = 0 - draining = false - } - } - } - } -} |
