schemaentry

package module
v2.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 17, 2022 License: MIT Imports: 22 Imported by: 2

README

schema-entry-go/V2

通过定义结构体同时声明jsonschem提供复杂的启动参数设置项

V2版本针对1.18以上的golang,大量使用了泛型.低版本请使用V1版本,V1版本将不再更新

特性

  • 支持多级子命令
  • 每级子命令会提示其下一级的子命令
  • 终点节点可以通过定义一个满足接口EndPointConfigInterface的结构体来指定参数的解析行为和入口函数的执行过程
  • 可以通过默认值,指定位置文件,环境变量,命令行参数来构造配置结构,其顺序是命令行参数->环境变量->命令行指定的配置文件->配置指定的配置文件路径->默认值
  • 通过定义满足接口EndPointConfigInterface的结构体中的jsonschematag来定义配置的校验规则
  • 支持jsonyaml两种格式的配置文件
  • 支持watch模式,可以通过监听指定文件更新配置

概念和一些规则

节点

我们使用节点来描述命令之间的关系,定义3类节点:

  1. 根节点,一颗节点树的起始点,它没有父节点
  2. 叶子节点,节点树当中没有子节点的节点
  3. 枝节点,既有父节点又有子节点的节点

叶子节点或者是要执行的的根节点我们使用func NewEndPoint[T EndPointConfigInterface](config T, opts ...optparams.Option[EntryPointMeta]) (*EndPoint[T], error)来创建

不用执行的根节点和枝节点我们使用func NewEntryPoint(opts ...optparams.Option[EntryPointMeta]) (*EntryPoint, error)来创建

一个节点最多只能有一个父节点,但可以有多个子节点.节点与节点间可以使用如下几个方式来注册:

  • func RegistSubNode(parent, child EntryPointInterface)函数
  • func (EntryPointInterface) SetChild(child EntryPointInterface) error,这个方法当在叶子节点上注册子节点时会报错
  • func (EntryPointInterface) SetParent(parent EntryPointInterface) EntryPointInterface,这个方法一般从叶子节点开始向根节点注册.返回的是父节点,所以可以用pipeline的形式注册
参数的解析规则
  1. 所有节点都会解析其--help命令,叶子节点会解析命令,用法,说明,以及参数,其他节点则是解析其命令,说明和支持的子命令.

    节点的名字使用EntryPointMeta.Name定义如果不定义则查找config字段有没有设置,如果设置了则使用config对象的结构体名,如果没有则会报错.

    命令为根节点到当前节点名字中间用空格分隔.

    说明使用EntryPointMeta.Usage设置.

  2. 只有定义了config对象的叶子节点才会进行参数解析 config满足接口:

    //EndPointConfigInterface 叶子节点配置接口
    type EndPointConfigInterface interface {
        Main()         //进入时执行的程序
    }
    

    解析的流程如下:

    使用配置指定路径的配置替换默认值(可以通过`EntryPointMeta.DefaultConfigFilePaths`配置默认路径)
                |
                v
    使用命令行参数`--config`指定的配置文件替换默认值(如果不为空字符串)
                |
                v
    
    使用环境变量替换默认值(如果设置`EntryPointMeta.NotParseEnv: false`)
    可以设置前缀`EntryPointMeta.EnvPrefix`作为环境变量的命名空间,默认前缀为根节点到当前节点间所有节点名中间以`_`分隔.
    前缀和参数间使用`_`分隔
                |
                v
    使用命令行参数替换默认值(如果对应flag有设置)
                |
                v
    解析jsonschema校验规则(如果设置`EntryPointMeta.NotVerifySchema:true`)
                |
                v
    执行`config.Main`
    

watchmode

