如何将命令状态传递给 Cobra CLI 中的 Postrun 函数?

huangapple go评论77阅读模式
英文:

how do I pass a command status to Postrun in cobra cli

问题

Cobra CLI支持在命令执行后调用PostRun。

https://github.com/spf13/cobra#prerun-and-postrun-hooks

我如何将命令状态传递给PostRun调用?
我需要在命令执行后将其状态发送到服务器。

英文:

Cobra CLI has support for PostRun to invoke after execution of a command.

https://github.com/spf13/cobra#prerun-and-postrun-hooks

How do I pass on the command status to PostRun call?
I have requirement of posting the command status after its execution to a server

答案1

得分: 2

更清晰的方法是利用cobra命令中提供的注释。

package main

import (
    "fmt"

    "github.com/spf13/cobra"
)


func main() {
    var rootCmd = &cobra.Command{
        Use:   "root [sub]",
        Short: "My root command",
        Run: func(cmd *cobra.Command, args []string) {
            // 在这里进行处理
            // 设置命令的注释
            cmd.Annotations = make(map[string]string)
            cmd.Annotations["status"] = "status_goes_here"
            cmd.Annotations["error"] = "error_goes_here"
        },
        PostRun: func(cmd *cobra.Command, args []string) {
            // 检索注释
            fmt.Println(cmd.Annotations["status"])
            fmt.Println(cmd.Annotations["error"])
        },
    }

    rootCmd.SetArgs([]string{"sub", "arg1", "arg2"})
    rootCmd.Execute()
}

我真的很喜欢@Bracken在这里采取的方法,尽管有一些调整可以使其工作。

package main

import (
    "fmt"
    "errors"

    "github.com/spf13/cobra"
)

type wrapper struct {
    err error
}

// RunE在出现错误的情况下无法继续执行,从而不执行PostRun操作
func (w *wrapper) Run(f func(cmd *cobra.Command, args []string) error) func(cmd *cobra.Command, args []string) {
    return func(cmd *cobra.Command, args []string) {
        err := f(cmd, args)
        w.err = err
    }
}

func (w *wrapper) PostRun(f func(cmd *cobra.Command, args []string, cmdErr error)) func(cmd *cobra.Command, args []string) {
    return func(cmd *cobra.Command, args []string) {
        f(cmd, args, w.err)
    }
}

func main() {
    cmdWrap := wrapper{}
    var rootCmd = &cobra.Command{
        Use:   "root [sub]",
        Short: "My root command",
        Run: cmdWrap.Run(func(cmd *cobra.Command, args []string) error {
            return errors.New("i'm not in the book, you know")
        }),
        PostRun: cmdWrap.PostRun(func(cmd *cobra.Command, args []string, cmdErr error) {
            fmt.Printf("error was %v\n", cmdErr)
        }),
    }

    rootCmd.SetArgs([]string{"sub", "arg1", "arg2"})
    rootCmd.Execute()
}

----- 旧回答 -----

如果我理解正确,需要将一些状态从cmd.Execute传递到PostRun。

您可以使用ExecuteContext(ctx context.Context)方法而不是Execute(),并在上下文中设置所需的键值对。

ctx := context.WithValue(context.Background(), "status", "statusValue")
rootCmd.ExecuteContext(ctx)

在PostRun中可以使用cmd.Context()检索相同的值。

PostRun: func(cmd *cobra.Command, args []string) {
   ctx := cmd.Context()
   status := ctx.Value("status")
}
英文:

Cleaner approach would be to leverage the Annotations provided in cobra command

package main

import (
    "fmt"

    "github.com/spf13/cobra"
)


func main() {
    var rootCmd = &cobra.Command{
        Use:   "root [sub]",
        Short: "My root command",
        Run: func(cmd *cobra.Command, args []string) {
            // Do your processing here
            // Set the command annotations
            cmd.Annotations = make(map[string]string)
            cmd.Annotations["status"] = "status_goes_here"
            cmd.Annotations["error"] = "error_goes_here"
        },
        PostRun: func(cmd *cobra.Command, args []string) {
            // Retrieve the annotations
            fmt.Println(cmd.Annotations["status"])
            fmt.Println(cmd.Annotations["error"])
        },
    }

    rootCmd.SetArgs([]string{"sub", "arg1", "arg2"})
    rootCmd.Execute()
}

Really liked the approach @Bracken has taken here, Although there are some tweaks that will make it work

package main

import (
    "fmt"
    "errors"

    "github.com/spf13/cobra"
)

type wrapper struct {
    err error
}

