add module config, sys, util & style

This commit is contained in:
Mahdi Abu Yasmine 2023-11-02 23:04:28 +01:00
parent 7bd37463ca
commit c719e245b9
16 changed files with 472 additions and 0 deletions

5
config/go.mod Normal file
View 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
View 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
View 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
View 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("{%", "%}")
}

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module gitea.meta-tech.academy/go/core
go 1.20

0
go.sum Normal file
View File

8
go.work Normal file
View File

@ -0,0 +1,8 @@
go 1.20
use (
./config
./style
./util
./sys
)

2
go.work.sum Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,3 @@
module gitea.meta-tech.academy/go/core/util
go 1.20

40
util/util.go Normal file
View 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
}