监听模式用于持续监听一个文件以保持配置最新,在更新模式下我们必须在命令行里显示的指定-c或者--config,来指向一个路径,支持两种方式指定路径:

  • path模式,即直接指定文件系统中的路径,这种方式只能针对本地文件系统,使用的路径可以为绝对路径或者相对路径
  • url模式,即使用url的形式指定路径,其形式为schema://user:password@host:port/path?params这种方式相对比较有扩展性,支持的获取方式有
    • 本地文件系统,使用schema可以为file, fs,使用的路径只能是绝对路径,比如file:///Users/mac/WORKSPACE/GITHUB/GolangTools/schema-entry-go/watch.json
    • docker容器中的文件系统,使用schemadockerfs,使用的路径只能是绝对路径,比如dockerfs:///Users/mac/WORKSPACE/GITHUB/GolangTools/schema-entry-go/watch.json
    • etcd中的内容,使用schemaetcd,其形式如etcd://localhost:9800/foo/bar?address=192.168.1.1:4324&address=192.168.1.2:4324&serialize=JSON,其中
      • host:port部分以及address部分填写etcd的访问地址,也就是说至少要有一个地址
      • path部分为etcd中的内容所在的key
      • 参数中的serialize指明序列化协议,一样的目前只支持JSON和YAML.
      • 其他支持的配置项还包括:
        • auto-sync-interval-ms
        • dial-timeout-ms
        • dial-keep-alive-time-ms
        • dial-keep-alive-timeout-ms
        • max-call-send-msg-size-bytes
        • max-call-recv-msg-size-bytes
        • reject-old-cluster
        • permit-without-stream
        • query-timeout-ms,请求etcd的超时,默认50ms

使用方法

整个使用流程可以拆分为如下步骤

  1. 定义一个配置结构体,并为其实现Main()接口,这个Main()接口就是业务的入口
  2. 使用NewEndPoint来构造一个叶子节点,如果有多个叶子节点可以用NewEntryPoint来构造根节点和枝节点用于串联叶子节点
  3. [可选]如果有根节点和枝节点则将各个节点串联成树
  4. 调用根节点的Parse(argv []string)方法解析配置,一般是写成root.Parse(os.Args)

下面是一个例子,例子中使用github.com/alecthomas/jsonschema在结构体构造时声明了jsonschema约束.

package main

import (
    "fmt"
    "os"
    "time"

    s "github.com/Golang-Tools/schema-entry-go/v2"
    jsoniter "github.com/json-iterator/go"
)

var json = jsoniter.ConfigCompatibleWithStandardLibrary

type C struct {
    A            int   `yaml:"aa" jsonschema:"required,title=a,description=测试int,maximum=10,default=10"`
    B            int   `yaml:"b" jsonschema:"required,title=b,description=测试int,maximum=10,default=100"`
    OK           bool  `json:"ok" jsonschema:"title=o,description=测试bool"`
    Field        []int `json:"field" jsonschema:"required,title=f,description=测试列表"`
    FieldDefault []int `json:"field_default" jsonschema:"required,title=d,description=测试列表默认值,default=1,default=2,default=3,default=4,default=5"`
    WatchValue   int   `json:"WatchValue" jsonschema:"required,title=w,description=测试监听"`
    s            int
}

func (c *C) Test() {
    fmt.Println(c)
}

func (c *C) Main() {
    c.Test()
    time.Sleep(time.Duration(1) * time.Minute)
}

func main() {
    root, _ := s.NewEntryPoint(s.WithName("foo"), s.WithDescription("测试用foo"), s.WithUsage("foo cmd test"))
    nodeb, _ := s.NewEntryPoint(s.WithName("bar"), s.WithDescription("测试用foo bar"), s.WithUsage("foo bar cmd test"))
    nodec, _ := s.NewEndPoint(new(C), s.WithName("par"), s.WithNotVerifySchema(),
        s.WithDefaultConfigFilePaths("conf.json", "config.json", "testconf.yml"),
        s.WithDescription("测试用foo bar par"),
        s.WithUsage("foo bar par cmd test"),
        s.WithLoadAllConfigFile(),
        s.WithWatchMode(),
    )
    nodec.OnRefresh(func(c *C) {
        c.Test()
    })
    os.Setenv("FOO_BAR_PAR_A", "123")
    nodec.SetParent(nodeb).SetParent(root).Parse(os.Args)
}

