add module config, sys, util & style
This commit is contained in:
parent
7bd37463ca
commit
c719e245b9
5
config/go.mod
Normal file
5
config/go.mod
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
module gitea.meta-tech.academy/go/core/config
|
||||||
|
|
||||||
|
go 1.20
|
||||||
|
|
||||||
|
require gopkg.in/yaml.v3 v3.0.1
|
4
config/go.sum
Normal file
4
config/go.sum
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
110
config/loader.go
Normal file
110
config/loader.go
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Cfg interface {
|
||||||
|
GetVar() []VarConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type VarConfig struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
Value string `yaml:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfigLoader struct {
|
||||||
|
Var []VarConfig
|
||||||
|
Config interface{}
|
||||||
|
varDef *VarPattern
|
||||||
|
refstr []*reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadConfig(path string, out Cfg, varPattern *VarPattern) {
|
||||||
|
cl := &ConfigLoader{varDef: varPattern, refstr: []*reflect.Value{}}
|
||||||
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err = yaml.Unmarshal(data, out); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
cl.Var = out.GetVar()
|
||||||
|
cl.Config = out
|
||||||
|
cl.parse()
|
||||||
|
cl.refstr = []*reflect.Value{}
|
||||||
|
// cl.setConfigPtr(outi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cl *ConfigLoader) findVarName(match string) string {
|
||||||
|
re := regexp.MustCompile(cl.varDef.getPatternCaptureName())
|
||||||
|
parts := re.FindStringSubmatch(match)
|
||||||
|
if len(parts) > 0 {
|
||||||
|
match = parts[1]
|
||||||
|
}
|
||||||
|
return match
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cl *ConfigLoader) findVarValue(v string) string {
|
||||||
|
names := strings.SplitN(v, ".", 2)
|
||||||
|
if names[0] == "var" {
|
||||||
|
for _, varConfig := range cl.Var {
|
||||||
|
if varConfig.Name == names[1] {
|
||||||
|
v = varConfig.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cl *ConfigLoader) findStringRef(ref reflect.Value) {
|
||||||
|
switch ref.Kind() {
|
||||||
|
case reflect.Ptr, reflect.Interface:
|
||||||
|
cl.findStringRef(ref.Elem())
|
||||||
|
case reflect.Struct:
|
||||||
|
for i := 0; i < ref.NumField(); i++ {
|
||||||
|
refc := ref.Field(i)
|
||||||
|
cl.findStringRef(refc)
|
||||||
|
}
|
||||||
|
case reflect.Slice:
|
||||||
|
if !ref.IsNil() {
|
||||||
|
for i := 0; i < ref.Len(); i++ {
|
||||||
|
refc := ref.Index(i)
|
||||||
|
cl.findStringRef(refc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
if ref.Len() > 0 {
|
||||||
|
cl.refstr = append(cl.refstr, &ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cl *ConfigLoader) parse() {
|
||||||
|
var name string
|
||||||
|
var tmp string
|
||||||
|
var parts []string
|
||||||
|
var re2 *regexp.Regexp
|
||||||
|
|
||||||
|
cl.findStringRef(reflect.ValueOf(&cl))
|
||||||
|
|
||||||
|
re := regexp.MustCompile(cl.varDef.getPatternVar())
|
||||||
|
for _, ref := range cl.refstr {
|
||||||
|
tmp = ref.String()
|
||||||
|
parts = re.FindStringSubmatch(tmp)
|
||||||
|
if len(parts) > 0 {
|
||||||
|
s := strings.SplitAfter(parts[1], cl.varDef.Close)
|
||||||
|
for _, part := range s {
|
||||||
|
name = cl.findVarName(part)
|
||||||
|
re2 = regexp.MustCompile(cl.varDef.getPatternVarName(name))
|
||||||
|
tmp = re2.ReplaceAllString(tmp, cl.findVarValue(name))
|
||||||
|
}
|
||||||
|
ref.SetString(tmp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
config/varpattern.go
Normal file
31
config/varpattern.go
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type VarPattern struct {
|
||||||
|
Open string
|
||||||
|
Close string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vp *VarPattern) getPatternCaptureName() string {
|
||||||
|
return fmt.Sprintf("%s([^%s]+)%s", regexp.QuoteMeta(vp.Open), regexp.QuoteMeta(string(vp.Close[:1])), regexp.QuoteMeta((vp.Close)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vp *VarPattern) getPatternVar() string {
|
||||||
|
return fmt.Sprintf("(%s.+%s)", regexp.QuoteMeta(vp.Open), regexp.QuoteMeta(vp.Close))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vp *VarPattern) getPatternVarName(name string) string {
|
||||||
|
return fmt.Sprintf("%s%s%s", regexp.QuoteMeta(vp.Open), name, regexp.QuoteMeta(vp.Close))
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewVarPattern(open string, close string) *VarPattern {
|
||||||
|
return &VarPattern{open, close}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultVarPattern() *VarPattern {
|
||||||
|
return NewVarPattern("{%", "%}")
|
||||||
|
}
|
2
go.work.sum
Normal file
2
go.work.sum
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
10
style/go.mod
Normal file
10
style/go.mod
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
module gitea.meta-tech.academy/go/core/style
|
||||||
|
|
||||||
|
go 1.20
|
||||||
|
|
||||||
|
require github.com/gookit/color v1.5.4
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
|
||||||
|
golang.org/x/sys v0.10.0 // indirect
|
||||||
|
)
|
10
style/go.sum
Normal file
10
style/go.sum
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
|
||||||
|
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
|
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
|
||||||
|
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
|
||||||
|
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||||
|
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
114
style/style.go
Normal file
114
style/style.go
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
package style
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"gitea.meta-tech.academy/go/core/util"
|
||||||
|
"github.com/gookit/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hello returns a greeting for the named person.
|
||||||
|
func Hello(name string) string {
|
||||||
|
// Return a greeting that embeds the name in a message.
|
||||||
|
message := fmt.Sprintf("Hi, %v. Welcome!", name)
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
|
||||||
|
const KEY_STYLE_NAME = 0
|
||||||
|
const KEY_STYLE_COLOR = 1
|
||||||
|
const KEY_STYLE_OPTION = 2
|
||||||
|
|
||||||
|
type Style struct {
|
||||||
|
color *color.RGBStyle
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Styles struct {
|
||||||
|
List map[string]*Style
|
||||||
|
DefaultKeyStyle string
|
||||||
|
DefaultValStyle string
|
||||||
|
DefaultKeyPadding string
|
||||||
|
DefaultIndent string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Style) Printf(format string, a ...any) {
|
||||||
|
s.color.Printf(format, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Style) Sprintf(format string, a ...any) string {
|
||||||
|
return s.color.Sprintf(format, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Style) Echo(data string, format ...string) {
|
||||||
|
fmt := "%s"
|
||||||
|
if len(format) > 1 {
|
||||||
|
fmt = format[0]
|
||||||
|
}
|
||||||
|
s.Printf(fmt, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Style) Apply(data string, format ...string) string {
|
||||||
|
if len(format) > 1 {
|
||||||
|
return s.Sprintf(format[0], data)
|
||||||
|
} else {
|
||||||
|
return s.Sprintf(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStyleByDef(def string) *Style {
|
||||||
|
var o []string = []string{}
|
||||||
|
d := strings.Fields(def)
|
||||||
|
c := strings.Split(d[KEY_STYLE_COLOR], ",")
|
||||||
|
if len(d) > KEY_STYLE_OPTION {
|
||||||
|
o = strings.Split(d[KEY_STYLE_OPTION], ",")
|
||||||
|
}
|
||||||
|
util.prependToSliceStr(&c, "#")
|
||||||
|
var s *color.RGBStyle
|
||||||
|
switch len(c) {
|
||||||
|
case 1:
|
||||||
|
s = color.HEXStyle(c[0])
|
||||||
|
case 2:
|
||||||
|
s = color.HEXStyle(c[0], c[1])
|
||||||
|
}
|
||||||
|
for _, elm := range o {
|
||||||
|
s.AddOpts(color.Color(util.str2int(elm, 10, 0)))
|
||||||
|
}
|
||||||
|
// s.Printf(" %-20s\n", d[KEY_STYLE_NAME])
|
||||||
|
return &Style{s, d[KEY_STYLE_NAME]}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStyles() *Styles {
|
||||||
|
l := &Styles{
|
||||||
|
List: make(map[string]*Style),
|
||||||
|
DefaultKeyStyle: "key",
|
||||||
|
DefaultValStyle: "val",
|
||||||
|
DefaultKeyPadding: "18",
|
||||||
|
DefaultIndent: "4",
|
||||||
|
}
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Styles) Apply(name string, data string) string {
|
||||||
|
return s.List[name].Apply(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Styles) Echo(name string, data string) {
|
||||||
|
s.List[name].Echo(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Styles) Keyval(key string, val string, names ...string) {
|
||||||
|
sk := s.List[s.DefaultKeyStyle]
|
||||||
|
sv := s.List[s.DefaultValStyle]
|
||||||
|
if len(names) > 1 {
|
||||||
|
sk = s.List[names[0]]
|
||||||
|
if len(names) > 2 {
|
||||||
|
sv = s.List[names[1]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Printf(
|
||||||
|
"%-"+s.DefaultIndent+"s%s : %s\n",
|
||||||
|
" ",
|
||||||
|
sk.Sprintf("%-"+s.DefaultKeyPadding+"s", key),
|
||||||
|
sv.Apply(val),
|
||||||
|
)
|
||||||
|
}
|
5
sys/go.mod
Normal file
5
sys/go.mod
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
module gitea.meta-tech.academy/go/core/sys
|
||||||
|
|
||||||
|
go 1.20
|
||||||
|
|
||||||
|
require golang.org/x/sys v0.13.0
|
2
sys/go.sum
Normal file
2
sys/go.sum
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||||
|
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
125
sys/sys.go
Normal file
125
sys/sys.go
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
package sys
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
var TERM_WIDTH = 0
|
||||||
|
|
||||||
|
func RunCmd(cmd *exec.Cmd) int {
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
return ManageStatusCmd(cmd, cmd.Run())
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunShellCmd(call string) int {
|
||||||
|
cmd := exec.Command("sh", "-c", call)
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
return ManageStatusCmd(cmd, cmd.Run())
|
||||||
|
}
|
||||||
|
|
||||||
|
func ManageStatusCmd(cmd *exec.Cmd, err error) int {
|
||||||
|
if err == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
// Figure out the exit code
|
||||||
|
if ws, ok := cmd.ProcessState.Sys().(syscall.WaitStatus); ok {
|
||||||
|
if ws.Exited() {
|
||||||
|
return ws.ExitStatus()
|
||||||
|
}
|
||||||
|
if ws.Signaled() {
|
||||||
|
return -int(ws.Signal())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunInteractiveCmd(cmd string, withStderr bool) int {
|
||||||
|
fmt.Printf(" == go before command : %s\n", cmd)
|
||||||
|
icmd := exec.Command("bash", "-c", cmd)
|
||||||
|
icmd.Stdin = os.Stdin
|
||||||
|
icmd.Stdout = os.Stdout
|
||||||
|
if withStderr {
|
||||||
|
icmd.Stderr = os.Stderr
|
||||||
|
}
|
||||||
|
return ManageStatusCmd(icmd, icmd.Run())
|
||||||
|
}
|
||||||
|
|
||||||
|
func PipeCmd(cmd1 *exec.Cmd, cmd2 *exec.Cmd, buffers ...io.Writer) {
|
||||||
|
fmt.Println("> Pipe Commands")
|
||||||
|
if len(buffers) > 0 {
|
||||||
|
pr, pw := io.Pipe()
|
||||||
|
cmd1.Stdout = pw
|
||||||
|
cmd2.Stdin = pr
|
||||||
|
cmd2.Stdout = buffers[0]
|
||||||
|
if len(buffers) > 1 {
|
||||||
|
cmd2.Stderr = buffers[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd1.Start()
|
||||||
|
cmd2.Start()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer pw.Close()
|
||||||
|
err1 := cmd1.Wait()
|
||||||
|
if err1 != nil {
|
||||||
|
fmt.Printf("error1 : %v\n", err1)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
err2 := cmd2.Wait()
|
||||||
|
if err2 != nil {
|
||||||
|
fmt.Printf("error2 : %v\n", err2)
|
||||||
|
}
|
||||||
|
fmt.Println("< Pipe Commands")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateTermSize() error {
|
||||||
|
ws, err := unix.IoctlGetWinsize(syscall.Stdout, unix.TIOCGWINSZ)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
TERM_WIDTH = int(ws.Col)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleTermChange() {
|
||||||
|
// set signal handler
|
||||||
|
sigwinch := make(chan os.Signal, 1)
|
||||||
|
defer close(sigwinch)
|
||||||
|
signal.Notify(sigwinch, syscall.SIGWINCH)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
if _, ok := <-sigwinch; !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_ = UpdateTermSize()
|
||||||
|
fmt.Printf("TERM WIDTH : %d\n", TERM_WIDTH)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleSigKill() {
|
||||||
|
done := make(chan os.Signal, 1)
|
||||||
|
defer close(done)
|
||||||
|
signal.Notify(done, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
go func() {
|
||||||
|
<-done // Will block here until user hits ctrl+c
|
||||||
|
cmd := exec.Command("tput", "cnorm")
|
||||||
|
RunCmd(cmd)
|
||||||
|
cmd = exec.Command("tput", "-x", "clear")
|
||||||
|
RunCmd(cmd)
|
||||||
|
os.Exit(0)
|
||||||
|
}()
|
||||||
|
}
|
3
util/go.mod
Normal file
3
util/go.mod
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
module gitea.meta-tech.academy/go/core/util
|
||||||
|
|
||||||
|
go 1.20
|
40
util/util.go
Normal file
40
util/util.go
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func prependToSliceStr(strs *[]string, prefix string) {
|
||||||
|
for i, elm := range *strs {
|
||||||
|
(*strs)[i] = prefix + elm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendToSliceStr(strs *[]string, suffix string) {
|
||||||
|
for i, elm := range *strs {
|
||||||
|
(*strs)[i] = elm + suffix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func str2int64(str string, base int, fallback int64) int64 {
|
||||||
|
str = strings.TrimSuffix(str, "\n")
|
||||||
|
num, err := strconv.ParseInt(str, base, 64)
|
||||||
|
if err != nil {
|
||||||
|
num = fallback
|
||||||
|
}
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
|
||||||
|
func str2int(str string, base int, fallback int) int {
|
||||||
|
return int(str2int64(str, base, int64(fallback)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func castStrings2ints(strs *[]string) []int {
|
||||||
|
a := make([]int, len(*strs))
|
||||||
|
for i, elm := range *strs {
|
||||||
|
var f int = str2int(elm, 10, 0)
|
||||||
|
a[i] = f
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user