1 Star 0 Fork 0

go-libs/console

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
command.go 7.20 KB
一键复制 编辑 原始数据 按行查看 历史
非一般 提交于 2024-08-09 14:21 . parse module name and folder
// Licensed 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.
//
// Author: wsfuyibing <682805@qq.com>
// Date: 2024-07-18
package src
import (
"context"
"errors"
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
)
// Command
// is a component used to schedule in container.
type Command struct {
defaulter bool
keys map[string]string
name, description string
options map[string]*Option
provider Provider
}
// NewCommand
// creates a new command instance.
func NewCommand(name string) *Command {
return &Command{
name: name,
keys: make(map[string]string),
options: make(map[string]*Option),
}
}
// GenerateModule
// generate application module name and working path relatives with
// working directory.
func (o *Command) GenerateModule(path string) (name, folder string) {
var (
body []byte
err error
folders = make([]string, 0)
info os.FileInfo
src string
regex = regexp.MustCompile(`^([a-zA-Z]+):`)
regexFolder = regexp.MustCompile(`/([^/]+)$`)
regexModule = regexp.MustCompile(`module\s+([^\n]+)`)
)
// Scan until root.
for {
// Return error
// if calculate absolute path failed.
if path, err = filepath.Abs(path); err != nil {
break
}
// Break loop
// until root path.
if path == "/" || regex.MatchString(path) {
break
}
// Check file
// for go.mod of an application.
src = fmt.Sprintf(`%s/go.mod`, path)
if info, err = os.Stat(src); err != nil {
// Goto
// parent folder if module file not found.
if errors.Is(err, os.ErrNotExist) {
// Collect
// folder name.
if m := regexFolder.FindStringSubmatch(path); len(m) > 0 {
folders = append(folders, m[1])
}
// Reset and goto parent.
err = nil
path = fmt.Sprintf(`%s/../`, path)
continue
}
// Break
// for stat failed.
break
}
// Break
// for target is a directory.
if info.IsDir() {
break
}
// Match content.
if body, err = os.ReadFile(src); err == nil {
if m := regexModule.FindStringSubmatch(string(body)); len(m) > 0 {
name = strings.TrimSpace(m[1])
}
}
break
}
// Build folders.
if name != "" {
if n := len(folders); n > 0 {
ks := make([]string, 0)
for i := n - 1; i >= 0; i-- {
ks = append(ks, folders[i])
}
folder = strings.Join(ks, "/")
}
}
return
}
// Add
// adds an options list into command.
func (o *Command) Add(options ...*Option) {
// Iterate options in parameters.
for _, opt := range options {
// Ignore nil option.
if opt == nil {
continue
}
// Ignore duplicated option.
if _, ok := o.options[opt.name]; ok {
continue
}
// Set mapping with full name.
o.options[opt.name] = opt
// Set keys mapping with full name.
o.keys[opt.name] = opt.name
// Set keys mapping with short name.
if opt.shortName != "" {
o.keys[opt.shortName] = opt.name
}
}
}
// GetDescription
// returns a command description.
func (o *Command) GetDescription() string {
return o.description
}
// GetName
// returns a command name.
//
// Code:
// println(cmd.GetName())
//
// Output:
// example
func (o *Command) GetName() string {
return o.name
}
// GetOption
// returns an option in command if exists.
//
// Code:
// opt, has := cmd.GetOption("key")
//
// Output:
// &Option{}, true
func (o *Command) GetOption(key string) (opt *Option, has bool) {
if name, ok := o.keys[key]; ok {
opt, has = o.options[name]
}
return
}
// GetOptions
// returns an option mapping.
//
// Output:
// {
// "key": &Option{...},
// }
func (o *Command) GetOptions() map[string]*Option {
return o.options
}
// SetDescription
// set description for command.
func (o *Command) SetDescription(description string) *Command {
o.description = strings.TrimSpace(description)
return o
}
// SetProvider
// set command provider. Method's in provider will be called when scheduler fired.
func (o *Command) SetProvider(provider Provider) *Command {
o.provider = provider
return o
}
// ToScript
// convert runtime command as runnable script.
//
// gen:model --key="value" --null
func (o *Command) ToScript() (script string) {
var (
keys = make([]string, 0)
mapper = make(map[string]*Option)
)
// Iterate
// options in command and specified.
for _, opt := range o.options {
// Ignore
// nil or not specified option.
if opt == nil || !opt.GetSpecified() {
continue
}
// Append
// to list.
keys = append(keys, opt.name)
mapper[opt.name] = opt
}
// Build
// with sorted keys.
script = o.name
for _, key := range keys {
if opt, ok := mapper[key]; ok {
if opt.kind == KindNull {
script += fmt.Sprintf(` --%s`, opt.name)
} else {
script += fmt.Sprintf(` --%s="%s"`, opt.name, opt.ToString())
}
}
}
return
}
// +---------------------------------------------------------------------------+
// | Access methods |
// +---------------------------------------------------------------------------+
// FormatDescription
// returns a string list for description if set and not empty.
func (o *Command) formatDescription() []string {
if o.description == "" {
return []string{}
}
return strings.Split(o.description, "\n")
}
// Run
// runs the command by schedule provider methods.
func (o *Command) run(ctx context.Context, container *Container) {
var err error
// Before handler.
if v, ok := o.provider.(ProviderBefore); ok {
if err = v.Before(ctx, container, o); err != nil {
container.GetOutput().Error(`%v`, err)
return
}
}
// Runner handler.
if err = o.provider.Run(ctx, container, o); err != nil {
container.GetOutput().Error(`%v`, err)
}
// After handler.
if v, ok := o.provider.(ProviderAfter); ok {
v.After(ctx, container, o, err)
}
}
// Verify
// verifies the command access.
func (o *Command) verify(container *Container) (success bool) {
// Iterate
// configuration in config file then assign it.
if c := Config.GetCommand(o.name); c != nil {
for k, v := range c.Options {
if opt, has := o.GetOption(k); has {
opt.assign(v)
continue
}
container.GetOutput().Error(`unsupported config option: %s`, k)
return false
}
}
// Iterate
// options in command-line arguments then assign it.
for k, v := range container.argument.GetOptions() {
// Defined in command-line arguments.
if opt, has := o.GetOption(k); has {
opt.assign(v)
continue
}
// Not defined in console.
if len(k) == 1 {
container.GetOutput().Error(`unsupported option: -%s`, k)
} else {
container.GetOutput().Error(`unsupported option: --%s`, k)
}
return false
}
// Validate
// command options.
for _, opt := range o.options {
if err := opt.validate(); err != nil {
container.GetOutput().Error(`%v`, err)
return false
}
}
return true
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/go-libs/console.git
git@gitee.com:go-libs/console.git
go-libs
console
console
v1.0.5

搜索帮助