缺陷

  • 目前不支持命令行位置参数.(依赖的github.com/akamensky/argparse目前不支持)

  • 目前只支持如下几种数据类型(依赖的github.com/akamensky/argparse目前不支持)

    • int,float64,bool,string

    • []int,[]float64,[]string

    • 如果是[]int,[]float64,[]string这三种类型设置default需要像这样写

      FieldDefault []int `json:"field_default" jsonschema:"default=1,default=2,default=3,default=4,default=5"`
      

      它等价于JSONSchema中的default:[1,2,3,4,5]

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	//ErrNotAllowSetChildToEndPoint 叶子节点无法设置子节点
	ErrNotAllowSetChildToEndPoint = errors.New("not allow set child to endpoint")
	//ErrUnsupportedSchema 不支持的的schema类型
	ErrUnsupportedSchema = errors.New("unsupported schema")

	//ErrReregistCallBack 重复注册回调函数
	ErrReregistCallBack = errors.New("not allow re-regist callback")

	//ErrUnsupportedSerialization 不支持的序列化协议
	ErrUnsupportedSerialization = errors.New("unsupported serialization protocol")
	//ErrNotSetSerialize 未设置序列化协议
	ErrNotSetSerialize = errors.New("need to set serialize")

	//ErrEtcdKeyLenNotMatch etcd的key数量不匹配
	ErrEtcdKeyLenNotMatch = errors.New("etcd key len not match")
)

Functions

func GetNodeEnvPrefix

func GetNodeEnvPrefix(node EntryPointInterface) string

GetNodeEnvPrefix 获取实际的EnvPrefix

func GetNodeProg

func GetNodeProg(node EntryPointInterface) string

GetNodeProg 获取节点的prog值

func GetNodeProgList

func GetNodeProgList(node EntryPointInterface) []string

GetNodeProgList 获取节点的prog值

func ReflectFieldName

func ReflectFieldName(f reflect.StructField) string

ReflectFieldInfo 返回字段的基础信息 @returns string 对应名字

func RegistSubNode

func RegistSubNode(parent, child EntryPointInterface)

RegistSubNode 将一对节点互设为父子节点 @params parent EntryPointInterface 父节点 @params child EntryPointInterface 子节点

func WithConfig

func WithConfig(conf *EntryPointMeta) optparams.Option[EntryPointMeta]

WithConfig 使用EntryPointMeta实例设置配置

func WithDefaultConfigFilePaths

func WithDefaultConfigFilePaths(paths ...string) optparams.Option[EntryPointMeta]

WithDefaultConfigFilePaths 设置节点用法说明

func WithDescription

func WithDescription(desc string) optparams.Option[EntryPointMeta]

WithDescription 设置节点说明文本

func WithEnvPrefix

func WithEnvPrefix(prefix string) optparams.Option[EntryPointMeta]

WithEnvPrefix 设置节点用法说明

func WithLoadAllConfigFile

func WithLoadAllConfigFile() optparams.Option[EntryPointMeta]

WithLoadAllConfigFile 设置节点是加载全部配置文件,否则找到第一个后就停止搜索

func WithName

func WithName(name string) optparams.Option[EntryPointMeta]

WithName 设置节点名

func WithNotParseEnv

func WithNotParseEnv() optparams.Option[EntryPointMeta]

WithNotParseEnv 设置节点不解析环境变量

func WithNotVerifySchema

func WithNotVerifySchema() optparams.Option[EntryPointMeta]

WithNotVerifySchema 设置节点不校验配置的schema

func WithUsage

func WithUsage(usage string) optparams.Option[EntryPointMeta]

WithUsage 设置节点用法说明

func WithWatchMode

func WithWatchMode() optparams.Option[EntryPointMeta]

WithWatchMode 设置监听模式 在程序执行过程中监听`-c`(或`--config`)指定的配置文件url内容变更. 当出现变更时更新`EndPoint[T]`对象中的config对象,并根据其中的回调函数设置执行相应回调

Types

type EndPoint

