From 99405a600713414a3effec8882f1ee1b0afa32ca Mon Sep 17 00:00:00 2001 From: xiantang Date: Mon, 23 Oct 2023 17:47:20 +0800 Subject: [PATCH 1/4] committed --- main.go | 9 +++-- runner/config.go | 94 ++++++++++++++++++++++++------------------------ 2 files changed, 54 insertions(+), 49 deletions(-) diff --git a/main.go b/main.go index 67167730..c6affbae 100644 --- a/main.go +++ b/main.go @@ -17,10 +17,11 @@ var ( cfgPath string debugMode bool showVersion bool + help bool cmdArgs map[string]runner.TomlInfo ) -func helpMessage() { +func usage() { fmt.Fprintf(flag.CommandLine.Output(), "Usage of %s:\n\n", os.Args[0]) fmt.Printf("If no command is provided %s will start the runner with the provided flags\n\n", os.Args[0]) fmt.Println("Commands:") @@ -35,10 +36,11 @@ func init() { } func parseFlag(args []string) { - flag.Usage = helpMessage + flag.Usage = usage flag.StringVar(&cfgPath, "c", "", "config path") flag.BoolVar(&debugMode, "d", false, "debug mode") flag.BoolVar(&showVersion, "v", false, "show version") + flag.BoolVar(&help, "h", false, "help") cmd := flag.CommandLine cmdArgs = runner.ParseConfigFlag(cmd) if err := flag.CommandLine.Parse(args); err != nil { @@ -82,6 +84,9 @@ func main() { if showVersion { return } + if help { + return + } if debugMode { fmt.Println("[debug] mode") diff --git a/runner/config.go b/runner/config.go index 10165365..06044901 100644 --- a/runner/config.go +++ b/runner/config.go @@ -23,8 +23,8 @@ const ( // Config is the main configuration structure for Air. type Config struct { - Root string `toml:"root"` - TmpDir string `toml:"tmp_dir"` + Root string `toml:"root" comment:". or absolute path, please note that the directories following must be under root."` + TmpDir string `toml:"tmp_dir" comment:"Temporary directory."` TestDataDir string `toml:"testdata_dir"` Build cfgBuild `toml:"build"` Color cfgColor `toml:"color"` @@ -34,32 +34,54 @@ type Config struct { } type cfgBuild struct { - PreCmd []string `toml:"pre_cmd"` - Cmd string `toml:"cmd"` - PostCmd []string `toml:"post_cmd"` - Bin string `toml:"bin"` - FullBin string `toml:"full_bin"` - ArgsBin []string `toml:"args_bin"` - Log string `toml:"log"` - IncludeExt []string `toml:"include_ext"` - ExcludeDir []string `toml:"exclude_dir"` - IncludeDir []string `toml:"include_dir"` - ExcludeFile []string `toml:"exclude_file"` - IncludeFile []string `toml:"include_file"` - ExcludeRegex []string `toml:"exclude_regex"` - ExcludeUnchanged bool `toml:"exclude_unchanged"` - FollowSymlink bool `toml:"follow_symlink"` - Poll bool `toml:"poll"` - PollInterval int `toml:"poll_interval"` - Delay int `toml:"delay"` - StopOnError bool `toml:"stop_on_error"` - SendInterrupt bool `toml:"send_interrupt"` - KillDelay time.Duration `toml:"kill_delay"` - Rerun bool `toml:"rerun"` - RerunDelay int `toml:"rerun_delay"` + PreCmd []string `toml:"pre_cmd" comment:"Array of commands to run before each build"` + Cmd string `toml:"cmd" comment:"Shell command to run for building."` + PostCmd []string `toml:"post_cmd" comment:"Array of commands to run after ^C"` + Bin string `toml:"bin" comment:"Binary file yields from cmd."` + FullBin string `toml:"full_bin" comment:"Customize binary, can setup environment variables when run your app."` + ArgsBin []string `toml:"args_bin" comment:"Add additional arguments when running binary (bin/full_bin)."` + Log string `toml:"log" comment:"Log file places in your tmp_dir."` + IncludeExt []string `toml:"include_ext" comment:"Watch these filename extensions."` + ExcludeDir []string `toml:"exclude_dir" comment:"Ignore these filename extensions or directories."` + IncludeDir []string `toml:"include_dir" comment:"Watch these directories if you specified."` + ExcludeFile []string `toml:"exclude_file" comment:"Exclude these files."` + IncludeFile []string `toml:"include_file" comment:"Watch these files."` + ExcludeRegex []string `toml:"exclude_regex" comment:"Exclude specific regular expressions."` + ExcludeUnchanged bool `toml:"exclude_unchanged" comment:"Exclude unchanged files."` + FollowSymlink bool `toml:"follow_symlink" comment:"Follow symlink for directories"` + Poll bool `toml:"poll" comment:"Poll files for changes instead of using fsnotify."` + PollInterval int `toml:"poll_interval" comment:"Poll interval (defaults to the minimum interval of 500ms)."` + Delay int `toml:"delay" comment:"Delay in milliseconds."` + StopOnError bool `toml:"stop_on_error" comment:"Stop running old binary when build errors occur."` + SendInterrupt bool `toml:"send_interrupt" comment:"Send Interrupt signal before killing process (windows does not support this feature)"` + KillDelay time.Duration `toml:"kill_delay" comment:"Delay after sending Interrupt signal in nanoseconds."` + Rerun bool `toml:"rerun" comment:"Rerun binary or not"` + RerunDelay int `toml:"rerun_delay" comment:"Delay after each executions in milliseconds."` regexCompiled []*regexp.Regexp } +type cfgLog struct { + AddTime bool `toml:"time" comment:"Show log time"` + MainOnly bool `toml:"main_only" comment:"Only show main log (silences watcher, build, runner)"` +} + +type cfgColor struct { + Main string `toml:"main" comment:"Customize main part's color. If no color found, use the raw app log."` + Watcher string `toml:"watcher" comment:"Customize watcher part's color."` + Build string `toml:"build" comment:"Customize build part's color."` + Runner string `toml:"runner" comment:"Customize runner part's color."` + App string `toml:"app" comment:"Customize app part's color."` +} + +type cfgMisc struct { + CleanOnExit bool `toml:"clean_on_exit" comment:"Delete tmp directory on exit"` +} + +type cfgScreen struct { + ClearOnRebuild bool `toml:"clear_on_rebuild" comment:"Clear screen on rebuild"` + KeepScroll bool `toml:"keep_scroll" comment:"Keep scroll position"` +} + func (c *cfgBuild) RegexCompiled() ([]*regexp.Regexp, error) { if len(c.ExcludeRegex) > 0 && len(c.regexCompiled) == 0 { c.regexCompiled = make([]*regexp.Regexp, 0, len(c.ExcludeRegex)) @@ -74,28 +96,6 @@ func (c *cfgBuild) RegexCompiled() ([]*regexp.Regexp, error) { return c.regexCompiled, nil } -type cfgLog struct { - AddTime bool `toml:"time"` - MainOnly bool `toml:"main_only"` -} - -type cfgColor struct { - Main string `toml:"main"` - Watcher string `toml:"watcher"` - Build string `toml:"build"` - Runner string `toml:"runner"` - App string `toml:"app"` -} - -type cfgMisc struct { - CleanOnExit bool `toml:"clean_on_exit"` -} - -type cfgScreen struct { - ClearOnRebuild bool `toml:"clear_on_rebuild"` - KeepScroll bool `toml:"keep_scroll"` -} - type sliceTransformer struct{} func (t sliceTransformer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error { From 4ba9c9e81db0372e3512349abcfc98527fca5976 Mon Sep 17 00:00:00 2001 From: xiantang Date: Mon, 23 Oct 2023 17:53:54 +0800 Subject: [PATCH 2/4] commit --- main.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/main.go b/main.go index c6affbae..3c91c5c1 100644 --- a/main.go +++ b/main.go @@ -11,6 +11,7 @@ import ( "syscall" "github.com/cosmtrek/air/runner" + "github.com/pelletier/go-toml" ) var ( @@ -72,6 +73,20 @@ func GetVersionInfo() versionInfo { } } +func helpMessage() { + data, err := os.ReadFile("air_example.toml") + if err != nil { + log.Fatal(err) + } + + var cfg runner.Config + err = toml.Unmarshal(data, &cfg) + if err != nil { + log.Fatal(err) + } + fmt.Printf("cfg: %+v\n", cfg) +} + func main() { versionInfo := GetVersionInfo() fmt.Printf(` @@ -85,6 +100,7 @@ func main() { return } if help { + helpMessage() return } From 02aa39ffd0b337edbfda995cdae50b4d34d3f409 Mon Sep 17 00:00:00 2001 From: xiantang Date: Mon, 23 Oct 2023 17:58:01 +0800 Subject: [PATCH 3/4] use embed go file --- main.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/main.go b/main.go index 3c91c5c1..d64bf020 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,7 @@ package main import ( + _ "embed" "flag" "fmt" "log" @@ -20,6 +21,9 @@ var ( showVersion bool help bool cmdArgs map[string]runner.TomlInfo + + //go:embed air_example.toml + airExampleToml string ) func usage() { @@ -74,13 +78,8 @@ func GetVersionInfo() versionInfo { } func helpMessage() { - data, err := os.ReadFile("air_example.toml") - if err != nil { - log.Fatal(err) - } - var cfg runner.Config - err = toml.Unmarshal(data, &cfg) + err := toml.Unmarshal([]byte(airExampleToml), &cfg) if err != nil { log.Fatal(err) } From 9f3d59bff75fa234976ca8f887575f2e4e173cbc Mon Sep 17 00:00:00 2001 From: xiantang Date: Mon, 23 Oct 2023 18:19:04 +0800 Subject: [PATCH 4/4] value and key --- main.go | 2 ++ runner/flag.go | 2 +- runner/util.go | 16 ++++++++++------ runner/util_test.go | 2 +- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/main.go b/main.go index d64bf020..d7186c2b 100644 --- a/main.go +++ b/main.go @@ -84,6 +84,8 @@ func helpMessage() { log.Fatal(err) } fmt.Printf("cfg: %+v\n", cfg) + m := runner.FlatConfig(cfg) + fmt.Printf("m: %+v\n", m) } func main() { diff --git a/runner/flag.go b/runner/flag.go index af8f478b..947a8a43 100644 --- a/runner/flag.go +++ b/runner/flag.go @@ -9,7 +9,7 @@ const unsetDefault = "DEFAULT" // ParseConfigFlag parse toml information for flag func ParseConfigFlag(f *flag.FlagSet) map[string]TomlInfo { c := Config{} - m := flatConfig(c) + m := FlatConfig(c) for k, v := range m { f.StringVar(v.Value, k, unsetDefault, "") } diff --git a/runner/util.go b/runner/util.go index e0b03b85..37b63c93 100644 --- a/runner/util.go +++ b/runner/util.go @@ -300,6 +300,7 @@ type TomlInfo struct { fieldPath string field reflect.StructField Value *string + Comment string } func setValue2Struct(v reflect.Value, fieldName string, value string) { @@ -350,22 +351,25 @@ func setValue2Struct(v reflect.Value, fieldName string, value string) { } } -// flatConfig ... -func flatConfig(stut interface{}) map[string]TomlInfo { +// FlatConfig ... +func FlatConfig(stut interface{}) map[string]TomlInfo { m := make(map[string]TomlInfo) - t := reflect.TypeOf(stut) + t := reflect.ValueOf(stut) setTage2Map("", t, m, "") return m } -func setTage2Map(root string, t reflect.Type, m map[string]TomlInfo, fieldPath string) { +func setTage2Map(root string, v reflect.Value, m map[string]TomlInfo, fieldPath string) { + t := v.Type() for i := 0; i < t.NumField(); i++ { field := t.Field(i) + value := v.Field(i) tomlVal := field.Tag.Get("toml") + comment := field.Tag.Get("comment") switch field.Type.Kind() { case reflect.Struct: path := fieldPath + field.Name + "." - setTage2Map(root+tomlVal+".", field.Type, m, path) + setTage2Map(root+tomlVal+".", value, m, path) default: if tomlVal == "" { continue @@ -375,7 +379,7 @@ func setTage2Map(root string, t reflect.Type, m map[string]TomlInfo, fieldPath s var v *string str := "" v = &str - m[tomlPath] = TomlInfo{field: field, Value: v, fieldPath: path} + m[tomlPath] = TomlInfo{field: field, Value: v, fieldPath: path, Comment: comment} } } } diff --git a/runner/util_test.go b/runner/util_test.go index fce01eca..63dcbba7 100644 --- a/runner/util_test.go +++ b/runner/util_test.go @@ -236,7 +236,7 @@ func Test_killCmd_SendInterrupt_false(t *testing.T) { func TestGetStructureFieldTagMap(t *testing.T) { c := Config{} - tagMap := flatConfig(c) + tagMap := FlatConfig(c) for _, i2 := range tagMap { fmt.Printf("%v\n", i2.fieldPath) }