Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Framework flag shell completion #80

47 changes: 19 additions & 28 deletions cmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/melkeydev/go-blueprint/cmd/frameworks"
"github.com/melkeydev/go-blueprint/cmd/program"
"github.com/melkeydev/go-blueprint/cmd/steps"
"github.com/melkeydev/go-blueprint/cmd/ui/multiInput"
Expand All @@ -30,17 +31,22 @@ const logo = `
`

var (
logoStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#01FAC6")).Bold(true)
tipMsgStyle = lipgloss.NewStyle().PaddingLeft(1).Foreground(lipgloss.Color("190")).Italic(true)
endingMsgStyle = lipgloss.NewStyle().PaddingLeft(1).Foreground(lipgloss.Color("170")).Bold(true)
allowedProjectTypes = []string{"chi", "gin", "fiber", "gorilla/mux", "httprouter", "standard-library", "echo"}
logoStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#01FAC6")).Bold(true)
tipMsgStyle = lipgloss.NewStyle().PaddingLeft(1).Foreground(lipgloss.Color("190")).Italic(true)
endingMsgStyle = lipgloss.NewStyle().PaddingLeft(1).Foreground(lipgloss.Color("170")).Bold(true)
)

func init() {
var frameworkFlag frameworks.Framework

rootCmd.AddCommand(createCmd)

createCmd.Flags().StringP("name", "n", "", "Name of project to create")
createCmd.Flags().StringP("framework", "f", "", fmt.Sprintf("Framework to use. Allowed values: %s", strings.Join(allowedProjectTypes, ", ")))
createCmd.Flags().VarP(&frameworkFlag, "framework", "f", fmt.Sprintf("Framework to use. Allowed values: %s", strings.Join(frameworks.AllowedProjectTypes, ", ")))

This comment was marked as resolved.


if err := createCmd.RegisterFlagCompletionFunc("framework", frameworks.FrameworkCompletion); err != nil {
log.Fatal(err)
}
}

// createCmd defines the "create" command for the CLI
Expand All @@ -59,19 +65,15 @@ var createCmd = &cobra.Command{
isInteractive := !utils.HasChangedFlag(cmd.Flags())

flagName := cmd.Flag("name").Value.String()
flagFramework := cmd.Flag("framework").Value.String()

if flagFramework != "" {
isValid := isValidProjectType(flagFramework, allowedProjectTypes)
if !isValid {
cobra.CheckErr(fmt.Errorf("Project type '%s' is not valid. Valid types are: %s", flagFramework, strings.Join(allowedProjectTypes, ", ")))
}
}
// VarP always returns a valid option, if the option is not
// valid the program errors out
flagFramework := frameworks.Framework(cmd.Flag("framework").Value.String())

project := &program.Project{
FrameworkMap: make(map[string]program.Framework),
FrameworkMap: make(map[frameworks.Framework]program.Framework),
ProjectName: flagName,
ProjectType: strings.ReplaceAll(flagFramework, "-", " "),
ProjectType: flagFramework,
}

steps := steps.InitSteps(&options)
Expand All @@ -86,7 +88,7 @@ var createCmd = &cobra.Command{
project.ExitCLI(tprogram)

project.ProjectName = options.ProjectName.Output
cmd.Flag("name").Value.Set(project.ProjectName)
_ = cmd.Flag("name").Value.Set(project.ProjectName)
}

if project.ProjectType == "" {
Expand All @@ -101,8 +103,8 @@ var createCmd = &cobra.Command{
*step.Field = s.Choice
}

project.ProjectType = strings.ToLower(options.ProjectType)
cmd.Flag("framework").Value.Set(project.ProjectType)
project.ProjectType = options.ProjectType
_ = cmd.Flag("framework").Value.Set(project.ProjectType.String())
}

currentWorkingDir, err := os.Getwd()
Expand Down Expand Up @@ -130,14 +132,3 @@ var createCmd = &cobra.Command{
}
},
}

// isValidProjectType checks if the inputted project type matches
// the currently supported list of project types
func isValidProjectType(input string, allowedTypes []string) bool {
for _, t := range allowedTypes {
if input == t {
return true
}
}
return false
}
56 changes: 56 additions & 0 deletions cmd/frameworks/frameworkFlag.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package frameworks

import (
"fmt"
"strings"

"github.com/spf13/cobra"
)

type Framework string

// These are all the current frameworks supported, if you want to add one you
// can simply copy and past a line here. Do not forget to also add it into the
// AllowedProjectTypes slice too!
const (
Chi Framework = "chi"
Gin Framework = "gin"
Fiber Framework = "fiber"
GorillaMux Framework = "gorilla/mux"
HttpRouter Framework = "httprouter"
StandardLibrary Framework = "standard-library"
Echo Framework = "echo"
)

var AllowedProjectTypes = []string{string(Chi), string(Gin), string(Fiber), string(GorillaMux), string(HttpRouter), string(StandardLibrary), string(Echo)}

// This interface is required on a type to make it useable as a flag
//
// type Value interface {
// String() string
// Set(string) error
// Type() string
// }
func (f Framework) String() string {
return string(f)
}