type EndPoint[T EndPointConfigInterface] struct {
	// contains filtered or unexported fields
}

EntryPoint 节点类 @generics T EndPointConfigInterface 内部`config`字段的类型

func NewEndPoint

func NewEndPoint[T EndPointConfigInterface](config T, opts ...optparams.Option[EntryPointMeta]) (*EndPoint[T], error)

NewEndPoint创建一个节点对象 @generics T EndPointConfigInterface EntryPoint泛型的实例化参数 @params meta *EntryPointMeta 为节点的元信息

func (*EndPoint[T]) BeforeRefresh

func (ep *EndPoint[T]) BeforeRefresh(callback func([]byte, SupportedSerialization) bool) error

BeforeRefresh 注册刷新前执行 @generics T EndPointConfigInterface 内部`config`字段的类型 @params callback func([]byte, SupportedSerialization) bool 刷新前执行的函数,返回false则不会进行刷新

func (*EndPoint[T]) GenEtcdWatcher added in v2.1.0

func (ep *EndPoint[T]) GenEtcdWatcher(serialize_protocol SupportedSerialization, filepath string, config clientv3.Config) (StopWatchFunc, error)

GenEtcdWatcher 生成文件系统监听器 @generics T EndPointConfigInterface 内部`config`字段的类型 @params serialize_protocol SupportedSerialization 文件使用的序列化协议 @params filepath string 文件路径 @params config clientv3.Config etcd配置 @returns StopWatchFunc 停止监听函数 @returns error 程序错误

func (*EndPoint[T]) GenFSWatcher added in v2.1.0

func (ep *EndPoint[T]) GenFSWatcher(serialize_protocol SupportedSerialization, filepath string, indocker bool) (StopWatchFunc, error)

GenFSWatcher 生成文件系统监听器 @generics T EndPointConfigInterface 内部`config`字段的类型 @params serialize_protocol SupportedSerialization 使用的序列化协议 @params filepath string 文件路径 @params indocker bool 文件系统是否在docker中 @returns StopWatchFunc 停止监听函数 @returns error 程序错误

func (*EndPoint[T]) IsEndpoint

func (ep *EndPoint[T]) IsEndpoint() bool

func (*EndPoint[T]) IsRoot

func (ep *EndPoint[T]) IsRoot() bool

func (*EndPoint[T]) Meta

func (ep *EndPoint[T]) Meta() *EntryPointMeta

func (*EndPoint[T]) OnRefresh

func (ep *EndPoint[T]) OnRefresh(callback func(T)) error

BeforeRefresh 注册刷新前执行 @generics T EndPointConfigInterface 内部`config`字段的类型 @params callback func(T) bool 注册刷新后执行的操作

func (*EndPoint[T]) OnRefreshError

func (ep *EndPoint[T]) OnRefreshError(callback func(error)) error

OnRefreshError 注册刷新失败后执行的回调 @generics T EndPointConfigInterface 内部`config`字段的类型 @params callback func(T) bool 注册刷新失败后执行的回调

func (*EndPoint[T]) Parse

func (ep *EndPoint[T]) Parse(argv []string)

Parse 解析节点并加载配置,配置加载顺序为

func (*EndPoint[T]) Schema

func (ep *EndPoint[T]) Schema() []byte

func (*EndPoint[T]) SetChild

func (ep *EndPoint[T]) SetChild(child EntryPointInterface) error

func (*EndPoint[T]) SetParent

func (ep *EndPoint[T]) SetParent(parent EntryPointInterface) EntryPointInterface

type EndPointConfigInterface

type EndPointConfigInterface interface {
	Main() //进入时执行的程序
}

EndPointConfigInterface 叶子节点配置接口

type EntryPoint

type EntryPoint struct {
	// contains filtered or unexported fields
}

EntryPoint 节点类

func NewEntryPoint

func NewEntryPoint(opts ...optparams.Option[EntryPointMeta]) (*EntryPoint, error)

New 创建一个节点对象 @params meta *EntryPointMeta 为节点的元信息

