我一直在努力让README为我自动生成一些Cobra CLI程序。起初,事情进展顺利,我得到了第一个生成良好的README。然而,由于某种原因,使用相同功能的第二次尝试失败了。因此,在几次尝试让它发挥作用后,我决定在这里发布一个问题。
所有代码都可以找到
here
使用Makefile(make generate是生成README文件的命令)。由于某种原因,未生成的模板将显示为空字符串。
生成的README和一个空字符串的README使用相同的代码。以下是共享代码:
package cmdhandler
import (
"bufio"
"bytes"
"errors"
"fmt"
"strings"
"text/template"
"github.com/MakeNowJust/heredoc"
"github.com/davecgh/go-spew/spew"
cmdtomd "github.com/pjkaufman/go-go-gadgets/pkg/cmd-to-md"
filehandler "github.com/pjkaufman/go-go-gadgets/pkg/file-handler"
"github.com/pjkaufman/go-go-gadgets/pkg/logger"
"github.com/spf13/cobra"
)
var generationDir string
const GenerationDirArgEmpty = "generation-dir must have a non-whitespace value"
type TmplData struct {
CommandStrings string
Todos []string
Description string
Title string
CustomValues map[string]any
}
func AddGenerateCmd(rootCmd *cobra.Command, title, description string, todos []string, getCustomValues func(string) (map[string]any, error)) {
var generateCmd = &cobra.Command{
Use: "generate",
Short: "Generates the readme file for the program",
Example: heredoc.Doc(`
` + rootCmd.Use + ` generate -d ./` + rootCmd.Use + `
will look for a file called README.md.tmpl and if it is found generate a readme based
on that file and the file command info.
`),
Run: func(cmd *cobra.Command, args []string) {
err := ValidateGenerateFlags(generationDir)
if err != nil {
logger.WriteError(err.Error())
}
err = filehandler.FolderMustExist(generationDir, "generation-dir")
if err != nil {
logger.WriteError(err.Error())
}
tmpl, err := template.ParseFiles(filehandler.JoinPath(generationDir, "README.md.tmpl"))
if err != nil {
logger.WriteError(err.Error())
}
var customValues = make(map[string]any)
if getCustomValues != nil {
customValues, err = getCustomValues(generationDir)
if err != nil {
logger.WriteError(err.Error())
}
}
var b bytes.Buffer
writer := bufio.NewWriter(&b)
err = tmpl.Execute(writer, TmplData{
CommandStrings: cmdtomd.RootToMd(rootCmd),
Todos: todos,
Description: description,
Title: title,
CustomValues: customValues,
})
if err != nil {
logger.WriteError(err.Error())
}
spew.Dump(TmplData{
CommandStrings: cmdtomd.RootToMd(rootCmd),
Todos: todos,
Description: description,
Title: title,
CustomValues: customValues,
})
err = filehandler.WriteFileContents(filehandler.JoinPath(generationDir, "README.md"), b.String())
if err != nil {
logger.WriteError(err.Error())
}
},
}
rootCmd.AddCommand(generateCmd)
generateCmd.Flags().StringVarP(&generationDir, "generation-dir", "g", "", "the path to the base folder of the "+rootCmd.Use+" program source code")
err := generateCmd.MarkFlagRequired("generation-dir")
if err != nil {
logger.WriteError(fmt.Sprintf(`failed to mark flag "generation-dir" as required on generate command: %v`, err))
}
// keep from showing up in the output of the command generation
generateCmd.Hidden = true
}
func ValidateGenerateFlags(generationDir string) error {
if strings.TrimSpace(generationDir) == "" {
return errors.New(GenerationDirArgEmpty)
}
return nil
}
使用此逻辑但无法正常工作的代码:
//go:build generate
package cmd
import (
cmdhandler "github.com/pjkaufman/go-go-gadgets/pkg/cmd-handler"
)
const (
title = "Jpeg and Png Processor"
description = `This is meant to be a replacement for my usage of imgp.
Currently I use imgp for the following things:
- image resizing
- exif data removal
- image quality setting
Given how this works, I find it easier to just go ahead and do a simple program in Go to see how things stack up and not be so reliant on Python. This also helps me learn some more about imaging processing as well. So a win-win in my book.`
)
func init() {
cmdhandler.AddGenerateCmd(rootCmd, title, description, []string{
"Resize png test",
}, nil)
}
传入的模板是:
<!-- This file is generated from https://github.com/pjkaufman/go-go-gadgets/jp-proc/README.md.tmpl. Please make any necessary changes there. -->
# {{ .Title }}
{{ .Description }}
## How does this program compare with imgp?
| Operation | Original Size | New Size (imgp) | New Size (imgp with optimize flag) | New Size (jp-proc) |
| --------- | ------------- | --------------- | ---------------------------------- | ------------------ |
| Resize jpeg to 800x600 and remove exif data | 3.4M | 57KB | 56KB | 68KB |
| Resize jpeg to 800x600 and remove exif data and set quality to 40 | 3.4M | 32KB | 28KB | 37KB |
{{- if .Todos }}
## TODOs
{{- range .Todos }}
- {{ . }}
{{- end}}
{{- end}}
## Commands
{{ .CommandStrings }}
我使用相同的模板制作了一个示例程序,它确实可以工作,但由于某种原因,我无法使其他设置工作。以下是正在工作的独立程序:
package main
import (
"log"
"os"
"text/template"
)
const format = `# {{ .Title }}
{{ .Description }}
## How does this program compare with imgp?
| Operation | Original Size | New Size (imgp) | New Size (imgp with optimize flag) | New Size (jp-proc) |
| --------- | ------------- | --------------- | ---------------------------------- | ------------------ |
| Resize jpeg to 800x600 and remove exif data | 3.4M | 57KB | 56KB | 68KB |
| Resize jpeg to 800x600 and remove exif data and set quality to 40 | 3.4M | 32KB | 28KB | 37KB |
{{- if .Todos }}
## TODOs
{{- range .Todos }}
- {{ . }}
{{- end}}
{{- end}}
## Commands
{{ .CommandStrings }}
`
type TmplData struct {
CommandStrings string
Todos []string
Description string
Title string
CustomValues map[string]any
}
func main() {
test := template.New("testTemp")
tmpl, err := test.Parse(format)
if err != nil {
log.Fatal(err)
}
err = tmpl.ExecuteTemplate(os.Stdout, "testTemp", TmplData{
Title: "Test Title",
Description: "This is a test template",
Todos: []string{
"TODO 1",
"TODO 2",
},
CommandStrings: "Some command string text here...",
})
if err != nil {
log.Fatal(err)
}
}
你知道为什么模板可以在独立程序中工作,但不能在cobra命令中工作吗?
如果有任何其他信息有帮助,请告诉我。谢谢