func (f *Framework) Type() string {
return "Framework"
}

func (f *Framework) Set(value string) error {
switch value {
case Chi.String(), Gin.String(), Fiber.String(), GorillaMux.String(), HttpRouter.String(), StandardLibrary.String(), Echo.String():
*f = Framework(value)
return nil
default:
return fmt.Errorf("Framework to use. Allowed values: %s", strings.Join(AllowedProjectTypes, ", "))
}
}

// This function returns the options that are shown to the user on shell
// completions for the -f or --framework flag
func FrameworkCompletion(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return AllowedProjectTypes, cobra.ShellCompDirectiveDefault
}
22 changes: 12 additions & 10 deletions cmd/program/program.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import (
"log"
"os"
"strings"

tea "github.com/charmbracelet/bubbletea"
"github.com/melkeydev/go-blueprint/cmd/frameworks"
tpl "github.com/melkeydev/go-blueprint/cmd/template"
"github.com/melkeydev/go-blueprint/cmd/utils"
"github.com/spf13/cobra"
Expand All @@ -20,8 +22,8 @@ type Project struct {
ProjectName string
Exit bool
AbsolutePath string
ProjectType string
FrameworkMap map[string]Framework
ProjectType frameworks.Framework
FrameworkMap map[frameworks.Framework]Framework
}

// A Framework contains the name and templater for a
Expand Down Expand Up @@ -66,37 +68,37 @@ func (p *Project) ExitCLI(tprogram *tea.Program) {
// createFrameWorkMap adds the current supported
// Frameworks into a Project's FrameworkMap
func (p *Project) createFrameworkMap() {
p.FrameworkMap["chi"] = Framework{
p.FrameworkMap[frameworks.Chi] = Framework{
packageName: chiPackage,
templater: tpl.ChiTemplates{},
}

p.FrameworkMap["standard library"] = Framework{
p.FrameworkMap[frameworks.StandardLibrary] = Framework{
packageName: []string{},
templater: tpl.StandardLibTemplate{},
}

p.FrameworkMap["gin"] = Framework{
p.FrameworkMap[frameworks.Gin] = Framework{
packageName: ginPackage,
templater: tpl.GinTemplates{},
}

p.FrameworkMap["fiber"] = Framework{
p.FrameworkMap[frameworks.Fiber] = Framework{
packageName: fiberPackage,
templater: tpl.FiberTemplates{},
}

p.FrameworkMap["gorilla/mux"] = Framework{
p.FrameworkMap[frameworks.GorillaMux] = Framework{
packageName: gorillaPackage,
templater: tpl.GorillaTemplates{},
}

p.FrameworkMap["httprouter"] = Framework{
p.FrameworkMap[frameworks.HttpRouter] = Framework{
packageName: routerPackage,
templater: tpl.RouterTemplates{},
}

p.FrameworkMap["echo"] = Framework{
p.FrameworkMap[frameworks.Echo] = Framework{
packageName: echoPackage,
templater: tpl.EchoTemplates{},
}
Expand Down Expand Up @@ -138,7 +140,7 @@ func (p *Project) CreateMainFile() error {
}

// Install the correct package for the selected framework
if p.ProjectType != "standard library" {
if p.ProjectType != frameworks.StandardLibrary {
err = utils.GoGetPackage(projectPath, p.FrameworkMap[p.ProjectType].packageName)
if err != nil {
log.Printf("Could not install go dependency for the chosen framework %v\n", err)
Expand Down
17 changes: 11 additions & 6 deletions cmd/steps/steps.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
// each step of the CLI
package steps

import textinput "github.com/melkeydev/go-blueprint/cmd/ui/textinput"
import (
"github.com/melkeydev/go-blueprint/cmd/frameworks"
textinput "github.com/melkeydev/go-blueprint/cmd/ui/textinput"
)

// A StepSchema contains the data that is used
// for an individual step of the CLI
Expand All @@ -27,18 +30,19 @@ type Item struct {
// Options contains the name and type of the created project
type Options struct {
ProjectName *textinput.Output
ProjectType string
ProjectType frameworks.Framework
}

// InitSteps initializes and returns the *Steps to be used in the CLI program
func InitSteps(options *Options) *Steps {
projectType := options.ProjectType.String()
steps := &Steps{
[]StepSchema{
{
StepName: "Go Project Framework",
Options: []Item{
{
Title: "Standard library",
Title: "Standard-library",

This comment was marked as resolved.

Desc: "The built-in Go standard library HTTP package",
},
{
Expand All @@ -61,12 +65,13 @@ func InitSteps(options *Options) *Steps {
Title: "HttpRouter",
Desc: "HttpRouter is a lightweight high performance HTTP request router for Go",
},
{Title: "Echo",
Desc: "High performance, extensible, minimalist Go web framework",
{
Title: "Echo",
Desc: "High performance, extensible, minimalist Go web framework",
},
},
Headers: "What framework do you want to use in your Go project?",
Field: &options.ProjectType,
Field: &projectType,
},
},
}
Expand Down
Loading