-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add command in charmil cli (#207)
* feat: add command in charmil cli * feat: add command in charmil * fix: build issues * fix: typo in logging * chore: apply review suggestions
- Loading branch information
Showing
10 changed files
with
295 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
add.cmd.use: | ||
description: "Use of add command" | ||
one: "add" | ||
add.cmd.short: | ||
description: "Short description of add command" | ||
one: "add command creates a new command" | ||
add.cmd.long: | ||
description: "Long description of add command" | ||
one: "add command creates a new command in specified directory with locales" | ||
add.cmd.example: | ||
description: "Examples" | ||
one: "$ charmil add cliname" | ||
|
||
add.flag.cmdPath.name: | ||
description: "command Path flag" | ||
one: "cmdPath" | ||
add.flag.cmdPath.description: | ||
description: "description of command path" | ||
one: "command path where you want to create the command" | ||
add.flag.cmdName.name: | ||
description: "command name" | ||
one: "cmdName" | ||
add.flag.cmdName.description: | ||
description: "abc" | ||
one: "name of the new command" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
package add | ||
|
||
import ( | ||
"fmt" | ||
"html/template" | ||
"io/fs" | ||
"io/ioutil" | ||
"os" | ||
"path" | ||
"path/filepath" | ||
|
||
"github.com/aerogear/charmil/cli/internal/common/modname" | ||
"github.com/aerogear/charmil/cli/internal/factory" | ||
"github.com/aerogear/charmil/cli/internal/template/add" | ||
"github.com/aerogear/charmil/core/color" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
// TemplateData defines fields that will store all the data used for generating templates | ||
type TemplateData struct { | ||
// Stores value of the `CmdPath` local flag. Default Value: "." | ||
CmdPath string | ||
|
||
// Stores value of the `CmdName` local flag | ||
CmdName string | ||
|
||
// Stores the name of the root module (extracted from go.mod file) | ||
ModName string | ||
} | ||
|
||
// Initializes a zero-valued struct | ||
var tmplData = TemplateData{} | ||
|
||
func AddCommand(f *factory.Factory) (*cobra.Command, error) { | ||
cmd := &cobra.Command{ | ||
Use: f.Localizer.LocalizeByID("add.cmd.use"), | ||
Short: f.Localizer.LocalizeByID("add.cmd.short"), | ||
Long: f.Localizer.LocalizeByID("add.cmd.long"), | ||
Example: f.Localizer.LocalizeByID("add.cmd.example"), | ||
SilenceErrors: true, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
// Extracts the module name from `go.mod` file and stores it | ||
modName, err := modname.GetModuleName() | ||
if err != nil { | ||
return err | ||
} | ||
tmplData.ModName = modName | ||
|
||
if err := generateCommand(); err != nil { | ||
return err | ||
} | ||
|
||
f.Logger.Infof(color.Success("%s command has been created in %s directory\n"), tmplData.CmdName, tmplData.CmdPath+"/"+tmplData.CmdName) | ||
|
||
return nil | ||
|
||
}, | ||
} | ||
|
||
// Adds local flags | ||
cmd.Flags().StringVarP(&tmplData.CmdPath, f.Localizer.LocalizeByID("add.flag.cmdPath.name"), "c", ".", f.Localizer.LocalizeByID("add.flag.cmdPath.description")) | ||
cmd.Flags().StringVarP(&tmplData.CmdName, f.Localizer.LocalizeByID("add.flag.cmdName.name"), "s", "", f.Localizer.LocalizeByID("add.flag.cmdName.description")) | ||
|
||
// Marks the `cmdName` flag as required. | ||
// This causes the add command to report an | ||
// error if invoked without the `cmdName` flag. | ||
err := cmd.MarkFlagRequired("cmdName") | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return cmd, nil | ||
} | ||
|
||
// generateCommand function generates a command with it's locales file | ||
func generateCommand() error { | ||
|
||
// create a directory with command name | ||
if mkdirerr := os.MkdirAll(path.Join(tmplData.CmdPath, tmplData.CmdName), 0755); mkdirerr != nil { | ||
return mkdirerr | ||
} | ||
|
||
// walk through add templates folder | ||
err := fs.WalkDir(add.AddTemplates, ".", func(p string, info fs.DirEntry, err error) error { | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// creating templates from add templates folder | ||
// to the cmdPath directory(provided by user) | ||
var buf []byte | ||
if info.Name() == "cmdname.en.yaml" || info.Name() == "cmdname.tmpl" { | ||
buf, err = add.AddTemplates.ReadFile(info.Name()) | ||
if err != nil { | ||
return err | ||
} | ||
var ext string | ||
|
||
if info.Name() == "cmdname.en.yaml" { | ||
ext = ".en.yaml" | ||
} else { | ||
ext = ".go" | ||
} | ||
|
||
err = ioutil.WriteFile(path.Join(tmplData.CmdPath, tmplData.CmdName, tmplData.CmdName+ext), buf, 0600) | ||
if err != nil { | ||
fmt.Printf("Unable to write file: %v", err) | ||
} | ||
} | ||
|
||
// apply templates according to tmplData | ||
err = applyTemplates() | ||
return err | ||
|
||
}) | ||
|
||
if err != nil { | ||
return fmt.Errorf("failed to walk directory: %w", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// applyTemplates parses the files and apply templates | ||
func applyTemplates() error { | ||
err := filepath.Walk(path.Join(tmplData.CmdPath, tmplData.CmdName), | ||
func(path string, info os.FileInfo, err error) error { | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
fi, err := os.Stat(path) | ||
if err != nil { | ||
return fmt.Errorf("failed to read file info: %w", err) | ||
} | ||
|
||
if fi.IsDir() { | ||
return nil | ||
} | ||
|
||
tmpl, tmplErr := template.ParseFiles(path) | ||
if tmplErr != nil { | ||
return fmt.Errorf("failed to parse template: %w", err) | ||
} | ||
|
||
f, PathErr := os.Create(path) | ||
if PathErr != nil { | ||
return fmt.Errorf("failed to create file: %w", err) | ||
} | ||
|
||
// apply templateContext to the folder | ||
if err := tmpl.Execute(f, tmplData); err != nil { | ||
return fmt.Errorf("failed to execute template: %w", err) | ||
} | ||
|
||
return nil | ||
}) | ||
|
||
return err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package generate | ||
|
||
import ( | ||
"fmt" | ||
"html/template" | ||
"os" | ||
) | ||
|
||
// GenerateFileFromTemplate uses the template to generate a | ||
// new file using the specified file name and output path | ||
func GenerateFileFromTemplate(name, path, tmplContent string, placeholderData interface{}) error { | ||
// Creates a new file using the specified name and path | ||
f, err := os.Create(fmt.Sprintf("%s/%s", path, name)) | ||
if err != nil { | ||
return err | ||
} | ||
defer f.Close() | ||
|
||
// Adds content to the generated file using the specified template | ||
tmpl := template.Must(template.New(name).Parse(tmplContent)) | ||
err = tmpl.Execute(f, placeholderData) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package modname | ||
|
||
import ( | ||
"io/ioutil" | ||
|
||
"golang.org/x/mod/modfile" | ||
) | ||
|
||
// GetModuleName returns the module name extracted from the `go.mod` file | ||
func GetModuleName() (string, error) { | ||
// Stores the contents of `go.mod` file as a byte array | ||
goModBytes, err := ioutil.ReadFile("go.mod") | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
// Extracts module name from the passed `go.mod` file contents | ||
modName := modfile.ModulePath(goModBytes) | ||
|
||
return modName, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{{ .CmdName }}.cmd.use: | ||
description: "Use of {{ .CmdName }} command" | ||
one: "{{ .CmdName }}" | ||
{{ .CmdName }}.cmd.short: | ||
description: "Short description of {{ .CmdName }} command" | ||
one: "describe {{ .CmdName }}" | ||
{{ .CmdName }}.cmd.long: | ||
description: "Long description of {{ .CmdName }} command" | ||
one: "describe {{ .CmdName }}" | ||
{{ .CmdName }}.cmd.example: | ||
description: "Examples" | ||
one: "$ give examples of {{ .CmdName }}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package {{ .CmdName }} | ||
|
||
import ( | ||
"{{ .ModName }}/internal/factory" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
func {{ .CmdName }}(f *factory.Factory) *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: f.Localizer.LocalizeByID("{{ .CmdName }}.cmd.use"), | ||
Short: f.Localizer.LocalizeByID("{{ .CmdName }}.cmd.short"), | ||
Long: f.Localizer.LocalizeByID("{{ .CmdName }}.cmd.long"), | ||
Example: f.Localizer.LocalizeByID("{{ .CmdName }}.cmd.example"), | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
|
||
return nil | ||
}, | ||
} | ||
|
||
return cmd | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package add | ||
|
||
import "embed" | ||
|
||
// AddTemplates stores embedded contents of all the add template files | ||
//go:embed * | ||
var AddTemplates embed.FS |
Oops, something went wrong.