// RunE fails to proceed further in case of error resulting in not executing PostRun actions
func (w *wrapper) Run(f func(cmd *cobra.Command, args []string) error) func(cmd *cobra.Command, args []string) {
    return func(cmd *cobra.Command, args []string) {
        err := f(cmd, args)
        w.err = err
    }
}

func (w *wrapper) PostRun(f func(cmd *cobra.Command, args []string, cmdErr error)) func(cmd *cobra.Command, args []string) {
    return func(cmd *cobra.Command, args []string) {
        f(cmd, args, w.err)
    }
}

func main() {
    cmdWrap := wrapper{}
    var rootCmd = &cobra.Command{
        Use:   "root [sub]",
        Short: "My root command",
        Run: cmdWrap.Run(func(cmd *cobra.Command, args []string) error {
            return errors.New("i'm not in the book, you know")
        }),
        PostRun: cmdWrap.PostRun(func(cmd *cobra.Command, args []string, cmdErr error) {
            fmt.Printf("error was %v\n", cmdErr)
        }),
    }

    rootCmd.SetArgs([]string{"sub", "arg1", "arg2"})
    rootCmd.Execute()
}

----- Old Answer -----

If I understand it right, There is some status that needs to be passed from cmd.Execute to PostRun.

You can use ExecuteContext(ctx context.Context) method instead of Execute() and set whatever key-value needs to be set in context.

ctx := context.WithValue(context.Background(), "status", "statusValue")
rootCmd.ExecuteContext(ctx)

Same values can be Retrieved inside PostRun using cmd.Context()

PostRun: func(cmd *cobra.Command, args []string) {
   ctx := cmd.Context()
   status := ctx.Value("status")
}

答案2

得分: 0

我会使用高阶函数来包装你的Run(或RunE)函数和PostRun函数,以捕获错误或恐慌,并将它们传递给你的PostRun函数:

package main

import (
	"fmt"

	"github.com/spf13/cobra"
)

type wrapper struct {
	err error
}

func (w *wrapper) RunE(f func(cmd *cobra.Command, args []string) error) func(cmd *cobra.Command, args []string) error {
	return func(cmd *cobra.Command, args []string) (err error) {
		defer func() {
			if r := recover(); r != nil {
				err = fmt.Errorf("panic: %v", r)
				w.err = err
			}
		}()
		err = f(cmd, args)
		w.err = err
		return
	}
}

func (w *wrapper) PostRun(f func(cmd *cobra.Command, args []string, cmdErr error)) func(cmd *cobra.Command, args []string) {
	return func(cmd *cobra.Command, args []string) {
		f(cmd, args, w.err)
	}
}

func main() {
	cmdWrap := wrapper{}
	var cmdFail = &cobra.Command{
		Use:   "fail",
		Short: "Doesn't work",
		RunE: cmdWrap.RunE(func(cmd *cobra.Command, args []string) error {
			panic("i'm not in the book, you know")
		}),
		PostRun: cmdWrap.PostRun(func(cmd *cobra.Command, args []string, cmdErr error) {
			fmt.Printf("error was %v\n", cmdErr)
		}),
	}

	var rootCmd = &cobra.Command{}
	rootCmd.AddCommand(cmdFail)
	rootCmd.Execute()
}
英文:

I would wrap your Run (or RunE) function and your PostRun function using high order functions to catch errors or panics and then pass them into your PostRun:

package main
import (
"fmt"
"github.com/spf13/cobra"
)
type wrapper struct {
err error
}
func (w *wrapper) RunE(f func(cmd *cobra.Command, args []string) error) func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("panic: %v", r)
w.err = err
}
}()
err = f(cmd, args)
w.err = err
return
}
}
func (w *wrapper) PostRun(f func(cmd *cobra.Command, args []string, cmdErr error)) func(cmd *cobra.Command, args []string) {
return func(cmd *cobra.Command, args []string) {
f(cmd, args, w.err)
}
}
func main() {
cmdWrap := wrapper{}
var cmdFail = &cobra.Command{
Use:   "fail",
Short: "Doesn't work",
RunE: cmdWrap.RunE(func(cmd *cobra.Command, args []string) error {
panic("i'm not in the book, you know")
}),
PostRun: cmdWrap.PostRun(func(cmd *cobra.Command, args []string, cmdErr error) {
fmt.Printf("error was %v\n", cmdErr)
}),
}
var rootCmd = &cobra.Command{}
rootCmd.AddCommand(cmdFail)
rootCmd.Execute()
}

huangapple
  • 本文由 发表于 2021年6月10日 06:24:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/67912398.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定