func (*EntryPoint) IsEndpoint

func (ep *EntryPoint) IsEndpoint() bool

func (*EntryPoint) IsRoot

func (ep *EntryPoint) IsRoot() bool

func (*EntryPoint) Meta

func (ep *EntryPoint) Meta() *EntryPointMeta

func (*EntryPoint) Parse

func (ep *EntryPoint) Parse(argv []string)

Parse 解析节点生成命令行说明文档

func (*EntryPoint) Schema

func (ep *EntryPoint) Schema() []byte

func (*EntryPoint) SetChild

func (ep *EntryPoint) SetChild(child EntryPointInterface) error

func (*EntryPoint) SetParent

func (ep *EntryPoint) SetParent(parent EntryPointInterface) EntryPointInterface

type EntryPointInterface

type EntryPointInterface interface {
	Meta() *EntryPointMeta
	Schema() []byte
	IsRoot() bool
	IsEndpoint() bool
	SetChild(EntryPointInterface) error
	SetParent(EntryPointInterface) EntryPointInterface
	Parse([]string)
}

type EntryPointMeta

type EntryPointMeta struct {
	Name                   string   //节点名
	Description            string   //节点简介
	Usage                  string   //节点用法介绍
	DefaultConfigFilePaths []string //节点执行的默认配置文件路径列表
	LoadAllConfigFile      bool     //是否加载全部配置文件,否则找到第一个后就停止搜索
	NotParseEnv            bool     //是否不解析环境变量
	EnvPrefix              string   //解析环境变量时的前缀
	NotVerifySchema        bool     //是否不校验配置的schema
	// DebugMode              bool     //当设置为debugmode时才会打印中间过程的log
	WatchMode bool //启用配置监听模式,
	// contains filtered or unexported fields
}

EntryPointMeta 节点的元数据类

func (*EntryPointMeta) IsEndpoint

func (ep *EntryPointMeta) IsEndpoint() bool

IsEndpoint 判断节点是否为叶子节点

func (*EntryPointMeta) IsRoot

func (ep *EntryPointMeta) IsRoot() bool

IsRoot 判断节点的是否为根节点

func (*EntryPointMeta) Meta

func (ep *EntryPointMeta) Meta() *EntryPointMeta

Meta 获取节点的元数据

func (*EntryPointMeta) Parent

func (ep *EntryPointMeta) Parent() EntryPointInterface

func (*EntryPointMeta) SetChild

func (ep *EntryPointMeta) SetChild(child EntryPointInterface)

SetChild 为节点设置子节点 @Params child EntryPointInterface 要作为子节点的节点

func (*EntryPointMeta) SetParent

func (ep *EntryPointMeta) SetParent(parent EntryPointInterface)

SetParent 为节点设置父节点 @Params parent EntryPointInterface 要作为父节点的节点

func (*EntryPointMeta) Subcmds

func (ep *EntryPointMeta) Subcmds() map[string]EntryPointInterface

type StopWatchFunc

type StopWatchFunc func()

type SupportedSerialization

type SupportedSerialization int8
const (
	SerializationJSON SupportedSerialization = iota
	SerializationYAML
)

func ParseEtcdUrl added in v2.1.0

ParseEtcdUrl 解析Etcd的URL @params U *url.URL url信息 @returns SupportedSerialization 序列化协议 @returns string 路径,即key @returns clientv3.Config etcd连接配置 @returns time.Duration etcd请求超时 @returns error 解析错误

func ParseFSPath added in v2.1.0

func ParseFSPath(path string) (SupportedSerialization, string, error)

ParseFSUrl 解析文件系统的URL @params U *url.URL url信息 @returns SupportedSerialization 序列化协议 @returns string 路径 @returns error 解析错误

func ParseFSUrl added in v2.1.0

func ParseFSUrl(U *url.URL) (SupportedSerialization, string, error)

ParseFSUrl 解析文件系统的URL @params U *url.URL url信息 @returns SupportedSerialization 序列化协议 @returns string 路径 @returns error 解析错误

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL