schemaentry

package module
v0.0.7 Latest Latest
Warning

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

Go to latest
Published: Oct 8, 2021 License: MIT Imports: 14 Imported by: 1

README

schema-entry-go

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

特性

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

概念和一些规则

节点

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

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

一个节点最多只能有一个父节点,但可以有多个子节点.节点与节点间可以使用RegistSubNode(parent,child EntryPointNode)函数来注册

参数的解析规则
  1. 所有节点都会解析其--help命令,叶子节点会解析命令,用法,说明,以及参数,其他节点则是解析其命令,说明和支持的子命令.

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

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

    说明使用EntryPointMeta.Usage设置.

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

    //EntryPointConfig 节点配置
    type EntryPointConfig interface {
        Main()
    }
    

    解析的流程如下:

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

使用方法

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

  1. 定义一个配置结构体,并为其实现Main()接口,这个Main()接口就是业务的入口
  2. 使用schema-entry-go.New(*EntryPointMeta, ...EntryPointConfig) (*EntryPoint, error)来构造一个解析节点,如果这个节点不作为叶子节点那可以不填...EntryPointConfig部分参数
  3. 使用schema-entry-go.RegistSubNode(parent *EntryPoint,child *EntryPoint)或者parent.RegistSubNode(child *EntryPoint)来构造命令树结构.
  4. 调用根节点的Parse(argv []string)方法解析配置,一般是写成root.Parse(os.Args)

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

package main

import (
    "fmt"
    "os"

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

var json = jsoniter.ConfigCompatibleWithStandardLibrary

type C struct {
    A     int   `json:"a" jsonschema:"required,title=field,description=测试列表"`
    Field []int `json:"field" jsonschema:"required,title=field,description=测试列表"`
    s     int
}

func (c *C) Main() {
    fmt.Println(c.Field)
    fmt.Println(c.A)
}

func main() {
    root, _ := s.New(&s.EntryPointMeta{Name: "foo", Usage: "foo cmd test"})
    nodeb, _ := s.New(&s.EntryPointMeta{Name: "bar", Usage: "foo bar cmd test"})
    nodec, _ := s.New(&s.EntryPointMeta{Name: "par", Usage: "foo bar par cmd test"}, &C{
        Field: []int{1, 2, 3},
    })
    s.RegistSubNode(root, nodeb)
    nodeb.RegistSubNode(nodec)
    os.Setenv("FOO_BAR_PAR_A", "123")
    root.Parse([]string{"foo", "bar", "par", "--Field=4", "--Field=5", "--Field=6"})
}

使用时需要注意:

  • 函数New,RegistSubNode以及节点对象的RegistSubNode方法中传入的都是指针而非值.

缺陷

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

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

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

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetNodeEnvPrefix added in v0.0.3

func GetNodeEnvPrefix(node EntryPointNode) string

GetNodeEnvPrefix 获取实际的EnvPrefix

func GetNodeProg

func GetNodeProg(node EntryPointNode) string

GetNodeProg 获取节点的prog值

func GetNodeProgList

func GetNodeProgList(node EntryPointNode) []string

GetNodeProgList 获取节点的prog值

func RegistSubNode

func RegistSubNode(parent, child EntryPointNode)

RegistSubNode 为节点注册子节点

Types

type EntryPoint

type EntryPoint struct {
	*EntryPointMeta

	Schema []byte
	// contains filtered or unexported fields
}

EntryPoint 节点类

func New

func New(meta *EntryPointMeta, config ...EntryPointConfig) (*EntryPoint, error)

New 创建一个节点对象 @Params meta *EntryPointMeta 为节点的元信息 @params config ...EntryPointConfig 为一个定义好的struct的对象的指针,根节点和中间节点可以不设置,叶子节点如果不设置则无法执行,最多设置一个

func (*EntryPoint) ConfigPtrFromArgparse

func (ep *EntryPoint) ConfigPtrFromArgparse(parser *argparse.Parser, argv []string) (*string, map[string]interface{}, error)

ConfigPtrFromArgparse 构造命令行参数解析,并获取flag的ptr @Params parser *argparse.Parser flag解析器 @Params argv []string 待解析的命令行参数 @Returns *string 指定configfile位置字符串 @Returns map[string]interface{} flag的ptr位置 @Returns error 错误信息

func (*EntryPoint) GetConfigFromConfigFile

func (ep *EntryPoint) GetConfigFromConfigFile() error

GetConfigFromConfigFile 从设置的或者默认配置文件中获取配置

func (*EntryPoint) GetEnvPrefix added in v0.0.3

func (ep *EntryPoint) GetEnvPrefix() string

GetEnvPrefix 获取实际的EnvPrefix

func (*EntryPoint) Parse

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

Parse 解析节点

func (*EntryPoint) ParseStruct

func (ep *EntryPoint) ParseStruct(flagConfptr map[string]interface{}) error

ParseStruct 解析结构体,构造命令行参数解析和环境变量解析,并设置到对象的Config值中 @Params flagConfptr map[string]interface{} 命令行参数除了指定的配置文件位置外的参数->值的指针的映射 @Returns error 解析过程中的错误

func (*EntryPoint) PassArgs

func (ep *EntryPoint) PassArgs(parser *argparse.Parser, argv []string)

PassArgs 解析叶子节点 @Params parser *argparse.Parser 命令行参数解析器对象 @Params argv []string 待解析的命令行参数

func (EntryPoint) PassArgsTosub

func (ep EntryPoint) PassArgsTosub(parser *argparse.Parser, argv []string)

PassArgsTosub 将解析传导给子节点

func (*EntryPoint) RegistConfig

func (ep *EntryPoint) RegistConfig(config EntryPointConfig)

RegistConfig 将对象注册进节点 如果创建时没有设置,那么可以用这个方法设置,

func (*EntryPoint) RegistSubNode

func (ep *EntryPoint) RegistSubNode(child EntryPointNode)

RegistSubNode 将一个节点注册为当前节点的子节点 @Params child EntryPointNode 节点对象,注意必须传入的是指针

func (*EntryPoint) VerifyConfig

func (ep *EntryPoint) VerifyConfig() bool

VerifyConfig 验证config是否符合要求

type EntryPointConfig

type EntryPointConfig interface {
	Main()
}

EntryPointConfig 叶子节点配置接口

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
	// 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) SetChild

func (ep *EntryPointMeta) SetChild(child EntryPointNode)

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

func (*EntryPointMeta) SetParent

func (ep *EntryPointMeta) SetParent(parent EntryPointNode)

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

type EntryPointNode

type EntryPointNode interface {
	Meta() *EntryPointMeta
	IsRoot() bool
	IsEndpoint() bool
	SetChild(EntryPointNode)
	SetParent(EntryPointNode)
	Parse([]string)
}

EntryPointNode 节点接口

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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