tools/tools.go (215 lines of code) (raw):

// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you 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 tools import ( "embed" "fmt" "log" "os" "runtime" "strings" gojq "github.com/itchyny/gojq/cli" envsubst "github.com/nuvolaris/envsubst/cmd/envsubstmain" replace "github.com/nuvolaris/go-replace" "github.com/nuvolaris/goawk" "github.com/nuvolaris/gron" "github.com/nuvolaris/jj" "golang.org/x/exp/slices" ) //go:embed *.md var markDownHelp embed.FS var tracing = os.Getenv("TRACE") != "" func trace(args ...any) { if tracing { log.Println(append([]any{"TRACE: "}, args...)) } } // shared with main func GetOS() string { res := os.Getenv("__OS") if res == "" { res = runtime.GOOS } return res } func GetARCH() string { res := os.Getenv("__ARCH") if res == "" { res = runtime.GOARCH } return res } type Tool struct { Name string HasDoc bool } // available in taskfiles // note some of them are implemented in main.go (config, retry) // Note the comment with @DOC which is used to generate the list of tools in documentation // put one here if you add a markdown file for a tool var ToolList = []Tool{ {"wsk", false}, {"awk", false}, {"jq", false}, {"sh", true}, // @DOC {"envsubst", false}, {"filetype", true}, // @DOC {"random", true}, // @DOC {"datefmt", true}, // @DOC {"die", false}, {"urlenc", true}, // @DOC {"replace", false}, {"base64", true}, // @DOC {"validate", true}, // @DOC {"echoif", true}, // @DOC {"echoifempty", true}, // @DOC {"echoifexists", true}, // @DOC {"needupdate", true}, // @DOC {"gron", false}, {"jj", false}, {"rename", true}, // @DOC {"remove", true}, // @DOC {"executable", true}, // @DOC {"empty", true}, // @DOC {"extract", true}, // @DOC {"opspath", true}, // @DOC } func IsTool(name string) bool { for _, s := range ToolList { if s.Name == name { return true } } return false } func RunTool(name string, args []string) (int, error) { switch name { case "wsk": //fmt.Println("=== wsk ===") cmd := append([]string{"wsk"}, args...) if err := Wsk(cmd); err != nil { return 1, err } case "awk": // fmt.Println("=== awk ===") os.Args = append([]string{"goawk"}, args...) if err := goawk.AwkMain(); err != nil { return 1, err } case "jq": os.Args = append([]string{"gojq"}, args...) return gojq.Run(), nil case "sh": os.Args = append([]string{"sh"}, args...) return Sh() case "envsubst": os.Args = append([]string{"envsubst"}, args...) if err := envsubst.EnvsubstMain(); err != nil { return 1, err } case "filetype": os.Args = append([]string{"mkdir"}, args...) if err := Filetype(); err != nil { return 1, err } case "random": if err := RandTool(args...); err != nil { return 1, err } case "datefmt": if err := DateFmtTool(append([]string{"datefmt"}, args...)); err != nil { return 1, err } case "die": if len(args) > 0 { fmt.Println(strings.Join(args, " ")) } return 1, nil case "urlenc": os.Args = append([]string{"urlenc"}, args...) if err := URLEncTool(); err != nil { return 1, err } case "replace": os.Args = append([]string{"replace"}, args...) return replace.ReplaceMain() case "base64": os.Args = append([]string{"base64"}, args...) if err := base64Tool(); err != nil { return 1, err } case "validate": os.Args = append([]string{"validate"}, args...) if err := validateTool(); err != nil { return 1, err } case "echoif": os.Args = append([]string{"echoif"}, args...) if err := echoIfTool(); err != nil { return 1, err } case "echoifempty": os.Args = append([]string{"echoifempty"}, args...) if err := echoIfEmptyTool(); err != nil { return 1, err } case "echoifexists": os.Args = append([]string{"echoifexists"}, args...) if err := echoIfExistsTool(); err != nil { return 1, err } case "needupdate": if err := needUpdateTool(args); err != nil { return 1, err } case "gron": os.Args = append([]string{"gron"}, args...) return gron.GronMain() case "jj": os.Args = append([]string{"jj"}, args...) return jj.JJMain() case "rename": os.Args = append([]string{"rename"}, args...) return Rename() case "remove": os.Args = append([]string{"remove"}, args...) return Remove() case "executable": os.Args = append([]string{"executable"}, args...) return Executable() case "extract": os.Args = append([]string{"extract"}, args...) return Extract() case "empty": os.Args = append([]string{"empty"}, args...) return Empty() case "opspath": os.Args = append([]string{"opspath"}, args...) return OpsPath() default: return 1, fmt.Errorf("unknown tool") } return 0, nil } func MergeToolsList(mainTools []string) []string { availableTools := mainTools for _, tool := range ToolList { availableTools = append(availableTools, tool.Name) } return availableTools } func Help(mainTools []string) { fmt.Println("Tools (use -<tool> -h for help):") availableTools := MergeToolsList(mainTools) slices.Sort(availableTools) for _, x := range availableTools { fmt.Printf("-%s\n", x) } } func GetMarkDown(toolName string) (string, error) { // extract markdown from embedded resource markDownFile := fmt.Sprintf("%s.md", toolName) fileData, err := markDownHelp.ReadFile(markDownFile) if err != nil { return "", err } return string(fileData), nil } func MarkdownHelp(toolName string) string { // extract markdown from embedded resource fileData, err := GetMarkDown(toolName) if err != nil { return "" } result := string(fileData) // convert to markdown help := MarkdownToText(result) // return opts and help markdown return help }